mirror of
https://github.com/home-assistant/core.git
synced 2026-09-24 07:25:52 -05:00
Add DHCP discovery for known Elgato devices (#168002)
This commit is contained in:
@@ -12,6 +12,8 @@ from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||
from homeassistant.const import CONF_HOST, CONF_MAC
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.device_registry import format_mac
|
||||
from homeassistant.helpers.service_info.dhcp import DhcpServiceInfo
|
||||
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo
|
||||
|
||||
from .const import DOMAIN
|
||||
@@ -23,7 +25,6 @@ class ElgatoFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
VERSION = 1
|
||||
|
||||
host: str
|
||||
port: int
|
||||
serial_number: str
|
||||
mac: str | None = None
|
||||
|
||||
@@ -70,6 +71,32 @@ class ElgatoFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a flow initiated by zeroconf."""
|
||||
return self._async_create_entry()
|
||||
|
||||
async def async_step_dhcp(
|
||||
self, discovery_info: DhcpServiceInfo
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle DHCP discovery of a known Elgato device.
|
||||
|
||||
Only devices already configured (matched via ``registered_devices``)
|
||||
reach this step. It is used to keep the stored host in sync with the
|
||||
current IP address of the device.
|
||||
"""
|
||||
mac = format_mac(discovery_info.macaddress)
|
||||
|
||||
for entry in self._async_current_entries():
|
||||
if (entry_mac := entry.data.get(CONF_MAC)) is None or format_mac(
|
||||
entry_mac
|
||||
) != mac:
|
||||
continue
|
||||
if entry.data[CONF_HOST] != discovery_info.ip:
|
||||
self.hass.config_entries.async_update_entry(
|
||||
entry,
|
||||
data=entry.data | {CONF_HOST: discovery_info.ip},
|
||||
)
|
||||
self.hass.config_entries.async_schedule_reload(entry.entry_id)
|
||||
return self.async_abort(reason="already_configured")
|
||||
|
||||
return self.async_abort(reason="no_devices_found")
|
||||
|
||||
@callback
|
||||
def _async_show_setup_form(
|
||||
self, errors: dict[str, str] | None = None
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
"name": "Elgato Light",
|
||||
"codeowners": ["@frenck"],
|
||||
"config_flow": true,
|
||||
"dhcp": [
|
||||
{
|
||||
"registered_devices": true
|
||||
}
|
||||
],
|
||||
"documentation": "https://www.home-assistant.io/integrations/elgato",
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_polling",
|
||||
|
||||
@@ -39,11 +39,7 @@ rules:
|
||||
# Gold
|
||||
devices: done
|
||||
diagnostics: done
|
||||
discovery-update-info:
|
||||
status: todo
|
||||
comment: |
|
||||
The integration doesn't update the device info based on DHCP discovery
|
||||
of known existing devices.
|
||||
discovery-update-info: done
|
||||
discovery: done
|
||||
docs-data-update: todo
|
||||
docs-examples: todo
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
|
||||
|
||||
Generated
+4
@@ -173,6 +173,10 @@ DHCP: Final[list[dict[str, str | bool]]] = [
|
||||
"domain": "dlink",
|
||||
"hostname": "dsp-w215",
|
||||
},
|
||||
{
|
||||
"domain": "elgato",
|
||||
"registered_devices": True,
|
||||
},
|
||||
{
|
||||
"domain": "elkm1",
|
||||
"registered_devices": True,
|
||||
|
||||
@@ -7,10 +7,11 @@ from elgato import ElgatoConnectionError
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.elgato.const import DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_USER, SOURCE_ZEROCONF
|
||||
from homeassistant.config_entries import SOURCE_DHCP, SOURCE_USER, SOURCE_ZEROCONF
|
||||
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_SOURCE
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
from homeassistant.helpers.service_info.dhcp import DhcpServiceInfo
|
||||
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
@@ -254,3 +255,79 @@ async def test_zeroconf_during_onboarding(
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
assert len(mock_elgato.info.mock_calls) == 1
|
||||
assert len(mock_onboarding.mock_calls) == 1
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_elgato")
|
||||
async def test_dhcp_discovery_updates_host(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test DHCP discovery of a known device updates its stored host."""
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={CONF_SOURCE: SOURCE_DHCP},
|
||||
data=DhcpServiceInfo(
|
||||
hostname="elgato",
|
||||
ip="127.0.0.42",
|
||||
macaddress="aabbccddeeff",
|
||||
),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
assert mock_config_entry.data[CONF_HOST] == "127.0.0.42"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_elgato")
|
||||
async def test_dhcp_discovery_same_host(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test DHCP discovery does nothing when the host is already up to date."""
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={CONF_SOURCE: SOURCE_DHCP},
|
||||
data=DhcpServiceInfo(
|
||||
hostname="elgato",
|
||||
ip="127.0.0.1",
|
||||
macaddress="aabbccddeeff",
|
||||
),
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
assert mock_config_entry.data[CONF_HOST] == "127.0.0.1"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_elgato")
|
||||
async def test_dhcp_discovery_no_match(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test DHCP discovery aborts when no matching entry is configured."""
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={CONF_SOURCE: SOURCE_DHCP},
|
||||
data=DhcpServiceInfo(
|
||||
hostname="elgato",
|
||||
ip="127.0.0.42",
|
||||
macaddress="001122334455",
|
||||
),
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "no_devices_found"
|
||||
assert mock_config_entry.data[CONF_HOST] == "127.0.0.1"
|
||||
|
||||
Reference in New Issue
Block a user