From 282e30f00880f1df980286a09a959218a522f06d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gro=C3=9Fklo=C3=9F?= Date: Sun, 7 Dec 2025 12:57:18 +0100 Subject: [PATCH] Add method to get midnight timestamp and update queries to use it --- main.py | 62 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/main.py b/main.py index 735b1d8..3d2a0bb 100644 --- a/main.py +++ b/main.py @@ -70,6 +70,21 @@ class GadgetbridgeMQTTPublisher: return int(day_start_time.timestamp()) + def get_day_midnight_timestamp_ms(self) -> int: + """Get the timestamp for midnight of the current day in milliseconds. + Used for XIAOMI_DAILY_SUMMARY_SAMPLE which stores data at midnight.""" + now = datetime.now() + today = now.date() + + # Daily summary is stored at midnight + day_midnight = datetime.combine(today, datetime.min.time()) + + # If current time is before 4am, use yesterday's midnight + if now.hour < 4: + day_midnight -= timedelta(days=1) + + return int(day_midnight.timestamp()) * 1000 + def initialize_sensors(self): """Initialize sensor definitions after device_name is available""" self.sensors = [ @@ -304,47 +319,47 @@ class GadgetbridgeMQTTPublisher: def query_latest_heart_rate(self, cursor) -> Any: cursor.execute( - "SELECT HEART_RATE FROM XIAOMI_ACTIVITY_SAMPLE ORDER BY TIMESTAMP DESC LIMIT 1" + "SELECT HEART_RATE FROM XIAOMI_ACTIVITY_SAMPLE WHERE HEART_RATE > 0 AND HEART_RATE < 255 ORDER BY TIMESTAMP DESC LIMIT 1" ) row = cursor.fetchone() return row[0] if row else None def query_hr_resting(self, cursor) -> Any: - day_start_ts = self.get_day_start_timestamp() + day_midnight_ts_ms = self.get_day_midnight_timestamp_ms() cursor.execute( "SELECT HR_RESTING FROM XIAOMI_DAILY_SUMMARY_SAMPLE WHERE TIMESTAMP >= ? ORDER BY TIMESTAMP DESC LIMIT 1", - (day_start_ts,) + (day_midnight_ts_ms,) ) row = cursor.fetchone() return row[0] if row else None def query_hr_max(self, cursor) -> Any: - day_start_ts = self.get_day_start_timestamp() + day_midnight_ts_ms = self.get_day_midnight_timestamp_ms() cursor.execute( "SELECT HR_MAX FROM XIAOMI_DAILY_SUMMARY_SAMPLE WHERE TIMESTAMP >= ? ORDER BY TIMESTAMP DESC LIMIT 1", - (day_start_ts,) + (day_midnight_ts_ms,) ) row = cursor.fetchone() return row[0] if row else None def query_hr_avg(self, cursor) -> Any: - day_start_ts = self.get_day_start_timestamp() + day_midnight_ts_ms = self.get_day_midnight_timestamp_ms() cursor.execute( "SELECT HR_AVG FROM XIAOMI_DAILY_SUMMARY_SAMPLE WHERE TIMESTAMP >= ? ORDER BY TIMESTAMP DESC LIMIT 1", - (day_start_ts,) + (day_midnight_ts_ms,) ) row = cursor.fetchone() return row[0] if row else None def query_calories(self, cursor) -> Any: - day_start_ts = self.get_day_start_timestamp() + day_midnight_ts_ms = self.get_day_midnight_timestamp_ms() cursor.execute( "SELECT CALORIES FROM XIAOMI_DAILY_SUMMARY_SAMPLE WHERE TIMESTAMP >= ? ORDER BY TIMESTAMP DESC LIMIT 1", - (day_start_ts,) + (day_midnight_ts_ms,) ) row = cursor.fetchone() return row[0] if row else None @@ -355,23 +370,34 @@ class GadgetbridgeMQTTPublisher: # 1. No data at all -> Assume Awake if not row: return True - last_ts_epoch = row[0] + last_ts_epoch = row[0] // 1000 # Convert from milliseconds to seconds is_awake_val = row[1] # This can be 1, 0, or None (NULL) - # 2. Timeout Safety: If last sleep data is older than 4 hours, force Awake - # This handles "Band Removed" or "Sync Failed" scenarios where the - # user has been up for hours but no new "awake" row was inserted. - import time - if (int(time.time()) - last_ts_epoch) > (4 * 3600): + wakeup_time = row[2] # Wakeup time in milliseconds + + # 2. Check if WAKEUP_TIME is in the past (user has woken up) + current_time_ms = int(time.time()) * 1000 + if wakeup_time and wakeup_time <= current_time_ms: return True - # 3. Explicit Status Check + + # 3. Timeout Safety: If last sleep data is older than 12 hours, force Awake + # This handles "Band Removed" or "Sync Failed" scenarios + if (int(time.time()) - last_ts_epoch) > (12 * 3600): + return True + + # 4. Explicit Status Check if is_awake_val == 1: return True - # If is_awake_val is 0 or None, the user is likely asleep (TODO: verify None) + + # If is_awake_val is 0 or None, the user is likely asleep return False def query_total_sleep_duration(self, cursor) -> Any: + # Get sleep from the last 24 hours + day_ago_ts = (int(time.time()) - 24 * 3600) * 1000 # 24 hours ago in milliseconds + cursor.execute( - "SELECT TOTAL_DURATION FROM XIAOMI_SLEEP_TIME_SAMPLE ORDER BY TIMESTAMP DESC LIMIT 1" + "SELECT TOTAL_DURATION FROM XIAOMI_SLEEP_TIME_SAMPLE WHERE TIMESTAMP >= ? ORDER BY TIMESTAMP DESC LIMIT 1", + (day_ago_ts,) ) row = cursor.fetchone() # Convert minutes to hours, round to 2 decimals