Skip to content

Commit 5f66298

Browse files
authored
Handle invalid zeroconf messages in Android TV Remote (#128819)
1 parent 87c9c0c commit 5f66298

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

homeassistant/components/androidtv_remote/config_flow.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,18 @@ async def async_step_zeroconf(
151151
if not (mac := discovery_info.properties.get("bt")):
152152
return self.async_abort(reason="cannot_connect")
153153
self.mac = mac
154-
await self.async_set_unique_id(format_mac(self.mac))
154+
existing_config_entry = await self.async_set_unique_id(format_mac(mac))
155+
# Sometimes, devices send an invalid zeroconf message with multiple addresses
156+
# and one of them, which could end up being in discovery_info.host, is from a
157+
# different device. If any of the discovery_info.ip_addresses matches the
158+
# existing host, don't update the host.
159+
if existing_config_entry and len(discovery_info.ip_addresses) > 1:
160+
existing_host = existing_config_entry.data[CONF_HOST]
161+
if existing_host != self.host:
162+
if existing_host in [
163+
str(ip_address) for ip_address in discovery_info.ip_addresses
164+
]:
165+
self.host = existing_host
155166
self._abort_if_unique_id_configured(
156167
updates={CONF_HOST: self.host, CONF_NAME: self.name}
157168
)

tests/components/androidtv_remote/test_config_flow.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,59 @@ async def test_zeroconf_flow_abort_if_mac_is_missing(
757757
assert result["reason"] == "cannot_connect"
758758

759759

760+
async def test_zeroconf_flow_already_configured_zeroconf_has_multiple_invalid_ip_addresses(
761+
hass: HomeAssistant,
762+
mock_setup_entry: AsyncMock,
763+
mock_unload_entry: AsyncMock,
764+
mock_api: MagicMock,
765+
) -> None:
766+
"""Test we abort the zeroconf flow if already configured and zeroconf has invalid ip addresses."""
767+
host = "1.2.3.4"
768+
name = "My Android TV"
769+
mac = "1A:2B:3C:4D:5E:6F"
770+
unique_id = "1a:2b:3c:4d:5e:6f"
771+
name_existing = name
772+
host_existing = host
773+
774+
mock_config_entry = MockConfigEntry(
775+
title=name,
776+
domain=DOMAIN,
777+
data={
778+
"host": host_existing,
779+
"name": name_existing,
780+
"mac": mac,
781+
},
782+
unique_id=unique_id,
783+
state=ConfigEntryState.LOADED,
784+
)
785+
mock_config_entry.add_to_hass(hass)
786+
787+
result = await hass.config_entries.flow.async_init(
788+
DOMAIN,
789+
context={"source": config_entries.SOURCE_ZEROCONF},
790+
data=zeroconf.ZeroconfServiceInfo(
791+
ip_address=ip_address("1.2.3.5"),
792+
ip_addresses=[ip_address("1.2.3.5"), ip_address(host)],
793+
port=6466,
794+
hostname=host,
795+
type="mock_type",
796+
name=name + "._androidtvremote2._tcp.local.",
797+
properties={"bt": mac},
798+
),
799+
)
800+
assert result["type"] is FlowResultType.ABORT
801+
assert result["reason"] == "already_configured"
802+
803+
await hass.async_block_till_done()
804+
assert hass.config_entries.async_entries(DOMAIN)[0].data == {
805+
"host": host,
806+
"name": name,
807+
"mac": mac,
808+
}
809+
assert len(mock_unload_entry.mock_calls) == 0
810+
assert len(mock_setup_entry.mock_calls) == 0
811+
812+
760813
async def test_reauth_flow_success(
761814
hass: HomeAssistant,
762815
mock_setup_entry: AsyncMock,

0 commit comments

Comments
 (0)