From 8294921de746d9ea0e23afd7b509c52d4a51d05a Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Thu, 11 Feb 2016 19:14:40 +0100 Subject: [PATCH] Do not ack the sleep data until we can actually store them Added helper method to fetch the latest timestamp stored in the DB, needed for the aforementioned feature. Update changelog This closes #188 \o/ --- CHANGELOG.md | 2 +- .../database/ActivityDatabaseHandler.java | 16 ++++++++++++++-- .../gadgetbridge/database/DBHandler.java | 2 ++ .../pebble/DatalogSessionHealthSleep.java | 18 ++++++++++-------- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5970c9e2..bf9cd1359 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ###Changelog ####Version (next) -* Pebble: Support reading Pebble Health steps/activity data +* Pebble: Support Pebble Health: steps/activity data are stored correctly. Sleep time is considered as light sleep. Deep sleep is discarded. The pebble will send data where it deems appropriate, there is no action to perform on the watch for this to happen. ####Version 0.7.4 * Refactored the settings activity: User details are now generic instead of miband specific. Old settings are preserved. diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java index 32bbc8280..1d8b54b49 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java @@ -246,9 +246,9 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl @Override public void changeStoredSamplesType(int timestampFrom, int timestampTo, byte kind, SampleProvider provider) { try (SQLiteDatabase db = this.getReadableDatabase()) { - String sql = "UPDATE " + TABLE_GBACTIVITYSAMPLES + " SET " + KEY_TYPE +"= ? WHERE " + String sql = "UPDATE " + TABLE_GBACTIVITYSAMPLES + " SET " + KEY_TYPE + "= ? WHERE " + KEY_PROVIDER + " = ? AND " - + KEY_TIMESTAMP + " >= ? AND "+ KEY_TIMESTAMP + " < ? ;"; //do not use BETWEEN because the range is inclusive in that case! + + KEY_TIMESTAMP + " >= ? AND " + KEY_TIMESTAMP + " < ? ;"; //do not use BETWEEN because the range is inclusive in that case! SQLiteStatement statement = db.compileStatement(sql); statement.bindLong(1, kind); @@ -258,4 +258,16 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl statement.execute(); } } + + @Override + public int fetchLatestTimestamp(SampleProvider provider) { + try (SQLiteDatabase db = this.getReadableDatabase()) { + try (Cursor cursor = db.query(TABLE_GBACTIVITYSAMPLES, new String[]{KEY_TIMESTAMP}, KEY_PROVIDER + "=" + String.valueOf(provider.getID()), null, null, null, KEY_TIMESTAMP + " DESC", "1")) { + if (cursor.moveToFirst()) { + return cursor.getInt(0); + } + } + } + return -1; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHandler.java index 52c4ba10c..6e7398e99 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHandler.java @@ -32,4 +32,6 @@ public interface DBHandler { void changeStoredSamplesType(int timestampFrom, int timestampTo, byte kind, SampleProvider provider); + int fetchLatestTimestamp(SampleProvider provider); + } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java index 553510249..a2ec192a4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java @@ -43,36 +43,38 @@ class DatalogSessionHealthSleep extends DatalogSession { beginOfRecordPosition = initialPosition + recordIdx * itemSize; datalogMessage.position(beginOfRecordPosition);//we may not consume all the bytes of a record recordVersion = datalogMessage.getShort(); - if (recordVersion!=1) + if (recordVersion != 1) return false;//we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it sleepRecords[recordIdx] = new SleepRecord(datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt()); - } - store(sleepRecords); - return true;//ACK by default + return store(sleepRecords);//NACK if we cannot store the data yet, the watch will send the sleep records again. } - private void store(SleepRecord[] sleepRecords) { + private boolean store(SleepRecord[] sleepRecords) { DBHandler dbHandler = null; SampleProvider sampleProvider = new HealthSampleProvider(); GB.toast("We don't know how to store deep sleep from the pebble yet.", Toast.LENGTH_LONG, GB.INFO); try { dbHandler = GBApplication.acquireDB(); - for (SleepRecord sleepRecord: sleepRecords) { - dbHandler.changeStoredSamplesType(sleepRecord.bedTimeStart,sleepRecord.bedTimeEnd, sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP),sampleProvider); + int latestTimestamp = dbHandler.fetchLatestTimestamp(sampleProvider); + for (SleepRecord sleepRecord : sleepRecords) { + if (latestTimestamp < sleepRecord.bedTimeEnd) + return false; + dbHandler.changeStoredSamplesType(sleepRecord.bedTimeStart, sleepRecord.bedTimeEnd, sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider); } - }catch (Exception ex) { + } catch (Exception ex) { LOG.debug(ex.getMessage()); } finally { if (dbHandler != null) { dbHandler.release(); } } + return true; } private class SleepRecord {