Created
November 28, 2018 00:02
-
-
Save freman/803c3e7c2bbd40303ca4cd680da62721 to your computer and use it in GitHub Desktop.
Scales
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.health.openscale.core.bluetooth; | |
import android.bluetooth.BluetoothGatt; | |
import android.bluetooth.BluetoothGattCharacteristic; | |
import android.bluetooth.BluetoothGattService; | |
import android.content.Context; | |
import com.health.openscale.R; | |
import com.health.openscale.core.OpenScale; | |
import com.health.openscale.core.datatypes.ScaleMeasurement; | |
import com.health.openscale.core.datatypes.ScaleUser; | |
import com.health.openscale.core.utils.Converters; | |
import java.io.ByteArrayOutputStream; | |
import java.io.IOException; | |
import java.text.ParseException; | |
import java.util.Arrays; | |
import java.util.Calendar; | |
import java.util.Collections; | |
import java.util.Date; | |
import java.util.TreeSet; | |
import java.util.UUID; | |
import timber.log.Timber; | |
public class BluetoothSenssunFat extends BluetoothCommunication { | |
private final UUID MODEL_A_MEASUREMENT_SERVICE = UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb"); | |
private final UUID MODEL_A_NOTIFICATION_CHARACTERISTIC = UUID.fromString("0000fff1-0000-1000-8000-00805f9b34fb"); | |
private final UUID MODEL_A_WRITE_CHARACTERISTIC = UUID.fromString("0000fff2-0000-1000-8000-00805f9b34fb"); | |
private final UUID MODEL_B_MEASUREMENT_SERVICE = UUID.fromString("0000ffb0-0000-1000-8000-00805f9b34fb"); | |
private final UUID MODEL_B_NOTIFICATION_CHARACTERISTIC = UUID.fromString("0000ffb2-0000-1000-8000-00805f9b34fb"); | |
private final UUID MODEL_B_WRITE_CHARACTERISTIC = UUID.fromString("0000ffb2-0000-1000-8000-00805f9b34fb"); | |
private final UUID WEIGHT_MEASUREMENT_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); | |
private static final byte[] SynchronizeDateBuffer = new byte[]{-91, 48, 0, 0, 0, 0, 0, 0, 0}; | |
private static final byte[] SynchronizeTimeBuffer = new byte[]{-91, 49, 0, 0, 0, 0, 0, 0, 0}; | |
private UUID measurementService; | |
private UUID writeCharacteristic; | |
private int lastWeight, lastFat, lastHydration, lastMuscle, lastBone, lastKcal; | |
private boolean weightStabilized, stepMessageDisplayed; | |
private int values; | |
public BluetoothSenssunFat(Context context) { | |
super(context); | |
} | |
@Override | |
public String driverName() { | |
return "Senssun Fat"; | |
} | |
@Override | |
protected boolean nextInitCmd(int stateNr) { | |
switch (stateNr) { | |
case 0: | |
weightStabilized = false; | |
stepMessageDisplayed = false; | |
values = 0; | |
for (BluetoothGattService gattService : getBluetoothGattServices()) { | |
if (gattService.getUuid().equals(MODEL_A_MEASUREMENT_SERVICE)) { | |
writeCharacteristic = MODEL_A_WRITE_CHARACTERISTIC; | |
measurementService = MODEL_A_MEASUREMENT_SERVICE; | |
setNotificationOn(MODEL_A_MEASUREMENT_SERVICE, MODEL_A_NOTIFICATION_CHARACTERISTIC, WEIGHT_MEASUREMENT_CONFIG); | |
Timber.d("Found a Model A"); | |
break; | |
} | |
if (gattService.getUuid().equals(MODEL_B_MEASUREMENT_SERVICE)) { | |
writeCharacteristic = MODEL_B_WRITE_CHARACTERISTIC; | |
measurementService = MODEL_B_MEASUREMENT_SERVICE; | |
setNotificationOn(MODEL_B_MEASUREMENT_SERVICE, MODEL_B_NOTIFICATION_CHARACTERISTIC, WEIGHT_MEASUREMENT_CONFIG); | |
Timber.d("Found a Model B"); | |
break; | |
} | |
} | |
break; | |
case 1: | |
Timber.d("Sync Date"); | |
synchroniseDate(); | |
break; | |
case 2: | |
Timber.d("Sync Time"); | |
synchroniseTime(); | |
break; | |
default: | |
return false; | |
} | |
return true; | |
} | |
@Override | |
protected boolean nextBluetoothCmd(int stateNr) { | |
return false; | |
} | |
@Override | |
protected boolean nextCleanUpCmd(int stateNr) { | |
return false; | |
} | |
@Override | |
public void onBluetoothDataChange(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic) { | |
final byte[] data = gattCharacteristic.getValue(); | |
Timber.d("got data %d", data[0]); | |
if (data == null || data[0] != (byte)0xFF) { | |
return; | |
} | |
Timber.d("Valid data"); | |
System.arraycopy(data, 1, data, 0, data.length - 1); | |
Timber.d ("got more data %d", (byte)data[0]); | |
switch (data[0]) { | |
case (byte)0xA5: | |
parseMeasurement(data); | |
break; | |
} | |
} | |
private void parseMeasurement(byte[] data) { | |
switch(data[5]) { | |
case (byte)0xAA: | |
case (byte)0xA0: | |
if (weightStabilized) { | |
return; | |
} | |
if (!stepMessageDisplayed) { | |
sendMessage(R.string.info_step_on_scale, 0); | |
stepMessageDisplayed = true; | |
} | |
weightStabilized = data[5] == (byte)0xAA; | |
Timber.d("the byte is %d stable is %s", (data[5] & 0xff), weightStabilized ? "true": "false"); | |
lastWeight = ((data[1] & 0xff) << 8) | (data[2] & 0xff); | |
if (lastWeight > 0) { | |
sendMessage(R.string.info_measuring, lastWeight / 10.0f); | |
} | |
if (weightStabilized) { | |
values |= 1; | |
synchroniseUser(); | |
} | |
break; | |
case (byte)0xBE: | |
setBtStatus(BT_STATUS_CODE.BT_UNEXPECTED_ERROR, "Fat Test Error"); | |
disconnect(false); | |
break; | |
case (byte)0xB0: | |
lastFat = ((data[1] & 0xff) << 8) | (data[2] & 0xff); | |
lastHydration = ((data[3] & 0xff) << 8) | (data[4] & 0xff); | |
values |= 2; | |
Timber.d("got fat %d", values); | |
break; | |
case (byte)0xC0: | |
lastMuscle = ((data[1] & 0xff) << 8) | (data[2] & 0xff); | |
lastBone = ((data[4] & 0xff) << 8) | (data[3] & 0xff); | |
values |= 4; | |
Timber.d("got muscle %d", values); | |
break; | |
case (byte)0xD0: | |
lastKcal = ((data[1] & 0xff) << 8) | (data[2] & 0xff); | |
int unknown = ((data[3] & 0xff) << 8) | (data[4] & 0xff); | |
values |= 8; | |
Timber.d("got kal %d", values); | |
break; | |
} | |
if (values == 15) { | |
ScaleMeasurement scaleBtData = new ScaleMeasurement(); | |
scaleBtData.setWeight((float)lastWeight / 10.0f); | |
scaleBtData.setFat((float)lastFat / 10.0f); | |
scaleBtData.setWater((float)lastHydration / 10.0f); | |
scaleBtData.setBone((float)lastBone / 10.0f); | |
scaleBtData.setMuscle((float)lastMuscle / 10.0f); | |
scaleBtData.setDateTime(new Date()); | |
addScaleData(scaleBtData); | |
disconnect(false); | |
} | |
} | |
private void synchroniseDate() { | |
Calendar cal = Calendar.getInstance(); | |
byte message[] = new byte[]{(byte)0xA5, (byte)0x30, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00}; | |
message[2] = (byte)Integer.parseInt(Long.toHexString(Integer.valueOf(String.valueOf(cal.get(Calendar.YEAR)).substring(2))), 16); | |
String DayLength=Long.toHexString(cal.get(Calendar.DAY_OF_YEAR)); | |
DayLength=DayLength.length()==1?"000"+DayLength: | |
DayLength.length()==2?"00"+DayLength: | |
DayLength.length()==3?"0"+DayLength:DayLength; | |
message[3]=(byte)Integer.parseInt(DayLength.substring(0,2), 16); | |
message[4]=(byte)Integer.parseInt(DayLength.substring(2,4), 16); | |
addChecksum(message); | |
writeBytes(measurementService, writeCharacteristic, message); | |
} | |
private void synchroniseTime() { | |
Calendar cal = Calendar.getInstance(); | |
byte message[] = new byte[]{(byte)0xA5, (byte)0x31, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00}; | |
message[2]=(byte)Integer.parseInt(Long.toHexString(cal.get(Calendar.HOUR_OF_DAY)), 16); | |
message[3]=(byte)Integer.parseInt(Long.toHexString(cal.get(Calendar.MINUTE)), 16); | |
message[4]=(byte)Integer.parseInt(Long.toHexString(cal.get(Calendar.SECOND)), 16); | |
addChecksum(message); | |
writeBytes(measurementService, writeCharacteristic, message); | |
} | |
private void addChecksum(byte[] message) { | |
byte verify = 0; | |
for(int i=1;i<message.length-2;i++){ | |
verify=(byte) (verify+message[i] & 0xff); | |
} | |
message[message.length-2]=verify; | |
} | |
private void synchroniseUser() { | |
final ScaleUser selectedUser = OpenScale.getInstance().getSelectedScaleUser(); | |
byte message[] = new byte[]{(byte)0xA5, (byte)0x10, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00}; | |
//message[2] = (byte)((selectedUser.getGender().isMale() ? (byte)0x80: (byte)0x00) + 1+selectedUser.getId()); | |
message[2] = (byte) ((byte)(selectedUser.getGender().isMale()?(byte)0:(byte)8)*(byte)16 + (byte)selectedUser.getId()); | |
message[3] = (byte)selectedUser.getAge(); | |
message[4] = (byte)selectedUser.getBodyHeight(); | |
addChecksum(message); | |
writeBytes(measurementService, writeCharacteristic, message); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
could you please add the following GPLv3 notice on the top of your code, so its comply with the GPLv3?