Fix device identifier in ViCare integration (#124483)
* use correct serial * add migration handler * adjust init call * add missing types * adjust init call * adjust init call * adjust init call * adjust init call * Update types.py * fix loop * fix loop * fix parameter order * align parameter naming * remove comment * correct init * update * Update types.py * correct merge * revert type change * add test case * add helper * add test case * update snapshot * add snapshot * add device.serial data point * fix device unique id * update snapshot * add comments * update nmigration * fix missing parameter * move static parameters * fix circuit access * update device.serial * update snapshots * remove test case * Update binary_sensor.py * convert climate entity * Update entity.py * update snapshot * use snake case * add migration test * enhance test case * add test case * Apply suggestions from code review --------- Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>pull/125246/head
parent
0fb1fbf0d1
commit
349ea35dc3
|
@ -15,10 +15,12 @@ from PyViCare.PyViCareUtils import (
|
|||
PyViCareInvalidCredentialsError,
|
||||
)
|
||||
|
||||
from homeassistant.components.climate import DOMAIN as DOMAIN_CLIMATE
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_CLIENT_ID, CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers.storage import STORAGE_DIR
|
||||
|
||||
from .const import (
|
||||
|
@ -47,6 +49,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
except (PyViCareInvalidConfigurationError, PyViCareInvalidCredentialsError) as err:
|
||||
raise ConfigEntryAuthFailed("Authentication failed") from err
|
||||
|
||||
for device in hass.data[DOMAIN][entry.entry_id][DEVICE_LIST]:
|
||||
# Migration can be removed in 2025.4.0
|
||||
await async_migrate_devices(hass, entry, device)
|
||||
# Migration can be removed in 2025.4.0
|
||||
await async_migrate_entities(hass, entry, device)
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
return True
|
||||
|
@ -109,6 +117,72 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
return unload_ok
|
||||
|
||||
|
||||
async def async_migrate_devices(
|
||||
hass: HomeAssistant, entry: ConfigEntry, device: ViCareDevice
|
||||
) -> None:
|
||||
"""Migrate old entry."""
|
||||
registry = dr.async_get(hass)
|
||||
|
||||
gateway_serial: str = device.config.getConfig().serial
|
||||
device_serial: str = device.api.getSerial()
|
||||
|
||||
old_identifier = gateway_serial
|
||||
new_identifier = f"{gateway_serial}_{device_serial}"
|
||||
|
||||
# Migrate devices
|
||||
for device_entry in dr.async_entries_for_config_entry(registry, entry.entry_id):
|
||||
if device_entry.identifiers == {(DOMAIN, old_identifier)}:
|
||||
_LOGGER.debug("Migrating device %s", device_entry.name)
|
||||
registry.async_update_device(
|
||||
device_entry.id,
|
||||
serial_number=device_serial,
|
||||
new_identifiers={(DOMAIN, new_identifier)},
|
||||
)
|
||||
|
||||
|
||||
async def async_migrate_entities(
|
||||
hass: HomeAssistant, entry: ConfigEntry, device: ViCareDevice
|
||||
) -> None:
|
||||
"""Migrate old entry."""
|
||||
gateway_serial: str = device.config.getConfig().serial
|
||||
device_serial: str = device.api.getSerial()
|
||||
new_identifier = f"{gateway_serial}_{device_serial}"
|
||||
|
||||
@callback
|
||||
def _update_unique_id(
|
||||
entity_entry: er.RegistryEntry,
|
||||
) -> dict[str, str] | None:
|
||||
"""Update unique ID of entity entry."""
|
||||
if not entity_entry.unique_id.startswith(gateway_serial):
|
||||
# belongs to other device/gateway
|
||||
return None
|
||||
if entity_entry.unique_id.startswith(f"{gateway_serial}_"):
|
||||
# Already correct, nothing to do
|
||||
return None
|
||||
|
||||
unique_id_parts = entity_entry.unique_id.split("-")
|
||||
unique_id_parts[0] = new_identifier
|
||||
|
||||
# convert climate entity unique id from `<device_identifier>-<circuit_no>` to `<device_identifier>-heating-<circuit_no>`
|
||||
if entity_entry.domain == DOMAIN_CLIMATE:
|
||||
unique_id_parts[len(unique_id_parts) - 1] = (
|
||||
f"{entity_entry.translation_key}-{unique_id_parts[len(unique_id_parts)-1]}"
|
||||
)
|
||||
|
||||
entity_new_unique_id = "-".join(unique_id_parts)
|
||||
|
||||
_LOGGER.debug(
|
||||
"Migrating entity %s from %s to new id %s",
|
||||
entity_entry.entity_id,
|
||||
entity_entry.unique_id,
|
||||
entity_new_unique_id,
|
||||
)
|
||||
return {"new_unique_id": entity_new_unique_id}
|
||||
|
||||
# Migrate entities
|
||||
await er.async_migrate_entries(hass, entry.entry_id, _update_unique_id)
|
||||
|
||||
|
||||
def get_supported_devices(
|
||||
devices: list[PyViCareDeviceConfig],
|
||||
) -> list[PyViCareDeviceConfig]:
|
||||
|
|
|
@ -148,10 +148,10 @@ class ViCareClimate(ViCareEntity, ClimateEntity):
|
|||
circuit: PyViCareHeatingCircuit,
|
||||
) -> None:
|
||||
"""Initialize the climate device."""
|
||||
super().__init__(circuit.id, device_config, device)
|
||||
self._circuit = circuit
|
||||
super().__init__(self._attr_translation_key, device_config, device, circuit)
|
||||
self._device = device
|
||||
self._attributes: dict[str, Any] = {}
|
||||
self._attributes["vicare_programs"] = self._circuit.getPrograms()
|
||||
self._attributes["vicare_programs"] = self._api.getPrograms()
|
||||
self._attr_preset_modes = [
|
||||
preset
|
||||
for heating_program in self._attributes["vicare_programs"]
|
||||
|
@ -163,11 +163,11 @@ class ViCareClimate(ViCareEntity, ClimateEntity):
|
|||
try:
|
||||
_room_temperature = None
|
||||
with suppress(PyViCareNotSupportedFeatureError):
|
||||
_room_temperature = self._circuit.getRoomTemperature()
|
||||
_room_temperature = self._api.getRoomTemperature()
|
||||
|
||||
_supply_temperature = None
|
||||
with suppress(PyViCareNotSupportedFeatureError):
|
||||
_supply_temperature = self._circuit.getSupplyTemperature()
|
||||
_supply_temperature = self._api.getSupplyTemperature()
|
||||
|
||||
if _room_temperature is not None:
|
||||
self._attr_current_temperature = _room_temperature
|
||||
|
@ -177,15 +177,13 @@ class ViCareClimate(ViCareEntity, ClimateEntity):
|
|||
self._attr_current_temperature = None
|
||||
|
||||
with suppress(PyViCareNotSupportedFeatureError):
|
||||
self._current_program = self._circuit.getActiveProgram()
|
||||
self._current_program = self._api.getActiveProgram()
|
||||
|
||||
with suppress(PyViCareNotSupportedFeatureError):
|
||||
self._attr_target_temperature = (
|
||||
self._circuit.getCurrentDesiredTemperature()
|
||||
)
|
||||
self._attr_target_temperature = self._api.getCurrentDesiredTemperature()
|
||||
|
||||
with suppress(PyViCareNotSupportedFeatureError):
|
||||
self._current_mode = self._circuit.getActiveMode()
|
||||
self._current_mode = self._api.getActiveMode()
|
||||
|
||||
# Update the generic device attributes
|
||||
self._attributes = {
|
||||
|
@ -196,25 +194,25 @@ class ViCareClimate(ViCareEntity, ClimateEntity):
|
|||
|
||||
with suppress(PyViCareNotSupportedFeatureError):
|
||||
self._attributes["heating_curve_slope"] = (
|
||||
self._circuit.getHeatingCurveSlope()
|
||||
self._api.getHeatingCurveSlope()
|
||||
)
|
||||
|
||||
with suppress(PyViCareNotSupportedFeatureError):
|
||||
self._attributes["heating_curve_shift"] = (
|
||||
self._circuit.getHeatingCurveShift()
|
||||
self._api.getHeatingCurveShift()
|
||||
)
|
||||
|
||||
with suppress(PyViCareNotSupportedFeatureError):
|
||||
self._attributes["vicare_modes"] = self._circuit.getModes()
|
||||
self._attributes["vicare_modes"] = self._api.getModes()
|
||||
|
||||
self._current_action = False
|
||||
# Update the specific device attributes
|
||||
with suppress(PyViCareNotSupportedFeatureError):
|
||||
for burner in get_burners(self._api):
|
||||
for burner in get_burners(self._device):
|
||||
self._current_action = self._current_action or burner.getActive()
|
||||
|
||||
with suppress(PyViCareNotSupportedFeatureError):
|
||||
for compressor in get_compressors(self._api):
|
||||
for compressor in get_compressors(self._device):
|
||||
self._current_action = (
|
||||
self._current_action or compressor.getActive()
|
||||
)
|
||||
|
@ -245,9 +243,9 @@ class ViCareClimate(ViCareEntity, ClimateEntity):
|
|||
raise ValueError(f"Cannot set invalid hvac mode: {hvac_mode}")
|
||||
|
||||
_LOGGER.debug("Setting hvac mode to %s / %s", hvac_mode, vicare_mode)
|
||||
self._circuit.setMode(vicare_mode)
|
||||
self._api.setMode(vicare_mode)
|
||||
|
||||
def vicare_mode_from_hvac_mode(self, hvac_mode):
|
||||
def vicare_mode_from_hvac_mode(self, hvac_mode) -> str | None:
|
||||
"""Return the corresponding vicare mode for an hvac_mode."""
|
||||
if "vicare_modes" not in self._attributes:
|
||||
return None
|
||||
|
@ -283,7 +281,7 @@ class ViCareClimate(ViCareEntity, ClimateEntity):
|
|||
def set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set new target temperatures."""
|
||||
if (temp := kwargs.get(ATTR_TEMPERATURE)) is not None:
|
||||
self._circuit.setProgramTemperature(self._current_program, temp)
|
||||
self._api.setProgramTemperature(self._current_program, temp)
|
||||
self._attr_target_temperature = temp
|
||||
|
||||
@property
|
||||
|
@ -312,7 +310,7 @@ class ViCareClimate(ViCareEntity, ClimateEntity):
|
|||
):
|
||||
_LOGGER.debug("deactivating %s", self._current_program)
|
||||
try:
|
||||
self._circuit.deactivateProgram(self._current_program)
|
||||
self._api.deactivateProgram(self._current_program)
|
||||
except PyViCareCommandError as err:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
|
@ -326,7 +324,7 @@ class ViCareClimate(ViCareEntity, ClimateEntity):
|
|||
if target_program in CHANGABLE_HEATING_PROGRAMS:
|
||||
_LOGGER.debug("activating %s", target_program)
|
||||
try:
|
||||
self._circuit.activateProgram(target_program)
|
||||
self._api.activateProgram(target_program)
|
||||
except PyViCareCommandError as err:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
|
@ -341,9 +339,9 @@ class ViCareClimate(ViCareEntity, ClimateEntity):
|
|||
"""Show Device Attributes."""
|
||||
return self._attributes
|
||||
|
||||
def set_vicare_mode(self, vicare_mode):
|
||||
def set_vicare_mode(self, vicare_mode) -> None:
|
||||
"""Service function to set vicare modes directly."""
|
||||
if vicare_mode not in self._attributes["vicare_modes"]:
|
||||
raise ValueError(f"Cannot set invalid vicare mode: {vicare_mode}.")
|
||||
|
||||
self._circuit.setMode(vicare_mode)
|
||||
self._api.setMode(vicare_mode)
|
||||
|
|
|
@ -25,18 +25,20 @@ class ViCareEntity(Entity):
|
|||
component: PyViCareHeatingDeviceComponent | None = None,
|
||||
) -> None:
|
||||
"""Initialize the entity."""
|
||||
gateway_serial = device_config.getConfig().serial
|
||||
device_serial = device.getSerial()
|
||||
identifier = f"{gateway_serial}_{device_serial}"
|
||||
|
||||
self._api: PyViCareDevice | PyViCareHeatingDeviceComponent = (
|
||||
component if component else device
|
||||
)
|
||||
|
||||
self._attr_unique_id = f"{device_config.getConfig().serial}-{unique_id_suffix}"
|
||||
# valid for compressors, circuits, burners (HeatingDeviceWithComponent)
|
||||
self._attr_unique_id = f"{identifier}-{unique_id_suffix}"
|
||||
if component:
|
||||
self._attr_unique_id += f"-{component.id}"
|
||||
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, device_config.getConfig().serial)},
|
||||
serial_number=device.getSerial(),
|
||||
identifiers={(DOMAIN, identifier)},
|
||||
serial_number=device_serial,
|
||||
name=device_config.getModel(),
|
||||
manufacturer="Viessmann",
|
||||
model=device_config.getModel(),
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
"properties": {
|
||||
"value": {
|
||||
"type": "string",
|
||||
"value": "################"
|
||||
"value": "deviceSerialViAir300F"
|
||||
}
|
||||
},
|
||||
"timestamp": "2024-03-20T01:29:35.549Z",
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
"properties": {
|
||||
"value": {
|
||||
"type": "string",
|
||||
"value": "################"
|
||||
"value": "deviceSerialVitodens300W"
|
||||
}
|
||||
},
|
||||
"timestamp": "2024-03-20T01:29:35.549Z",
|
||||
"timestamp": "2024-07-30T20:03:40.073Z",
|
||||
"uri": "https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/devices/0/features/device.serial"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'burner',
|
||||
'unique_id': 'gateway0-burner_active-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-burner_active-0',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -75,7 +75,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'circulation_pump',
|
||||
'unique_id': 'gateway0-circulationpump_active-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-circulationpump_active-0',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -122,7 +122,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'circulation_pump',
|
||||
'unique_id': 'gateway0-circulationpump_active-1',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-circulationpump_active-1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -169,7 +169,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'domestic_hot_water_charging',
|
||||
'unique_id': 'gateway0-charging_active',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-charging_active',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -216,7 +216,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'domestic_hot_water_circulation_pump',
|
||||
'unique_id': 'gateway0-dhw_circulationpump_active',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-dhw_circulationpump_active',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -263,7 +263,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'domestic_hot_water_pump',
|
||||
'unique_id': 'gateway0-dhw_pump_active',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-dhw_pump_active',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -310,7 +310,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'frost_protection',
|
||||
'unique_id': 'gateway0-frost_protection_active-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-frost_protection_active-0',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -356,7 +356,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'frost_protection',
|
||||
'unique_id': 'gateway0-frost_protection_active-1',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-frost_protection_active-1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'activate_onetimecharge',
|
||||
'unique_id': 'gateway0-activate_onetimecharge',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-activate_onetimecharge',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'translation_key': 'heating',
|
||||
'unique_id': 'gateway0-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-heating-0',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -123,7 +123,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'translation_key': 'heating',
|
||||
'unique_id': 'gateway0-1',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-heating-1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
'properties': dict({
|
||||
'value': dict({
|
||||
'type': 'string',
|
||||
'value': '################',
|
||||
'value': 'deviceSerialVitodens300W',
|
||||
}),
|
||||
}),
|
||||
'timestamp': '2024-03-20T01:29:35.549Z',
|
||||
'timestamp': '2024-07-30T20:03:40.073Z',
|
||||
'uri': 'https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/devices/0/features/device.serial',
|
||||
}),
|
||||
dict({
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': <FanEntityFeature: 9>,
|
||||
'translation_key': 'ventilation',
|
||||
'unique_id': 'gateway0-ventilation',
|
||||
'unique_id': 'gateway0_deviceSerialViAir300F-ventilation',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'comfort_temperature',
|
||||
'unique_id': 'gateway0-comfort_temperature-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-comfort_temperature-0',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -90,7 +90,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'comfort_temperature',
|
||||
'unique_id': 'gateway0-comfort_temperature-1',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-comfort_temperature-1',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -147,7 +147,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'heating_curve_shift',
|
||||
'unique_id': 'gateway0-heating curve shift-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-heating curve shift-0',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -204,7 +204,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'heating_curve_shift',
|
||||
'unique_id': 'gateway0-heating curve shift-1',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-heating curve shift-1',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -261,7 +261,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'heating_curve_slope',
|
||||
'unique_id': 'gateway0-heating curve slope-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-heating curve slope-0',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -316,7 +316,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'heating_curve_slope',
|
||||
'unique_id': 'gateway0-heating curve slope-1',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-heating curve slope-1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -371,7 +371,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'normal_temperature',
|
||||
'unique_id': 'gateway0-normal_temperature-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-normal_temperature-0',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -428,7 +428,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'normal_temperature',
|
||||
'unique_id': 'gateway0-normal_temperature-1',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-normal_temperature-1',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -485,7 +485,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'reduced_temperature',
|
||||
'unique_id': 'gateway0-reduced_temperature-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-reduced_temperature-0',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -542,7 +542,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'reduced_temperature',
|
||||
'unique_id': 'gateway0-reduced_temperature-1',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-reduced_temperature-1',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -599,7 +599,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'dhw_temperature',
|
||||
'unique_id': 'gateway0-dhw_temperature',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-dhw_temperature',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'boiler_temperature',
|
||||
'unique_id': 'gateway0-boiler_temperature',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-boiler_temperature',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -81,7 +81,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'burner_hours',
|
||||
'unique_id': 'gateway0-burner_hours-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-burner_hours-0',
|
||||
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -131,7 +131,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'burner_modulation',
|
||||
'unique_id': 'gateway0-burner_modulation-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-burner_modulation-0',
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
|
@ -181,7 +181,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'burner_starts',
|
||||
'unique_id': 'gateway0-burner_starts-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-burner_starts-0',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -230,7 +230,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'hotwater_gas_consumption_heating_this_month',
|
||||
'unique_id': 'gateway0-hotwater_gas_consumption_heating_this_month',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-hotwater_gas_consumption_heating_this_month',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -279,7 +279,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'hotwater_gas_consumption_heating_this_week',
|
||||
'unique_id': 'gateway0-hotwater_gas_consumption_heating_this_week',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-hotwater_gas_consumption_heating_this_week',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -328,7 +328,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'hotwater_gas_consumption_heating_this_year',
|
||||
'unique_id': 'gateway0-hotwater_gas_consumption_heating_this_year',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-hotwater_gas_consumption_heating_this_year',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -377,7 +377,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'hotwater_gas_consumption_today',
|
||||
'unique_id': 'gateway0-hotwater_gas_consumption_today',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-hotwater_gas_consumption_today',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -426,7 +426,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'hotwater_max_temperature',
|
||||
'unique_id': 'gateway0-hotwater_max_temperature',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-hotwater_max_temperature',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -477,7 +477,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'hotwater_min_temperature',
|
||||
'unique_id': 'gateway0-hotwater_min_temperature',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-hotwater_min_temperature',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -528,7 +528,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'power consumption this month',
|
||||
'unique_id': 'gateway0-power consumption this month',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-power consumption this month',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -579,7 +579,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'power_consumption_this_year',
|
||||
'unique_id': 'gateway0-power consumption this year',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-power consumption this year',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -630,7 +630,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'power_consumption_today',
|
||||
'unique_id': 'gateway0-power consumption today',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-power consumption today',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -681,7 +681,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'gas_consumption_heating_this_month',
|
||||
'unique_id': 'gateway0-gas_consumption_heating_this_month',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-gas_consumption_heating_this_month',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -730,7 +730,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'gas_consumption_heating_this_week',
|
||||
'unique_id': 'gateway0-gas_consumption_heating_this_week',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-gas_consumption_heating_this_week',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -779,7 +779,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'gas_consumption_heating_this_year',
|
||||
'unique_id': 'gateway0-gas_consumption_heating_this_year',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-gas_consumption_heating_this_year',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -828,7 +828,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'gas_consumption_heating_today',
|
||||
'unique_id': 'gateway0-gas_consumption_heating_today',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-gas_consumption_heating_today',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -877,7 +877,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'outside_temperature',
|
||||
'unique_id': 'gateway0-outside_temperature',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-outside_temperature',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -928,7 +928,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'power_consumption_this_week',
|
||||
'unique_id': 'gateway0-power consumption this week',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-power consumption this week',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -979,7 +979,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'supply_temperature',
|
||||
'unique_id': 'gateway0-supply_temperature-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-supply_temperature-0',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
@ -1030,7 +1030,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'supply_temperature',
|
||||
'unique_id': 'gateway0-supply_temperature-1',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-supply_temperature-1',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': <WaterHeaterEntityFeature: 1>,
|
||||
'translation_key': 'domestic_hot_water',
|
||||
'unique_id': 'gateway0-0',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-0',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
@ -87,7 +87,7 @@
|
|||
'previous_unique_id': None,
|
||||
'supported_features': <WaterHeaterEntityFeature: 1>,
|
||||
'translation_key': 'domestic_hot_water',
|
||||
'unique_id': 'gateway0-1',
|
||||
'unique_id': 'gateway0_deviceSerialVitodens300W-1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
"""Test ViCare migration."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.vicare.const import DOMAIN
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
|
||||
from . import MODULE
|
||||
from .conftest import Fixture, MockPyViCare
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
# Device migration test can be removed in 2025.4.0
|
||||
async def test_device_migration(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test that the device registry is updated correctly."""
|
||||
fixtures: list[Fixture] = [Fixture({"type:boiler"}, "vicare/Vitodens300W.json")]
|
||||
with (
|
||||
patch(f"{MODULE}.vicare_login", return_value=MockPyViCare(fixtures)),
|
||||
patch(f"{MODULE}.PLATFORMS", [Platform.CLIMATE]),
|
||||
):
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
device_registry.async_get_or_create(
|
||||
config_entry_id=mock_config_entry.entry_id,
|
||||
identifiers={
|
||||
(DOMAIN, "gateway0"),
|
||||
},
|
||||
)
|
||||
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert device_registry.async_get_device(identifiers={(DOMAIN, "gateway0")}) is None
|
||||
|
||||
assert (
|
||||
device_registry.async_get_device(
|
||||
identifiers={(DOMAIN, "gateway0_deviceSerialVitodens300W")}
|
||||
)
|
||||
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,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test that the climate entity unique_id gets migrated correctly."""
|
||||
fixtures: list[Fixture] = [Fixture({"type:boiler"}, "vicare/Vitodens300W.json")]
|
||||
with (
|
||||
patch(f"{MODULE}.vicare_login", return_value=MockPyViCare(fixtures)),
|
||||
patch(f"{MODULE}.PLATFORMS", [Platform.CLIMATE]),
|
||||
):
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
entry1 = entity_registry.async_get_or_create(
|
||||
domain=Platform.CLIMATE,
|
||||
platform=DOMAIN,
|
||||
config_entry=mock_config_entry,
|
||||
unique_id="gateway0-0",
|
||||
translation_key="heating",
|
||||
)
|
||||
entry2 = entity_registry.async_get_or_create(
|
||||
domain=Platform.CLIMATE,
|
||||
platform=DOMAIN,
|
||||
config_entry=mock_config_entry,
|
||||
unique_id="gateway0_deviceSerialVitodens300W-heating-1",
|
||||
translation_key="heating",
|
||||
)
|
||||
entry3 = entity_registry.async_get_or_create(
|
||||
domain=Platform.CLIMATE,
|
||||
platform=DOMAIN,
|
||||
config_entry=mock_config_entry,
|
||||
unique_id="gateway1-0",
|
||||
translation_key="heating",
|
||||
)
|
||||
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert (
|
||||
entity_registry.async_get(entry1.entity_id).unique_id
|
||||
== "gateway0_deviceSerialVitodens300W-heating-0"
|
||||
)
|
||||
assert (
|
||||
entity_registry.async_get(entry2.entity_id).unique_id
|
||||
== "gateway0_deviceSerialVitodens300W-heating-1"
|
||||
)
|
||||
assert entity_registry.async_get(entry3.entity_id).unique_id == "gateway1-0"
|
Loading…
Reference in New Issue