Add DHCP updates to Fully Kiosk (#76896)

This commit is contained in:
Franck Nijhof 2022-08-17 03:19:23 +02:00 committed by GitHub
parent 6f3cdb6db1
commit ec1b133201
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 87 additions and 7 deletions

View File

@ -11,9 +11,11 @@ from fullykiosk.exceptions import FullyKioskError
import voluptuous as vol import voluptuous as vol
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.const import CONF_HOST, CONF_PASSWORD from homeassistant.components.dhcp import DhcpServiceInfo
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PASSWORD
from homeassistant.data_entry_flow import FlowResult from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.device_registry import format_mac
from .const import DEFAULT_PORT, DOMAIN, LOGGER from .const import DEFAULT_PORT, DOMAIN, LOGGER
@ -48,7 +50,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
await self.async_set_unique_id(device_info["deviceID"]) await self.async_set_unique_id(device_info["deviceID"])
self._abort_if_unique_id_configured(updates=user_input) self._abort_if_unique_id_configured(updates=user_input)
return self.async_create_entry( return self.async_create_entry(
title=device_info["deviceName"], data=user_input title=device_info["deviceName"],
data=user_input | {CONF_MAC: format_mac(device_info["Mac"])},
) )
return self.async_show_form( return self.async_show_form(
@ -61,3 +64,20 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
), ),
errors=errors, errors=errors,
) )
async def async_step_dhcp(self, discovery_info: DhcpServiceInfo) -> FlowResult:
"""Handle dhcp discovery."""
mac = format_mac(discovery_info.macaddress)
for entry in self._async_current_entries():
if entry.data[CONF_MAC] == mac:
self.hass.config_entries.async_update_entry(
entry,
data=entry.data | {CONF_HOST: discovery_info.ip},
)
self.hass.async_create_task(
self.hass.config_entries.async_reload(entry.entry_id)
)
return self.async_abort(reason="already_configured")
return self.async_abort(reason="unknown")

View File

@ -1,6 +1,7 @@
"""Base entity for the Fully Kiosk Browser integration.""" """Base entity for the Fully Kiosk Browser integration."""
from __future__ import annotations from __future__ import annotations
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.entity import DeviceInfo, Entity from homeassistant.helpers.entity import DeviceInfo, Entity
from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.helpers.update_coordinator import CoordinatorEntity
@ -23,4 +24,5 @@ class FullyKioskEntity(CoordinatorEntity[FullyKioskDataUpdateCoordinator], Entit
model=coordinator.data["deviceModel"], model=coordinator.data["deviceModel"],
sw_version=coordinator.data["appVersionName"], sw_version=coordinator.data["appVersionName"],
configuration_url=f"http://{coordinator.data['ip4']}:2323", configuration_url=f"http://{coordinator.data['ip4']}:2323",
connections={(CONNECTION_NETWORK_MAC, coordinator.data["Mac"])},
) )

View File

@ -6,5 +6,6 @@
"requirements": ["python-fullykiosk==0.0.11"], "requirements": ["python-fullykiosk==0.0.11"],
"dependencies": [], "dependencies": [],
"codeowners": ["@cgarwood"], "codeowners": ["@cgarwood"],
"iot_class": "local_polling" "iot_class": "local_polling",
"dhcp": [{ "registered_devices": true }]
} }

View File

