Added morning training readiness, fallback midnight

This commit is contained in:
Ron Klinkien
2026-01-04 12:04:55 +01:00
parent e2fc279d89
commit e713b01846
3 changed files with 44 additions and 5 deletions

View File

@@ -127,14 +127,23 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
self.api.get_user_summary, today.isoformat()
)
# Midnight fallback: During 0:00-2:00 window, if today's data is empty/None,
# fallback to yesterday's data to avoid gaps due to UTC/GMT timezone differences
if current_hour < 2 and (not summary or summary.get("totalSteps") in (None, 0)):
_LOGGER.debug("Midnight fallback: Today's data empty, fetching yesterday's data")
# Smart fallback: detect when Garmin servers haven't populated today's data yet
# Key signal: dailyStepGoal is None means the day data structure doesn't exist
# This works regardless of timezone - no fixed hour window needed
today_data_not_ready = (
not summary
or summary.get("dailyStepGoal") is None
)
if today_data_not_ready:
_LOGGER.debug(
"Today's data not ready (dailyStepGoal=%s), fetching yesterday's data",
summary.get("dailyStepGoal") if summary else None
)
yesterday_summary = await self.hass.async_add_executor_job(
self.api.get_user_summary, yesterday_date
)
if yesterday_summary and yesterday_summary.get("totalSteps"):
if yesterday_summary and yesterday_summary.get("dailyStepGoal") is not None:
summary = yesterday_summary
_LOGGER.debug("Using yesterday's summary data as fallback")
@@ -205,6 +214,15 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
except Exception:
summary["trainingReadiness"] = {}
# Fetch morning training readiness (AFTER_WAKEUP_RESET context)
try:
morning_training_readiness = await self.hass.async_add_executor_job(
self.api.get_morning_training_readiness, today.isoformat()
)
summary["morningTrainingReadiness"] = morning_training_readiness or {}
except Exception:
summary["morningTrainingReadiness"] = {}
# Fetch training status
try:
training_status = await self.hass.async_add_executor_job(

View File

@@ -886,6 +886,24 @@ ACTIVITY_TRACKING_SENSORS: tuple[GarminConnectSensorEntityDescription, ...] = (
value_fn=lambda data: data.get("trainingStatus", {}).get("trainingStatusPhrase"),
attributes_fn=lambda data: data.get("trainingStatus", {}),
),
GarminConnectSensorEntityDescription(
key="morningTrainingReadiness",
translation_key="morning_training_readiness",
icon="mdi:weather-sunset-up",
native_unit_of_measurement=PERCENTAGE,
value_fn=lambda data: data.get("morningTrainingReadiness", {}).get("score"),
attributes_fn=lambda data: {
"level": data.get("morningTrainingReadiness", {}).get("level"),
"sleep_score": data.get("morningTrainingReadiness", {}).get("sleepScore"),
"recovery_score": data.get("morningTrainingReadiness", {}).get("recoveryScore"),
"hrv_status": data.get("morningTrainingReadiness", {}).get("hrvStatus"),
"acuteLoad": data.get("morningTrainingReadiness", {}).get("acuteLoad"),
"input_context": data.get("morningTrainingReadiness", {}).get("inputContext"),
**{k: v for k, v in data.get("morningTrainingReadiness", {}).items()
if k not in ("score", "level", "sleepScore", "recoveryScore", "hrvStatus", "acuteLoad", "inputContext")},
},
),
GarminConnectSensorEntityDescription(
key="lactateThresholdHeartRate",
translation_key="lactate_threshold_hr",

View File

@@ -349,6 +349,9 @@
"training_status": {
"name": "Training status"
},
"morning_training_readiness": {
"name": "Morning training readiness"
},
"lactate_threshold_hr": {
"name": "Lactate threshold heart rate"
},