Huawei: fixes related to new sleep calculation

This commit is contained in:
Me7c7
2025-08-02 17:03:50 +02:00
committed by José Rebelo
parent 4997c9a901
commit 0ae90fe5c3
6 changed files with 158 additions and 15 deletions
@@ -58,7 +58,7 @@ public class GBDaoGenerator {
public static void main(String[] args) throws Exception {
final Schema schema = new Schema(108, MAIN_PACKAGE + ".entities");
final Schema schema = new Schema(109, MAIN_PACKAGE + ".entities");
Entity userAttributes = addUserAttributes(schema);
Entity user = addUserInfo(schema, userAttributes);
@@ -1559,13 +1559,11 @@ public class GBDaoGenerator {
private static Entity addHuaweiSleepStatsSample(Schema schema, Entity user, Entity device) {
Entity sample = addEntity(schema, "HuaweiSleepStatsSample");
sample.addImport(MAIN_PACKAGE + ".model.SleepScoreSample");
addCommonTimeSampleProperties("AbstractTimeSample", sample, user, device);
sample.implementsInterface("SleepScoreSample");
sample.addIntProperty("sleepScore").notNull().codeBeforeGetter(OVERRIDE);
sample.addIntProperty("sleepScore").notNull();
sample.addLongProperty("bedTime").notNull();
sample.addLongProperty("risingTime").notNull();
sample.addLongProperty("wakeupTime").notNull();
final Property wakeupTime = sample.addLongProperty("wakeupTime").notNull().getProperty();
sample.addIntProperty("sleepDataQuality").notNull();
sample.addIntProperty("deepPart").notNull();
sample.addIntProperty("snoreFreq").notNull();
@@ -1577,6 +1575,11 @@ public class GBDaoGenerator {
sample.addDoubleProperty("maxOxygenSaturation").notNull();
sample.addDoubleProperty("minBreathRate").notNull();
sample.addDoubleProperty("maxBreathRate").notNull();
final Index indexWakeUp = new Index();
indexWakeUp.addProperty(wakeupTime);
sample.addIndex(indexWakeUp);
return sample;
}
@@ -0,0 +1,22 @@
package nodomain.freeyourgadget.gadgetbridge.database.schema;
import android.database.sqlite.SQLiteDatabase;
import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript;
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiSleepStatsSample;
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiSleepStatsSampleDao;
public class GadgetbridgeUpdate_109 implements DBUpdateScript {
@Override
public void upgradeSchema(SQLiteDatabase db) {
String IDX_NAME = "IDX_" + HuaweiSleepStatsSampleDao.TABLENAME + "_" + HuaweiSleepStatsSampleDao.Properties.WakeupTime.columnName;
String CREATE_WAKEUP_TIME_INDEX = "CREATE INDEX IF NOT EXISTS " + IDX_NAME + " ON " + HuaweiSleepStatsSampleDao.TABLENAME + "("
+ HuaweiSleepStatsSampleDao.Properties.WakeupTime.columnName + ");";
db.execSQL(CREATE_WAKEUP_TIME_INDEX);
}
@Override
public void downgradeSchema(SQLiteDatabase db) {
}
}
@@ -267,7 +267,7 @@ public abstract class HuaweiBRCoordinator extends AbstractBLClassicDeviceCoordin
@Override
public TimeSampleProvider<? extends SleepScoreSample> getSleepScoreProvider(final GBDevice device, final DaoSession session) {
return new HuaweiSleepStatsSampleProvider(device, session);
return new HuaweiSleepScoreSampleProvider(device, session);
}
@Override
@@ -275,7 +275,7 @@ public abstract class HuaweiLECoordinator extends AbstractBLEDeviceCoordinator i
@Override
public TimeSampleProvider<? extends SleepScoreSample> getSleepScoreProvider(final GBDevice device, final DaoSession session) {
return new HuaweiSleepStatsSampleProvider(device, session);
return new HuaweiSleepScoreSampleProvider(device, session);
}
@Override
@@ -69,6 +69,7 @@ public class HuaweiSampleProvider extends AbstractSampleProvider<HuaweiActivityS
public static final int TRUSLEEP_REM = 0x5656;
public static final int TRUSLEEP_AWAKE = 0x5658;
public static final int TRUSLEEP_NAP = 0x5659;
}
public HuaweiSampleProvider(GBDevice device, DaoSession session) {
@@ -82,6 +83,7 @@ public class HuaweiSampleProvider extends AbstractSampleProvider<HuaweiActivityS
case RawTypes.LIGHT_SLEEP -> ActivityKind.LIGHT_SLEEP;
case RawTypes.TRUSLEEP_REM -> ActivityKind.REM_SLEEP;
case RawTypes.TRUSLEEP_AWAKE -> ActivityKind.AWAKE_SLEEP;
case RawTypes.TRUSLEEP_NAP -> ActivityKind.LIGHT_SLEEP; // TODO:
default -> ActivityKind.UNKNOWN;
};
}
@@ -298,13 +300,20 @@ public class HuaweiSampleProvider extends AbstractSampleProvider<HuaweiActivityS
return samples;
}
private static int adjustTimeToMinute(int time) {
private static int adjustTimeSecToMinute(int time) {
if (time % 60 != 0) {
time = (time / 60) * 60;
}
return time;
}
private static long adjustTimeMillisToMinute(long time) {
if (time % 60000L != 0) {
time = (time / 60000L) * 60000L;
}
return time;
}
/*
* This takes the following three steps:
* - Generate a sample every minute
@@ -315,8 +324,8 @@ public class HuaweiSampleProvider extends AbstractSampleProvider<HuaweiActivityS
protected List<HuaweiActivitySample> getGBActivitySamples(int timestamp_from, int timestamp_to) {
List<HuaweiActivitySample> processedSamples = new ArrayList<>();
timestamp_from = adjustTimeToMinute(timestamp_from);
timestamp_to = adjustTimeToMinute(timestamp_to);
timestamp_from = adjustTimeSecToMinute(timestamp_from);
timestamp_to = adjustTimeSecToMinute(timestamp_to);
for (int timestamp = timestamp_from; timestamp <= timestamp_to; timestamp += 60) {
processedSamples.add(createDummySample(timestamp));
@@ -331,8 +340,8 @@ public class HuaweiSampleProvider extends AbstractSampleProvider<HuaweiActivityS
@Override
protected List<HuaweiActivitySample> getGBActivitySamplesHighRes(int timestamp_from, int timestamp_to) {
timestamp_from = adjustTimeToMinute(timestamp_from);
timestamp_to = adjustTimeToMinute(timestamp_to);
timestamp_from = adjustTimeSecToMinute(timestamp_from);
timestamp_to = adjustTimeSecToMinute(timestamp_to);
List<HuaweiActivitySample> processedSamples = getRawOrderedActivitySamples(timestamp_from, timestamp_to);
addWorkoutSamples(processedSamples, timestamp_from, timestamp_to);
@@ -571,7 +580,7 @@ public class HuaweiSampleProvider extends AbstractSampleProvider<HuaweiActivityS
case 2 -> RawTypes.TRUSLEEP_REM;
case 3 -> RawTypes.DEEP_SLEEP;
case 4 -> RawTypes.TRUSLEEP_AWAKE;
//case 5 -> RawTypes.UNKNOWN;
case 5 -> RawTypes.TRUSLEEP_NAP;
default -> RawTypes.UNKNOWN;
};
}
@@ -586,8 +595,8 @@ public class HuaweiSampleProvider extends AbstractSampleProvider<HuaweiActivityS
if (!sleepStatsSamples.isEmpty()) {
for(HuaweiSleepStatsSample sample: sleepStatsSamples) {
final List<HuaweiSleepStageSample> stageSamples = sleepStageSampleProvider.getAllSamples(
sample.getTimestamp(),
sample.getWakeupTime() - 60000L
adjustTimeMillisToMinute(sample.getTimestamp()),
adjustTimeMillisToMinute(sample.getWakeupTime()) - 60000L
);
for (final HuaweiSleepStageSample stageSample : stageSamples) {
stagesMap.put(stageSample.getTimestamp(), toActivityKind(stageSample));
@@ -0,0 +1,109 @@
package nodomain.freeyourgadget.gadgetbridge.devices.huawei;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiSleepStatsSample;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.SleepScoreSample;
public class HuaweiSleepScoreSampleProvider implements TimeSampleProvider<HuaweiSleepScoreSampleProvider.HuaweiSleepScoreSample> {
private final GBDevice device;
private final DaoSession session;
public HuaweiSleepScoreSampleProvider(GBDevice device, DaoSession session) {
this.device = device;
this.session = session;
}
public static class HuaweiSleepScoreSample implements SleepScoreSample {
long timestamp;
int score;
public HuaweiSleepScoreSample(long timestamp, int score) {
this.timestamp = timestamp;
this.score = score;
}
@Override
public int getSleepScore() {
return score;
}
@Override
public long getTimestamp() {
return timestamp;
}
}
@NonNull
@Override
public List<HuaweiSleepScoreSample> getAllSamples(long timestamp_from, long timestamp_to) {
List<HuaweiSleepScoreSample> ret = new ArrayList<>();
final HuaweiSleepStatsSampleProvider sleepStatsSampleProvider = new HuaweiSleepStatsSampleProvider(this.device, this.session);
List<HuaweiSleepStatsSample> sleepStatsSamples = sleepStatsSampleProvider.getSleepSamples(timestamp_from, timestamp_to);
for (HuaweiSleepStatsSample sample : sleepStatsSamples) {
if (sample.getSleepScore() > 0)
ret.add(new HuaweiSleepScoreSample(sample.getWakeupTime(), sample.getSleepScore()));
}
return ret;
}
@Override
public void addSample(HuaweiSleepScoreSample timeSample) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public void addSamples(List<HuaweiSleepScoreSample> timeSamples) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public HuaweiSleepScoreSample createSample() {
throw new UnsupportedOperationException("read-only sample provider");
}
@Nullable
@Override
public HuaweiSleepScoreSample getLatestSample() {
final HuaweiSleepStatsSampleProvider sleepStatsSampleProvider = new HuaweiSleepStatsSampleProvider(this.device, this.session);
HuaweiSleepStatsSample sample = sleepStatsSampleProvider.getLatestSample();
if (sample == null)
return null;
return new HuaweiSleepScoreSample(sample.getWakeupTime(), sample.getSleepScore());
}
@Nullable
@Override
public HuaweiSleepScoreSample getLatestSample(final long until) {
final HuaweiSleepStatsSampleProvider sleepStatsSampleProvider = new HuaweiSleepStatsSampleProvider(this.device, this.session);
HuaweiSleepStatsSample sample = sleepStatsSampleProvider.getLatestSample(until);
if (sample == null)
return null;
return new HuaweiSleepScoreSample(sample.getWakeupTime(), sample.getSleepScore());
}
@Nullable
@Override
public HuaweiSleepScoreSample getFirstSample() {
final HuaweiSleepStatsSampleProvider sleepStatsSampleProvider = new HuaweiSleepStatsSampleProvider(this.device, this.session);
HuaweiSleepStatsSample sample = sleepStatsSampleProvider.getFirstSample();
if (sample == null)
return null;
return new HuaweiSleepScoreSample(sample.getWakeupTime(), sample.getSleepScore());
}
}