mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 02:07:09 +00:00
Add support for externally connected utility devices in HomeWizard (#100684)
* Backport code from #86386 * Add tests * Remove local dev change * Implement device class validation based on unit * Swap sensor and externalsensor classes (based on importance) * Use translations for external sensor entities * Re-add meter identifier as sensor for external devices * Add migration for Gas identifier * Rename HomeWizardExternalIdentifierSensorEntity class * Fix all existing tests * Reimplement tests for extenal devices with smapshots * Remove non-used 'None' type in unit * Add migration test * Clean up parameterize * Add test to fix last coverage issue * Fix non-frozen mypy issue * Set device name via added EntityDescription field * Remove device key translations for external sensors, * Bring back translation keys * Set device unique_id as serial number * Remove meter identifier sensor * Simplify external device initialization * Adjust tests * Remove unused gas_meter_id migration * Remove external_devices redaction * Remove old gas meter id sensor after migration
This commit is contained in:
parent
c54b65fdf0
commit
0c9a30ab69
@ -5,9 +5,10 @@ from collections.abc import Callable
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
from homewizard_energy.models import Data
|
from homewizard_energy.models import Data, ExternalDevice
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
|
DEVICE_CLASS_UNITS,
|
||||||
SensorDeviceClass,
|
SensorDeviceClass,
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
SensorEntityDescription,
|
SensorEntityDescription,
|
||||||
@ -15,8 +16,10 @@ from homeassistant.components.sensor import (
|
|||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
ATTR_VIA_DEVICE,
|
||||||
PERCENTAGE,
|
PERCENTAGE,
|
||||||
EntityCategory,
|
EntityCategory,
|
||||||
|
Platform,
|
||||||
UnitOfElectricCurrent,
|
UnitOfElectricCurrent,
|
||||||
UnitOfElectricPotential,
|
UnitOfElectricPotential,
|
||||||
UnitOfEnergy,
|
UnitOfEnergy,
|
||||||
@ -25,6 +28,8 @@ from homeassistant.const import (
|
|||||||
UnitOfVolume,
|
UnitOfVolume,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
from homeassistant.helpers.device_registry import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import StateType
|
from homeassistant.helpers.typing import StateType
|
||||||
|
|
||||||
@ -44,6 +49,14 @@ class HomeWizardSensorEntityDescription(SensorEntityDescription):
|
|||||||
value_fn: Callable[[Data], StateType]
|
value_fn: Callable[[Data], StateType]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, kw_only=True)
|
||||||
|
class HomeWizardExternalSensorEntityDescription(SensorEntityDescription):
|
||||||
|
"""Class describing HomeWizard sensor entities."""
|
||||||
|
|
||||||
|
suggested_device_class: SensorDeviceClass
|
||||||
|
device_name: str
|
||||||
|
|
||||||
|
|
||||||
SENSORS: Final[tuple[HomeWizardSensorEntityDescription, ...]] = (
|
SENSORS: Final[tuple[HomeWizardSensorEntityDescription, ...]] = (
|
||||||
HomeWizardSensorEntityDescription(
|
HomeWizardSensorEntityDescription(
|
||||||
key="smr_version",
|
key="smr_version",
|
||||||
@ -378,22 +391,6 @@ SENSORS: Final[tuple[HomeWizardSensorEntityDescription, ...]] = (
|
|||||||
has_fn=lambda data: data.monthly_power_peak_w is not None,
|
has_fn=lambda data: data.monthly_power_peak_w is not None,
|
||||||
value_fn=lambda data: data.monthly_power_peak_w,
|
value_fn=lambda data: data.monthly_power_peak_w,
|
||||||
),
|
),
|
||||||
HomeWizardSensorEntityDescription(
|
|
||||||
key="total_gas_m3",
|
|
||||||
translation_key="total_gas_m3",
|
|
||||||
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
|
|
||||||
device_class=SensorDeviceClass.GAS,
|
|
||||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
|
||||||
has_fn=lambda data: data.total_gas_m3 is not None,
|
|
||||||
value_fn=lambda data: data.total_gas_m3,
|
|
||||||
),
|
|
||||||
HomeWizardSensorEntityDescription(
|
|
||||||
key="gas_unique_id",
|
|
||||||
translation_key="gas_unique_id",
|
|
||||||
entity_category=EntityCategory.DIAGNOSTIC,
|
|
||||||
has_fn=lambda data: data.gas_unique_id is not None,
|
|
||||||
value_fn=lambda data: data.gas_unique_id,
|
|
||||||
),
|
|
||||||
HomeWizardSensorEntityDescription(
|
HomeWizardSensorEntityDescription(
|
||||||
key="active_liter_lpm",
|
key="active_liter_lpm",
|
||||||
translation_key="active_liter_lpm",
|
translation_key="active_liter_lpm",
|
||||||
@ -414,16 +411,86 @@ SENSORS: Final[tuple[HomeWizardSensorEntityDescription, ...]] = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
EXTERNAL_SENSORS = {
|
||||||
|
ExternalDevice.DeviceType.GAS_METER: HomeWizardExternalSensorEntityDescription(
|
||||||
|
key="gas_meter",
|
||||||
|
translation_key="total_gas_m3",
|
||||||
|
suggested_device_class=SensorDeviceClass.GAS,
|
||||||
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
|
device_name="Gas meter",
|
||||||
|
),
|
||||||
|
ExternalDevice.DeviceType.HEAT_METER: HomeWizardExternalSensorEntityDescription(
|
||||||
|
key="heat_meter",
|
||||||
|
translation_key="total_energy_gj",
|
||||||
|
suggested_device_class=SensorDeviceClass.ENERGY,
|
||||||
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
|
device_name="Heat meter",
|
||||||
|
),
|
||||||
|
ExternalDevice.DeviceType.WARM_WATER_METER: HomeWizardExternalSensorEntityDescription(
|
||||||
|
key="warm_water_meter",
|
||||||
|
translation_key="total_liter_m3",
|
||||||
|
suggested_device_class=SensorDeviceClass.WATER,
|
||||||
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
|
device_name="Warm water meter",
|
||||||
|
),
|
||||||
|
ExternalDevice.DeviceType.WATER_METER: HomeWizardExternalSensorEntityDescription(
|
||||||
|
key="water_meter",
|
||||||
|
translation_key="total_liter_m3",
|
||||||
|
suggested_device_class=SensorDeviceClass.WATER,
|
||||||
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
|
device_name="Water meter",
|
||||||
|
),
|
||||||
|
ExternalDevice.DeviceType.INLET_HEAT_METER: HomeWizardExternalSensorEntityDescription(
|
||||||
|
key="inlet_heat_meter",
|
||||||
|
translation_key="total_energy_gj",
|
||||||
|
suggested_device_class=SensorDeviceClass.ENERGY,
|
||||||
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
|
device_name="Inlet heat meter",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize sensors."""
|
"""Initialize sensors."""
|
||||||
coordinator: HWEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
coordinator: HWEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
||||||
async_add_entities(
|
|
||||||
|
# Migrate original gas meter sensor to ExternalDevice
|
||||||
|
ent_reg = er.async_get(hass)
|
||||||
|
|
||||||
|
if (
|
||||||
|
entity_id := ent_reg.async_get_entity_id(
|
||||||
|
Platform.SENSOR, DOMAIN, f"{entry.unique_id}_total_gas_m3"
|
||||||
|
)
|
||||||
|
) and coordinator.data.data.gas_unique_id is not None:
|
||||||
|
ent_reg.async_update_entity(
|
||||||
|
entity_id,
|
||||||
|
new_unique_id=f"{DOMAIN}_{coordinator.data.data.gas_unique_id}",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Remove old gas_unique_id sensor
|
||||||
|
if entity_id := ent_reg.async_get_entity_id(
|
||||||
|
Platform.SENSOR, DOMAIN, f"{entry.unique_id}_gas_unique_id"
|
||||||
|
):
|
||||||
|
ent_reg.async_remove(entity_id)
|
||||||
|
|
||||||
|
# Initialize default sensors
|
||||||
|
entities: list = [
|
||||||
HomeWizardSensorEntity(coordinator, description)
|
HomeWizardSensorEntity(coordinator, description)
|
||||||
for description in SENSORS
|
for description in SENSORS
|
||||||
if description.has_fn(coordinator.data.data)
|
if description.has_fn(coordinator.data.data)
|
||||||
)
|
]
|
||||||
|
|
||||||
|
# Initialize external devices
|
||||||
|
if coordinator.data.data.external_devices is not None:
|
||||||
|
for unique_id, device in coordinator.data.data.external_devices.items():
|
||||||
|
if description := EXTERNAL_SENSORS.get(device.meter_type):
|
||||||
|
entities.append(
|
||||||
|
HomeWizardExternalSensorEntity(coordinator, description, unique_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
class HomeWizardSensorEntity(HomeWizardEntity, SensorEntity):
|
class HomeWizardSensorEntity(HomeWizardEntity, SensorEntity):
|
||||||
@ -452,3 +519,74 @@ class HomeWizardSensorEntity(HomeWizardEntity, SensorEntity):
|
|||||||
def available(self) -> bool:
|
def available(self) -> bool:
|
||||||
"""Return availability of meter."""
|
"""Return availability of meter."""
|
||||||
return super().available and self.native_value is not None
|
return super().available and self.native_value is not None
|
||||||
|
|
||||||
|
|
||||||
|
class HomeWizardExternalSensorEntity(HomeWizardEntity, SensorEntity):
|
||||||
|
"""Representation of externally connected HomeWizard Sensor."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: HWEnergyDeviceUpdateCoordinator,
|
||||||
|
description: HomeWizardExternalSensorEntityDescription,
|
||||||
|
device_unique_id: str,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize Externally connected HomeWizard Sensors."""
|
||||||
|
super().__init__(coordinator)
|
||||||
|
self.entity_description = description
|
||||||
|
self._device_id = device_unique_id
|
||||||
|
self._suggested_device_class = description.suggested_device_class
|
||||||
|
self._attr_unique_id = f"{DOMAIN}_{device_unique_id}"
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
identifiers={(DOMAIN, device_unique_id)},
|
||||||
|
name=description.device_name,
|
||||||
|
manufacturer="HomeWizard",
|
||||||
|
model=coordinator.data.device.product_type,
|
||||||
|
serial_number=device_unique_id,
|
||||||
|
)
|
||||||
|
if coordinator.data.device.serial is not None:
|
||||||
|
self._attr_device_info[ATTR_VIA_DEVICE] = (
|
||||||
|
DOMAIN,
|
||||||
|
coordinator.data.device.serial,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def native_value(self) -> float | int | str | None:
|
||||||
|
"""Return the sensor value."""
|
||||||
|
return self.device.value if self.device is not None else None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device(self) -> ExternalDevice | None:
|
||||||
|
"""Return ExternalDevice object."""
|
||||||
|
return (
|
||||||
|
self.coordinator.data.data.external_devices[self._device_id]
|
||||||
|
if self.coordinator.data.data.external_devices is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self) -> bool:
|
||||||
|
"""Return availability of meter."""
|
||||||
|
return super().available and self.device is not None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def native_unit_of_measurement(self) -> str | None:
|
||||||
|
"""Return unit of measurement based on device unit."""
|
||||||
|
if (device := self.device) is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# API returns 'm3' but we expect m³
|
||||||
|
if device.unit == "m3":
|
||||||
|
return UnitOfVolume.CUBIC_METERS
|
||||||
|
|
||||||
|
return device.unit
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_class(self) -> SensorDeviceClass | None:
|
||||||
|
"""Validate unit of measurement and set device class."""
|
||||||
|
if (
|
||||||
|
self.native_unit_of_measurement
|
||||||
|
not in DEVICE_CLASS_UNITS[self._suggested_device_class]
|
||||||
|
):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self._suggested_device_class
|
||||||
|
@ -149,14 +149,17 @@
|
|||||||
"total_gas_m3": {
|
"total_gas_m3": {
|
||||||
"name": "Total gas"
|
"name": "Total gas"
|
||||||
},
|
},
|
||||||
"gas_unique_id": {
|
"meter_identifier": {
|
||||||
"name": "Gas meter identifier"
|
"name": "Meter identifier"
|
||||||
},
|
},
|
||||||
"active_liter_lpm": {
|
"active_liter_lpm": {
|
||||||
"name": "Active water usage"
|
"name": "Active water usage"
|
||||||
},
|
},
|
||||||
"total_liter_m3": {
|
"total_liter_m3": {
|
||||||
"name": "Total water usage"
|
"name": "Total water usage"
|
||||||
|
},
|
||||||
|
"total_energy_gj": {
|
||||||
|
"name": "Total heat energy"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"switch": {
|
"switch": {
|
||||||
|
@ -41,5 +41,42 @@
|
|||||||
"montly_power_peak_w": 1111.0,
|
"montly_power_peak_w": 1111.0,
|
||||||
"montly_power_peak_timestamp": 230101080010,
|
"montly_power_peak_timestamp": 230101080010,
|
||||||
"active_liter_lpm": 12.345,
|
"active_liter_lpm": 12.345,
|
||||||
"total_liter_m3": 1234.567
|
"total_liter_m3": 1234.567,
|
||||||
|
"external": [
|
||||||
|
{
|
||||||
|
"unique_id": "47303031",
|
||||||
|
"type": "gas_meter",
|
||||||
|
"timestamp": 230125220957,
|
||||||
|
"value": 111.111,
|
||||||
|
"unit": "m3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unique_id": "57303031",
|
||||||
|
"type": "water_meter",
|
||||||
|
"timestamp": 230125220957,
|
||||||
|
"value": 222.222,
|
||||||
|
"unit": "m3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unique_id": "5757303031",
|
||||||
|
"type": "warm_water_meter",
|
||||||
|
"timestamp": 230125220957,
|
||||||
|
"value": 333.333,
|
||||||
|
"unit": "m3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unique_id": "48303031",
|
||||||
|
"type": "heat_meter",
|
||||||
|
"timestamp": 230125220957,
|
||||||
|
"value": 444.444,
|
||||||
|
"unit": "GJ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unique_id": "4948303031",
|
||||||
|
"type": "inlet_heat_meter",
|
||||||
|
"timestamp": 230125220957,
|
||||||
|
"value": 555.555,
|
||||||
|
"unit": "m3"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,58 @@
|
|||||||
'active_voltage_l3_v': 230.333,
|
'active_voltage_l3_v': 230.333,
|
||||||
'active_voltage_v': None,
|
'active_voltage_v': None,
|
||||||
'any_power_fail_count': 4,
|
'any_power_fail_count': 4,
|
||||||
'external_devices': None,
|
'external_devices': dict({
|
||||||
|
'G001': dict({
|
||||||
|
'meter_type': dict({
|
||||||
|
'__type': "<enum 'DeviceType'>",
|
||||||
|
'repr': '<DeviceType.GAS_METER: 3>',
|
||||||
|
}),
|
||||||
|
'timestamp': '2023-01-25T22:09:57',
|
||||||
|
'unique_id': '**REDACTED**',
|
||||||
|
'unit': 'm3',
|
||||||
|
'value': 111.111,
|
||||||
|
}),
|
||||||
|
'H001': dict({
|
||||||
|
'meter_type': dict({
|
||||||
|
'__type': "<enum 'DeviceType'>",
|
||||||
|
'repr': '<DeviceType.HEAT_METER: 4>',
|
||||||
|
}),
|
||||||
|
'timestamp': '2023-01-25T22:09:57',
|
||||||
|
'unique_id': '**REDACTED**',
|
||||||
|
'unit': 'GJ',
|
||||||
|
'value': 444.444,
|
||||||
|
}),
|
||||||
|
'IH001': dict({
|
||||||
|
'meter_type': dict({
|
||||||
|
'__type': "<enum 'DeviceType'>",
|
||||||
|
'repr': '<DeviceType.INLET_HEAT_METER: 12>',
|
||||||
|
}),
|
||||||
|
'timestamp': '2023-01-25T22:09:57',
|
||||||
|
'unique_id': '**REDACTED**',
|
||||||
|
'unit': 'm3',
|
||||||
|
'value': 555.555,
|
||||||
|
}),
|
||||||
|
'W001': dict({
|
||||||
|
'meter_type': dict({
|
||||||
|
'__type': "<enum 'DeviceType'>",
|
||||||
|
'repr': '<DeviceType.WATER_METER: 7>',
|
||||||
|
}),
|
||||||
|
'timestamp': '2023-01-25T22:09:57',
|
||||||
|
'unique_id': '**REDACTED**',
|
||||||
|
'unit': 'm3',
|
||||||
|
'value': 222.222,
|
||||||
|
}),
|
||||||
|
'WW001': dict({
|
||||||
|
'meter_type': dict({
|
||||||
|
'__type': "<enum 'DeviceType'>",
|
||||||
|
'repr': '<DeviceType.WARM_WATER_METER: 6>',
|
||||||
|
}),
|
||||||
|
'timestamp': '2023-01-25T22:09:57',
|
||||||
|
'unique_id': '**REDACTED**',
|
||||||
|
'unit': 'm3',
|
||||||
|
'value': 333.333,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
'gas_timestamp': '2021-03-14T11:22:33',
|
'gas_timestamp': '2021-03-14T11:22:33',
|
||||||
'gas_unique_id': '**REDACTED**',
|
'gas_unique_id': '**REDACTED**',
|
||||||
'long_power_fail_count': 5,
|
'long_power_fail_count': 5,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -3,16 +3,18 @@
|
|||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from homewizard_energy.errors import DisabledError, RequestError
|
from homewizard_energy.errors import DisabledError, RequestError
|
||||||
|
from homewizard_energy.models import Data
|
||||||
import pytest
|
import pytest
|
||||||
from syrupy.assertion import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
|
from homeassistant.components.homewizard import DOMAIN
|
||||||
from homeassistant.components.homewizard.const import UPDATE_INTERVAL
|
from homeassistant.components.homewizard.const import UPDATE_INTERVAL
|
||||||
from homeassistant.const import STATE_UNAVAILABLE
|
from homeassistant.const import STATE_UNAVAILABLE, Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from tests.common import async_fire_time_changed
|
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||||
|
|
||||||
pytestmark = [
|
pytestmark = [
|
||||||
pytest.mark.usefixtures("init_integration"),
|
pytest.mark.usefixtures("init_integration"),
|
||||||
@ -63,10 +65,13 @@ pytestmark = [
|
|||||||
"sensor.device_long_power_failures_detected",
|
"sensor.device_long_power_failures_detected",
|
||||||
"sensor.device_active_average_demand",
|
"sensor.device_active_average_demand",
|
||||||
"sensor.device_peak_demand_current_month",
|
"sensor.device_peak_demand_current_month",
|
||||||
"sensor.device_total_gas",
|
|
||||||
"sensor.device_gas_meter_identifier",
|
|
||||||
"sensor.device_active_water_usage",
|
"sensor.device_active_water_usage",
|
||||||
"sensor.device_total_water_usage",
|
"sensor.device_total_water_usage",
|
||||||
|
"sensor.gas_meter_total_gas",
|
||||||
|
"sensor.water_meter_total_water_usage",
|
||||||
|
"sensor.warm_water_meter_total_water_usage",
|
||||||
|
"sensor.heat_meter_total_heat_energy",
|
||||||
|
"sensor.inlet_heat_meter_total_heat_energy",
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -102,8 +107,6 @@ pytestmark = [
|
|||||||
"sensor.device_power_failures_detected",
|
"sensor.device_power_failures_detected",
|
||||||
"sensor.device_long_power_failures_detected",
|
"sensor.device_long_power_failures_detected",
|
||||||
"sensor.device_active_average_demand",
|
"sensor.device_active_average_demand",
|
||||||
"sensor.device_peak_demand_current_month",
|
|
||||||
"sensor.device_total_gas",
|
|
||||||
"sensor.device_active_water_usage",
|
"sensor.device_active_water_usage",
|
||||||
"sensor.device_total_water_usage",
|
"sensor.device_total_water_usage",
|
||||||
],
|
],
|
||||||
@ -256,6 +259,22 @@ async def test_sensors_unreachable(
|
|||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
|
async def test_external_sensors_unreachable(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_homewizardenergy: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test external device sensor handles API unreachable."""
|
||||||
|
assert (state := hass.states.get("sensor.gas_meter_total_gas"))
|
||||||
|
assert state.state == "111.111"
|
||||||
|
|
||||||
|
mock_homewizardenergy.data.return_value = Data.from_dict({})
|
||||||
|
async_fire_time_changed(hass, dt_util.utcnow() + UPDATE_INTERVAL)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert (state := hass.states.get(state.entity_id))
|
||||||
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("device_fixture", "entity_ids"),
|
("device_fixture", "entity_ids"),
|
||||||
[
|
[
|
||||||
@ -275,7 +294,6 @@ async def test_sensors_unreachable(
|
|||||||
"sensor.device_active_voltage_phase_3",
|
"sensor.device_active_voltage_phase_3",
|
||||||
"sensor.device_active_water_usage",
|
"sensor.device_active_water_usage",
|
||||||
"sensor.device_dsmr_version",
|
"sensor.device_dsmr_version",
|
||||||
"sensor.device_gas_meter_identifier",
|
|
||||||
"sensor.device_long_power_failures_detected",
|
"sensor.device_long_power_failures_detected",
|
||||||
"sensor.device_peak_demand_current_month",
|
"sensor.device_peak_demand_current_month",
|
||||||
"sensor.device_power_failures_detected",
|
"sensor.device_power_failures_detected",
|
||||||
@ -289,7 +307,6 @@ async def test_sensors_unreachable(
|
|||||||
"sensor.device_total_energy_import_tariff_2",
|
"sensor.device_total_energy_import_tariff_2",
|
||||||
"sensor.device_total_energy_import_tariff_3",
|
"sensor.device_total_energy_import_tariff_3",
|
||||||
"sensor.device_total_energy_import_tariff_4",
|
"sensor.device_total_energy_import_tariff_4",
|
||||||
"sensor.device_total_gas",
|
|
||||||
"sensor.device_total_water_usage",
|
"sensor.device_total_water_usage",
|
||||||
"sensor.device_voltage_sags_detected_phase_1",
|
"sensor.device_voltage_sags_detected_phase_1",
|
||||||
"sensor.device_voltage_sags_detected_phase_2",
|
"sensor.device_voltage_sags_detected_phase_2",
|
||||||
@ -337,8 +354,6 @@ async def test_sensors_unreachable(
|
|||||||
"sensor.device_long_power_failures_detected",
|
"sensor.device_long_power_failures_detected",
|
||||||
"sensor.device_active_average_demand",
|
"sensor.device_active_average_demand",
|
||||||
"sensor.device_peak_demand_current_month",
|
"sensor.device_peak_demand_current_month",
|
||||||
"sensor.device_total_gas",
|
|
||||||
"sensor.device_gas_meter_identifier",
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -357,7 +372,6 @@ async def test_sensors_unreachable(
|
|||||||
"sensor.device_active_voltage_phase_3",
|
"sensor.device_active_voltage_phase_3",
|
||||||
"sensor.device_active_water_usage",
|
"sensor.device_active_water_usage",
|
||||||
"sensor.device_dsmr_version",
|
"sensor.device_dsmr_version",
|
||||||
"sensor.device_gas_meter_identifier",
|
|
||||||
"sensor.device_long_power_failures_detected",
|
"sensor.device_long_power_failures_detected",
|
||||||
"sensor.device_peak_demand_current_month",
|
"sensor.device_peak_demand_current_month",
|
||||||
"sensor.device_power_failures_detected",
|
"sensor.device_power_failures_detected",
|
||||||
@ -371,7 +385,6 @@ async def test_sensors_unreachable(
|
|||||||
"sensor.device_total_energy_import_tariff_2",
|
"sensor.device_total_energy_import_tariff_2",
|
||||||
"sensor.device_total_energy_import_tariff_3",
|
"sensor.device_total_energy_import_tariff_3",
|
||||||
"sensor.device_total_energy_import_tariff_4",
|
"sensor.device_total_energy_import_tariff_4",
|
||||||
"sensor.device_total_gas",
|
|
||||||
"sensor.device_total_water_usage",
|
"sensor.device_total_water_usage",
|
||||||
"sensor.device_voltage_sags_detected_phase_1",
|
"sensor.device_voltage_sags_detected_phase_1",
|
||||||
"sensor.device_voltage_sags_detected_phase_2",
|
"sensor.device_voltage_sags_detected_phase_2",
|
||||||
@ -395,7 +408,6 @@ async def test_sensors_unreachable(
|
|||||||
"sensor.device_active_voltage_phase_3",
|
"sensor.device_active_voltage_phase_3",
|
||||||
"sensor.device_active_water_usage",
|
"sensor.device_active_water_usage",
|
||||||
"sensor.device_dsmr_version",
|
"sensor.device_dsmr_version",
|
||||||
"sensor.device_gas_meter_identifier",
|
|
||||||
"sensor.device_long_power_failures_detected",
|
"sensor.device_long_power_failures_detected",
|
||||||
"sensor.device_peak_demand_current_month",
|
"sensor.device_peak_demand_current_month",
|
||||||
"sensor.device_power_failures_detected",
|
"sensor.device_power_failures_detected",
|
||||||
@ -409,7 +421,6 @@ async def test_sensors_unreachable(
|
|||||||
"sensor.device_total_energy_import_tariff_2",
|
"sensor.device_total_energy_import_tariff_2",
|
||||||
"sensor.device_total_energy_import_tariff_3",
|
"sensor.device_total_energy_import_tariff_3",
|
||||||
"sensor.device_total_energy_import_tariff_4",
|
"sensor.device_total_energy_import_tariff_4",
|
||||||
"sensor.device_total_gas",
|
|
||||||
"sensor.device_total_water_usage",
|
"sensor.device_total_water_usage",
|
||||||
"sensor.device_voltage_sags_detected_phase_1",
|
"sensor.device_voltage_sags_detected_phase_1",
|
||||||
"sensor.device_voltage_sags_detected_phase_2",
|
"sensor.device_voltage_sags_detected_phase_2",
|
||||||
@ -428,3 +439,49 @@ async def test_entities_not_created_for_device(
|
|||||||
"""Ensures entities for a specific device are not created."""
|
"""Ensures entities for a specific device are not created."""
|
||||||
for entity_id in entity_ids:
|
for entity_id in entity_ids:
|
||||||
assert not hass.states.get(entity_id)
|
assert not hass.states.get(entity_id)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_gas_meter_migrated(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
init_integration: MockConfigEntry,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
) -> None:
|
||||||
|
"""Test old gas meter sensor is migrated."""
|
||||||
|
entity_registry.async_get_or_create(
|
||||||
|
Platform.SENSOR,
|
||||||
|
DOMAIN,
|
||||||
|
"aabbccddeeff_total_gas_m3",
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.config_entries.async_reload(init_integration.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
entity_id = "sensor.homewizard_aabbccddeeff_total_gas_m3"
|
||||||
|
|
||||||
|
assert (entity_entry := entity_registry.async_get(entity_id))
|
||||||
|
assert snapshot(name=f"{entity_id}:entity-registry") == entity_entry
|
||||||
|
|
||||||
|
# Make really sure this happens
|
||||||
|
assert entity_entry.previous_unique_id == "aabbccddeeff_total_gas_m3"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_gas_unique_id_removed(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
init_integration: MockConfigEntry,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
) -> None:
|
||||||
|
"""Test old gas meter id sensor is removed."""
|
||||||
|
entity_registry.async_get_or_create(
|
||||||
|
Platform.SENSOR,
|
||||||
|
DOMAIN,
|
||||||
|
"aabbccddeeff_gas_unique_id",
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.config_entries.async_reload(init_integration.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
entity_id = "sensor.homewizard_aabbccddeeff_gas_unique_id"
|
||||||
|
|
||||||
|
assert not entity_registry.async_get(entity_id)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user