diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCommunication.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCommunication.java index dd0ad7d7..f1013646 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCommunication.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCommunication.java @@ -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 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() { + 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; } diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMedisanaBS444.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMedisanaBS444.java index 077a8df1..9e71a766 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMedisanaBS444.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMedisanaBS444.java @@ -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 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); - } } diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMiScale.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMiScale.java index f00a7fe1..bb673eda 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMiScale.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMiScale.java @@ -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 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); - } - - } - } - }; } diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothSanitasSbf70.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothSanitasSbf70.java index b44d87c8..8b723cc0 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothSanitasSbf70.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothSanitasSbf70.java @@ -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 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); - } }