mirror of https://github.com/home-assistant/core
188 lines
5.9 KiB
Python
188 lines
5.9 KiB
Python
"""Config flow for Random helper."""
|
|
|
|
from collections.abc import Callable, Coroutine, Mapping
|
|
from enum import StrEnum
|
|
from typing import Any, cast
|
|
|
|
import voluptuous as vol
|
|
|
|
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
|
|
from homeassistant.components.sensor import DEVICE_CLASS_UNITS, SensorDeviceClass
|
|
from homeassistant.const import (
|
|
CONF_DEVICE_CLASS,
|
|
CONF_MAXIMUM,
|
|
CONF_MINIMUM,
|
|
CONF_NAME,
|
|
CONF_UNIT_OF_MEASUREMENT,
|
|
Platform,
|
|
)
|
|
from homeassistant.core import callback
|
|
import homeassistant.helpers.config_validation as cv
|
|
from homeassistant.helpers.schema_config_entry_flow import (
|
|
SchemaCommonFlowHandler,
|
|
SchemaConfigFlowHandler,
|
|
SchemaFlowFormStep,
|
|
SchemaFlowMenuStep,
|
|
)
|
|
from homeassistant.helpers.selector import (
|
|
SelectSelector,
|
|
SelectSelectorConfig,
|
|
SelectSelectorMode,
|
|
TextSelector,
|
|
)
|
|
|
|
from .const import DOMAIN
|
|
from .sensor import DEFAULT_MAX, DEFAULT_MIN
|
|
|
|
|
|
class _FlowType(StrEnum):
|
|
CONFIG = "config"
|
|
OPTION = "option"
|
|
|
|
|
|
def _generate_schema(domain: str, flow_type: _FlowType) -> vol.Schema:
|
|
"""Generate schema."""
|
|
schema: dict[vol.Marker, Any] = {}
|
|
|
|
if flow_type == _FlowType.CONFIG:
|
|
schema[vol.Required(CONF_NAME)] = TextSelector()
|
|
|
|
if domain == Platform.BINARY_SENSOR:
|
|
schema[vol.Optional(CONF_DEVICE_CLASS)] = SelectSelector(
|
|
SelectSelectorConfig(
|
|
options=[cls.value for cls in BinarySensorDeviceClass],
|
|
sort=True,
|
|
mode=SelectSelectorMode.DROPDOWN,
|
|
translation_key="binary_sensor_device_class",
|
|
),
|
|
)
|
|
|
|
if domain == Platform.SENSOR:
|
|
schema.update(
|
|
{
|
|
vol.Optional(CONF_MINIMUM, default=DEFAULT_MIN): cv.positive_int,
|
|
vol.Optional(CONF_MAXIMUM, default=DEFAULT_MAX): cv.positive_int,
|
|
vol.Optional(CONF_DEVICE_CLASS): SelectSelector(
|
|
SelectSelectorConfig(
|
|
options=[
|
|
cls.value
|
|
for cls in SensorDeviceClass
|
|
if cls != SensorDeviceClass.ENUM
|
|
],
|
|
sort=True,
|
|
mode=SelectSelectorMode.DROPDOWN,
|
|
translation_key="sensor_device_class",
|
|
),
|
|
),
|
|
vol.Optional(CONF_UNIT_OF_MEASUREMENT): SelectSelector(
|
|
SelectSelectorConfig(
|
|
options=[
|
|
str(unit)
|
|
for units in DEVICE_CLASS_UNITS.values()
|
|
for unit in units
|
|
if unit is not None
|
|
],
|
|
sort=True,
|
|
mode=SelectSelectorMode.DROPDOWN,
|
|
translation_key="sensor_unit_of_measurement",
|
|
custom_value=True,
|
|
),
|
|
),
|
|
}
|
|
)
|
|
|
|
return vol.Schema(schema)
|
|
|
|
|
|
async def choose_options_step(options: dict[str, Any]) -> str:
|
|
"""Return next step_id for options flow according to entity_type."""
|
|
return cast(str, options["entity_type"])
|
|
|
|
|
|
def _validate_unit(options: dict[str, Any]) -> None:
|
|
"""Validate unit of measurement."""
|
|
if (
|
|
(device_class := options.get(CONF_DEVICE_CLASS))
|
|
and (units := DEVICE_CLASS_UNITS.get(device_class))
|
|
and (unit := options.get(CONF_UNIT_OF_MEASUREMENT)) not in units
|
|
):
|
|
sorted_units = sorted(
|
|
[f"'{unit!s}'" if unit else "no unit of measurement" for unit in units],
|
|
key=str.casefold,
|
|
)
|
|
if len(sorted_units) == 1:
|
|
units_string = sorted_units[0]
|
|
else:
|
|
units_string = f"one of {', '.join(sorted_units)}"
|
|
|
|
raise vol.Invalid(
|
|
f"'{unit}' is not a valid unit for device class '{device_class}'; "
|
|
f"expected {units_string}"
|
|
)
|
|
|
|
|
|
def validate_user_input(
|
|
entity_type: str,
|
|
) -> Callable[
|
|
[SchemaCommonFlowHandler, dict[str, Any]],
|
|
Coroutine[Any, Any, dict[str, Any]],
|
|
]:
|
|
"""Do post validation of user input.
|
|
|
|
For sensors: Validate unit of measurement.
|
|
"""
|
|
|
|
async def _validate_user_input(
|
|
_: SchemaCommonFlowHandler,
|
|
user_input: dict[str, Any],
|
|
) -> dict[str, Any]:
|
|
"""Add entity type to user input."""
|
|
if entity_type == Platform.SENSOR:
|
|
_validate_unit(user_input)
|
|
return {"entity_type": entity_type} | user_input
|
|
|
|
return _validate_user_input
|
|
|
|
|
|
RANDOM_TYPES = [
|
|
Platform.BINARY_SENSOR.value,
|
|
Platform.SENSOR.value,
|
|
]
|
|
|
|
CONFIG_FLOW = {
|
|
"user": SchemaFlowMenuStep(RANDOM_TYPES),
|
|
Platform.BINARY_SENSOR: SchemaFlowFormStep(
|
|
_generate_schema(Platform.BINARY_SENSOR, _FlowType.CONFIG),
|
|
validate_user_input=validate_user_input(Platform.BINARY_SENSOR),
|
|
),
|
|
Platform.SENSOR: SchemaFlowFormStep(
|
|
_generate_schema(Platform.SENSOR, _FlowType.CONFIG),
|
|
validate_user_input=validate_user_input(Platform.SENSOR),
|
|
),
|
|
}
|
|
|
|
|
|
OPTIONS_FLOW = {
|
|
"init": SchemaFlowFormStep(next_step=choose_options_step),
|
|
Platform.BINARY_SENSOR: SchemaFlowFormStep(
|
|
_generate_schema(Platform.BINARY_SENSOR, _FlowType.OPTION),
|
|
validate_user_input=validate_user_input(Platform.BINARY_SENSOR),
|
|
),
|
|
Platform.SENSOR: SchemaFlowFormStep(
|
|
_generate_schema(Platform.SENSOR, _FlowType.OPTION),
|
|
validate_user_input=validate_user_input(Platform.SENSOR),
|
|
),
|
|
}
|
|
|
|
|
|
class RandomConfigFlowHandler(SchemaConfigFlowHandler, domain=DOMAIN):
|
|
"""Handle config flow for random helper."""
|
|
|
|
config_flow = CONFIG_FLOW
|
|
options_flow = OPTIONS_FLOW
|
|
|
|
@callback
|
|
def async_config_entry_title(self, options: Mapping[str, Any]) -> str:
|
|
"""Return config entry title."""
|
|
return cast(str, options["name"])
|