Skip to content

Commit

Permalink
Merge branch 'release/1.6.6'
Browse files Browse the repository at this point in the history
  • Loading branch information
Limych committed Nov 21, 2020
2 parents 7d7d0ba + 3ea64a0 commit 28a7a50
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 84 deletions.
68 changes: 41 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,41 +38,55 @@ I also suggest you [visit the support topic][forum-support] on the community for

* Since version 1.3.0 the default sensor name is “Average” instead of “Average Temperature”

## Known Limitations and Issues

* Due to the fact that HA does not store in history the temperature units of measurement for weather, climate and water heater entities, the average sensor always assumes that their values ​​are specified in the same units that are now configured in HA globally.

## Installation

### Install from HACS (recommended)

1. Just search for Average sensor integration in [HACS][hacs] and install it.
1. Add `average` sensor to your `configuration.yaml` file. See configuration examples below.
1. Restart Home Assistant

### Manual installation

1. Using the tool of choice open the directory (folder) for your HA configuration (where you find `configuration.yaml`).
1. If you do not have a `custom_components` directory (folder) there, you need to create it.
1. In the `custom_components` directory (folder) create a new folder called `average`.
1. Download _all_ the files from the `custom_components/average/` directory (folder) in this repository.
1. Place the files you downloaded in the new directory (folder) you created.
1. Add `average` sensor to your `configuration.yaml` file. See configuration examples below.
1. Restart Home Assistant
1. Add `average` sensor to your `configuration.yaml` file:

To measure the average current temperature from multiple sources:
```yaml
# Example configuration.yaml entry
sensor:
- platform: average
name: 'Average Temperature'
entities:
- weather.gismeteo
- sensor.owm_temperature
- sensor.dark_sky_temperature
```
To measure average temperature for some period:
```yaml
# Example configuration.yaml entry
sensor:
- platform: average
name: 'Average Temperature'
duration:
days: 1
entities:
- sensor.gismeteo_temperature
```
or you can combine this variants for some reason.

### Configuration Examples

To measure the average of current values from multiple sources:
```yaml
# Example configuration.yaml entry
sensor:
- platform: average
name: 'Average Temperature'
entities:
- weather.gismeteo
- sensor.owm_temperature
- sensor.dark_sky_temperature
```
To measure the average of all values of a single source over a period:
```yaml
# Example configuration.yaml entry
sensor:
- platform: average
name: 'Average Temperature'
duration:
days: 1
entities:
- sensor.gismeteo_temperature
```
or you can combine this variants for some reason.
<p align="center">* * *</p>
I put a lot of work into making this repo and component available and updated to inspire and help others! I will be glad to receive thanks from you — it will give me new strength and add enthusiasm:
Expand Down
2 changes: 1 addition & 1 deletion bin/setup
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ set -e
ROOT="$( cd "$( dirname "$(readlink -f "$0")" )/.." >/dev/null 2>&1 && pwd )"

cd "${ROOT}"
script/bootstrap
bin/bootstrap

pre-commit install
pip3 install -r requirements-dev.txt
Expand Down
84 changes: 36 additions & 48 deletions custom_components/average/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,21 @@
import homeassistant.util.dt as dt_util
import voluptuous as vol
from homeassistant.components import history
from homeassistant.components.climate import ClimateDevice
from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN
from homeassistant.components.group import expand_entity_ids
from homeassistant.components.water_heater import WaterHeaterDevice
from homeassistant.components.weather import WeatherEntity
from homeassistant.components.history import LazyState
from homeassistant.components.water_heater import DOMAIN as WATER_HEATER_DOMAIN
from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN
from homeassistant.const import (
CONF_NAME,
CONF_ENTITIES,
EVENT_HOMEASSISTANT_START,
ATTR_UNIT_OF_MEASUREMENT,
UNIT_NOT_RECOGNIZED_TEMPLATE,
TEMPERATURE,
STATE_UNKNOWN,
STATE_UNAVAILABLE,
ATTR_ICON,
)
from homeassistant.core import callback
from homeassistant.core import callback, split_entity_id
from homeassistant.exceptions import TemplateError
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA
Expand Down Expand Up @@ -233,47 +232,29 @@ def _has_state(state) -> bool:
"None",
]

@staticmethod
def _is_temperature(entity) -> bool:
"""Return True if entity are temperature sensor."""
entity_unit = entity.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
return entity_unit in TEMPERATURE_UNITS or isinstance(
entity, (WeatherEntity, ClimateDevice, WaterHeaterDevice)
)

