Dedup and clarify imported konnected config flows (#32138)

* dedup config flows

* use default (imported) options until user goes thru options flow

* address pr feedback

* correct key used to distinguish pro model
pull/32094/head^2
Kit Klein 2020-02-25 07:55:06 -05:00 committed by GitHub
parent 438c4acf07
commit 5488389244
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 478 additions and 181 deletions

View File

@ -11,9 +11,13 @@
},
"step": {
"confirm": {
"description": "Model: {model}\nHost: {host}\nPort: {port}\n\nYou can configure the IO and panel behavior in the Konnected Alarm Panel settings.",
"description": "Model: {model}\nID: {id}\nHost: {host}\nPort: {port}\n\nYou can configure the IO and panel behavior in the Konnected Alarm Panel settings.",
"title": "Konnected Device Ready"
},
"import_confirm": {
"description": "A Konnected Alarm Panel with ID {id} has been discovered in configuration.yaml. This flow will allow you to import it into a config entry.",
"title": "Import Konnected Device"
},
"user": {
"data": {
"host": "Konnected device IP address",
@ -29,6 +33,7 @@
"abort": {
"not_konn_panel": "Not a recognized Konnected.io device"
},
"error": {},
"step": {
"options_binary": {
"data": {

View File

@ -32,6 +32,7 @@ from homeassistant.helpers import config_validation as cv
from .const import (
CONF_ACTIVATION,
CONF_BLINK,
CONF_DEFAULT_OPTIONS,
CONF_DISCOVERY,
CONF_INVERSE,
CONF_MODEL,
@ -138,7 +139,6 @@ OPTIONS_SCHEMA = vol.Schema(
extra=vol.REMOVE_EXTRA,
)
CONF_DEFAULT_OPTIONS = "default_options"
CONFIG_ENTRY_SCHEMA = vol.Schema(
{
vol.Required(CONF_ID): cv.matches_regex("[0-9a-f]{12}"),
@ -158,6 +158,9 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH
# class variable to store/share discovered host information
discovered_hosts = {}
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
def __init__(self):
@ -178,7 +181,7 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
except (CannotConnect, KeyError):
raise CannotConnect
else:
self.data[CONF_MODEL] = status.get("name", KONN_MODEL)
self.data[CONF_MODEL] = status.get("model", KONN_MODEL)
self.data[CONF_ACCESS_TOKEN] = "".join(
random.choices(f"{string.ascii_uppercase}{string.digits}", k=20)
)
@ -196,6 +199,7 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
# config schema ensures we have port if we have host
if device_config.get(CONF_HOST):
# automatically connect if we have host info
return await self.async_step_user(
user_input={
CONF_HOST: device_config[CONF_HOST],
@ -205,6 +209,28 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
# if we have no host info wait for it or abort if previously configured
self._abort_if_unique_id_configured()
return await self.async_step_import_confirm()
async def async_step_import_confirm(self, user_input=None):
"""Confirm the user wants to import the config entry."""
if user_input is None:
return self.async_show_form(
step_id="import_confirm",
description_placeholders={"id": self.unique_id},
)
# if we have ssdp discovered applicable host info use it
if KonnectedFlowHandler.discovered_hosts.get(self.unique_id):
return await self.async_step_user(
user_input={
CONF_HOST: KonnectedFlowHandler.discovered_hosts[self.unique_id][
CONF_HOST
],
CONF_PORT: KonnectedFlowHandler.discovered_hosts[self.unique_id][
CONF_PORT
],
}
)
return await self.async_step_user()
async def async_step_ssdp(self, discovery_info):
@ -265,7 +291,13 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
errors["base"] = "cannot_connect"
else:
self.data[CONF_ID] = status["mac"].replace(":", "")
self.data[CONF_MODEL] = status.get("name", KONN_MODEL)
self.data[CONF_MODEL] = status.get("model", KONN_MODEL)
# save off our discovered host info
KonnectedFlowHandler.discovered_hosts[self.data[CONF_ID]] = {
CONF_HOST: self.data[CONF_HOST],
CONF_PORT: self.data[CONF_PORT],
}
return await self.async_step_confirm()
return self.async_show_form(
@ -290,23 +322,14 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
the connection.
"""
if user_input is None:
# update an existing config entry if host info changes
entry = await self.async_set_unique_id(
self.data[CONF_ID], raise_on_progress=False
)
if entry and (
entry.data[CONF_HOST] != self.data[CONF_HOST]
or entry.data[CONF_PORT] != self.data[CONF_PORT]
):
entry_data = copy.deepcopy(entry.data)
entry_data.update(self.data)
self.hass.config_entries.async_update_entry(entry, data=entry_data)
self._abort_if_unique_id_configured()
# abort and update an existing config entry if host info changes
await self.async_set_unique_id(self.data[CONF_ID])
self._abort_if_unique_id_configured(updates=self.data)
return self.async_show_form(
step_id="confirm",
description_placeholders={
"model": KONN_PANEL_MODEL_NAMES[self.data[CONF_MODEL]],
"id": self.unique_id,
"host": self.data[CONF_HOST],
"port": self.data[CONF_PORT],
},

View File

@ -4,6 +4,7 @@ DOMAIN = "konnected"
CONF_ACTIVATION = "activation"
CONF_API_HOST = "api_host"
CONF_DEFAULT_OPTIONS = "default_options"
CONF_MOMENTARY = "momentary"
CONF_PAUSE = "pause"
CONF_POLL_INTERVAL = "poll_interval"

View File

@ -28,6 +28,7 @@ from .const import (
CONF_ACTIVATION,
CONF_API_HOST,
CONF_BLINK,
CONF_DEFAULT_OPTIONS,
CONF_DHT_SENSORS,
CONF_DISCOVERY,
CONF_DS18B20_SENSORS,
@ -64,7 +65,9 @@ class AlarmPanel:
self.hass = hass
self.config_entry = config_entry
self.config = config_entry.data
self.options = config_entry.options
self.options = config_entry.options or config_entry.data.get(
CONF_DEFAULT_OPTIONS, {}
)
self.host = self.config.get(CONF_HOST)
self.port = self.config.get(CONF_PORT)
self.client = None

View File

@ -2,6 +2,10 @@
"config": {
"title": "Konnected.io",
"step": {
"import_confirm": {
"title": "Import Konnected Device",
"description": "A Konnected Alarm Panel with ID {id} has been discovered in configuration.yaml. This flow will allow you to import it into a config entry."
},
"user": {
"title": "Discover Konnected Device",
"description": "Please enter the host information for your Konnected Panel.",
@ -12,7 +16,7 @@
},
"confirm": {
"title": "Konnected Device Ready",
"description": "Model: {model}\nHost: {host}\nPort: {port}\n\nYou can configure the IO and panel behavior in the Konnected Alarm Panel settings."
"description": "Model: {model}\nID: {id}\nHost: {host}\nPort: {port}\n\nYou can configure the IO and panel behavior in the Konnected Alarm Panel settings."
}
},
"error": {

View File

@ -34,7 +34,7 @@ async def test_flow_works(hass, mock_panel):
mock_panel.get_status.return_value = {
"mac": "11:22:33:44:55:66",
"name": "Konnected",
"model": "Konnected",
}
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={"port": 1234, "host": "1.2.3.4"}
@ -43,6 +43,7 @@ async def test_flow_works(hass, mock_panel):
assert result["step_id"] == "confirm"
assert result["description_placeholders"] == {
"model": "Konnected Alarm Panel",
"id": "112233445566",
"host": "1.2.3.4",
"port": 1234,
}
@ -70,7 +71,7 @@ async def test_pro_flow_works(hass, mock_panel):
mock_panel.get_status.return_value = {
"mac": "11:22:33:44:55:66",
"name": "Konnected Pro",
"model": "Konnected Pro",
}
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={"port": 1234, "host": "1.2.3.4"}
@ -79,6 +80,7 @@ async def test_pro_flow_works(hass, mock_panel):
assert result["step_id"] == "confirm"
assert result["description_placeholders"] == {
"model": "Konnected Alarm Panel Pro",
"id": "112233445566",
"host": "1.2.3.4",
"port": 1234,
}
@ -100,7 +102,7 @@ async def test_ssdp(hass, mock_panel):
"""Test a panel being discovered."""
mock_panel.get_status.return_value = {
"mac": "11:22:33:44:55:66",
"name": "Konnected",
"model": "Konnected",
}
result = await hass.config_entries.flow.async_init(
@ -117,6 +119,7 @@ async def test_ssdp(hass, mock_panel):
assert result["step_id"] == "confirm"
assert result["description_placeholders"] == {
"model": "Konnected Alarm Panel",
"id": "112233445566",
"host": "1.2.3.4",
"port": 1234,
}
@ -125,8 +128,8 @@ async def test_ssdp(hass, mock_panel):
async def test_import_no_host_user_finish(hass, mock_panel):
"""Test importing a panel with no host info."""
mock_panel.get_status.return_value = {
"mac": "11:22:33:44:55:66",
"name": "Konnected Pro",
"mac": "aa:bb:cc:dd:ee:ff",
"model": "Konnected Pro",
}
result = await hass.config_entries.flow.async_init(
@ -159,6 +162,13 @@ async def test_import_no_host_user_finish(hass, mock_panel):
},
)
assert result["type"] == "form"
assert result["step_id"] == "import_confirm"
assert result["description_placeholders"]["id"] == "aabbccddeeff"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
assert result["type"] == "form"
assert result["step_id"] == "user"
# confirm user is prompted to enter host
@ -169,6 +179,7 @@ async def test_import_no_host_user_finish(hass, mock_panel):
assert result["step_id"] == "confirm"
assert result["description_placeholders"] == {
"model": "Konnected Alarm Panel Pro",
"id": "aabbccddeeff",
"host": "1.1.1.1",
"port": 1234,
}
@ -180,6 +191,78 @@ async def test_import_no_host_user_finish(hass, mock_panel):
assert result["type"] == "create_entry"
async def test_import_ssdp_host_user_finish(hass, mock_panel):
"""Test importing a panel with no host info which ssdp discovers."""
mock_panel.get_status.return_value = {
"mac": "11:22:33:44:55:66",
"model": "Konnected Pro",
}
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
context={"source": "import"},
data={
"default_options": {
"blink": True,
"discovery": True,
"io": {
"1": "Disabled",
"10": "Disabled",
"11": "Disabled",
"12": "Disabled",
"2": "Disabled",
"3": "Disabled",
"4": "Disabled",
"5": "Disabled",
"6": "Disabled",
"7": "Disabled",
"8": "Disabled",
"9": "Disabled",
"alarm1": "Disabled",
"alarm2_out2": "Disabled",
"out": "Disabled",
"out1": "Disabled",
},
},
"id": "112233445566",
},
)
assert result["type"] == "form"
assert result["step_id"] == "import_confirm"
assert result["description_placeholders"]["id"] == "112233445566"
# discover the panel via ssdp
ssdp_result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
context={"source": "ssdp"},
data={
"ssdp_location": "http://0.0.0.0:1234/Device.xml",
"manufacturer": config_flow.KONN_MANUFACTURER,
"modelName": config_flow.KONN_MODEL_PRO,
},
)
assert ssdp_result["type"] == "abort"
assert ssdp_result["reason"] == "already_in_progress"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
assert result["type"] == "form"
assert result["step_id"] == "confirm"
assert result["description_placeholders"] == {
"model": "Konnected Alarm Panel Pro",
"id": "112233445566",
"host": "0.0.0.0",
"port": 1234,
}
# final confirmation
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
assert result["type"] == "create_entry"
async def test_ssdp_already_configured(hass, mock_panel):
"""Test if a discovered panel has already been configured."""
MockConfigEntry(
@ -189,7 +272,7 @@ async def test_ssdp_already_configured(hass, mock_panel):
).add_to_hass(hass)
mock_panel.get_status.return_value = {
"mac": "11:22:33:44:55:66",
"name": "Konnected Pro",
"model": "Konnected Pro",
}
result = await hass.config_entries.flow.async_init(
@ -265,7 +348,7 @@ async def test_ssdp_host_update(hass, mock_panel):
).add_to_hass(hass)
mock_panel.get_status.return_value = {
"mac": "11:22:33:44:55:66",
"name": "Konnected Pro",
"model": "Konnected Pro",
}
result = await hass.config_entries.flow.async_init(
@ -289,7 +372,7 @@ async def test_import_existing_config(hass, mock_panel):
"""Test importing a host with an existing config file."""
mock_panel.get_status.return_value = {
"mac": "11:22:33:44:55:66",
"name": "Konnected Pro",
"model": "Konnected Pro",
}
result = await hass.config_entries.flow.async_init(
@ -402,7 +485,7 @@ async def test_import_existing_config_entry(hass, mock_panel):
mock_panel.get_status.return_value = {
"mac": "11:22:33:44:55:66",
"name": "Konnected Pro",
"model": "Konnected Pro",
}
# utilize a global access token this time
@ -462,7 +545,7 @@ async def test_import_pin_config(hass, mock_panel):
"""Test importing a host with an existing config file that specifies pin configs."""
mock_panel.get_status.return_value = {
"mac": "11:22:33:44:55:66",
"name": "Konnected Pro",
"model": "Konnected Pro",
}
result = await hass.config_entries.flow.async_init(

View File

@ -3,6 +3,7 @@ from asynctest import patch
import pytest
from homeassistant.components.konnected import config_flow, panel
from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry
@ -92,9 +93,6 @@ async def test_create_and_setup(hass, mock_panel):
options=device_options,
)
entry.add_to_hass(hass)
hass.data[panel.DOMAIN] = {
panel.CONF_API_HOST: "192.168.1.1",
}
# override get_status to reflect non-pro board
mock_panel.get_status.return_value = {
@ -111,19 +109,35 @@ async def test_create_and_setup(hass, mock_panel):
"mac": "11:22:33:44:55:66",
"settings": {},
}
device = panel.AlarmPanel(hass, entry)
await device.async_save_data()
await device.async_connect()
# setup the integration and inspect panel behavior
assert (
await async_setup_component(
hass,
panel.DOMAIN,
{
panel.DOMAIN: {
panel.CONF_ACCESS_TOKEN: "arandomstringvalue",
panel.CONF_API_HOST: "http://192.168.1.1:8123",
}
},
)
is True
)
# confirm panel instance was created and configured
# hass.data is the only mechanism to get a reference to the created panel instance
device = hass.data[panel.DOMAIN][panel.CONF_DEVICES]["112233445566"]["panel"]
await device.update_switch("1", 0)
# confirm the correct api is used
# pylint: disable=no-member
assert device.client.put_device.call_count == 1
assert device.client.put_zone.call_count == 0
assert mock_panel.put_device.call_count == 1
assert mock_panel.put_zone.call_count == 0
# confirm the settings are sent to the panel
# pylint: disable=no-member
assert device.client.put_settings.call_args_list[0][1] == {
assert mock_panel.put_settings.call_args_list[0][1] == {
"sensors": [{"pin": "1"}, {"pin": "2"}, {"pin": "5"}],
"actuators": [{"trigger": 0, "pin": "8"}, {"trigger": 1, "pin": "9"}],
"dht_sensors": [{"poll_interval": 3, "pin": "6"}],
@ -131,67 +145,60 @@ async def test_create_and_setup(hass, mock_panel):
"auth_token": "11223344556677889900",
"blink": True,
"discovery": True,
"endpoint": "192.168.1.1/api/konnected",
"endpoint": "http://192.168.1.1:8123/api/konnected",
}
# confirm the device settings are saved in hass.data
assert hass.data[panel.DOMAIN][panel.CONF_DEVICES] == {
"112233445566": {
"binary_sensors": {
"1": {
"inverse": False,
"name": "Konnected 445566 Zone 1",
"state": None,
"type": "door",
},
"2": {
"inverse": True,
"name": "winder",
"state": None,
"type": "window",
},
"3": {
"inverse": False,
"name": "Konnected 445566 Zone 3",
"state": None,
"type": "door",
},
assert device.stored_configuration == {
"binary_sensors": {
"1": {
"inverse": False,
"name": "Konnected 445566 Zone 1",
"state": None,
"type": "door",
},
"blink": True,
"panel": device,
"discovery": True,
"host": "1.2.3.4",
"port": 1234,
"sensors": [
{
"name": "Konnected 445566 Sensor 4",
"poll_interval": 3,
"type": "dht",
"zone": "4",
},
{"name": "temper", "poll_interval": 3, "type": "ds18b20", "zone": "5"},
],
"switches": [
{
"activation": "low",
"momentary": 50,
"name": "switcher",
"pause": 100,
"repeat": 4,
"state": None,
"zone": "out",
},
{
"activation": "high",
"momentary": None,
"name": "Konnected 445566 Actuator 6",
"pause": None,
"repeat": None,
"state": None,
"zone": "6",
},
],
}
"2": {"inverse": True, "name": "winder", "state": None, "type": "window"},
"3": {
"inverse": False,
"name": "Konnected 445566 Zone 3",
"state": None,
"type": "door",
},
},
"blink": True,
"panel": device,
"discovery": True,
"host": "1.2.3.4",
"port": 1234,
"sensors": [
{
"name": "Konnected 445566 Sensor 4",
"poll_interval": 3,
"type": "dht",
"zone": "4",
},
{"name": "temper", "poll_interval": 3, "type": "ds18b20", "zone": "5"},
],
"switches": [
{
"activation": "low",
"momentary": 50,
"name": "switcher",
"pause": 100,
"repeat": 4,
"state": None,
"zone": "out",
},
{
"activation": "high",
"momentary": None,
"name": "Konnected 445566 Actuator 6",
"pause": None,
"repeat": None,
"state": None,
"zone": "6",
},
],
}
@ -255,23 +262,35 @@ async def test_create_and_setup_pro(hass, mock_panel):
options=device_options,
)
entry.add_to_hass(hass)
hass.data[panel.DOMAIN] = {
panel.CONF_API_HOST: "192.168.1.1",
}
device = panel.AlarmPanel(hass, entry)
await device.async_save_data()
await device.async_connect()
# setup the integration and inspect panel behavior
assert (
await async_setup_component(
hass,
panel.DOMAIN,
{
panel.DOMAIN: {
panel.CONF_ACCESS_TOKEN: "arandomstringvalue",
panel.CONF_API_HOST: "http://192.168.1.1:8123",
}
},
)
is True
)
# confirm panel instance was created and configured
# hass.data is the only mechanism to get a reference to the created panel instance
device = hass.data[panel.DOMAIN][panel.CONF_DEVICES]["112233445566"]["panel"]
await device.update_switch("2", 1)
# confirm the correct api is used
# pylint: disable=no-member
assert device.client.put_device.call_count == 0
assert device.client.put_zone.call_count == 1
assert mock_panel.put_device.call_count == 0
assert mock_panel.put_zone.call_count == 1
# confirm the settings are sent to the panel
# pylint: disable=no-member
assert device.client.put_settings.call_args_list[0][1] == {
assert mock_panel.put_settings.call_args_list[0][1] == {
"sensors": [{"zone": "2"}, {"zone": "6"}, {"zone": "10"}],
"actuators": [
{"trigger": 1, "zone": "4"},
@ -287,89 +306,248 @@ async def test_create_and_setup_pro(hass, mock_panel):
"auth_token": "11223344556677889900",
"blink": True,
"discovery": True,
"endpoint": "192.168.1.1/api/konnected",
"endpoint": "http://192.168.1.1:8123/api/konnected",
}
# confirm the device settings are saved in hass.data
assert hass.data[panel.DOMAIN][panel.CONF_DEVICES] == {
"112233445566": {
"binary_sensors": {
"10": {
"inverse": False,
"name": "Konnected 445566 Zone 10",
"state": None,
"type": "door",
},
"2": {
"inverse": False,
"name": "Konnected 445566 Zone 2",
"state": None,
"type": "door",
},
"6": {
"inverse": True,
"name": "winder",
"state": None,
"type": "window",
},
assert device.stored_configuration == {
"binary_sensors": {
"10": {
"inverse": False,
"name": "Konnected 445566 Zone 10",
"state": None,
"type": "door",
},
"blink": True,
"panel": device,
"discovery": True,
"2": {
"inverse": False,
"name": "Konnected 445566 Zone 2",
"state": None,
"type": "door",
},
"6": {"inverse": True, "name": "winder", "state": None, "type": "window"},
},
"blink": True,
"panel": device,
"discovery": True,
"host": "1.2.3.4",
"port": 1234,
"sensors": [
{
"name": "Konnected 445566 Sensor 3",
"poll_interval": 3,
"type": "dht",
"zone": "3",
},
{"name": "temper", "poll_interval": 3, "type": "ds18b20", "zone": "7"},
{
"name": "Konnected 445566 Sensor 11",
"poll_interval": 5,
"type": "dht",
"zone": "11",
},
],
"switches": [
{
"activation": "high",
"momentary": None,
"name": "Konnected 445566 Actuator 4",
"pause": None,
"repeat": None,
"state": None,
"zone": "4",
},
{
"activation": "low",
"momentary": 50,
"name": "switcher",
"pause": 100,
"repeat": 4,
"state": None,
"zone": "8",
},
{
"activation": "high",
"momentary": None,
"name": "Konnected 445566 Actuator out1",
"pause": None,
"repeat": None,
"state": None,
"zone": "out1",
},
{
"activation": "high",
"momentary": None,
"name": "Konnected 445566 Actuator alarm1",
"pause": None,
"repeat": None,
"state": None,
"zone": "alarm1",
},
],
}
async def test_default_options(hass, mock_panel):
"""Test that we create a Konnected Panel and save the data."""
device_config = config_flow.CONFIG_ENTRY_SCHEMA(
{
"host": "1.2.3.4",
"port": 1234,
"sensors": [
"id": "112233445566",
"model": "Konnected Pro",
"access_token": "11223344556677889900",
"default_options": config_flow.OPTIONS_SCHEMA(
{
"name": "Konnected 445566 Sensor 3",
"poll_interval": 3,
"type": "dht",
"zone": "3",
},
{"name": "temper", "poll_interval": 3, "type": "ds18b20", "zone": "7"},
{
"name": "Konnected 445566 Sensor 11",
"poll_interval": 5,
"type": "dht",
"zone": "11",
},
],
"switches": [
{
"activation": "high",
"momentary": None,
"name": "Konnected 445566 Actuator 4",
"pause": None,
"repeat": None,
"state": None,
"zone": "4",
},
{
"activation": "low",
"momentary": 50,
"name": "switcher",
"pause": 100,
"repeat": 4,
"state": None,
"zone": "8",
},
{
"activation": "high",
"momentary": None,
"name": "Konnected 445566 Actuator out1",
"pause": None,
"repeat": None,
"state": None,
"zone": "out1",
},
{
"activation": "high",
"momentary": None,
"name": "Konnected 445566 Actuator alarm1",
"pause": None,
"repeat": None,
"state": None,
"zone": "alarm1",
},
],
"io": {
"1": "Binary Sensor",
"2": "Binary Sensor",
"3": "Binary Sensor",
"4": "Digital Sensor",
"5": "Digital Sensor",
"6": "Switchable Output",
"out": "Switchable Output",
},
"binary_sensors": [
{"zone": "1", "type": "door"},
{
"zone": "2",
"type": "window",
"name": "winder",
"inverse": True,
},
{"zone": "3", "type": "door"},
],
"sensors": [
{"zone": "4", "type": "dht"},
{"zone": "5", "type": "ds18b20", "name": "temper"},
],
"switches": [
{
"zone": "out",
"name": "switcher",
"activation": "low",
"momentary": 50,
"pause": 100,
"repeat": 4,
},
{"zone": "6"},
],
}
),
}
)
entry = MockConfigEntry(
domain="konnected",
title="Konnected Alarm Panel",
data=device_config,
options={},
)
entry.add_to_hass(hass)
# override get_status to reflect non-pro board
mock_panel.get_status.return_value = {
"hwVersion": "2.3.0",
"swVersion": "2.3.1",
"heap": 10000,
"uptime": 12222,
"ip": "192.168.1.90",
"port": 9123,
"sensors": [],
"actuators": [],
"dht_sensors": [],
"ds18b20_sensors": [],
"mac": "11:22:33:44:55:66",
"settings": {},
}
# setup the integration and inspect panel behavior
assert (
await async_setup_component(
hass,
panel.DOMAIN,
{
panel.DOMAIN: {
panel.CONF_ACCESS_TOKEN: "arandomstringvalue",
panel.CONF_API_HOST: "http://192.168.1.1:8123",
}
},
)
is True
)
# confirm panel instance was created and configured.
# hass.data is the only mechanism to get a reference to the created panel instance
device = hass.data[panel.DOMAIN][panel.CONF_DEVICES]["112233445566"]["panel"]
await device.update_switch("1", 0)
# confirm the correct api is used
# pylint: disable=no-member
assert mock_panel.put_device.call_count == 1
assert mock_panel.put_zone.call_count == 0
# confirm the settings are sent to the panel
# pylint: disable=no-member
assert mock_panel.put_settings.call_args_list[0][1] == {
"sensors": [{"pin": "1"}, {"pin": "2"}, {"pin": "5"}],
"actuators": [{"trigger": 0, "pin": "8"}, {"trigger": 1, "pin": "9"}],
"dht_sensors": [{"poll_interval": 3, "pin": "6"}],
"ds18b20_sensors": [{"pin": "7"}],
"auth_token": "11223344556677889900",
"blink": True,
"discovery": True,
"endpoint": "http://192.168.1.1:8123/api/konnected",
}
# confirm the device settings are saved in hass.data
assert device.stored_configuration == {
"binary_sensors": {
"1": {
"inverse": False,
"name": "Konnected 445566 Zone 1",
"state": None,
"type": "door",
},
"2": {"inverse": True, "name": "winder", "state": None, "type": "window"},
"3": {
"inverse": False,
"name": "Konnected 445566 Zone 3",
"state": None,
"type": "door",
},
},
"blink": True,
"panel": device,
"discovery": True,
"host": "1.2.3.4",
"port": 1234,
"sensors": [
{
"name": "Konnected 445566 Sensor 4",
"poll_interval": 3,
"type": "dht",
"zone": "4",
},
{"name": "temper", "poll_interval": 3, "type": "ds18b20", "zone": "5"},
],
"switches": [
{
"activation": "low",
"momentary": 50,
"name": "switcher",
"pause": 100,
"repeat": 4,
"state": None,
"zone": "out",
},
{
"activation": "high",
"momentary": None,
"name": "Konnected 445566 Actuator 6",
"pause": None,
"repeat": None,
"state": None,
"zone": "6",
},
],
}