Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for Mold indicator."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Mapping
6 from typing import Any, cast
7 
8 import voluptuous as vol
9 
10 from homeassistant.components import websocket_api
11 from homeassistant.components.sensor import SensorDeviceClass
12 from homeassistant.const import CONF_NAME, Platform
13 from homeassistant.core import HomeAssistant, callback
14 from homeassistant.exceptions import HomeAssistantError
16  SchemaCommonFlowHandler,
17  SchemaConfigFlowHandler,
18  SchemaFlowError,
19  SchemaFlowFormStep,
20 )
22  EntitySelector,
23  EntitySelectorConfig,
24  NumberSelector,
25  NumberSelectorConfig,
26  NumberSelectorMode,
27  TextSelector,
28 )
29 from homeassistant.util.unit_system import METRIC_SYSTEM
30 
31 from .const import (
32  CONF_CALIBRATION_FACTOR,
33  CONF_INDOOR_HUMIDITY,
34  CONF_INDOOR_TEMP,
35  CONF_OUTDOOR_TEMP,
36  DEFAULT_NAME,
37  DOMAIN,
38 )
39 from .sensor import MoldIndicator
40 
41 
42 async def validate_input(
43  handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
44 ) -> dict[str, Any]:
45  """Validate already existing entry."""
46  handler.parent_handler._async_abort_entries_match({**handler.options, **user_input}) # noqa: SLF001
47  if user_input[CONF_CALIBRATION_FACTOR] == 0.0:
48  raise SchemaFlowError("calibration_is_zero")
49  return user_input
50 
51 
52 DATA_SCHEMA_OPTIONS = vol.Schema(
53  {
54  vol.Required(CONF_CALIBRATION_FACTOR): NumberSelector(
55  NumberSelectorConfig(step=0.1, mode=NumberSelectorMode.BOX)
56  )
57  }
58 )
59 
60 DATA_SCHEMA_CONFIG = vol.Schema(
61  {
62  vol.Required(CONF_NAME, default=DEFAULT_NAME): TextSelector(),
63  vol.Required(CONF_INDOOR_TEMP): EntitySelector(
65  domain=Platform.SENSOR, device_class=SensorDeviceClass.TEMPERATURE
66  )
67  ),
68  vol.Required(CONF_INDOOR_HUMIDITY): EntitySelector(
70  domain=Platform.SENSOR, device_class=SensorDeviceClass.HUMIDITY
71  )
72  ),
73  vol.Required(CONF_OUTDOOR_TEMP): EntitySelector(
75  domain=Platform.SENSOR, device_class=SensorDeviceClass.TEMPERATURE
76  )
77  ),
78  }
79 ).extend(DATA_SCHEMA_OPTIONS.schema)
80 
81 
82 CONFIG_FLOW = {
83  "user": SchemaFlowFormStep(
84  schema=DATA_SCHEMA_CONFIG,
85  validate_user_input=validate_input,
86  preview="mold_indicator",
87  ),
88 }
89 OPTIONS_FLOW = {
90  "init": SchemaFlowFormStep(
91  DATA_SCHEMA_OPTIONS,
92  validate_user_input=validate_input,
93  preview="mold_indicator",
94  )
95 }
96 
97 
99  """Handle a config flow for Mold indicator."""
100 
101  config_flow = CONFIG_FLOW
102  options_flow = OPTIONS_FLOW
103 
104  def async_config_entry_title(self, options: Mapping[str, Any]) -> str:
105  """Return config entry title."""
106  return cast(str, options[CONF_NAME])
107 
108  @staticmethod
109  async def async_setup_preview(hass: HomeAssistant) -> None:
110  """Set up preview WS API."""
111  websocket_api.async_register_command(hass, ws_start_preview)
112 
113 
114 @websocket_api.websocket_command( { vol.Required("type"): "mold_indicator/start_preview",
115  vol.Required("flow_id"): str,
116  vol.Required("flow_type"): vol.Any("config_flow", "options_flow"),
117  vol.Required("user_input"): dict,
118  }
119 )
120 @callback
121 def ws_start_preview(
122  hass: HomeAssistant,
124  msg: dict[str, Any],
125 ) -> None:
126  """Generate a preview."""
127 
128  if msg["flow_type"] == "config_flow":
129  flow_status = hass.config_entries.flow.async_get(msg["flow_id"])
130  flow_sets = hass.config_entries.flow._handler_progress_index.get( # noqa: SLF001
131  flow_status["handler"]
132  )
133  assert flow_sets
134  config_entry = hass.config_entries.async_get_entry(flow_status["handler"])
135  indoor_temp = msg["user_input"].get(CONF_INDOOR_TEMP)
136  outdoor_temp = msg["user_input"].get(CONF_OUTDOOR_TEMP)
137  indoor_hum = msg["user_input"].get(CONF_INDOOR_HUMIDITY)
138  name = msg["user_input"].get(CONF_NAME)
139  else:
140  flow_status = hass.config_entries.options.async_get(msg["flow_id"])
141  config_entry = hass.config_entries.async_get_entry(flow_status["handler"])
142  if not config_entry:
143  raise HomeAssistantError("Config entry not found")
144  indoor_temp = config_entry.options[CONF_INDOOR_TEMP]
145  outdoor_temp = config_entry.options[CONF_OUTDOOR_TEMP]
146  indoor_hum = config_entry.options[CONF_INDOOR_HUMIDITY]
147  name = config_entry.options[CONF_NAME]
148 
149  @callback
150  def async_preview_updated(state: str, attributes: Mapping[str, Any]) -> None:
151  """Forward config entry state events to websocket."""
152  connection.send_message(
153  websocket_api.event_message(
154  msg["id"], {"attributes": attributes, "state": state}
155  )
156  )
157 
158  preview_entity = MoldIndicator(
159  hass,
160  name,
161  hass.config.units is METRIC_SYSTEM,
162  indoor_temp,
163  outdoor_temp,
164  indoor_hum,
165  msg["user_input"].get(CONF_CALIBRATION_FACTOR),
166  None,
167  )
168  preview_entity.hass = hass
169 
170  connection.send_result(msg["id"])
171  connection.subscriptions[msg["id"]] = preview_entity.async_start_preview(
172  async_preview_updated
173  )
174 
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
None ws_start_preview(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
Definition: config_flow.py:127
dict[str, Any] validate_input(SchemaCommonFlowHandler handler, dict[str, Any] user_input)
Definition: config_flow.py:44