mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 14:17:45 +00:00
Reinitialize dhcp discovery flow on config entry removal (#126556)
* Reinitialize dhcp discovery flow on unignore * Tweak * Rediscover on any removed config entry * Adjust log message
This commit is contained in:
parent
b6fe3a3022
commit
972dc89c0f
@ -51,6 +51,7 @@ from homeassistant.helpers import (
|
|||||||
discovery_flow,
|
discovery_flow,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, format_mac
|
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, format_mac
|
||||||
|
from homeassistant.helpers.discovery_flow import DiscoveryKey
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.event import (
|
from homeassistant.helpers.event import (
|
||||||
async_track_state_added_domain,
|
async_track_state_added_domain,
|
||||||
@ -155,6 +156,12 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
await dhcp_watcher.async_start()
|
await dhcp_watcher.async_start()
|
||||||
watchers.append(dhcp_watcher)
|
watchers.append(dhcp_watcher)
|
||||||
|
|
||||||
|
rediscovery_watcher = RediscoveryWatcher(
|
||||||
|
hass, address_data, integration_matchers
|
||||||
|
)
|
||||||
|
rediscovery_watcher.async_start()
|
||||||
|
watchers.append(rediscovery_watcher)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_stop(event: Event) -> None:
|
def _async_stop(event: Event) -> None:
|
||||||
for watcher in watchers:
|
for watcher in watchers:
|
||||||
@ -192,7 +199,11 @@ class WatcherBase:
|
|||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_process_client(
|
def async_process_client(
|
||||||
self, ip_address: str, hostname: str, unformatted_mac_address: str
|
self,
|
||||||
|
ip_address: str,
|
||||||
|
hostname: str,
|
||||||
|
unformatted_mac_address: str,
|
||||||
|
force: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Process a client."""
|
"""Process a client."""
|
||||||
if (made_ip_address := cached_ip_addresses(ip_address)) is None:
|
if (made_ip_address := cached_ip_addresses(ip_address)) is None:
|
||||||
@ -217,7 +228,8 @@ class WatcherBase:
|
|||||||
|
|
||||||
data = self._address_data.get(mac_address)
|
data = self._address_data.get(mac_address)
|
||||||
if (
|
if (
|
||||||
data
|
not force
|
||||||
|
and data
|
||||||
and data[IP_ADDRESS] == compressed_ip_address
|
and data[IP_ADDRESS] == compressed_ip_address
|
||||||
and data[HOSTNAME].startswith(hostname)
|
and data[HOSTNAME].startswith(hostname)
|
||||||
):
|
):
|
||||||
@ -271,6 +283,14 @@ class WatcherBase:
|
|||||||
_LOGGER.debug("Matched %s against %s", data, matcher)
|
_LOGGER.debug("Matched %s against %s", data, matcher)
|
||||||
matched_domains.add(domain)
|
matched_domains.add(domain)
|
||||||
|
|
||||||
|
if not matched_domains:
|
||||||
|
return # avoid creating DiscoveryKey if there are no matches
|
||||||
|
|
||||||
|
discovery_key = DiscoveryKey(
|
||||||
|
domain=DOMAIN,
|
||||||
|
key=mac_address,
|
||||||
|
version=1,
|
||||||
|
)
|
||||||
for domain in matched_domains:
|
for domain in matched_domains:
|
||||||
discovery_flow.async_create_flow(
|
discovery_flow.async_create_flow(
|
||||||
self.hass,
|
self.hass,
|
||||||
@ -281,6 +301,7 @@ class WatcherBase:
|
|||||||
hostname=lowercase_hostname,
|
hostname=lowercase_hostname,
|
||||||
macaddress=mac_address,
|
macaddress=mac_address,
|
||||||
),
|
),
|
||||||
|
discovery_key=discovery_key,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -414,6 +435,38 @@ class DHCPWatcher(WatcherBase):
|
|||||||
self._unsub = await aiodhcpwatcher.async_start(self._async_process_dhcp_request)
|
self._unsub = await aiodhcpwatcher.async_start(self._async_process_dhcp_request)
|
||||||
|
|
||||||
|
|
||||||
|
class RediscoveryWatcher(WatcherBase):
|
||||||
|
"""Class to trigger rediscovery on config entry removal."""
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _handle_config_entry_removed(
|
||||||
|
self,
|
||||||
|
entry: config_entries.ConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Handle config entry changes."""
|
||||||
|
for discovery_key in entry.discovery_keys[DOMAIN]:
|
||||||
|
if discovery_key.version != 1 or not isinstance(discovery_key.key, str):
|
||||||
|
continue
|
||||||
|
mac_address = discovery_key.key
|
||||||
|
_LOGGER.debug("Rediscover service %s", mac_address)
|
||||||
|
if data := self._address_data.get(mac_address):
|
||||||
|
self.async_process_client(
|
||||||
|
data[IP_ADDRESS],
|
||||||
|
data[HOSTNAME],
|
||||||
|
mac_address,
|
||||||
|
True, # Force rediscovery
|
||||||
|
)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_start(self) -> None:
|
||||||
|
"""Start watching for config entry removals."""
|
||||||
|
self._unsub = async_dispatcher_connect(
|
||||||
|
self.hass,
|
||||||
|
config_entries.signal_discovered_config_entry_removed(DOMAIN),
|
||||||
|
self._handle_config_entry_removed,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=4096, typed=True)
|
@lru_cache(maxsize=4096, typed=True)
|
||||||
def _compile_fnmatch(pattern: str) -> re.Pattern:
|
def _compile_fnmatch(pattern: str) -> re.Pattern:
|
||||||
"""Compile a fnmatch pattern."""
|
"""Compile a fnmatch pattern."""
|
||||||
|
@ -35,11 +35,17 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
import homeassistant.helpers.device_registry as dr
|
import homeassistant.helpers.device_registry as dr
|
||||||
|
from homeassistant.helpers.discovery_flow import DiscoveryKey
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
from tests.common import (
|
||||||
|
MockConfigEntry,
|
||||||
|
MockModule,
|
||||||
|
async_fire_time_changed,
|
||||||
|
mock_integration,
|
||||||
|
)
|
||||||
|
|
||||||
# connect b8:b7:f1:6d:b5:33 192.168.210.56
|
# connect b8:b7:f1:6d:b5:33 192.168.210.56
|
||||||
RAW_DHCP_REQUEST = (
|
RAW_DHCP_REQUEST = (
|
||||||
@ -138,11 +144,15 @@ RAW_DHCP_REQUEST_WITHOUT_HOSTNAME = (
|
|||||||
|
|
||||||
|
|
||||||
async def _async_get_handle_dhcp_packet(
|
async def _async_get_handle_dhcp_packet(
|
||||||
hass: HomeAssistant, integration_matchers: dhcp.DhcpMatchers
|
hass: HomeAssistant,
|
||||||
|
integration_matchers: dhcp.DhcpMatchers,
|
||||||
|
address_data: dict | None = None,
|
||||||
) -> Callable[[Any], Awaitable[None]]:
|
) -> Callable[[Any], Awaitable[None]]:
|
||||||
|
if address_data is None:
|
||||||
|
address_data = {}
|
||||||
dhcp_watcher = dhcp.DHCPWatcher(
|
dhcp_watcher = dhcp.DHCPWatcher(
|
||||||
hass,
|
hass,
|
||||||
{},
|
address_data,
|
||||||
integration_matchers,
|
integration_matchers,
|
||||||
)
|
)
|
||||||
with patch("aiodhcpwatcher.async_start"):
|
with patch("aiodhcpwatcher.async_start"):
|
||||||
@ -177,7 +187,8 @@ async def test_dhcp_match_hostname_and_macaddress(hass: HomeAssistant) -> None:
|
|||||||
assert len(mock_init.mock_calls) == 1
|
assert len(mock_init.mock_calls) == 1
|
||||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[0][2]["context"] == {
|
assert mock_init.mock_calls[0][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.210.56",
|
ip="192.168.210.56",
|
||||||
@ -205,7 +216,8 @@ async def test_dhcp_renewal_match_hostname_and_macaddress(hass: HomeAssistant) -
|
|||||||
assert len(mock_init.mock_calls) == 1
|
assert len(mock_init.mock_calls) == 1
|
||||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[0][2]["context"] == {
|
assert mock_init.mock_calls[0][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="50147903852c", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.1.120",
|
ip="192.168.1.120",
|
||||||
@ -254,7 +266,8 @@ async def test_registered_devices(
|
|||||||
assert len(mock_init.mock_calls) == 1
|
assert len(mock_init.mock_calls) == 1
|
||||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[0][2]["context"] == {
|
assert mock_init.mock_calls[0][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="50147903852c", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.1.120",
|
ip="192.168.1.120",
|
||||||
@ -280,7 +293,8 @@ async def test_dhcp_match_hostname(hass: HomeAssistant) -> None:
|
|||||||
assert len(mock_init.mock_calls) == 1
|
assert len(mock_init.mock_calls) == 1
|
||||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[0][2]["context"] == {
|
assert mock_init.mock_calls[0][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.210.56",
|
ip="192.168.210.56",
|
||||||
@ -306,7 +320,8 @@ async def test_dhcp_match_macaddress(hass: HomeAssistant) -> None:
|
|||||||
assert len(mock_init.mock_calls) == 1
|
assert len(mock_init.mock_calls) == 1
|
||||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[0][2]["context"] == {
|
assert mock_init.mock_calls[0][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.210.56",
|
ip="192.168.210.56",
|
||||||
@ -335,7 +350,8 @@ async def test_dhcp_multiple_match_only_one_flow(hass: HomeAssistant) -> None:
|
|||||||
assert len(mock_init.mock_calls) == 1
|
assert len(mock_init.mock_calls) == 1
|
||||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[0][2]["context"] == {
|
assert mock_init.mock_calls[0][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.210.56",
|
ip="192.168.210.56",
|
||||||
@ -361,7 +377,8 @@ async def test_dhcp_match_macaddress_without_hostname(hass: HomeAssistant) -> No
|
|||||||
assert len(mock_init.mock_calls) == 1
|
assert len(mock_init.mock_calls) == 1
|
||||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[0][2]["context"] == {
|
assert mock_init.mock_calls[0][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="606bbd59e4b4", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.107.151",
|
ip="192.168.107.151",
|
||||||
@ -687,7 +704,8 @@ async def test_device_tracker_hostname_and_macaddress_exists_before_start(
|
|||||||
assert len(mock_init.mock_calls) == 1
|
assert len(mock_init.mock_calls) == 1
|
||||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[0][2]["context"] == {
|
assert mock_init.mock_calls[0][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.210.56",
|
ip="192.168.210.56",
|
||||||
@ -724,7 +742,8 @@ async def test_device_tracker_registered(hass: HomeAssistant) -> None:
|
|||||||
assert len(mock_init.mock_calls) == 1
|
assert len(mock_init.mock_calls) == 1
|
||||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[0][2]["context"] == {
|
assert mock_init.mock_calls[0][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.210.56",
|
ip="192.168.210.56",
|
||||||
@ -803,7 +822,8 @@ async def test_device_tracker_hostname_and_macaddress_after_start(
|
|||||||
assert len(mock_init.mock_calls) == 1
|
assert len(mock_init.mock_calls) == 1
|
||||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[0][2]["context"] == {
|
assert mock_init.mock_calls[0][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.210.56",
|
ip="192.168.210.56",
|
||||||
@ -1012,7 +1032,8 @@ async def test_aiodiscover_finds_new_hosts(hass: HomeAssistant) -> None:
|
|||||||
assert len(mock_init.mock_calls) == 1
|
assert len(mock_init.mock_calls) == 1
|
||||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[0][2]["context"] == {
|
assert mock_init.mock_calls[0][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.210.56",
|
ip="192.168.210.56",
|
||||||
@ -1074,7 +1095,8 @@ async def test_aiodiscover_does_not_call_again_on_shorter_hostname(
|
|||||||
assert len(mock_init.mock_calls) == 2
|
assert len(mock_init.mock_calls) == 2
|
||||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[0][2]["context"] == {
|
assert mock_init.mock_calls[0][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.210.56",
|
ip="192.168.210.56",
|
||||||
@ -1083,7 +1105,8 @@ async def test_aiodiscover_does_not_call_again_on_shorter_hostname(
|
|||||||
)
|
)
|
||||||
assert mock_init.mock_calls[1][1][0] == "mock-domain"
|
assert mock_init.mock_calls[1][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[1][2]["context"] == {
|
assert mock_init.mock_calls[1][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[1][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[1][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.210.56",
|
ip="192.168.210.56",
|
||||||
@ -1140,10 +1163,290 @@ async def test_aiodiscover_finds_new_hosts_after_interval(hass: HomeAssistant) -
|
|||||||
assert len(mock_init.mock_calls) == 1
|
assert len(mock_init.mock_calls) == 1
|
||||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
assert mock_init.mock_calls[0][2]["context"] == {
|
assert mock_init.mock_calls[0][2]["context"] == {
|
||||||
"source": config_entries.SOURCE_DHCP
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
}
|
}
|
||||||
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
ip="192.168.210.56",
|
ip="192.168.210.56",
|
||||||
hostname="connect",
|
hostname="connect",
|
||||||
macaddress="b8b7f16db533",
|
macaddress="b8b7f16db533",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
(
|
||||||
|
"entry_domain",
|
||||||
|
"entry_discovery_keys",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
# Matching discovery key
|
||||||
|
(
|
||||||
|
"mock-domain",
|
||||||
|
{"dhcp": (DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),)},
|
||||||
|
),
|
||||||
|
# Matching discovery key
|
||||||
|
(
|
||||||
|
"mock-domain",
|
||||||
|
{
|
||||||
|
"dhcp": (DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),),
|
||||||
|
"other": (DiscoveryKey(domain="other", key="blah", version=1),),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
# Matching discovery key, other domain
|
||||||
|
# Note: Rediscovery is not currently restricted to the domain of the removed
|
||||||
|
# entry. Such a check can be added if needed.
|
||||||
|
(
|
||||||
|
"comp",
|
||||||
|
{"dhcp": (DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),)},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize("entry_source", [config_entries.SOURCE_IGNORE])
|
||||||
|
async def test_dhcp_rediscover(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry_domain: str,
|
||||||
|
entry_discovery_keys: tuple,
|
||||||
|
entry_source: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test we reinitiate flows when an ignored config entry is removed."""
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=entry_domain,
|
||||||
|
discovery_keys=entry_discovery_keys,
|
||||||
|
unique_id="mock-unique-id",
|
||||||
|
state=config_entries.ConfigEntryState.LOADED,
|
||||||
|
source=entry_source,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
address_data = {}
|
||||||
|
integration_matchers = dhcp.async_index_integration_matchers(
|
||||||
|
[{"domain": "mock-domain", "hostname": "connect", "macaddress": "B8B7F1*"}]
|
||||||
|
)
|
||||||
|
packet = Ether(RAW_DHCP_REQUEST)
|
||||||
|
|
||||||
|
async_handle_dhcp_packet = await _async_get_handle_dhcp_packet(
|
||||||
|
hass, integration_matchers, address_data
|
||||||
|
)
|
||||||
|
rediscovery_watcher = dhcp.RediscoveryWatcher(
|
||||||
|
hass, address_data, integration_matchers
|
||||||
|
)
|
||||||
|
rediscovery_watcher.async_start()
|
||||||
|
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||||
|
await async_handle_dhcp_packet(packet)
|
||||||
|
# Ensure no change is ignored
|
||||||
|
await async_handle_dhcp_packet(packet)
|
||||||
|
|
||||||
|
# Assert the cached MAC address is hexstring without :
|
||||||
|
assert address_data == {
|
||||||
|
"b8b7f16db533": {"hostname": "connect", "ip": "192.168.210.56"}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_context = {
|
||||||
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
|
}
|
||||||
|
assert len(mock_init.mock_calls) == 1
|
||||||
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
|
assert mock_init.mock_calls[0][2]["context"] == expected_context
|
||||||
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
|
ip="192.168.210.56",
|
||||||
|
hostname="connect",
|
||||||
|
macaddress="b8b7f16db533",
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||||
|
await hass.config_entries.async_remove(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert len(mock_init.mock_calls) == 2
|
||||||
|
assert mock_init.mock_calls[0][1][0] == entry_domain
|
||||||
|
assert mock_init.mock_calls[0][2]["context"] == {"source": "unignore"}
|
||||||
|
assert mock_init.mock_calls[1][1][0] == "mock-domain"
|
||||||
|
assert mock_init.mock_calls[1][2]["context"] == expected_context
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
(
|
||||||
|
"entry_domain",
|
||||||
|
"entry_discovery_keys",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
# Matching discovery key
|
||||||
|
(
|
||||||
|
"mock-domain",
|
||||||
|
{"dhcp": (DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),)},
|
||||||
|
),
|
||||||
|
# Matching discovery key
|
||||||
|
(
|
||||||
|
"mock-domain",
|
||||||
|
{
|
||||||
|
"dhcp": (DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),),
|
||||||
|
"other": (DiscoveryKey(domain="other", key="blah", version=1),),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
# Matching discovery key, other domain
|
||||||
|
# Note: Rediscovery is not currently restricted to the domain of the removed
|
||||||
|
# entry. Such a check can be added if needed.
|
||||||
|
(
|
||||||
|
"comp",
|
||||||
|
{"dhcp": (DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),)},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"entry_source", [config_entries.SOURCE_USER, config_entries.SOURCE_ZEROCONF]
|
||||||
|
)
|
||||||
|
async def test_dhcp_rediscover_2(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry_domain: str,
|
||||||
|
entry_discovery_keys: tuple,
|
||||||
|
entry_source: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test we reinitiate flows when an ignored config entry is removed.
|
||||||
|
|
||||||
|
This test can be merged with test_zeroconf_rediscover when
|
||||||
|
async_step_unignore has been removed from the ConfigFlow base class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=entry_domain,
|
||||||
|
discovery_keys=entry_discovery_keys,
|
||||||
|
unique_id="mock-unique-id",
|
||||||
|
state=config_entries.ConfigEntryState.LOADED,
|
||||||
|
source=entry_source,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
address_data = {}
|
||||||
|
integration_matchers = dhcp.async_index_integration_matchers(
|
||||||
|
[{"domain": "mock-domain", "hostname": "connect", "macaddress": "B8B7F1*"}]
|
||||||
|
)
|
||||||
|
packet = Ether(RAW_DHCP_REQUEST)
|
||||||
|
|
||||||
|
async_handle_dhcp_packet = await _async_get_handle_dhcp_packet(
|
||||||
|
hass, integration_matchers, address_data
|
||||||
|
)
|
||||||
|
rediscovery_watcher = dhcp.RediscoveryWatcher(
|
||||||
|
hass, address_data, integration_matchers
|
||||||
|
)
|
||||||
|
rediscovery_watcher.async_start()
|
||||||
|
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||||
|
await async_handle_dhcp_packet(packet)
|
||||||
|
# Ensure no change is ignored
|
||||||
|
await async_handle_dhcp_packet(packet)
|
||||||
|
|
||||||
|
# Assert the cached MAC address is hexstring without :
|
||||||
|
assert address_data == {
|
||||||
|
"b8b7f16db533": {"hostname": "connect", "ip": "192.168.210.56"}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_context = {
|
||||||
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
|
}
|
||||||
|
assert len(mock_init.mock_calls) == 1
|
||||||
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
|
assert mock_init.mock_calls[0][2]["context"] == expected_context
|
||||||
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
|
ip="192.168.210.56",
|
||||||
|
hostname="connect",
|
||||||
|
macaddress="b8b7f16db533",
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||||
|
await hass.config_entries.async_remove(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert len(mock_init.mock_calls) == 1
|
||||||
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
|
assert mock_init.mock_calls[0][2]["context"] == expected_context
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("mock_async_zeroconf")
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
(
|
||||||
|
"entry_domain",
|
||||||
|
"entry_discovery_keys",
|
||||||
|
"entry_source",
|
||||||
|
"entry_unique_id",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
# Discovery key from other domain
|
||||||
|
(
|
||||||
|
"mock-domain",
|
||||||
|
{
|
||||||
|
"bluetooth": (
|
||||||
|
DiscoveryKey(domain="bluetooth", key="b8b7f16db533", version=1),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
config_entries.SOURCE_IGNORE,
|
||||||
|
"mock-unique-id",
|
||||||
|
),
|
||||||
|
# Discovery key from the future
|
||||||
|
(
|
||||||
|
"mock-domain",
|
||||||
|
{"dhcp": (DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=2),)},
|
||||||
|
config_entries.SOURCE_IGNORE,
|
||||||
|
"mock-unique-id",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_dhcp_rediscover_no_match(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry_domain: str,
|
||||||
|
entry_discovery_keys: tuple,
|
||||||
|
entry_source: str,
|
||||||
|
entry_unique_id: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test we don't reinitiate flows when a non matching config entry is removed."""
|
||||||
|
|
||||||
|
mock_integration(hass, MockModule(entry_domain))
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=entry_domain,
|
||||||
|
discovery_keys=entry_discovery_keys,
|
||||||
|
unique_id=entry_unique_id,
|
||||||
|
state=config_entries.ConfigEntryState.LOADED,
|
||||||
|
source=entry_source,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
address_data = {}
|
||||||
|
integration_matchers = dhcp.async_index_integration_matchers(
|
||||||
|
[{"domain": "mock-domain", "hostname": "connect", "macaddress": "B8B7F1*"}]
|
||||||
|
)
|
||||||
|
packet = Ether(RAW_DHCP_REQUEST)
|
||||||
|
|
||||||
|
async_handle_dhcp_packet = await _async_get_handle_dhcp_packet(
|
||||||
|
hass, integration_matchers, address_data
|
||||||
|
)
|
||||||
|
rediscovery_watcher = dhcp.RediscoveryWatcher(
|
||||||
|
hass, address_data, integration_matchers
|
||||||
|
)
|
||||||
|
rediscovery_watcher.async_start()
|
||||||
|
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||||
|
await async_handle_dhcp_packet(packet)
|
||||||
|
# Ensure no change is ignored
|
||||||
|
await async_handle_dhcp_packet(packet)
|
||||||
|
|
||||||
|
expected_context = {
|
||||||
|
"discovery_key": DiscoveryKey(domain="dhcp", key="b8b7f16db533", version=1),
|
||||||
|
"source": config_entries.SOURCE_DHCP,
|
||||||
|
}
|
||||||
|
assert len(mock_init.mock_calls) == 1
|
||||||
|
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||||
|
assert mock_init.mock_calls[0][2]["context"] == expected_context
|
||||||
|
assert mock_init.mock_calls[0][2]["data"] == dhcp.DhcpServiceInfo(
|
||||||
|
ip="192.168.210.56",
|
||||||
|
hostname="connect",
|
||||||
|
macaddress="b8b7f16db533",
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||||
|
await hass.config_entries.async_remove(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert len(mock_init.mock_calls) == 1
|
||||||
|
assert mock_init.mock_calls[0][1][0] == entry_domain
|
||||||
|
assert mock_init.mock_calls[0][2]["context"] == {"source": "unignore"}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user