From c33626a7797d9c40b79ad974eeb62f228878e2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rune=20A=2E=20Juel=20M=C3=B8nnike?= Date: Wed, 5 Oct 2022 21:35:39 +0200 Subject: [PATCH] #51: Added sensor for sum of tariffs for current hour, with attributes for tariff sum for each hour of the day. --- custom_components/eloverblik/__init__.py | 48 ++++++++++++++++++-- custom_components/eloverblik/const.py | 1 + custom_components/eloverblik/sensor.py | 56 ++++++++++++++++++++++-- 3 files changed, 99 insertions(+), 6 deletions(-) diff --git a/custom_components/eloverblik/__init__.py b/custom_components/eloverblik/__init__.py index 67a80f0..a43f3df 100644 --- a/custom_components/eloverblik/__init__.py +++ b/custom_components/eloverblik/__init__.py @@ -69,6 +69,7 @@ def __init__(self, refresh_token, metering_point): self._day_data = None self._year_data = None + self._tariff_data = None def get_total_day(self): if self._day_data != None: @@ -102,9 +103,26 @@ def get_data_date(self): def get_metering_point(self): return self._metering_point + def get_tariff_sum_hour(self, hour): + if self._tariff_data != None: + sum = 0.0 + for tariff in self._tariff_data.charges.values(): + if isinstance(tariff, list): + if len(tariff) == 24: + sum += tariff[hour - 1] + else: + _LOGGER.warning(f"Unexpected length of tariff array ({len(tariff)}), expected 24 entries.") + else: + sum += float(tariff) + + return sum + + else: + return None + @Throttle(MIN_TIME_BETWEEN_UPDATES) - def update(self): - _LOGGER.debug("Fetching data from Eloverblik") + def update_energy(self): + _LOGGER.debug("Fetching energy data from Eloverblik") try: day_data = self._client.get_latest(self._metering_point) @@ -131,5 +149,29 @@ def update(self): e = sys.exc_info()[1] _LOGGER.warn(f"Exception: {e}") - _LOGGER.debug("Done fetching data from Eloverblik") + _LOGGER.debug("Done fetching energy data from Eloverblik") + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update_tariffs(self): + _LOGGER.debug("Fetching tariff data from Eloverblik") + + try: + tariff_data = self._client.get_tariffs(self._metering_point) + if tariff_data.status == 200: + self._tariff_data = tariff_data + else: + _LOGGER.warn(f"Error from eloverblik when getting tariff data: {tariff_data.status} - {tariff_data.detailed_status}") + except requests.exceptions.HTTPError as he: + message = None + if he.response.status_code == 401: + message = f"Unauthorized error while accessing eloverblik.dk. Wrong or expired refresh token?" + else: + e = sys.exc_info()[1] + message = f"Exception: {e}" + + _LOGGER.warn(message) + except: + e = sys.exc_info()[1] + _LOGGER.warn(f"Exception: {e}") + _LOGGER.debug("Done fetching tariff data from Eloverblik") \ No newline at end of file diff --git a/custom_components/eloverblik/const.py b/custom_components/eloverblik/const.py index dd24589..62d44ea 100644 --- a/custom_components/eloverblik/const.py +++ b/custom_components/eloverblik/const.py @@ -1,3 +1,4 @@ """Constants for the Eloverblik integration.""" DOMAIN = "eloverblik" +CURRENCY_KRONER_PER_KILO_WATT_HOUR = "kr/kWh" \ No newline at end of file diff --git a/custom_components/eloverblik/sensor.py b/custom_components/eloverblik/sensor.py index 46e7ab9..a7e322b 100644 --- a/custom_components/eloverblik/sensor.py +++ b/custom_components/eloverblik/sensor.py @@ -1,4 +1,5 @@ """Platform for Eloverblik sensor integration.""" +import datetime import logging from homeassistant.const import ENERGY_KILO_WATT_HOUR from homeassistant.helpers.entity import Entity @@ -6,7 +7,7 @@ from pyeloverblik.models import TimeSeries _LOGGER = logging.getLogger(__name__) -from .const import DOMAIN +from .const import DOMAIN, CURRENCY_KRONER_PER_KILO_WATT_HOUR @@ -19,11 +20,12 @@ async def async_setup_entry(hass, config, async_add_entities): sensors.append(EloverblikEnergy("Eloverblik Energy Total (Year)", 'year_total', eloverblik)) for x in range(1, 25): sensors.append(EloverblikEnergy(f"Eloverblik Energy {x-1}-{x}", 'hour', eloverblik, x)) + sensors.append(EloverblikTariff("Eloverblik Tariff Sum", eloverblik)) async_add_entities(sensors) class EloverblikEnergy(Entity): - """Representation of a Sensor.""" + """Representation of an energy sensor.""" def __init__(self, name, sensor_type, client, hour=None): """Initialize the sensor.""" @@ -76,7 +78,7 @@ def update(self): """Fetch new state data for the sensor. This is the only method that should fetch new data for Home Assistant. """ - self._data.update() + self._data.update_energy() self._data_date = self._data.get_data_date() @@ -88,3 +90,51 @@ def update(self): self._state = self._data.get_total_year() else: raise ValueError(f"Unexpected sensor_type: {self._sensor_type}.") + + +class EloverblikTariff(Entity): + """Representation of an energy sensor.""" + + def __init__(self, name, client): + """Initialize the sensor.""" + self._state = None + self._data = client + self._data_hourly_tariff_sums = [0] * 24 + self._name = name + self._unique_id = f"{self._data.get_metering_point()}-tariff-sum" + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def unique_id(self): + """The unique id of the sensor.""" + return self._unique_id + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + @property + def extra_state_attributes(self): + """Return state attributes.""" + attributes = {f"hour_{i}": self._data_hourly_tariff_sums[i] for i in range(24)} + + return attributes + + @property + def unit_of_measurement(self): + """Return the unit of measurement.""" + return CURRENCY_KRONER_PER_KILO_WATT_HOUR + + def update(self): + """Fetch new state data for the sensor. + This is the only method that should fetch new data for Home Assistant. + """ + self._data.update_tariffs() + + self._data_hourly_tariff_sums = [self._data.get_tariff_sum_hour(h) for h in range(1, 25)] + self._state = self._data_hourly_tariff_sums[datetime.datetime.now().hour]