Files
HomeAssistantVS/custom_components/powercalc/flow_helper/strategy_form.py
T
2026-07-14 23:57:03 -04:00

89 lines
3.3 KiB
Python

from __future__ import annotations
from typing import Any
from custom_components.powercalc.const import (
CONF_FIXED_VALUE,
CONF_PLAYBOOK_ID,
CONF_POWER,
CONF_POWER_TEMPLATE,
CONF_STATE,
CONF_STATE_TRIGGER,
CONF_STATES_POWER,
CalculationStrategy,
)
from custom_components.powercalc.flow_helper.common import unwrap_choose_selector, wrap_choose_selector
FIXED_CHOICES: dict[str, list[str] | str] = {
CONF_STATES_POWER: CONF_STATES_POWER,
CONF_POWER_TEMPLATE: CONF_POWER_TEMPLATE,
CONF_POWER: CONF_POWER,
}
def order_choices_for_default[T](
choices: dict[str, T],
default_choice: str | None,
) -> dict[str, T]:
"""Put the default choice first because HA initializes choose selectors from the first choice."""
if default_choice not in choices:
return choices
return {
default_choice: choices[default_choice],
**{choice: config for choice, config in choices.items() if choice != default_choice},
}
def has_saved_choice_value(value: object) -> bool:
"""Return whether a saved strategy value should drive the selected form choice."""
if value is None:
return False
if isinstance(value, (str, list, dict)):
return bool(value)
return True
def find_present_choice(form_data: dict[str, Any], choices: dict[str, list[str] | str]) -> str | None:
"""Find the first choice that has matching config data."""
for choice_id, mapping in choices.items():
keys = [mapping] if isinstance(mapping, str) else mapping
if any(has_saved_choice_value(form_data.get(key)) for key in keys):
return choice_id
return None
def fixed_choice_key_from_validated_value(value: object) -> str:
"""Infer the fixed strategy config key from a validated ChooseSelector value."""
if isinstance(value, list):
return CONF_STATES_POWER
if isinstance(value, str):
return CONF_POWER_TEMPLATE
return CONF_POWER
def unwrap_strategy_user_input(strategy: CalculationStrategy, user_input: dict[str, Any]) -> dict[str, Any]:
"""Unwrap form-only selector wrappers and normalize strategy user input."""
if strategy == CalculationStrategy.FIXED:
unwrap_choose_selector(user_input, CONF_FIXED_VALUE, fixed_choice_key_from_validated_value)
if CONF_STATE_TRIGGER in user_input and isinstance(user_input[CONF_STATE_TRIGGER], list):
user_input[CONF_STATE_TRIGGER] = {
item[CONF_STATE]: item[CONF_PLAYBOOK_ID] for item in user_input[CONF_STATE_TRIGGER]
}
return user_input
def wrap_strategy_form_data(strategy: CalculationStrategy, form_data: dict[str, Any]) -> dict[str, Any]:
"""Wrap stored strategy config back into form-only selector structures."""
if strategy == CalculationStrategy.FIXED:
choices = order_choices_for_default(FIXED_CHOICES, find_present_choice(form_data, FIXED_CHOICES))
form_data = wrap_choose_selector(form_data, CONF_FIXED_VALUE, choices, raw_value=True)
if CONF_STATE_TRIGGER in form_data and isinstance(form_data[CONF_STATE_TRIGGER], dict):
form_data = {
**form_data,
CONF_STATE_TRIGGER: [
{CONF_STATE: state, CONF_PLAYBOOK_ID: playbook_id}
for state, playbook_id in form_data[CONF_STATE_TRIGGER].items()
],
}
return form_data