1
0
mirror of https://github.com/oliexdev/openScale.git synced 2025-08-09 10:16:44 +02:00

refactoring existing Bluetooth classes for easy programming new Bluetooth classes.

This commit is contained in:
OliE
2017-06-18 16:54:57 +02:00
parent 490061f7b8
commit 18a84570e4
5 changed files with 672 additions and 644 deletions

View File

@@ -17,27 +17,58 @@
package com.health.openscale.core.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import com.health.openscale.core.datatypes.ScaleData;
import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_RETRIEVE_SCALE_DATA;
import java.util.ArrayList;
import java.util.UUID;
public abstract class BluetoothCommunication {
public enum BT_STATUS_CODE {BT_RETRIEVE_SCALE_DATA, BT_INIT_PROCESS, BT_CONNECTION_ESTABLISHED, BT_CONNECTION_LOST, BT_NO_DEVICE_FOUND, BT_UNEXPECTED_ERROR };
private Handler callbackBtHandler;
protected BluetoothAdapter btAdapter;
public enum BT_MACHINE_STATE {BT_INIT_STATE, BT_CMD_STATE, BT_CLEANUP_STATE}
protected Context context;
private Handler callbackBtHandler;
private BluetoothGatt bluetoothGatt;
protected BluetoothGattCallback gattCallback;
private BluetoothAdapter.LeScanCallback scanCallback;
protected BluetoothAdapter btAdapter;
private Handler searchHandler;
private String btDeviceName;
private int cmdStepNr;
private int initStepNr;
private int cleanupStepNr;
private BT_MACHINE_STATE btMachineState;
private final UUID WEIGHT_MEASUREMENT_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
public BluetoothCommunication(Context context)
{
this.context = context;
btAdapter = BluetoothAdapter.getDefaultAdapter();
searchHandler = new Handler();
scanCallback = null;
gattCallback = new GattCallback();
}
/**
* Create and return a new Bluetooth object.
*
* @param context In which context should the Bluetooth device created
* @param i the specidific number of which Bluetooth device should be created (correspond to "deviceTypes" key in BluetoothPreferences)
* @return created object specified by the number i otherwise null
*/
public static BluetoothCommunication getBtDevice(Context context, int i) {
switch (i) {
case 0:
@@ -53,43 +84,429 @@ public abstract class BluetoothCommunication {
return null;
}
/**
* Register a callback Bluetooth handler that notify any BT_STATUS_CODE changes for GUI/CORE.
*
* @param cbBtHandler a handler that is registered
*/
public void registerCallbackHandler(Handler cbBtHandler) {
callbackBtHandler = cbBtHandler;
}
/**
* Set for the openScale GUI/CORE the Bluetooth status code.
*
* @param statusCode the status code that should be set
*/
protected void setBtStatus(BT_STATUS_CODE statusCode) {
setBtStatus(statusCode, "");
}
/**
* Set for the openScale GUI/CORE the Bluetooth status code.
*
* @param statusCode the status code that should be set
* @param infoText the information text that is displayed to the status code.
*/
protected void setBtStatus(BT_STATUS_CODE statusCode, String infoText) {
callbackBtHandler.obtainMessage(statusCode.ordinal(), infoText).sendToTarget();
}
/**
* Add a new scale data to openScale
*
* @param scaleData the scale data that should be added to openScale
*/
protected void addScaleData(ScaleData scaleData) {
callbackBtHandler.obtainMessage(BT_RETRIEVE_SCALE_DATA.ordinal(), scaleData).sendToTarget();
callbackBtHandler.obtainMessage(BT_STATUS_CODE.BT_RETRIEVE_SCALE_DATA.ordinal(), scaleData).sendToTarget();
}
abstract public String deviceName();
abstract public String defaultDeviceName();
abstract public void startSearching(String deviceName);
abstract public void stopSearching();
/**
* Is the Bluetooth initialized process supported.
*
* @return true if it supported otherwise false
*/
public boolean initSupported() {
return true;
}
/**
* Is the Bluetooth transfer process supported.
*
* @return true if it supported otherwise false
*/
public boolean transferSupported() {
return true;
}
/**
* Is the Bluetooth history process supported.
*
* @return true if it supported otherwise false
*/
public boolean historySupported() {
return true;
}
/**
* Supports Bluetooth device BLE (Bluetooth 4.x/smart).
*
* @return true if it Bluetooth 4.x (smart) otherwise false
*/
public boolean isBLE() {
return true;
}
/**
* Should the device name checked while searching for a Bluetooth device.
*
* @return true if device name is checked otherwise false
*/
public boolean isDeviceNameCheck() {
return true;
}
/**
* Return the Bluetooth device name
*
* @return a string in a human readable name
*/
abstract public String deviceName();
/**
* Return the Bluetooth default device name
*
* @return the Bluetooth default device name for the scale
*/
abstract public String defaultDeviceName();
/**
* Return all hardware addresses of the Bluetooth device.
*
* The format should be the first six hex values of a know Bluetooth hardware address without any colon e.g. 12:AB:65:12:34:52 becomes "12AB65"
*
* @return a list of all hardware addresses that are known for this device.
*/
abstract public ArrayList<String> hwAddresses();
/**
* State machine for the initialization process for the Bluetooth device.
*
* @param stateNr the current step number
* @return false if no next step is available otherwise true
*/
abstract boolean nextInitCmd(int stateNr);
/**
* State machine for the normal/command process for the Bluetooth device.
*
* This state machine is automatically triggered if initialization process is finished.
*
* @param stateNr the current step number
* @return false if no next step is available otherwise true
*/
abstract boolean nextBluetoothCmd(int stateNr);
/**
* State machine for the clean up process for the Bluetooth device.
*
* This state machine is *not* automatically triggered. You have to setBtMachineState(BT_MACHINE_STATE.BT_CLEANUP_STATE) to trigger this process if necessary.
*
* @param stateNr the current step number
* @return false if no next step is available otherwise true
*/
abstract boolean nextCleanUpCmd(int stateNr);
/**
* Method is triggered if a Bluetooth data is read from a device.
*
* @param bluetoothGatt the Bluetooth Gatt
* @param gattCharacteristic the Bluetooth Gatt characteristic
* @param status the status code
*/
protected void onBluetoothDataRead(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic, int status){};
/**
* Method is triggered if a Bluetooth data from a device is notified or indicated.
*
* @param bluetoothGatt the Bluetooth Gatt
* @param gattCharacteristic the Bluetooth characteristic
*/
protected void onBluetoothDataChange(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic){};
/**
* Set the Bluetooth machine state to a specific state.
*
* @note after setting a new state the next step is automatically triggered.
*
* @param btMachineState the machine state that should be set.
*/
protected void setBtMachineState(BT_MACHINE_STATE btMachineState) {
this.btMachineState = btMachineState;
nextMachineStateStep();
}
/**
* Write a byte array to a Bluetooth device.
*
* @param service the Bluetooth UUID device service
* @param characteristic the Bluetooth UUID characteristic
* @param bytes the bytes that should be write
*/
protected void writeBytes(UUID service, UUID characteristic, byte[] bytes) {
BluetoothGattCharacteristic gattCharacteristic = bluetoothGatt.getService(service)
.getCharacteristic(characteristic);
gattCharacteristic.setValue(bytes);
bluetoothGatt.writeCharacteristic(gattCharacteristic);
}
/**
* Read bytes from a Bluetooth device.
*
* @note onBluetoothDataRead() will be triggered if read command was successful.
*
* @param service the Bluetooth UUID device service
* @param characteristic the Bluetooth UUID characteristic
*/
protected void readBytes(UUID service, UUID characteristic) {
BluetoothGattCharacteristic gattCharacteristic = bluetoothGatt.getService(service)
.getCharacteristic(characteristic);
bluetoothGatt.readCharacteristic(gattCharacteristic);
}
/**
* Set indication flag on for the Bluetooth device.
*
* @param service the Bluetooth UUID device service
* @param characteristic the Bluetooth UUID characteristic
*/
protected void setInidicationOn(UUID service, UUID characteristic) {
BluetoothGattCharacteristic gattCharacteristic = bluetoothGatt.getService(service)
.getCharacteristic(characteristic);
bluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);
BluetoothGattDescriptor gattDescriptor = gattCharacteristic.getDescriptor(WEIGHT_MEASUREMENT_CONFIG);
gattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
bluetoothGatt.writeDescriptor(gattDescriptor);
}
/**
* Set notification flag on for the Bluetooth device.
*
* @param service the Bluetooth UUID device service
* @param characteristic the Bluetooth UUID characteristic
*/
protected void setNotificationOn(UUID service, UUID characteristic) {
BluetoothGattCharacteristic gattCharacteristic = bluetoothGatt.getService(service)
.getCharacteristic(characteristic);
bluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);
BluetoothGattDescriptor gattDescriptor = gattCharacteristic.getDescriptor(WEIGHT_MEASUREMENT_CONFIG);
gattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(gattDescriptor);
}
/**
* Set notification flag off for the Bluetooth device.
*
* @param service the Bluetooth UUID device service
* @param characteristic the Bluetooth UUID characteristic
*/
protected void setNotificationOff(UUID service, UUID characteristic) {
BluetoothGattCharacteristic gattCharacteristic = bluetoothGatt.getService(service)
.getCharacteristic(characteristic);
bluetoothGatt.setCharacteristicNotification(gattCharacteristic, false);
BluetoothGattDescriptor gattDescriptor = gattCharacteristic.getDescriptor(WEIGHT_MEASUREMENT_CONFIG);
gattDescriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(gattDescriptor);
}
/**
* Convert a byte array to hex for debugging purpose
*
* @param data data we want to make human-readable (hex)
* @return a human-readable string representing the content of 'data'
*/
protected String byteInHex(byte[] data) {
if (data == null) {
Log.e("BluetoothCommunication", "Data is null");
return new String();
}
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data) {
stringBuilder.append(String.format("%02X ", byteChar));
}
return stringBuilder.toString();
}
/**
* Test in a byte if a bit is set (1) or not (0)
*
* @param value byte which is tested
* @param bit bit position which is tested
* @return true if bit is set (1) ohterwise false (0)
*/
protected boolean isBitSet(byte value, int bit) {
return (value & (1 << bit)) != 0;
}
/**
* Start searching for a Bluetooth device.
*
* @note the hardware address is checked. Bluetooth device address has to be start with one of hwAddresses().
*
* On successfully connection Bluetooth machine state is automatically triggered.
* If no device was found the search process is automatically stopped.
*
* @param deviceName the Bluetooth device name that is compared to the found devices.
*/
public void startSearching(String deviceName) {
btDeviceName = deviceName;
if (scanCallback == null)
{
scanCallback = new BluetoothAdapter.LeScanCallback()
{
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
for (int i=0; i<hwAddresses().size(); i++) {
if (device.getAddress().replace(":", "").toUpperCase().startsWith(hwAddresses().get(i)))
{
if (isDeviceNameCheck()) {
if (!device.getName().toLowerCase().equals(btDeviceName.toLowerCase())) {
return;
}
}
Log.d("BluetoothMiScale", "Mi Scale found trying to connect...");
bluetoothGatt = device.connectGatt(context, false, gattCallback);
searchHandler.removeCallbacksAndMessages(null);
btAdapter.stopLeScan(scanCallback);
}
}
}
};
}
searchHandler.postDelayed(new Runnable()
{
@Override
public void run()
{
btAdapter.stopLeScan(scanCallback);
setBtStatus(BT_STATUS_CODE.BT_NO_DEVICE_FOUND);
}
}, 10000);
btAdapter.startLeScan(scanCallback);
}
/**
* Stop searching for a Bluetooth device
*/
public void stopSearching() {
if (bluetoothGatt != null)
{
bluetoothGatt.close();
bluetoothGatt = null;
}
searchHandler.removeCallbacksAndMessages(null);
btAdapter.stopLeScan(scanCallback);
}
/**
* Invoke next step for internal Bluetooth state machine.
*/
protected void nextMachineStateStep() {
switch (btMachineState) {
case BT_INIT_STATE:
Log.d("BluetoothCommunication", "INIT STATE: " + initStepNr);
if (!nextInitCmd(initStepNr)) {
btMachineState = BT_MACHINE_STATE.BT_CMD_STATE;
nextMachineStateStep();
}
initStepNr++;
break;
case BT_CMD_STATE:
Log.d("BluetoothCommunication", "CMD STATE: " + cmdStepNr);
nextBluetoothCmd(cmdStepNr);
cmdStepNr++;
break;
case BT_CLEANUP_STATE:
Log.d("BluetoothCommunication", "CLEANUP STATE: " + cleanupStepNr);
nextCleanUpCmd(cleanupStepNr);
cleanupStepNr++;
break;
}
}
/**
* Custom Gatt callback class to set up a Bluetooth state machine.
*/
protected class GattCallback extends BluetoothGattCallback {
@Override
public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
setBtStatus(BT_STATUS_CODE.BT_CONNECTION_ESTABLISHED);
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
setBtStatus(BT_STATUS_CODE.BT_CONNECTION_LOST);
stopSearching();
}
}
@Override
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
cmdStepNr = 0;
initStepNr = 0;
cleanupStepNr = 0;
btMachineState = BT_MACHINE_STATE.BT_INIT_STATE;
nextMachineStateStep();
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt,
BluetoothGattDescriptor descriptor,
int status) {
nextMachineStateStep();
}
@Override
public void onCharacteristicWrite (BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
nextMachineStateStep();
}
@Override
public void onCharacteristicRead (BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
onBluetoothDataRead(gatt, characteristic, status);
nextMachineStateStep();
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
onBluetoothDataChange(gatt, characteristic);
}
};
}

