Initial Commit
This commit is contained in:
@@ -0,0 +1,554 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, cast
|
||||
|
||||
from homeassistant.config_entries import ConfigFlowResult
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers import selector, translation
|
||||
import voluptuous as vol
|
||||
|
||||
from custom_components.powercalc import (
|
||||
DOMAIN,
|
||||
DeviceType,
|
||||
)
|
||||
from custom_components.powercalc.const import (
|
||||
CONF_AVAILABILITY_ENTITY,
|
||||
CONF_FIXED,
|
||||
CONF_MANUFACTURER,
|
||||
CONF_MODE,
|
||||
CONF_MODEL,
|
||||
CONF_POWER,
|
||||
CONF_SELF_USAGE_INCLUDED,
|
||||
CONF_SUB_PROFILE,
|
||||
CONF_VARIABLES,
|
||||
DUMMY_ENTITY_ID,
|
||||
LIBRARY_URL,
|
||||
CalculationStrategy,
|
||||
)
|
||||
from custom_components.powercalc.discovery import (
|
||||
get_power_profile_by_source_device,
|
||||
get_power_profile_by_source_entity,
|
||||
)
|
||||
from custom_components.powercalc.flow_helper.common import FlowType, PowercalcFormStep, Step
|
||||
from custom_components.powercalc.flow_helper.dynamic_field_builder import build_dynamic_field_schema
|
||||
from custom_components.powercalc.flow_helper.schema import SCHEMA_ENERGY_SENSOR_TOGGLE, SCHEMA_UTILITY_METER_TOGGLE, build_sub_profile_schema
|
||||
from custom_components.powercalc.helpers import collect_placeholders, iter_related_entity_placeholders, resolve_related_entity_placeholder
|
||||
from custom_components.powercalc.power_profile.library import ModelInfo, ProfileLibrary
|
||||
from custom_components.powercalc.power_profile.power_profile import DEVICE_TYPE_DOMAIN, DOMAIN_DEVICE_TYPE_MAPPING, DiscoveryBy, PowerProfile
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from custom_components.powercalc.config_flow import PowercalcCommonFlow, PowercalcConfigFlow, PowercalcOptionsFlow
|
||||
|
||||
CONF_CONFIRM_AUTODISCOVERED_MODEL = "confirm_autodisovered_model"
|
||||
|
||||
SCHEMA_POWER_AUTODISCOVERED = vol.Schema(
|
||||
{vol.Optional(CONF_CONFIRM_AUTODISCOVERED_MODEL, default=True): bool},
|
||||
)
|
||||
|
||||
SCHEMA_POWER_OPTIONS_LIBRARY = vol.Schema(
|
||||
{
|
||||
**SCHEMA_ENERGY_SENSOR_TOGGLE.schema,
|
||||
**SCHEMA_UTILITY_METER_TOGGLE.schema,
|
||||
},
|
||||
)
|
||||
|
||||
SCHEMA_POWER_SMART_SWITCH = vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_POWER): vol.Coerce(float),
|
||||
vol.Optional(CONF_SELF_USAGE_INCLUDED): selector.BooleanSelector(),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class LibraryFlow:
|
||||
def __init__(self, flow: PowercalcCommonFlow) -> None:
|
||||
self.flow = flow
|
||||
|
||||
async def async_step_manufacturer(
|
||||
self,
|
||||
user_input: dict[str, Any] | None = None,
|
||||
) -> FlowResult:
|
||||
"""Ask the user to select the manufacturer."""
|
||||
|
||||
async def _create_schema() -> vol.Schema:
|
||||
"""Create manufacturer schema."""
|
||||
library = await ProfileLibrary.factory(self.flow.hass)
|
||||
manufacturers = [
|
||||
selector.SelectOptionDict(value=manufacturer[0], label=manufacturer[1])
|
||||
for manufacturer in await library.get_manufacturer_listing(
|
||||
self._get_library_device_types(),
|
||||
self._get_library_discovery_by(),
|
||||
)
|
||||
]
|
||||
return vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_MANUFACTURER, default=self.flow.sensor_config.get(CONF_MANUFACTURER)): selector.SelectSelector(
|
||||
selector.SelectSelectorConfig(
|
||||
options=manufacturers,
|
||||
mode=selector.SelectSelectorMode.DROPDOWN,
|
||||
),
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
return await self.flow.handle_form_step(
|
||||
PowercalcFormStep(
|
||||
step=Step.MANUFACTURER,
|
||||
schema=_create_schema,
|
||||
next_step=Step.MODEL,
|
||||
),
|
||||
user_input,
|
||||
)
|
||||
|
||||
async def async_step_model(
|
||||
self,
|
||||
user_input: dict[str, Any] | None = None,
|
||||
) -> FlowResult:
|
||||
"""Ask the user to select the model."""
|
||||
|
||||
def _build_model_label(model_id: str, model_name: str) -> str:
|
||||
if not model_name or model_name == model_id:
|
||||
return model_id
|
||||
return f"{model_id} ({model_name})"
|
||||
|
||||
async def _validate(user_input: dict[str, Any]) -> dict[str, str]:
|
||||
library = await ProfileLibrary.factory(self.flow.hass)
|
||||
profile = await library.get_profile(
|
||||
ModelInfo(
|
||||
str(self.flow.sensor_config.get(CONF_MANUFACTURER)),
|
||||
str(user_input.get(CONF_MODEL)),
|
||||
),
|
||||
self.flow.source_entity,
|
||||
process_variables=False,
|
||||
)
|
||||
self.flow.selected_profile = profile
|
||||
if self.flow.selected_profile and not await self.flow.selected_profile.needs_user_configuration:
|
||||
await self.flow.validate_strategy_config()
|
||||
return user_input
|
||||
|
||||
async def _create_schema() -> vol.Schema:
|
||||
"""Create model schema."""
|
||||
manufacturer = str(self.flow.sensor_config.get(CONF_MANUFACTURER))
|
||||
library = await ProfileLibrary.factory(self.flow.hass)
|
||||
models = [
|
||||
selector.SelectOptionDict(value=model_id, label=_build_model_label(model_id, model_name))
|
||||
for model_id, model_name in await library.get_model_listing(
|
||||
manufacturer,
|
||||
self._get_library_device_types(),
|
||||
self._get_library_discovery_by(),
|
||||
)
|
||||
]
|
||||
model = self.flow.selected_profile.model if self.flow.selected_profile else self.flow.sensor_config.get(CONF_MODEL)
|
||||
return vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_MODEL, description={"suggested_value": model}, default=model): selector.SelectSelector(
|
||||
selector.SelectSelectorConfig(
|
||||
options=models,
|
||||
mode=selector.SelectSelectorMode.DROPDOWN,
|
||||
),
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
return await self.flow.handle_form_step(
|
||||
PowercalcFormStep(
|
||||
step=Step.MODEL,
|
||||
schema=_create_schema,
|
||||
next_step=Step.POST_LIBRARY,
|
||||
validate_user_input=_validate,
|
||||
form_kwarg={"description_placeholders": {"supported_models_link": LIBRARY_URL}},
|
||||
),
|
||||
user_input,
|
||||
)
|
||||
|
||||
async def async_step_post_library(
|
||||
self,
|
||||
user_input: dict[str, Any] | None = None,
|
||||
) -> FlowResult:
|
||||
"""
|
||||
Handles the logic after the user either selected manufacturer/model himself or confirmed autodiscovered.
|
||||
Forwards to the next step in the flow.
|
||||
"""
|
||||
if not self.flow.selected_profile:
|
||||
return self.flow.async_abort(reason="model_not_supported") # type:ignore # pragma: no cover
|
||||
|
||||
if Step.LIBRARY_CUSTOM_FIELDS not in self.flow.handled_steps and self.flow.selected_profile.has_custom_fields:
|
||||
return await self.async_step_library_custom_fields()
|
||||
|
||||
if Step.AVAILABILITY_ENTITY not in self.flow.handled_steps and self.flow.selected_profile.discovery_by == DiscoveryBy.DEVICE:
|
||||
result = await self.async_step_availability_entity()
|
||||
if result:
|
||||
return result
|
||||
|
||||
if Step.SUB_PROFILE not in self.flow.handled_steps and await self.flow.selected_profile.requires_manual_sub_profile_selection:
|
||||
return await self.async_step_sub_profile()
|
||||
|
||||
if (
|
||||
Step.SMART_SWITCH not in self.flow.handled_steps
|
||||
and self.flow.selected_profile.device_type == DeviceType.SMART_SWITCH
|
||||
and self.flow.selected_profile.calculation_strategy == CalculationStrategy.FIXED
|
||||
):
|
||||
return await self.async_step_smart_switch()
|
||||
|
||||
if Step.FIXED not in self.flow.handled_steps and self.flow.selected_profile.needs_fixed_config: # pragma: no cover
|
||||
return await self.flow.flow_handlers[FlowType.VIRTUAL_POWER].async_step_fixed() # type:ignore
|
||||
|
||||
if Step.LINEAR not in self.flow.handled_steps and self.flow.selected_profile.needs_linear_config:
|
||||
return await self.flow.flow_handlers[FlowType.VIRTUAL_POWER].async_step_linear() # type:ignore
|
||||
|
||||
if Step.MULTI_SWITCH not in self.flow.handled_steps and self.flow.selected_profile.calculation_strategy == CalculationStrategy.MULTI_SWITCH:
|
||||
return await self.flow.flow_handlers[FlowType.VIRTUAL_POWER].async_step_multi_switch() # type:ignore
|
||||
|
||||
return await self.flow.flow_handlers[FlowType.GROUP].async_step_assign_groups() # type:ignore
|
||||
|
||||
async def async_step_library_custom_fields(self, user_input: dict[str, Any] | None = None) -> FlowResult:
|
||||
"""Handle the flow for custom fields."""
|
||||
|
||||
async def _process_user_input(user_input: dict[str, Any]) -> dict[str, Any]:
|
||||
return {CONF_VARIABLES: user_input}
|
||||
|
||||
form_kwarg: dict[str, Any] | None = None
|
||||
if self.flow.selected_profile and self.flow.selected_profile.documentation_url:
|
||||
form_kwarg = {
|
||||
"description_placeholders": {
|
||||
"documentation_url": self.flow.selected_profile.documentation_url,
|
||||
},
|
||||
}
|
||||
|
||||
return await self.flow.handle_form_step(
|
||||
PowercalcFormStep(
|
||||
step=Step.LIBRARY_CUSTOM_FIELDS,
|
||||
schema=build_dynamic_field_schema(
|
||||
self.flow.hass,
|
||||
self.flow.selected_profile, # type: ignore
|
||||
self.flow.source_entity,
|
||||
),
|
||||
next_step=Step.POST_LIBRARY,
|
||||
validate_user_input=_process_user_input,
|
||||
form_kwarg=form_kwarg,
|
||||
),
|
||||
user_input,
|
||||
)
|
||||
|
||||
async def async_step_sub_profile(
|
||||
self,
|
||||
user_input: dict[str, Any] | None = None,
|
||||
) -> FlowResult:
|
||||
"""Handle the flow for sub profile selection."""
|
||||
assert self.flow.selected_profile is not None
|
||||
|
||||
async def _validate(user_input: dict[str, Any]) -> dict[str, str]:
|
||||
return {CONF_MODEL: f"{self.flow.sensor_config.get(CONF_MODEL)}/{user_input.get(CONF_SUB_PROFILE)}"}
|
||||
|
||||
library = await ProfileLibrary.factory(self.flow.hass)
|
||||
profile = await library.get_profile(
|
||||
ModelInfo(
|
||||
str(self.flow.sensor_config.get(CONF_MANUFACTURER)),
|
||||
str(self.flow.sensor_config.get(CONF_MODEL)),
|
||||
),
|
||||
self.flow.source_entity,
|
||||
process_variables=False,
|
||||
)
|
||||
remarks = profile.config_flow_sub_profile_remarks
|
||||
if remarks:
|
||||
remarks = "\n\n" + remarks
|
||||
|
||||
step = Step.SUB_PROFILE_PER_DEVICE if self.flow.selected_profile.discovery_by == DiscoveryBy.DEVICE else Step.SUB_PROFILE
|
||||
|
||||
return await self.flow.handle_form_step(
|
||||
PowercalcFormStep(
|
||||
step=step,
|
||||
schema=await build_sub_profile_schema(profile, self.flow.selected_sub_profile),
|
||||
next_step=Step.POWER_ADVANCED,
|
||||
validate_user_input=_validate,
|
||||
form_kwarg={
|
||||
"description_placeholders": {
|
||||
"entity_id": self.flow.source_entity_id,
|
||||
"remarks": remarks,
|
||||
},
|
||||
},
|
||||
),
|
||||
user_input,
|
||||
)
|
||||
|
||||
async def async_step_sub_profile_per_device(
|
||||
self,
|
||||
user_input: dict[str, Any] | None = None,
|
||||
) -> FlowResult:
|
||||
return await self.async_step_sub_profile(user_input)
|
||||
|
||||
async def async_step_smart_switch(self, user_input: dict[str, Any] | None = None) -> FlowResult:
|
||||
"""Asks the user for the power of connect appliance for the smart switch."""
|
||||
|
||||
if self.flow.selected_profile and not self.flow.selected_profile.needs_fixed_config:
|
||||
return self.flow.persist_config_entry()
|
||||
|
||||
async def _validate(user_input: dict[str, Any]) -> dict[str, Any]:
|
||||
return {
|
||||
CONF_SELF_USAGE_INCLUDED: user_input.get(CONF_SELF_USAGE_INCLUDED),
|
||||
CONF_MODE: CalculationStrategy.FIXED,
|
||||
CONF_FIXED: {CONF_POWER: user_input.get(CONF_POWER, 0)},
|
||||
}
|
||||
|
||||
self_usage_on = self.flow.selected_profile.standby_power_on if self.flow.selected_profile else 0
|
||||
return await self.flow.handle_form_step(
|
||||
PowercalcFormStep(
|
||||
step=Step.SMART_SWITCH,
|
||||
schema=SCHEMA_POWER_SMART_SWITCH,
|
||||
validate_user_input=_validate,
|
||||
next_step=Step.POWER_ADVANCED,
|
||||
form_kwarg={"description_placeholders": {"self_usage_power": str(self_usage_on)}},
|
||||
),
|
||||
user_input,
|
||||
)
|
||||
|
||||
async def async_step_availability_entity(self, user_input: dict[str, Any] | None = None) -> FlowResult | None:
|
||||
"""Handle the flow for availability entity."""
|
||||
# Auto-resolve availability entity from profile placeholders
|
||||
auto_entity = self._resolve_availability_entity()
|
||||
if auto_entity:
|
||||
self.flow.sensor_config[CONF_AVAILABILITY_ENTITY] = auto_entity
|
||||
self.flow.handled_steps.append(Step.AVAILABILITY_ENTITY)
|
||||
return None
|
||||
|
||||
domains = DEVICE_TYPE_DOMAIN[self.flow.selected_profile.device_type] # type: ignore
|
||||
entity_selector = self.flow.create_device_entity_selector(
|
||||
list(domains) if isinstance(domains, set) else [domains],
|
||||
)
|
||||
try:
|
||||
first_entity = entity_selector.config["include_entities"][0]
|
||||
except IndexError:
|
||||
# Skip step if no entities are available
|
||||
self.flow.handled_steps.append(Step.AVAILABILITY_ENTITY)
|
||||
return None
|
||||
return await self.flow.handle_form_step(
|
||||
PowercalcFormStep(
|
||||
step=Step.AVAILABILITY_ENTITY,
|
||||
schema=vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_AVAILABILITY_ENTITY, default=first_entity): entity_selector,
|
||||
},
|
||||
),
|
||||
next_step=Step.POST_LIBRARY,
|
||||
),
|
||||
user_input,
|
||||
)
|
||||
|
||||
def _resolve_availability_entity(self) -> str | None:
|
||||
"""Try to auto-resolve an availability entity from profile placeholders."""
|
||||
profile = self.flow.selected_profile
|
||||
device_entry = self.flow.source_entity.device_entry if self.flow.source_entity else None
|
||||
if not profile or not device_entry:
|
||||
return None
|
||||
|
||||
for placeholder in iter_related_entity_placeholders(collect_placeholders(profile.json_data)):
|
||||
entity = resolve_related_entity_placeholder(
|
||||
self.flow.hass,
|
||||
placeholder,
|
||||
source_entity=self.flow.source_entity,
|
||||
)
|
||||
if entity:
|
||||
return entity
|
||||
return None
|
||||
|
||||
def _get_library_device_types(self) -> set[DeviceType] | None:
|
||||
"""Determine which device types should be shown in the library selectors."""
|
||||
if self._get_library_discovery_by() == DiscoveryBy.DEVICE:
|
||||
return None
|
||||
|
||||
if self.flow.source_entity:
|
||||
return DOMAIN_DEVICE_TYPE_MAPPING.get(self.flow.source_entity.domain, set())
|
||||
|
||||
return None # pragma: no cover
|
||||
|
||||
def _get_library_discovery_by(self) -> DiscoveryBy | None:
|
||||
"""Determine whether listing should be filtered by discovery mode."""
|
||||
if self.flow.source_entity and self.flow.source_entity.entity_id == DUMMY_ENTITY_ID:
|
||||
return DiscoveryBy.DEVICE
|
||||
return None
|
||||
|
||||
|
||||
class LibraryConfigFlow(LibraryFlow):
|
||||
def __init__(self, flow: PowercalcConfigFlow) -> None:
|
||||
super().__init__(flow)
|
||||
self.flow: PowercalcConfigFlow = flow
|
||||
|
||||
async def async_step_library_multi_profile(
|
||||
self,
|
||||
user_input: dict[str, Any] | None = None,
|
||||
) -> FlowResult | ConfigFlowResult:
|
||||
"""This step gets executed when multiple profiles are found for the source entity."""
|
||||
if user_input is not None:
|
||||
selected_model: str = user_input.get(CONF_MODEL) # type: ignore
|
||||
selected_profile = self.flow.discovered_profiles.get(selected_model)
|
||||
if selected_profile is None: # pragma: no cover
|
||||
return self.flow.async_abort(reason="invalid_profile")
|
||||
self.flow.selected_profile = selected_profile
|
||||
self.flow.sensor_config.update(
|
||||
{
|
||||
CONF_MANUFACTURER: selected_profile.manufacturer,
|
||||
CONF_MODEL: selected_profile.model,
|
||||
},
|
||||
)
|
||||
return await self.async_step_post_library(user_input)
|
||||
|
||||
schema = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_MODEL): selector.SelectSelector(
|
||||
selector.SelectSelectorConfig(
|
||||
options=[
|
||||
selector.SelectOptionDict(
|
||||
value=profile.unique_id,
|
||||
label=profile.model,
|
||||
)
|
||||
for profile in self.flow.discovered_profiles.values()
|
||||
],
|
||||
mode=selector.SelectSelectorMode.DROPDOWN,
|
||||
),
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
manufacturer = str(self.flow.sensor_config.get(CONF_MANUFACTURER))
|
||||
model = str(self.flow.sensor_config.get(CONF_MODEL))
|
||||
return self.flow.async_show_form(
|
||||
step_id=Step.LIBRARY_MULTI_PROFILE,
|
||||
data_schema=schema,
|
||||
description_placeholders={
|
||||
"library_link": f"{LIBRARY_URL}/?manufacturer={manufacturer}",
|
||||
"manufacturer": manufacturer,
|
||||
"model": model,
|
||||
},
|
||||
last_step=False,
|
||||
)
|
||||
|
||||
async def async_step_library(
|
||||
self,
|
||||
user_input: dict[str, Any] | None = None,
|
||||
) -> FlowResult:
|
||||
"""Try to autodiscover manufacturer/model first.
|
||||
Ask the user to confirm this or forward to manual library selection.
|
||||
"""
|
||||
if user_input is not None:
|
||||
return await self._handle_library_confirmation(user_input)
|
||||
|
||||
await self._async_autodiscover_profile()
|
||||
if not self.flow.selected_profile:
|
||||
return await self.async_step_manufacturer()
|
||||
|
||||
return self._show_autodiscovered_profile_form()
|
||||
|
||||
async def _handle_library_confirmation(self, user_input: dict[str, Any]) -> FlowResult:
|
||||
"""Handle the user's response to an autodiscovered library profile."""
|
||||
if not user_input.get(CONF_CONFIRM_AUTODISCOVERED_MODEL) or not self.flow.selected_profile:
|
||||
return await self.async_step_manufacturer()
|
||||
|
||||
self.flow.sensor_config.update(
|
||||
{
|
||||
CONF_MANUFACTURER: self.flow.selected_profile.manufacturer,
|
||||
CONF_MODEL: self.flow.selected_profile.model,
|
||||
},
|
||||
)
|
||||
return await self.async_step_post_library(user_input)
|
||||
|
||||
async def _async_autodiscover_profile(self) -> None:
|
||||
"""Populate the selected profile from the source entity when possible."""
|
||||
if not self.flow.source_entity or not self.flow.source_entity.entity_entry or self.flow.selected_profile is not None:
|
||||
return
|
||||
|
||||
self.flow.selected_profile = await get_power_profile_by_source_entity(self.flow.hass, self.flow.source_entity)
|
||||
if self.flow.selected_profile is None and self.flow.source_entity.device_entry:
|
||||
self.flow.selected_profile = await get_power_profile_by_source_device(self.flow.hass, self.flow.source_entity)
|
||||
|
||||
def _show_autodiscovered_profile_form(self) -> FlowResult:
|
||||
"""Show the confirmation form for an autodiscovered library profile."""
|
||||
profile = self.flow.selected_profile
|
||||
assert profile is not None
|
||||
|
||||
return cast(
|
||||
FlowResult,
|
||||
self.flow.async_show_form(
|
||||
step_id=Step.LIBRARY,
|
||||
description_placeholders=self._build_library_description_placeholders(profile),
|
||||
data_schema=SCHEMA_POWER_AUTODISCOVERED,
|
||||
errors={},
|
||||
last_step=False,
|
||||
),
|
||||
)
|
||||
|
||||
def _build_library_description_placeholders(self, profile: PowerProfile) -> dict[str, Any]:
|
||||
"""Build the placeholders for the autodiscovered profile confirmation form."""
|
||||
return {
|
||||
"remarks": self._build_library_remarks(profile),
|
||||
"manufacturer": profile.manufacturer,
|
||||
"model": profile.model,
|
||||
"source": self._get_profile_source(profile),
|
||||
}
|
||||
|
||||
def _build_library_remarks(self, profile: PowerProfile) -> str | None:
|
||||
"""Build the remarks text for the autodiscovered profile confirmation form."""
|
||||
remarks = self._get_conditional_remarks()
|
||||
if remarks:
|
||||
remarks = "\n\n" + remarks
|
||||
|
||||
if profile.documentation_url:
|
||||
return (remarks or "") + f"\n\n[Documentation]({profile.documentation_url})"
|
||||
|
||||
return remarks
|
||||
|
||||
def _get_profile_source(self, profile: PowerProfile) -> str:
|
||||
"""Build the autodiscovery source description."""
|
||||
translations = translation.async_get_cached_translations(self.flow.hass, self.flow.hass.config.language, "common", DOMAIN)
|
||||
if profile.discovery_by == DiscoveryBy.DEVICE and self.flow.source_entity and self.flow.source_entity.device_entry:
|
||||
return f"{translations.get(f'component.{DOMAIN}.common.source_device')}: {self.flow.source_entity.device_entry.name}"
|
||||
|
||||
return f"{translations.get(f'component.{DOMAIN}.common.source_entity')}: {self.flow.source_entity_id}"
|
||||
|
||||
def _get_conditional_remarks(self) -> str | None:
|
||||
"""Get discovery remarks, only showing them if required entities are missing."""
|
||||
profile = self.flow.selected_profile
|
||||
if not profile:
|
||||
return None # pragma: no cover
|
||||
|
||||
remarks = profile.config_flow_discovery_remarks
|
||||
if not remarks:
|
||||
return None
|
||||
|
||||
# Check if all entity_by_* placeholders can be resolved from the device
|
||||
device_entry = self.flow.source_entity.device_entry if self.flow.source_entity else None
|
||||
if not device_entry:
|
||||
return remarks
|
||||
|
||||
related_placeholders = iter_related_entity_placeholders(collect_placeholders(profile.json_data))
|
||||
all_resolved = all(
|
||||
resolve_related_entity_placeholder(
|
||||
self.flow.hass,
|
||||
placeholder,
|
||||
source_entity=self.flow.source_entity,
|
||||
)
|
||||
for placeholder in related_placeholders
|
||||
)
|
||||
return None if all_resolved else remarks
|
||||
|
||||
|
||||
class LibraryOptionsFlow(LibraryFlow):
|
||||
def __init__(self, flow: PowercalcOptionsFlow) -> None:
|
||||
super().__init__(flow)
|
||||
self.flow: PowercalcOptionsFlow = flow
|
||||
|
||||
async def async_step_library_options(self, user_input: dict[str, Any] | None = None) -> FlowResult:
|
||||
"""Handle the basic options flow."""
|
||||
self.flow.is_library_flow = True
|
||||
self.flow.selected_sub_profile = self.flow.selected_profile.sub_profile # type: ignore
|
||||
if user_input is not None:
|
||||
return await self.async_step_manufacturer()
|
||||
|
||||
return self.flow.async_show_form(
|
||||
step_id=Step.LIBRARY_OPTIONS,
|
||||
description_placeholders={
|
||||
"manufacturer": self.flow.selected_profile.manufacturer, # type: ignore
|
||||
"model": self.flow.selected_profile.model, # type: ignore
|
||||
},
|
||||
last_step=False,
|
||||
)
|
||||
Reference in New Issue
Block a user