217 files
This commit is contained in:
@@ -14,6 +14,7 @@ from homeassistant.helpers.condition import ConditionCheckerType
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.event import TrackTemplate
|
||||
from homeassistant.helpers.template import Template
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
import voluptuous as vol
|
||||
|
||||
from custom_components.powercalc.const import (
|
||||
@@ -189,23 +190,30 @@ class CompositeStrategy(PowerCalculationStrategyInterface):
|
||||
|
||||
total = Decimal(0)
|
||||
for sub_strategy in self.strategies:
|
||||
strategy = sub_strategy.strategy
|
||||
|
||||
if sub_strategy.condition and not self._condition_matches(sub_strategy.condition, entity_state):
|
||||
value = await self._calculate_sub_strategy(sub_strategy, entity_state)
|
||||
if value is None:
|
||||
continue
|
||||
|
||||
if isinstance(strategy, PlaybookStrategy):
|
||||
await self.activate_playbook(strategy)
|
||||
|
||||
if entity_state.state != STATE_OFF or strategy.can_calculate_standby():
|
||||
value = await strategy.calculate(entity_state)
|
||||
if value is not None:
|
||||
if self.mode == CompositeMode.STOP_AT_FIRST:
|
||||
return value
|
||||
total += value
|
||||
if self.mode == CompositeMode.STOP_AT_FIRST:
|
||||
return value
|
||||
total += value
|
||||
|
||||
return total if self.mode == CompositeMode.SUM_ALL else None
|
||||
|
||||
async def _calculate_sub_strategy(self, sub_strategy: SubStrategy, entity_state: State) -> Decimal | None:
|
||||
"""Calculate the power for a single sub strategy. Returns None when the sub strategy must be skipped."""
|
||||
strategy = sub_strategy.strategy
|
||||
|
||||
if sub_strategy.condition and not self._condition_matches(sub_strategy.condition, entity_state):
|
||||
return None
|
||||
|
||||
if isinstance(strategy, PlaybookStrategy):
|
||||
await self.activate_playbook(strategy)
|
||||
|
||||
if entity_state.state == STATE_OFF and not strategy.can_calculate_standby():
|
||||
return None
|
||||
|
||||
return await strategy.calculate(entity_state)
|
||||
|
||||
def _condition_matches(self, condition: ConditionCheckerType, entity_state: State) -> bool:
|
||||
try:
|
||||
return condition(self.hass, {"state": entity_state})
|
||||
@@ -265,7 +273,7 @@ class CompositeStrategy(PowerCalculationStrategyInterface):
|
||||
|
||||
def resolve_track_templates_from_condition(
|
||||
self,
|
||||
condition_config: dict,
|
||||
condition_config: ConfigType,
|
||||
templates: list[str | TrackTemplate],
|
||||
) -> None:
|
||||
"""Resolve track templates from condition config."""
|
||||
@@ -282,6 +290,6 @@ class CompositeStrategy(PowerCalculationStrategyInterface):
|
||||
|
||||
@dataclass
|
||||
class SubStrategy:
|
||||
condition_config: dict | None
|
||||
condition_config: ConfigType | None
|
||||
condition: ConditionCheckerType | None
|
||||
strategy: PowerCalculationStrategyInterface
|
||||
|
||||
@@ -80,7 +80,7 @@ class PowerCalculatorStrategyFactory:
|
||||
|
||||
async def create(
|
||||
self,
|
||||
config: dict,
|
||||
config: ConfigType,
|
||||
strategy: str,
|
||||
power_profile: PowerProfile | None,
|
||||
source_entity: SourceEntity,
|
||||
@@ -116,7 +116,7 @@ class PowerCalculatorStrategyFactory:
|
||||
def _create_linear(
|
||||
self,
|
||||
source_entity: SourceEntity,
|
||||
config: dict,
|
||||
config: ConfigType,
|
||||
power_profile: PowerProfile | None,
|
||||
) -> LinearStrategy:
|
||||
"""Create the linear strategy."""
|
||||
@@ -132,7 +132,7 @@ class PowerCalculatorStrategyFactory:
|
||||
def _create_fixed(
|
||||
self,
|
||||
source_entity: SourceEntity,
|
||||
config: dict,
|
||||
config: ConfigType,
|
||||
power_profile: PowerProfile | None,
|
||||
) -> FixedStrategy:
|
||||
"""Create the fixed strategy."""
|
||||
@@ -165,7 +165,7 @@ class PowerCalculatorStrategyFactory:
|
||||
|
||||
return LutStrategy(source_entity, self._lut_registry, power_profile)
|
||||
|
||||
def _create_wled(self, source_entity: SourceEntity, config: dict) -> WledStrategy:
|
||||
def _create_wled(self, source_entity: SourceEntity, config: ConfigType) -> WledStrategy:
|
||||
"""Create the WLED strategy."""
|
||||
wled_config = self._get_strategy_config(CalculationStrategy.WLED, config, None)
|
||||
return WledStrategy(
|
||||
@@ -190,7 +190,7 @@ class PowerCalculatorStrategyFactory:
|
||||
source_entity: SourceEntity,
|
||||
power_profile: PowerProfile | None,
|
||||
) -> CompositeStrategy:
|
||||
composite_config: list | dict | None = config.get(CONF_COMPOSITE)
|
||||
composite_config: list[ConfigType] | ConfigType | None = config.get(CONF_COMPOSITE)
|
||||
if composite_config is None:
|
||||
if power_profile and power_profile.composite_config:
|
||||
composite_config = self._validate_composite_config(power_profile.composite_config)
|
||||
@@ -231,7 +231,7 @@ class PowerCalculatorStrategyFactory:
|
||||
return CompositeStrategy(self._hass, strategies, mode)
|
||||
|
||||
@staticmethod
|
||||
def _validate_composite_config(composite_config: list | dict) -> list | dict:
|
||||
def _validate_composite_config(composite_config: list[ConfigType] | ConfigType) -> list[ConfigType] | ConfigType:
|
||||
"""Validate the composite configuration of a library profile.
|
||||
|
||||
Configuration from YAML and the config flow is already validated by the sensor schema.
|
||||
@@ -239,7 +239,7 @@ class PowerCalculatorStrategyFactory:
|
||||
for example entity_id to a list and value_template to a Template instance.
|
||||
"""
|
||||
try:
|
||||
return cast(list | dict, COMPOSITE_SCHEMA(composite_config))
|
||||
return cast(list[ConfigType] | ConfigType, COMPOSITE_SCHEMA(composite_config))
|
||||
except vol.Invalid as err:
|
||||
raise StrategyConfigurationError(f"Invalid composite configuration in profile: {err}") from err
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ class LinearStrategy(PowerCalculationStrategyInterface):
|
||||
|
||||
return sorted(calibration_list, key=lambda tup: tup[0])
|
||||
|
||||
def get_entity_value_range(self) -> tuple:
|
||||
def get_entity_value_range(self) -> tuple[int, int]:
|
||||
"""Get the min/max range for a given entity domain."""
|
||||
if self.get_initialized_value_entity().domain == light.DOMAIN:
|
||||
return 0, 255
|
||||
|
||||
@@ -71,12 +71,16 @@ class _EffectEntry:
|
||||
table: EffectTableType
|
||||
|
||||
|
||||
# manufacturer, model, lookup mode, sub profile
|
||||
_CacheKey = tuple[str, str, LookupMode, str | None]
|
||||
|
||||
|
||||
class LutRegistry:
|
||||
def __init__(self, hass: HomeAssistant) -> None:
|
||||
self._hass = hass
|
||||
self._lut_entries: dict[tuple, _LutEntry] = {}
|
||||
self._effect_entries: dict[tuple, _EffectEntry] = {}
|
||||
self._supported_modes: dict[tuple, set[LookupMode]] = {}
|
||||
self._lut_entries: dict[_CacheKey, _LutEntry] = {}
|
||||
self._effect_entries: dict[_CacheKey, _EffectEntry] = {}
|
||||
self._supported_modes: dict[tuple[str, str, str], set[LookupMode]] = {}
|
||||
|
||||
async def get_lookup_entry(
|
||||
self,
|
||||
@@ -121,7 +125,7 @@ class LutRegistry:
|
||||
return supported_modes
|
||||
|
||||
@staticmethod
|
||||
def _cache_key(power_profile: PowerProfile, lookup_mode: LookupMode) -> tuple:
|
||||
def _cache_key(power_profile: PowerProfile, lookup_mode: LookupMode) -> _CacheKey:
|
||||
return power_profile.manufacturer, power_profile.model, lookup_mode, power_profile.sub_profile
|
||||
|
||||
@classmethod
|
||||
|
||||
Reference in New Issue
Block a user