Skip to content

Commit df87dec

Browse files
committed
Add HistoricalSensor for daily per-tariff statistics #6
Signed-off-by: Olivier Mehani <[email protected]>
1 parent 2c8e710 commit df87dec

File tree

2 files changed

+142
-7
lines changed

2 files changed

+142
-7
lines changed

custom_components/auroraplus/manifest.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
"issue_tracker": "https://github.com/LeighCurran/AuroraPlusHA/issues",
66
"dependencies": [],
77
"codeowners": ["@LeighCurran"],
8-
"requirements": ["AuroraPlus==1.1.6"],
8+
"requirements": [
9+
"AuroraPlus==1.1.6",
10+
"homeassistant-historical-sensor==2.0.0rc2"
11+
],
912
"iot_class": "cloud_polling",
1013
"config_flow": false,
1114
"version": "1.1.9"

custom_components/auroraplus/sensor.py

Lines changed: 138 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
SensorEntity
1313
)
1414

15+
from homeassistant.components.recorder.models import (StatisticData,
16+
StatisticMetaData)
17+
from homeassistant.components.recorder.statistics import StatisticsRow
18+
1519
from homeassistant.const import (
1620
CONF_USERNAME,
1721
CONF_PASSWORD,
@@ -26,6 +30,12 @@
2630

2731
from homeassistant.util import Throttle
2832

33+
from homeassistant_historical_sensor import (
34+
HistoricalSensor,
35+
HistoricalState,
36+
PollUpdateMixin,
37+
)
38+
2939
CONF_ROUNDING = "rounding"
3040

3141

@@ -42,7 +52,6 @@
4252
]
4353

4454
SENSORS_ENERGY = [
45-
SENSOR_KILOWATTHOURUSAGE,
4655
SENSOR_KILOWATTHOURUSAGETARIFF + 'T31',
4756
SENSOR_KILOWATTHOURUSAGETARIFF + 'T41',
4857
SENSOR_KILOWATTHOURUSAGETARIFF + 'T61',
@@ -52,7 +61,7 @@
5261
SENSOR_KILOWATTHOURUSAGETARIFF + 'T140',
5362
]
5463

55-
POSSIBLE_MONITORED = SENSORS_MONETARY + SENSORS_ENERGY
64+
POSSIBLE_MONITORED = SENSORS_MONETARY + [SENSOR_KILOWATTHOURUSAGE]
5665

5766
DEFAULT_MONITORED = POSSIBLE_MONITORED
5867

@@ -101,6 +110,11 @@ def aurora_init():
101110
sensor, name,
102111
aurora_api, rounding)
103112
for sensor in config.get(CONF_MONITORED_CONDITIONS)
113+
] + [
114+
AuroraHistoricalSensor(hass,
115+
sensor, name,
116+
aurora_api, rounding)
117+
for sensor in SENSORS_ENERGY
104118
],
105119
True)
106120

