Skip to content

Commit

Permalink
Added libre sensor data and optional trend icons
Browse files Browse the repository at this point in the history
  • Loading branch information
PTST committed Feb 23, 2024
1 parent d453a04 commit 295abd0
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 30 deletions.
28 changes: 22 additions & 6 deletions custom_components/libreview/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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
}
),
)
Expand Down Expand Up @@ -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},
),
)

Expand Down
11 changes: 11 additions & 0 deletions custom_components/libreview/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
76 changes: 63 additions & 13 deletions custom_components/libreview/sensor.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,74 @@
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


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
Expand All @@ -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:
Expand All @@ -57,14 +103,18 @@ 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."""
name = f"{self.connection.first_name } {self.connection.last_name}"
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
Expand Down
20 changes: 18 additions & 2 deletions custom_components/libreview/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand All @@ -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"
}
}
}
}
}
12 changes: 8 additions & 4 deletions custom_components/libreview/translations/da.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand All @@ -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"
}
}
}
Expand Down
14 changes: 9 additions & 5 deletions custom_components/libreview/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand All @@ -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"
}
}
}
Expand Down

0 comments on commit 295abd0

Please sign in to comment.