mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Make DHCP discovery aware of the network integration (#144767)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
31847d8cfb
commit
ab5d60e33d
@ -7,6 +7,7 @@ from collections.abc import Callable
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from fnmatch import translate
|
from fnmatch import translate
|
||||||
from functools import lru_cache, partial
|
from functools import lru_cache, partial
|
||||||
|
from ipaddress import IPv4Address
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
@ -22,6 +23,7 @@ from aiodiscover.discovery import (
|
|||||||
from cached_ipaddress import cached_ip_addresses
|
from cached_ipaddress import cached_ip_addresses
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
|
from homeassistant.components import network
|
||||||
from homeassistant.components.device_tracker import (
|
from homeassistant.components.device_tracker import (
|
||||||
ATTR_HOST_NAME,
|
ATTR_HOST_NAME,
|
||||||
ATTR_IP,
|
ATTR_IP,
|
||||||
@ -421,9 +423,33 @@ class DHCPWatcher(WatcherBase):
|
|||||||
response.ip_address, response.hostname, response.mac_address
|
response.ip_address, response.hostname, response.mac_address
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def async_get_adapter_indexes(self) -> list[int] | None:
|
||||||
|
"""Get the adapter indexes."""
|
||||||
|
adapters = await network.async_get_adapters(self.hass)
|
||||||
|
if network.async_only_default_interface_enabled(adapters):
|
||||||
|
return None
|
||||||
|
return [
|
||||||
|
adapter["index"]
|
||||||
|
for adapter in adapters
|
||||||
|
if (
|
||||||
|
adapter["enabled"]
|
||||||
|
and adapter["index"] is not None
|
||||||
|
and adapter["ipv4"]
|
||||||
|
and (
|
||||||
|
addresses := [IPv4Address(ip["address"]) for ip in adapter["ipv4"]]
|
||||||
|
)
|
||||||
|
and any(
|
||||||
|
ip for ip in addresses if not ip.is_loopback and not ip.is_global
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
async def async_start(self) -> None:
|
async def async_start(self) -> None:
|
||||||
"""Start watching for dhcp packets."""
|
"""Start watching for dhcp packets."""
|
||||||
self._unsub = await aiodhcpwatcher.async_start(self._async_process_dhcp_request)
|
self._unsub = await aiodhcpwatcher.async_start(
|
||||||
|
self._async_process_dhcp_request,
|
||||||
|
await self.async_get_adapter_indexes(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RediscoveryWatcher(WatcherBase):
|
class RediscoveryWatcher(WatcherBase):
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"domain": "dhcp",
|
"domain": "dhcp",
|
||||||
"name": "DHCP Discovery",
|
"name": "DHCP Discovery",
|
||||||
"codeowners": ["@bdraco"],
|
"codeowners": ["@bdraco"],
|
||||||
|
"dependencies": ["network"],
|
||||||
"documentation": "https://www.home-assistant.io/integrations/dhcp",
|
"documentation": "https://www.home-assistant.io/integrations/dhcp",
|
||||||
"integration_type": "system",
|
"integration_type": "system",
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
|
@ -157,6 +157,7 @@ async def _async_get_handle_dhcp_packet(
|
|||||||
hass,
|
hass,
|
||||||
DHCPData(integration_matchers, set(), address_data),
|
DHCPData(integration_matchers, set(), address_data),
|
||||||
)
|
)
|
||||||
|
|
||||||
with patch("aiodhcpwatcher.async_start"):
|
with patch("aiodhcpwatcher.async_start"):
|
||||||
await dhcp_watcher.async_start()
|
await dhcp_watcher.async_start()
|
||||||
|
|
||||||
@ -171,6 +172,53 @@ async def _async_get_handle_dhcp_packet(
|
|||||||
return cast("Callable[[Any], Awaitable[None]]", _async_handle_dhcp_packet)
|
return cast("Callable[[Any], Awaitable[None]]", _async_handle_dhcp_packet)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_dhcp_start_using_multiple_interfaces(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
) -> None:
|
||||||
|
"""Test start using multiple interfaces."""
|
||||||
|
|
||||||
|
def _generate_mock_adapters():
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"auto": False,
|
||||||
|
"default": False,
|
||||||
|
"enabled": True,
|
||||||
|
"ipv4": [{"address": "192.168.0.1", "network_prefix": 24}],
|
||||||
|
"ipv6": [],
|
||||||
|
"name": "eth0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 2,
|
||||||
|
"auto": True,
|
||||||
|
"default": True,
|
||||||
|
"enabled": True,
|
||||||
|
"ipv4": [{"address": "192.168.1.1", "network_prefix": 24}],
|
||||||
|
"ipv6": [],
|
||||||
|
"name": "eth1",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
integration_matchers = dhcp.async_index_integration_matchers(
|
||||||
|
[{"domain": "mock-domain", "hostname": "connect", "macaddress": "B8B7F1*"}]
|
||||||
|
)
|
||||||
|
dhcp_watcher = dhcp.DHCPWatcher(
|
||||||
|
hass,
|
||||||
|
DHCPData(integration_matchers, set(), {}),
|
||||||
|
)
|
||||||
|
|
||||||
|
with (
|
||||||
|
patch("aiodhcpwatcher.async_start") as mock_start,
|
||||||
|
patch(
|
||||||
|
"homeassistant.components.dhcp.network.async_get_adapters",
|
||||||
|
return_value=_generate_mock_adapters(),
|
||||||
|
),
|
||||||
|
):
|
||||||
|
await dhcp_watcher.async_start()
|
||||||
|
|
||||||
|
mock_start.assert_called_with(dhcp_watcher._async_process_dhcp_request, [1, 2])
|
||||||
|
|
||||||
|
|
||||||
async def test_dhcp_match_hostname_and_macaddress(hass: HomeAssistant) -> None:
|
async def test_dhcp_match_hostname_and_macaddress(hass: HomeAssistant) -> None:
|
||||||
"""Test matching based on hostname and macaddress."""
|
"""Test matching based on hostname and macaddress."""
|
||||||
integration_matchers = dhcp.async_index_integration_matchers(
|
integration_matchers = dhcp.async_index_integration_matchers(
|
||||||
|
@ -22,6 +22,7 @@ async def test_subscribe_discovery(
|
|||||||
|
|
||||||
async def mock_start(
|
async def mock_start(
|
||||||
callback: Callable[[aiodhcpwatcher.DHCPRequest], None],
|
callback: Callable[[aiodhcpwatcher.DHCPRequest], None],
|
||||||
|
if_indexes: list[int] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Mock start."""
|
"""Mock start."""
|
||||||
nonlocal saved_callback
|
nonlocal saved_callback
|
||||||
|
@ -655,5 +655,5 @@ async def test_discovery_requirements_dhcp(hass: HomeAssistant) -> None:
|
|||||||
) as mock_process:
|
) as mock_process:
|
||||||
await async_get_integration_with_requirements(hass, "comp")
|
await async_get_integration_with_requirements(hass, "comp")
|
||||||
|
|
||||||
assert len(mock_process.mock_calls) == 1 # dhcp does not depend on http
|
assert len(mock_process.mock_calls) == 2 # dhcp does not depend on http
|
||||||
assert mock_process.mock_calls[0][1][1] == dhcp.requirements
|
assert mock_process.mock_calls[0][1][1] == dhcp.requirements
|
||||||
|
Loading…
x
Reference in New Issue
Block a user