updated apps
This commit is contained in:
@@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
from abc import abstractmethod
|
||||
from collections.abc import Callable
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal, DecimalException
|
||||
from decimal import Decimal
|
||||
import logging
|
||||
import time
|
||||
from typing import Any
|
||||
@@ -19,7 +19,6 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_UNIT_OF_MEASUREMENT,
|
||||
CONF_DEVICE,
|
||||
CONF_DOMAIN,
|
||||
CONF_ENTITY_ID,
|
||||
CONF_NAME,
|
||||
@@ -49,11 +48,6 @@ from homeassistant.helpers.event import (
|
||||
from homeassistant.helpers.json import JSONEncoder
|
||||
from homeassistant.helpers.singleton import singleton
|
||||
from homeassistant.helpers.storage import Store
|
||||
from homeassistant.util.unit_conversion import (
|
||||
BaseUnitConverter,
|
||||
EnergyConverter,
|
||||
PowerConverter,
|
||||
)
|
||||
|
||||
from custom_components.powercalc.analytics.analytics import collect_analytics
|
||||
from custom_components.powercalc.const import (
|
||||
@@ -96,11 +90,11 @@ from custom_components.powercalc.const import (
|
||||
ENTRY_DATA_ENERGY_ENTITY,
|
||||
ENTRY_DATA_POWER_ENTITY,
|
||||
SERVICE_RESET_ENERGY,
|
||||
UNAVAILABLE_STATES,
|
||||
GroupType,
|
||||
SensorType,
|
||||
UnitPrefix,
|
||||
)
|
||||
from custom_components.powercalc.device_binding import get_device_info
|
||||
from custom_components.powercalc.group_include.filter import (
|
||||
AreaFilter,
|
||||
CompositeFilter,
|
||||
@@ -119,8 +113,13 @@ from custom_components.powercalc.sensors.abstract import (
|
||||
generate_power_sensor_name,
|
||||
)
|
||||
from custom_components.powercalc.sensors.energy import EnergySensor, VirtualEnergySensor
|
||||
from custom_components.powercalc.sensors.energy_related import create_energy_related_sensors
|
||||
from custom_components.powercalc.sensors.power import PowerSensor
|
||||
from custom_components.powercalc.sensors.utility_meter import create_utility_meters
|
||||
from custom_components.powercalc.unit import (
|
||||
ENERGY_UNIT_PREFIX_MAPPING,
|
||||
convert_to_decimal,
|
||||
parse_decimal,
|
||||
)
|
||||
|
||||
ENTITY_ID_FORMAT = SENSOR_DOMAIN + ".{}"
|
||||
|
||||
@@ -130,17 +129,6 @@ STORAGE_VERSION = 2
|
||||
# How long between periodically saving the current states to disk
|
||||
STATE_DUMP_INTERVAL = timedelta(minutes=10)
|
||||
|
||||
ENERGY_UNIT_PREFIX_MAPPING = {
|
||||
UnitPrefix.KILO: UnitOfEnergy.KILO_WATT_HOUR,
|
||||
UnitPrefix.MEGA: UnitOfEnergy.MEGA_WATT_HOUR,
|
||||
UnitPrefix.NONE: UnitOfEnergy.WATT_HOUR,
|
||||
}
|
||||
|
||||
UNIT_CONVERTERS: dict[str | None, type[BaseUnitConverter]] = {
|
||||
**dict.fromkeys(EnergyConverter.VALID_UNITS, EnergyConverter),
|
||||
**dict.fromkeys(PowerConverter.VALID_UNITS, PowerConverter),
|
||||
}
|
||||
|
||||
|
||||
def create_group_sensors_yaml(
|
||||
hass: HomeAssistant,
|
||||
@@ -224,13 +212,7 @@ def create_group_sensors_custom(
|
||||
group_sensors.append(energy_sensor)
|
||||
|
||||
sensor_config[CONF_UTILITY_METER_NET_CONSUMPTION] = True
|
||||
group_sensors.extend(
|
||||
create_utility_meters(
|
||||
hass,
|
||||
energy_sensor,
|
||||
sensor_config,
|
||||
),
|
||||
)
|
||||
group_sensors.extend(create_energy_related_sensors(hass, sensor_config, energy_sensor))
|
||||
|
||||
collect_analytics(hass, None).add(DATA_GROUP_SIZES, len(power_sensor_ids) + len(energy_sensor_ids))
|
||||
|
||||
@@ -388,7 +370,6 @@ def create_grouped_power_sensor(
|
||||
sensor_config=sensor_config,
|
||||
group_type=group_type,
|
||||
entity_id=entity_id,
|
||||
device_id=sensor_config.get(CONF_DEVICE),
|
||||
)
|
||||
|
||||
|
||||
@@ -428,7 +409,6 @@ def create_grouped_energy_sensor(
|
||||
name=name,
|
||||
unique_id=energy_unique_id,
|
||||
sensor_config=sensor_config,
|
||||
device_info=get_device_info(hass, sensor_config, None),
|
||||
unit_prefix=sensor_config.get(CONF_ENERGY_SENSOR_UNIT_PREFIX, UnitPrefix.NONE),
|
||||
)
|
||||
|
||||
@@ -440,7 +420,6 @@ def create_grouped_energy_sensor(
|
||||
sensor_config=sensor_config,
|
||||
group_type=group_type,
|
||||
entity_id=entity_id,
|
||||
device_id=sensor_config.get(CONF_DEVICE),
|
||||
)
|
||||
|
||||
|
||||
@@ -465,10 +444,8 @@ class GroupedSensor(BaseEntity, SensorEntity):
|
||||
sensor_config: dict[str, Any],
|
||||
group_type: GroupType,
|
||||
unique_id: str | None = None,
|
||||
device_id: str | None = None,
|
||||
) -> None:
|
||||
self.entity_id = entity_id
|
||||
self.source_device_id = device_id
|
||||
|
||||
self._attr_name = name
|
||||
# Remove own entity from entities, when it happens to be there. To prevent recursion
|
||||
@@ -569,7 +546,7 @@ class GroupedSensor(BaseEntity, SensorEntity):
|
||||
SensorDeviceClass.ENERGY if self._is_energy_sensor else SensorDeviceClass.POWER,
|
||||
)
|
||||
excluded_entities = self._sensor_config.get(CONF_EXCLUDE_ENTITIES) or []
|
||||
self._entities = set({entity for entity in entities if entity not in excluded_entities})
|
||||
self._entities = {entity for entity in entities if entity not in excluded_entities}
|
||||
|
||||
async def on_start(self, _: HomeAssistant) -> None:
|
||||
"""Initialize group sensor when HA is starting."""
|
||||
@@ -595,9 +572,7 @@ class GroupedSensor(BaseEntity, SensorEntity):
|
||||
"""Initial update for the group sensor state."""
|
||||
all_states = [self.hass.states.get(entity_id) for entity_id in self._entities]
|
||||
states: list[State] = list(filter(None, all_states))
|
||||
available_states = [
|
||||
state for state in states if state and state.state not in [STATE_UNKNOWN, STATE_UNAVAILABLE]
|
||||
]
|
||||
available_states = [state for state in states if state and state.state not in UNAVAILABLE_STATES]
|
||||
if not available_states and not self._ignore_unavailable_state:
|
||||
new_state: Decimal | str = STATE_UNAVAILABLE
|
||||
else:
|
||||
@@ -663,21 +638,19 @@ class GroupedSensor(BaseEntity, SensorEntity):
|
||||
|
||||
def _get_state_value_in_native_unit(self, state: State) -> Decimal:
|
||||
"""Convert value of member entity state to match the unit of measurement of the group sensor."""
|
||||
value: str | float = state.state
|
||||
unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
|
||||
if unit and self._attr_native_unit_of_measurement != unit:
|
||||
converter = UNIT_CONVERTERS[unit]
|
||||
value = converter.convert(float(value), unit, self._attr_native_unit_of_measurement)
|
||||
try:
|
||||
return Decimal(value)
|
||||
except DecimalException as err:
|
||||
value = convert_to_decimal(state.state, unit, self._attr_native_unit_of_measurement)
|
||||
else:
|
||||
value = parse_decimal(state.state)
|
||||
if value is None:
|
||||
_LOGGER.warning(
|
||||
"Error converting state value %s to Decimal for %s: %s",
|
||||
value,
|
||||
"Error converting state value %s to Decimal for %s",
|
||||
state.state,
|
||||
state.entity_id,
|
||||
err,
|
||||
)
|
||||
return Decimal(0)
|
||||
return value
|
||||
|
||||
def _set_native_value(self, value: Decimal, write_state: bool = True) -> None:
|
||||
self._native_value_exact = value
|
||||
@@ -711,7 +684,7 @@ class GroupedSensor(BaseEntity, SensorEntity):
|
||||
ATTR_UNIT_OF_MEASUREMENT: None,
|
||||
}
|
||||
|
||||
if state.state in [STATE_UNKNOWN, STATE_UNAVAILABLE]:
|
||||
if state.state in UNAVAILABLE_STATES:
|
||||
return {
|
||||
ATTR_STATE: str(state.state),
|
||||
ATTR_UNIT_OF_MEASUREMENT: state.attributes.get(ATTR_UNIT_OF_MEASUREMENT),
|
||||
@@ -758,7 +731,7 @@ class GroupedPowerSensor(GroupedSensor, PowerSensor):
|
||||
return self.get_summed_state()
|
||||
|
||||
def calculate_new_state(self, state: State) -> Decimal | str:
|
||||
if state.state in [STATE_UNKNOWN, STATE_UNAVAILABLE]:
|
||||
if state.state in UNAVAILABLE_STATES:
|
||||
if state.entity_id in self._member_states:
|
||||
del self._member_states[state.entity_id]
|
||||
else:
|
||||
@@ -788,7 +761,6 @@ class GroupedEnergySensor(GroupedSensor, RestoreSensor, EnergySensor):
|
||||
sensor_config: dict[str, Any],
|
||||
group_type: GroupType,
|
||||
unique_id: str | None = None,
|
||||
device_id: str | None = None,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
hass,
|
||||
@@ -798,7 +770,6 @@ class GroupedEnergySensor(GroupedSensor, RestoreSensor, EnergySensor):
|
||||
sensor_config,
|
||||
group_type,
|
||||
unique_id,
|
||||
device_id,
|
||||
)
|
||||
|
||||
self._attr_native_unit_of_measurement = ENERGY_UNIT_PREFIX_MAPPING.get(
|
||||
@@ -853,7 +824,7 @@ class GroupedEnergySensor(GroupedSensor, RestoreSensor, EnergySensor):
|
||||
|
||||
For each member, calculate the delta between the previous known state and the current.
|
||||
"""
|
||||
group_sum = Decimal(self._native_value_exact) if self._native_value_exact else Decimal(0)
|
||||
group_sum = self._native_value_exact
|
||||
_LOGGER.debug("%s: Recalculate, current value: %s", self.entity_id, group_sum)
|
||||
for state in member_available_states:
|
||||
group_sum += self.calculate_delta(state)
|
||||
@@ -866,8 +837,8 @@ class GroupedEnergySensor(GroupedSensor, RestoreSensor, EnergySensor):
|
||||
return group_sum
|
||||
|
||||
def calculate_new_state(self, state: State) -> Decimal | str:
|
||||
group_sum = Decimal(self._native_value_exact) if self._native_value_exact else Decimal(0)
|
||||
if state.state in [STATE_UNKNOWN, STATE_UNAVAILABLE]:
|
||||
group_sum = self._native_value_exact
|
||||
if state.state in UNAVAILABLE_STATES:
|
||||
if group_sum == 0:
|
||||
return STATE_UNAVAILABLE
|
||||
_LOGGER.debug(
|
||||
@@ -931,22 +902,23 @@ class GroupedEnergySensor(GroupedSensor, RestoreSensor, EnergySensor):
|
||||
return
|
||||
|
||||
last_sensor_state = await self.async_get_last_sensor_data()
|
||||
try:
|
||||
if last_sensor_state and last_sensor_state.native_value:
|
||||
self._set_native_value(Decimal(last_sensor_state.native_value)) # type: ignore
|
||||
elif last_state:
|
||||
self._set_native_value(Decimal(last_state.state))
|
||||
_LOGGER.debug(
|
||||
"%s: Restoring state: %s",
|
||||
self.entity_id,
|
||||
self._attr_native_value,
|
||||
)
|
||||
except DecimalException as err:
|
||||
_LOGGER.warning(
|
||||
"%s: Could not restore last state: %s",
|
||||
self.entity_id,
|
||||
err,
|
||||
)
|
||||
if last_sensor_state and last_sensor_state.native_value:
|
||||
restored = parse_decimal(last_sensor_state.native_value)
|
||||
elif last_state:
|
||||
restored = parse_decimal(last_state.state)
|
||||
else:
|
||||
restored = None
|
||||
|
||||
if restored is None:
|
||||
_LOGGER.warning("%s: Could not restore last state", self.entity_id)
|
||||
return
|
||||
|
||||
self._set_native_value(restored)
|
||||
_LOGGER.debug(
|
||||
"%s: Restoring state: %s",
|
||||
self.entity_id,
|
||||
self._attr_native_value,
|
||||
)
|
||||
|
||||
|
||||
class PreviousStateStore:
|
||||
|
||||
Reference in New Issue
Block a user