mirror of
https://github.com/home-assistant/core.git
synced 2025-07-09 14:27:07 +00:00
Use dataclass for DhcpServiceInfo (#60136)
Co-authored-by: epenet <epenet@users.noreply.github.com>
This commit is contained in:
parent
e673d9dbd0
commit
560546f65e
@ -1,12 +1,13 @@
|
|||||||
"""The dhcp integration."""
|
"""The dhcp integration."""
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import fnmatch
|
import fnmatch
|
||||||
from ipaddress import ip_address as make_ip_address
|
from ipaddress import ip_address as make_ip_address
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
from typing import Final, TypedDict
|
from typing import Any, Final
|
||||||
|
|
||||||
from aiodiscover import DiscoverHosts
|
from aiodiscover import DiscoverHosts
|
||||||
from aiodiscover.discovery import (
|
from aiodiscover.discovery import (
|
||||||
@ -32,12 +33,14 @@ from homeassistant.const import (
|
|||||||
STATE_HOME,
|
STATE_HOME,
|
||||||
)
|
)
|
||||||
from homeassistant.core import Event, HomeAssistant, State, callback
|
from homeassistant.core import Event, HomeAssistant, State, callback
|
||||||
|
from homeassistant.data_entry_flow import BaseServiceInfo
|
||||||
from homeassistant.helpers import discovery_flow
|
from homeassistant.helpers import discovery_flow
|
||||||
from homeassistant.helpers.device_registry import format_mac
|
from homeassistant.helpers.device_registry import format_mac
|
||||||
from homeassistant.helpers.event import (
|
from homeassistant.helpers.event import (
|
||||||
async_track_state_added_domain,
|
async_track_state_added_domain,
|
||||||
async_track_time_interval,
|
async_track_time_interval,
|
||||||
)
|
)
|
||||||
|
from homeassistant.helpers.frame import report
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.loader import async_get_dhcp
|
from homeassistant.loader import async_get_dhcp
|
||||||
from homeassistant.util.async_ import run_callback_threadsafe
|
from homeassistant.util.async_ import run_callback_threadsafe
|
||||||
@ -55,13 +58,33 @@ SCAN_INTERVAL = timedelta(minutes=60)
|
|||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DhcpServiceInfo(TypedDict):
|
@dataclass
|
||||||
|
class DhcpServiceInfo(BaseServiceInfo):
|
||||||
"""Prepared info from dhcp entries."""
|
"""Prepared info from dhcp entries."""
|
||||||
|
|
||||||
ip: str
|
ip: str # pylint: disable=invalid-name
|
||||||
hostname: str
|
hostname: str
|
||||||
macaddress: str
|
macaddress: str
|
||||||
|
|
||||||
|
# Used to prevent log flooding. To be removed in 2022.6
|
||||||
|
_warning_logged: bool = False
|
||||||
|
|
||||||
|
def __getitem__(self, name: str) -> Any:
|
||||||
|
"""
|
||||||
|
Allow property access by name for compatibility reason.
|
||||||
|
|
||||||
|
Deprecated, and will be removed in version 2022.6.
|
||||||
|
"""
|
||||||
|
if not self._warning_logged:
|
||||||
|
report(
|
||||||
|
f"accessed discovery_info['{name}'] instead of discovery_info.{name}; this will fail in version 2022.6",
|
||||||
|
exclude_integrations={"dhcp"},
|
||||||
|
error_if_core=False,
|
||||||
|
level=logging.DEBUG,
|
||||||
|
)
|
||||||
|
self._warning_logged = True
|
||||||
|
return getattr(self, name)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
"""Set up the dhcp component."""
|
"""Set up the dhcp component."""
|
||||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
import abc
|
import abc
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Iterable, Mapping
|
from collections.abc import Iterable, Mapping
|
||||||
|
from dataclasses import dataclass
|
||||||
from types import MappingProxyType
|
from types import MappingProxyType
|
||||||
from typing import Any, TypedDict
|
from typing import Any, TypedDict
|
||||||
import uuid
|
import uuid
|
||||||
@ -25,6 +26,11 @@ RESULT_TYPE_SHOW_PROGRESS_DONE = "progress_done"
|
|||||||
EVENT_DATA_ENTRY_FLOW_PROGRESSED = "data_entry_flow_progressed"
|
EVENT_DATA_ENTRY_FLOW_PROGRESSED = "data_entry_flow_progressed"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BaseServiceInfo:
|
||||||
|
"""Base class for discovery ServiceInfo."""
|
||||||
|
|
||||||
|
|
||||||
class FlowError(HomeAssistantError):
|
class FlowError(HomeAssistantError):
|
||||||
"""Error while configuring an account."""
|
"""Error while configuring an account."""
|
||||||
|
|
||||||
@ -301,7 +307,7 @@ class FlowManager(abc.ABC):
|
|||||||
self,
|
self,
|
||||||
flow: Any,
|
flow: Any,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
user_input: dict | None,
|
user_input: dict | BaseServiceInfo | None,
|
||||||
step_done: asyncio.Future | None = None,
|
step_done: asyncio.Future | None = None,
|
||||||
) -> FlowResult:
|
) -> FlowResult:
|
||||||
"""Handle a step of a flow."""
|
"""Handle a step of a flow."""
|
||||||
|
@ -51,7 +51,10 @@ class MissingIntegrationFrame(HomeAssistantError):
|
|||||||
|
|
||||||
|
|
||||||
def report(
|
def report(
|
||||||
what: str, exclude_integrations: set | None = None, error_if_core: bool = True
|
what: str,
|
||||||
|
exclude_integrations: set | None = None,
|
||||||
|
error_if_core: bool = True,
|
||||||
|
level: int = logging.WARNING,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Report incorrect usage.
|
"""Report incorrect usage.
|
||||||
|
|
||||||
@ -68,11 +71,13 @@ def report(
|
|||||||
_LOGGER.warning(msg, stack_info=True)
|
_LOGGER.warning(msg, stack_info=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
report_integration(what, integration_frame)
|
report_integration(what, integration_frame, level)
|
||||||
|
|
||||||
|
|
||||||
def report_integration(
|
def report_integration(
|
||||||
what: str, integration_frame: tuple[FrameSummary, str, str]
|
what: str,
|
||||||
|
integration_frame: tuple[FrameSummary, str, str],
|
||||||
|
level: int = logging.WARNING,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Report incorrect usage in an integration.
|
"""Report incorrect usage in an integration.
|
||||||
|
|
||||||
@ -86,7 +91,8 @@ def report_integration(
|
|||||||
else:
|
else:
|
||||||
extra = ""
|
extra = ""
|
||||||
|
|
||||||
_LOGGER.warning(
|
_LOGGER.log(
|
||||||
|
level,
|
||||||
"Detected integration that %s. "
|
"Detected integration that %s. "
|
||||||
"Please report issue%s for %s using this method at %s, line %s: %s",
|
"Please report issue%s for %s using this method at %s, line %s: %s",
|
||||||
what,
|
what,
|
||||||
|
@ -191,7 +191,9 @@ async def test_discovered_dhcp(
|
|||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_DHCP},
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
data=dhcp.DhcpServiceInfo(ip="1.2.3.4", macaddress=MOCK_MAC_ADDR),
|
data=dhcp.DhcpServiceInfo(
|
||||||
|
ip="1.2.3.4", macaddress=MOCK_MAC_ADDR, hostname="mock_hostname"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
assert result["type"] == RESULT_TYPE_FORM
|
assert result["type"] == RESULT_TYPE_FORM
|
||||||
assert result["errors"] == {}
|
assert result["errors"] == {}
|
||||||
@ -246,7 +248,9 @@ async def test_discovered_by_homekit_and_dhcp(hass):
|
|||||||
result2 = await hass.config_entries.flow.async_init(
|
result2 = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_DHCP},
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
data=dhcp.DhcpServiceInfo(ip="1.2.3.4", macaddress=MOCK_MAC_ADDR),
|
data=dhcp.DhcpServiceInfo(
|
||||||
|
ip="1.2.3.4", macaddress=MOCK_MAC_ADDR, hostname="mock_hostname"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
assert result2["type"] == RESULT_TYPE_ABORT
|
assert result2["type"] == RESULT_TYPE_ABORT
|
||||||
assert result2["reason"] == "already_in_progress"
|
assert result2["reason"] == "already_in_progress"
|
||||||
@ -254,7 +258,9 @@ async def test_discovered_by_homekit_and_dhcp(hass):
|
|||||||
result3 = await hass.config_entries.flow.async_init(
|
result3 = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_DHCP},
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
data=dhcp.DhcpServiceInfo(ip="1.2.3.4", macaddress="00:00:00:00:00:00"),
|
data=dhcp.DhcpServiceInfo(
|
||||||
|
ip="1.2.3.4", macaddress="00:00:00:00:00:00", hostname="mock_hostname"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
assert result3["type"] == RESULT_TYPE_ABORT
|
assert result3["type"] == RESULT_TYPE_ABORT
|
||||||
assert result3["reason"] == "already_in_progress"
|
assert result3["reason"] == "already_in_progress"
|
||||||
|
@ -23,7 +23,9 @@ ZEROCONF_DISCOVERY_INFO = zeroconf.ZeroconfServiceInfo(
|
|||||||
)
|
)
|
||||||
|
|
||||||
DHCP_DISCOVERY_INFO = dhcp.DhcpServiceInfo(
|
DHCP_DISCOVERY_INFO = dhcp.DhcpServiceInfo(
|
||||||
hostname="Hunter Douglas Powerview Hub", ip="1.2.3.4"
|
hostname="Hunter Douglas Powerview Hub",
|
||||||
|
ip="1.2.3.4",
|
||||||
|
macaddress="AA:BB:CC:DD:EE:FF",
|
||||||
)
|
)
|
||||||
|
|
||||||
DISCOVERY_DATA = [
|
DISCOVERY_DATA = [
|
||||||
|
@ -84,7 +84,9 @@ MOCK_SSDP_DATA_WRONGMODEL = {
|
|||||||
ATTR_UPNP_MODEL_NAME: "HW-Qfake",
|
ATTR_UPNP_MODEL_NAME: "HW-Qfake",
|
||||||
ATTR_UPNP_UDN: "uuid:0d1cef00-00dc-1000-9c80-4844f7b172df",
|
ATTR_UPNP_UDN: "uuid:0d1cef00-00dc-1000-9c80-4844f7b172df",
|
||||||
}
|
}
|
||||||
MOCK_DHCP_DATA = dhcp.DhcpServiceInfo(ip="fake_host", macaddress="aa:bb:cc:dd:ee:ff")
|
MOCK_DHCP_DATA = dhcp.DhcpServiceInfo(
|
||||||
|
ip="fake_host", macaddress="aa:bb:cc:dd:ee:ff", hostname="fake_hostname"
|
||||||
|
)
|
||||||
EXISTING_IP = "192.168.40.221"
|
EXISTING_IP = "192.168.40.221"
|
||||||
MOCK_ZEROCONF_DATA = zeroconf.ZeroconfServiceInfo(
|
MOCK_ZEROCONF_DATA = zeroconf.ZeroconfServiceInfo(
|
||||||
host="fake_host",
|
host="fake_host",
|
||||||
@ -1131,7 +1133,9 @@ async def test_update_legacy_missing_mac_from_dhcp(hass, remote: Mock):
|
|||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_DHCP},
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
data=dhcp.DhcpServiceInfo(ip=EXISTING_IP, macaddress="aa:bb:cc:dd:ee:ff"),
|
data=dhcp.DhcpServiceInfo(
|
||||||
|
ip=EXISTING_IP, macaddress="aa:bb:cc:dd:ee:ff", hostname="fake_hostname"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(mock_setup.mock_calls) == 1
|
assert len(mock_setup.mock_calls) == 1
|
||||||
@ -1165,7 +1169,9 @@ async def test_update_legacy_missing_mac_from_dhcp_no_unique_id(hass, remote: Mo
|
|||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_DHCP},
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
data=dhcp.DhcpServiceInfo(ip=EXISTING_IP, macaddress="aa:bb:cc:dd:ee:ff"),
|
data=dhcp.DhcpServiceInfo(
|
||||||
|
ip=EXISTING_IP, macaddress="aa:bb:cc:dd:ee:ff", hostname="fake_hostname"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(mock_setup.mock_calls) == 1
|
assert len(mock_setup.mock_calls) == 1
|
||||||
|
@ -141,6 +141,7 @@ async def test_dhcp(hass):
|
|||||||
data=dhcp.DhcpServiceInfo(
|
data=dhcp.DhcpServiceInfo(
|
||||||
hostname="Pentair: 01-01-01",
|
hostname="Pentair: 01-01-01",
|
||||||
ip="1.1.1.1",
|
ip="1.1.1.1",
|
||||||
|
macaddress="AA:BB:CC:DD:EE:FF",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -321,7 +321,9 @@ async def test_discovered_by_discovery_and_dhcp(hass):
|
|||||||
result3 = await hass.config_entries.flow.async_init(
|
result3 = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_DHCP},
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
data=dhcp.DhcpServiceInfo(ip=IP_ADDRESS, macaddress="00:00:00:00:00:00"),
|
data=dhcp.DhcpServiceInfo(
|
||||||
|
ip=IP_ADDRESS, macaddress="00:00:00:00:00:00", hostname="mock_hostname"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert result3["type"] == RESULT_TYPE_ABORT
|
assert result3["type"] == RESULT_TYPE_ABORT
|
||||||
@ -331,7 +333,9 @@ async def test_discovered_by_discovery_and_dhcp(hass):
|
|||||||
result3 = await hass.config_entries.flow.async_init(
|
result3 = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_DHCP},
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
data=dhcp.DhcpServiceInfo(ip="1.2.3.5", macaddress="00:00:00:00:00:01"),
|
data=dhcp.DhcpServiceInfo(
|
||||||
|
ip="1.2.3.5", macaddress="00:00:00:00:00:01", hostname="mock_hostname"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert result3["type"] == RESULT_TYPE_ABORT
|
assert result3["type"] == RESULT_TYPE_ABORT
|
||||||
|
@ -176,7 +176,9 @@ async def test_dhcp(hass: HomeAssistant) -> None:
|
|||||||
"""Test that DHCP discovery works."""
|
"""Test that DHCP discovery works."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
data=dhcp.DhcpServiceInfo(macaddress="01:23:45:67:89:ab"),
|
data=dhcp.DhcpServiceInfo(
|
||||||
|
ip="1.2.3.4", macaddress="01:23:45:67:89:ab", hostname="mock_hostname"
|
||||||
|
),
|
||||||
context={"source": config_entries.SOURCE_DHCP},
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -471,7 +471,9 @@ async def test_discovered_by_homekit_and_dhcp(hass):
|
|||||||
result2 = await hass.config_entries.flow.async_init(
|
result2 = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_DHCP},
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
data=dhcp.DhcpServiceInfo(ip=IP_ADDRESS, macaddress="aa:bb:cc:dd:ee:ff"),
|
data=dhcp.DhcpServiceInfo(
|
||||||
|
ip=IP_ADDRESS, macaddress="aa:bb:cc:dd:ee:ff", hostname="mock_hostname"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert result2["type"] == RESULT_TYPE_ABORT
|
assert result2["type"] == RESULT_TYPE_ABORT
|
||||||
@ -483,7 +485,9 @@ async def test_discovered_by_homekit_and_dhcp(hass):
|
|||||||
result3 = await hass.config_entries.flow.async_init(
|
result3 = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_DHCP},
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
data=dhcp.DhcpServiceInfo(ip=IP_ADDRESS, macaddress="00:00:00:00:00:00"),
|
data=dhcp.DhcpServiceInfo(
|
||||||
|
ip=IP_ADDRESS, macaddress="00:00:00:00:00:00", hostname="mock_hostname"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert result3["type"] == RESULT_TYPE_ABORT
|
assert result3["type"] == RESULT_TYPE_ABORT
|
||||||
@ -497,7 +501,9 @@ async def test_discovered_by_homekit_and_dhcp(hass):
|
|||||||
result3 = await hass.config_entries.flow.async_init(
|
result3 = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_DHCP},
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
data=dhcp.DhcpServiceInfo(ip="1.2.3.5", macaddress="00:00:00:00:00:01"),
|
data=dhcp.DhcpServiceInfo(
|
||||||
|
ip="1.2.3.5", macaddress="00:00:00:00:00:01", hostname="mock_hostname"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert result3["type"] == RESULT_TYPE_ABORT
|
assert result3["type"] == RESULT_TYPE_ABORT
|
||||||
@ -509,7 +515,9 @@ async def test_discovered_by_homekit_and_dhcp(hass):
|
|||||||
[
|
[
|
||||||
(
|
(
|
||||||
config_entries.SOURCE_DHCP,
|
config_entries.SOURCE_DHCP,
|
||||||
dhcp.DhcpServiceInfo(ip=IP_ADDRESS, macaddress="aa:bb:cc:dd:ee:ff"),
|
dhcp.DhcpServiceInfo(
|
||||||
|
ip=IP_ADDRESS, macaddress="aa:bb:cc:dd:ee:ff", hostname="mock_hostname"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
config_entries.SOURCE_HOMEKIT,
|
config_entries.SOURCE_HOMEKIT,
|
||||||
@ -570,7 +578,9 @@ async def test_discovered_by_dhcp_or_homekit(hass, source, data):
|
|||||||
[
|
[
|
||||||
(
|
(
|
||||||
config_entries.SOURCE_DHCP,
|
config_entries.SOURCE_DHCP,
|
||||||
dhcp.DhcpServiceInfo(ip=IP_ADDRESS, macaddress="aa:bb:cc:dd:ee:ff"),
|
dhcp.DhcpServiceInfo(
|
||||||
|
ip=IP_ADDRESS, macaddress="aa:bb:cc:dd:ee:ff", hostname="mock_hostname"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
config_entries.SOURCE_HOMEKIT,
|
config_entries.SOURCE_HOMEKIT,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user