def _get_temperature(self, entity) -> Optional[float]:
def _get_temperature(self, state: LazyState) -> Optional[float]:
"""Get temperature value from entity."""
if isinstance(entity, WeatherEntity):
temperature = entity.temperature
entity_unit = entity.temperature_unit
elif isinstance(entity, (ClimateDevice, WaterHeaterDevice)):
temperature = entity.current_temperature
entity_unit = entity.temperature_unit
ha_unit = self._hass.config.units.temperature_unit
domain = split_entity_id(state.entity_id)[0]
if domain == WEATHER_DOMAIN:
temperature = state.attributes.get("temperature")
entity_unit = ha_unit
elif domain in (CLIMATE_DOMAIN, WATER_HEATER_DOMAIN):
temperature = state.attributes.get("current_temperature")
entity_unit = ha_unit
else:
temperature = entity.state
entity_unit = entity.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
temperature = state.state
entity_unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)

if not self._has_state(temperature):
return None

if entity_unit not in TEMPERATURE_UNITS:
raise ValueError(
UNIT_NOT_RECOGNIZED_TEMPLATE.format(entity_unit, TEMPERATURE)
)

temperature = float(temperature)
ha_unit = self._hass.config.units.temperature_unit

if entity_unit != ha_unit:
temperature = convert_temperature(temperature, entity_unit, ha_unit)

temperature = convert_temperature(float(temperature), entity_unit, ha_unit)
return temperature

def _get_entity_state(self, entity):
"""Return current state of given entity and count some sensor attributes."""
state = (
self._get_temperature(entity) if self._temperature_mode else entity.state
)
def _get_state_value(self, state: LazyState) -> Optional[float]:
"""Return value of given entity state and count some sensor attributes."""
state = self._get_temperature(state) if self._temperature_mode else state.state
if not self._has_state(state):
return self._undef

Expand Down Expand Up @@ -422,29 +403,36 @@ def _update_state(self): # pylint: disable=r0914,r0912,r0915
for entity_id in self.sources:
_LOGGER.debug('Processing entity "%s"', entity_id)

entity = self._hass.states.get(entity_id)
state = self._hass.states.get(entity_id) # type: LazyState

if entity is None:
if state is None:
_LOGGER.error('Unable to find an entity "%s"', entity_id)
continue

if self._temperature_mode is None:
self._temperature_mode = self._is_temperature(entity)
domain = split_entity_id(state.entity_id)[0]
self._temperature_mode = (
domain in (WEATHER_DOMAIN, CLIMATE_DOMAIN, WATER_HEATER_DOMAIN)
or state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
in TEMPERATURE_UNITS
)
if self._temperature_mode:
_LOGGER.debug("%s is a temperature entity.", entity_id)
self._unit_of_measurement = self._hass.config.units.temperature_unit
self._icon = "mdi:thermometer"
else:
self._unit_of_measurement = entity.attributes.get(
_LOGGER.debug("%s is NOT a temperature entity.", entity_id)
self._unit_of_measurement = state.attributes.get(
ATTR_UNIT_OF_MEASUREMENT
)
self._icon = entity.attributes.get(ATTR_ICON)
self._icon = state.attributes.get(ATTR_ICON)

value = 0
elapsed = 0

if self._period is None:
# Get current state
value = self._get_entity_state(entity)
value = self._get_state_value(state)
_LOGGER.debug("Current state: %s", value)

else:
Expand All @@ -454,7 +442,7 @@ def _update_state(self): # pylint: disable=r0914,r0912,r0915
)

if entity_id not in history_list.keys():
value = self._get_entity_state(entity)
value = self._get_state_value(state)
_LOGGER.warning(
'Historical data not found for entity "%s". '
"Current state used: %s",
Expand All @@ -468,13 +456,13 @@ def _update_state(self): # pylint: disable=r0914,r0912,r0915
last_state = None
last_time = start_ts
if item is not None and self._has_state(item.state):
last_state = self._get_entity_state(item)
last_state = self._get_state_value(item)

# Get the other states
for item in history_list.get(entity_id):
_LOGGER.debug("Historical state: %s", item)
if self._has_state(item.state):
current_state = self._get_entity_state(item)
current_state = self._get_state_value(item)
current_time = item.last_changed.timestamp()

if last_state is not None:
Expand Down
6 changes: 3 additions & 3 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
-r requirements.txt
black==20.8b1
flake8~=3.8
mypy==0.782
mypy==0.790
packaging~=20.4
pre-commit~=2.7
pre-commit~=2.8
PyGithub==1.53
pylint~=2.6
pylint-strict-informational==0.1
pyupgrade~=2.7
yamllint~=1.24
yamllint~=1.25
7 changes: 2 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
geopy
geohash2
voluptuous
homeassistant
sqlalchemy
voluptuous==0.12
homeassistant~=0.118

0 comments on commit 28a7a50

Please sign in to comment.