@ -43,6 +43,7 @@ DHCP: list[dict[str, str | bool]] = [
{'domain': 'flux_led', 'hostname': 'zengge_[0-9a-f][0-9a-f]_*'}, {'domain': 'flux_led', 'hostname': 'zengge_[0-9a-f][0-9a-f]_*'},
{'domain': 'flux_led', 'hostname': 'sta*', 'macaddress': 'C82E47*'}, {'domain': 'flux_led', 'hostname': 'sta*', 'macaddress': 'C82E47*'},
{'domain': 'fronius', 'macaddress': '0003AC*'}, {'domain': 'fronius', 'macaddress': '0003AC*'},
{'domain': 'fully_kiosk', 'registered_devices': True},
{'domain': 'goalzero', 'registered_devices': True}, {'domain': 'goalzero', 'registered_devices': True},
{'domain': 'goalzero', 'hostname': 'yeti*'}, {'domain': 'goalzero', 'hostname': 'yeti*'},
{'domain': 'gogogate2', 'hostname': 'ismartgate*'}, {'domain': 'gogogate2', 'hostname': 'ismartgate*'},

View File

@ -8,7 +8,7 @@ from unittest.mock import AsyncMock, MagicMock, patch
import pytest import pytest
from homeassistant.components.fully_kiosk.const import DOMAIN from homeassistant.components.fully_kiosk.const import DOMAIN
from homeassistant.const import CONF_HOST, CONF_PASSWORD from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PASSWORD
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, load_fixture from tests.common import MockConfigEntry, load_fixture
@ -20,7 +20,11 @@ def mock_config_entry() -> MockConfigEntry:
return MockConfigEntry( return MockConfigEntry(
title="Test device", title="Test device",
domain=DOMAIN, domain=DOMAIN,
data={CONF_HOST: "127.0.0.1", CONF_PASSWORD: "mocked-password"}, data={
CONF_HOST: "127.0.0.1",
CONF_PASSWORD: "mocked-password",
CONF_MAC: "aa:bb:cc:dd:ee:ff",
},
unique_id="12345", unique_id="12345",
) )
@ -45,6 +49,7 @@ def mock_fully_kiosk_config_flow() -> Generator[MagicMock, None, None]:
client.getDeviceInfo.return_value = { client.getDeviceInfo.return_value = {
"deviceName": "Test device", "deviceName": "Test device",
"deviceID": "12345", "deviceID": "12345",
"Mac": "AA:BB:CC:DD:EE:FF",
} }
yield client yield client

View File

@ -7,9 +7,10 @@ from aiohttp.client_exceptions import ClientConnectorError
from fullykiosk import FullyKioskError from fullykiosk import FullyKioskError
import pytest import pytest
from homeassistant.components.dhcp import DhcpServiceInfo
from homeassistant.components.fully_kiosk.const import DOMAIN from homeassistant.components.fully_kiosk.const import DOMAIN
from homeassistant.config_entries import SOURCE_USER from homeassistant.config_entries import SOURCE_DHCP, SOURCE_USER
from homeassistant.const import CONF_HOST, CONF_PASSWORD from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PASSWORD
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType from homeassistant.data_entry_flow import FlowResultType
@ -42,6 +43,7 @@ async def test_full_flow(
assert result2.get("data") == { assert result2.get("data") == {
CONF_HOST: "1.1.1.1", CONF_HOST: "1.1.1.1",
CONF_PASSWORD: "test-password", CONF_PASSWORD: "test-password",
CONF_MAC: "aa:bb:cc:dd:ee:ff",
} }
assert "result" in result2 assert "result" in result2
assert result2["result"].unique_id == "12345" assert result2["result"].unique_id == "12345"
@ -95,6 +97,7 @@ async def test_errors(
assert result3.get("data") == { assert result3.get("data") == {
CONF_HOST: "1.1.1.1", CONF_HOST: "1.1.1.1",
CONF_PASSWORD: "test-password", CONF_PASSWORD: "test-password",
CONF_MAC: "aa:bb:cc:dd:ee:ff",
} }
assert "result" in result3 assert "result" in result3
assert result3["result"].unique_id == "12345" assert result3["result"].unique_id == "12345"
@ -131,6 +134,54 @@ async def test_duplicate_updates_existing_entry(
assert mock_config_entry.data == { assert mock_config_entry.data == {
CONF_HOST: "1.1.1.1", CONF_HOST: "1.1.1.1",
CONF_PASSWORD: "test-password", CONF_PASSWORD: "test-password",
CONF_MAC: "aa:bb:cc:dd:ee:ff",
} }
assert len(mock_fully_kiosk_config_flow.getDeviceInfo.mock_calls) == 1 assert len(mock_fully_kiosk_config_flow.getDeviceInfo.mock_calls) == 1
async def test_dhcp_discovery_updates_entry(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test DHCP discovery updates config entries."""
mock_config_entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_DHCP},
data=DhcpServiceInfo(
hostname="tablet",
ip="127.0.0.2",
macaddress="aa:bb:cc:dd:ee:ff",
),
)
assert result.get("type") == FlowResultType.ABORT
assert result.get("reason") == "already_configured"
assert mock_config_entry.data == {
CONF_HOST: "127.0.0.2",
CONF_PASSWORD: "mocked-password",
CONF_MAC: "aa:bb:cc:dd:ee:ff",
}
async def test_dhcp_unknown_device(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test unknown DHCP discovery aborts flow."""
mock_config_entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_DHCP},
data=DhcpServiceInfo(
hostname="tablet",
ip="127.0.0.2",
macaddress="aa:bb:cc:dd:ee:00",
),
)
assert result.get("type") == FlowResultType.ABORT
assert result.get("reason") == "unknown"