Add zeroconf support to roomba (#93309)
parent
40c74ad5b7
commit
ab0d35df92
|
@ -10,7 +10,7 @@ from roombapy.getpassword import RoombaPassword
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries, core
|
||||
from homeassistant.components import dhcp
|
||||
from homeassistant.components import dhcp, zeroconf
|
||||
from homeassistant.const import CONF_DELAY, CONF_HOST, CONF_NAME, CONF_PASSWORD
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
|
@ -85,17 +85,31 @@ class RoombaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
"""Get the options flow for this handler."""
|
||||
return OptionsFlowHandler(config_entry)
|
||||
|
||||
async def async_step_zeroconf(
|
||||
self, discovery_info: zeroconf.ZeroconfServiceInfo
|
||||
) -> FlowResult:
|
||||
"""Handle zeroconf discovery."""
|
||||
return await self._async_step_discovery(
|
||||
discovery_info.host, discovery_info.hostname.lower().rstrip(".local.")
|
||||
)
|
||||
|
||||
async def async_step_dhcp(self, discovery_info: dhcp.DhcpServiceInfo) -> FlowResult:
|
||||
"""Handle dhcp discovery."""
|
||||
self._async_abort_entries_match({CONF_HOST: discovery_info.ip})
|
||||
return await self._async_step_discovery(
|
||||
discovery_info.ip, discovery_info.hostname
|
||||
)
|
||||
|
||||
if not discovery_info.hostname.startswith(("irobot-", "roomba-")):
|
||||
async def _async_step_discovery(self, ip_address: str, hostname: str) -> FlowResult:
|
||||
"""Handle any discovery."""
|
||||
self._async_abort_entries_match({CONF_HOST: ip_address})
|
||||
|
||||
if not hostname.startswith(("irobot-", "roomba-")):
|
||||
return self.async_abort(reason="not_irobot_device")
|
||||
|
||||
self.host = discovery_info.ip
|
||||
self.blid = _async_blid_from_hostname(discovery_info.hostname)
|
||||
self.host = ip_address
|
||||
self.blid = _async_blid_from_hostname(hostname)
|
||||
await self.async_set_unique_id(self.blid)
|
||||
self._abort_if_unique_id_configured(updates={CONF_HOST: self.host})
|
||||
self._abort_if_unique_id_configured(updates={CONF_HOST: ip_address})
|
||||
|
||||
# Because the hostname is so long some sources may
|
||||
# truncate the hostname since it will be longer than
|
||||
|
@ -103,7 +117,7 @@ class RoombaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
# going for a longer hostname we abort so the user
|
||||
# does not see two flows if discovery fails.
|
||||
for progress in self._async_in_progress():
|
||||
flow_unique_id = progress["context"]["unique_id"]
|
||||
flow_unique_id: str = progress["context"]["unique_id"]
|
||||
if flow_unique_id.startswith(self.blid):
|
||||
return self.async_abort(reason="short_blid")
|
||||
if self.blid.startswith(flow_unique_id):
|
||||
|
|
|
@ -24,5 +24,15 @@
|
|||
"documentation": "https://www.home-assistant.io/integrations/roomba",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["paho_mqtt", "roombapy"],
|
||||
"requirements": ["roombapy==1.6.8"]
|
||||
"requirements": ["roombapy==1.6.8"],
|
||||
"zeroconf": [
|
||||
{
|
||||
"type": "_amzn-alexa._tcp.local.",
|
||||
"name": "irobot-*"
|
||||
},
|
||||
{
|
||||
"type": "_amzn-alexa._tcp.local.",
|
||||
"name": "roomba-*"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -279,6 +279,16 @@ ZEROCONF = {
|
|||
"domain": "apple_tv",
|
||||
},
|
||||
],
|
||||
"_amzn-alexa._tcp.local.": [
|
||||
{
|
||||
"domain": "roomba",
|
||||
"name": "irobot-*",
|
||||
},
|
||||
{
|
||||
"domain": "roomba",
|
||||
"name": "roomba-*",
|
||||
},
|
||||
],
|
||||
"_androidtvremote2._tcp.local.": [
|
||||
{
|
||||
"domain": "androidtv_remote",
|
||||
|
|
|
@ -5,7 +5,7 @@ import pytest
|
|||
from roombapy import RoombaConnectionError, RoombaInfo
|
||||
|
||||
from homeassistant import config_entries, data_entry_flow
|
||||
from homeassistant.components import dhcp
|
||||
from homeassistant.components import dhcp, zeroconf
|
||||
from homeassistant.components.roomba import config_flow
|
||||
from homeassistant.components.roomba.const import CONF_BLID, CONF_CONTINUOUS, DOMAIN
|
||||
from homeassistant.const import CONF_DELAY, CONF_HOST, CONF_PASSWORD
|
||||
|
@ -16,16 +16,46 @@ from tests.common import MockConfigEntry
|
|||
MOCK_IP = "1.2.3.4"
|
||||
VALID_CONFIG = {CONF_HOST: MOCK_IP, CONF_BLID: "BLID", CONF_PASSWORD: "password"}
|
||||
|
||||
DHCP_DISCOVERY_DEVICES = [
|
||||
dhcp.DhcpServiceInfo(
|
||||
ip=MOCK_IP,
|
||||
macaddress="50:14:79:DD:EE:FF",
|
||||
hostname="irobot-blid",
|
||||
DISCOVERY_DEVICES = [
|
||||
(
|
||||
config_entries.SOURCE_DHCP,
|
||||
dhcp.DhcpServiceInfo(
|
||||
ip=MOCK_IP,
|
||||
macaddress="50:14:79:DD:EE:FF",
|
||||
hostname="irobot-blid",
|
||||
),
|
||||
),
|
||||
dhcp.DhcpServiceInfo(
|
||||
ip=MOCK_IP,
|
||||
macaddress="80:A5:89:DD:EE:FF",
|
||||
hostname="roomba-blid",
|
||||
(
|
||||
config_entries.SOURCE_DHCP,
|
||||
dhcp.DhcpServiceInfo(
|
||||
ip=MOCK_IP,
|
||||
macaddress="80:A5:89:DD:EE:FF",
|
||||
hostname="roomba-blid",
|
||||
),
|
||||
),
|
||||
(
|
||||
config_entries.SOURCE_ZEROCONF,
|
||||
zeroconf.ZeroconfServiceInfo(
|
||||
host=MOCK_IP,
|
||||
hostname="irobot-blid.local.",
|
||||
name="irobot-blid._amzn-alexa._tcp.local.",
|
||||
type="_amzn-alexa._tcp.local.",
|
||||
port=443,
|
||||
properties={},
|
||||
addresses=[MOCK_IP],
|
||||
),
|
||||
),
|
||||
(
|
||||
config_entries.SOURCE_ZEROCONF,
|
||||
zeroconf.ZeroconfServiceInfo(
|
||||
host=MOCK_IP,
|
||||
hostname="roomba-blid.local.",
|
||||
name="roomba-blid._amzn-alexa._tcp.local.",
|
||||
type="_amzn-alexa._tcp.local.",
|
||||
port=443,
|
||||
properties={},
|
||||
addresses=[MOCK_IP],
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
|
@ -625,9 +655,10 @@ async def test_form_user_discovery_and_password_fetch_gets_connection_refused(
|
|||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize("discovery_data", DHCP_DISCOVERY_DEVICES)
|
||||
@pytest.mark.parametrize("discovery_data", DISCOVERY_DEVICES)
|
||||
async def test_dhcp_discovery_and_roomba_discovery_finds(
|
||||
hass: HomeAssistant, discovery_data
|
||||
hass: HomeAssistant,
|
||||
discovery_data: tuple[str, dhcp.DhcpServiceInfo | zeroconf.ZeroconfServiceInfo],
|
||||
) -> None:
|
||||
"""Test we can process the discovery from dhcp and roomba discovery matches the device."""
|
||||
|
||||
|
@ -635,14 +666,15 @@ async def test_dhcp_discovery_and_roomba_discovery_finds(
|
|||
roomba_connected=True,
|
||||
master_state={"state": {"reported": {"name": "myroomba"}}},
|
||||
)
|
||||
source, discovery = discovery_data
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.roomba.config_flow.RoombaDiscovery", _mocked_discovery
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
data=discovery_data,
|
||||
context={"source": source},
|
||||
data=discovery,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
|
Loading…
Reference in New Issue