Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for chipsea / OKOK 2.0 scales
For now only handles weight, impedance is read, but not used for anything, algorithms not known. The scale does not indicate whether it is sending the weight in kg or in lbs, always assuming kg.
- Loading branch information
Showing
2 changed files
with
98 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
95 changes: 95 additions & 0 deletions
95
android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothOKOK.java
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
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<byte[]> manufacturerSpecificData = scanResult.getScanRecord().getManufacturerSpecificData(); | ||
byte[] data = scanResult.getScanRecord().getManufacturerSpecificData(MANUFACTURER_DATA_ID); | ||
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] == 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; | ||
} | ||
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 / 10f, impedance / 10f); | ||
ScaleMeasurement entry = new ScaleMeasurement(); | ||
entry.setWeight(weight / 10.0f); | ||
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<ScanFilter> filters = new LinkedList<ScanFilter>(); | ||
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; | ||
} | ||
} |