mirror of
https://github.com/oliexdev/openScale.git
synced 2025-08-22 16:23:09 +02:00
@@ -44,7 +44,7 @@ public abstract class BluetoothCommunication {
|
||||
public enum BT_MACHINE_STATE {BT_INIT_STATE, BT_CMD_STATE, BT_CLEANUP_STATE}
|
||||
public enum BT_DEVICE_ID {CUSTOM_OPENSCALE, MI_SCALE_V1, MI_SCALE_V2,
|
||||
SANITAS_SBF70, MEDISANA_BS444, DIGOO_DGS038H, EXCELVANT_CF369BLE,
|
||||
YUNMAI_MINI, YUNMAI_SE, MGB, EXINGTECH_Y1, BEURER_BF700_800, HESLEY, ONEBYONE}
|
||||
YUNMAI_MINI, YUNMAI_SE, MGB, EXINGTECH_Y1, BEURER_BF700_800, HESLEY, ONEBYONE, IHEALTH_HS3}
|
||||
|
||||
protected Context context;
|
||||
|
||||
@@ -112,6 +112,8 @@ public abstract class BluetoothCommunication {
|
||||
return new BluetoothHesley(context);
|
||||
case ONEBYONE:
|
||||
return new BluetoothOneByone(context);
|
||||
case IHEALTH_HS3:
|
||||
return new BluetoothIhealthHS3(context);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@@ -0,0 +1,314 @@
|
||||
/* Copyright (C) 2014 olie.xdev <olie.xdev@googlemail.com>
|
||||
* Copyright (C) 2018 John Lines <john+openscale@paladyn.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package com.health.openscale.core.bluetooth;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothSocket;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.health.openscale.core.datatypes.ScaleMeasurement;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.Date;
|
||||
import java.util.Calendar;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class BluetoothIhealthHS3 extends BluetoothCommunication {
|
||||
private final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); // Standard SerialPortService ID
|
||||
|
||||
private BluetoothSocket btSocket = null;
|
||||
private BluetoothDevice btDevice = null;
|
||||
|
||||
private BluetoothConnectedThread btConnectThread = null;
|
||||
|
||||
private byte[] lastWeight = new byte[2];
|
||||
private Date lastWeighed = new Date();
|
||||
private final long maxTimeDiff = 60000; // maximum time interval we will consider two identical
|
||||
// weight readings to be the same and hence ignored - 60 seconds in milliseconds
|
||||
|
||||
public BluetoothIhealthHS3(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceName() {
|
||||
Log.w("openscale","ihealthHS3 - DeviceName - returning iHealth HS33FA4A");
|
||||
return "iHealth HS33FA4A";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defaultDeviceName() {
|
||||
Log.w("openscale","ihealthHS3 - defaultDeviceName - returning iHealth HS3");
|
||||
return "iHealth HS3";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkDeviceName(String btDeviceName) {
|
||||
Log.w("openscale","ihealthHS3 - checkDeviceName "+btDeviceName);
|
||||
if (btDeviceName.startsWith("iHealth HS3")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
boolean nextInitCmd(int stateNr) {
|
||||
Log.w("openscale","ihealthHS3 - nextInitCmd - returning false");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean nextBluetoothCmd(int stateNr) {
|
||||
Log.w("openscale","ihealthHS3 - nextBluetoothCmd - returning false");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean nextCleanUpCmd(int stateNr) {
|
||||
Log.w("openscale","ihealthHS3 - nextCleanUpCmd - returning false");
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isBLE() {
|
||||
Log.w("openscale","iHealth HS3 - isBLE - returning false");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void startSearching(String deviceName) {
|
||||
|
||||
// Log.w("openscale","iHealth HS3 - startSearching "+deviceName);
|
||||
|
||||
if (btAdapter == null) {
|
||||
setBtStatus(BT_STATUS_CODE.BT_NO_DEVICE_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
Set<BluetoothDevice> pairedDevices = btAdapter.getBondedDevices();
|
||||
|
||||
// Log.w("openscale","about to start searching paired devices");
|
||||
|
||||
for (BluetoothDevice device : pairedDevices) {
|
||||
// check if we can found bluetooth device name in the pairing list
|
||||
// if (device != null ) { Log.w("openscale","Looking at device "+device.getName()); } ;
|
||||
|
||||
if (device != null && device.getName().equals(deviceName)) {
|
||||
btDevice = device;
|
||||
|
||||
try {
|
||||
// Get a BluetoothSocket to connect with the given BluetoothDevice
|
||||
btSocket = btDevice.createRfcommSocketToServiceRecord(uuid);
|
||||
} catch (IOException e) {
|
||||
setBtStatus(BT_STATUS_CODE.BT_UNEXPECTED_ERROR, "Can't get a bluetooth socket");
|
||||
}
|
||||
|
||||
Thread socketThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (!btSocket.isConnected()) {
|
||||
// Connect the device through the socket. This will block
|
||||
// until it succeeds or throws an exception
|
||||
btSocket.connect();
|
||||
|
||||
// Bluetooth connection was successful
|
||||
setBtStatus(BT_STATUS_CODE.BT_CONNECTION_ESTABLISHED);
|
||||
|
||||
btConnectThread = new BluetoothConnectedThread();
|
||||
btConnectThread.start();
|
||||
}
|
||||
} catch (IOException connectException) {
|
||||
// Unable to connect; close the socket and get out
|
||||
stopSearching();
|
||||
setBtStatus(BT_STATUS_CODE.BT_NO_DEVICE_FOUND);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
socketThread.start();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setBtStatus(BT_STATUS_CODE.BT_NO_DEVICE_FOUND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopSearching() {
|
||||
|
||||
Log.w("openscale","HS3 - stopSearching");
|
||||
if (btSocket != null) {
|
||||
if (btSocket.isConnected()) {
|
||||
try {
|
||||
btSocket.close();
|
||||
btSocket = null;
|
||||
} catch (IOException closeException) {
|
||||
setBtStatus(BT_STATUS_CODE.BT_UNEXPECTED_ERROR, "Can't close bluetooth socket");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (btConnectThread != null) {
|
||||
btConnectThread.cancel();
|
||||
btConnectThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean sendBtData(String data) {
|
||||
Log.w("openscale","ihealthHS3 - sendBtData"+data);
|
||||
if (btSocket.isConnected()) {
|
||||
btConnectThread = new BluetoothConnectedThread();
|
||||
btConnectThread.write(data.getBytes());
|
||||
|
||||
btConnectThread.cancel();
|
||||
|
||||
return true;
|
||||
}
|
||||
Log.w("openscale","ihealthHS3 - sendBtData - socket is not connected");
|
||||
return false;
|
||||
}
|
||||
|
||||
private class BluetoothConnectedThread extends Thread {
|
||||
private InputStream btInStream;
|
||||
private OutputStream btOutStream;
|
||||
private volatile boolean isCancel;
|
||||
|
||||
public BluetoothConnectedThread() {
|
||||
// Log.w("openscale","ihealthHS3 - BluetoothConnectedThread");
|
||||
isCancel = false;
|
||||
|
||||
// Get the input and output bluetooth streams
|
||||
try {
|
||||
btInStream = btSocket.getInputStream();
|
||||
btOutStream = btSocket.getOutputStream();
|
||||
} catch (IOException e) {
|
||||
setBtStatus(BT_STATUS_CODE.BT_UNEXPECTED_ERROR, "Can't get bluetooth input or output stream " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
byte btByte;
|
||||
byte[] weightBytes = new byte[2];
|
||||
// Log.w("openscale","ihealthHS3 - run");
|
||||
// Keep listening to the InputStream until an exception occurs (e.g. device partner goes offline)
|
||||
while (!isCancel) {
|
||||
try {
|
||||
// stream read is a blocking method
|
||||
|
||||
btByte = (byte) btInStream.read();
|
||||
// Log.w("openscale","iheathHS3 - seen a byte "+String.format("%02X",btByte));
|
||||
|
||||
if ( btByte == (byte) 0xA0 ) {
|
||||
btByte = (byte) btInStream.read();
|
||||
if ( btByte == (byte) 0x09 ) {
|
||||
btByte = (byte) btInStream.read();
|
||||
if ( btByte == (byte) 0xa6 ) {
|
||||
btByte = (byte) btInStream.read();
|
||||
if ( btByte == (byte) 0x28 ) {
|
||||
// Log.w("openscale","seen 0xa009a628 - Weight packet");
|
||||
// deal with a weight packet - read 5 bytes we dont care about
|
||||
btByte = (byte) btInStream.read();
|
||||
btByte = (byte) btInStream.read();
|
||||
btByte = (byte) btInStream.read();
|
||||
btByte = (byte) btInStream.read();
|
||||
btByte = (byte) btInStream.read();
|
||||
// and the weight - which should follow
|
||||
weightBytes[0] = (byte) btInStream.read();
|
||||
weightBytes[1] = (byte) btInStream.read();
|
||||
|
||||
ScaleMeasurement scaleMeasurement = parseWeightArray(weightBytes);
|
||||
|
||||
if (scaleMeasurement != null) {
|
||||
addScaleData(scaleMeasurement);
|
||||
}
|
||||
|
||||
}
|
||||
else if (btByte == (byte) 0x33 ) {
|
||||
Log.w("openscale","seen 0xa009a633 - time packet");
|
||||
// deal with a time packet, if needed
|
||||
} else {
|
||||
Log.w("openscale","iHealthHS3 - seen byte after control leader "+String.format("%02X",btByte));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
cancel();
|
||||
setBtStatus(BT_STATUS_CODE.BT_CONNECTION_LOST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ScaleMeasurement parseWeightArray(byte[] weightBytes ) throws IOException {
|
||||
ScaleMeasurement scaleBtData = new ScaleMeasurement();
|
||||
|
||||
// Log.w("openscale","iHealthHS3 - ScaleMeasurement "+String.format("%02X",weightBytes[0])+String.format("%02X",weightBytes[1]));
|
||||
|
||||
String ws = String.format("%02X",weightBytes[0])+String.format("%02X",weightBytes[1]);
|
||||
StringBuilder ws1 = new StringBuilder (ws);
|
||||
ws1.insert(ws.length()-1,".");
|
||||
|
||||
|
||||
float weight = Float.parseFloat(ws1.toString());
|
||||
// Log.w("openscale","iHealthHS3 - ScaleMeasurement "+String.format("%f",weight));
|
||||
|
||||
Date now = new Date();
|
||||
|
||||
// If the weight is the same as the lastWeight, and the time since the last reading is less than maxTimeDiff then return null
|
||||
if (Arrays.equals(weightBytes,lastWeight) && (now.getTime() - lastWeighed.getTime() < maxTimeDiff)) {
|
||||
// Log.w("openscale","iHealthHS3 - parseWeightArray returning null");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
scaleBtData.setDateTime(now);
|
||||
scaleBtData.setWeight(weight);
|
||||
lastWeighed = now;
|
||||
System.arraycopy(weightBytes,0,lastWeight,0,lastWeight.length);
|
||||
return scaleBtData;
|
||||
|
||||
}
|
||||
|
||||
public void write(byte[] bytes) {
|
||||
try {
|
||||
btOutStream.write(bytes);
|
||||
} catch (IOException e) {
|
||||
setBtStatus(BT_STATUS_CODE.BT_UNEXPECTED_ERROR, "Error while writing to bluetooth socket " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
isCancel = true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -46,6 +46,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class BluetoothPreferences extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private static final String PREFERENCE_KEY_BLUETOOTH_SMARTUSERASSIGN = "smartUserAssign";
|
||||
private static final String PREFERENCE_KEY_BLUETOOTH_IGNOREOUTOFRANGE = "ignoreOutOfRange";
|
||||
@@ -136,6 +137,7 @@ public class BluetoothPreferences extends PreferenceFragment implements SharedPr
|
||||
|
||||
btAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
|
||||
|
||||
addPreferencesFromResource(R.xml.bluetooth_preferences);
|
||||
|
||||
smartAssignEnable = (CheckBoxPreference) findPreference(PREFERENCE_KEY_BLUETOOTH_SMARTUSERASSIGN);
|
||||
|
Reference in New Issue
Block a user