Initil after Upgrade

This commit is contained in:
2026-06-15 10:53:52 -04:00
parent 2fe9bf0dd6
commit 887feaa50a
143 changed files with 2288 additions and 881 deletions
@@ -20,11 +20,11 @@ from custom_components.powercalc.const import (
_LOGGER = logging.getLogger(__name__)
async def remove_power_sensor_from_associated_groups(
def remove_power_sensor_from_associated_groups(
hass: HomeAssistant,
config_entry: ConfigEntry,
) -> list[ConfigEntry]:
"""When the user remove a virtual power config entry we need to update all the groups which this sensor belongs to."""
"""When the user removes a virtual power config entry, update all groups this sensor belongs to."""
group_entries = get_groups_having_member(hass, config_entry)
for group_entry in group_entries:
@@ -39,18 +39,18 @@ async def remove_power_sensor_from_associated_groups(
return group_entries
async def add_to_associated_groups(hass: HomeAssistant, config_entry: ConfigEntry) -> ConfigEntry | None: # type: ignore
async def add_to_associated_groups(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
"""
When the user has set a group on a virtual power config entry,
we need to add this config entry to the group members sensors and update the group.
"""
sensor_type = config_entry.data.get(CONF_SENSOR_TYPE)
if sensor_type not in [SensorType.VIRTUAL_POWER, SensorType.DAILY_ENERGY]:
return None
return
raw_groups = config_entry.data.get(CONF_GROUP)
if not raw_groups:
return None
return
group_ids = raw_groups if isinstance(raw_groups, list) else [raw_groups]
for group_entry_id in group_ids:
@@ -130,7 +130,9 @@ async def add_to_associated_group(
def get_entries_having_subgroup(hass: HomeAssistant, subgroup_entry: ConfigEntry) -> list[ConfigEntry]:
"""Get all virtual power entries which have the subgroup in their subgroups list."""
return [entry for entry in get_group_entries(hass) if subgroup_entry.entry_id in (entry.data.get(CONF_SUB_GROUPS) or [])]
return [
entry for entry in get_group_entries(hass) if subgroup_entry.entry_id in (entry.data.get(CONF_SUB_GROUPS) or [])
]
def get_groups_having_member(hass: HomeAssistant, member_entry: ConfigEntry) -> list[ConfigEntry]:
@@ -138,7 +140,8 @@ def get_groups_having_member(hass: HomeAssistant, member_entry: ConfigEntry) ->
return [
entry
for entry in hass.config_entries.async_entries(DOMAIN)
if entry.data.get(CONF_SENSOR_TYPE) == SensorType.GROUP and member_entry.entry_id in (entry.data.get(CONF_GROUP_MEMBER_SENSORS) or [])
if entry.data.get(CONF_SENSOR_TYPE) == SensorType.GROUP
and member_entry.entry_id in (entry.data.get(CONF_GROUP_MEMBER_SENSORS) or [])
]
@@ -154,4 +157,6 @@ def get_group_entries(hass: HomeAssistant, group_type: GroupType | None = None)
@callback
def get_entries_excluding_global_config(hass: HomeAssistant) -> list[ConfigEntry]:
return [entry for entry in hass.config_entries.async_entries(DOMAIN) if entry.unique_id != ENTRY_GLOBAL_CONFIG_UNIQUE_ID]
return [
entry for entry in hass.config_entries.async_entries(DOMAIN) if entry.unique_id != ENTRY_GLOBAL_CONFIG_UNIQUE_ID
]
@@ -59,6 +59,8 @@ from custom_components.powercalc.analytics.analytics import collect_analytics
from custom_components.powercalc.const import (
ATTR_ENTITIES,
ATTR_IS_GROUP,
ATTR_MEMBERS,
ATTR_STATE,
CONF_ALL,
CONF_AREA,
CONF_CREATE_ENERGY_SENSOR,
@@ -99,7 +101,14 @@ from custom_components.powercalc.const import (
UnitPrefix,
)
from custom_components.powercalc.device_binding import get_device_info
from custom_components.powercalc.group_include.filter import AreaFilter, CompositeFilter, DeviceFilter, EntityFilter, FilterOperator, FloorFilter
from custom_components.powercalc.group_include.filter import (
AreaFilter,
CompositeFilter,
DeviceFilter,
EntityFilter,
FilterOperator,
FloorFilter,
)
from custom_components.powercalc.group_include.include import find_entities
from custom_components.powercalc.helpers import async_cache
from custom_components.powercalc.sensors.abstract import (
@@ -133,7 +142,7 @@ UNIT_CONVERTERS: dict[str | None, type[BaseUnitConverter]] = {
}
async def create_group_sensors_yaml(
def create_group_sensors_yaml(
hass: HomeAssistant,
sensor_config: dict[str, Any],
entities: list[Entity],
@@ -152,7 +161,7 @@ async def create_group_sensors_yaml(
)
group_name = str(sensor_config.get(CONF_CREATE_GROUP))
return await create_group_sensors_custom(hass, group_name, sensor_config, power_sensor_ids, energy_sensor_ids)
return create_group_sensors_custom(hass, group_name, sensor_config, power_sensor_ids, energy_sensor_ids)
async def create_group_sensors_gui(
@@ -171,10 +180,10 @@ async def create_group_sensors_gui(
energy_sensor_ids = await resolve_entity_ids_recursively(hass, entry, SensorDeviceClass.ENERGY)
return await create_group_sensors_custom(hass, group_name, sensor_config, power_sensor_ids, energy_sensor_ids)
return create_group_sensors_custom(hass, group_name, sensor_config, power_sensor_ids, energy_sensor_ids)
async def create_group_sensors_custom(
def create_group_sensors_custom(
hass: HomeAssistant,
group_name: str,
sensor_config: dict[str, Any],
@@ -216,7 +225,7 @@ async def create_group_sensors_custom(
sensor_config[CONF_UTILITY_METER_NET_CONSUMPTION] = True
group_sensors.extend(
await create_utility_meters(
create_utility_meters(
hass,
energy_sensor,
sensor_config,
@@ -273,64 +282,83 @@ async def resolve_entity_ids_recursively(
if resolved_ids is None:
resolved_ids = set()
def add_member_entry_ids() -> None:
"""Add power/energy sensors from the group member entries."""
member_entry_ids = entry.data.get(CONF_GROUP_MEMBER_SENSORS) or []
for member_entry_id in member_entry_ids:
member_entry = hass.config_entries.async_get_entry(member_entry_id)
if member_entry is None:
continue
key = resolve_key_based_on_device_class(member_entry)
if key and key in member_entry.data:
resolved_ids.add(str(member_entry.data.get(key)))
def resolve_key_based_on_device_class(member_entry: ConfigEntry) -> str | None:
"""Resolve the correct key for power/energy sensor based on device class."""
if member_entry.data.get(CONF_SENSOR_TYPE) == SensorType.REAL_POWER:
return CONF_ENTITY_ID if device_class == SensorDeviceClass.POWER else ENTRY_DATA_ENERGY_ENTITY
return ENTRY_DATA_POWER_ENTITY if device_class == SensorDeviceClass.POWER else ENTRY_DATA_ENERGY_ENTITY
def add_specified_sensors() -> None:
"""Add additional power/energy sensors specified by the user."""
conf_key = CONF_GROUP_POWER_ENTITIES if device_class == SensorDeviceClass.POWER else CONF_GROUP_ENERGY_ENTITIES
resolved_ids.update(entry.data.get(conf_key) or [])
async def add_include_based_sensors() -> None:
"""Add entities from the defined areas, devices and floors."""
if all(k not in entry.data for k in (CONF_AREA, CONF_FLOOR, CONF_GROUP_MEMBER_DEVICES)):
return
result = await find_entities(
hass,
await build_entity_include_filter(hass, entry),
bool(entry.data.get(CONF_INCLUDE_NON_POWERCALC_SENSORS)),
)
resolved_ids.update(filter_entity_list_by_class(result.resolved, device_class))
async def add_subgroup_entities() -> None:
"""Recursively add entities from subgroups."""
subgroups = entry.data.get(CONF_SUB_GROUPS)
if not subgroups:
return
for subgroup_entry_id in subgroups:
subgroup_entry = hass.config_entries.async_get_entry(subgroup_entry_id)
if subgroup_entry is None:
_LOGGER.error("Subgroup config entry not found: %s", subgroup_entry_id)
continue
await resolve_entity_ids_recursively(hass, subgroup_entry, device_class, resolved_ids)
# Process the main logic
add_member_entry_ids()
add_specified_sensors()
await add_include_based_sensors()
await add_subgroup_entities()
_add_member_entry_ids(hass, entry, device_class, resolved_ids)
_add_specified_sensors(entry, device_class, resolved_ids)
await _add_include_based_sensors(hass, entry, device_class, resolved_ids)
await _add_subgroup_entities(hass, entry, device_class, resolved_ids)
return resolved_ids
def _add_member_entry_ids(
hass: HomeAssistant,
entry: ConfigEntry,
device_class: SensorDeviceClass,
resolved_ids: set[str],
) -> None:
"""Add power/energy sensors from the group member entries."""
member_entry_ids = entry.data.get(CONF_GROUP_MEMBER_SENSORS) or []
for member_entry_id in member_entry_ids:
member_entry = hass.config_entries.async_get_entry(member_entry_id)
if member_entry is None:
continue
key = _resolve_key_based_on_device_class(member_entry, device_class)
if key and key in member_entry.data:
resolved_ids.add(str(member_entry.data.get(key)))
def _resolve_key_based_on_device_class(member_entry: ConfigEntry, device_class: SensorDeviceClass) -> str | None:
"""Resolve the correct key for power/energy sensor based on device class."""
if member_entry.data.get(CONF_SENSOR_TYPE) == SensorType.REAL_POWER:
return CONF_ENTITY_ID if device_class == SensorDeviceClass.POWER else ENTRY_DATA_ENERGY_ENTITY
return ENTRY_DATA_POWER_ENTITY if device_class == SensorDeviceClass.POWER else ENTRY_DATA_ENERGY_ENTITY
def _add_specified_sensors(entry: ConfigEntry, device_class: SensorDeviceClass, resolved_ids: set[str]) -> None:
"""Add additional power/energy sensors specified by the user."""
conf_key = CONF_GROUP_POWER_ENTITIES if device_class == SensorDeviceClass.POWER else CONF_GROUP_ENERGY_ENTITIES
resolved_ids.update(entry.data.get(conf_key) or [])
async def _add_include_based_sensors(
hass: HomeAssistant,
entry: ConfigEntry,
device_class: SensorDeviceClass,
resolved_ids: set[str],
) -> None:
"""Add entities from the defined areas, devices and floors."""
if all(k not in entry.data for k in (CONF_AREA, CONF_FLOOR, CONF_GROUP_MEMBER_DEVICES)):
return
result = await find_entities(
hass,
await build_entity_include_filter(hass, entry),
bool(entry.data.get(CONF_INCLUDE_NON_POWERCALC_SENSORS)),
)
resolved_ids.update(filter_entity_list_by_class(result.resolved, device_class))
async def _add_subgroup_entities(
hass: HomeAssistant,
entry: ConfigEntry,
device_class: SensorDeviceClass,
resolved_ids: set[str],
) -> None:
"""Recursively add entities from subgroups."""
subgroups = entry.data.get(CONF_SUB_GROUPS)
if not subgroups:
return
for subgroup_entry_id in subgroups:
subgroup_entry = hass.config_entries.async_get_entry(subgroup_entry_id)
if subgroup_entry is None:
_LOGGER.error("Subgroup config entry not found: %s", subgroup_entry_id)
continue
await resolve_entity_ids_recursively(hass, subgroup_entry, device_class, resolved_ids)
@callback
def create_grouped_power_sensor(
hass: HomeAssistant,
@@ -448,11 +476,17 @@ class GroupedSensor(BaseEntity, SensorEntity):
self._entities = entities
self._sensor_config = sensor_config
if self._is_energy_sensor:
self._rounding_digits = int(sensor_config.get(CONF_ENERGY_SENSOR_PRECISION, DEFAULT_ENERGY_SENSOR_PRECISION))
self._update_interval: int = int(sensor_config.get(CONF_GROUP_ENERGY_UPDATE_INTERVAL, DEFAULT_GROUP_ENERGY_UPDATE_INTERVAL))
self._rounding_digits = int(
sensor_config.get(CONF_ENERGY_SENSOR_PRECISION, DEFAULT_ENERGY_SENSOR_PRECISION),
)
self._update_interval: int = int(
sensor_config.get(CONF_GROUP_ENERGY_UPDATE_INTERVAL, DEFAULT_GROUP_ENERGY_UPDATE_INTERVAL),
)
else:
self._rounding_digits = int(sensor_config.get(CONF_POWER_SENSOR_PRECISION, DEFAULT_POWER_SENSOR_PRECISION))
self._update_interval = int(sensor_config.get(CONF_GROUP_POWER_UPDATE_INTERVAL, DEFAULT_GROUP_POWER_UPDATE_INTERVAL))
self._update_interval = int(
sensor_config.get(CONF_GROUP_POWER_UPDATE_INTERVAL, DEFAULT_GROUP_POWER_UPDATE_INTERVAL),
)
self._attr_suggested_display_precision = self._rounding_digits
if unique_id:
self._attr_unique_id = unique_id
@@ -523,7 +557,11 @@ class GroupedSensor(BaseEntity, SensorEntity):
domain = self._sensor_config.get(CONF_DOMAIN)
if domain == CONF_ALL:
entity_registry = er.async_get(self.hass)
entities = {entity.entity_id for entity in entity_registry.entities.values() if entity.device_class == self.device_class}
entities = {
entity.entity_id
for entity in entity_registry.entities.values()
if entity.device_class == self.device_class
}
else:
entities = self.hass.data[DOMAIN].get(DATA_DOMAIN_ENTITIES).get(domain, [])
entities = filter_entity_list_by_class(
@@ -533,7 +571,7 @@ class GroupedSensor(BaseEntity, SensorEntity):
excluded_entities = self._sensor_config.get(CONF_EXCLUDE_ENTITIES) or []
self._entities = set({entity for entity in entities if entity not in excluded_entities})
async def on_start(self, _: Any) -> None: # noqa
async def on_start(self, _: HomeAssistant) -> None:
"""Initialize group sensor when HA is starting."""
await self.init_domain_group()
@@ -557,7 +595,9 @@ 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 [STATE_UNKNOWN, STATE_UNAVAILABLE]
]
if not available_states and not self._ignore_unavailable_state:
new_state: Decimal | str = STATE_UNAVAILABLE
else:
@@ -652,6 +692,37 @@ class GroupedSensor(BaseEntity, SensorEntity):
def get_group_entities(self) -> dict[str, set[str]]:
return {ATTR_ENTITIES: self._entities}
def debug_group(self) -> dict[str, Any]:
members: dict[str, dict[str, str | None]] = {}
for entity_id in sorted(self._entities):
members[entity_id] = self._get_member_debug_info(entity_id)
return {
ATTR_STATE: str(self.state),
ATTR_UNIT_OF_MEASUREMENT: self.native_unit_of_measurement,
ATTR_MEMBERS: members,
}
def _get_member_debug_info(self, entity_id: str) -> dict[str, str | None]:
state = self.hass.states.get(entity_id)
if state is None:
return {
ATTR_STATE: None,
ATTR_UNIT_OF_MEASUREMENT: None,
}
if state.state in [STATE_UNKNOWN, STATE_UNAVAILABLE]:
return {
ATTR_STATE: str(state.state),
ATTR_UNIT_OF_MEASUREMENT: state.attributes.get(ATTR_UNIT_OF_MEASUREMENT),
}
converted_value = round(self._get_state_value_in_native_unit(state), self._rounding_digits)
return {
ATTR_STATE: str(converted_value),
ATTR_UNIT_OF_MEASUREMENT: self.native_unit_of_measurement,
}
@abstractmethod
def calculate_initial_state(
self,
@@ -681,7 +752,9 @@ class GroupedPowerSensor(GroupedSensor, PowerSensor):
member_available_states: list[State],
member_states: list[State],
) -> Decimal | str:
self._member_states = {state.entity_id: self._get_state_value_in_native_unit(state) for state in member_available_states}
self._member_states = {
state.entity_id: self._get_state_value_in_native_unit(state) for state in member_available_states
}
return self.get_summed_state()
def calculate_new_state(self, state: State) -> Decimal | str:
@@ -776,8 +849,9 @@ class GroupedEnergySensor(GroupedSensor, RestoreSensor, EnergySensor):
member_available_states: list[State],
member_states: list[State],
) -> Decimal:
"""Calculate the new group energy sensor state
For each member sensor we calculate the delta by looking at the previous known state and compare it to the current.
"""Calculate the new group energy sensor state.
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)
_LOGGER.debug("%s: Recalculate, current value: %s", self.entity_id, group_sum)
@@ -830,10 +904,7 @@ class GroupedEnergySensor(GroupedSensor, RestoreSensor, EnergySensor):
)
start_at_zero = self._sensor_config.get(CONF_GROUP_ENERGY_START_AT_ZERO, True)
if prev_state is None and start_at_zero: # noqa: SIM108
delta = Decimal(0)
else:
delta = cur_value - prev_value
delta = Decimal(0) if prev_state is None and start_at_zero else cur_value - prev_value
if _LOGGER.isEnabledFor(logging.DEBUG): # pragma: no cover
_LOGGER.debug(
@@ -890,7 +961,9 @@ class PreviousStateStore:
_LOGGER.debug("Load previous energy sensor states from store")
stored_states = await instance.store.async_load() or {}
for group, entities in stored_states.items():
instance.states[group] = {entity_id: State.from_dict(json_state) for (entity_id, json_state) in entities.items()}
instance.states[group] = {
entity_id: State.from_dict(json_state) for (entity_id, json_state) in entities.items()
}
except HomeAssistantError as exc: # pragma: no cover
_LOGGER.error("Error loading previous energy sensor states", exc_info=exc)
@@ -943,7 +1016,7 @@ class PreviousStateStore:
def async_setup_dump(self) -> None:
"""Set up the listeners for persistence."""
async def _async_dump_states(*_: Any) -> None: # noqa: ANN401
async def _async_dump_states(*_: object) -> None:
await self.persist_states()
# Dump states periodically
@@ -951,9 +1024,10 @@ class PreviousStateStore:
self.hass,
_async_dump_states,
STATE_DUMP_INTERVAL,
cancel_on_shutdown=True,
)
async def _async_dump_states_at_stop(*_: Any) -> None: # noqa: ANN401
async def _async_dump_states_at_stop(*_: object) -> None:
cancel_interval()
await self.persist_states()
@@ -7,7 +7,7 @@ from custom_components.powercalc.const import CONF_GROUP_TYPE, GroupType
from custom_components.powercalc.sensors.group.custom import create_group_sensors_custom
async def create_domain_group_sensor(
def create_domain_group_sensor(
hass: HomeAssistant,
config: ConfigType,
) -> list[Entity]:
@@ -16,7 +16,7 @@ async def create_domain_group_sensor(
if CONF_UNIQUE_ID not in config:
config[CONF_UNIQUE_ID] = generate_unique_id(config)
config[CONF_GROUP_TYPE] = GroupType.DOMAIN
return await create_group_sensors_custom(
return create_group_sensors_custom(
hass,
name,
config,
@@ -24,12 +24,12 @@ async def create_group_sensors(
collect_analytics(hass, config_entry).inc(DATA_GROUP_TYPES, group_type)
if group_type == GroupType.DOMAIN:
return await domain_group.create_domain_group_sensor(
return domain_group.create_domain_group_sensor(
hass,
sensor_config,
)
if group_type == GroupType.STANDBY:
return await standby_group.create_general_standby_sensors(hass, sensor_config)
return standby_group.create_general_standby_sensors(hass, sensor_config)
if group_type == GroupType.CUSTOM:
if config_entry:
@@ -38,14 +38,14 @@ async def create_group_sensors(
entry=config_entry,
sensor_config=sensor_config,
)
return await custom_group.create_group_sensors_yaml(
return custom_group.create_group_sensors_yaml(
hass=hass,
sensor_config=sensor_config,
entities=entities or [],
)
if group_type == GroupType.SUBTRACT:
return await subtract_group.create_subtract_group_sensors(
return subtract_group.create_subtract_group_sensors(
hass=hass,
config=sensor_config,
)
@@ -30,7 +30,7 @@ from custom_components.powercalc.sensors.power import PowerSensor
_LOGGER = logging.getLogger(__name__)
async def create_general_standby_sensors(
def create_general_standby_sensors(
hass: HomeAssistant,
config: ConfigType,
) -> list[Entity]:
@@ -44,8 +44,8 @@ async def create_general_standby_sensors(
power_sensor.entity_id = "sensor.all_standby_power"
sensor_config = config.copy()
sensor_config[CONF_NAME] = "All standby"
source_entity = await create_source_entity(DUMMY_ENTITY_ID, hass)
energy_sensor = await create_energy_sensor(
source_entity = create_source_entity(DUMMY_ENTITY_ID, hass)
energy_sensor = create_energy_sensor(
hass,
sensor_config,
power_sensor,
@@ -80,8 +80,8 @@ class StandbyPowerSensor(SensorEntity, PowerSensor):
"""Calculate sum of all power sensors in standby, and update the state of the sensor."""
if self.standby_sensors:
self._attr_native_value = Decimal(
round( # type: ignore
sum(self.standby_sensors.values()),
round(
sum(self.standby_sensors.values(), Decimal(0)),
self._rounding_digits,
),
)
@@ -24,7 +24,7 @@ from custom_components.powercalc.sensors.utility_meter import create_utility_met
_LOGGER = logging.getLogger(__name__)
async def create_subtract_group_sensors(
def create_subtract_group_sensors(
hass: HomeAssistant,
config: ConfigType,
) -> list[Entity]:
@@ -58,7 +58,7 @@ async def create_subtract_group_sensors(
)
sensors.append(power_sensor)
if config.get(CONF_CREATE_ENERGY_SENSORS):
energy_sensor = await create_energy_sensor(
energy_sensor = create_energy_sensor(
hass,
config,
power_sensor,
@@ -67,7 +67,7 @@ async def create_subtract_group_sensors(
config[CONF_UTILITY_METER_NET_CONSUMPTION] = True
sensors.extend(
await create_utility_meters(
create_utility_meters(
hass,
energy_sensor,
config,
@@ -2,7 +2,6 @@ from __future__ import annotations
from enum import StrEnum
import logging
from typing import Any
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.config_entries import ConfigEntry
@@ -53,7 +52,11 @@ async def find_auto_tracked_power_entities(hass: HomeAssistant, exclude_entities
if exclude_entities:
entity_filter = LambdaFilter(lambda entity: entity.entity_id not in exclude_entities)
result = await find_entities(hass, entity_filter)
return {entity.entity_id for entity in result.resolved if isinstance(entity, PowerSensor) and not isinstance(entity, GroupedSensor)}
return {
entity.entity_id
for entity in result.resolved
if isinstance(entity, PowerSensor) and not isinstance(entity, GroupedSensor)
}
class TrackedPowerSensorFactory:
@@ -67,7 +70,9 @@ class TrackedPowerSensorFactory:
"""Create tracked/untracked group sensors."""
unique_id = str(self.config.get(CONF_UNIQUE_ID))
main_power_sensor = str(self.config.get(CONF_MAIN_POWER_SENSOR)) if self.config.get(CONF_MAIN_POWER_SENSOR) else None
main_power_sensor = (
str(self.config.get(CONF_MAIN_POWER_SENSOR)) if self.config.get(CONF_MAIN_POWER_SENSOR) else None
)
self.config[CONF_DISABLE_EXTENDED_ATTRIBUTES] = True # prevent adding all entities in the state attributes
self.tracked_entities = await self.get_tracked_power_entities()
@@ -83,7 +88,7 @@ class TrackedPowerSensorFactory:
energy_sensor = await self.create_energy_sensor(SensorType.TRACKED, tracked_sensor)
entities.append(energy_sensor)
entities.extend(
await create_utility_meters(
create_utility_meters(
self.hass,
energy_sensor,
{CONF_UTILITY_METER_NET_CONSUMPTION: True, **self.config},
@@ -102,7 +107,7 @@ class TrackedPowerSensorFactory:
energy_sensor = await self.create_energy_sensor(SensorType.UNTRACKED, untracked_sensor)
entities.append(energy_sensor)
entities.extend(
await create_utility_meters(
create_utility_meters(
self.hass,
energy_sensor,
{CONF_UTILITY_METER_NET_CONSUMPTION: True, **self.config},
@@ -116,12 +121,15 @@ class TrackedPowerSensorFactory:
Get all power entities which are part of the tracked sensor group
"""
if not bool(self.config.get(CONF_GROUP_TRACKED_AUTO, False)):
return set(self.config.get(CONF_GROUP_TRACKED_POWER_ENTITIES)) # type: ignore
tracked_entities: list[str] | None = self.config.get(CONF_GROUP_TRACKED_POWER_ENTITIES)
if not isinstance(tracked_entities, list):
return set()
return set(tracked_entities)
# For auto mode, we also want to listen for any changes in the entity registry
# Dynamically add/remove power sensors from the tracked group
@callback
def _start_entity_registry_listener(_: Any) -> None: # noqa ANN401
def _start_entity_registry_listener(_: Event) -> None:
self.hass.bus.async_listen(EVENT_ENTITY_REGISTRY_UPDATED, self._handle_entity_registry_updated)
self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, _start_entity_registry_listener)
@@ -137,8 +145,9 @@ class TrackedPowerSensorFactory:
entity_id = event.data["entity_id"]
action = event.data["action"]
if action == "update" and "old_entity_id" in event.data:
if event.data["old_entity_id"] in self.tracked_entities: # type: ignore
old_entity_id = event.data.get("old_entity_id")
if action == "update" and old_entity_id is not None:
if old_entity_id in self.tracked_entities:
return await self.reload()
return None # pragma: no cover