mirror of
https://github.com/oliexdev/openScale.git
synced 2025-08-16 21:54:05 +02:00
support for 1byOne model CF398BLE, set clock and download and delete historic measurements (#613)
This commit is contained in:
@@ -25,6 +25,7 @@ import com.health.openscale.core.datatypes.ScaleMeasurement;
|
||||
import com.health.openscale.core.datatypes.ScaleUser;
|
||||
import com.health.openscale.core.utils.Converters;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.UUID;
|
||||
|
||||
import timber.log.Timber;
|
||||
@@ -36,9 +37,18 @@ public class BluetoothOneByone extends BluetoothCommunication {
|
||||
|
||||
private final UUID CMD_MEASUREMENT_CHARACTERISTIC = BluetoothGattUuid.fromShortCode(0xfff1); // write only
|
||||
|
||||
private boolean waitAck = false; // if true, resume after receiving acknowledgement
|
||||
private boolean historicMeasurement = false; // processing real-time vs historic measurement
|
||||
private int noHistoric = 0; // number of historic measurements received
|
||||
|
||||
// don't save any measurements closer than 3 seconds to each other
|
||||
private Calendar lastDateTime;
|
||||
private final int DATE_TIME_THRESHOLD = 3000;
|
||||
|
||||
public BluetoothOneByone(Context context) {
|
||||
super(context);
|
||||
lastDateTime = Calendar.getInstance();
|
||||
lastDateTime.set(2000, 1, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,6 +82,25 @@ public class BluetoothOneByone extends BluetoothCommunication {
|
||||
writeBytes(WEIGHT_MEASUREMENT_SERVICE, CMD_MEASUREMENT_CHARACTERISTIC, magicBytes);
|
||||
break;
|
||||
case 2:
|
||||
Calendar dt = Calendar.getInstance();
|
||||
final byte[] setClockCmd = {(byte)0xf1, (byte)(dt.get(Calendar.YEAR) >> 8),
|
||||
(byte)(dt.get(Calendar.YEAR) & 255), (byte)(dt.get(Calendar.MONTH) + 1),
|
||||
(byte)dt.get(Calendar.DAY_OF_MONTH), (byte)dt.get(Calendar.HOUR_OF_DAY),
|
||||
(byte)dt.get(Calendar.MINUTE), (byte)dt.get(Calendar.SECOND)};
|
||||
waitAck = true;
|
||||
writeBytes(WEIGHT_MEASUREMENT_SERVICE, CMD_MEASUREMENT_CHARACTERISTIC, setClockCmd);
|
||||
// 2-byte notification value f1 00 will be received after this command
|
||||
stopMachineState(); // we will resume after receiving acknowledgement f1 00
|
||||
break;
|
||||
case 3:
|
||||
// request historic measurements; they are followed by real-time measurements
|
||||
historicMeasurement = true;
|
||||
final byte[] getHistoryCmd = {(byte)0xf2, (byte)0x00};
|
||||
writeBytes(WEIGHT_MEASUREMENT_SERVICE, CMD_MEASUREMENT_CHARACTERISTIC, getHistoryCmd);
|
||||
// multiple measurements will be received, they start cf ... and are 11 or 18 bytes long
|
||||
// 2-byte notification value f2 00 follows last historic measurement
|
||||
break;
|
||||
case 4:
|
||||
sendMessage(R.string.info_step_on_scale, 0);
|
||||
break;
|
||||
default:
|
||||
@@ -89,8 +118,28 @@ public class BluetoothOneByone extends BluetoothCommunication {
|
||||
}
|
||||
|
||||
// if data is valid data
|
||||
if (data.length == 20 && data[0] == (byte)0xcf) {
|
||||
if (data.length >= 11 && data[0] == (byte)0xcf) {
|
||||
if (historicMeasurement) {
|
||||
++noHistoric;
|
||||
}
|
||||
parseBytes(data);
|
||||
} else {
|
||||
// show 2-byte ack messages in debug output:
|
||||
// f1 00 setClockCmd acknowledgement
|
||||
// f2 00 end of historic measurements, real-time measurements follow
|
||||
// f2 01 clearHistoryCmd acknowledgement
|
||||
Timber.d("received bytes [%s]", byteInHex(data));
|
||||
|
||||
if (waitAck && data.length == 2 && data[0] == (byte)0xf1 && data[1] == 0) {
|
||||
waitAck = false;
|
||||
resumeMachineState();
|
||||
} else if (data.length == 2 && data[0] == (byte)0xf2 && data[1] == 0) {
|
||||
historicMeasurement = false;
|
||||
if (noHistoric > 0) {
|
||||
final byte[] clearHistoryCmd = {(byte)0xf2, (byte)0x01};
|
||||
writeBytes(WEIGHT_MEASUREMENT_SERVICE, CMD_MEASUREMENT_CHARACTERISTIC, clearHistoryCmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +147,21 @@ public class BluetoothOneByone extends BluetoothCommunication {
|
||||
float weight = Converters.fromUnsignedInt16Le(weightBytes, 3) / 100.0f;
|
||||
int impedanceCoeff = Converters.fromUnsignedInt24Le(weightBytes, 5);
|
||||
int impedanceValue = weightBytes[5] + weightBytes[6] + weightBytes[7];
|
||||
boolean impedancePresent = (weightBytes[9] != 1) && (impedanceCoeff != 0);
|
||||
boolean dateTimePresent = weightBytes.length >= 18;
|
||||
|
||||
if (!impedancePresent || (!dateTimePresent && historicMeasurement)) {
|
||||
// unwanted, no impedance or historic measurement w/o time-stamp
|
||||
return;
|
||||
}
|
||||
|
||||
Calendar dateTime = Calendar.getInstance();
|
||||
if (dateTimePresent) {
|
||||
// 18-byte or longer measurements contain date and time, used in history
|
||||
dateTime.set(Converters.fromUnsignedInt16Be(weightBytes, 11),
|
||||
weightBytes[13] - 1, weightBytes[14], weightBytes[15],
|
||||
weightBytes[16], weightBytes[17]);
|
||||
}
|
||||
|
||||
final ScaleUser scaleUser = OpenScale.getInstance().getSelectedScaleUser();
|
||||
|
||||
@@ -135,6 +199,19 @@ public class BluetoothOneByone extends BluetoothCommunication {
|
||||
|
||||
ScaleMeasurement scaleBtData = new ScaleMeasurement();
|
||||
scaleBtData.setWeight(weight);
|
||||
try {
|
||||
dateTime.setLenient(false);
|
||||
scaleBtData.setDateTime(dateTime.getTime());
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
if (historicMeasurement) {
|
||||
Timber.d("invalid time-stamp: year %d, month %d, day %d, hour %d, minute %d, second %d",
|
||||
Converters.fromUnsignedInt16Be(weightBytes, 11),
|
||||
weightBytes[13], weightBytes[14], weightBytes[15],
|
||||
weightBytes[16], weightBytes[17]);
|
||||
return; // discard historic measurement with invalid time-stamp
|
||||
}
|
||||
}
|
||||
scaleBtData.setFat(oneByoneLib.getBodyFat(weight, impedanceCoeff));
|
||||
scaleBtData.setWater(oneByoneLib.getWater(scaleBtData.getFat()));
|
||||
scaleBtData.setBone(oneByoneLib.getBoneMass(weight, impedanceValue));
|
||||
@@ -143,6 +220,11 @@ public class BluetoothOneByone extends BluetoothCommunication {
|
||||
|
||||
Timber.d("scale measurement [%s]", scaleBtData);
|
||||
|
||||
if (dateTime.getTimeInMillis() - lastDateTime.getTimeInMillis() < DATE_TIME_THRESHOLD) {
|
||||
return; // don't save measurements too close to each other
|
||||
}
|
||||
lastDateTime = dateTime;
|
||||
|
||||
addScaleMeasurement(scaleBtData);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user