Insteon HUB DHCP discovery (#70685)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>pull/70699/head
parent
28ba572d9d
commit
6363c67398
|
@ -7,7 +7,7 @@ from pyinsteon import async_connect
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components import usb
|
from homeassistant.components import dhcp, usb
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_ADDRESS,
|
CONF_ADDRESS,
|
||||||
CONF_DEVICE,
|
CONF_DEVICE,
|
||||||
|
@ -19,6 +19,7 @@ from homeassistant.const import (
|
||||||
)
|
)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
|
from homeassistant.helpers.device_registry import format_mac
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
|
@ -114,6 +115,7 @@ class InsteonFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
|
|
||||||
_device_path: str | None = None
|
_device_path: str | None = None
|
||||||
_device_name: str | None = None
|
_device_name: str | None = None
|
||||||
|
discovered_conf: dict[str, str] = {}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@callback
|
@callback
|
||||||
|
@ -170,7 +172,7 @@ class InsteonFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
return self.async_create_entry(title="", data=user_input)
|
return self.async_create_entry(title="", data=user_input)
|
||||||
user_input.pop(CONF_HUB_VERSION)
|
user_input.pop(CONF_HUB_VERSION)
|
||||||
errors["base"] = "cannot_connect"
|
errors["base"] = "cannot_connect"
|
||||||
schema_defaults = user_input if user_input is not None else {}
|
schema_defaults = user_input if user_input is not None else self.discovered_conf
|
||||||
data_schema = build_hub_schema(hub_version=hub_version, **schema_defaults)
|
data_schema = build_hub_schema(hub_version=hub_version, **schema_defaults)
|
||||||
step_id = STEP_HUB_V2 if hub_version == 2 else STEP_HUB_V1
|
step_id = STEP_HUB_V2 if hub_version == 2 else STEP_HUB_V1
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
|
@ -203,12 +205,14 @@ class InsteonFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
discovery_info.pid,
|
discovery_info.pid,
|
||||||
)
|
)
|
||||||
self._set_confirm_only()
|
self._set_confirm_only()
|
||||||
self.context["title_placeholders"] = {CONF_NAME: self._device_name}
|
self.context["title_placeholders"] = {
|
||||||
|
CONF_NAME: f"Insteon PLM {self._device_name}"
|
||||||
|
}
|
||||||
await self.async_set_unique_id(config_entries.DEFAULT_DISCOVERY_UNIQUE_ID)
|
await self.async_set_unique_id(config_entries.DEFAULT_DISCOVERY_UNIQUE_ID)
|
||||||
return await self.async_step_confirm_usb()
|
return await self.async_step_confirm_usb()
|
||||||
|
|
||||||
async def async_step_confirm_usb(self, user_input=None):
|
async def async_step_confirm_usb(self, user_input=None):
|
||||||
"""Confirm a discovery."""
|
"""Confirm a USB discovery."""
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
return await self.async_step_plm({CONF_DEVICE: self._device_path})
|
return await self.async_step_plm({CONF_DEVICE: self._device_path})
|
||||||
|
|
||||||
|
@ -217,6 +221,15 @@ class InsteonFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
description_placeholders={CONF_NAME: self._device_name},
|
description_placeholders={CONF_NAME: self._device_name},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def async_step_dhcp(self, discovery_info: dhcp.DhcpServiceInfo) -> FlowResult:
|
||||||
|
"""Handle a DHCP discovery."""
|
||||||
|
self.discovered_conf = {CONF_HOST: discovery_info.ip}
|
||||||
|
self.context["title_placeholders"] = {
|
||||||
|
CONF_NAME: f"Insteon Hub {discovery_info.ip}"
|
||||||
|
}
|
||||||
|
await self.async_set_unique_id(format_mac(discovery_info.macaddress))
|
||||||
|
return await self.async_step_user()
|
||||||
|
|
||||||
|
|
||||||
class InsteonOptionsFlowHandler(config_entries.OptionsFlow):
|
class InsteonOptionsFlowHandler(config_entries.OptionsFlow):
|
||||||
"""Handle an Insteon options flow."""
|
"""Handle an Insteon options flow."""
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
"documentation": "https://www.home-assistant.io/integrations/insteon",
|
"documentation": "https://www.home-assistant.io/integrations/insteon",
|
||||||
"requirements": ["pyinsteon==1.0.13"],
|
"requirements": ["pyinsteon==1.0.13"],
|
||||||
"codeowners": ["@teharris1"],
|
"codeowners": ["@teharris1"],
|
||||||
|
"dhcp": [{ "macaddress": "000EF3*" }, { "registered_devices": true }],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["pyinsteon", "pypubsub"],
|
"loggers": ["pyinsteon", "pypubsub"],
|
||||||
|
|
|
@ -43,7 +43,8 @@
|
||||||
},
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
|
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
|
||||||
|
"not_insteon_device": "Discovered device not an Insteon device"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
|
|
|
@ -49,6 +49,8 @@ DHCP: list[dict[str, str | bool]] = [
|
||||||
{'domain': 'hunterdouglas_powerview',
|
{'domain': 'hunterdouglas_powerview',
|
||||||
'hostname': 'hunter*',
|
'hostname': 'hunter*',
|
||||||
'macaddress': '002674*'},
|
'macaddress': '002674*'},
|
||||||
|
{'domain': 'insteon', 'macaddress': '000EF3*'},
|
||||||
|
{'domain': 'insteon', 'registered_devices': True},
|
||||||
{'domain': 'intellifire', 'hostname': 'zentrios-*'},
|
{'domain': 'intellifire', 'hostname': 'zentrios-*'},
|
||||||
{'domain': 'isy994', 'registered_devices': True},
|
{'domain': 'isy994', 'registered_devices': True},
|
||||||
{'domain': 'isy994', 'hostname': 'isy*', 'macaddress': '0021B9*'},
|
{'domain': 'isy994', 'hostname': 'isy*', 'macaddress': '0021B9*'},
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import voluptuous_serialize
|
||||||
|
|
||||||
from homeassistant import config_entries, data_entry_flow
|
from homeassistant import config_entries, data_entry_flow
|
||||||
from homeassistant.components import usb
|
from homeassistant.components import dhcp, usb
|
||||||
from homeassistant.components.insteon.config_flow import (
|
from homeassistant.components.insteon.config_flow import (
|
||||||
HUB1,
|
HUB1,
|
||||||
HUB2,
|
HUB2,
|
||||||
|
@ -37,6 +39,7 @@ from homeassistant.const import (
|
||||||
CONF_USERNAME,
|
CONF_USERNAME,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
MOCK_HOSTNAME,
|
MOCK_HOSTNAME,
|
||||||
|
@ -648,3 +651,48 @@ async def test_discovery_via_usb_already_setup(hass):
|
||||||
|
|
||||||
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||||
assert result["reason"] == "single_instance_allowed"
|
assert result["reason"] == "single_instance_allowed"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_discovery_via_dhcp_hubv1(hass):
|
||||||
|
"""Test usb flow."""
|
||||||
|
await _test_dhcp(hass, HUB1)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_discovery_via_dhcp_hubv2(hass):
|
||||||
|
"""Test usb flow."""
|
||||||
|
await _test_dhcp(hass, HUB2)
|
||||||
|
|
||||||
|
|
||||||
|
async def _test_dhcp(hass, modem_type):
|
||||||
|
"""Test the dhcp discovery for a moddem type."""
|
||||||
|
discovery_info = dhcp.DhcpServiceInfo(
|
||||||
|
ip="11.22.33.44", hostname="", macaddress="00:0e:f3:aa:bb:cc"
|
||||||
|
)
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
"insteon",
|
||||||
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
|
data=discovery_info,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
with patch("homeassistant.components.insteon.config_flow.async_connect"), patch(
|
||||||
|
"homeassistant.components.insteon.async_setup_entry", return_value=True
|
||||||
|
):
|
||||||
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={"modem_type": modem_type}
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
schema = voluptuous_serialize.convert(
|
||||||
|
result2["data_schema"],
|
||||||
|
custom_serializer=cv.custom_serializer,
|
||||||
|
)
|
||||||
|
for field in schema:
|
||||||
|
if field["name"] == "host":
|
||||||
|
assert field.get("default") == "11.22.33.44"
|
||||||
|
break
|
||||||
|
|
Loading…
Reference in New Issue