Add coordinator to emoncms (#120008)
parent
1a962b415e
commit
cb045a794d
|
@ -0,0 +1,31 @@
|
|||
"""DataUpdateCoordinator for the emoncms integration."""
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from pyemoncms import EmoncmsClient
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EmoncmsCoordinator(DataUpdateCoordinator[list[dict[str, Any]] | None]):
|
||||
"""Emoncms Data Update Coordinator."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
emoncms_client: EmoncmsClient,
|
||||
scan_interval: timedelta,
|
||||
) -> None:
|
||||
"""Initialize the emoncms data coordinator."""
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
name="emoncms_coordinator",
|
||||
update_method=emoncms_client.async_list_feeds,
|
||||
update_interval=scan_interval,
|
||||
)
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
|
@ -17,18 +18,22 @@ from homeassistant.components.sensor import (
|
|||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_ID,
|
||||
CONF_SCAN_INTERVAL,
|
||||
CONF_UNIT_OF_MEASUREMENT,
|
||||
CONF_URL,
|
||||
CONF_VALUE_TEMPLATE,
|
||||
STATE_UNKNOWN,
|
||||
UnitOfPower,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import template
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from .coordinator import EmoncmsCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -84,19 +89,21 @@ async def async_setup_platform(
|
|||
exclude_feeds = config.get(CONF_EXCLUDE_FEEDID)
|
||||
include_only_feeds = config.get(CONF_ONLY_INCLUDE_FEEDID)
|
||||
sensor_names = config.get(CONF_SENSOR_NAMES)
|
||||
scan_interval = config.get(CONF_SCAN_INTERVAL, timedelta(seconds=30))
|
||||
|
||||
if value_template is not None:
|
||||
value_template.hass = hass
|
||||
|
||||
emoncms_client = EmoncmsClient(url, apikey, session=async_get_clientsession(hass))
|
||||
elems = await emoncms_client.async_list_feeds()
|
||||
|
||||
coordinator = EmoncmsCoordinator(hass, emoncms_client, scan_interval)
|
||||
await coordinator.async_refresh()
|
||||
elems = coordinator.data
|
||||
if elems is None:
|
||||
return
|
||||
|
||||
sensors = []
|
||||
sensors: list[EmonCmsSensor] = []
|
||||
|
||||
for elem in elems:
|
||||
for idx, elem in enumerate(elems):
|
||||
if exclude_feeds is not None and int(elem["id"]) in exclude_feeds:
|
||||
continue
|
||||
|
||||
|
@ -114,48 +121,48 @@ async def async_setup_platform(
|
|||
|
||||
sensors.append(
|
||||
EmonCmsSensor(
|
||||
hass,
|
||||
emoncms_client,
|
||||
coordinator,
|
||||
name,
|
||||
value_template,
|
||||
unit_of_measurement,
|
||||
str(sensorid),
|
||||
elem,
|
||||
idx,
|
||||
)
|
||||
)
|
||||
async_add_entities(sensors)
|
||||
|
||||
|
||||
class EmonCmsSensor(SensorEntity):
|
||||
class EmonCmsSensor(CoordinatorEntity[EmoncmsCoordinator], SensorEntity):
|
||||
"""Implementation of an Emoncms sensor."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
emoncms_client: EmoncmsClient,
|
||||
coordinator: EmoncmsCoordinator,
|
||||
name: str | None,
|
||||
value_template: template.Template | None,
|
||||
unit_of_measurement: str | None,
|
||||
sensorid: str,
|
||||
elem: dict[str, Any],
|
||||
idx: int,
|
||||
) -> None:
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(coordinator)
|
||||
self.idx = idx
|
||||
elem = {}
|
||||
if self.coordinator.data:
|
||||
elem = self.coordinator.data[self.idx]
|
||||
if name is None:
|
||||
# Suppress ID in sensor name if it's 1, since most people won't
|
||||
# have more than one EmonCMS source and it's redundant to show the
|
||||
# ID if there's only one.
|
||||
id_for_name = "" if str(sensorid) == "1" else sensorid
|
||||
# Use the feed name assigned in EmonCMS or fall back to the feed ID
|
||||
feed_name = elem.get("name") or f"Feed {elem['id']}"
|
||||
feed_name = elem.get("name", f"Feed {elem.get('id')}")
|
||||
self._attr_name = f"EmonCMS{id_for_name} {feed_name}"
|
||||
else:
|
||||
self._attr_name = name
|
||||
self._hass = hass
|
||||
self._emoncms_client = emoncms_client
|
||||
self._value_template = value_template
|
||||
self._attr_native_unit_of_measurement = unit_of_measurement
|
||||
self._sensorid = sensorid
|
||||
self._feed_id = elem["id"]
|
||||
|
||||
if unit_of_measurement in ("kWh", "Wh"):
|
||||
self._attr_device_class = SensorDeviceClass.ENERGY
|
||||
|
@ -208,9 +215,10 @@ class EmonCmsSensor(SensorEntity):
|
|||
elif elem["value"] is not None:
|
||||
self._attr_native_value = round(float(elem["value"]), DECIMALS)
|
||||
|
||||
async def async_update(self) -> None:
|
||||
"""Get the latest data and updates the state."""
|
||||
elem = await self._emoncms_client.async_get_feed_fields(self._feed_id)
|
||||
if elem is None:
|
||||
return
|
||||
self._update_attributes(elem)
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Handle updated data from the coordinator."""
|
||||
data = self.coordinator.data
|
||||
if data:
|
||||
self._update_attributes(data[self.idx])
|
||||
super()._handle_coordinator_update()
|
||||
|
|
Loading…
Reference in New Issue