"""Support for Nightscout sensors.""" from __future__ import annotations from asyncio import TimeoutError as AsyncIOTimeoutError from datetime import timedelta import logging from typing import Any from aiohttp import ClientError from py_nightscout import Api as NightscoutAPI from homeassistant.components.sensor import SensorEntity from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_DATE from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import ATTR_DELTA, ATTR_DEVICE, ATTR_DIRECTION, DOMAIN SCAN_INTERVAL = timedelta(minutes=1) _LOGGER = logging.getLogger(__name__) DEFAULT_NAME = "Blood Glucose" async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the Glucose Sensor.""" api = hass.data[DOMAIN][entry.entry_id] async_add_entities([NightscoutSensor(api, "Blood Sugar", entry.unique_id)], True) class NightscoutSensor(SensorEntity): """Implementation of a Nightscout sensor.""" def __init__(self, api: NightscoutAPI, name, unique_id): """Initialize the Nightscout sensor.""" self.api = api self._unique_id = unique_id self._name = name self._state = None self._attributes: dict[str, Any] = {} self._unit_of_measurement = "mg/dL" self._icon = "mdi:cloud-question" self._available = False @property def unique_id(self): """Return the unique ID of the sensor.""" return self._unique_id @property def name(self): """Return the name of the sensor.""" return self._name @property def native_unit_of_measurement(self): """Return the unit the value is expressed in.""" return self._unit_of_measurement @property def available(self): """Return if the sensor data are available.""" return self._available @property def native_value(self): """Return the state of the device.""" return self._state @property def icon(self): """Return the icon to use in the frontend, if any.""" return self._icon async def async_update(self): """Fetch the latest data from Nightscout REST API and update the state.""" try: values = await self.api.get_sgvs() except (ClientError, AsyncIOTimeoutError, OSError) as error: _LOGGER.error("Error fetching data. Failed with %s", error) self._available = False return self._available = True self._attributes = {} self._state = None if values: value = values[0] self._attributes = { ATTR_DEVICE: value.device, ATTR_DATE: value.date, ATTR_DELTA: value.delta, ATTR_DIRECTION: value.direction, } self._state = value.sgv self._icon = self._parse_icon() else: self._available = False _LOGGER.warning("Empty reply found when expecting JSON data") def _parse_icon(self) -> str: """Update the icon based on the direction attribute.""" switcher = { "Flat": "mdi:arrow-right", "SingleDown": "mdi:arrow-down", "FortyFiveDown": "mdi:arrow-bottom-right", "DoubleDown": "mdi:chevron-triple-down", "SingleUp": "mdi:arrow-up", "FortyFiveUp": "mdi:arrow-top-right", "DoubleUp": "mdi:chevron-triple-up", } return switcher.get(self._attributes[ATTR_DIRECTION], "mdi:cloud-question") @property def extra_state_attributes(self): """Return the state attributes.""" return self._attributes