Skip to content

Commit

Permalink
HACS update to PowerCalc #16 #89
Browse files Browse the repository at this point in the history
  • Loading branch information
BeardedTinker committed Nov 12, 2022
1 parent 9d14ea1 commit 2b56d2b
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 35 deletions.
2 changes: 1 addition & 1 deletion custom_components/powercalc/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@
"requirements": [
"numpy>=1.21.1"
],
"version": "v1.0.4"
"version": "v1.0.5"
}
20 changes: 1 addition & 19 deletions custom_components/powercalc/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,29 +151,11 @@

_LOGGER = logging.getLogger(__name__)

SUPPORTED_ENTITY_DOMAINS = [
light.DOMAIN,
switch.DOMAIN,
fan.DOMAIN,
humidifier.DOMAIN,
binary_sensor.DOMAIN,
climate.DOMAIN,
device_tracker.DOMAIN,
remote.DOMAIN,
media_player.DOMAIN,
input_boolean.DOMAIN,
input_number.DOMAIN,
input_select.DOMAIN,
sensor.DOMAIN,
vacuum.DOMAIN,
water_heater.DOMAIN,
]

MAX_GROUP_NESTING_LEVEL = 5

SENSOR_CONFIG = {
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_ENTITY_ID): cv.entity_domain(SUPPORTED_ENTITY_DOMAINS),
vol.Optional(CONF_ENTITY_ID): cv.entity_id,
vol.Optional(CONF_UNIQUE_ID): cv.string,
vol.Optional(CONF_MODEL): cv.string,
vol.Optional(CONF_MANUFACTURER): cv.string,
Expand Down
74 changes: 59 additions & 15 deletions custom_components/powercalc/sensors/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from typing import Any, Callable

import homeassistant.util.dt as dt_util
from awesomeversion.awesomeversion import AwesomeVersion
from homeassistant.components.sensor import ATTR_STATE_CLASS
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.sensor import (
Expand All @@ -25,11 +26,19 @@
STATE_UNAVAILABLE,
STATE_UNKNOWN,
)
from homeassistant.const import __version__ as HA_VERSION
from homeassistant.core import CoreState, HomeAssistant, State, callback
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.event import async_track_state_change_event
from homeassistant.helpers.restore_state import RestoreEntity

if AwesomeVersion(HA_VERSION) >= AwesomeVersion("2022.10.0"):
from homeassistant.util.unit_conversion import (
EnergyConverter,
PowerConverter,
BaseUnitConverter,
)

from ..const import (
ATTR_ENTITIES,
ATTR_IS_GROUP,
Expand Down Expand Up @@ -349,6 +358,9 @@ def __init__(
if unique_id:
self._attr_unique_id = unique_id
self.entity_id = entity_id
self.unit_converter: BaseUnitConverter | None = None
if hasattr(self, "get_unit_converter"):
self.unit_converter = self.get_unit_converter()

async def async_added_to_hass(self) -> None:
"""Register state listeners."""
Expand Down Expand Up @@ -410,32 +422,64 @@ def on_state_change(self, event) -> None:
if state and state.state not in [STATE_UNKNOWN, STATE_UNAVAILABLE]
]

# Remove members with an incompatible unit of measurement for now
# Maybe we will convert these units in the future
for state in available_states:
unit_of_measurement = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
if (
unit_of_measurement is None
): # No unit of measurement, probably sensor has been reset
continue
if unit_of_measurement != self._attr_native_unit_of_measurement:
_LOGGER.warning(
f"Group member '{state.entity_id}' has another unit of measurement '{unit_of_measurement}' than the group '{self.entity_id}' which has '{self._attr_native_unit_of_measurement}', this is not supported yet. Removing this entity from the total sum."
)
available_states.remove(state)
self._entities.remove(state.entity_id)
apply_unit_conversions = AwesomeVersion(HA_VERSION) >= AwesomeVersion(
"2022.10.0"
)
if not apply_unit_conversions:
self._remove_incompatible_unit_entities(available_states)

if not available_states:
self._attr_available = False
self.async_schedule_update_ha_state(True)
return

summed = sum(Decimal(state.state) for state in available_states)
summed = sum(self._get_state_values(available_states, apply_unit_conversions))

self._attr_native_value = round(summed, self._rounding_digits)
self._attr_available = True
self.async_schedule_update_ha_state(True)

def _get_state_values(
self, states: list[State], apply_unit_conversions: bool
) -> list[Decimal]:
"""Get the state value from all individual entity state. Apply unit conversions"""
values = []
for state in states:
value = float(state.state)
unit_of_measurement = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
if (
unit_of_measurement
and apply_unit_conversions
and self._attr_native_unit_of_measurement != unit_of_measurement
):
unit_converter = (
EnergyConverter
if isinstance(self, GroupedEnergySensor)
else PowerConverter
)
value = unit_converter.convert(
value, unit_of_measurement, self._attr_native_unit_of_measurement
)
values.append(Decimal(value))
return values

def _remove_incompatible_unit_entities(
self, states: list[State]
) -> None: # pragma: no cover
"""Remove members with an incompatible unit of measurements"""
for state in states:
unit_of_measurement = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
if (
unit_of_measurement is None
): # No unit of measurement, probably sensor has been reset
continue
if unit_of_measurement != self._attr_native_unit_of_measurement:
_LOGGER.warning(
f"Group member '{state.entity_id}' has another unit of measurement '{unit_of_measurement}' than the group '{self.entity_id}' which has '{self._attr_native_unit_of_measurement}', this is not supported yet. Removing this entity from the total sum."
)
states.remove(state)
self._entities.remove(state.entity_id)


class GroupedPowerSensor(GroupedSensor, PowerSensor):
"""Grouped power sensor. Sums all values of underlying individual power sensors"""
Expand Down

0 comments on commit 2b56d2b

Please sign in to comment.