From fd7f6d873033f4e9928261332023505df6828b31 Mon Sep 17 00:00:00 2001 From: Santtu Lakkala Date: Tue, 9 Mar 2021 16:09:30 +0200 Subject: [PATCH] Add support for chipsea / OKOK 2.0 scales (#706) add support for chipsea / OKOK 2.0 scales (only weight supported) --- .../core/bluetooth/BluetoothFactory.java | 3 + .../core/bluetooth/BluetoothOKOK.java | 98 +++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothOKOK.java diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothFactory.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothFactory.java index bef7f12e..da3013a6 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothFactory.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothFactory.java @@ -118,6 +118,9 @@ public class BluetoothFactory { } if (deviceName.equals("Hoffen BS-8107")) { return new BluetoothHoffenBBS8107(context); + } + if (deviceName.equals("ADV")) { + return new BluetoothOKOK(context); } return null; } diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothOKOK.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothOKOK.java new file mode 100644 index 00000000..c77877fa --- /dev/null +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothOKOK.java @@ -0,0 +1,98 @@ +package com.health.openscale.core.bluetooth; + +import android.bluetooth.le.ScanResult; +import android.content.Context; +import android.bluetooth.le.ScanFilter; +import android.os.Handler; +import android.os.Looper; +import android.util.SparseArray; + +import com.health.openscale.core.datatypes.ScaleMeasurement; +import com.welie.blessed.BluetoothCentral; +import com.welie.blessed.BluetoothCentralCallback; +import com.welie.blessed.BluetoothPeripheral; + +import org.jetbrains.annotations.NotNull; + +import java.util.LinkedList; +import java.util.List; + +import timber.log.Timber; + +public class BluetoothOKOK extends BluetoothCommunication { + private static final int MANUFACTURER_DATA_ID = 0x20ca; // 16-bit little endian "header" 0xca 0x20 + private static final int IDX_FINAL = 6; + private static final int IDX_WEIGHT_MSB = 8; + private static final int IDX_WEIGHT_LSB = 9; + private static final int IDX_IMPEDANCE_MSB = 10; + private static final int IDX_IMPEDANCE_LSB = 11; + private static final int IDX_CHECKSUM = 12; + + private BluetoothCentral central; + private final BluetoothCentralCallback btCallback = new BluetoothCentralCallback() { + @Override + public void onDiscoveredPeripheral(@NotNull BluetoothPeripheral peripheral, @NotNull ScanResult scanResult) { + SparseArray manufacturerSpecificData = scanResult.getScanRecord().getManufacturerSpecificData(); + byte[] data = scanResult.getScanRecord().getManufacturerSpecificData(MANUFACTURER_DATA_ID); + float divider = 10.0f; + byte checksum = 0x20; // Version field is part of the checksum, but not in array + if (data == null || data.length != 19) + return; + if ((data[IDX_FINAL] & 1) == 0) + return; + for (int i = 0; i < IDX_CHECKSUM; i++) + checksum ^= data[i]; + if (data[IDX_CHECKSUM] != checksum) { + Timber.d("Checksum error, got %x, expected %x", data[12] & 0xff, checksum & 0xff); + return; + } + if ((data[IDX_FINAL] & 4) == 4) + divider = 100.0f; + int weight = data[IDX_WEIGHT_MSB] & 0xff; + weight = weight << 8 | (data[IDX_WEIGHT_LSB] & 0xff); + int impedance = data[IDX_IMPEDANCE_MSB] & 0xff; + impedance = impedance << 8 | (data[IDX_IMPEDANCE_LSB] & 0xff); + Timber.d("Got weight: %f and impedance %f", weight / divider, impedance / 10f); + ScaleMeasurement entry = new ScaleMeasurement(); + entry.setWeight(weight / divider); + addScaleMeasurement(entry); + disconnect(); + } + }; + + public BluetoothOKOK(Context context) + { + super(context); + central = new BluetoothCentral(context, btCallback, new Handler(Looper.getMainLooper())); + } + + @Override + public String driverName() { + return "OKOK"; + } + + @Override + public void connect(String macAddress) { + Timber.d("Mac address: %s", macAddress); + List filters = new LinkedList(); + ScanFilter.Builder b = new ScanFilter.Builder(); + b.setDeviceAddress(macAddress); + b.setDeviceName("ADV"); + b.setManufacturerData(MANUFACTURER_DATA_ID, null, null); + filters.add(b.build()); + central.scanForPeripheralsUsingFilters(filters); + } + + @Override + public void disconnect() { + if (central != null) + central.stopScan(); + central = null; + super.disconnect(); + } + + @Override + protected boolean onNextStep(int stepNr) { + return false; + } +}