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 92193bd3..ba0a1306 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 @@ -85,6 +85,8 @@ public abstract class BluetoothCommunication { return new BluetoothSanitasSbf70(context); case 3: return new BluetoothMedisanaBS444(context); + case 4: + return new BluetoothDigooDGSO38H(context); } return null; diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothDigooDGSO38H.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothDigooDGSO38H.java new file mode 100644 index 00000000..0146f3ae --- /dev/null +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothDigooDGSO38H.java @@ -0,0 +1,173 @@ +/* Copyright (C) 2017 Murgi +* +* 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 +*/ + +package com.health.openscale.core.bluetooth; + +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; +import android.content.Context; +import android.util.Log; + +import com.health.openscale.core.OpenScale; +import com.health.openscale.core.datatypes.ScaleData; +import com.health.openscale.core.datatypes.ScaleUser; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.UUID; + +public class BluetoothDigooDGSO38H extends BluetoothCommunication { + private final UUID WEIGHT_MEASUREMENT_SERVICE = UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb"); + private final UUID WEIGHT_MEASUREMENT_CHARACTERISTIC = UUID.fromString("0000fff1-0000-1000-8000-00805f9b34fb"); + private final UUID EXTRA_MEASUREMENT_CHARACTERISTIC = UUID.fromString("0000fff2-0000-1000-8000-00805f9b34fb"); + private final UUID WEIGHT_MEASUREMENT_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); + public BluetoothDigooDGSO38H(Context context) { + super(context); + } + + @Override + public String deviceName() { + return "Digoo DG-SO38H"; + } + + @Override + public String defaultDeviceName() { + return "Mengii"; + } + + @Override + public ArrayList hwAddresses() { + ArrayList hwAddresses = new ArrayList<>(); + hwAddresses.add("C8B21E"); + + return hwAddresses; + } + + @Override + public void onBluetoothDataRead(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic, int status) { + } + + @Override + public void onBluetoothDataChange(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic) { + final byte[] data = gattCharacteristic.getValue(); + + if (data != null && data.length > 0) { + + if (data.length == 20) { + parseBytes(data); + } + } + } + + + @Override + boolean nextInitCmd(int stateNr) { + switch (stateNr) { + case 0: + //Tell device to send us weight measurements + setNotificationOn(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_CHARACTERISTIC, WEIGHT_MEASUREMENT_DESCRIPTOR); + return false; + } + + return false; + } + + @Override + boolean nextBluetoothCmd(int stateNr) { + switch (stateNr) { + default: + return false; + } + } + + @Override + boolean nextCleanUpCmd(int stateNr) { + + switch (stateNr) { + default: + return false; + } + } + + private void parseBytes(byte[] weightBytes) { + float weight, fat, water, muscle; + //float subcutaneousFat, visceralFat, metabolicBaseRate, biologicalAge, boneWeight; + + final byte ctrlByte = weightBytes[5]; + final boolean allValues = isBitSet(ctrlByte, 1); + final boolean weightStabilized = isBitSet(ctrlByte, 0); + + if (weightStabilized) { + //The weight is stabilized, now we want to measure all available values + final ScaleUser selectedUser = OpenScale.getInstance(context).getSelectedScaleUser(); + byte gender = selectedUser.isMale() ? (byte)0x00: (byte)0x01; + byte height = (byte) (selectedUser.body_height & 0xFF); + Calendar today = Calendar.getInstance(); + Calendar birthday = Calendar.getInstance(); + birthday.setTime(selectedUser.birthday); + int userAge = today.get(Calendar.YEAR) - birthday.get(Calendar.YEAR); + if (today.get(Calendar.DAY_OF_YEAR) < birthday.get(Calendar.DAY_OF_YEAR)) userAge--; + byte age = (byte)(userAge & 0xff); + byte unit; + switch (selectedUser.scale_unit) { + case 0: + unit = 0x1; + break; + case 1: + unit = 0x02; + break; + case 2: + unit = 0x8; + break; + default: + unit = 0x1; + } + byte configBytes[] = new byte[]{(byte)0x09, (byte)0x10, (byte)0x12, (byte)0x11, (byte)0x0d, (byte)0x01, height, age, gender, unit, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00}; + //Write checksum is sum of all bytes % 256 + int checksum = 0x00; + for (int i=3; i