1 """Config flow for Group integration."""
3 from __future__
import annotations
5 from collections.abc
import Callable, Coroutine, Mapping
6 from functools
import partial
7 from typing
import Any, cast
9 import voluptuous
as vol
17 SchemaCommonFlowHandler,
18 SchemaConfigFlowHandler,
21 SchemaOptionsFlowHandler,
22 entity_selector_without_own_entities,
25 from .binary_sensor
import CONF_ALL, async_create_preview_binary_sensor
26 from .button
import async_create_preview_button
27 from .const
import CONF_HIDE_MEMBERS, CONF_IGNORE_NON_NUMERIC, DOMAIN
28 from .cover
import async_create_preview_cover
29 from .entity
import GroupEntity
30 from .event
import async_create_preview_event
31 from .fan
import async_create_preview_fan
32 from .light
import async_create_preview_light
33 from .lock
import async_create_preview_lock
34 from .media_player
import MediaPlayerGroup, async_create_preview_media_player
35 from .notify
import async_create_preview_notify
36 from .sensor
import async_create_preview_sensor
37 from .switch
import async_create_preview_switch
39 _STATISTIC_MEASURES = [
53 domain: str | list[str], handler: SchemaCommonFlowHandler |
None
55 """Generate options schema."""
56 entity_selector: selector.Selector[Any] | vol.Schema
58 entity_selector = selector.selector(
59 {
"entity": {
"domain": domain,
"multiple":
True}}
63 cast(SchemaOptionsFlowHandler, handler.parent_handler),
64 selector.EntitySelectorConfig(domain=domain, multiple=
True),
69 vol.Required(CONF_ENTITIES): entity_selector,
70 vol.Required(CONF_HIDE_MEMBERS, default=
False): selector.BooleanSelector(),
76 """Generate config schema."""
79 vol.Required(
"name"): selector.TextSelector(),
80 vol.Required(CONF_ENTITIES): selector.EntitySelector(
81 selector.EntitySelectorConfig(domain=domain, multiple=
True),
83 vol.Required(CONF_HIDE_MEMBERS, default=
False): selector.BooleanSelector(),
89 handler: SchemaCommonFlowHandler |
None,
91 """Generate options schema."""
94 vol.Required(CONF_ALL, default=
False): selector.BooleanSelector(),
101 vol.Required(CONF_ALL, default=
False): selector.BooleanSelector(),
105 SENSOR_CONFIG_EXTENDS = {
106 vol.Required(CONF_TYPE): selector.SelectSelector(
107 selector.SelectSelectorConfig(
108 options=_STATISTIC_MEASURES, translation_key=CONF_TYPE
113 vol.Optional(CONF_IGNORE_NON_NUMERIC, default=
False): selector.BooleanSelector(),
114 vol.Required(CONF_TYPE): selector.SelectSelector(
115 selector.SelectSelectorConfig(
116 options=_STATISTIC_MEASURES, translation_key=CONF_TYPE
123 domain: str, handler: SchemaCommonFlowHandler |
None
125 """Generate options schema."""
128 ).extend(SENSOR_OPTIONS)
132 [
"sensor",
"number",
"input_number"]
133 ).extend(SENSOR_CONFIG_EXTENDS)
137 domain: str, handler: SchemaCommonFlowHandler |
None
139 """Generate options schema."""
143 CONF_ALL, default=
False, description={
"advanced":
True}
144 ): selector.BooleanSelector(),
165 """Return next step_id for options flow according to group_type."""
166 return cast(str, options[
"group_type"])
172 [SchemaCommonFlowHandler, dict[str, Any]], Coroutine[Any, Any, dict[str, Any]]
174 """Set group type."""
176 async
def _set_group_type(
177 handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
179 """Add group type to user input."""
180 return {
"group_type": group_type, **user_input}
182 return _set_group_type
188 BINARY_SENSOR_CONFIG_SCHEMA,
233 SENSOR_CONFIG_SCHEMA,
248 binary_sensor_options_schema,
252 partial(basic_group_options_schema,
"button"),
256 partial(basic_group_options_schema,
"cover"),
260 partial(basic_group_options_schema,
"event"),
264 partial(basic_group_options_schema,
"fan"),
268 partial(light_switch_options_schema,
"light"),
272 partial(basic_group_options_schema,
"lock"),
276 partial(basic_group_options_schema,
"media_player"),
280 partial(basic_group_options_schema,
"notify"),
284 partial(sensor_options_schema,
"sensor"),
288 partial(light_switch_options_schema,
"switch"),
293 PREVIEW_OPTIONS_SCHEMA: dict[str, vol.Schema] = {}
295 CREATE_PREVIEW_ENTITY: dict[
297 Callable[[HomeAssistant, str, dict[str, Any]], GroupEntity | MediaPlayerGroup],
299 "binary_sensor": async_create_preview_binary_sensor,
300 "button": async_create_preview_button,
301 "cover": async_create_preview_cover,
302 "event": async_create_preview_event,
303 "fan": async_create_preview_fan,
304 "light": async_create_preview_light,
305 "lock": async_create_preview_lock,
306 "media_player": async_create_preview_media_player,
307 "notify": async_create_preview_notify,
308 "sensor": async_create_preview_sensor,
309 "switch": async_create_preview_switch,
314 """Handle a config or options flow for groups."""
316 config_flow = CONFIG_FLOW
317 options_flow = OPTIONS_FLOW
321 """Return config entry title.
323 The options parameter contains config entry options, which is the union of user
324 input from the config flow steps.
326 return cast(str, options[
"name"])
if "name" in options
else ""
330 """Hide the group members if requested."""
331 if options[CONF_HIDE_MEMBERS]:
333 self.hass, options[CONF_ENTITIES], er.RegistryEntryHider.INTEGRATION
339 hass: HomeAssistant, options: Mapping[str, Any]
341 """Hide or unhide the group members as requested."""
343 er.RegistryEntryHider.INTEGRATION
if options[CONF_HIDE_MEMBERS]
else None
349 """Set up preview WS API."""
350 for group_type, form_step
in OPTIONS_FLOW.items():
351 if group_type
not in GROUP_TYPES:
355 [SchemaCommonFlowHandler |
None], Coroutine[Any, Any, vol.Schema]
359 PREVIEW_OPTIONS_SCHEMA[group_type] = await schema(
None)
360 websocket_api.async_register_command(hass, ws_start_preview)
364 hass: HomeAssistant, members: list[str], hidden_by: er.RegistryEntryHider |
None
366 """Hide or unhide group members."""
367 registry = er.async_get(hass)
368 for member
in members:
369 if not (entity_id := er.async_resolve_entity_id(registry, member)):
371 if entity_id
not in registry.entities:
373 registry.async_update_entity(entity_id, hidden_by=hidden_by)
376 @websocket_api.websocket_command(
{
vol.Required("type"):
"group/start_preview",
377 vol.Required(
"flow_id"): str,
378 vol.Required(
"flow_type"): vol.Any(
"config_flow",
"options_flow"),
379 vol.Required(
"user_input"): dict,
388 """Generate a preview."""
389 entity_registry_entry: er.RegistryEntry |
None =
None
390 if msg[
"flow_type"] ==
"config_flow":
391 flow_status = hass.config_entries.flow.async_get(msg[
"flow_id"])
392 group_type = flow_status[
"step_id"]
393 form_step = cast(SchemaFlowFormStep, CONFIG_FLOW[group_type])
394 schema = cast(vol.Schema, form_step.schema)
395 validated = schema(msg[
"user_input"])
396 name = validated[
"name"]
398 flow_status = hass.config_entries.options.async_get(msg[
"flow_id"])
399 config_entry_id = flow_status[
"handler"]
400 config_entry = hass.config_entries.async_get_entry(config_entry_id)
402 raise HomeAssistantError
403 group_type = config_entry.options[
"group_type"]
404 name = config_entry.options[
"name"]
405 validated = PREVIEW_OPTIONS_SCHEMA[group_type](msg[
"user_input"])
406 entity_registry = er.async_get(hass)
407 entries = er.async_entries_for_config_entry(entity_registry, config_entry_id)
409 entity_registry_entry = entries[0]
412 def async_preview_updated(state: str, attributes: Mapping[str, Any]) ->
None:
413 """Forward config entry state events to websocket."""
414 connection.send_message(
415 websocket_api.event_message(
416 msg[
"id"], {
"attributes": attributes,
"state": state}
420 preview_entity: GroupEntity | MediaPlayerGroup = CREATE_PREVIEW_ENTITY[group_type](
421 hass, name, validated
423 preview_entity.hass = hass
424 preview_entity.registry_entry = entity_registry_entry
426 connection.send_result(msg[
"id"])
427 connection.subscriptions[msg[
"id"]] = preview_entity.async_start_preview(
428 async_preview_updated
430
None async_options_flow_finished(HomeAssistant hass, Mapping[str, Any] options)
None async_setup_preview(HomeAssistant hass)
None async_config_flow_finished(self, Mapping[str, Any] options)
str async_config_entry_title(self, Mapping[str, Any] options)
None _async_hide_members(HomeAssistant hass, list[str] members, er.RegistryEntryHider|None hidden_by)
vol.Schema basic_group_options_schema(str|list[str] domain, SchemaCommonFlowHandler|None handler)
vol.Schema light_switch_options_schema(str domain, SchemaCommonFlowHandler|None handler)
vol.Schema sensor_options_schema(str domain, SchemaCommonFlowHandler|None handler)
Callable[[SchemaCommonFlowHandler, dict[str, Any]], Coroutine[Any, Any, dict[str, Any]]] set_group_type(str group_type)
vol.Schema basic_group_config_schema(str|list[str] domain)
str choose_options_step(dict[str, Any] options)
None ws_start_preview(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
vol.Schema binary_sensor_options_schema(SchemaCommonFlowHandler|None handler)
selector.EntitySelector entity_selector_without_own_entities(SchemaOptionsFlowHandler handler, selector.EntitySelectorConfig entity_selector_config)