mirror of
https://github.com/home-assistant/core.git
synced 2025-07-14 08:47:10 +00:00
Add konnected multi output (#33412)
* add test to for importing multiple output settings * provide option to set multiple output states * tweaks after testing * Update homeassistant/components/konnected/config_flow.py Co-Authored-By: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
d59209ff47
commit
0e6b905cdf
@ -33,6 +33,7 @@
|
||||
"abort": {
|
||||
"not_konn_panel": "Not a recognized Konnected.io device"
|
||||
},
|
||||
"error": {},
|
||||
"step": {
|
||||
"options_binary": {
|
||||
"data": {
|
||||
@ -91,11 +92,12 @@
|
||||
"data": {
|
||||
"activation": "Output when on",
|
||||
"momentary": "Pulse duration (ms) (optional)",
|
||||
"more_states": "Configure additional states for this zone",
|
||||
"name": "Name (optional)",
|
||||
"pause": "Pause between pulses (ms) (optional)",
|
||||
"repeat": "Times to repeat (-1=infinite) (optional)"
|
||||
},
|
||||
"description": "Please select the output options for {zone}",
|
||||
"description": "Please select the output options for {zone}: state {state}",
|
||||
"title": "Configure Switchable Output"
|
||||
}
|
||||
},
|
||||
|
@ -57,6 +57,10 @@ CONF_IO_BIN = "Binary Sensor"
|
||||
CONF_IO_DIG = "Digital Sensor"
|
||||
CONF_IO_SWI = "Switchable Output"
|
||||
|
||||
CONF_MORE_STATES = "more_states"
|
||||
CONF_YES = "Yes"
|
||||
CONF_NO = "No"
|
||||
|
||||
KONN_MANUFACTURER = "konnected.io"
|
||||
KONN_PANEL_MODEL_NAMES = {
|
||||
KONN_MODEL: "Konnected Alarm Panel",
|
||||
@ -117,7 +121,7 @@ SWITCH_SCHEMA = vol.Schema(
|
||||
vol.Required(CONF_ZONE): vol.In(ZONES),
|
||||
vol.Optional(CONF_NAME): cv.string,
|
||||
vol.Optional(CONF_ACTIVATION, default=STATE_HIGH): vol.All(
|
||||
vol.Lower, vol.Any(STATE_HIGH, STATE_LOW)
|
||||
vol.Lower, vol.In([STATE_HIGH, STATE_LOW])
|
||||
),
|
||||
vol.Optional(CONF_MOMENTARY): vol.All(vol.Coerce(int), vol.Range(min=10)),
|
||||
vol.Optional(CONF_PAUSE): vol.All(vol.Coerce(int), vol.Range(min=10)),
|
||||
@ -361,6 +365,8 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
self.new_opt = {CONF_IO: {}}
|
||||
self.active_cfg = None
|
||||
self.io_cfg = {}
|
||||
self.current_states = []
|
||||
self.current_state = 1
|
||||
|
||||
@callback
|
||||
def get_current_cfg(self, io_type, zone):
|
||||
@ -666,12 +672,21 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
if user_input is not None:
|
||||
zone = {"zone": self.active_cfg}
|
||||
zone.update(user_input)
|
||||
del zone[CONF_MORE_STATES]
|
||||
self.new_opt[CONF_SWITCHES] = self.new_opt.get(CONF_SWITCHES, []) + [zone]
|
||||
self.io_cfg.pop(self.active_cfg)
|
||||
self.active_cfg = None
|
||||
|
||||
# iterate through multiple switch states
|
||||
if self.current_states:
|
||||
self.current_states.pop(0)
|
||||
|
||||
# only go to next zone if all states are entered
|
||||
self.current_state += 1
|
||||
if user_input[CONF_MORE_STATES] == CONF_NO:
|
||||
self.io_cfg.pop(self.active_cfg)
|
||||
self.active_cfg = None
|
||||
|
||||
if self.active_cfg:
|
||||
current_cfg = self.get_current_cfg(CONF_SWITCHES, self.active_cfg)
|
||||
current_cfg = next(iter(self.current_states), {})
|
||||
return self.async_show_form(
|
||||
step_id="options_switch",
|
||||
data_schema=vol.Schema(
|
||||
@ -682,7 +697,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
vol.Optional(
|
||||
CONF_ACTIVATION,
|
||||
default=current_cfg.get(CONF_ACTIVATION, STATE_HIGH),
|
||||
): vol.All(vol.Lower, vol.Any(STATE_HIGH, STATE_LOW)),
|
||||
): vol.All(vol.Lower, vol.In([STATE_HIGH, STATE_LOW])),
|
||||
vol.Optional(
|
||||
CONF_MOMENTARY,
|
||||
default=current_cfg.get(CONF_MOMENTARY, vol.UNDEFINED),
|
||||
@ -695,12 +710,19 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
CONF_REPEAT,
|
||||
default=current_cfg.get(CONF_REPEAT, vol.UNDEFINED),
|
||||
): vol.All(vol.Coerce(int), vol.Range(min=-1)),
|
||||
vol.Required(
|
||||
CONF_MORE_STATES,
|
||||
default=CONF_YES
|
||||
if len(self.current_states) > 1
|
||||
else CONF_NO,
|
||||
): vol.In([CONF_YES, CONF_NO]),
|
||||
}
|
||||
),
|
||||
description_placeholders={
|
||||
"zone": f"Zone {self.active_cfg}"
|
||||
if len(self.active_cfg) < 3
|
||||
else self.active_cfg.upper()
|
||||
else self.active_cfg.upper(),
|
||||
"state": str(self.current_state),
|
||||
},
|
||||
errors=errors,
|
||||
)
|
||||
@ -709,7 +731,13 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
for key, value in self.io_cfg.items():
|
||||
if value == CONF_IO_SWI:
|
||||
self.active_cfg = key
|
||||
current_cfg = self.get_current_cfg(CONF_SWITCHES, self.active_cfg)
|
||||
self.current_states = [
|
||||
cfg
|
||||
for cfg in self.current_opt.get(CONF_SWITCHES, [])
|
||||
if cfg[CONF_ZONE] == self.active_cfg
|
||||
]
|
||||
current_cfg = next(iter(self.current_states), {})
|
||||
self.current_state = 1
|
||||
return self.async_show_form(
|
||||
step_id="options_switch",
|
||||
data_schema=vol.Schema(
|
||||
@ -720,7 +748,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
): str,
|
||||
vol.Optional(
|
||||
CONF_ACTIVATION,
|
||||
default=current_cfg.get(CONF_ACTIVATION, "high"),
|
||||
default=current_cfg.get(CONF_ACTIVATION, STATE_HIGH),
|
||||
): vol.In(["low", "high"]),
|
||||
vol.Optional(
|
||||
CONF_MOMENTARY,
|
||||
@ -734,12 +762,19 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
CONF_REPEAT,
|
||||
default=current_cfg.get(CONF_REPEAT, vol.UNDEFINED),
|
||||
): vol.All(vol.Coerce(int), vol.Range(min=-1)),
|
||||
vol.Required(
|
||||
CONF_MORE_STATES,
|
||||
default=CONF_YES
|
||||
if len(self.current_states) > 1
|
||||
else CONF_NO,
|
||||
): vol.In([CONF_YES, CONF_NO]),
|
||||
}
|
||||
),
|
||||
description_placeholders={
|
||||
"zone": f"Zone {self.active_cfg}"
|
||||
if len(self.active_cfg) < 3
|
||||
else self.active_cfg.upper()
|
||||
else self.active_cfg.upper(),
|
||||
"state": str(self.current_state),
|
||||
},
|
||||
errors=errors,
|
||||
)
|
||||
|
@ -80,13 +80,14 @@
|
||||
},
|
||||
"options_switch": {
|
||||
"title": "Configure Switchable Output",
|
||||
"description": "Please select the output options for {zone}",
|
||||
"description": "Please select the output options for {zone}: state {state}",
|
||||
"data": {
|
||||
"name": "Name (optional)",
|
||||
"activation": "Output when on",
|
||||
"momentary": "Pulse duration (ms) (optional)",
|
||||
"pause": "Pause between pulses (ms) (optional)",
|
||||
"repeat": "Times to repeat (-1=infinite) (optional)"
|
||||
"repeat": "Times to repeat (-1=infinite) (optional)",
|
||||
"more_states": "Configure additional states for this zone"
|
||||
}
|
||||
},
|
||||
"options_misc": {
|
||||
|
@ -403,6 +403,14 @@ async def test_import_existing_config(hass, mock_panel):
|
||||
"pause": 100,
|
||||
"repeat": 4,
|
||||
},
|
||||
{
|
||||
"zone": 8,
|
||||
"name": "alarm",
|
||||
"activation": "low",
|
||||
"momentary": 100,
|
||||
"pause": 100,
|
||||
"repeat": -1,
|
||||
},
|
||||
{"zone": "out1"},
|
||||
{"zone": "alarm1"},
|
||||
],
|
||||
@ -463,6 +471,14 @@ async def test_import_existing_config(hass, mock_panel):
|
||||
"pause": 100,
|
||||
"repeat": 4,
|
||||
},
|
||||
{
|
||||
"zone": "8",
|
||||
"name": "alarm",
|
||||
"activation": "low",
|
||||
"momentary": 100,
|
||||
"pause": 100,
|
||||
"repeat": -1,
|
||||
},
|
||||
{"activation": "high", "zone": "out1"},
|
||||
{"activation": "high", "zone": "alarm1"},
|
||||
],
|
||||
@ -713,6 +729,7 @@ async def test_option_flow(hass, mock_panel):
|
||||
assert result["step_id"] == "options_switch"
|
||||
assert result["description_placeholders"] == {
|
||||
"zone": "Zone 4",
|
||||
"state": "1",
|
||||
}
|
||||
|
||||
# zone 4
|
||||
@ -723,6 +740,7 @@ async def test_option_flow(hass, mock_panel):
|
||||
assert result["step_id"] == "options_switch"
|
||||
assert result["description_placeholders"] == {
|
||||
"zone": "OUT",
|
||||
"state": "1",
|
||||
}
|
||||
|
||||
# zone out
|
||||
@ -734,6 +752,27 @@ async def test_option_flow(hass, mock_panel):
|
||||
"momentary": 50,
|
||||
"pause": 100,
|
||||
"repeat": 4,
|
||||
"more_states": "Yes",
|
||||
},
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "options_switch"
|
||||
assert result["description_placeholders"] == {
|
||||
"zone": "OUT",
|
||||
"state": "2",
|
||||
}
|
||||
|
||||
# zone out - state 2
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
"name": "alarm",
|
||||
"activation": "low",
|
||||
"momentary": 100,
|
||||
"pause": 100,
|
||||
"repeat": -1,
|
||||
"more_states": "No",
|
||||
},
|
||||
)
|
||||
|
||||
@ -768,6 +807,14 @@ async def test_option_flow(hass, mock_panel):
|
||||
"pause": 100,
|
||||
"repeat": 4,
|
||||
},
|
||||
{
|
||||
"zone": "out",
|
||||
"name": "alarm",
|
||||
"activation": "low",
|
||||
"momentary": 100,
|
||||
"pause": 100,
|
||||
"repeat": -1,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@ -977,6 +1024,14 @@ async def test_option_flow_import(hass, mock_panel):
|
||||
"pause": 100,
|
||||
"repeat": 4,
|
||||
},
|
||||
{
|
||||
"zone": "3",
|
||||
"name": "alarm",
|
||||
"activation": "low",
|
||||
"momentary": 100,
|
||||
"pause": 100,
|
||||
"repeat": -1,
|
||||
},
|
||||
],
|
||||
}
|
||||
)
|
||||
@ -1056,8 +1111,9 @@ async def test_option_flow_import(hass, mock_panel):
|
||||
assert schema["momentary"] == 50
|
||||
assert schema["pause"] == 100
|
||||
assert schema["repeat"] == 4
|
||||
assert schema["more_states"] == "Yes"
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"], user_input={"activation": "high"}
|
||||
result["flow_id"], user_input={"activation": "high", "more_states": "No"}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "options_misc"
|
||||
|
@ -124,7 +124,7 @@ async def test_config_schema(hass):
|
||||
}
|
||||
}
|
||||
|
||||
# check pin to zone
|
||||
# check pin to zone and multiple output
|
||||
config = {
|
||||
konnected.DOMAIN: {
|
||||
konnected.CONF_ACCESS_TOKEN: "abcdefgh",
|
||||
@ -135,6 +135,22 @@ async def test_config_schema(hass):
|
||||
{"pin": 2, "type": "door"},
|
||||
{"zone": 1, "type": "door"},
|
||||
],
|
||||
"switches": [
|
||||
{
|
||||
"zone": 3,
|
||||
"name": "Beep Beep",
|
||||
"momentary": 65,
|
||||
"pause": 55,
|
||||
"repeat": 4,
|
||||
},
|
||||
{
|
||||
"zone": 3,
|
||||
"name": "Warning",
|
||||
"momentary": 100,
|
||||
"pause": 100,
|
||||
"repeat": -1,
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
@ -153,7 +169,7 @@ async def test_config_schema(hass):
|
||||
"11": "Disabled",
|
||||
"12": "Disabled",
|
||||
"2": "Binary Sensor",
|
||||
"3": "Disabled",
|
||||
"3": "Switchable Output",
|
||||
"4": "Disabled",
|
||||
"5": "Disabled",
|
||||
"6": "Disabled",
|
||||
@ -169,6 +185,24 @@ async def test_config_schema(hass):
|
||||
{"inverse": False, "type": "door", "zone": "2"},
|
||||
{"inverse": False, "type": "door", "zone": "1"},
|
||||
],
|
||||
"switches": [
|
||||
{
|
||||
"zone": "3",
|
||||
"activation": "high",
|
||||
"name": "Beep Beep",
|
||||
"momentary": 65,
|
||||
"pause": 55,
|
||||
"repeat": 4,
|
||||
},
|
||||
{
|
||||
"zone": "3",
|
||||
"activation": "high",
|
||||
"name": "Warning",
|
||||
"momentary": 100,
|
||||
"pause": 100,
|
||||
"repeat": -1,
|
||||
},
|
||||
],
|
||||
},
|
||||
"id": "aabbccddeeff",
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user