"""Support for Linky.""" from datetime import timedelta import json import logging from pylinky.client import DAILY, MONTHLY, YEARLY, LinkyClient, PyLinkyException from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_ATTRIBUTION, CONF_PASSWORD, CONF_TIMEOUT, CONF_USERNAME, ENERGY_KILO_WATT_HOUR, ) from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers.entity import Entity from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.typing import HomeAssistantType from .const import DOMAIN _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(hours=4) ICON_ENERGY = "mdi:flash" CONSUMPTION = "conso" TIME = "time" INDEX_CURRENT = -1 INDEX_LAST = -2 ATTRIBUTION = "Data provided by Enedis" async def async_setup_entry( hass: HomeAssistantType, entry: ConfigEntry, async_add_entities ) -> None: """Add Linky entries.""" account = LinkyAccount( entry.data[CONF_USERNAME], entry.data[CONF_PASSWORD], entry.data[CONF_TIMEOUT] ) await hass.async_add_executor_job(account.update_linky_data) sensors = [ LinkySensor("Linky yesterday", account, DAILY, INDEX_LAST), LinkySensor("Linky current month", account, MONTHLY, INDEX_CURRENT), LinkySensor("Linky last month", account, MONTHLY, INDEX_LAST), LinkySensor("Linky current year", account, YEARLY, INDEX_CURRENT), LinkySensor("Linky last year", account, YEARLY, INDEX_LAST), ] async_track_time_interval(hass, account.update_linky_data, SCAN_INTERVAL) async_add_entities(sensors, True) class LinkyAccount: """Representation of a Linky account.""" def __init__(self, username, password, timeout): """Initialise the Linky account.""" self._username = username self._password = password self._timeout = timeout self._data = None def update_linky_data(self, event_time=None): """Fetch new state data for the sensor.""" client = LinkyClient(self._username, self._password, None, self._timeout) try: client.login() client.fetch_data() self._data = client.get_data() _LOGGER.debug(json.dumps(self._data, indent=2)) except PyLinkyException as exp: _LOGGER.error(exp) raise PlatformNotReady finally: client.close_session() @property def username(self): """Return the username.""" return self._username @property def data(self): """Return the data.""" return self._data class LinkySensor(Entity): """Representation of a sensor entity for Linky.""" def __init__(self, name, account: LinkyAccount, scale, when): """Initialize the sensor.""" self._name = name self._account = account self._scale = scale self._when = when self._username = account.username self._time = None self._consumption = None self._unique_id = f"{self._username}_{scale}_{when}" @property def unique_id(self): """Return a unique ID.""" return self._unique_id @property def name(self): """Return the name of the sensor.""" return self._name @property def state(self): """Return the state of the sensor.""" return self._consumption @property def unit_of_measurement(self): """Return the unit of measurement.""" return ENERGY_KILO_WATT_HOUR @property def icon(self): """Return the icon of the sensor.""" return ICON_ENERGY @property def device_state_attributes(self): """Return the state attributes of the sensor.""" return { ATTR_ATTRIBUTION: ATTRIBUTION, "time": self._time, CONF_USERNAME: self._username, } @property def device_info(self): """Return device information.""" return { "identifiers": {(DOMAIN, self._username)}, "name": "Linky meter", "manufacturer": "Enedis", } async def async_update(self) -> None: """Retrieve the new data for the sensor.""" if self._account.data is None: return data = self._account.data[self._scale][self._when] self._consumption = data[CONSUMPTION] self._time = data[TIME] if self._scale is not YEARLY: year_index = INDEX_CURRENT if self._time.endswith("Dec"): year_index = INDEX_LAST self._time += f" {self._account.data[YEARLY][year_index][TIME]}"