From 4cf872664cb3bc3954c7f88d3459b3aff3a128bd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Joa=CC=83o=20Paulo=20Barraca?= <jpbarraca@gmail.com>
Date: Tue, 10 Jan 2017 13:08:45 +0000
Subject: [PATCH] HPlus: Improved support for storing and displaying data.

---
 .../devices/hplus/HPlusConstants.java         |  29 +-
 .../devices/hplus/HPlusCoordinator.java       |   4 +
 .../hplus/HPlusHealthSampleProvider.java      |  76 ++-
 .../devices/hplus/HPlusDataRecord.java        |  17 +-
 .../devices/hplus/HPlusDataRecordDaySlot.java |  31 +-
 .../hplus/HPlusDataRecordDaySummary.java      |   4 +-
 .../hplus/HPlusDataRecordRealtime.java        |  21 +-
 .../devices/hplus/HPlusDataRecordSleep.java   |  14 +-
 .../devices/hplus/HPlusHandlerThread.java     | 484 +++++++++++-------
 .../service/devices/hplus/HPlusSupport.java   |  44 +-
 10 files changed, 466 insertions(+), 258 deletions(-)

diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java
index 70546e87b..5feaf6d7d 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusConstants.java
@@ -28,8 +28,8 @@ public final class HPlusConstants {
     public static final byte ARG_HEARTRATE_MEASURE_ON = 11;
     public static final byte ARG_HEARTRATE_MEASURE_OFF = 22;
 
-    public static final byte ARG_HEARTRATE_ALLDAY_ON = 10;
-    public static final byte ARG_HEARTRATE_ALLDAY_OFF = -1;
+    public static final byte ARG_HEARTRATE_ALLDAY_ON = 0x0A;
+    public static final byte ARG_HEARTRATE_ALLDAY_OFF = (byte) 0xff;
 
     public static final byte INCOMING_CALL_STATE_DISABLED_THRESHOLD = 0x7B;
     public static final byte INCOMING_CALL_STATE_ENABLED = (byte) 0xAA;
@@ -64,9 +64,7 @@ public final class HPlusConstants {
     public static final byte CMD_SET_CONF_END = 0x4f;
     public static final byte CMD_SET_PREFS = 0x50;
     public static final byte CMD_SET_SIT_INTERVAL = 0x51;
-
-    public static final byte[] COMMAND_FACTORY_RESET = new byte[] {-74, 90};
-
+    public static final byte CMD_SET_HEARTRATE_STATE = 0x32;
 
     //Actions to device
     public static final byte CMD_GET_ACTIVE_DAY = 0x27;
@@ -76,19 +74,17 @@ public final class HPlusConstants {
     public static final byte CMD_GET_DEVICE_ID = 0x24;
 
     public static final byte CMD_ACTION_INCOMING_SOCIAL = 0x31;
-    //public static final byte COMMAND_ACTION_INCOMING_SMS = 0x40;
+    //public static final byte COMMAND_ACTION_INCOMING_SMS = 0x40; //Unknown
     public static final byte CMD_ACTION_DISPLAY_TEXT = 0x43;
 
     public static final byte CMD_ACTION_DISPLAY_TEXT_NAME = 0x3F;
     public static final byte CMD_ACTION_DISPLAY_TEXT_NAME_CN = 0x3E; //Text in GB2312?
-    public static final byte[] CMD_ACTION_HELLO = new byte[]{0x01, 0};
-    public static final byte CMD_SHUTDOWN = 91;
-    public static final byte ARG_SHUTDOWN_EN = 90;
+    public static final byte[] CMD_ACTION_HELLO = new byte[]{0x01, 0x00};
+    public static final byte CMD_SHUTDOWN = 0x5B;
+    public static final byte ARG_SHUTDOWN_EN = 0x5A;
 
     public static final byte CMD_FACTORY_RESET = -74;
-    public static final byte ARG_FACTORY_RESET_EN = 90;
-
-
+    public static final byte ARG_FACTORY_RESET_EN = 0x5A;
 
     public static final byte CMD_SET_INCOMING_MESSAGE = 0x07;
     public static final byte CMD_SET_INCOMING_CALL = 0x06;
@@ -103,15 +99,9 @@ public final class HPlusConstants {
     public static final byte DATA_SLEEP = 0x1A;
     public static final byte DATA_VERSION = 0x18;
 
-
-    public static final byte DB_TYPE_DAY_SLOT_SUMMARY = 1;
-    public static final byte DB_TYPE_DAY_SUMMARY = 2;
-    public static final byte DB_TYPE_INSTANT_STATS = 3;
-    public static final byte DB_TYPE_SLEEP_STATS = 4;
-
-
     public static final String PREF_HPLUS_SCREENTIME = "hplus_screentime";
     public static final String PREF_HPLUS_ALLDAYHR = "hplus_alldayhr";
+    public static final String PREF_HPLUS_HR = "hplus_hr_enable";
     public static final String PREF_HPLUS_UNIT = "hplus_unit";
     public static final String PREF_HPLUS_TIMEMODE = "hplus_timemode";
     public static final String PREF_HPLUS_WRIST = "hplus_wrist";
@@ -120,5 +110,4 @@ public final class HPlusConstants {
     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";
-
 }
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java
index 3de594b62..8a596d4ce 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusCoordinator.java
@@ -198,6 +198,10 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator {
         return (byte) (prefs.getInt(HPlusConstants.PREF_HPLUS_ALLDAYHR + "_" + address, HPlusConstants.ARG_HEARTRATE_ALLDAY_ON) & 0xFF);
     }
 
+    public static byte getHRState(String address) {
+        return (byte) (prefs.getInt(HPlusConstants.PREF_HPLUS_HR + "_" + address, HPlusConstants.ARG_HEARTRATE_MEASURE_ON) & 0xFF);
+    }
+
     public static byte getSocial(String address) {
         //TODO: Figure what this is. Returning the default value
 
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusHealthSampleProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusHealthSampleProvider.java
index 3fe16e41f..9a7fa8c1c 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusHealthSampleProvider.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/HPlusHealthSampleProvider.java
@@ -5,9 +5,12 @@ package nodomain.freeyourgadget.gadgetbridge.devices.hplus;
 */
 
 import android.support.annotation.NonNull;
+import android.util.Log;
 
+import java.util.Calendar;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.GregorianCalendar;
 import java.util.List;
 
 import de.greenrobot.dao.AbstractDao;
@@ -25,6 +28,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.HPlusHealthActivitySampleDa
 import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
 import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
 import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.hplus.HPlusDataRecord;
 
 public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealthActivitySample> {
 
@@ -44,13 +48,28 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
     }
 
     public int normalizeType(int rawType) {
-
-        return rawType;
+        switch (rawType){
+            case HPlusDataRecord.TYPE_DAY_SLOT:
+            case HPlusDataRecord.TYPE_DAY_SUMMARY:
+            case HPlusDataRecord.TYPE_REALTIME:
+            case HPlusDataRecord.TYPE_SLEEP:
+            case HPlusDataRecord.TYPE_UNKNOWN:
+                return ActivityKind.TYPE_UNKNOWN;
+            default:
+                return rawType;
+        }
     }
 
     public int toRawActivityKind(int activityKind) {
+        switch (activityKind){
+            case ActivityKind.TYPE_DEEP_SLEEP:
+                return ActivityKind.TYPE_DEEP_SLEEP;
+            case ActivityKind.TYPE_LIGHT_SLEEP:
+                return ActivityKind.TYPE_LIGHT_SLEEP;
+            default:
+                return HPlusDataRecord.TYPE_DAY_SLOT;
+        }
 
-        return activityKind;
     }
 
     @NonNull
@@ -85,6 +104,15 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
         return getSession().getHPlusHealthActivitySampleDao();
     }
 
+
+    public List<HPlusHealthActivitySample> getActivityamples(int timestamp_from, int timestamp_to) {
+        return getAllActivitySamples(timestamp_from, timestamp_to);
+    }
+
+    public List<HPlusHealthActivitySample> getSleepSamples(int timestamp_from, int timestamp_to) {
+        return getAllActivitySamples(timestamp_from, timestamp_to);
+    }
+
     @NonNull
     @Override
     public List<HPlusHealthActivitySample> getAllActivitySamples(int timestamp_from, int timestamp_to) {
@@ -97,16 +125,48 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
 
         QueryBuilder<HPlusHealthActivityOverlay> qb = getSession().getHPlusHealthActivityOverlayDao().queryBuilder();
 
-        qb.where(HPlusHealthActivityOverlayDao.Properties.DeviceId.eq(dbDevice.getId()), HPlusHealthActivityOverlayDao.Properties.TimestampFrom.ge(timestamp_from))
-                .where(HPlusHealthActivityOverlayDao.Properties.TimestampTo.le(timestamp_to));
+        qb.where(HPlusHealthActivityOverlayDao.Properties.DeviceId.eq(dbDevice.getId()),
+                HPlusHealthActivityOverlayDao.Properties.TimestampFrom.ge(timestamp_from - 3600 * 24),
+                HPlusHealthActivityOverlayDao.Properties.TimestampTo.le(timestamp_to),
+                HPlusHealthActivityOverlayDao.Properties.TimestampTo.ge(timestamp_from));
 
         List<HPlusHealthActivityOverlay> overlayRecords = qb.build().list();
 
+        //Todays sample steps will come from the Day Slots messages
+        //Historical steps will be provided by Day Summaries messages
+        //This will allow both week and current day results to be consistent
+        Calendar today = GregorianCalendar.getInstance();
+        today.set(Calendar.HOUR_OF_DAY, 0);
+        today.set(Calendar.MINUTE, 0);
+        today.set(Calendar.SECOND, 0);
+        today.set(Calendar.MILLISECOND, 0);
+
+        int stepsToday = 0;
+        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
+                 if(sample.getRawKind() == HPlusDataRecord.TYPE_REALTIME) {
+                    int aux = sample.getSteps();
+                    sample.setSteps(sample.getSteps() - stepsToday);
+                    stepsToday = aux;
+                }else
+                    sample.setSteps(ActivitySample.NOT_MEASURED);
+            }else{
+                if (sample.getRawKind() != HPlusDataRecord.TYPE_DAY_SUMMARY) {
+                    sample.setSteps(ActivityKind.TYPE_NOT_MEASURED);
+                }
+            }
+        }
+
         for (HPlusHealthActivityOverlay overlay : overlayRecords) {
+
+            //Create fake events to improve activity counters if there are no events around the overlay
+            //timestamp boundaries
             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 (sample.getTimestamp() >= overlay.getTimestampFrom() && sample.getTimestamp() < overlay.getTimestampTo()) {
                     sample.setRawKind(overlay.getRawKind());
                 }
@@ -124,7 +184,7 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
         return samples;
     }
 
-    private List<HPlusHealthActivitySample> insertVirtualItem(List<HPlusHealthActivitySample> samples, int timestamp, long deviceId, long userId){
+    private List<HPlusHealthActivitySample> insertVirtualItem(List<HPlusHealthActivitySample> samples, int timestamp, long deviceId, long userId) {
         HPlusHealthActivitySample sample = new HPlusHealthActivitySample(
                 timestamp,            // ts
                 deviceId,
@@ -143,5 +203,5 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
 
         return samples;
     }
-
 }
+
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecord.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecord.java
index d2c96471e..b116b00a5 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecord.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecord.java
@@ -8,7 +8,13 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
 
 
 public  class HPlusDataRecord {
-    public final static int TYPE_SLEEP = 1;
+    public final static int TYPE_UNKNOWN = 0;
+    public final static int TYPE_SLEEP = 100;
+    public final static int TYPE_DAY_SUMMARY = 101;
+    public final static int TYPE_DAY_SLOT = 102;
+    public final static int TYPE_REALTIME = 103;
+
+    public int type = TYPE_UNKNOWN;
     public int activityKind = ActivityKind.TYPE_UNKNOWN;
 
     /**
@@ -21,8 +27,13 @@ public  class HPlusDataRecord {
      */
     public byte[] rawData;
 
-    public HPlusDataRecord(byte[] data){
-        rawData = data;
+    protected HPlusDataRecord(){
+
+    }
+
+    protected HPlusDataRecord(byte[] data, int type){
+        this.rawData = data;
+        this.type = type;
     }
 
     public byte[] getRawData() {
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordDaySlot.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordDaySlot.java
index 5f9e310dc..c742e0461 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordDaySlot.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordDaySlot.java
@@ -4,6 +4,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.hplus;
 * @author João Paulo Barraca &lt;jpbarraca@gmail.com&gt;
 */
 
+import java.util.Calendar;
 import java.util.GregorianCalendar;
 import java.util.Locale;
 
@@ -35,7 +36,7 @@ public class HPlusDataRecordDaySlot extends HPlusDataRecord {
     public int heartRate;
 
     public HPlusDataRecordDaySlot(byte[] data) {
-        super(data);
+        super(data, TYPE_DAY_SLOT);
 
         int a = (data[4] & 0xFF) * 256 + (data[5] & 0xFF);
         if (a >= 144) {
@@ -50,14 +51,34 @@ public class HPlusDataRecordDaySlot extends HPlusDataRecord {
 
         steps = (data[2] & 0xFF) * 256 + data[3] & 0xFF;
 
-        //?? data[6];
+        //?? data[6]; atemp?? always 0
         secondsInactive = data[7] & 0xFF; // ?
 
-        int now = (int) (GregorianCalendar.getInstance().getTimeInMillis() / (3600 * 24 * 1000L));
-        timestamp = now * 3600 * 24 + (slot / 6 * 3600 + slot % 6 * 10);
+        Calendar slotTime = GregorianCalendar.getInstance();
+
+        slotTime.set(Calendar.MINUTE, (slot % 6) * 10);
+        slotTime.set(Calendar.HOUR_OF_DAY, slot / 6);
+        slotTime.set(Calendar.SECOND, 0);
+
+        timestamp = (int) (slotTime.getTimeInMillis() / 1000L);
     }
 
     public String toString(){
-        return String.format(Locale.US, "Slot: %d, Steps: %d, InactiveSeconds: %d, HeartRate: %d", slot, steps, secondsInactive, heartRate);
+        Calendar slotTime = GregorianCalendar.getInstance();
+        slotTime.setTimeInMillis(timestamp * 1000L);
+        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){
+        if(other == null)
+            return;
+
+        steps += other.steps;
+        secondsInactive += other.secondsInactive;
+        if(heartRate == -1)
+            heartRate = other.heartRate;
+        else if(other.heartRate != -1) {
+            heartRate = (heartRate + other.heartRate) / 2;
+        }
     }
 }
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordDaySummary.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordDaySummary.java
index 0bb6609c6..e28960f98 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordDaySummary.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordDaySummary.java
@@ -60,7 +60,7 @@ class HPlusDataRecordDaySummary extends HPlusDataRecord{
     public int calories;
 
     HPlusDataRecordDaySummary(byte[] data) {
-        super(data);
+        super(data, TYPE_DAY_SUMMARY);
 
         year =  (data[10] & 0xFF) * 256 + (data[9] & 0xFF);
         month = data[11] & 0xFF;
@@ -75,7 +75,7 @@ class HPlusDataRecordDaySummary extends HPlusDataRecord{
             throw new IllegalArgumentException("Invalid record date "+year+"-"+month+"-"+day);
         }
         steps = (data[2] & 0xFF) * 256 + (data[1] & 0xFF);
-        distance = (data[4] & 0xFF) * 256 + (data[3] & 0xFF);
+        distance = ((data[4] & 0xFF) * 256 + (data[3] & 0xFF)) * 10;
         activeTime = (data[14] & 0xFF) * 256 + (data[13] & 0xFF);
         calories = (data[6] & 0xFF) * 256 + (data[5] & 0xFF);
         calories += (data[8] & 0xFF) * 256 + (data[7] & 0xFF);
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordRealtime.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordRealtime.java
index d827976d6..8b39f84f7 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordRealtime.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordRealtime.java
@@ -33,6 +33,11 @@ class HPlusDataRecordRealtime extends HPlusDataRecord {
      */
     public byte battery;
 
+    /**
+     * Number of steps today
+     */
+    public int steps;
+
     /**
      * Time active (To be determined how it works)
      */
@@ -45,7 +50,7 @@ class HPlusDataRecordRealtime extends HPlusDataRecord {
     public int intensity;
 
     public HPlusDataRecordRealtime(byte[] data) {
-        super(data);
+        super(data, TYPE_REALTIME);
 
         if (data.length < 15) {
             throw new IllegalArgumentException("Invalid data packet");
@@ -53,7 +58,7 @@ 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;
 
@@ -63,10 +68,14 @@ class HPlusDataRecordRealtime extends HPlusDataRecord {
 
         heartRate = data[11] & 0xFF; // BPM
         activeTime = (data[14] & 0xFF * 256) + (data[13] & 0xFF);
-        if(heartRate == 255)
+        if(heartRate == 255) {
             intensity = 0;
-        else
+            activityKind = ActivityKind.TYPE_NOT_MEASURED;
+        }
+        else {
             intensity = (int) (100 * Math.max(0, Math.min((heartRate - 60) / 120.0, 1))); // TODO: Calculate a proper value
+            activityKind = ActivityKind.TYPE_UNKNOWN;
+        }
     }
 
     public void computeActivity(HPlusDataRecordRealtime prev){
@@ -93,11 +102,11 @@ class HPlusDataRecordRealtime extends HPlusDataRecord {
         if(other == null)
             return false;
 
-        return distance == other.distance && calories == other.calories && heartRate == other.heartRate && battery == other.battery;
+        return steps == other.steps && 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);
+        return String.format(Locale.US, "Distance: %d Steps: %d Calories: %d HeartRate: %d Battery: %d ActiveTime: %d Intensity: %d", distance, steps, calories, heartRate, battery, activeTime, intensity);
     }
 
 }
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordSleep.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordSleep.java
index 97ea0294f..f74db8fb9 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordSleep.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusDataRecordSleep.java
@@ -9,6 +9,7 @@ import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
 import java.util.List;
+import java.util.Locale;
 
 import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
 
@@ -67,7 +68,7 @@ public class HPlusDataRecordSleep extends HPlusDataRecord {
     public int wakeupCount;
 
     public HPlusDataRecordSleep(byte[] data) {
-        super(data);
+        super(data, TYPE_SLEEP);
 
         int year = (data[2] & 0xFF) * 256 + (data[1] & 0xFF);
         int month = data[3] & 0xFF;
@@ -91,6 +92,7 @@ public class HPlusDataRecordSleep extends HPlusDataRecord {
         int minute = data[18] & 0xFF;
 
         Calendar sleepStart = GregorianCalendar.getInstance();
+        sleepStart.clear();
         sleepStart.set(Calendar.YEAR, year);
         sleepStart.set(Calendar.MONTH, month - 1);
         sleepStart.set(Calendar.DAY_OF_MONTH, day);
@@ -114,4 +116,14 @@ public class HPlusDataRecordSleep extends HPlusDataRecord {
         intervals.add(new RecordInterval(ts, bedTimeEnd, ActivityKind.TYPE_DEEP_SLEEP));
         return intervals;
     }
+
+    public String toString(){
+        Calendar s = GregorianCalendar.getInstance();
+        s.setTimeInMillis(bedTimeStart * 1000L);
+
+        Calendar end = GregorianCalendar.getInstance();
+        end.setTimeInMillis(bedTimeEnd * 1000L);
+
+        return String.format(Locale.US, "Sleep start: %s end: %s enter: %d spindles: %d rem: %d deep: %d wake: %d-%d", s.getTime(), end.getTime(), enterSleepMinutes, spindleMinutes, remSleepMinutes, deepSleepMinutes, wakeupMinutes, wakeupCount);
+    }
 }
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusHandlerThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusHandlerThread.java
index 93715fce7..d8e5de5a3 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusHandlerThread.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusHandlerThread.java
@@ -6,14 +6,21 @@ 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;
 
 import java.util.ArrayList;
 import java.util.Calendar;
+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;
@@ -28,6 +35,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.HPlusHealthActivitySample;
 import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
 import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
 import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
+import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
 import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
 import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread;
 
@@ -35,20 +43,22 @@ import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread;
 class HPlusHandlerThread extends GBDeviceIoThread {
     private static final Logger LOG = LoggerFactory.getLogger(HPlusHandlerThread.class);
 
-    private int CURRENT_DAY_SYNC_PERIOD = 60 * 10;
+    private int CURRENT_DAY_SYNC_PERIOD = 24 * 60 * 60 * 365; //Never
     private int CURRENT_DAY_SYNC_RETRY_PERIOD = 10;
+
     private int SLEEP_SYNC_PERIOD = 12 * 60 * 60;
     private int SLEEP_SYNC_RETRY_PERIOD = 30;
 
     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;
-    private int mLastSlotReceived = 0;
+
+    private int mLastSlotReceived = -1;
     private int mLastSlotRequested = 0;
-    private int mSlotsToRequest = 6;
 
     private Calendar mLastSleepDayReceived = GregorianCalendar.getInstance();
     private Calendar mHelloTime = GregorianCalendar.getInstance();
@@ -56,10 +66,13 @@ class HPlusHandlerThread extends GBDeviceIoThread {
     private Calendar mGetSleepTime = GregorianCalendar.getInstance();
     private Calendar mGetDaySummaryTime = GregorianCalendar.getInstance();
 
+    private boolean mSlotsInitialSync = true;
+
     private HPlusDataRecordRealtime prevRealTimeRecord = null;
 
     private final Object waitObject = new Object();
-    List<HPlusHealthActivitySample> mDaySlotSamples = new ArrayList<>();
+
+    List<HPlusDataRecordDaySlot> mDaySlotSamples = new ArrayList<>();
 
     public HPlusHandlerThread(GBDevice gbDevice, Context context, HPlusSupport hplusSupport) {
         super(gbDevice, context);
@@ -78,7 +91,7 @@ class HPlusHandlerThread extends GBDeviceIoThread {
 
         long waitTime = 0;
         while (!mQuit) {
-            //LOG.debug("Waiting " + (waitTime));
+
             if (waitTime > 0) {
                 synchronized (waitObject) {
                     try {
@@ -88,10 +101,16 @@ class HPlusHandlerThread extends GBDeviceIoThread {
                     }
                 }
             }
+
             if (mQuit) {
                 break;
             }
 
+            if(!mHPlusSupport.getDevice().isConnected()){
+                quit();
+                break;
+            }
+
             Calendar now = GregorianCalendar.getInstance();
 
             if (now.compareTo(mHelloTime) > 0) {
@@ -111,7 +130,7 @@ class HPlusHandlerThread extends GBDeviceIoThread {
             }
 
             now = GregorianCalendar.getInstance();
-            waitTime = Math.min(Math.min(mGetDaySlotsTime.getTimeInMillis(), mGetSleepTime.getTimeInMillis()), mHelloTime.getTimeInMillis()) - now.getTimeInMillis();
+            waitTime = Math.min(mGetDaySummaryTime.getTimeInMillis(), Math.min(Math.min(mGetDaySlotsTime.getTimeInMillis(), mGetSleepTime.getTimeInMillis()), mHelloTime.getTimeInMillis())) - now.getTimeInMillis();
         }
 
     }
@@ -128,151 +147,153 @@ class HPlusHandlerThread extends GBDeviceIoThread {
         mGetSleepTime.setTimeInMillis(0);
         mGetDaySlotsTime.setTimeInMillis(0);
         mGetDaySummaryTime.setTimeInMillis(0);
+        mLastSleepDayReceived.setTimeInMillis(0);
+
+        mSlotsInitialSync = true;
+        mLastSlotReceived = -1;
+        mLastSlotRequested = 0;
 
         TransactionBuilder builder = new TransactionBuilder("startSyncDayStats");
 
-        builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_SLEEP});
-        builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_DAY_DATA});
-        builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_ACTIVE_DAY});
         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.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SET_ALLDAY_HRM, HPlusConstants.ARG_HEARTRATE_ALLDAY_ON});
-
         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.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);
     }
 
-    public void requestDaySummaryData(){
-        TransactionBuilder builder = new TransactionBuilder("startSyncDaySummary");
-        builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_DAY_DATA});
-        builder.queue(mHPlusSupport.getQueue());
-
-        mGetDaySummaryTime = GregorianCalendar.getInstance();
-        mGetDaySummaryTime.add(Calendar.SECOND, DAY_SUMMARY_SYNC_PERIOD);
-    }
-
+    /**
+     * Process a message containing information regarding a day slot
+     * A slot summarizes 10 minutes of data
+     *
+     * @param data the message from the device
+     * @return boolean indicating success or fail
+     */
     public boolean processIncomingDaySlotData(byte[] data) {
 
         HPlusDataRecordDaySlot record;
+
         try{
             record = new HPlusDataRecordDaySlot(data);
         } catch(IllegalArgumentException e){
             LOG.debug((e.getMessage()));
+            return false;
+        }
+
+        //Ignore real time messages as they are still not understood
+        if(!mSlotsInitialSync){
+            mGetDaySlotsTime.set(Calendar.SECOND, CURRENT_DAY_SYNC_PERIOD);
             return true;
         }
-        mLastSlotReceived = record.slot;
 
-        try (DBHandler dbHandler = GBApplication.acquireDB()) {
-            HPlusHealthSampleProvider provider = new HPlusHealthSampleProvider(getDevice(), dbHandler.getDaoSession());
+        Calendar now = GregorianCalendar.getInstance();
+        int nowSlot = now.get(Calendar.HOUR_OF_DAY) * 6 + (now.get(Calendar.MINUTE) / 10);
 
-            Long userId = DBHelper.getUser(dbHandler.getDaoSession()).getId();
-            Long deviceId = DBHelper.getDevice(getDevice(), dbHandler.getDaoSession()).getId();
-            HPlusHealthActivitySample sample = new HPlusHealthActivitySample(
-                    record.timestamp,               // ts
-                    deviceId, userId,               // User id
-                    record.getRawData(),            // Raw Data
-                    ActivityKind.TYPE_UNKNOWN,
-                    0,    // Intensity
-                    record.steps,                   // Steps
-                    record.heartRate,               // HR
-                    ActivitySample.NOT_MEASURED,    // Distance
-                    ActivitySample.NOT_MEASURED     // Calories
-            );
-            sample.setProvider(provider);
-            mDaySlotSamples.add(sample);
-
-            Calendar now = GregorianCalendar.getInstance();
-
-            //Dump buffered samples to DB
-            if ((record.timestamp + (60*100) >= (now.getTimeInMillis() / 1000L) )) {
-
-                provider.getSampleDao().insertOrReplaceInTx(mDaySlotSamples);
-
-                mGetDaySlotsTime.setTimeInMillis(0);
-                mDaySlotSamples.clear();
-                mSlotsToRequest = 144 - mLastSlotReceived;
-            }
-        } catch (GBException ex) {
-            LOG.debug((ex.getMessage()));
-        } catch (Exception ex) {
-            LOG.debug(ex.getMessage());
+        //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;
         }
 
-        //Request next slot
-        if(mLastSlotReceived == mLastSlotRequested){
+        //Ignore out of order messages
+        if(record.slot == mLastSlotReceived + 1) {
+            mLastSlotReceived = record.slot;
+        }
+
+        if(record.slot < 143){
+            mDaySlotSamples.add(record);
+        }else {
+
+            //Sort the samples
+            Collections.sort(mDaySlotSamples, new Comparator<HPlusDataRecordDaySlot>() {
+                public int compare(HPlusDataRecordDaySlot one, HPlusDataRecordDaySlot other) {
+                    return one.timestamp - other.timestamp;
+                }
+            });
+
+            try (DBHandler dbHandler = GBApplication.acquireDB()) {
+                HPlusHealthSampleProvider provider = new HPlusHealthSampleProvider(getDevice(), dbHandler.getDaoSession());
+                List<HPlusHealthActivitySample> samples = new ArrayList<>();
+
+                for(HPlusDataRecordDaySlot storedRecord : mDaySlotSamples) {
+                    HPlusHealthActivitySample sample = createSample(dbHandler, storedRecord.timestamp);
+
+                    sample.setRawHPlusHealthData(record.getRawData());
+                    sample.setSteps(record.steps);
+                    sample.setHeartRate(record.heartRate);
+                    sample.setRawKind(record.type);
+
+                    sample.setProvider(provider);
+                    samples.add(sample);
+                }
+
+                provider.getSampleDao().insertOrReplaceInTx(samples);
+                mDaySlotSamples.clear();
+
+            } catch (GBException ex) {
+                LOG.debug((ex.getMessage()));
+            } catch (Exception ex) {
+                LOG.debug(ex.getMessage());
+            }
+        }
+        //Still fetching ring buffer. Request the next slots
+        if (record.slot == mLastSlotRequested) {
+            mGetDaySlotsTime.clear();
             synchronized (waitObject) {
-                mGetDaySlotsTime.setTimeInMillis(0);
                 waitObject.notify();
             }
         }
 
-
         return true;
     }
 
-    private void requestNextDaySlots() {
-
-        Calendar now = GregorianCalendar.getInstance();
-
-        if (mLastSlotReceived >= 144 + 6) { // 24 * 6 + 6
-            LOG.debug("Reached End of the Day");
-            mLastSlotReceived = 0;
-            mSlotsToRequest = 6; // 1h
-            mGetDaySlotsTime = now;
-            mGetDaySlotsTime.add(Calendar.SECOND, CURRENT_DAY_SYNC_PERIOD);
-            mLastSlotRequested = 0;
-            return;
-        }
-
-        //Sync Day Stats
-        mLastSlotRequested = Math.min(mLastSlotReceived + mSlotsToRequest, 144);
-
-        LOG.debug("Requesting slot " + mLastSlotRequested);
-
-        byte nextHour = (byte) (mLastSlotRequested / 6);
-        byte nextMinute = (byte) ((mLastSlotRequested % 6) * 10);
-
-        if (nextHour == (byte) now.get(Calendar.HOUR_OF_DAY)) {
-            nextMinute = (byte) now.get(Calendar.MINUTE);
-        }
-
-        byte hour = (byte) (mLastSlotReceived / 6);
-        byte minute = (byte) ((mLastSlotReceived % 6) * 10);
-
-        byte[] msg = new byte[]{39, hour, minute, nextHour, nextMinute};
-
-        TransactionBuilder builder = new TransactionBuilder("getNextDaySlot");
-        builder.write(mHPlusSupport.ctrlCharacteristic, msg);
-        builder.queue(mHPlusSupport.getQueue());
-
-        mGetDaySlotsTime = now;
-        if(mSlotsToRequest == 6) {
-            mGetDaySlotsTime.add(Calendar.SECOND, CURRENT_DAY_SYNC_RETRY_PERIOD);
-        }else{
-            mGetDaySlotsTime.add(Calendar.SECOND, CURRENT_DAY_SYNC_PERIOD);
-        }
-        LOG.debug("Requesting next slot " + mLastSlotRequested+ " at " + mGetDaySlotsTime.getTime());
-
-    }
 
+    /**
+     * Process sleep data from the device
+     * Devices send a single sleep message for each sleep period
+     * This message contains the duration of the sub-intervals (rem, deep, etc...)
+     *
+     * @param data the message from the device
+     * @return boolean indicating success or fail
+     */
     public boolean processIncomingSleepData(byte[] data){
         HPlusDataRecordSleep record;
 
@@ -280,7 +301,7 @@ class HPlusHandlerThread extends GBDeviceIoThread {
             record = new HPlusDataRecordSleep(data);
         } catch(IllegalArgumentException e){
             LOG.debug((e.getMessage()));
-            return true;
+            return false;
         }
 
         mLastSleepDayReceived.setTimeInMillis(record.bedTimeStart * 1000L);
@@ -293,9 +314,10 @@ class HPlusHandlerThread extends GBDeviceIoThread {
             HPlusHealthActivityOverlayDao overlayDao = session.getHPlusHealthActivityOverlayDao();
             HPlusHealthSampleProvider provider = new HPlusHealthSampleProvider(getDevice(), dbHandler.getDaoSession());
 
-            //Insert the Overlays
+            //Get the individual Sleep overlays and insert them
             List<HPlusHealthActivityOverlay> overlayList = new ArrayList<>();
             List<HPlusDataRecord.RecordInterval> intervals = record.getIntervals();
+
             for(HPlusDataRecord.RecordInterval interval : intervals){
                 overlayList.add(new HPlusHealthActivityOverlay(interval.timestampFrom, interval.timestampTo, interval.activityKind, deviceId, userId, null));
             }
@@ -303,23 +325,13 @@ class HPlusHandlerThread extends GBDeviceIoThread {
             overlayDao.insertOrReplaceInTx(overlayList);
 
             //Store the data
-            HPlusHealthActivitySample sample = new HPlusHealthActivitySample(
-                    record.timestamp,            // ts
-                    deviceId, userId,            // User id
-                    record.getRawData(),         // Raw Data
-                    record.activityKind,
-                    0,                           // Intensity
-                    ActivitySample.NOT_MEASURED, // Steps
-                    ActivitySample.NOT_MEASURED, // HR
-                    ActivitySample.NOT_MEASURED, // Distance
-                    ActivitySample.NOT_MEASURED  // Calories
-            );
+            HPlusHealthActivitySample sample = createSample(dbHandler, record.timestamp);
+            sample.setRawHPlusHealthData(record.getRawData());
+            sample.setRawKind(record.activityKind);
 
             sample.setProvider(provider);
 
             provider.addGBActivitySample(sample);
-
-
         } catch (Exception ex) {
             LOG.debug(ex.getMessage());
         }
@@ -330,16 +342,12 @@ class HPlusHandlerThread extends GBDeviceIoThread {
         return true;
     }
 
-    private void requestNextSleepData() {
-        mGetSleepTime = GregorianCalendar.getInstance();
-        mGetSleepTime.add(GregorianCalendar.SECOND, SLEEP_SYNC_RETRY_PERIOD);
-
-        TransactionBuilder builder = new TransactionBuilder("requestSleepStats");
-        builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_SLEEP});
-        builder.queue(mHPlusSupport.getQueue());
-    }
-
-
+    /**
+     * Process a message containing real time information
+     *
+     * @param data the message from the device
+     * @return boolean indicating success or fail
+     */
     public boolean processRealtimeStats(byte[] data) {
         HPlusDataRecordRealtime record;
 
@@ -347,49 +355,59 @@ class HPlusHandlerThread extends GBDeviceIoThread {
             record = new HPlusDataRecordRealtime(data);
         } catch(IllegalArgumentException e){
             LOG.debug((e.getMessage()));
-            return true;
+            return false;
         }
-
-        if(record.same(prevRealTimeRecord))
+        //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))
             return true;
 
         prevRealTimeRecord = record;
 
         getDevice().setBatteryLevel(record.battery);
-        getDevice().sendDeviceUpdateIntent(getContext());
 
-        //Skip when measuring
-        if(record.heartRate == 255) {
+        //Skip when measuring heart rate
+        //Calories and Distance are updated and these values will be lost.
+        //Because a message with a valid Heart Rate will be provided, this loss very limited
+        if(record.heartRate == ActivityKind.TYPE_NOT_MEASURED) {
             getDevice().setFirmwareVersion2("---");
             getDevice().sendDeviceUpdateIntent(getContext());
-            return true;
+        }else {
+            getDevice().setFirmwareVersion2("" + record.heartRate);
+            getDevice().sendDeviceUpdateIntent(getContext());
         }
 
-        getDevice().setFirmwareVersion2("" + record.heartRate);
-        getDevice().sendDeviceUpdateIntent(getContext());
-
         try (DBHandler dbHandler = GBApplication.acquireDB()) {
             HPlusHealthSampleProvider provider = new HPlusHealthSampleProvider(getDevice(), dbHandler.getDaoSession());
-            Long userId = DBHelper.getUser(dbHandler.getDaoSession()).getId();
-            Long deviceId = DBHelper.getDevice(getDevice(), dbHandler.getDaoSession()).getId();
 
-            HPlusHealthActivitySample sample = new HPlusHealthActivitySample(
-                    record.timestamp,            // ts
-                    deviceId, userId,            // User id
-                    record.getRawData(),         // Raw Data
-                    record.activityKind,
-                    record.intensity, // Intensity
-                    ActivitySample.NOT_MEASURED, // Steps
-                    record.heartRate,            // HR
-                    record.distance,             // Distance
-                    record.calories              // Calories
-            );
+            HPlusHealthActivitySample sample = createSample(dbHandler, record.timestamp);
+            sample.setRawKind(record.type);
+            sample.setRawIntensity(record.intensity);
+            sample.setHeartRate(record.heartRate);
+            sample.setDistance(record.distance);
+            sample.setCalories(record.calories);
+            sample.setSteps(record.steps);
 
+            sample.setRawHPlusHealthData(record.getRawData());
             sample.setProvider(provider);
+
+            if (sample.getSteps() != ActivitySample.NOT_MEASURED && sample.getSteps() - prevRealTimeRecord.steps > 0) {
+                Intent intent = new Intent(DeviceService.ACTION_REALTIME_STEPS)
+                        .putExtra(DeviceService.EXTRA_REALTIME_STEPS, sample.getSteps() - prevRealTimeRecord.steps)
+                        .putExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis());
+                LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
+            }
+
+            if (sample.getHeartRate() != ActivitySample.NOT_MEASURED) {
+                Intent intent = new Intent(DeviceService.ACTION_HEARTRATE_MEASUREMENT)
+                        .putExtra(DeviceService.EXTRA_HEART_RATE_VALUE, sample.getHeartRate())
+                        .putExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis());
+                LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
+            }
+
             provider.addGBActivitySample(sample);
 
             //TODO: Handle Active Time. With Overlay?
-
         } catch (GBException ex) {
             LOG.debug((ex.getMessage()));
         } catch (Exception ex) {
@@ -398,57 +416,35 @@ class HPlusHandlerThread extends GBDeviceIoThread {
         return true;
     }
 
-
+    /**
+     * Process a day summary message
+     * This message includes aggregates regarding an entire day
+     *
+     * @param data the message from the device
+     * @return boolean indicating success or fail
+     */
     public boolean processDaySummary(byte[] data) {
-        LOG.debug("Process Day Summary");
         HPlusDataRecordDaySummary record;
 
         try{
             record = new HPlusDataRecordDaySummary(data);
         } catch(IllegalArgumentException e){
             LOG.debug((e.getMessage()));
-            return true;
+            return false;
         }
-        LOG.debug("Received: " + record);
 
         try (DBHandler dbHandler = GBApplication.acquireDB()) {
             HPlusHealthSampleProvider provider = new HPlusHealthSampleProvider(getDevice(), dbHandler.getDaoSession());
 
-            Long userId = DBHelper.getUser(dbHandler.getDaoSession()).getId();
-            Long deviceId = DBHelper.getDevice(getDevice(), dbHandler.getDaoSession()).getId();
+            HPlusHealthActivitySample sample = createSample(dbHandler, record.timestamp);
 
-            //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,
-                    0,                              // Intensity
-                    Math.max( missingSteps, 0),     // Steps
-                    ActivitySample.NOT_MEASURED,    // HR
-                    Math.max( missingDistance, 0),  // Distance
-                    ActivitySample.NOT_MEASURED     // Calories
-            );
+            sample.setRawKind(record.type);
+            sample.setSteps(record.steps);
+            sample.setDistance(record.distance);
+            sample.setCalories(record.calories);
+            sample.setDistance(record.distance);
+            sample.setHeartRate((record.maxHeartRate - record.minHeartRate) / 2); //TODO: Find an alternative approach for Day Summary Heart Rate
+            sample.setRawHPlusHealthData(record.getRawData());
 
             sample.setProvider(provider);
             provider.addGBActivitySample(sample);
@@ -458,9 +454,17 @@ class HPlusHandlerThread extends GBDeviceIoThread {
             LOG.debug(ex.getMessage());
         }
 
+        mGetDaySummaryTime = GregorianCalendar.getInstance();
+        mGetDaySummaryTime.add(Calendar.SECOND, DAY_SUMMARY_SYNC_PERIOD);
         return true;
     }
 
+    /**
+     * Process a message containing information regarding firmware version
+     *
+     * @param data the message from the device
+     * @return boolean indicating success or fail
+     */
     public boolean processVersion(byte[] data) {
         int major = data[2] & 0xFF;
         int minor = data[1] & 0xFF;
@@ -471,4 +475,102 @@ class HPlusHandlerThread extends GBDeviceIoThread {
 
         return true;
     }
-}
\ No newline at end of file
+
+    /**
+     * Issue a message requesting the next batch of sleep data
+     */
+    private void requestNextSleepData() {
+        TransactionBuilder builder = new TransactionBuilder("requestSleepStats");
+        builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_SLEEP});
+        builder.queue(mHPlusSupport.getQueue());
+
+
+        mGetSleepTime = GregorianCalendar.getInstance();
+        mGetSleepTime.add(GregorianCalendar.SECOND, SLEEP_SYNC_RETRY_PERIOD);
+    }
+
+    /**
+     * Issue a message requesting the next set of slots
+     * The process will sync 1h at a time until the device is in sync
+     * Then it will request samples until the end of the day in order to minimize data loss
+     * 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;
+
+        //Finished dumping the entire ring buffer
+        //Sync to current time
+        mGetDaySlotsTime = now;
+
+        if(mSlotsInitialSync) {
+            if(mLastSlotReceived == 143) {
+                mSlotsInitialSync = false;
+                mGetDaySlotsTime.set(Calendar.SECOND, CURRENT_DAY_SYNC_PERIOD); //Sync complete. Delay timer forever
+                mLastSlotReceived = -1;
+                mLastSlotRequested = mLastSlotReceived + 1;
+                return;
+            }else {
+                mGetDaySlotsTime.add(Calendar.SECOND, CURRENT_DAY_SYNC_RETRY_PERIOD);
+            }
+        }else{
+            //Sync complete. Delay timer forever
+            mGetDaySlotsTime.set(Calendar.SECOND, CURRENT_DAY_SYNC_PERIOD);
+            return;
+        }
+
+        if(mLastSlotReceived == 143)
+            mLastSlotReceived = -1;
+
+        byte hour = (byte) ((mLastSlotReceived + 1)/ 6);
+        byte minute = (byte) (((mLastSlotReceived + 1) % 6) * 10);
+
+        byte nextHour = hour;
+        byte nextMinute = 59;
+
+        mLastSlotRequested = nextHour * 6 + (nextMinute / 10);
+
+        byte[] msg = new byte[]{HPlusConstants.CMD_GET_ACTIVE_DAY, hour, minute, nextHour, nextMinute};
+
+        TransactionBuilder builder = new TransactionBuilder("getNextDaySlot");
+        builder.write(mHPlusSupport.ctrlCharacteristic, msg);
+        builder.queue(mHPlusSupport.getQueue());
+    }
+    /**
+     * Request a batch of data with the summary of the previous days
+     */
+    public void requestDaySummaryData(){
+        TransactionBuilder builder = new TransactionBuilder("startSyncDaySummary");
+        builder.write(mHPlusSupport.ctrlCharacteristic, new byte[]{HPlusConstants.CMD_GET_DAY_DATA});
+        builder.queue(mHPlusSupport.getQueue());
+
+        mGetDaySummaryTime = GregorianCalendar.getInstance();
+        mGetDaySummaryTime.add(Calendar.SECOND, DAY_SUMMARY_SYNC_RETRY_PERIOD);
+    }
+
+    /**
+     * Helper function to create a sample
+     * @param dbHandler The database handler
+     * @param timestamp The sample timestamp
+     * @return The sample just created
+     */
+    private HPlusHealthActivitySample createSample(DBHandler dbHandler, int timestamp){
+        Long userId = DBHelper.getUser(dbHandler.getDaoSession()).getId();
+        Long deviceId = DBHelper.getDevice(getDevice(), dbHandler.getDaoSession()).getId();
+        HPlusHealthActivitySample sample = new HPlusHealthActivitySample(
+                timestamp,                      // ts
+                deviceId, userId,               // User id
+                null,            // Raw Data
+                ActivityKind.TYPE_UNKNOWN,
+                0,                              // Intensity
+                ActivitySample.NOT_MEASURED,     // Steps
+                ActivitySample.NOT_MEASURED,    // HR
+                ActivitySample.NOT_MEASURED,  // Distance
+                ActivitySample.NOT_MEASURED     // Calories
+        );
+
+        return sample;
+    }
+
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java
index 17e9e666b..dd229b819 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java
@@ -37,6 +37,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSuppo
 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.AbstractBleProfile;
 import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo;
 import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile;
 import nodomain.freeyourgadget.gadgetbridge.util.GB;
@@ -344,14 +345,23 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
     }
 
     private HPlusSupport setAllDayHeart(TransactionBuilder transaction) {
-        LOG.info("Attempting to set All Day HR...");
 
-        byte value = HPlusCoordinator.getAllDayHR(getDevice().getAddress());
+        byte value = HPlusCoordinator.getHRState(getDevice().getAddress());
+
+        transaction.write(ctrlCharacteristic, new byte[]{
+                HPlusConstants.CMD_SET_HEARTRATE_STATE,
+                value
+        });
+
+
+        value = HPlusCoordinator.getAllDayHR(getDevice().getAddress());
+
         transaction.write(ctrlCharacteristic, new byte[]{
                 HPlusConstants.CMD_SET_ALLDAY_HRM,
                 value
 
         });
+
         return this;
     }
 
@@ -415,6 +425,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
     @Override
     public void onNotification(NotificationSpec notificationSpec) {
         //TODO: Show different notifications according to source as Band supports this
+        //LOG.debug("OnNotification: Title: "+notificationSpec.title+" Body: "+notificationSpec.body+" Source: "+notificationSpec.sourceName+" Sender: "+notificationSpec.sender+" Subject: "+notificationSpec.subject);
         showText(notificationSpec.title, notificationSpec.body);
     }
 
@@ -534,7 +545,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
 
         TransactionBuilder builder = new TransactionBuilder("HeartRateTest");
 
-        builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SET_ALLDAY_HRM, 0x0A}); //Set Real Time... ?
+        builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SET_HEARTRATE_STATE, HPlusConstants.ARG_HEARTRATE_MEASURE_ON}); //Set Real Time... ?
         builder.queue(getQueue());
     }
 
@@ -629,20 +640,14 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
             builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_ACTION_INCOMING_CALL, 1});
 
             //Show Call Icon
-            builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_ACTION_INCOMING_CALL, HPlusConstants.ARG_INCOMING_CALL});
+            builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SET_INCOMING_CALL, HPlusConstants.ARG_INCOMING_CALL});
 
             builder.queue(getQueue());
 