View File

@@ -27,6 +27,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;
@@ -57,6 +58,26 @@ public class BluetoothCustomOpenScale extends BluetoothCommunication {
return "openScale_MCU";
}
@Override
public ArrayList<String> hwAddresses() {
return null;
}
@Override
boolean nextInitCmd(int stateNr) {
return false;
}
@Override
boolean nextBluetoothCmd(int stateNr) {
return false;
}
@Override
boolean nextCleanUpCmd(int stateNr) {
return false;
}
public boolean isBLE() {
return false;
}

View File

@@ -15,30 +15,17 @@
*/
package com.health.openscale.core.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import com.health.openscale.core.datatypes.ScaleData;
import java.util.ArrayList;
import java.util.Date;
import java.util.UUID;
import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_CONNECTION_ESTABLISHED;
import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_CONNECTION_LOST;
import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_NO_DEVICE_FOUND;
public class BluetoothMedisanaBS444 extends BluetoothCommunication {
private BluetoothGatt bluetoothGatt;
private BluetoothAdapter.LeScanCallback scanCallback;
private final UUID WEIGHT_MEASUREMENT_SERVICE = UUID.fromString("000078b2-0000-1000-8000-00805f9b34fb");
private final UUID WEIGHT_MEASUREMENT_CHARACTERISTIC = UUID.fromString("00008a21-0000-1000-8000-00805f9b34fb"); // indication, read-only
private final UUID FEATURE_MEASUREMENT_CHARACTERISTIC = UUID.fromString("00008a22-0000-1000-8000-00805f9b34fb"); // indication, read-only
@@ -47,16 +34,11 @@ public class BluetoothMedisanaBS444 extends BluetoothCommunication {
private final UUID CUSTOM5_MEASUREMENT_CHARACTERISTIC = UUID.fromString("00008a82-0000-1000-8000-00805f9b34fb"); // indication, read-only
private final UUID WEIGHT_MEASUREMENT_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
private String btDeviceName;
private Handler searchHandler;
private ScaleData btScaleData;
private int nextCmdState;
public BluetoothMedisanaBS444(Context context) {
super(context);
searchHandler = new Handler();
btScaleData = new ScaleData();
scanCallback = null;
}
@Override
@@ -69,163 +51,76 @@ public class BluetoothMedisanaBS444 extends BluetoothCommunication {
return "Medisana BS444";
}
@Override
public boolean isDeviceNameCheck() {
return false;
}
@Override
public ArrayList<String> hwAddresses() {
ArrayList hwAddresses = new ArrayList();
hwAddresses.add("E454EB");
return hwAddresses;
}
public boolean initSupported() {
return false;
}
@Override
public void startSearching(String deviceName) {
btDeviceName = deviceName;
if (scanCallback == null) {
scanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
if (device.getAddress().replace(":", "").toUpperCase().startsWith("E454EB")) {
//if (device.getName().equals(btDeviceName)) {
bluetoothGatt = device.connectGatt(context, false, gattCallback);
searchHandler.removeCallbacksAndMessages(null);
btAdapter.stopLeScan(scanCallback);
//}
}
}
};
}
searchHandler.postDelayed(new Runnable()
{
@Override
public void run()
{
btAdapter.stopLeScan(scanCallback);
setBtStatus(BT_NO_DEVICE_FOUND);
}
}, 10000);
btAdapter.startLeScan(scanCallback);
boolean nextInitCmd(int stateNr){
return false;
}
@Override
public void stopSearching() {
if (bluetoothGatt != null)
{
bluetoothGatt.close();
bluetoothGatt = null;
boolean nextBluetoothCmd(int stateNr){
switch (stateNr) {
case 0:
// set indication on for feature characteristic
setInidicationOn(WEIGHT_MEASUREMENT_SERVICE, FEATURE_MEASUREMENT_CHARACTERISTIC);
break;
case 1:
// set indication on for weight measurement
setInidicationOn(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_CHARACTERISTIC);
break;
case 2:
// set indication on for custom5 measurement
setInidicationOn(WEIGHT_MEASUREMENT_SERVICE, CUSTOM5_MEASUREMENT_CHARACTERISTIC);
break;
case 3:
// send magic number to receive weight data
byte[] magicBytes = new byte[]{(byte)0x02, (byte)0x7B, (byte)0x7B, (byte)0xF6, (byte)0x0D}; // 02:7b:7b:f6:0d
writeBytes(WEIGHT_MEASUREMENT_SERVICE, CMD_MEASUREMENT_CHARACTERISTIC, magicBytes);
break;
default:
return false;
}
searchHandler.removeCallbacksAndMessages(null);
btAdapter.stopLeScan(scanCallback);
return true;
}
private BluetoothGattCallback gattCallback= new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
setBtStatus(BT_CONNECTION_ESTABLISHED);
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
setBtStatus(BT_CONNECTION_LOST);
stopSearching();
}
@Override
boolean nextCleanUpCmd(int stateNr){
return false;
}
@Override
public void onBluetoothDataChange(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic){
final byte[] data = gattCharacteristic.getValue();
if (gattCharacteristic.getUuid().equals(WEIGHT_MEASUREMENT_CHARACTERISTIC)) {
parseWeightData(data);
}
@Override
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
nextCmdState = 0;
if (gattCharacteristic.getUuid().equals(FEATURE_MEASUREMENT_CHARACTERISTIC)) {
parseFeatureData(data);
invokeNextBluetoothCmd(gatt);
addScaleData(btScaleData);
}
private void invokeNextBluetoothCmd(BluetoothGatt gatt) {
BluetoothGattCharacteristic characteristic;
BluetoothGattDescriptor descriptor;
switch (nextCmdState) {
case 0:
// set indication on for feature characteristic
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(FEATURE_MEASUREMENT_CHARACTERISTIC);
gatt.setCharacteristicNotification(characteristic, true);
descriptor = characteristic.getDescriptor(WEIGHT_MEASUREMENT_CONFIG);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descriptor);
break;
case 1:
// set indication on for weight measurement
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(WEIGHT_MEASUREMENT_CHARACTERISTIC);
gatt.setCharacteristicNotification(characteristic, true);
descriptor = characteristic.getDescriptor(WEIGHT_MEASUREMENT_CONFIG);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descriptor);
break;
case 2:
// set indication on for custom5 measurement
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(CUSTOM5_MEASUREMENT_CHARACTERISTIC);
gatt.setCharacteristicNotification(characteristic, true);
descriptor = characteristic.getDescriptor(WEIGHT_MEASUREMENT_CONFIG);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descriptor);
break;
case 3:
// send magic number to receive weight data
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(CMD_MEASUREMENT_CHARACTERISTIC);
characteristic.setValue(new byte[]{(byte)0x02, (byte)0x7B, (byte)0x7B, (byte)0xF6, (byte)0x0D}); // 02:7b:7b:f6:0d
gatt.writeCharacteristic(characteristic);
break;
case 4:
// end of command mode
break;
default:
Log.e("BluetoothMedisanaScale", "Error invalid Bluetooth State");
break;
}
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt,
BluetoothGattDescriptor descriptor,
int status) {
nextCmdState++;
invokeNextBluetoothCmd(gatt);
}
@Override
public void onCharacteristicWrite (BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
nextCmdState++;
invokeNextBluetoothCmd(gatt);
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
final byte[] data = characteristic.getValue();
if (characteristic.getUuid().equals(WEIGHT_MEASUREMENT_CHARACTERISTIC)) {
parseWeightData(data);
}
if (characteristic.getUuid().equals(FEATURE_MEASUREMENT_CHARACTERISTIC)) {
parseFeatureData(data);
addScaleData(btScaleData);
}
}
};
}
private void parseWeightData(byte[] weightData) {
float weight = (float)(((weightData[2] & 0xFF) << 8) | (weightData[1] & 0xFF)) / 100.0f;
@@ -250,18 +145,4 @@ public class BluetoothMedisanaBS444 extends BluetoothCommunication {
private float decodeFeature(byte highByte, byte lowByte) {
return (float)(((lowByte& 0x0F) << 8) | (highByte & 0xFF)) / 10.0f;
}
private void printByteInHex(byte[] data) {
if (data == null) {
Log.e("BluetoothMedisanaScale", "Data is null");
return;
}
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data) {
stringBuilder.append(String.format("%02X ", byteChar));
}
Log.d("BluetoothMedisanaScale", "Raw hex data: " + stringBuilder);
}
}

