mirror of
https://github.com/cyberjunky/home-assistant-garmin_connect.git
synced 2026-01-07 20:13:57 -05:00
Retain data overnight for certain sensors
This commit is contained in:
@@ -18,6 +18,7 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import IntegrationError
|
||||
from homeassistant.helpers import entity_platform
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
CoordinatorEntity,
|
||||
DataUpdateCoordinator,
|
||||
@@ -140,7 +141,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e
|
||||
)
|
||||
|
||||
|
||||
class GarminConnectSensor(GarminConnectEntity, SensorEntity):
|
||||
class GarminConnectSensor(GarminConnectEntity, SensorEntity, RestoreEntity):
|
||||
"""Representation of a Garmin Connect Sensor."""
|
||||
|
||||
def __init__(
|
||||
@@ -153,11 +154,22 @@ class GarminConnectSensor(GarminConnectEntity, SensorEntity):
|
||||
super().__init__(coordinator, unique_id)
|
||||
self.entity_description = description
|
||||
self._attr_unique_id = f"{unique_id}_{description.key}"
|
||||
self._last_known_value: str | int | float | None = None
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Restore last known value when added to hass."""
|
||||
await super().async_added_to_hass()
|
||||
if (last_state := await self.async_get_last_state()) is not None:
|
||||
if last_state.state not in ("unknown", "unavailable"):
|
||||
self._last_known_value = last_state.state
|
||||
|
||||
@property
|
||||
def native_value(self):
|
||||
"""Return the state of the sensor."""
|
||||
if not self.coordinator.data:
|
||||
# Only return last known value if preserve_value is enabled
|
||||
if self.entity_description.preserve_value:
|
||||
return self._last_known_value
|
||||
return None
|
||||
|
||||
# Use custom value function if provided in description
|
||||
@@ -167,6 +179,9 @@ class GarminConnectSensor(GarminConnectEntity, SensorEntity):
|
||||
value = self.coordinator.data.get(self.entity_description.key)
|
||||
|
||||
if value is None:
|
||||
# Return last known value if preserve_value enabled (e.g., weight at midnight)
|
||||
if self.entity_description.preserve_value:
|
||||
return self._last_known_value
|
||||
return None
|
||||
|
||||
# Handle timestamp device class
|
||||
@@ -178,13 +193,17 @@ class GarminConnectSensor(GarminConnectEntity, SensorEntity):
|
||||
|
||||
# Preserve int types, only round floats
|
||||
if isinstance(value, int):
|
||||
self._last_known_value = value
|
||||
return value
|
||||
if isinstance(value, float):
|
||||
# Round floats to 1 decimal place, but return int if it's a whole number
|
||||
rounded = round(value, 1)
|
||||
if rounded == int(rounded):
|
||||
self._last_known_value = int(rounded)
|
||||
return int(rounded)
|
||||
self._last_known_value = rounded
|
||||
return rounded
|
||||
self._last_known_value = value
|
||||
return value
|
||||
|
||||
@property
|
||||
|
||||
@@ -28,6 +28,9 @@ class GarminConnectSensorEntityDescription(SensorEntityDescription):
|
||||
attributes_fn: Callable[[dict[str, Any]], dict[str, Any]] | None = None
|
||||
"""Function to extract attributes from coordinator data."""
|
||||
|
||||
preserve_value: bool = False
|
||||
"""If True, preserve last known value when API returns None (for weight, BMI, etc)."""
|
||||
|
||||
|
||||
|
||||
# Activity & Steps Sensors
|
||||
@@ -353,7 +356,7 @@ BODY_COMPOSITION_SENSORS: tuple[GarminConnectSensorEntityDescription, ...] = (
|
||||
icon="mdi:weight-kilogram",
|
||||
value_fn=lambda data: round(
|
||||
data.get("weight", 0) / 1000, 2) if data.get("weight") else None,
|
||||
|
||||
preserve_value=True,
|
||||
),
|
||||
GarminConnectSensorEntityDescription(
|
||||
key="bmi",
|
||||
@@ -361,7 +364,7 @@ BODY_COMPOSITION_SENSORS: tuple[GarminConnectSensorEntityDescription, ...] = (
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement="BMI",
|
||||
icon="mdi:human",
|
||||
|
||||
preserve_value=True,
|
||||
),
|
||||
GarminConnectSensorEntityDescription(
|
||||
key="bodyFat",
|
||||
@@ -369,7 +372,7 @@ BODY_COMPOSITION_SENSORS: tuple[GarminConnectSensorEntityDescription, ...] = (
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
icon="mdi:percent",
|
||||
|
||||
preserve_value=True,
|
||||
),
|
||||
GarminConnectSensorEntityDescription(
|
||||
key="bodyWater",
|
||||
@@ -377,7 +380,7 @@ BODY_COMPOSITION_SENSORS: tuple[GarminConnectSensorEntityDescription, ...] = (
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
icon="mdi:water-percent",
|
||||
|
||||
preserve_value=True,
|
||||
),
|
||||
GarminConnectSensorEntityDescription(
|
||||
key="boneMass",
|
||||
@@ -388,7 +391,7 @@ BODY_COMPOSITION_SENSORS: tuple[GarminConnectSensorEntityDescription, ...] = (
|
||||
icon="mdi:bone",
|
||||
value_fn=lambda data: round(
|
||||
data.get("boneMass", 0) / 1000, 2) if data.get("boneMass") else None,
|
||||
|
||||
preserve_value=True,
|
||||
),
|
||||
GarminConnectSensorEntityDescription(
|
||||
key="muscleMass",
|
||||
@@ -399,7 +402,7 @@ BODY_COMPOSITION_SENSORS: tuple[GarminConnectSensorEntityDescription, ...] = (
|
||||
icon="mdi:dumbbell",
|
||||
value_fn=lambda data: round(
|
||||
data.get("muscleMass", 0) / 1000, 2) if data.get("muscleMass") else None,
|
||||
|
||||
preserve_value=True,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -611,7 +614,7 @@ FITNESS_SENSORS: tuple[GarminConnectSensorEntityDescription, ...] = (
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfTime.YEARS,
|
||||
icon="mdi:calendar-heart",
|
||||
|
||||
preserve_value=True,
|
||||
),
|
||||
GarminConnectSensorEntityDescription(
|
||||
key="enduranceScore",
|
||||
@@ -630,7 +633,7 @@ FITNESS_SENSORS: tuple[GarminConnectSensorEntityDescription, ...] = (
|
||||
translation_key="physique_rating",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
icon="mdi:numeric",
|
||||
|
||||
preserve_value=True,
|
||||
),
|
||||
GarminConnectSensorEntityDescription(
|
||||
key="visceralFat",
|
||||
@@ -638,7 +641,7 @@ FITNESS_SENSORS: tuple[GarminConnectSensorEntityDescription, ...] = (
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
icon="mdi:food",
|
||||
|
||||
preserve_value=True,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user