From c71fc0f335ef1925d1b479f5db9b738bc465d13c Mon Sep 17 00:00:00 2001 From: Andrey Khrolenok Date: Sun, 28 Mar 2021 01:54:45 +0300 Subject: [PATCH] Add device_class for average sensor --- .devcontainer/bootstrap.sh | 8 ----- .devcontainer/configuration.yaml | 4 +++ custom_components/average/sensor.py | 49 ++++++++++++++++++----------- 3 files changed, 34 insertions(+), 27 deletions(-) delete mode 100755 .devcontainer/bootstrap.sh diff --git a/.devcontainer/bootstrap.sh b/.devcontainer/bootstrap.sh deleted file mode 100755 index 1b4c33a..0000000 --- a/.devcontainer/bootstrap.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -ROOT="$( cd "$( dirname "$(readlink -f "$0")" )/.." >/dev/null 2>&1 && pwd )" - -GITHUB_TOKEN=$(grep github_token ${ROOT}/secrets.yaml | cut -d' ' -f2) -FILES=$(grep "{GITHUB_TOKEN}" ${ROOT}/requirements.txt | sed "s/{GITHUB_TOKEN}/${GITHUB_TOKEN}/g" | tr "\r\n" " ") - -python3 -m pip install --upgrade ${FILES} diff --git a/.devcontainer/configuration.yaml b/.devcontainer/configuration.yaml index 72ac9c5..e2df39f 100644 --- a/.devcontainer/configuration.yaml +++ b/.devcontainer/configuration.yaml @@ -13,8 +13,12 @@ sensor: sensors: test1: value_template: "{{ state_attr('sun.sun', 'elevation') }}" + unit_of_measurement: '°C' + device_class: 'temperature' test2: value_template: "{{ 2 }}" + unit_of_measurement: '°C' + device_class: 'temperature' - platform: average entities: diff --git a/custom_components/average/sensor.py b/custom_components/average/sensor.py index 48da1db..1c0ea53 100644 --- a/custom_components/average/sensor.py +++ b/custom_components/average/sensor.py @@ -24,10 +24,12 @@ from homeassistant.components.water_heater import DOMAIN as WATER_HEATER_DOMAIN from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN from homeassistant.const import ( + ATTR_DEVICE_CLASS, ATTR_ICON, ATTR_UNIT_OF_MEASUREMENT, CONF_ENTITIES, CONF_NAME, + DEVICE_CLASS_TEMPERATURE, EVENT_HOMEASSISTANT_START, STATE_UNAVAILABLE, STATE_UNKNOWN, @@ -142,6 +144,7 @@ def __init__( self._unit_of_measurement = None self._icon = None self._temperature_mode = None + self._device_class = None self.sources = expand_entity_ids(hass, entity_ids) self.count_sources = len(self.sources) @@ -191,6 +194,11 @@ def state(self) -> Union[None, str, int, float]: """Return the state of the sensor.""" return self._state if self.available else STATE_UNAVAILABLE + @property + def device_class(self) -> Optional[str]: + """Return the class of this device, from component DEVICE_CLASSES.""" + return self._device_class + @property def unit_of_measurement(self) -> Optional[str]: """Return the unit of measurement of this entity.""" @@ -266,8 +274,8 @@ def _get_temperature(self, state: LazyState) -> Optional[float]: try: temperature = convert_temperature(float(temperature), entity_unit, ha_unit) - except ValueError: - _LOGGER.error('Could not convert value "%s" to float', state) + except ValueError as exc: + _LOGGER.error('Could not convert value "%s" to float: %s', state, exc) return None return temperature @@ -280,8 +288,8 @@ def _get_state_value(self, state: LazyState) -> Optional[float]: try: state = float(state) - except ValueError: - _LOGGER.error('Could not convert value "%s" to float', state) + except ValueError as exc: + _LOGGER.error('Could not convert value "%s" to float: %s', state, exc) return None self.count += 1 @@ -300,14 +308,16 @@ def update(self): self._update_state() @staticmethod - def handle_template_exception(ex, field): + def handle_template_exception(exc, field): """Log an error nicely if the template cannot be interpreted.""" - if ex.args and ex.args[0].startswith("UndefinedError: 'None' has no attribute"): + if exc.args and exc.args[0].startswith( + "UndefinedError: 'None' has no attribute" + ): # Common during HA startup - so just a warning - _LOGGER.warning(ex) - return - _LOGGER.error("Error parsing template for field %s", field) - _LOGGER.error(ex) + _LOGGER.warning(exc) + + else: + _LOGGER.error('Error parsing template for field "%s": %s', field, exc) def _update_period(self): # pylint: disable=r0912 """Parse the templates and calculate a datetime tuples.""" @@ -331,7 +341,7 @@ def _update_period(self): # pylint: disable=r0912 ) except ValueError: _LOGGER.error( - "Parsing error: start must be a datetime" "or a timestamp" + 'Parsing error: field "start" must be a datetime or a timestamp' ) return @@ -352,7 +362,7 @@ def _update_period(self): # pylint: disable=r0912 ) except ValueError: _LOGGER.error( - "Parsing error: end must be a datetime " "or a timestamp" + 'Parsing error: field "end" must be a datetime or a timestamp' ) return @@ -433,20 +443,21 @@ def _update_state(self): # pylint: disable=r0914,r0912,r0915 if self._temperature_mode is None: domain = split_entity_id(state.entity_id)[0] + self._device_class = state.attributes.get(ATTR_DEVICE_CLASS) + self._unit_of_measurement = state.attributes.get( + ATTR_UNIT_OF_MEASUREMENT + ) self._temperature_mode = ( - domain in (WEATHER_DOMAIN, CLIMATE_DOMAIN, WATER_HEATER_DOMAIN) - or state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) - in TEMPERATURE_UNITS + self._device_class == DEVICE_CLASS_TEMPERATURE + or domain in (WEATHER_DOMAIN, CLIMATE_DOMAIN, WATER_HEATER_DOMAIN) + or self._unit_of_measurement in TEMPERATURE_UNITS ) if self._temperature_mode: _LOGGER.debug("%s is a temperature entity.", entity_id) + self._device_class = DEVICE_CLASS_TEMPERATURE self._unit_of_measurement = self._hass.config.units.temperature_unit - self._icon = "mdi:thermometer" else: _LOGGER.debug("%s is NOT a temperature entity.", entity_id) - self._unit_of_measurement = state.attributes.get( - ATTR_UNIT_OF_MEASUREMENT - ) self._icon = state.attributes.get(ATTR_ICON) value = 0