diff --git a/homeassistant/components/opentherm_gw/__init__.py b/homeassistant/components/opentherm_gw/__init__.py index f0f5c709d0c..d8c352f3768 100644 --- a/homeassistant/components/opentherm_gw/__init__.py +++ b/homeassistant/components/opentherm_gw/__init__.py @@ -9,6 +9,7 @@ import pyotgw.vars as gw_vars from serial import SerialException import voluptuous as vol +from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import ( ATTR_DATE, @@ -27,7 +28,11 @@ from homeassistant.const import ( ) from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.exceptions import ConfigEntryNotReady -from homeassistant.helpers import config_validation as cv, device_registry as dr +from homeassistant.helpers import ( + config_validation as cv, + device_registry as dr, + entity_registry as er, +) from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.typing import ConfigType @@ -132,6 +137,18 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b }, ) + # Migration can be removed in 2025.4.0 + ent_reg = er.async_get(hass) + if ( + entity_id := ent_reg.async_get_entity_id( + CLIMATE_DOMAIN, DOMAIN, config_entry.data[CONF_ID] + ) + ) is not None: + ent_reg.async_update_entity( + entity_id, + new_unique_id=f"{config_entry.data[CONF_ID]}-{OpenThermDeviceIdentifier.THERMOSTAT}-thermostat_entity", + ) + config_entry.add_update_listener(options_updated) try: diff --git a/homeassistant/components/opentherm_gw/climate.py b/homeassistant/components/opentherm_gw/climate.py index 795a508be12..45f1ca478f5 100644 --- a/homeassistant/components/opentherm_gw/climate.py +++ b/homeassistant/components/opentherm_gw/climate.py @@ -103,7 +103,6 @@ class OpenThermClimate(OpenThermEntity, ClimateEntity): self._attr_precision = options[CONF_READ_PRECISION] self._attr_target_temperature_step = options.get(CONF_SET_PRECISION) self.temporary_ovrd_mode = options.get(CONF_TEMPORARY_OVRD_MODE, True) - self._attr_unique_id = gw_hub.hub_id @callback def update_options(self, entry): diff --git a/tests/components/opentherm_gw/test_init.py b/tests/components/opentherm_gw/test_init.py index 7b9801c8280..ed829cb1986 100644 --- a/tests/components/opentherm_gw/test_init.py +++ b/tests/components/opentherm_gw/test_init.py @@ -12,7 +12,7 @@ from homeassistant.components.opentherm_gw.const import ( ) from homeassistant.const import CONF_DEVICE, CONF_ID, CONF_NAME from homeassistant.core import HomeAssistant -from homeassistant.helpers import device_registry as dr +from homeassistant.helpers import device_registry as dr, entity_registry as er from tests.common import MockConfigEntry @@ -154,3 +154,36 @@ async def test_device_migration( ) is not None ) + + +# Entity migration test can be removed in 2025.4.0 +async def test_climate_entity_migration( + hass: HomeAssistant, entity_registry: er.EntityRegistry +) -> None: + """Test that the climate entity unique_id gets migrated correctly.""" + MOCK_CONFIG_ENTRY.add_to_hass(hass) + entry = entity_registry.async_get_or_create( + domain="climate", + platform="opentherm_gw", + unique_id=MOCK_CONFIG_ENTRY.data[CONF_ID], + ) + + with ( + patch( + "homeassistant.components.opentherm_gw.OpenThermGateway", + return_value=MagicMock( + connect=AsyncMock(return_value=MINIMAL_STATUS_UPD), + set_control_setpoint=AsyncMock(), + set_max_relative_mod=AsyncMock(), + disconnect=AsyncMock(), + ), + ), + ): + await setup.async_setup_component(hass, DOMAIN, {}) + + await hass.async_block_till_done() + + assert ( + entity_registry.async_get(entry.entity_id).unique_id + == f"{MOCK_CONFIG_ENTRY.data[CONF_ID]}-{OpenThermDeviceIdentifier.THERMOSTAT}-thermostat_entity" + )