@@ -226,11 +240,129 @@ async def async_update(self):
226240
self._state = round(
227241
self._api.KilowattHourUsage['Total'], self._rounding)
228242
elif self._sensor.startswith(SENSOR_KILOWATTHOURUSAGETARIFF):
229-
tariff = self._sensor.removeprefix(SENSOR_KILOWATTHOURUSAGETARIFF)
230-
self._state = self._api.KilowattHourUsage.get(tariff)
231-
if self._state:
232-
self._state = round(self._state, self._rounding)
243+
pass
244+
233245
else:
234246
_LOGGER.error("Unknown sensor type found")
235247
if self._old_state and self._state != self._old_state:
236248
self._last_reset = datetime.datetime.now()
249+
250+
251+
class AuroraHistoricalSensor(PollUpdateMixin, HistoricalSensor, SensorEntity):
252+
def __init__(self, hass, sensor, name, aurora_api, rounding):
253+
"""Initialize the Aurora+ sensor."""
254+
self._hass = hass
255+
self._name = name + ' ' + sensor
256+
self._sensor = sensor
257+
self._unit_of_measurement = None
258+
self._attr_historical_states = []
259+
self._api = aurora_api
260+
self._uniqueid = self._name.replace(' ', '_').lower()
261+
self._rounding = rounding
262+
_LOGGER.debug("Created historical sensor %s", self._sensor)
263+
264+
@property
265+
def name(self):
266+
"""Return the name of the sensor."""
267+
return self._name
268+
269+
# @property
270+
# def state_class(self):
271+
# """Return the state class of the sensor."""
272+
# return STATE_CLASS_TOTAL
273+
274+
@property
275+
def device_class(self):
276+
"""Return device class fo the sensor."""
277+
if self._sensor in SENSORS_MONETARY:
278+
return DEVICE_CLASS_MONETARY
279+
else:
280+
return DEVICE_CLASS_ENERGY
281+
282+
@property
283+
def unique_id(self):
284+
"""Return the unique_id of the sensor."""
285+
return self._uniqueid
286+
287+
@property
288+
def statistic_id(self) -> str:
289+
_LOGGER.debug("Statistic_id: %s",
290+
'sensor:' + self._uniqueid)
291+
return 'sensor:' + self._uniqueid
292+
293+
@property
294+
def unit_of_measurement(self):
295+
"""Return the unit of measurement."""
296+
if self._sensor in SENSORS_MONETARY:
297+
return CURRENCY_DOLLAR
298+
else:
299+
return ENERGY_KILO_WATT_HOUR
300+
301+
@property
302+
def historical_states(self):
303+
"""Return the historical state of the sensor."""
304+
_LOGGER.debug("Returning historical states for: %s %s",
305+
self._sensor, self._attr_historical_states)
306+
return self._attr_historical_states
307+
308+
async def async_update_historical(self):
309+
if self._sensor.startswith(SENSOR_KILOWATTHOURUSAGETARIFF):
310+
tariff = self._sensor.removeprefix(SENSOR_KILOWATTHOURUSAGETARIFF)
311+
312+
await self._api.async_update()
313+
314+
metered_records = self._api.day.get(
315+
'MeteredUsageRecords'
316+
)
317+
if not metered_records:
318+
_LOGGER.warning(f"Empty daily records for {self._sensor}")
319+
return
320+
# _LOGGER.debug(f"MeteredUsageRecords: {metered_records}")
321+
322+
self._attr_historical_states = [
323+
HistoricalState(
324+
state=round(
325+
float(r['KilowattHourUsage'][tariff]),
326+
self._rounding
327+
),
328+
dt=datetime.datetime.fromisoformat(r['EndTime'])
329+
)
330+
for r in metered_records
331+
if r
332+
and r.get('KilowattHourUsage')
333+
and r.get('KilowattHourUsage').get(tariff)
334+
]
335+
_LOGGER.debug("Done with historical states for: %s",
336+
self._sensor)
337+
338+
def get_statistic_metadata(self) -> StatisticMetaData:
339+
_LOGGER.debug("Getting statistic meta for: %s",
340+
self._sensor)
341+
meta = super().get_statistic_metadata()
342+
meta["has_sum"] = True
343+
344+
return meta
345+
346+
async def async_calculate_statistic_data(
347+
self,
348+
hist_states: list[HistoricalState],
349+
*,
350+
latest: StatisticsRow | None = None,
351+
) -> list[StatisticData]:
352+
accumulated = latest["sum"] if latest else 0
353+
354+
ret = []
355+
356+
for hs in hist_states:
357+
accumulated = accumulated + hs.state
358+
ret.append(
359+
StatisticData(
360+
start=hs.dt,
361+
state=hs.state,
362+
sum=accumulated,
363+
)
364+
)
365+
366+
_LOGGER.debug("Calculated statistics for: %s, %s",
367+
self._sensor, ret)
368+
return ret

0 commit comments

Comments
 (0)