-            //TODO: Use WaitAction
-            try {
-                Thread.sleep(200);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-
             byte[] msg = new byte[13];
 
             builder = performInitialized("incomingCallNumber");
+            builder.wait(200);
 
             //Show call number
             for (int i = 0; i < msg.length; i++)
@@ -657,13 +662,8 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
             builder.write(ctrlCharacteristic, msg);
             builder.queue(getQueue());
 
-            try {
-                Thread.sleep(200);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-
             builder = performInitialized("incomingCallText");
+            builder.wait(200);
 
             //Show call name
             //Must call twice, otherwise nothing happens
@@ -676,11 +676,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
             msg[0] = HPlusConstants.CMD_ACTION_DISPLAY_TEXT_NAME;
             builder.write(ctrlCharacteristic, msg);
 
-            try {
-                Thread.sleep(200);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
+            builder.wait(200);
 
             msg[0] = HPlusConstants.CMD_ACTION_DISPLAY_TEXT_NAME_CN;
             builder.write(ctrlCharacteristic, msg);
@@ -693,6 +689,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
     }
 
     private void showText(String title, String body) {
+        LOG.debug("Show Notification: "+title+" --> "+body);
         try {
             TransactionBuilder builder = performInitialized("notification");
 
@@ -720,6 +717,8 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
 
             builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_ACTION_INCOMING_SOCIAL, (byte) 255});
 
+            builder.write(ctrlCharacteristic, new byte[]{HPlusConstants.CMD_SET_INCOMING_MESSAGE, HPlusConstants.ARG_INCOMING_MESSAGE});
+
             int remaining;
 
             if (message.length() % 17 > 0)
@@ -801,4 +800,5 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
                 return true;
         }
     }
+
 }