1 """Config flow for AlarmDecoder."""
3 from __future__
import annotations
8 from adext
import AdExt
9 from alarmdecoder.devices
import SerialDevice, SocketDevice
10 from alarmdecoder.util
import NoDeviceError
11 import voluptuous
as vol
14 DEVICE_CLASSES_SCHEMA
as BINARY_SENSOR_DEVICE_CLASSES_SCHEMA,
28 CONF_CODE_ARM_REQUIRED,
52 EDIT_KEY =
"edit_selection"
54 EDIT_SETTINGS =
"Arming Settings"
56 _LOGGER = logging.getLogger(__name__)
60 """Handle a AlarmDecoder config flow."""
65 """Initialize AlarmDecoder ConfigFlow."""
71 config_entry: ConfigEntry,
72 ) -> AlarmDecoderOptionsFlowHandler:
73 """Get the options flow for AlarmDecoder."""
77 self, user_input: dict[str, Any] |
None =
None
78 ) -> ConfigFlowResult:
79 """Handle a flow initialized by the user."""
80 if user_input
is not None:
81 self.
protocolprotocol = user_input[CONF_PROTOCOL]
86 data_schema=vol.Schema(
88 vol.Required(CONF_PROTOCOL): vol.In(
89 [PROTOCOL_SOCKET, PROTOCOL_SERIAL]
96 self, user_input: dict[str, Any] |
None =
None
97 ) -> ConfigFlowResult:
98 """Handle AlarmDecoder protocol setup."""
100 if user_input
is not None:
107 if self.
protocolprotocol == PROTOCOL_SOCKET:
108 host = connection[CONF_HOST] = user_input[CONF_HOST]
109 port = connection[CONF_PORT] = user_input[CONF_PORT]
110 title = f
"{host}:{port}"
111 device = SocketDevice(interface=(host, port))
112 if self.
protocolprotocol == PROTOCOL_SERIAL:
113 path = connection[CONF_DEVICE_PATH] = user_input[CONF_DEVICE_PATH]
114 baud = connection[CONF_DEVICE_BAUD] = user_input[CONF_DEVICE_BAUD]
116 device = SerialDevice(interface=path)
118 controller = AdExt(device)
121 controller.open(baud)
125 await self.hass.async_add_executor_job(test_connection)
127 title=title, data={CONF_PROTOCOL: self.
protocolprotocol, **connection}
129 except NoDeviceError:
130 errors[
"base"] =
"cannot_connect"
132 _LOGGER.exception(
"Unexpected exception during AlarmDecoder setup")
133 errors[
"base"] =
"unknown"
135 if self.
protocolprotocol == PROTOCOL_SOCKET:
138 vol.Required(CONF_HOST, default=DEFAULT_DEVICE_HOST): str,
139 vol.Required(CONF_PORT, default=DEFAULT_DEVICE_PORT): int,
142 if self.
protocolprotocol == PROTOCOL_SERIAL:
145 vol.Required(CONF_DEVICE_PATH, default=DEFAULT_DEVICE_PATH): str,
146 vol.Required(CONF_DEVICE_BAUD, default=DEFAULT_DEVICE_BAUD): int,
158 """Handle AlarmDecoder options."""
162 def __init__(self, config_entry: ConfigEntry) ->
None:
163 """Initialize AlarmDecoder options flow."""
164 self.
arm_optionsarm_options = config_entry.options.get(OPTIONS_ARM, DEFAULT_ARM_OPTIONS)
166 OPTIONS_ZONES, DEFAULT_ZONE_OPTIONS
170 self, user_input: dict[str, Any] |
None =
None
171 ) -> ConfigFlowResult:
172 """Manage the options."""
173 if user_input
is not None:
174 if user_input[EDIT_KEY] == EDIT_SETTINGS:
176 if user_input[EDIT_KEY] == EDIT_ZONES:
181 data_schema=vol.Schema(
183 vol.Required(EDIT_KEY, default=EDIT_SETTINGS): vol.In(
184 [EDIT_SETTINGS, EDIT_ZONES]
191 self, user_input: dict[str, Any] |
None =
None
192 ) -> ConfigFlowResult:
193 """Arming options form."""
194 if user_input
is not None:
197 data={OPTIONS_ARM: user_input, OPTIONS_ZONES: self.
zone_optionszone_options},
201 step_id=
"arm_settings",
202 data_schema=vol.Schema(
206 default=self.
arm_optionsarm_options[CONF_ALT_NIGHT_MODE],
209 CONF_AUTO_BYPASS, default=self.
arm_optionsarm_options[CONF_AUTO_BYPASS]
212 CONF_CODE_ARM_REQUIRED,
213 default=self.
arm_optionsarm_options[CONF_CODE_ARM_REQUIRED],
220 self, user_input: dict[str, Any] |
None =
None
221 ) -> ConfigFlowResult:
222 """Zone selection form."""
225 if user_input
is not None and not errors:
227 int(user_input[CONF_ZONE_NUMBER])
232 step_id=
"zone_select",
233 data_schema=vol.Schema({vol.Required(CONF_ZONE_NUMBER): str}),
238 self, user_input: dict[str, Any] |
None =
None
239 ) -> ConfigFlowResult:
240 """Zone details form."""
243 if user_input
is not None and not errors:
249 if CONF_ZONE_NAME
not in zone_options[zone_id]:
250 zone_options.pop(zone_id)
254 data={OPTIONS_ARM: self.
arm_optionsarm_options, OPTIONS_ZONES: zone_options},
260 step_id=
"zone_details",
261 description_placeholders={CONF_ZONE_NUMBER: self.
selected_zoneselected_zone},
262 data_schema=vol.Schema(
267 "suggested_value": existing_zone_settings.get(
274 default=existing_zone_settings.get(
275 CONF_ZONE_TYPE, DEFAULT_ZONE_TYPE
277 ): BINARY_SENSOR_DEVICE_CLASSES_SCHEMA,
281 "suggested_value": existing_zone_settings.get(
289 "suggested_value": existing_zone_settings.get(
297 "suggested_value": existing_zone_settings.get(
305 "suggested_value": existing_zone_settings.get(
322 if (CONF_RELAY_ADDR
in zone_input
and CONF_RELAY_CHAN
not in zone_input)
or (
323 CONF_RELAY_ADDR
not in zone_input
and CONF_RELAY_CHAN
in zone_input
325 errors[
"base"] =
"relay_inclusive"
328 for key
in (CONF_ZONE_NUMBER, CONF_ZONE_LOOP, CONF_RELAY_ADDR, CONF_RELAY_CHAN):
329 if key
in zone_input:
336 if CONF_ZONE_LOOP
in zone_input
and CONF_ZONE_RFID
not in zone_input:
337 errors[CONF_ZONE_LOOP] =
"loop_rfid"
341 CONF_ZONE_LOOP
in zone_input
342 and zone_input[CONF_ZONE_LOOP].isdigit()
343 and int(zone_input[CONF_ZONE_LOOP])
not in list(range(1, 5))
345 errors[CONF_ZONE_LOOP] =
"loop_range"
351 """Convert necessary keys to int.
353 Since ConfigFlow inputs of type int cannot default to an empty string, we collect the values below as
354 strings and then convert them to ints.
357 for key
in (CONF_ZONE_LOOP, CONF_RELAY_ADDR, CONF_RELAY_CHAN):
358 if key
in zone_input:
359 zone_input[key] =
int(zone_input[key])
365 current_entries: list[ConfigEntry], user_input: dict[str, Any], protocol: str |
None
367 """Determine if entry has already been added to HA."""
368 user_host = user_input.get(CONF_HOST)
369 user_port = user_input.get(CONF_PORT)
370 user_path = user_input.get(CONF_DEVICE_PATH)
371 user_baud = user_input.get(CONF_DEVICE_BAUD)
373 for entry
in current_entries:
374 entry_host = entry.data.get(CONF_HOST)
375 entry_port = entry.data.get(CONF_PORT)
376 entry_path = entry.data.get(CONF_DEVICE_PATH)
377 entry_baud = entry.data.get(CONF_DEVICE_BAUD)
380 protocol == PROTOCOL_SOCKET
381 and user_host == entry_host
382 and user_port == entry_port
387 protocol == PROTOCOL_SERIAL
388 and user_baud == entry_baud
389 and user_path == entry_path
AlarmDecoderOptionsFlowHandler async_get_options_flow(ConfigEntry config_entry)
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_protocol(self, dict[str, Any]|None user_input=None)
None __init__(self, ConfigEntry config_entry)
ConfigFlowResult async_step_zone_select(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_zone_details(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_init(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_arm_settings(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_create_entry(self, *str title, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None, Mapping[str, Any]|None options=None)
list[ConfigEntry] _async_current_entries(self, bool|None include_ignore=None)
ConfigFlowResult async_abort(self, *str reason, Mapping[str, str]|None description_placeholders=None)
ConfigFlowResult async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
_FlowResultT async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
_FlowResultT async_create_entry(self, *str|None title=None, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None)
_FlowResultT async_abort(self, *str reason, Mapping[str, str]|None description_placeholders=None)
dict[str, str] _validate_zone_input(dict[str, Any]|None zone_input)
dict[str, Any] _fix_input_types(dict[str, Any] zone_input)
bool _device_already_added(list[ConfigEntry] current_entries, dict[str, Any] user_input, str|None protocol)
web.Response get(self, web.Request request, str config_key)
str test_connection(HomeAssistant hass, str host, int port)