Code quality improvements in emoncms integration (#118468)

* type hints
remove unused var interval

* corrections as suggested by epenet

* reintroducing property extra_state_attributes
so that the extra parameters update correctly
This commit is contained in:
Alexandre CUER 2024-05-31 11:50:18 +02:00 committed by GitHub
parent 7804076064
commit 8a3b49434e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -5,6 +5,7 @@ from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from http import HTTPStatus from http import HTTPStatus
import logging import logging
from typing import Any
import requests import requests
import voluptuous as vol import voluptuous as vol
@ -18,7 +19,6 @@ from homeassistant.components.sensor import (
from homeassistant.const import ( from homeassistant.const import (
CONF_API_KEY, CONF_API_KEY,
CONF_ID, CONF_ID,
CONF_SCAN_INTERVAL,
CONF_UNIT_OF_MEASUREMENT, CONF_UNIT_OF_MEASUREMENT,
CONF_URL, CONF_URL,
CONF_VALUE_TEMPLATE, CONF_VALUE_TEMPLATE,
@ -72,7 +72,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
) )
def get_id(sensorid, feedtag, feedname, feedid, feeduserid): def get_id(
sensorid: str, feedtag: str, feedname: str, feedid: str, feeduserid: str
) -> str:
"""Return unique identifier for feed / sensor.""" """Return unique identifier for feed / sensor."""
return f"emoncms{sensorid}_{feedtag}_{feedname}_{feedid}_{feeduserid}" return f"emoncms{sensorid}_{feedtag}_{feedname}_{feedid}_{feeduserid}"
@ -84,20 +86,19 @@ def setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up the Emoncms sensor.""" """Set up the Emoncms sensor."""
apikey = config.get(CONF_API_KEY) apikey = config[CONF_API_KEY]
url = config.get(CONF_URL) url = config[CONF_URL]
sensorid = config.get(CONF_ID) sensorid = config[CONF_ID]
value_template = config.get(CONF_VALUE_TEMPLATE) value_template = config.get(CONF_VALUE_TEMPLATE)
config_unit = config.get(CONF_UNIT_OF_MEASUREMENT) config_unit = config.get(CONF_UNIT_OF_MEASUREMENT)
exclude_feeds = config.get(CONF_EXCLUDE_FEEDID) exclude_feeds = config.get(CONF_EXCLUDE_FEEDID)
include_only_feeds = config.get(CONF_ONLY_INCLUDE_FEEDID) include_only_feeds = config.get(CONF_ONLY_INCLUDE_FEEDID)
sensor_names = config.get(CONF_SENSOR_NAMES) sensor_names = config.get(CONF_SENSOR_NAMES)
interval = config.get(CONF_SCAN_INTERVAL)
if value_template is not None: if value_template is not None:
value_template.hass = hass value_template.hass = hass
data = EmonCmsData(hass, url, apikey, interval) data = EmonCmsData(hass, url, apikey)
data.update() data.update()
@ -140,8 +141,15 @@ class EmonCmsSensor(SensorEntity):
"""Implementation of an Emoncms sensor.""" """Implementation of an Emoncms sensor."""
def __init__( def __init__(
self, hass, data, name, value_template, unit_of_measurement, sensorid, elem self,
): hass: HomeAssistant,
data: EmonCmsData,
name: str | None,
value_template: template.Template | None,
unit_of_measurement: str | None,
sensorid: str,
elem: dict[str, Any],
) -> None:
"""Initialize the sensor.""" """Initialize the sensor."""
if name is None: if name is None:
# Suppress ID in sensor name if it's 1, since most people won't # Suppress ID in sensor name if it's 1, since most people won't
@ -150,16 +158,16 @@ class EmonCmsSensor(SensorEntity):
id_for_name = "" if str(sensorid) == "1" else sensorid id_for_name = "" if str(sensorid) == "1" else sensorid
# Use the feed name assigned in EmonCMS or fall back to the feed ID # 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") or f"Feed {elem['id']}"
self._name = f"EmonCMS{id_for_name} {feed_name}" self._attr_name = f"EmonCMS{id_for_name} {feed_name}"
else: else:
self._name = name self._attr_name = name
self._identifier = get_id( self._identifier = get_id(
sensorid, elem["tag"], elem["name"], elem["id"], elem["userid"] sensorid, elem["tag"], elem["name"], elem["id"], elem["userid"]
) )
self._hass = hass self._hass = hass
self._data = data self._data = data
self._value_template = value_template self._value_template = value_template
self._unit_of_measurement = unit_of_measurement self._attr_native_unit_of_measurement = unit_of_measurement
self._sensorid = sensorid self._sensorid = sensorid
self._elem = elem self._elem = elem
@ -189,32 +197,19 @@ class EmonCmsSensor(SensorEntity):
self._attr_state_class = SensorStateClass.MEASUREMENT self._attr_state_class = SensorStateClass.MEASUREMENT
if self._value_template is not None: if self._value_template is not None:
self._state = self._value_template.render_with_possible_json_value( self._attr_native_value = (
elem["value"], STATE_UNKNOWN self._value_template.render_with_possible_json_value(
elem["value"], STATE_UNKNOWN
)
) )
elif elem["value"] is not None: elif elem["value"] is not None:
self._state = round(float(elem["value"]), DECIMALS) self._attr_native_value = round(float(elem["value"]), DECIMALS)
else: else:
self._state = None self._attr_native_value = None
@property @property
def name(self): def extra_state_attributes(self) -> dict[str, Any]:
"""Return the name of the sensor.""" """Return the sensor extra attributes."""
return self._name
@property
def native_unit_of_measurement(self):
"""Return the unit of measurement of this entity, if any."""
return self._unit_of_measurement
@property
def native_value(self):
"""Return the state of the device."""
return self._state
@property
def extra_state_attributes(self):
"""Return the attributes of the sensor."""
return { return {
ATTR_FEEDID: self._elem["id"], ATTR_FEEDID: self._elem["id"],
ATTR_TAG: self._elem["tag"], ATTR_TAG: self._elem["tag"],
@ -254,28 +249,29 @@ class EmonCmsSensor(SensorEntity):
self._elem = elem self._elem = elem
if self._value_template is not None: if self._value_template is not None:
self._state = self._value_template.render_with_possible_json_value( self._attr_native_value = (
elem["value"], STATE_UNKNOWN self._value_template.render_with_possible_json_value(
elem["value"], STATE_UNKNOWN
)
) )
elif elem["value"] is not None: elif elem["value"] is not None:
self._state = round(float(elem["value"]), DECIMALS) self._attr_native_value = round(float(elem["value"]), DECIMALS)
else: else:
self._state = None self._attr_native_value = None
class EmonCmsData: class EmonCmsData:
"""The class for handling the data retrieval.""" """The class for handling the data retrieval."""
def __init__(self, hass, url, apikey, interval): def __init__(self, hass: HomeAssistant, url: str, apikey: str) -> None:
"""Initialize the data object.""" """Initialize the data object."""
self._apikey = apikey self._apikey = apikey
self._url = f"{url}/feed/list.json" self._url = f"{url}/feed/list.json"
self._interval = interval
self._hass = hass self._hass = hass
self.data = None self.data: list[dict[str, Any]] | None = None
@Throttle(MIN_TIME_BETWEEN_UPDATES) @Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self): def update(self) -> None:
"""Get the latest data from Emoncms.""" """Get the latest data from Emoncms."""
try: try:
parameters = {"apikey": self._apikey} parameters = {"apikey": self._apikey}