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

support for 1byOne model CF398BLE, set clock and download and delete historic measurements (#613)

This commit is contained in:
joergmlpts
2020-08-18 09:55:19 -07:00
committed by GitHub
parent e65e949922
commit 390fc41053

View File

@@ -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);
}
}