diff --git a/custom_components/libreview/config_flow.py b/custom_components/libreview/config_flow.py index 0714ba9..3bae26c 100755 --- a/custom_components/libreview/config_flow.py +++ b/custom_components/libreview/config_flow.py @@ -9,7 +9,7 @@ from homeassistant.data_entry_flow import FlowResult from LibreView import LibreView -from .const import CONF_UOM, DOMAIN, LOGGER, GlucoseUnitOfMeasurement +from .const import CONF_UOM, CONF_SENSOR_DURATION, DOMAIN, LOGGER, GlucoseUnitOfMeasurement, CONF_SHOW_TREND_ARROW class LibreViewOptionsFlowHandler(OptionsFlow): @@ -31,17 +31,27 @@ async def async_step_init( self.async_abort(reason="configuration updated") return self.async_create_entry(title="", data={}) - default = GlucoseUnitOfMeasurement.MMOLL + default_uom = GlucoseUnitOfMeasurement.MMOLL if self.entry.data.get(CONF_UOM) is not None: - default = GlucoseUnitOfMeasurement(self.entry.data.get(CONF_UOM)) + default_uom = GlucoseUnitOfMeasurement(self.entry.data.get(CONF_UOM)) + + default_duration = 14 + if self.entry.data.get(CONF_SENSOR_DURATION) is not None: + default_duration = int(self.entry.data.get(CONF_SENSOR_DURATION)) + + default_show_trend = 14 + if self.entry.data.get(CONF_SHOW_TREND_ARROW) is not None: + default_show_trend = bool(self.entry.data.get(CONF_SHOW_TREND_ARROW)) return self.async_show_form( step_id="init", data_schema=vol.Schema( { - vol.Required(CONF_UOM, default=default): vol.In( + vol.Required(CONF_UOM, default=default_uom): vol.In( GlucoseUnitOfMeasurement - ) + ), + vol.Required(CONF_SENSOR_DURATION, default=default_duration): int, + vol.Required(CONF_SHOW_TREND_ARROW, default=default_show_trend): bool } ), ) @@ -94,18 +104,24 @@ async def async_step_options( ) -> FlowResult: if user_input is not None: self.uom = user_input[CONF_UOM] + self.sensor_duration = user_input[CONF_SENSOR_DURATION] + self.show_trend_icon = user_input[CONF_SHOW_TREND_ARROW] return self.async_create_entry( title="LibreView", data={ CONF_EMAIL: self.email, CONF_PASSWORD: self.password, CONF_UOM: self.uom, + CONF_SENSOR_DURATION: int(self.sensor_duration), + CONF_SHOW_TREND_ARROW: bool(self.show_trend_icon), }, ) return self.async_show_form( step_id="options", data_schema=vol.Schema( - {vol.Required(CONF_UOM): vol.In(GlucoseUnitOfMeasurement)} + {vol.Required(CONF_UOM): vol.In(GlucoseUnitOfMeasurement), + vol.Required(CONF_SENSOR_DURATION, default=14): int, + vol.Required(CONF_SHOW_TREND_ARROW, default=default_show_trend): bool}, ), ) diff --git a/custom_components/libreview/const.py b/custom_components/libreview/const.py index 9875c34..10980b1 100755 --- a/custom_components/libreview/const.py +++ b/custom_components/libreview/const.py @@ -11,7 +11,18 @@ DEFAULT_SCAN_INTERVAL = timedelta(minutes=1) CONF_UOM = "uom" +CONF_SENSOR_DURATION = "sensor_duration" +CONF_SHOW_TREND_ARROW = "show_trend_arrow" +DEFAULT_ICON = "mdi:diabetes" +SENSOR_ICON = "mdi:circle-double" +TREND_ICONS = { + 0: "mdi:arrow-down-thick", + 1: "mdi:arrow-bottom-right-thick", + 2: "mdi:arrow-right-thick", + 3: "mdi:arrow-top-right-thick", + 4: "mdi:arrow-up-thick", +} class GlucoseUnitOfMeasurement(Enum): MMOLL = "mmol/L" diff --git a/custom_components/libreview/sensor.py b/custom_components/libreview/sensor.py index f8d2ce9..642dbbd 100644 --- a/custom_components/libreview/sensor.py +++ b/custom_components/libreview/sensor.py @@ -1,15 +1,16 @@ from typing import Dict from uuid import UUID +import datetime -from homeassistant.components.sensor import SensorEntity +from homeassistant.components.sensor import SensorEntity, SensorDeviceClass from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity -from LibreView.models import Connection, GlucoseMeasurement +from LibreView.models import Connection, GlucoseMeasurement, Sensor -from .const import CONF_UOM, DOMAIN, GlucoseUnitOfMeasurement +from .const import CONF_UOM, CONF_SENSOR_DURATION, DOMAIN, GlucoseUnitOfMeasurement, TREND_ICONS, DEFAULT_ICON, SENSOR_ICON, CONF_SHOW_TREND_ARROW from .coordinator import LibreViewCoordinator @@ -17,15 +18,57 @@ async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: coordinator: LibreViewCoordinator = hass.data[DOMAIN][entry.entry_id] - sensors: list[Entity] = [ - GlucoseSensor( - coordinator, connection_id, GlucoseUnitOfMeasurement(entry.data[CONF_UOM]) - ) - for connection_id, _ in coordinator.data["glucose_readings"].items() - ] - + uom = GlucoseUnitOfMeasurement(entry.data[CONF_UOM]) + sensor_duration = int(entry.data[CONF_SENSOR_DURATION]) + show_trend_arrow = bool(entry.data[CONF_SHOW_TREND_ARROW]) + sensors: list[Entity] = [GlucoseSensor(coordinator, connection_id, uom, show_trend_arrow) for connection_id, _ in coordinator.data["glucose_readings"].items()] + [LibreSensor(coordinator, connection_id, sensor_duration) for connection_id, _ in coordinator.data["glucose_readings"].items()] async_add_entities(sensors) +class LibreSensor(CoordinatorEntity, SensorEntity): + _attr_device_class = SensorDeviceClass.TIMESTAMP + def __init__( + self, + coordinator: LibreViewCoordinator, + connection_id: UUID, + sensor_duration: int + ): + super().__init__(coordinator) + self._attr_unique_id = f"{connection_id}_sensor_expiry" + self.connection_id = connection_id + self.sensor_duration = sensor_duration + + @property + def application_dt(self): + return datetime.datetime.fromtimestamp(self.sensor.a, datetime.timezone.utc) + + @property + def icon(self): + return SENSOR_ICON + + @property + def connection(self) -> Connection: + return self.coordinator.data["glucose_readings"][self.connection_id] + + @property + def sensor(self) -> Sensor: + return self.connection.sensor + + @property + def name(self) -> str: + """Return the name of the entity.""" + name = f"{self.connection.first_name } {self.connection.last_name}" + return f"{name} sensor expiry" + + @property + def native_value(self) -> datetime.datetime | None: + return self.application_dt + datetime.timedelta(days=self.sensor_duration) + + @property + def extra_state_attributes(self) -> Dict[str, str]: + return { + "application_datetime": self.application_dt, + "serial_no": self.sensor.sn, + } class GlucoseSensor(CoordinatorEntity, SensorEntity): _attr_native_unit_of_measurement: str @@ -37,17 +80,20 @@ def __init__( coordinator: LibreViewCoordinator, connection_id: UUID, uom: GlucoseUnitOfMeasurement, + use_trend_icons: bool ): super().__init__(coordinator) self._attr_unique_id = f"{connection_id}_glucose_reading" self.connection_id = connection_id self.uom = uom self._attr_native_unit_of_measurement = self.uom.value + self.use_trend_icons = use_trend_icons @property def icon(self): - # trend icons? - return "mdi:diabetes" + if (self.use_trend_icons): + return TREND_ICONS.get(self.trend_arrow, DEFAULT_ICON) + return DEFAULT_ICON @property def connection(self) -> Connection: @@ -57,6 +103,10 @@ def connection(self) -> Connection: def gcm(self) -> GlucoseMeasurement: return self.connection.glucose_measurement + @property + def trend_arrow(self) -> int: + return self.gcm.trend_arrow + @property def name(self) -> str: """Return the name of the entity.""" @@ -64,7 +114,7 @@ def name(self) -> str: return f"{name} Glucose Measurement" @property - def native_value(self) -> str | None: + def native_value(self) -> int | float | None: """Return the state of the entity.""" if self.uom == GlucoseUnitOfMeasurement.MMOLL: return self.gcm.value diff --git a/custom_components/libreview/strings.json b/custom_components/libreview/strings.json index 9e7c4da..78896aa 100644 --- a/custom_components/libreview/strings.json +++ b/custom_components/libreview/strings.json @@ -10,9 +10,12 @@ } }, "async_step_options": { - "description": "Please select your preffered unit of measurent for blood glucose measurements", + "title": "LibreView Configuration", + "description": "Set settings for the LibreView integration.", "data": { - "uom": "Unit" + "uom": "Unit of measurement for blood glucose measurements", + "sensor_duration": "How many days do your Libre Sensor stay active after application", + "show_trend_arrow": "Use icon to show current trend of the glucose level" } }, "reauth_confirm": { @@ -31,5 +34,18 @@ "already_configured": "[%key:common::config_flow::abort::already_configured_account%]", "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]" } + }, + "options": { + "step": { + "init": { + "title": "LibreView Configuration", + "description": "Change settings for the LibreView integration.", + "data": { + "uom": "Unit of measurement for blood glucose measurements", + "sensor_duration": "How many days do your Libre Sensor stay active after application", + "show_trend_arrow": "Use icon to show current trend of the glucose level" + } + } + } } } \ No newline at end of file diff --git a/custom_components/libreview/translations/da.json b/custom_components/libreview/translations/da.json index a941119..5923008 100644 --- a/custom_components/libreview/translations/da.json +++ b/custom_components/libreview/translations/da.json @@ -11,9 +11,11 @@ }, "options": { "title": "LibreView opsætning", - "description": "Vælg din foretrukne målenhed for blodsukkermålinger", + "description": "Indstillinger for LibreView integrationen", "data": { - "uom": "Enhed" + "uom": "Måleenhed for blodsukkermålinger", + "sensor_duration": "Hvor mange dage er din Libre sensor aktiv efter påsætning", + "show_trend_arrow": "Brug ikon til at vise glukosetendens" } }, "reauth_confirm": { @@ -37,9 +39,11 @@ "step": { "init": { "title": "LibreView indstillinger", - "description": "Vælg din foretrukne målenhed for blodsukkermålinger", + "description": "Indstillinger for LibreView integrationen", "data": { - "uom": "Enhed" + "uom": "Måleenhed for blodsukkermålinger", + "sensor_duration": "Hvor mange dage er din Libre sensor aktiv efter påsætning", + "show_trend_arrow": "Brug ikon til at vise glukosetendens" } } } diff --git a/custom_components/libreview/translations/en.json b/custom_components/libreview/translations/en.json index 8d47553..69c6f2e 100644 --- a/custom_components/libreview/translations/en.json +++ b/custom_components/libreview/translations/en.json @@ -11,9 +11,11 @@ }, "options": { "title": "LibreView Configuration", - "description": "Please select your preffered unit of measurent for blood glucose measurements", + "description": "Set settings for the LibreView integration.", "data": { - "uom": "Unit" + "uom": "Unit of measurement for blood glucose measurements", + "sensor_duration": "How many days do your Libre Sensor stay active after application", + "show_trend_arrow": "Use icon to show current trend of the glucose level" } }, "reauth_confirm": { @@ -36,10 +38,12 @@ "options": { "step": { "init": { - "title": "LibreView Options", - "description": "Please select your preffered unit of measurent for blood glucose measurements", + "title": "LibreView Configuration", + "description": "Change settings for the LibreView integration.", "data": { - "uom": "Unit" + "uom": "Unit of measurement for blood glucose measurements", + "sensor_duration": "How many days do your Libre Sensor stay active after application", + "show_trend_arrow": "Use icon to show current trend of the glucose level" } } }