Skip to content

Commit

Permalink
Add support for chipsea / OKOK 2.0 scales
Browse files Browse the repository at this point in the history
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
inzanity authored and Santtu Lakkala committed Mar 3, 2021
1 parent 6cc23ea commit 7715cce
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 0 deletions.
Expand Up @@ -116,6 +116,9 @@ public static BluetoothCommunication createDeviceDriver(Context context, String
if (deviceName.startsWith("Shape200") || deviceName.startsWith("Shape100") || deviceName.startsWith("Shape50") || deviceName.startsWith("Style100")) {
return new BluetoothSoehnle(context);
}
if (deviceName.equals("ADV")) {
return new BluetoothOKOK(context);
}
return null;
}
}
@@ -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;
}
}

0 comments on commit 7715cce

Please sign in to comment.