View File

@@ -16,16 +16,10 @@
package com.health.openscale.core.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
@@ -33,42 +27,24 @@ import com.health.openscale.core.datatypes.ScaleData;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_CONNECTION_ESTABLISHED;
import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_CONNECTION_LOST;
import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_INIT_PROCESS;
import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_NO_DEVICE_FOUND;
import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_UNEXPECTED_ERROR;
public class BluetoothMiScale extends BluetoothCommunication {
private BluetoothGatt bluetoothGatt;
private BluetoothAdapter.LeScanCallback scanCallback;
private final UUID WEIGHT_MEASUREMENT_SERVICE = UUID.fromString("0000181d-0000-1000-8000-00805f9b34fb");
private final UUID WEIGHT_MEASUREMENT_CHARACTERISTIC = UUID.fromString("00002a9d-0000-1000-8000-00805f9b34fb");
private final UUID WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC = UUID.fromString("00002a2f-0000-3512-2118-0009af100700");
private final UUID WEIGHT_MEASUREMENT_TIME_CHARACTERISTIC = UUID.fromString("00002a2b-0000-1000-8000-00805f9b34fb");
private final UUID WEIGHT_MEASUREMENT_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
private Handler searchHandler;
private String btDeviceName;
private int nextCmdState;
private int nextInitState;
private int nextClearUpState;
private boolean initProcessOn;
private boolean clearUpProcessOn;
public BluetoothMiScale(Context context) {
super(context);
searchHandler = new Handler();
scanCallback = null;
}
@Override
@@ -82,57 +58,154 @@ public class BluetoothMiScale extends BluetoothCommunication {
}
@Override
public void startSearching(String deviceName) {
btDeviceName = deviceName;
public ArrayList<String> hwAddresses() {
ArrayList hwAddresses = new ArrayList();
hwAddresses.add("880F10");
hwAddresses.add("C80F10");
if (scanCallback == null)
{
scanCallback = new BluetoothAdapter.LeScanCallback()
{
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
if (device.getAddress().replace(":", "").toUpperCase().startsWith("880F10") ||
device.getAddress().replace(":", "").toUpperCase().startsWith("C80F10") ) // Xiaomi
{
if (device.getName().equals(btDeviceName)) {
Log.d("BluetoothMiScale", "Mi Scale found trying to connect...");
bluetoothGatt = device.connectGatt(context, false, gattCallback);
searchHandler.removeCallbacksAndMessages(null);
btAdapter.stopLeScan(scanCallback);
}
}
}
};
}
searchHandler.postDelayed(new Runnable()
{
@Override
public void run()
{
btAdapter.stopLeScan(scanCallback);
setBtStatus(BT_NO_DEVICE_FOUND);
}
}, 10000);
btAdapter.startLeScan(scanCallback);
return hwAddresses;
}
@Override
public void stopSearching() {
if (bluetoothGatt != null)
{
bluetoothGatt.close();
bluetoothGatt = null;
}
public void onBluetoothDataRead(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic, int status) {
byte[] data = gattCharacteristic.getValue();
searchHandler.removeCallbacksAndMessages(null);
btAdapter.stopLeScan(scanCallback);
int currentYear = Calendar.getInstance().get(Calendar.YEAR);
int currentMonth = Calendar.getInstance().get(Calendar.MONTH)+1;
int currentDay = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
int scaleYear = ((data[1] & 0xFF) << 8) | (data[0] & 0xFF);
int scaleMonth = (int) data[2];
int scaleDay = (int) data[3];
if (currentYear == scaleYear && currentMonth == scaleMonth && currentDay == scaleDay) {
setBtMachineState(BT_MACHINE_STATE.BT_CMD_STATE);
} else {
Log.d("BluetoothMiScale", "Current year and scale year is different");
}
}
@Override
public void onBluetoothDataChange(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic) {
final byte[] data = gattCharacteristic.getValue();
if (data != null && data.length > 0) {
// Stop command from mi scale received
if (data[0] == 0x03) {
setBtMachineState(BT_MACHINE_STATE.BT_CLEANUP_STATE);
}
if (data.length == 20) {
final byte[] firstWeight = Arrays.copyOfRange(data, 0, 10);
final byte[] secondWeight = Arrays.copyOfRange(data, 10, 20);
parseBytes(firstWeight);
parseBytes(secondWeight);
}
if (data.length == 10) {
parseBytes(data);
}
}
}
@Override
boolean nextInitCmd(int stateNr) {
switch (stateNr) {
case 0:
// read device time
readBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_TIME_CHARACTERISTIC);
break;
case 1:
// set current time
Calendar currentDateTime = Calendar.getInstance();
int year = currentDateTime.get(Calendar.YEAR);
byte month = (byte)(currentDateTime.get(Calendar.MONTH)+1);
byte day = (byte)currentDateTime.get(Calendar.DAY_OF_MONTH);
byte hour = (byte)currentDateTime.get(Calendar.HOUR_OF_DAY);
byte min = (byte)currentDateTime.get(Calendar.MINUTE);
byte sec = (byte)currentDateTime.get(Calendar.SECOND);
byte[] dateTimeByte = {(byte)(year), (byte)(year >> 8), month, day, hour, min, sec, 0x03, 0x00, 0x00};
writeBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_TIME_CHARACTERISTIC, dateTimeByte);
break;
case 2:
// set notification on for weight measurement history
setNotificationOn(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC);
break;
case 3:
// Set on history weight measurement
byte[] magicBytes = new byte[]{(byte)0x01, (byte)0x96, (byte)0x8a, (byte)0xbd, (byte)0x62};
writeBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, magicBytes);
break;
default:
return false;
}
return true;
}
@Override
boolean nextBluetoothCmd(int stateNr) {
switch (stateNr) {
case 0:
// set notification on for weight measurement
setNotificationOn(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_CHARACTERISTIC);
break;
case 1:
// set notification on for weight measurement history
setNotificationOn(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC);
break;
case 2:
// configure scale to get only last measurements
int uniqueNumber = getUniqueNumber();
byte[] userIdentifier = new byte[]{(byte)0x01, (byte)0xFF, (byte)0xFF, (byte) ((uniqueNumber & 0xFF00) >> 8), (byte) ((uniqueNumber & 0xFF) >> 0)};
writeBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, userIdentifier);
break;
case 3:
// set notification off for weight measurement history
setNotificationOff(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC);
break;
case 4:
// set notification on for weight measurement history
setNotificationOn(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC);
break;
case 5:
// invoke receiving history data
writeBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, new byte[]{0x02});
break;
default:
return false;
}
return true;
}
@Override
boolean nextCleanUpCmd(int stateNr) {
switch (stateNr) {
case 0:
// send stop command to mi scale
writeBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, new byte[]{0x03});
break;
case 1:
// acknowledge that you received the last history data
int uniqueNumber = getUniqueNumber();
byte[] userIdentifier = new byte[]{(byte)0x04, (byte)0xFF, (byte)0xFF, (byte) ((uniqueNumber & 0xFF00) >> 8), (byte) ((uniqueNumber & 0xFF) >> 0)};
writeBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, userIdentifier);
break;
default:
return false;
}
return true;
}
private void parseBytes(byte[] weightBytes) {
try {
@@ -205,10 +278,6 @@ public class BluetoothMiScale extends BluetoothCommunication {
return false;
}
private boolean isBitSet(byte value, int bit) {
return (value & (1 << bit)) != 0;
}
private int getUniqueNumber() {
int uniqueNumber;
@@ -227,299 +296,4 @@ public class BluetoothMiScale extends BluetoothCommunication {
return uniqueNumber + userId;
}
private void printByteInHex(byte[] data) {
if (data == null) {
Log.e("BluetoothMiScale", "Data is null");
return;
}
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data) {
stringBuilder.append(String.format("%02X ", byteChar));
}
Log.d("BluetoothMiScale", "Raw hex data: " + stringBuilder);
}
private BluetoothGattCallback gattCallback= new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.d("BluetoothMiScale", "Connection established");
setBtStatus(BT_CONNECTION_ESTABLISHED);
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.d("BluetoothMiScale", "Connection lost");
setBtStatus(BT_CONNECTION_LOST);
stopSearching();
}
}
@Override
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
nextCmdState = 0;
nextInitState = 0;
nextClearUpState = 0;
initProcessOn = false;
clearUpProcessOn = false;
invokeNextBluetoothCmd(gatt);
}
private void invokeNextBluetoothCmd(BluetoothGatt gatt) {
BluetoothGattCharacteristic characteristic;
BluetoothGattDescriptor descriptor;
switch (nextCmdState) {
case 0:
// read device time
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(WEIGHT_MEASUREMENT_TIME_CHARACTERISTIC);
gatt.readCharacteristic(characteristic);
break;
case 1:
// set notification on for weight measurement
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(WEIGHT_MEASUREMENT_CHARACTERISTIC);
gatt.setCharacteristicNotification(characteristic, true);
descriptor = characteristic.getDescriptor(WEIGHT_MEASUREMENT_CONFIG);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
break;
case 2:
// set notification on for weight measurement history
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC);
gatt.setCharacteristicNotification(characteristic, true);
descriptor = characteristic.getDescriptor(WEIGHT_MEASUREMENT_CONFIG);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
break;
case 3:
// configure scale to get only last measurements
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC);
int uniqueNumber = getUniqueNumber();
characteristic.setValue(new byte[]{(byte)0x01, (byte)0xFF, (byte)0xFF, (byte) ((uniqueNumber & 0xFF00) >> 8), (byte) ((uniqueNumber & 0xFF) >> 0)});
gatt.writeCharacteristic(characteristic);
break;
case 4:
// set notification off for weight measurement history
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC);
gatt.setCharacteristicNotification(characteristic, false);
descriptor = characteristic.getDescriptor(WEIGHT_MEASUREMENT_CONFIG);
descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
break;
case 5:
// set notification on for weight measurement history
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC);
gatt.setCharacteristicNotification(characteristic, true);
descriptor = characteristic.getDescriptor(WEIGHT_MEASUREMENT_CONFIG);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
break;
case 6:
// invoke receiving history data
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC);
characteristic.setValue(new byte[]{0x02});
gatt.writeCharacteristic(characteristic);
break;
case 7:
// end of command mode
break;
default:
Log.e("BluetoothMiScale", "Error invalid Bluetooth State");
break;
}
}
private void invokeClearUpBluetooth(BluetoothGatt gatt) {
BluetoothGattCharacteristic characteristic;
clearUpProcessOn = true;
switch (nextClearUpState) {
case 0:
// send stop command to mi scale
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC);
characteristic.setValue(new byte[]{0x03});
gatt.writeCharacteristic(characteristic);
break;
case 1:
// acknowledge that you received the last history data
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC);
int uniqueNumber = getUniqueNumber();
characteristic.setValue(new byte[]{(byte)0x04, (byte)0xFF, (byte)0xFF, (byte) ((uniqueNumber & 0xFF00) >> 8), (byte) ((uniqueNumber & 0xFF) >> 0)});
gatt.writeCharacteristic(characteristic);
break;
case 2:
// end of clear up process
break;
default:
Log.e("BluetoothMiScale", "Error invalid Bluetooth State");
break;
}
}
private void invokeInitBluetoothCmd(BluetoothGatt gatt) {
BluetoothGattCharacteristic characteristic;
BluetoothGattDescriptor descriptor;
initProcessOn = true;
switch (nextInitState) {
case 0:
setBtStatus(BT_INIT_PROCESS);
// set current time
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(WEIGHT_MEASUREMENT_TIME_CHARACTERISTIC);
Log.d("BluetoothMiScale", "Set current time on Mi scale");
Calendar currentDateTime = Calendar.getInstance();
int year = currentDateTime.get(Calendar.YEAR);
byte month = (byte)(currentDateTime.get(Calendar.MONTH)+1);
byte day = (byte)currentDateTime.get(Calendar.DAY_OF_MONTH);
byte hour = (byte)currentDateTime.get(Calendar.HOUR_OF_DAY);
byte min = (byte)currentDateTime.get(Calendar.MINUTE);
byte sec = (byte)currentDateTime.get(Calendar.SECOND);
byte[] dateTimeByte = {(byte)(year), (byte)(year >> 8), month, day, hour, min, sec, 0x03, 0x00, 0x00};
characteristic.setValue(dateTimeByte);
gatt.writeCharacteristic(characteristic);
break;
case 1:
// set notification on for weight measurement history
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC);
gatt.setCharacteristicNotification(characteristic, true);
descriptor = characteristic.getDescriptor(WEIGHT_MEASUREMENT_CONFIG);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
break;
case 2:
// Set on history weight measurement
characteristic = gatt.getService(WEIGHT_MEASUREMENT_SERVICE)
.getCharacteristic(WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC);
characteristic.setValue(new byte[]{(byte)0x01, (byte)0x96, (byte)0x8a, (byte)0xbd, (byte)0x62});
gatt.writeCharacteristic(characteristic);
break;
case 3:
initProcessOn = false;
stopSearching();
startSearching(btDeviceName);
break;
}
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt,
BluetoothGattDescriptor descriptor,
int status) {
if (initProcessOn) {
nextInitState++;
invokeInitBluetoothCmd(gatt);
} else if (clearUpProcessOn) {
nextClearUpState++;
invokeClearUpBluetooth(gatt);
}
else {
nextCmdState++;
invokeNextBluetoothCmd(gatt);
}
}
@Override
public void onCharacteristicWrite (BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (initProcessOn) {
nextInitState++;
invokeInitBluetoothCmd(gatt);
} else if (clearUpProcessOn) {
nextClearUpState++;
invokeClearUpBluetooth(gatt);
}else {
nextCmdState++;
invokeNextBluetoothCmd(gatt);
}
}
@Override
public void onCharacteristicRead (BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
byte[] data = characteristic.getValue();
int currentYear = Calendar.getInstance().get(Calendar.YEAR);
int currentMonth = Calendar.getInstance().get(Calendar.MONTH)+1;
int currentDay = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
int scaleYear = ((data[1] & 0xFF) << 8) | (data[0] & 0xFF);
int scaleMonth = (int) data[2];
int scaleDay = (int) data[3];
if (currentYear != scaleYear || currentMonth != scaleMonth || currentDay != scaleDay) {
Log.d("BluetoothMiScale", "Current year and scale year is different");
invokeInitBluetoothCmd(gatt);
} else {
nextCmdState++;
invokeNextBluetoothCmd(gatt);
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
// Stop command from mi scale received
if (data[0] == 0x03) {
invokeClearUpBluetooth(gatt);
}
if (data.length == 20) {
final byte[] firstWeight = Arrays.copyOfRange(data, 0, 10);
final byte[] secondWeight = Arrays.copyOfRange(data, 10, 20);
parseBytes(firstWeight);
parseBytes(secondWeight);
}
if (data.length == 10) {
parseBytes(data);
}
}
}
};
}

