1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-28 12:56:49 +01:00

HPlus: Code cleanup

This commit is contained in:
João Paulo Barraca 2017-01-04 01:46:24 +00:00
parent 547736f8f7
commit 9d67394720
9 changed files with 188 additions and 240 deletions

View File

@ -36,6 +36,7 @@ public final class HPlusConstants {
public static final byte[] CMD_SET_PREF_START = new byte[]{0x4f, 0x5a};
public static final byte[] CMD_SET_PREF_START1 = new byte[]{0x4d};
public static final byte CMD_SET_ALARM = 0x4c;
public static final byte CMD_SET_LANGUAGE = 0x22;
public static final byte CMD_SET_TIMEMODE = 0x47;
public static final byte CMD_SET_UNITS = 0x48;

View File

@ -6,9 +6,6 @@ package nodomain.freeyourgadget.gadgetbridge.devices.hplus;
import android.support.annotation.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@ -30,8 +27,6 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealthActivitySample> {
private static final Logger LOG = LoggerFactory.getLogger(HPlusHealthSampleProvider.class);
private GBDevice mDevice;
private DaoSession mSession;
@ -71,12 +66,12 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
@Override
protected Property getRawKindSampleProperty() {
return HPlusHealthActivitySampleDao.Properties.RawKind;
return null; // HPlusHealthActivitySampleDao.Properties.RawKind;
}
@Override
public float normalizeIntensity(int rawIntensity) {
return rawIntensity; //TODO: Calculate actual value
return rawIntensity / (float) 100.0;
}
@NonNull
@ -90,6 +85,7 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
return getSession().getHPlusHealthActivitySampleDao();
}
@NonNull
@Override
public List<HPlusHealthActivitySample> getAllActivitySamples(int timestamp_from, int timestamp_to) {
List<HPlusHealthActivitySample> samples = super.getGBActivitySamples(timestamp_from, timestamp_to, ActivityKind.TYPE_ALL);
@ -107,11 +103,11 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
List<HPlusHealthActivityOverlay> overlayRecords = qb.build().list();
for (HPlusHealthActivityOverlay overlay : overlayRecords) {
insertVirtualItem(samples, overlay.getTimestampFrom(), overlay.getDeviceId(), overlay.getUserId());
insertVirtualItem(samples, overlay.getTimestampTo() - 1, overlay.getDeviceId(), overlay.getUserId());
insertVirtualItem(samples, Math.max(overlay.getTimestampFrom(), timestamp_from), overlay.getDeviceId(), overlay.getUserId());
insertVirtualItem(samples, Math.min(overlay.getTimestampTo() - 1, timestamp_to - 1), overlay.getDeviceId(), overlay.getUserId());
for (HPlusHealthActivitySample sample : samples) {
if (overlay.getTimestampFrom() <= sample.getTimestamp() && sample.getTimestamp() < overlay.getTimestampTo()) {
if (sample.getTimestamp() >= overlay.getTimestampFrom() && sample.getTimestamp() < overlay.getTimestampTo()) {
sample.setRawKind(overlay.getRawKind());
}
}
@ -119,8 +115,6 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
detachFromSession();
LOG.debug("Returning " + samples.size() + " samples processed by " + overlayRecords.size() + " overlays");
Collections.sort(samples, new Comparator<HPlusHealthActivitySample>() {
public int compare(HPlusHealthActivitySample one, HPlusHealthActivitySample other) {
return one.getTimestamp() - other.getTimestamp();
@ -137,7 +131,7 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
userId, // User id
null, // Raw Data
ActivityKind.TYPE_UNKNOWN,
ActivitySample.NOT_MEASURED, // Intensity
0, // Intensity
ActivitySample.NOT_MEASURED, // Steps
ActivitySample.NOT_MEASURED, // HR
ActivitySample.NOT_MEASURED, // Distance
@ -149,4 +143,5 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
return samples;
}
}

View File

@ -1,12 +1,11 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.hplus;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
/**
* Created by jpbarraca on 30/12/2016.
*/
/*
* @author João Paulo Barraca &lt;jpbarraca@gmail.com&gt;
*/
public class HPlusDataRecord {
public final static int TYPE_SLEEP = 1;

View File

@ -9,10 +9,10 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
public class HPlusDataRecordDay extends HPlusDataRecord {
int slot;
int steps;
int secondsInactive;
int heartRate;
public int slot;
public int steps;
public int secondsInactive;
public int heartRate;
public HPlusDataRecordDay(byte[] data) {
super(data);

View File

@ -6,16 +6,18 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.hplus;
import java.util.Calendar;
import java.util.Locale;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
public class HPlusDataRecordRealtime extends HPlusDataRecord {
int distance;
int calories;
int heartRate;
byte battery;
int activeTime;
class HPlusDataRecordRealtime extends HPlusDataRecord {
public int distance;
public int calories;
public int heartRate;
public byte battery;
public int activeTime;
public int intensity;
public HPlusDataRecordRealtime(byte[] data) {
super(data);
@ -36,7 +38,10 @@ public class HPlusDataRecordRealtime extends HPlusDataRecord {
heartRate = data[11] & 0xFF; // BPM
activeTime = (data[14] & 0xFF * 256) + (data[13] & 0xFF);
if(heartRate == 255)
intensity = 0;
else
intensity = (int) (100 * Math.max(0, Math.min((heartRate - 60) / 120.0, 1))); // TODO: Calculate a proper value
}
public void computeActivity(HPlusDataRecordRealtime prev){
@ -66,4 +71,8 @@ public class HPlusDataRecordRealtime extends HPlusDataRecord {
return distance == other.distance && calories == other.calories && heartRate == other.heartRate && battery == other.battery;
}
public String toString(){
return String.format(Locale.US, "Distance: %d Calories: %d HeartRate: %d Battery: %d ActiveTime: %d Intensity: %d", distance, calories, heartRate, battery, activeTime, intensity);
}
}

View File

@ -5,9 +5,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.hplus;
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
@ -15,18 +12,16 @@ import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
public class HPlusDataRecordSleep extends HPlusDataRecord {
private static final Logger LOG = LoggerFactory.getLogger(HPlusDataRecordSleep.class);
int type = TYPE_SLEEP;
int bedTimeStart;
int bedTimeEnd;
int deepSleepMinutes;
int lightSleepMinutes;
int enterSleepMinutes;
int spindleMinutes;
int remSleepMinutes;
int wakeupMinutes;
int wakeupCount;
public int bedTimeStart;
public int bedTimeEnd;
public int deepSleepMinutes;
public int lightSleepMinutes;
public int enterSleepMinutes;
public int spindleMinutes;
public int remSleepMinutes;
public int wakeupMinutes;
public int wakeupCount;
public HPlusDataRecordSleep(byte[] data) {
super(data);
@ -56,7 +51,7 @@ public class HPlusDataRecordSleep extends HPlusDataRecord {
sleepStart.set(Calendar.YEAR, year);
sleepStart.set(Calendar.MONTH, month - 1);
sleepStart.set(Calendar.DAY_OF_MONTH, day);
sleepStart.set(Calendar.HOUR, hour);
sleepStart.set(Calendar.HOUR_OF_DAY, hour);
sleepStart.set(Calendar.MINUTE, minute);
sleepStart.set(Calendar.SECOND, 0);
sleepStart.set(Calendar.MILLISECOND, 0);
@ -66,10 +61,13 @@ public class HPlusDataRecordSleep extends HPlusDataRecord {
lightSleepMinutes = enterSleepMinutes + spindleMinutes + remSleepMinutes;
timestamp = bedTimeStart;
}
Calendar sleepEnd = Calendar.getInstance();
sleepEnd.setTimeInMillis(bedTimeEnd * 1000L);
}
public List<RecordInterval> getIntervals() {
List<RecordInterval> intervals = new ArrayList<RecordInterval>();
List<RecordInterval> intervals = new ArrayList<>();
int ts = bedTimeStart + lightSleepMinutes * 60;
intervals.add(new RecordInterval(bedTimeStart, ts, ActivityKind.TYPE_LIGHT_SLEEP));

View File

@ -5,19 +5,12 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.hplus;
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
public class HPlusDataRecordSteps extends HPlusDataRecord{
private static final Logger LOG = LoggerFactory.getLogger(HPlusDataRecordSteps.class);
int steps;
int distance;
class HPlusDataRecordSteps extends HPlusDataRecord{
public int steps;
public int distance;
HPlusDataRecordSteps(byte[] data) {
super(data);
@ -45,15 +38,11 @@ public class HPlusDataRecordSteps extends HPlusDataRecord{
date.set(Calendar.YEAR, year);
date.set(Calendar.MONTH, month - 1);
date.set(Calendar.DAY_OF_MONTH, day);
date.set(Calendar.HOUR, 23);
date.set(Calendar.HOUR_OF_DAY, 23);
date.set(Calendar.MINUTE, 59);
date.set(Calendar.SECOND, 59);
date.set(Calendar.MILLISECOND, 999);
timestamp = (int) (date.getTimeInMillis() / 1000);
}
public int getType(int ts){
return ActivityKind.TYPE_UNKNOWN;
}
}

View File

@ -18,15 +18,12 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusConstants;
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusHealthSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.entities.HPlusHealthActivityOverlay;
import nodomain.freeyourgadget.gadgetbridge.entities.HPlusHealthActivityOverlayDao;
import nodomain.freeyourgadget.gadgetbridge.entities.HPlusHealthActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.User;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
@ -34,16 +31,15 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread;
public class HPlusHandlerThread extends GBDeviceIoThread {
class HPlusHandlerThread extends GBDeviceIoThread {
private static final Logger LOG = LoggerFactory.getLogger(HPlusHandlerThread.class);
private int SYNC_PERIOD = 60 * 10;
private int SYNC_RETRY_PERIOD = 6;
private int SLEEP_SYNC_PERIOD = 12 * 60 * 60;
private int SLEEP_RETRY_PERIOD = 30;
private int HELLO_INTERVAL = 30;
private static final Logger LOG = LoggerFactory.getLogger(HPlusHandlerThread.class);
private int HELLO_INTERVAL = 60;
private boolean mQuit = false;
private HPlusSupport mHPlusSupport;
@ -57,7 +53,7 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
private Calendar mGetDaySlotsTime = Calendar.getInstance();
private Calendar mGetSleepTime = Calendar.getInstance();
private Object waitObject = new Object();
private final Object waitObject = new Object();
private HPlusDataRecordRealtime prevRealTimeRecord = null;
@ -80,7 +76,6 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
sync();
boolean starting = true;
long waitTime = 0;
while (!mQuit) {
//LOG.debug("Waiting " + (waitTime));
@ -147,25 +142,27 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
}
}
public void sendHello() {
mHelloTime = Calendar.getInstance();
mHelloTime.add(Calendar.SECOND, HELLO_INTERVAL);
private void sendHello() {
TransactionBuilder builder = new TransactionBuilder("hello");
builder.write(mHPlusSupport.ctrlCharacteristic, HPlusConstants.CMD_ACTION_HELLO);
builder.queue(mHPlusSupport.getQueue());
scheduleHello();
}
public void scheduleHello(){
mHelloTime = Calendar.getInstance();
mHelloTime.add(Calendar.SECOND, HELLO_INTERVAL);
}
public void processIncomingDaySlotData(byte[] data) {
public boolean processIncomingDaySlotData(byte[] data) {
HPlusDataRecordDay record;
try{
record = new HPlusDataRecordDay(data);
} catch(IllegalArgumentException e){
LOG.debug((e.getMessage()));
return;
return true;
}
if ((record.slot == 0 && mLastSlotReceived == 0) || (record.slot == mLastSlotReceived + 1)) {
@ -181,7 +178,7 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
deviceId, userId, // User id
record.getRawData(), // Raw Data
ActivityKind.TYPE_UNKNOWN,
ActivitySample.NOT_MEASURED, // Intensity
0, // Intensity
record.steps, // Steps
record.heartRate, // HR
ActivitySample.NOT_MEASURED, // Distance
@ -204,11 +201,10 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
}
}
}
return true;
}
private void requestNextDaySlots() {
LOG.debug("Request Next Slot: Got: " + mLastSlotReceived + " Request: " + mLastSlotRequested);
//Sync Day Stats
byte hour = (byte) ((mLastSlotReceived) / 6);
byte nextHour = (byte) (hour + 1);
@ -240,7 +236,7 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
return;
}
LOG.debug("Making new Request From " + hour + ":" + minute + " to " + nextHour + ":" + nextMinute);
//LOG.debug("Making new Request From " + hour + ":" + minute + " to " + nextHour + ":" + nextMinute);
byte[] msg = new byte[]{39, hour, minute, nextHour, nextMinute}; //Request the entire day
TransactionBuilder builder = new TransactionBuilder("getNextDaySlot");
@ -251,16 +247,14 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
mGetDaySlotsTime.add(Calendar.SECOND, SYNC_RETRY_PERIOD);
}
public void processIncomingSleepData(byte[] data){
LOG.debug("Processing Sleep Data");
public boolean processIncomingSleepData(byte[] data){
HPlusDataRecordSleep record;
try{
record = new HPlusDataRecordSleep(data);
} catch(IllegalArgumentException e){
LOG.debug((e.getMessage()));
return;
return true;
}
mLastSleepDayReceived.setTimeInMillis(record.bedTimeStart * 1000L);
@ -288,7 +282,7 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
deviceId, userId, // User id
record.getRawData(), // Raw Data
record.activityKind,
ActivitySample.NOT_MEASURED, // Intensity
0, // Intensity
ActivitySample.NOT_MEASURED, // Steps
ActivitySample.NOT_MEASURED, // HR
ActivitySample.NOT_MEASURED, // Distance
@ -307,11 +301,10 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
mGetSleepTime = Calendar.getInstance();
mGetSleepTime.add(Calendar.SECOND, SLEEP_SYNC_PERIOD);
return true;
}
private void requestNextSleepData() {
LOG.debug("Request New Sleep Data");
mGetSleepTime = Calendar.getInstance();
mGetSleepTime.add(Calendar.SECOND, SLEEP_RETRY_PERIOD);
@ -321,20 +314,18 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
}
public void processRealtimeStats(byte[] data) {
LOG.debug("Processing Real time Stats");
public boolean processRealtimeStats(byte[] data) {
HPlusDataRecordRealtime record;
try{
record = new HPlusDataRecordRealtime(data);
} catch(IllegalArgumentException e){
LOG.debug((e.getMessage()));
return;
return true;
}
if(record.same(prevRealTimeRecord))
return;
return true;
prevRealTimeRecord = record;
@ -345,18 +336,14 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
if(record.heartRate == 255) {
getDevice().setFirmwareVersion2("---");
getDevice().sendDeviceUpdateIntent(getContext());
return;
return true;
}
getDevice().setFirmwareVersion2(""+record.heartRate);
getDevice().setFirmwareVersion2("" + record.heartRate);
getDevice().sendDeviceUpdateIntent(getContext());
try (DBHandler dbHandler = GBApplication.acquireDB()) {
DaoSession session = dbHandler.getDaoSession();
HPlusHealthSampleProvider provider = new HPlusHealthSampleProvider(getDevice(), dbHandler.getDaoSession());
HPlusHealthActivityOverlayDao overlayDao = session.getHPlusHealthActivityOverlayDao();
Long userId = DBHelper.getUser(dbHandler.getDaoSession()).getId();
Long deviceId = DBHelper.getDevice(getDevice(), dbHandler.getDaoSession()).getId();
@ -365,7 +352,7 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
deviceId, userId, // User id
record.getRawData(), // Raw Data
record.activityKind,
ActivitySample.NOT_MEASURED, // Intensity
record.intensity, // Intensity
ActivitySample.NOT_MEASURED, // Steps
record.heartRate, // HR
record.distance, // Distance
@ -375,32 +362,25 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
sample.setProvider(provider);
provider.addGBActivitySample(sample);
if(record.activeTime > 0){
//TODO: Register ACTIVITY Time
//Insert the Overlays
//List<HPlusHealthActivityOverlay> overlayList = new ArrayList<>();
//overlayList.add(new HPlusHealthActivityOverlay(record.timestamp - record.activeTime * 60, record.timestamp, ActivityKind.TYPE_ACTIVITY, deviceId, userId, null));
//overlayDao.insertOrReplaceInTx(overlayList);
}
//TODO: Handle Active Time. With Overlay?
} catch (GBException ex) {
LOG.debug((ex.getMessage()));
} catch (Exception ex) {
LOG.debug(ex.getMessage());
}
return true;
}
public void processStepStats(byte[] data) {
LOG.debug("Processing Step Stats");
public boolean processStepStats(byte[] data) {
HPlusDataRecordSteps record;
try{
record = new HPlusDataRecordSteps(data);
} catch(IllegalArgumentException e){
LOG.debug((e.getMessage()));
return;
return true;
}
try (DBHandler dbHandler = GBApplication.acquireDB()) {
@ -408,17 +388,40 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
Long userId = DBHelper.getUser(dbHandler.getDaoSession()).getId();
Long deviceId = DBHelper.getDevice(getDevice(), dbHandler.getDaoSession()).getId();
//Hugly (?) fix.
//This message returns the day summary, but the DB already has some detailed entries with steps and distance.
//However DB data is probably incomplete as some update messages could be missing
//Proposed fix: Calculate the total steps and distance and store a new sample with the remaining data
//Existing data will reflect user activity with the issue of a potencially large number of steps at midnight.
//Steps counters by day will be OK with this
List<HPlusHealthActivitySample> samples = provider.getActivitySamples(record.timestamp - 3600 * 24 + 1, record.timestamp);
int missingDistance = record.distance;
int missingSteps = record.steps;
for(HPlusHealthActivitySample sample : samples){
if(sample.getSteps() > 0) {
missingSteps -= sample.getSteps();
}
if(sample.getDistance() > 0){
missingDistance -= sample.getDistance();
}
}
HPlusHealthActivitySample sample = new HPlusHealthActivitySample(
record.timestamp, // ts
deviceId, userId, // User id
record.getRawData(), // Raw Data
ActivityKind.TYPE_UNKNOWN,
ActivitySample.NOT_MEASURED, // Intensity
record.steps, // Steps
0, // Intensity
Math.max( missingSteps, 0), // Steps
ActivitySample.NOT_MEASURED, // HR
record.distance, // Distance
Math.max( missingDistance, 0), // Distance
ActivitySample.NOT_MEASURED // Calories
);
sample.setProvider(provider);
provider.addGBActivitySample(sample);
} catch (GBException ex) {
@ -426,11 +429,11 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
} catch (Exception ex) {
LOG.debug(ex.getMessage());
}
return true;
}
public boolean processVersion(byte[] data) {
LOG.debug("Process Version");
int major = data[2] & 0xFF;
int minor = data[1] & 0xFF;
@ -440,14 +443,4 @@ public class HPlusHandlerThread extends GBDeviceIoThread {
return true;
}
public static HPlusHealthActivitySample createActivitySample(Device device, User user, int timestampInSeconds, SampleProvider provider) {
HPlusHealthActivitySample sample = new HPlusHealthActivitySample();
sample.setDevice(device);
sample.setUser(user);
sample.setTimestamp(timestampInSeconds);
sample.setProvider(provider);
return sample;
}
}

View File

@ -4,7 +4,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.hplus;
* @author João Paulo Barraca &lt;jpbarraca@gmail.com&gt;
*/
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.BroadcastReceiver;
@ -23,7 +22,6 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusConstants;
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusCoordinator;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
@ -35,10 +33,10 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@ -49,9 +47,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
public BluetoothGattCharacteristic ctrlCharacteristic = null;
public BluetoothGattCharacteristic measureCharacteristic = null;
private int[] lastDataStats = null;
private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
private HPlusHandlerThread syncHelper;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@ -82,10 +77,10 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
LOG.debug("Dispose");
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getContext());
broadcastManager.unregisterReceiver(mReceiver);
super.dispose();
if(syncHelper != null)
syncHelper.quit();
close();
super.dispose();
}
@Override
@ -112,15 +107,12 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
setInitialized(builder);
syncHelper.start();
builder.notify(getCharacteristic(HPlusConstants.UUID_CHARACTERISTIC_MEASURE), true);
builder.setGattCallback(this);
builder.notify(measureCharacteristic, true);
//LOG.debug("Initialization Done");
return builder;
}
@ -135,8 +127,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
}
private HPlusSupport syncPreferences(TransactionBuilder transaction) {
LOG.info("Attempting to sync preferences with: " + getDevice().getAddress());
byte gender = HPlusCoordinator.getUserGender(getDevice().getAddress());
byte age = HPlusCoordinator.getUserAge(getDevice().getAddress());
byte bodyHeight = HPlusCoordinator.getUserHeight(getDevice().getAddress());
@ -189,8 +179,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
}
private HPlusSupport setLanguage(TransactionBuilder transaction) {
LOG.info("Attempting to set language...");
byte value = HPlusCoordinator.getCountry(getDevice().getAddress());
transaction.write(ctrlCharacteristic, new byte[]{
HPlusConstants.CMD_SET_LANGUAGE,
@ -201,8 +189,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
private HPlusSupport setTimeMode(TransactionBuilder transaction) {
LOG.info("Attempting to set Time Mode...");
byte value = HPlusCoordinator.getTimeMode(getDevice().getAddress());
transaction.write(ctrlCharacteristic, new byte[]{
HPlusConstants.CMD_SET_TIMEMODE,
@ -212,9 +198,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
}
private HPlusSupport setUnit(TransactionBuilder transaction) {
LOG.info("Attempting to set Units...");
byte value = HPlusCoordinator.getUnit(getDevice().getAddress());
transaction.write(ctrlCharacteristic, new byte[]{
HPlusConstants.CMD_SET_UNITS,
@ -224,8 +207,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
}
private HPlusSupport setCurrentDate(TransactionBuilder transaction) {
LOG.info("Attempting to set Current Date...");
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR) - 1900;
int month = c.get(Calendar.MONTH);
@ -243,8 +224,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
}
private HPlusSupport setCurrentTime(TransactionBuilder transaction) {
LOG.info("Attempting to set Current Time...");
Calendar c = Calendar.getInstance();
transaction.write(ctrlCharacteristic, new byte[]{
@ -259,8 +238,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
private HPlusSupport setDayOfWeek(TransactionBuilder transaction) {
LOG.info("Attempting to set Day Of Week...");
Calendar c = Calendar.getInstance();
transaction.write(ctrlCharacteristic, new byte[]{
@ -272,8 +249,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
private HPlusSupport setSIT(TransactionBuilder transaction) {
LOG.info("Attempting to set SIT...");
int startTime = HPlusCoordinator.getSITStartTime(getDevice().getAddress());
int endTime = HPlusCoordinator.getSITEndTime(getDevice().getAddress());
@ -291,7 +266,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
(byte) (now.get(Calendar.YEAR) % 256),
(byte) (now.get(Calendar.MONTH) + 1),
(byte) (now.get(Calendar.DAY_OF_MONTH)),
(byte) (now.get(Calendar.HOUR)),
(byte) (now.get(Calendar.HOUR_OF_DAY)),
(byte) (now.get(Calendar.MINUTE)),
(byte) (now.get(Calendar.SECOND)),
0,
@ -304,8 +279,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
}
private HPlusSupport setWeight(TransactionBuilder transaction) {
LOG.info("Attempting to set Weight...");
byte value = HPlusCoordinator.getUserWeight(getDevice().getAddress());
transaction.write(ctrlCharacteristic, new byte[]{
HPlusConstants.CMD_SET_WEIGHT,
@ -316,8 +289,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
}
private HPlusSupport setHeight(TransactionBuilder transaction) {
LOG.info("Attempting to set Height...");
byte value = HPlusCoordinator.getUserHeight(getDevice().getAddress());
transaction.write(ctrlCharacteristic, new byte[]{
HPlusConstants.CMD_HEIGHT,
@ -329,8 +300,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
private HPlusSupport setAge(TransactionBuilder transaction) {
LOG.info("Attempting to set Age...");
byte value = HPlusCoordinator.getUserAge(getDevice().getAddress());
transaction.write(ctrlCharacteristic, new byte[]{
HPlusConstants.CMD_SET_AGE,
@ -341,8 +310,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
}
private HPlusSupport setGender(TransactionBuilder transaction) {
LOG.info("Attempting to set Gender...");
byte value = HPlusCoordinator.getUserGender(getDevice().getAddress());
transaction.write(ctrlCharacteristic, new byte[]{
HPlusConstants.CMD_SET_GENDER,
@ -354,8 +321,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
private HPlusSupport setGoal(TransactionBuilder transaction) {
LOG.info("Attempting to set Sex...");
int value = HPlusCoordinator.getGoal(getDevice().getAddress());
transaction.write(ctrlCharacteristic, new byte[]{
HPlusConstants.CMD_SET_GOAL,
@ -368,8 +333,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
private HPlusSupport setScreenTime(TransactionBuilder transaction) {
LOG.info("Attempting to set Screentime...");
byte value = HPlusCoordinator.getScreenTime(getDevice().getAddress());
transaction.write(ctrlCharacteristic, new byte[]{
HPlusConstants.CMD_SET_SCREENTIME,
@ -392,28 +355,35 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
}
private HPlusSupport setAlarm(TransactionBuilder transaction) {
LOG.info("Attempting to set Alarm...");
//TODO: Find how to set alarms
private HPlusSupport setAlarm(TransactionBuilder transaction, Calendar t) {
transaction.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SET_ALARM,
(byte) (t.get(Calendar.YEAR) / 256),
(byte) (t.get(Calendar.YEAR) % 256),
(byte) (t.get(Calendar.MONTH) + 1),
(byte) t.get(Calendar.HOUR_OF_DAY),
(byte) t.get(Calendar.MINUTE),
(byte) t.get(Calendar.SECOND)});
return this;
}
private HPlusSupport setBlood(TransactionBuilder transaction) {
LOG.info("Attempting to set Blood...");
//TODO: Find what blood means for the band
return this;
}
private HPlusSupport setFindMe(TransactionBuilder transaction) {
LOG.info("Attempting to set Findme...");
private HPlusSupport setFindMe(TransactionBuilder transaction, boolean state) {
//TODO: Find how this works
byte[] msg = new byte[2];
msg[0] = HPlusConstants.CMD_SET_FINDME;
if (state)
msg[1] = HPlusConstants.ARG_FINDME_ON;
else
msg[1] = HPlusConstants.ARG_FINDME_OFF;
transaction.write(ctrlCharacteristic, msg);
return this;
}
private HPlusSupport requestDeviceInfo(TransactionBuilder builder) {
LOG.debug("Requesting Device Info!");
// HPlus devices seem to report some information in an alternative manner
builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_DEVICE_ID});
builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_VERSION});
@ -433,31 +403,50 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
@Override
public void pair() {
LOG.debug("Pair");
}
private void handleDeviceInfo(nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo info) {
private void handleDeviceInfo(DeviceInfo info) {
LOG.warn("Device info: " + info);
}
@Override
public void onNotification(NotificationSpec notificationSpec) {
LOG.debug("Got Notification");
//TODO: Show different notifications acccording to source as Band supports this
//TODO: Show different notifications according to source as Band supports this
showText(notificationSpec.title, notificationSpec.body);
}
@Override
public void onSetTime() {
TransactionBuilder builder = new TransactionBuilder("time");
setCurrentDate(builder);
setCurrentTime(builder);
builder.queue(getQueue());
}
@Override
public void onSetAlarms(ArrayList<? extends Alarm> alarms) {
if (alarms.size() == 0)
return;
for (Alarm alarm : alarms) {
if (!alarm.isEnabled())
continue;
if (alarm.isSmartWakeup()) //Not available
continue;
Calendar t = alarm.getAlarmCal();
TransactionBuilder builder = new TransactionBuilder("alarm");
setAlarm(builder, t);
builder.queue(getQueue());
return; //Only first alarm
}
}
@ -524,19 +513,22 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
@Override
public void onFetchActivityData() {
if(syncHelper != null)
if (syncHelper != null)
syncHelper.sync();
}
@Override
public void onReboot() {
getQueue().clear();
TransactionBuilder builder = new TransactionBuilder("Shutdown");
builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SHUTDOWN, HPlusConstants.ARG_SHUTDOWN_EN});
builder.queue(getQueue());
}
@Override
public void onHeartRateTest() {
LOG.debug("On HeartRateTest");
getQueue().clear();
TransactionBuilder builder = new TransactionBuilder("HeartRateTest");
@ -547,8 +539,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
@Override
public void onEnableRealtimeHeartRateMeasurement(boolean enable) {
LOG.debug("Set Real Time HR Measurement: " + enable);
getQueue().clear();
TransactionBuilder builder = new TransactionBuilder("realTimeHeartMeasurement");
@ -561,35 +551,24 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SET_ALLDAY_HRM, state});
builder.queue(getQueue());
}
@Override
public void onFindDevice(boolean start) {
LOG.debug("Find Me");
try {
TransactionBuilder builder = performInitialized("findMe");
byte[] msg = new byte[2];
msg[0] = HPlusConstants.CMD_SET_FINDME;
if (start)
msg[1] = HPlusConstants.ARG_FINDME_ON;
else
msg[1] = HPlusConstants.ARG_FINDME_OFF;
builder.write(ctrlCharacteristic, msg);
setFindMe(builder, start);
builder.queue(getQueue());
} catch (IOException e) {
GB.toast(getContext(), "Error toogling Find Me: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
GB.toast(getContext(), "Error toggling Find Me: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
}
}
@Override
public void onSetConstantVibration(int intensity) {
LOG.debug("Vibration Trigger");
getQueue().clear();
try {
@ -615,6 +594,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
@Override
public void onEnableHeartRateSleepSupport(boolean enable) {
onEnableRealtimeHeartRateMeasurement(enable);
}
@ -641,8 +621,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
private void showIncomingCall(String name, String number) {
LOG.debug("Show Incoming Call");
try {
TransactionBuilder builder = performInitialized("incomingCallIcon");
@ -652,7 +630,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
//Show Call Icon
builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_ACTION_INCOMING_CALL, HPlusConstants.ARG_INCOMING_CALL});
//builder = performInitialized("incomingCallText");
builder.queue(getQueue());
//TODO: Use WaitAction
@ -714,18 +691,10 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
}
}
private void showText(String message) {
showText(null, message);
}
private void showText(String title, String body) {
LOG.debug("Show Notification");
try {
TransactionBuilder builder = performInitialized("notification");
byte[] msg = new byte[20];
for (int i = 0; i < msg.length; i++)
msg[i] = ' ';
@ -790,11 +759,11 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
}
}
public boolean isExpectedDevice(BluetoothDevice device) {
return true;
}
public void close() {
private void close() {
if (syncHelper != null) {
syncHelper.quit();
syncHelper = null;
}
}
@Override
@ -811,29 +780,24 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
switch (data[0]) {
case HPlusConstants.DATA_VERSION:
syncHelper.processVersion(data);
case HPlusConstants.DATA_STATS: {
syncHelper.processRealtimeStats(data);
return true;
}
case HPlusConstants.DATA_SLEEP: {
syncHelper.processIncomingSleepData(data);
return true;
}
case HPlusConstants.DATA_STEPS:{
syncHelper.processStepStats(data);
return true;
}
return syncHelper.processVersion(data);
case HPlusConstants.DATA_STATS:
return syncHelper.processRealtimeStats(data);
case HPlusConstants.DATA_SLEEP:
return syncHelper.processIncomingSleepData(data);
case HPlusConstants.DATA_STEPS:
return syncHelper.processStepStats(data);
case HPlusConstants.DATA_DAY_SUMMARY:
case HPlusConstants.DATA_DAY_SUMMARY_ALT:
syncHelper.processIncomingDaySlotData(data);
return true;
return syncHelper.processIncomingDaySlotData(data);
default:
LOG.info("Unhandled characteristic changed: " + characteristicUUID);
LOG.debug("Unhandled characteristic changed: " + characteristicUUID);
return true;
}
return false;
}
}