Moyoung: Fix sleep data being malformed by subsequent syncs

This commit is contained in:
Arjan Schrijver
2025-06-11 20:58:00 +02:00
parent 8e5d14da84
commit 1aa0e57e77
3 changed files with 29 additions and 6 deletions
@@ -368,12 +368,14 @@ public class MoyoungConstants {
// The watch stores all dates in GMT+8 time zone with seconds resolution
// These helper functions convert between the watch time representation and local system representation
public static final TimeZone WATCH_INTERNAL_TIME_ZONE = TimeZone.getTimeZone("GMT+8");
public static int LocalTimeToWatchTime(Date localTime)
{
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
simpleDateFormat.setTimeZone(TimeZone.getDefault());
String format = simpleDateFormat.format(localTime);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+8"));
simpleDateFormat.setTimeZone(WATCH_INTERNAL_TIME_ZONE);
try {
return (int)(simpleDateFormat.parse(format).getTime() / 1000);
} catch (ParseException e) {
@@ -384,7 +386,7 @@ public class MoyoungConstants {
public static Date WatchTimeToLocalTime(int watchTime)
{
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+8"));
simpleDateFormat.setTimeZone(WATCH_INTERNAL_TIME_ZONE);
String format = simpleDateFormat.format(new Date((long)watchTime * 1000));
simpleDateFormat.setTimeZone(TimeZone.getDefault());
try {
@@ -24,6 +24,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.Logging;
@@ -129,6 +131,16 @@ public class FetchDataOperation extends AbstractBTLEOperation<MoyoungDeviceSuppo
byte[] data = new byte[payload.length - 1];
System.arraycopy(payload, 1, data, 0, data.length);
// The watch uses the GMT+8 timezone internally. The sleep identifiers below are based
// on that timezone. That means the watch thinks "yesterday" starts at a different
// moment than in our current locale.
long currentTime = System.currentTimeMillis();
final TimeZone localTZ = Calendar.getInstance().getTimeZone();
int hourDifference = (MoyoungConstants.WATCH_INTERNAL_TIME_ZONE.getOffset(currentTime) - localTZ.getOffset(currentTime)) / (1000 * 60 * 60);
int currentHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
int daysAgoOffset = 0;
if (currentHour + hourDifference >= 24) daysAgoOffset = 1;
if (dataType == MoyoungConstants.ARG_SYNC_DAY_BEFORE_YESTERDAY_STEPS) {
LOG.info("2 DAYS AGO STEPS data: " + Logging.formatBytes(data));
decodeSteps(2, data);
@@ -141,12 +153,12 @@ public class FetchDataOperation extends AbstractBTLEOperation<MoyoungDeviceSuppo
}
else if (dataType == MoyoungConstants.ARG_SYNC_DAY_BEFORE_YESTERDAY_SLEEP) {
LOG.info("2 DAYS AGO SLEEP data: " + Logging.formatBytes(data));
decodeSleep(2, data);
decodeSleep(2 - daysAgoOffset, data);
return true;
}
else if (dataType == MoyoungConstants.ARG_SYNC_YESTERDAY_SLEEP) {
LOG.info("YESTERDAY SLEEP data: " + Logging.formatBytes(data));
decodeSleep(1, data);
decodeSleep(1 - daysAgoOffset, data);
return true;
}
}
@@ -20,6 +20,7 @@ import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.os.Handler;
import android.text.format.DateFormat;
@@ -1242,6 +1243,10 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
if (data.length % 3 != 0)
throw new IllegalArgumentException();
SharedPreferences sharedPreferences = getDevicePrefs().getPreferences();
long prefLastSyncTime = sharedPreferences.getLong("lastSyncTimeMillis", 0);
sharedPreferences.edit().putLong("lastSyncTimeMillis", System.currentTimeMillis()).apply();
try (DBHandler dbHandler = GBApplication.acquireDB()) {
MoyoungSleepStageSampleProvider provider = new MoyoungSleepStageSampleProvider(getDevice(), dbHandler.getDaoSession());
@@ -1274,9 +1279,13 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
currentSample.setUser(user);
currentSample.setStage(type);
currentSample.setTimestamp(thisSample.getTimeInMillis());
samples.add(currentSample);
LOG.debug("Adding sleep stage sample: ts={} stage={}", thisSample.getTime(), type);
if (thisSample.getTime().getTime() > prefLastSyncTime) {
samples.add(currentSample);
LOG.debug("Adding sleep stage sample: ts={} stage={}", thisSample.getTime(), type);
} else {
LOG.debug("Skipping sleep stage sample from before last sync time: prevSync={} ts={} stage={}", prefLastSyncTime, thisSample.getTime(), type);
}
}
LOG.debug("Will persist {} sleep stage samples", samples.size());