View File

@@ -16,26 +16,23 @@
*/
package com.health.openscale.core.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import com.health.openscale.core.datatypes.ScaleData;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.UUID;
import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_CONNECTION_ESTABLISHED;
import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_CONNECTION_LOST;
import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_NO_DEVICE_FOUND;
import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_UNEXPECTED_ERROR;
public class BluetoothSanitasSbf70 extends BluetoothCommunication {
@@ -99,17 +96,9 @@ public class BluetoothSanitasSbf70 extends BluetoothCommunication {
private static final UUID CUSTOM_CHARACTERISTIC_IMG_BLOCK = // write-only, notify
UUID.fromString("F000FFC2-0451-4000-8000-000000000000");
private BluetoothAdapter.LeScanCallback scanCallback = null;
// default name is usually "SANITAS SBF70"
private String btDeviceName = null;
private Handler searchHandler = null;
private BluetoothGattCallback gattCallback = null;
private BluetoothGatt bluetoothGatt;
public BluetoothSanitasSbf70(Context context) {
super(context);
searchHandler = new Handler();
gattCallback = new BluetoothSanitasGattCallback();
}
@Override
@@ -122,26 +111,32 @@ public class BluetoothSanitasSbf70 extends BluetoothCommunication {
return "SANITAS SBF70";
}
public boolean initSupported() {
@Override
public ArrayList<String> hwAddresses() {
ArrayList hwAddresses = new ArrayList();
hwAddresses.add("C4BE84");
hwAddresses.add("209148");
return hwAddresses;
}
@Override
boolean nextInitCmd(int stateNr) {
return false;
}
private static final String HEX_DIGITS = "0123456789ABCDEF";
@Override
boolean nextBluetoothCmd(int stateNr) {
return false;
}
/**
* @brief for debugging purpose
* @param data data we want to make human-readable (hex)
* @return a human-readable string representing the content of 'data'
*/
public static String toHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i != data.length; i++) {
int v = data[i] & 0xff;
buf.append(HEX_DIGITS.charAt(v >> 4));
buf.append(HEX_DIGITS.charAt(v & 0xf));
buf.append(" ");
}
return buf.toString();
@Override
boolean nextCleanUpCmd(int stateNr) {
return false;
}
public boolean initSupported() {
return false;
}
private class BluetoothSanitasGattCallback extends BluetoothGattCallback {
@@ -278,7 +273,7 @@ public class BluetoothSanitasSbf70 extends BluetoothCommunication {
final UUID uuid = characteristic.getUuid();
final byte[] data = characteristic.getValue();
Log.d(TAG, "onCharacteristicChanged(" + uuid + "): " + toHex(data));
Log.d(TAG, "onCharacteristicChanged(" + uuid + "): " + byteInHex(data));
if (!uuid.equals(CUSTOM_CHARACTERISTIC_WEIGHT)) {
Log.d(TAG, "Got characteristic changed from unexpected UUID ?");
@@ -379,64 +374,4 @@ public class BluetoothSanitasSbf70 extends BluetoothCommunication {
}
}
}
@Override
public void startSearching(String deviceName) {
btDeviceName = deviceName;
if (gattCallback == null) {
gattCallback = new BluetoothSanitasGattCallback();
}
if (scanCallback == null)
{
scanCallback = new BluetoothAdapter.LeScanCallback()
{
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
Log.d(TAG,
"LeScan: device found: "
+ device.getAddress() + " : " + device.getName()
);
// Texas Instrument (Sanitas)
if (device.getAddress().replace(":", "").toUpperCase().startsWith("C4BE84") ||
device.getAddress().replace(":", "").toUpperCase().startsWith("209148")) {
if (!device.getName().toLowerCase().equals(btDeviceName.toLowerCase()))
return;
Log.d(TAG, "Sanitas scale found. Connecting...");
bluetoothGatt = device.connectGatt(context, false, gattCallback);
searchHandler.removeCallbacksAndMessages(null);
btAdapter.stopLeScan(scanCallback);
}
}
};
}
searchHandler.postDelayed(new Runnable()
{
@Override
public void run()
{
btAdapter.stopLeScan(scanCallback);
setBtStatus(BT_NO_DEVICE_FOUND);
}
}, 10000);
btAdapter.startLeScan(scanCallback);
}
@Override
public void stopSearching() {
if (bluetoothGatt != null)
{
bluetoothGatt.close();
bluetoothGatt = null;
}
searchHandler.removeCallbacksAndMessages(null);
btAdapter.stopLeScan(scanCallback);
}
}