From 666b908242254c5132ba3d211dc4e6c173cc5e51 Mon Sep 17 00:00:00 2001 From: Josef Zweck <24647999+zweckj@users.noreply.github.com> Date: Tue, 26 Nov 2024 10:57:46 +0100 Subject: [PATCH] Allow dhcp discovery to update host for lamarzocco (#131047) --- .../components/lamarzocco/config_flow.py | 9 +++++- homeassistant/components/lamarzocco/entity.py | 14 +++++++- .../components/lamarzocco/manifest.json | 3 ++ .../components/lamarzocco/quality_scale.yaml | 2 +- homeassistant/generated/dhcp.py | 4 +++ tests/components/lamarzocco/conftest.py | 9 +++++- .../lamarzocco/snapshots/test_switch.ambr | 4 +++ .../components/lamarzocco/test_config_flow.py | 32 +++++++++++++++++++ tests/components/lamarzocco/test_init.py | 26 +++++++++++---- 9 files changed, 92 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/lamarzocco/config_flow.py b/homeassistant/components/lamarzocco/config_flow.py index b81fc8f9e4b..0f288e22c4a 100644 --- a/homeassistant/components/lamarzocco/config_flow.py +++ b/homeassistant/components/lamarzocco/config_flow.py @@ -26,6 +26,7 @@ from homeassistant.config_entries import ( OptionsFlow, ) from homeassistant.const import ( + CONF_ADDRESS, CONF_HOST, CONF_MAC, CONF_MODEL, @@ -284,7 +285,12 @@ class LmConfigFlow(ConfigFlow, domain=DOMAIN): serial = discovery_info.hostname.upper() await self.async_set_unique_id(serial) - self._abort_if_unique_id_configured() + self._abort_if_unique_id_configured( + updates={ + CONF_HOST: discovery_info.ip, + CONF_ADDRESS: discovery_info.macaddress, + } + ) _LOGGER.debug( "Discovered La Marzocco machine %s through DHCP at address %s", @@ -294,6 +300,7 @@ class LmConfigFlow(ConfigFlow, domain=DOMAIN): self._discovered[CONF_MACHINE] = serial self._discovered[CONF_HOST] = discovery_info.ip + self._discovered[CONF_ADDRESS] = discovery_info.macaddress return await self.async_step_user() diff --git a/homeassistant/components/lamarzocco/entity.py b/homeassistant/components/lamarzocco/entity.py index 1ea84302a17..f0942f51ace 100644 --- a/homeassistant/components/lamarzocco/entity.py +++ b/homeassistant/components/lamarzocco/entity.py @@ -6,7 +6,8 @@ from dataclasses import dataclass from pylamarzocco.const import FirmwareType from pylamarzocco.lm_machine import LaMarzoccoMachine -from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.const import CONF_ADDRESS +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo from homeassistant.helpers.entity import EntityDescription from homeassistant.helpers.update_coordinator import CoordinatorEntity @@ -47,6 +48,17 @@ class LaMarzoccoBaseEntity( serial_number=device.serial_number, sw_version=device.firmware[FirmwareType.MACHINE].current_version, ) + if coordinator.config_entry.data.get(CONF_ADDRESS): + self._attr_device_info.update( + DeviceInfo( + connections={ + ( + CONNECTION_NETWORK_MAC, + coordinator.config_entry.data[CONF_ADDRESS], + ) + } + ) + ) class LaMarzoccoEntity(LaMarzoccoBaseEntity): diff --git a/homeassistant/components/lamarzocco/manifest.json b/homeassistant/components/lamarzocco/manifest.json index 4aef30a5c26..a71da7c4754 100644 --- a/homeassistant/components/lamarzocco/manifest.json +++ b/homeassistant/components/lamarzocco/manifest.json @@ -19,6 +19,9 @@ "config_flow": true, "dependencies": ["bluetooth_adapters"], "dhcp": [ + { + "registered_devices": true + }, { "hostname": "gs[0-9][0-9][0-9][0-9][0-9][0-9]" }, diff --git a/homeassistant/components/lamarzocco/quality_scale.yaml b/homeassistant/components/lamarzocco/quality_scale.yaml index 3cea45539c9..3677bd8d6b8 100644 --- a/homeassistant/components/lamarzocco/quality_scale.yaml +++ b/homeassistant/components/lamarzocco/quality_scale.yaml @@ -49,7 +49,7 @@ rules: # Gold devices: done diagnostics: done - discovery-update-info: todo + discovery-update-info: done discovery: status: done comment: | diff --git a/homeassistant/generated/dhcp.py b/homeassistant/generated/dhcp.py index 7dacf9a0bca..1ef91841db8 100644 --- a/homeassistant/generated/dhcp.py +++ b/homeassistant/generated/dhcp.py @@ -276,6 +276,10 @@ DHCP: Final[list[dict[str, str | bool]]] = [ "hostname": "polisy*", "macaddress": "000DB9*", }, + { + "domain": "lamarzocco", + "registered_devices": True, + }, { "domain": "lamarzocco", "hostname": "gs[0-9][0-9][0-9][0-9][0-9][0-9]", diff --git a/tests/components/lamarzocco/conftest.py b/tests/components/lamarzocco/conftest.py index 9c568962e34..d6d59cf9ebc 100644 --- a/tests/components/lamarzocco/conftest.py +++ b/tests/components/lamarzocco/conftest.py @@ -11,7 +11,13 @@ from pylamarzocco.models import LaMarzoccoDeviceInfo import pytest from homeassistant.components.lamarzocco.const import DOMAIN -from homeassistant.const import CONF_HOST, CONF_MODEL, CONF_NAME, CONF_TOKEN +from homeassistant.const import ( + CONF_ADDRESS, + CONF_HOST, + CONF_MODEL, + CONF_NAME, + CONF_TOKEN, +) from homeassistant.core import HomeAssistant from . import SERIAL_DICT, USER_INPUT, async_init_integration @@ -40,6 +46,7 @@ def mock_config_entry( data=USER_INPUT | { CONF_MODEL: mock_lamarzocco.model, + CONF_ADDRESS: "00:00:00:00:00:00", CONF_HOST: "host", CONF_TOKEN: "token", CONF_NAME: "GS3", diff --git a/tests/components/lamarzocco/snapshots/test_switch.ambr b/tests/components/lamarzocco/snapshots/test_switch.ambr index 5e3b99da617..084b54b3f3a 100644 --- a/tests/components/lamarzocco/snapshots/test_switch.ambr +++ b/tests/components/lamarzocco/snapshots/test_switch.ambr @@ -97,6 +97,10 @@ 'config_entries': , 'configuration_url': None, 'connections': set({ + tuple( + 'mac', + '00:00:00:00:00:00', + ), }), 'disabled_by': None, 'entry_type': None, diff --git a/tests/components/lamarzocco/test_config_flow.py b/tests/components/lamarzocco/test_config_flow.py index 516fb1db31a..f8103ac3054 100644 --- a/tests/components/lamarzocco/test_config_flow.py +++ b/tests/components/lamarzocco/test_config_flow.py @@ -18,6 +18,7 @@ from homeassistant.config_entries import ( ConfigEntryState, ) from homeassistant.const import ( + CONF_ADDRESS, CONF_HOST, CONF_MAC, CONF_MODEL, @@ -483,6 +484,7 @@ async def test_dhcp_discovery( assert result2["type"] is FlowResultType.CREATE_ENTRY assert result2["data"] == { **USER_INPUT, + CONF_ADDRESS: "aa:bb:cc:dd:ee:ff", CONF_HOST: "192.168.1.42", CONF_MACHINE: mock_lamarzocco.serial_number, CONF_MODEL: mock_device_info.model, @@ -491,6 +493,36 @@ async def test_dhcp_discovery( } +async def test_dhcp_already_configured_and_update( + hass: HomeAssistant, + mock_lamarzocco: MagicMock, + mock_cloud_client: MagicMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test discovered IP address change.""" + old_ip = mock_config_entry.data[CONF_HOST] + old_address = mock_config_entry.data[CONF_ADDRESS] + + mock_config_entry.add_to_hass(hass) + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_DHCP}, + data=DhcpServiceInfo( + ip="192.168.1.42", + hostname=mock_lamarzocco.serial_number, + macaddress="aa:bb:cc:dd:ee:ff", + ), + ) + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "already_configured" + + assert mock_config_entry.data[CONF_HOST] != old_ip + assert mock_config_entry.data[CONF_HOST] == "192.168.1.42" + + assert mock_config_entry.data[CONF_ADDRESS] != old_address + assert mock_config_entry.data[CONF_ADDRESS] == "aa:bb:cc:dd:ee:ff" + + async def test_options_flow( hass: HomeAssistant, mock_lamarzocco: MagicMock, diff --git a/tests/components/lamarzocco/test_init.py b/tests/components/lamarzocco/test_init.py index 5ef0eca13af..75c3019afb4 100644 --- a/tests/components/lamarzocco/test_init.py +++ b/tests/components/lamarzocco/test_init.py @@ -10,7 +10,14 @@ from websockets.protocol import State from homeassistant.components.lamarzocco.config_flow import CONF_MACHINE from homeassistant.components.lamarzocco.const import DOMAIN from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState -from homeassistant.const import CONF_HOST, CONF_MAC, CONF_NAME, EVENT_HOMEASSISTANT_STOP +from homeassistant.const import ( + CONF_HOST, + CONF_MAC, + CONF_MODEL, + CONF_NAME, + CONF_TOKEN, + EVENT_HOMEASSISTANT_STOP, +) from homeassistant.core import HomeAssistant from homeassistant.helpers import issue_registry as ir @@ -81,20 +88,22 @@ async def test_invalid_auth( async def test_v1_migration( hass: HomeAssistant, - mock_config_entry: MockConfigEntry, mock_cloud_client: MagicMock, mock_lamarzocco: MagicMock, ) -> None: """Test v1 -> v2 Migration.""" + common_data = { + **USER_INPUT, + CONF_HOST: "host", + CONF_MAC: "aa:bb:cc:dd:ee:ff", + } entry_v1 = MockConfigEntry( domain=DOMAIN, version=1, unique_id=mock_lamarzocco.serial_number, data={ - **USER_INPUT, - CONF_HOST: "host", + **common_data, CONF_MACHINE: mock_lamarzocco.serial_number, - CONF_MAC: "aa:bb:cc:dd:ee:ff", }, ) @@ -103,8 +112,11 @@ async def test_v1_migration( await hass.async_block_till_done() assert entry_v1.version == 2 - assert dict(entry_v1.data) == dict(mock_config_entry.data) | { - CONF_MAC: "aa:bb:cc:dd:ee:ff" + assert dict(entry_v1.data) == { + **common_data, + CONF_NAME: "GS3", + CONF_MODEL: mock_lamarzocco.model, + CONF_TOKEN: "token", }