mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-25 18:15:49 +01:00
HPlus: Support of Makibes F68 and small fixes to HPlus devices
This commit is contained in:
parent
5d3028c123
commit
b3e1cbf55e
@ -15,8 +15,8 @@ public final class HPlusConstants {
|
||||
public static final UUID UUID_SERVICE_HP = UUID.fromString("14701820-620a-3973-7c78-9cfff0876abd");
|
||||
|
||||
|
||||
public static final byte ARG_COUNTRY_CN = 1;
|
||||
public static final byte ARG_COUNTRY_OTHER = 2;
|
||||
public static final byte ARG_LANGUAGE_CN = 1;
|
||||
public static final byte ARG_LANGUAGE_EN = 2;
|
||||
|
||||
public static final byte ARG_TIMEMODE_24H = 0;
|
||||
public static final byte ARG_TIMEMODE_12H = 1;
|
||||
@ -111,7 +111,7 @@ public final class HPlusConstants {
|
||||
public static final String PREF_HPLUS_ALERT_TIME = "hplus_alert_time";
|
||||
public static final String PREF_HPLUS_SIT_START_TIME = "hplus_sit_start_time";
|
||||
public static final String PREF_HPLUS_SIT_END_TIME = "hplus_sit_end_time";
|
||||
public static final String PREF_HPLUS_COUNTRY = "hplus_country";
|
||||
public static final String PREF_HPLUS_LANGUAGE = "hplus_language";
|
||||
|
||||
public static final Map<Character, Byte> transliterateMap = new HashMap<Character, Byte>(){
|
||||
{
|
||||
|
@ -38,8 +38,8 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public class HPlusCoordinator extends AbstractDeviceCoordinator {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HPlusCoordinator.class);
|
||||
private static Prefs prefs = GBApplication.getPrefs();
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(HPlusCoordinator.class);
|
||||
protected static Prefs prefs = GBApplication.getPrefs();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
@ -144,8 +144,8 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator {
|
||||
return activityUser.getStepsGoal();
|
||||
}
|
||||
|
||||
public static byte getCountry(String address) {
|
||||
return (byte) prefs.getInt(HPlusConstants.PREF_HPLUS_COUNTRY + "_" + address, 10);
|
||||
public static byte getLanguage(String address) {
|
||||
return (byte) prefs.getInt(HPlusConstants.PREF_HPLUS_LANGUAGE + "_" + address, HPlusConstants.ARG_LANGUAGE_EN);
|
||||
|
||||
}
|
||||
|
||||
|
@ -141,30 +141,46 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
|
||||
today.set(Calendar.SECOND, 0);
|
||||
today.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
int stepsToday = 0;
|
||||
int stepsTodayMax = 0;
|
||||
int stepsTodayCount = 0;
|
||||
HPlusHealthActivitySample lastSample = null;
|
||||
|
||||
for(HPlusHealthActivitySample sample: samples){
|
||||
if(sample.getTimestamp() >= today.getTimeInMillis() / 1000){
|
||||
//Only consider these for the current day as a single message is enough for steps
|
||||
//HR and Overlays will still benefit from the full set of samples
|
||||
|
||||
/**Strategy is:
|
||||
* Calculate max steps from realtime messages
|
||||
* Calculate sum of steps from day 10 minute slot summaries
|
||||
*/
|
||||
|
||||
if(sample.getRawKind() == HPlusDataRecord.TYPE_REALTIME) {
|
||||
int aux = sample.getSteps();
|
||||
sample.setSteps(sample.getSteps() - stepsToday);
|
||||
stepsToday = aux;
|
||||
}else
|
||||
sample.setSteps(ActivitySample.NOT_MEASURED);
|
||||
stepsTodayMax = Math.max(stepsTodayMax, sample.getSteps());
|
||||
}else if(sample.getRawKind() == HPlusDataRecord.TYPE_DAY_SLOT) {
|
||||
stepsTodayCount += sample.getSteps();
|
||||
}
|
||||
|
||||
sample.setSteps(ActivitySample.NOT_MEASURED);
|
||||
lastSample = sample;
|
||||
}else{
|
||||
if (sample.getRawKind() != HPlusDataRecord.TYPE_DAY_SUMMARY) {
|
||||
sample.setSteps(ActivityKind.TYPE_NOT_MEASURED);
|
||||
sample.setSteps(ActivitySample.NOT_MEASURED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(lastSample != null)
|
||||
lastSample.setSteps(Math.max(stepsTodayCount, stepsTodayMax));
|
||||
|
||||
for (HPlusHealthActivityOverlay overlay : overlayRecords) {
|
||||
|
||||
//Create fake events to improve activity counters if there are no events around the overlay
|
||||
//timestamp boundaries
|
||||
//Insert one before, one at the beginning, one at the end, and one 1s after.
|
||||
insertVirtualItem(samples, Math.max(overlay.getTimestampFrom() - 1, timestamp_from), 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());
|
||||
insertVirtualItem(samples, Math.min(overlay.getTimestampTo(), timestamp_to), overlay.getDeviceId(), overlay.getUserId());
|
||||
|
||||
for (HPlusHealthActivitySample sample : samples) {
|
||||
|
||||
if (sample.getTimestamp() >= overlay.getTimestampFrom() && sample.getTimestamp() < overlay.getTimestampTo()) {
|
||||
@ -191,7 +207,7 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
|
||||
userId, // User id
|
||||
null, // Raw Data
|
||||
ActivityKind.TYPE_UNKNOWN,
|
||||
0, // Intensity
|
||||
1, // Intensity
|
||||
ActivitySample.NOT_MEASURED, // Steps
|
||||
ActivitySample.NOT_MEASURED, // HR
|
||||
ActivitySample.NOT_MEASURED, // Distance
|
||||
|
@ -0,0 +1,33 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.hplus;
|
||||
|
||||
/*
|
||||
* @author João Paulo Barraca <jpbarraca@gmail.com>
|
||||
*/
|
||||
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||
|
||||
/**
|
||||
* Pseudo Coordinator for the Makibes F68, a sub type of the HPLUS devices
|
||||
*/
|
||||
public class MakibesF68Coordinator extends HPlusCoordinator {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DeviceType getSupportedType(GBDeviceCandidate candidate) {
|
||||
String name = candidate.getDevice().getName();
|
||||
if(name != null && name.startsWith("SPORT")){
|
||||
return DeviceType.MAKIBESF68;
|
||||
}
|
||||
|
||||
return DeviceType.UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceType getDeviceType() {
|
||||
return DeviceType.MAKIBESF68;
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ public enum DeviceType {
|
||||
VIBRATISSIMO(20),
|
||||
LIVEVIEW(30),
|
||||
HPLUS(40),
|
||||
MAKIBESF68(50),
|
||||
TEST(1000);
|
||||
|
||||
private final int key;
|
||||
|
@ -10,6 +10,7 @@ import java.util.EnumSet;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.liveview.LiveviewSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.MiBandSupport;
|
||||
@ -98,7 +99,10 @@ public class DeviceSupportFactory {
|
||||
deviceSupport = new ServiceDeviceSupport(new LiveviewSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
case HPLUS:
|
||||
deviceSupport = new ServiceDeviceSupport(new HPlusSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
deviceSupport = new ServiceDeviceSupport(new HPlusSupport(DeviceType.HPLUS), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
case MAKIBESF68:
|
||||
deviceSupport = new ServiceDeviceSupport(new HPlusSupport(DeviceType.MAKIBESF68), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
}
|
||||
if (deviceSupport != null) {
|
||||
|
@ -8,7 +8,7 @@ import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
|
||||
|
||||
public class HPlusDataRecordDaySlot extends HPlusDataRecord {
|
||||
@ -47,9 +47,9 @@ public class HPlusDataRecordDaySlot extends HPlusDataRecord {
|
||||
heartRate = data[1] & 0xFF;
|
||||
|
||||
if(heartRate == 255 || heartRate == 0)
|
||||
heartRate = ActivityKind.TYPE_NOT_MEASURED;
|
||||
heartRate = ActivitySample.NOT_MEASURED;
|
||||
|
||||
steps = (data[2] & 0xFF) * 256 + data[3] & 0xFF;
|
||||
steps = (data[2] & 0xFF) * 256 + (data[3] & 0xFF);
|
||||
|
||||
//?? data[6]; atemp?? always 0
|
||||
secondsInactive = data[7] & 0xFF; // ?
|
||||
@ -69,16 +69,21 @@ public class HPlusDataRecordDaySlot extends HPlusDataRecord {
|
||||
return String.format(Locale.US, "Slot: %d, Time: %s, Steps: %d, InactiveSeconds: %d, HeartRate: %d", slot, slotTime.getTime(), steps, secondsInactive, heartRate);
|
||||
}
|
||||
|
||||
public void add(HPlusDataRecordDaySlot other){
|
||||
public void accumulate(HPlusDataRecordDaySlot other){
|
||||
if(other == null)
|
||||
return;
|
||||
|
||||
steps += other.steps;
|
||||
secondsInactive += other.secondsInactive;
|
||||
if(heartRate == -1)
|
||||
if(steps == ActivitySample.NOT_MEASURED)
|
||||
steps = other.steps;
|
||||
else if(other.steps != ActivitySample.NOT_MEASURED)
|
||||
steps += other.steps;
|
||||
|
||||
if(heartRate == ActivitySample.NOT_MEASURED)
|
||||
heartRate = other.heartRate;
|
||||
else if(other.heartRate != -1) {
|
||||
else if(other.heartRate != ActivitySample.NOT_MEASURED) {
|
||||
heartRate = (heartRate + other.heartRate) / 2;
|
||||
}
|
||||
|
||||
secondsInactive += other.secondsInactive;
|
||||
}
|
||||
}
|
||||
|
@ -60,8 +60,8 @@ class HPlusDataRecordRealtime extends HPlusDataRecord {
|
||||
timestamp = (int) (GregorianCalendar.getInstance().getTimeInMillis() / 1000);
|
||||
distance = 10 * ((data[4] & 0xFF) * 256 + (data[3] & 0xFF)); // meters
|
||||
steps = (data[2] & 0xFF) * 256 + (data[1] & 0xFF);
|
||||
int x = (data[6] & 0xFF) * 256 + data[5] & 0xFF;
|
||||
int y = (data[8] & 0xFF) * 256 + data[7] & 0xFF;
|
||||
int x = (data[6] & 0xFF) * 256 + (data[5] & 0xFF);
|
||||
int y = (data[8] & 0xFF) * 256 + (data[7] & 0xFF);
|
||||
|
||||
battery = data[9];
|
||||
|
||||
|
@ -8,7 +8,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.hplus;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.util.Log;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -19,8 +18,6 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
@ -52,8 +49,6 @@ class HPlusHandlerThread extends GBDeviceIoThread {
|
||||
private int DAY_SUMMARY_SYNC_PERIOD = 24 * 60 * 60;
|
||||
private int DAY_SUMMARY_SYNC_RETRY_PERIOD = 30;
|
||||
|
||||
private int HELLO_INTERVAL = 60;
|
||||
|
||||
private boolean mQuit = false;
|
||||
private HPlusSupport mHPlusSupport;
|
||||
|
||||
@ -61,7 +56,6 @@ class HPlusHandlerThread extends GBDeviceIoThread {
|
||||
private int mLastSlotRequested = 0;
|
||||
|
||||
private Calendar mLastSleepDayReceived = GregorianCalendar.getInstance();
|
||||
private Calendar mHelloTime = GregorianCalendar.getInstance();
|
||||
private Calendar mGetDaySlotsTime = GregorianCalendar.getInstance();
|
||||
private Calendar mGetSleepTime = GregorianCalendar.getInstance();
|
||||
private Calendar mGetDaySummaryTime = GregorianCalendar.getInstance();
|
||||
@ -72,7 +66,9 @@ class HPlusHandlerThread extends GBDeviceIoThread {
|
||||
|
||||
private final Object waitObject = new Object();
|
||||
|
||||
List<HPlusDataRecordDaySlot> mDaySlotSamples = new ArrayList<>();
|
||||
List<HPlusDataRecordDaySlot> mDaySlotRecords = new ArrayList<>();
|
||||
|
||||
private HPlusDataRecordDaySlot mCurrentDaySlot = null;
|
||||
|
||||
public HPlusHandlerThread(GBDevice gbDevice, Context context, HPlusSupport hplusSupport) {
|
||||
super(gbDevice, context);
|
||||
@ -113,10 +109,6 @@ class HPlusHandlerThread extends GBDeviceIoThread {
|
||||
|
||||
Calendar now = GregorianCalendar.getInstance();
|
||||
|
||||
if (now.compareTo(mHelloTime) > 0) {
|
||||
sendHello();
|
||||
}
|
||||
|
||||
if (now.compareTo(mGetDaySlotsTime) > 0) {
|
||||
requestNextDaySlots();
|
||||
}
|
||||
@ -130,7 +122,7 @@ class HPlusHandlerThread extends GBDeviceIoThread {
|
||||
}
|
||||
|
||||
now = GregorianCalendar.getInstance();
|
||||
waitTime = Math.min(mGetDaySummaryTime.getTimeInMillis(), Math.min(Math.min(mGetDaySlotsTime.getTimeInMillis(), mGetSleepTime.getTimeInMillis()), mHelloTime.getTimeInMillis())) - now.getTimeInMillis();
|
||||
waitTime = Math.min(mGetDaySummaryTime.getTimeInMillis(), Math.min(mGetDaySlotsTime.getTimeInMillis(), mGetSleepTime.getTimeInMillis())) - now.getTimeInMillis();
|
||||
}
|
||||
|
||||
}
|
||||
@ -152,54 +144,22 @@ class HPlusHandlerThread extends GBDeviceIoThread {
|
||||
mSlotsInitialSync = true;
|
||||
mLastSlotReceived = -1;
|
||||
mLastSlotRequested = 0;
|
||||
mCurrentDaySlot = null;
|
||||
mDaySlotRecords.clear();
|
||||
|
||||
TransactionBuilder builder = new TransactionBuilder("startSyncDayStats");
|
||||
|
||||
builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_DEVICE_ID});
|
||||
builder.wait(400);
|
||||
builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_VERSION});
|
||||
builder.wait(400);
|
||||
|
||||
builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_SLEEP});
|
||||
builder.wait(400);
|
||||
builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_DAY_DATA});
|
||||
builder.wait(400);
|
||||
builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_ACTIVE_DAY});
|
||||
builder.wait(400);
|
||||
builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_CURR_DATA});
|
||||
|
||||
builder.queue(mHPlusSupport.getQueue());
|
||||
scheduleHello();
|
||||
|
||||
synchronized (waitObject) {
|
||||
waitObject.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an Hello/Null Packet to keep connection
|
||||
*/
|
||||
private void sendHello() {
|
||||
TransactionBuilder builder = new TransactionBuilder("hello");
|
||||
|
||||
builder.write(mHPlusSupport.ctrlCharacteristic, HPlusConstants.CMD_ACTION_HELLO);
|
||||
builder.queue(mHPlusSupport.getQueue());
|
||||
|
||||
scheduleHello();
|
||||
|
||||
synchronized (waitObject) {
|
||||
waitObject.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule an Hello Packet in the future
|
||||
*/
|
||||
public void scheduleHello(){
|
||||
mHelloTime = GregorianCalendar.getInstance();
|
||||
mHelloTime.add(Calendar.SECOND, HELLO_INTERVAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message containing information regarding a day slot
|
||||
* A slot summarizes 10 minutes of data
|
||||
@ -218,32 +178,56 @@ class HPlusHandlerThread extends GBDeviceIoThread {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Ignore real time messages as they are still not understood
|
||||
if(!mSlotsInitialSync){
|
||||
mGetDaySlotsTime.set(Calendar.SECOND, CURRENT_DAY_SYNC_PERIOD);
|
||||
return true;
|
||||
}
|
||||
|
||||
Calendar now = GregorianCalendar.getInstance();
|
||||
int nowSlot = now.get(Calendar.HOUR_OF_DAY) * 6 + (now.get(Calendar.MINUTE) / 10);
|
||||
|
||||
//If the slot is in the future, actually it is from the previous day
|
||||
//Subtract a day of seconds
|
||||
if(record.slot >= nowSlot){
|
||||
record.timestamp -= 3600 * 24;
|
||||
if(record.slot == nowSlot){
|
||||
if(mCurrentDaySlot != null && mCurrentDaySlot != record){
|
||||
mCurrentDaySlot.accumulate(record);
|
||||
mDaySlotRecords.add(mCurrentDaySlot);
|
||||
mCurrentDaySlot = null;
|
||||
}else{
|
||||
//Store it to a temp variable as this is an intermediate value
|
||||
mCurrentDaySlot = record;
|
||||
if(!mSlotsInitialSync)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//Ignore out of order messages
|
||||
if(record.slot == mLastSlotReceived + 1) {
|
||||
mLastSlotReceived = record.slot;
|
||||
if(mSlotsInitialSync) {
|
||||
|
||||
//If the slot is in the future, actually it is from the previous day
|
||||
//Subtract a day of seconds
|
||||
if(record.slot > nowSlot){
|
||||
record.timestamp -= 3600 * 24;
|
||||
}
|
||||
|
||||
if (record.slot == mLastSlotReceived + 1) {
|
||||
mLastSlotReceived = record.slot;
|
||||
}
|
||||
|
||||
//Ignore the current slot as it is incomplete
|
||||
if(record.slot != nowSlot)
|
||||
mDaySlotRecords.add(record);
|
||||
|
||||
//Still fetching ring buffer. Request the next slots
|
||||
if (record.slot == mLastSlotRequested) {
|
||||
mGetDaySlotsTime.clear();
|
||||
synchronized (waitObject) {
|
||||
waitObject.notify();
|
||||
}
|
||||
}
|
||||
|
||||
//Keep buffering
|
||||
if(record.slot != 143)
|
||||
return true;
|
||||
} else {
|
||||
mGetDaySlotsTime = GregorianCalendar.getInstance();
|
||||
mGetDaySlotsTime.add(Calendar.DAY_OF_MONTH, 1);
|
||||
}
|
||||
|
||||
if(record.slot < 143){
|
||||
mDaySlotSamples.add(record);
|
||||
}else {
|
||||
|
||||
if(mDaySlotRecords.size() > 0) {
|
||||
//Sort the samples
|
||||
Collections.sort(mDaySlotSamples, new Comparator<HPlusDataRecordDaySlot>() {
|
||||
Collections.sort(mDaySlotRecords, new Comparator<HPlusDataRecordDaySlot>() {
|
||||
public int compare(HPlusDataRecordDaySlot one, HPlusDataRecordDaySlot other) {
|
||||
return one.timestamp - other.timestamp;
|
||||
}
|
||||
@ -253,20 +237,20 @@ class HPlusHandlerThread extends GBDeviceIoThread {
|
||||
HPlusHealthSampleProvider provider = new HPlusHealthSampleProvider(getDevice(), dbHandler.getDaoSession());
|
||||
List<HPlusHealthActivitySample> samples = new ArrayList<>();
|
||||
|
||||
for(HPlusDataRecordDaySlot storedRecord : mDaySlotSamples) {
|
||||
for (HPlusDataRecordDaySlot storedRecord : mDaySlotRecords) {
|
||||
HPlusHealthActivitySample sample = createSample(dbHandler, storedRecord.timestamp);
|
||||
|
||||
sample.setRawHPlusHealthData(record.getRawData());
|
||||
sample.setSteps(record.steps);
|
||||
sample.setHeartRate(record.heartRate);
|
||||
sample.setRawKind(record.type);
|
||||
sample.setRawHPlusHealthData(storedRecord.getRawData());
|
||||
sample.setSteps(storedRecord.steps);
|
||||
sample.setHeartRate(storedRecord.heartRate);
|
||||
sample.setRawKind(storedRecord.type);
|
||||
|
||||
sample.setProvider(provider);
|
||||
samples.add(sample);
|
||||
}
|
||||
|
||||
provider.getSampleDao().insertOrReplaceInTx(samples);
|
||||
mDaySlotSamples.clear();
|
||||
mDaySlotRecords.clear();
|
||||
|
||||
} catch (GBException ex) {
|
||||
LOG.debug((ex.getMessage()));
|
||||
@ -274,13 +258,6 @@ class HPlusHandlerThread extends GBDeviceIoThread {
|
||||
LOG.debug(ex.getMessage());
|
||||
}
|
||||
}
|
||||
//Still fetching ring buffer. Request the next slots
|
||||
if (record.slot == mLastSlotRequested) {
|
||||
mGetDaySlotsTime.clear();
|
||||
synchronized (waitObject) {
|
||||
waitObject.notify();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -357,6 +334,7 @@ class HPlusHandlerThread extends GBDeviceIoThread {
|
||||
LOG.debug((e.getMessage()));
|
||||
return false;
|
||||
}
|
||||
|
||||
//Skip duplicated messages as the device seems to send the same record multiple times
|
||||
//This can be used to detect the user is moving (not sleeping)
|
||||
if(prevRealTimeRecord != null && record.same(prevRealTimeRecord))
|
||||
@ -490,7 +468,6 @@ class HPlusHandlerThread extends GBDeviceIoThread {
|
||||
* Messages will be provided every 10 minutes after they are available
|
||||
*/
|
||||
private void requestNextDaySlots() {
|
||||
|
||||
Calendar now = GregorianCalendar.getInstance();
|
||||
int currentSlot = now.get(Calendar.HOUR_OF_DAY) * 6 + now.get(Calendar.MINUTE) / 10;
|
||||
|
||||
|
@ -33,6 +33,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
@ -54,6 +55,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
|
||||
public BluetoothGattCharacteristic measureCharacteristic = null;
|
||||
|
||||
private HPlusHandlerThread syncHelper;
|
||||
private DeviceType deviceType = DeviceType.UNKNOWN;
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
@ -65,8 +67,11 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
};
|
||||
|
||||
public HPlusSupport() {
|
||||
public HPlusSupport(DeviceType type) {
|
||||
super(LOG);
|
||||
|
||||
deviceType = type;
|
||||
|
||||
addSupportedService(GattService.UUID_SERVICE_GENERIC_ACCESS);
|
||||
addSupportedService(GattService.UUID_SERVICE_GENERIC_ATTRIBUTE);
|
||||
addSupportedService(HPlusConstants.UUID_SERVICE_HP);
|
||||
@ -75,7 +80,6 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
|
||||
broadcastManager.registerReceiver(mReceiver, intentFilter);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -107,7 +111,9 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
|
||||
sendUserInfo(builder); //Sync preferences
|
||||
setSIT(builder); //Sync SIT Interval
|
||||
setCurrentDate(builder); // Sync Current Date
|
||||
setDayOfWeek(builder);
|
||||
setCurrentTime(builder); // Sync Current Time
|
||||
setLanguage(builder);
|
||||
|
||||
requestDeviceInfo(builder);
|
||||
|
||||
@ -133,51 +139,69 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
|
||||
private HPlusSupport syncPreferences(TransactionBuilder transaction) {
|
||||
byte gender = HPlusCoordinator.getUserGender(getDevice().getAddress());
|
||||
byte age = HPlusCoordinator.getUserAge(getDevice().getAddress());
|
||||
byte bodyHeight = HPlusCoordinator.getUserHeight(getDevice().getAddress());
|
||||
byte bodyWeight = HPlusCoordinator.getUserWeight(getDevice().getAddress());
|
||||
int goal = HPlusCoordinator.getGoal(getDevice().getAddress());
|
||||
byte displayTime = HPlusCoordinator.getScreenTime(getDevice().getAddress());
|
||||
byte country = HPlusCoordinator.getCountry(getDevice().getAddress());
|
||||
byte social = HPlusCoordinator.getSocial(getDevice().getAddress()); // ??
|
||||
byte allDayHeart = HPlusCoordinator.getAllDayHR(getDevice().getAddress());
|
||||
byte wrist = HPlusCoordinator.getUserWrist(getDevice().getAddress());
|
||||
byte alertTimeHour = 0;
|
||||
byte alertTimeMinute = 0;
|
||||
|
||||
if (HPlusCoordinator.getSWAlertTime(getDevice().getAddress())) {
|
||||
int t = HPlusCoordinator.getAlertTime(getDevice().getAddress());
|
||||
if(deviceType == DeviceType.HPLUS) {
|
||||
byte gender = HPlusCoordinator.getUserGender(getDevice().getAddress());
|
||||
byte age = HPlusCoordinator.getUserAge(getDevice().getAddress());
|
||||
byte bodyHeight = HPlusCoordinator.getUserHeight(getDevice().getAddress());
|
||||
byte bodyWeight = HPlusCoordinator.getUserWeight(getDevice().getAddress());
|
||||
int goal = HPlusCoordinator.getGoal(getDevice().getAddress());
|
||||
byte displayTime = HPlusCoordinator.getScreenTime(getDevice().getAddress());
|
||||
byte country = HPlusCoordinator.getLanguage(getDevice().getAddress());
|
||||
byte social = HPlusCoordinator.getSocial(getDevice().getAddress()); // ??
|
||||
byte allDayHeart = HPlusCoordinator.getAllDayHR(getDevice().getAddress());
|
||||
byte wrist = HPlusCoordinator.getUserWrist(getDevice().getAddress());
|
||||
byte alertTimeHour = 0;
|
||||
byte alertTimeMinute = 0;
|
||||
|
||||
alertTimeHour = (byte) ((t / 256) & 0xff);
|
||||
alertTimeMinute = (byte) (t % 256);
|
||||
if (HPlusCoordinator.getSWAlertTime(getDevice().getAddress())) {
|
||||
int t = HPlusCoordinator.getAlertTime(getDevice().getAddress());
|
||||
|
||||
alertTimeHour = (byte) ((t / 256) & 0xff);
|
||||
alertTimeMinute = (byte) (t % 256);
|
||||
}
|
||||
|
||||
byte unit = HPlusCoordinator.getUnit(getDevice().getAddress());
|
||||
byte timemode = HPlusCoordinator.getTimeMode((getDevice().getAddress()));
|
||||
|
||||
transaction.write(ctrlCharacteristic, new byte[]{
|
||||
HPlusConstants.CMD_SET_PREFS,
|
||||
gender,
|
||||
age,
|
||||
bodyHeight,
|
||||
bodyWeight,
|
||||
0,
|
||||
0,
|
||||
(byte) ((goal / 256) & 0xff),
|
||||
(byte) (goal % 256),
|
||||
displayTime,
|
||||
country,
|
||||
0,
|
||||
social,
|
||||
allDayHeart,
|
||||
wrist,
|
||||
0,
|
||||
alertTimeHour,
|
||||
alertTimeMinute,
|
||||
unit,
|
||||
timemode
|
||||
});
|
||||
|
||||
}else if(deviceType == DeviceType.MAKIBESF68){
|
||||
//Makibes doesn't support setting everything at once.
|
||||
|
||||
setGender(transaction);
|
||||
setAge(transaction);
|
||||
setWeight(transaction);
|
||||
setHeight(transaction);
|
||||
setGoal(transaction);
|
||||
setLanguage(transaction);
|
||||
setScreenTime(transaction);
|
||||
//setAlarm(transaction, t);
|
||||
setUnit(transaction);
|
||||
setTimeMode(transaction);
|
||||
}
|
||||
|
||||
byte unit = HPlusCoordinator.getUnit(getDevice().getAddress());
|
||||
byte timemode = HPlusCoordinator.getTimeMode((getDevice().getAddress()));
|
||||
|
||||
transaction.write(ctrlCharacteristic, new byte[]{
|
||||
HPlusConstants.CMD_SET_PREFS,
|
||||
gender,
|
||||
age,
|
||||
bodyHeight,
|
||||
bodyWeight,
|
||||
0,
|
||||
0,
|
||||
(byte) ((goal / 256) & 0xff),
|
||||
(byte) (goal % 256),
|
||||
displayTime,
|
||||
country,
|
||||
0,
|
||||
social,
|
||||
allDayHeart,
|
||||
wrist,
|
||||
0,
|
||||
alertTimeHour,
|
||||
alertTimeMinute,
|
||||
unit,
|
||||
timemode
|
||||
});
|
||||
|
||||
setAllDayHeart(transaction);
|
||||
|
||||
@ -185,7 +209,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
|
||||
private HPlusSupport setLanguage(TransactionBuilder transaction) {
|
||||
byte value = HPlusCoordinator.getCountry(getDevice().getAddress());
|
||||
byte value = HPlusCoordinator.getLanguage(getDevice().getAddress());
|
||||
transaction.write(ctrlCharacteristic, new byte[]{
|
||||
HPlusConstants.CMD_SET_LANGUAGE,
|
||||
value
|
||||
@ -248,13 +272,20 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
transaction.write(ctrlCharacteristic, new byte[]{
|
||||
HPlusConstants.CMD_SET_WEEK,
|
||||
(byte) c.get(Calendar.DAY_OF_WEEK)
|
||||
(byte) (c.get(Calendar.DAY_OF_WEEK) - 1)
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
private HPlusSupport setSIT(TransactionBuilder transaction) {
|
||||
|
||||
//Makibes F68 doesn't like this command.
|
||||
//Just ignore.
|
||||
if(deviceType == DeviceType.MAKIBESF68){
|
||||
return this;
|
||||
}
|
||||
|
||||
int startTime = HPlusCoordinator.getSITStartTime(getDevice().getAddress());
|
||||
int endTime = HPlusCoordinator.getSITEndTime(getDevice().getAddress());
|
||||
|
||||
@ -646,8 +677,17 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
|
||||
|
||||
private void showIncomingCall(String name, String number) {
|
||||
private void showIncomingCall(String name, String rawNumber) {
|
||||
try {
|
||||
StringBuilder number = new StringBuilder();
|
||||
|
||||
//Clean up number as the device only accepts digits
|
||||
for(char c : rawNumber.toCharArray()){
|
||||
if(Character.isDigit(c)){
|
||||
number.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
TransactionBuilder builder = performInitialized("incomingCall");
|
||||
|
||||
//Enable call notifications
|
||||
|
@ -23,6 +23,7 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.UnknownDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.MakibesF68Coordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.liveview.LiveviewCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Coordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||
@ -172,6 +173,8 @@ public class DeviceHelper {
|
||||
result.add(new VibratissimoCoordinator());
|
||||
result.add(new LiveviewCoordinator());
|
||||
result.add(new HPlusCoordinator());
|
||||
result.add(new MakibesF68Coordinator());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user