diff --git a/homeassistant/components/homematicip_cloud/generic_entity.py b/homeassistant/components/homematicip_cloud/generic_entity.py index a2e6f8a145f..5cd48515ad7 100644 --- a/homeassistant/components/homematicip_cloud/generic_entity.py +++ b/homeassistant/components/homematicip_cloud/generic_entity.py @@ -7,6 +7,7 @@ from typing import Any from homematicip.aio.device import AsyncDevice from homematicip.aio.group import AsyncGroup +from homematicip.base.functionalChannels import FunctionalChannel from homeassistant.const import ATTR_ID from homeassistant.core import callback @@ -91,6 +92,7 @@ class HomematicipGenericEntity(Entity): self._post = post self._channel = channel self._is_multi_channel = is_multi_channel + self.functional_channel = self.get_current_channel() # Marker showing that the HmIP device hase been removed. self.hmip_device_removed = False _LOGGER.info("Setting up %s (%s)", self.name, self._device.modelType) @@ -214,13 +216,14 @@ class HomematicipGenericEntity(Entity): @property def unique_id(self) -> str: """Return a unique ID.""" - unique_id = f"{self.__class__.__name__}_{self._device.id}" - if self._is_multi_channel: - unique_id = ( - f"{self.__class__.__name__}_Channel{self._channel}_{self._device.id}" - ) + suffix = "" + if self._post is not None: + suffix = f"_{self._post}" - return unique_id + if self._is_multi_channel: + return f"{self.__class__.__name__}_Channel{self._channel}_{self._device.id}{suffix}" + + return f"{self.__class__.__name__}_{self._device.id}{suffix}" @property def icon(self) -> str | None: @@ -251,3 +254,14 @@ class HomematicipGenericEntity(Entity): state_attr[ATTR_IS_GROUP] = True return state_attr + + def get_current_channel(self) -> FunctionalChannel: + """Return the FunctionalChannel for device.""" + if hasattr(self._device, "functionalChannels"): + if self._is_multi_channel: + return self._device.functionalChannels[self._channel] + + if len(self._device.functionalChannels) > 1: + return self._device.functionalChannels[1] + + return None diff --git a/homeassistant/components/homematicip_cloud/helpers.py b/homeassistant/components/homematicip_cloud/helpers.py index 4ac9af48ee1..5b7f98ad884 100644 --- a/homeassistant/components/homematicip_cloud/helpers.py +++ b/homeassistant/components/homematicip_cloud/helpers.py @@ -8,6 +8,9 @@ import json import logging from typing import Any, Concatenate, TypeGuard +from homematicip.base.enums import FunctionalChannelType +from homematicip.device import Device + from homeassistant.exceptions import HomeAssistantError from . import HomematicipGenericEntity @@ -47,3 +50,12 @@ def handle_errors[_HomematicipGenericEntityT: HomematicipGenericEntity, **_P]( ) return inner + + +def get_channels_from_device(device: Device, channel_type: FunctionalChannelType): + """Get all channels matching with channel_type from device.""" + return [ + ch + for ch in device.functionalChannels + if ch.functionalChannelType == channel_type + ] diff --git a/homeassistant/components/homematicip_cloud/sensor.py b/homeassistant/components/homematicip_cloud/sensor.py index d344639bbc9..6cdff6caef3 100644 --- a/homeassistant/components/homematicip_cloud/sensor.py +++ b/homeassistant/components/homematicip_cloud/sensor.py @@ -2,10 +2,13 @@ from __future__ import annotations +from collections.abc import Callable +from dataclasses import dataclass from typing import Any from homematicip.aio.device import ( AsyncBrandSwitchMeasuring, + AsyncEnergySensorsInterface, AsyncFullFlushSwitchMeasuring, AsyncHeatingThermostat, AsyncHeatingThermostatCompact, @@ -27,11 +30,13 @@ from homematicip.aio.device import ( AsyncWeatherSensorPlus, AsyncWeatherSensorPro, ) -from homematicip.base.enums import ValveState +from homematicip.base.enums import FunctionalChannelType, ValveState +from homematicip.base.functionalChannels import FunctionalChannel from homeassistant.components.sensor import ( SensorDeviceClass, SensorEntity, + SensorEntityDescription, SensorStateClass, ) from homeassistant.config_entries import ConfigEntry @@ -43,12 +48,16 @@ from homeassistant.const import ( UnitOfPrecipitationDepth, UnitOfSpeed, UnitOfTemperature, + UnitOfVolume, + UnitOfVolumeFlowRate, ) from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.typing import StateType from . import DOMAIN as HMIPC_DOMAIN, HomematicipGenericEntity from .hap import HomematicipHAP +from .helpers import get_channels_from_device ATTR_CURRENT_ILLUMINATION = "current_illumination" ATTR_LOWEST_ILLUMINATION = "lowest_illumination" @@ -58,6 +67,18 @@ ATTR_RIGHT_COUNTER = "right_counter" ATTR_TEMPERATURE_OFFSET = "temperature_offset" ATTR_WIND_DIRECTION = "wind_direction" ATTR_WIND_DIRECTION_VARIATION = "wind_direction_variation_in_degree" +ATTR_ESI_TYPE = "type" +ESI_TYPE_UNKNOWN = "UNKNOWN" +ESI_CONNECTED_SENSOR_TYPE_IEC = "ES_IEC" +ESI_CONNECTED_SENSOR_TYPE_GAS = "ES_GAS" +ESI_CONNECTED_SENSOR_TYPE_LED = "ES_LED" + +ESI_TYPE_CURRENT_POWER_CONSUMPTION = "CurrentPowerConsumption" +ESI_TYPE_ENERGY_COUNTER_USAGE_HIGH_TARIFF = "ENERGY_COUNTER_USAGE_HIGH_TARIFF" +ESI_TYPE_ENERGY_COUNTER_USAGE_LOW_TARIFF = "ENERGY_COUNTER_USAGE_LOW_TARIFF" +ESI_TYPE_ENERGY_COUNTER_INPUT_SINGLE_TARIFF = "ENERGY_COUNTER_INPUT_SINGLE_TARIFF" +ESI_TYPE_CURRENT_GAS_FLOW = "CurrentGasFlow" +ESI_TYPE_CURRENT_GAS_VOLUME = "GasVolume" ILLUMINATION_DEVICE_ATTRIBUTES = { "currentIllumination": ATTR_CURRENT_ILLUMINATION, @@ -138,6 +159,23 @@ async def async_setup_entry( entities.append(HomematicpTemperatureExternalSensorCh1(hap, device)) entities.append(HomematicpTemperatureExternalSensorCh2(hap, device)) entities.append(HomematicpTemperatureExternalSensorDelta(hap, device)) + if isinstance(device, AsyncEnergySensorsInterface): + for ch in get_channels_from_device( + device, FunctionalChannelType.ENERGY_SENSORS_INTERFACE_CHANNEL + ): + if ch.connectedEnergySensorType not in SENSORS_ESI: + continue + + new_entities = [ + HmipEsiSensorEntity(hap, device, ch.index, description) + for description in SENSORS_ESI[ch.connectedEnergySensorType] + ] + + entities.extend( + entity + for entity in new_entities + if entity.entity_description.exists_fn(ch) + ) async_add_entities(entities) @@ -396,6 +434,134 @@ class HomematicpTemperatureExternalSensorDelta(HomematicipGenericEntity, SensorE return self._device.temperatureExternalDelta +@dataclass(kw_only=True, frozen=True) +class HmipEsiSensorEntityDescription(SensorEntityDescription): + """SensorEntityDescription for HmIP Sensors.""" + + value_fn: Callable[[AsyncEnergySensorsInterface], StateType] + exists_fn: Callable[[FunctionalChannel], bool] + type_fn: Callable[[AsyncEnergySensorsInterface], str] + + +SENSORS_ESI = { + ESI_CONNECTED_SENSOR_TYPE_IEC: [ + HmipEsiSensorEntityDescription( + key=ESI_TYPE_CURRENT_POWER_CONSUMPTION, + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda device: device.functional_channel.currentPowerConsumption, + exists_fn=lambda channel: channel.currentPowerConsumption is not None, + type_fn=lambda device: "CurrentPowerConsumption", + ), + HmipEsiSensorEntityDescription( + key=ESI_TYPE_ENERGY_COUNTER_USAGE_HIGH_TARIFF, + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + value_fn=lambda device: device.functional_channel.energyCounterOne, + exists_fn=lambda channel: channel.energyCounterOneType != ESI_TYPE_UNKNOWN, + type_fn=lambda device: device.functional_channel.energyCounterOneType, + ), + HmipEsiSensorEntityDescription( + key=ESI_TYPE_ENERGY_COUNTER_USAGE_LOW_TARIFF, + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + value_fn=lambda device: device.functional_channel.energyCounterTwo, + exists_fn=lambda channel: channel.energyCounterTwoType != ESI_TYPE_UNKNOWN, + type_fn=lambda device: device.functional_channel.energyCounterTwoType, + ), + HmipEsiSensorEntityDescription( + key=ESI_TYPE_ENERGY_COUNTER_INPUT_SINGLE_TARIFF, + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + value_fn=lambda device: device.functional_channel.energyCounterThree, + exists_fn=lambda channel: channel.energyCounterThreeType + != ESI_TYPE_UNKNOWN, + type_fn=lambda device: device.functional_channel.energyCounterThreeType, + ), + ], + ESI_CONNECTED_SENSOR_TYPE_LED: [ + HmipEsiSensorEntityDescription( + key=ESI_TYPE_CURRENT_POWER_CONSUMPTION, + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda device: device.functional_channel.currentPowerConsumption, + exists_fn=lambda channel: channel.currentPowerConsumption is not None, + type_fn=lambda device: "CurrentPowerConsumption", + ), + HmipEsiSensorEntityDescription( + key=ESI_TYPE_ENERGY_COUNTER_USAGE_HIGH_TARIFF, + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + value_fn=lambda device: device.functional_channel.energyCounterOne, + exists_fn=lambda channel: channel.energyCounterOne is not None, + type_fn=lambda device: ESI_TYPE_ENERGY_COUNTER_USAGE_HIGH_TARIFF, + ), + ], + ESI_CONNECTED_SENSOR_TYPE_GAS: [ + HmipEsiSensorEntityDescription( + key=ESI_TYPE_CURRENT_GAS_FLOW, + native_unit_of_measurement=UnitOfVolumeFlowRate.CUBIC_METERS_PER_HOUR, + device_class=SensorDeviceClass.VOLUME_FLOW_RATE, + state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda device: device.functional_channel.currentGasFlow, + exists_fn=lambda channel: channel.currentGasFlow is not None, + type_fn=lambda device: "CurrentGasFlow", + ), + HmipEsiSensorEntityDescription( + key=ESI_TYPE_CURRENT_GAS_VOLUME, + native_unit_of_measurement=UnitOfVolume.CUBIC_METERS, + device_class=SensorDeviceClass.VOLUME, + state_class=SensorStateClass.TOTAL_INCREASING, + value_fn=lambda device: device.functional_channel.gasVolume, + exists_fn=lambda channel: channel.gasVolume is not None, + type_fn=lambda device: "GasVolume", + ), + ], +} + + +class HmipEsiSensorEntity(HomematicipGenericEntity, SensorEntity): + """EntityDescription for HmIP-ESI Sensors.""" + + entity_description: HmipEsiSensorEntityDescription + + def __init__( + self, + hap: HomematicipHAP, + device: HomematicipGenericEntity, + channel_index: int, + entity_description: HmipEsiSensorEntityDescription, + ) -> None: + """Initialize Sensor Entity.""" + super().__init__( + hap=hap, + device=device, + channel=channel_index, + post=entity_description.key, + is_multi_channel=False, + ) + self.entity_description = entity_description + + @property + def extra_state_attributes(self) -> dict[str, Any]: + """Return the state attributes of the esi sensor.""" + state_attr = super().extra_state_attributes + state_attr[ATTR_ESI_TYPE] = self.entity_description.type_fn(self) + + return state_attr + + @property + def native_value(self) -> str | None: + """Return the state of the sensor.""" + return str(self.entity_description.value_fn(self)) + + class HomematicipPassageDetectorDeltaCounter(HomematicipGenericEntity, SensorEntity): """Representation of the HomematicIP passage detector delta counter.""" diff --git a/tests/components/homematicip_cloud/fixtures/homematicip_cloud.json b/tests/components/homematicip_cloud/fixtures/homematicip_cloud.json index 922601ca733..eba2c803b1f 100644 --- a/tests/components/homematicip_cloud/fixtures/homematicip_cloud.json +++ b/tests/components/homematicip_cloud/fixtures/homematicip_cloud.json @@ -7347,6 +7347,416 @@ "serializedGlobalTradeItemNumber": "3014F7110000000000000DLD", "type": "DOOR_LOCK_DRIVE", "updateState": "UP_TO_DATE" + }, + "3014F7110000000000ESIGAS": { + "availableFirmwareVersion": "1.2.2", + "connectionType": "HMIP_RF", + "deviceArchetype": "HMIP", + "firmwareVersion": "1.2.2", + "firmwareVersionInteger": 66050, + "functionalChannels": { + "0": { + "busConfigMismatch": null, + "coProFaulty": false, + "coProRestartNeeded": false, + "coProUpdateFailure": false, + "configPending": false, + "controlsMountingOrientation": null, + "daliBusState": null, + "defaultLinkedGroup": [], + "deviceCommunicationError": null, + "deviceDriveError": null, + "deviceDriveModeError": null, + "deviceId": "3014F7110000000000ESIGAS", + "deviceOperationMode": null, + "deviceOverheated": false, + "deviceOverloaded": false, + "devicePowerFailureDetected": false, + "deviceUndervoltage": false, + "displayContrast": null, + "dutyCycle": false, + "functionalChannelType": "DEVICE_BASE", + "groupIndex": 0, + "groups": ["00000000-0000-0000-0000-000000000047"], + "index": 0, + "label": "", + "lockJammed": null, + "lowBat": false, + "mountingOrientation": null, + "multicastRoutingEnabled": false, + "particulateMatterSensorCommunicationError": null, + "particulateMatterSensorError": null, + "powerShortCircuit": null, + "profilePeriodLimitReached": null, + "routerModuleEnabled": false, + "routerModuleSupported": false, + "rssiDeviceValue": -73, + "rssiPeerValue": null, + "sensorCommunicationError": false, + "sensorError": false, + "shortCircuitDataLine": null, + "supportedOptionalFeatures": { + "IFeatureBusConfigMismatch": false, + "IFeatureDeviceCoProError": false, + "IFeatureDeviceCoProRestart": false, + "IFeatureDeviceCoProUpdate": false, + "IFeatureDeviceCommunicationError": false, + "IFeatureDeviceDaliBusError": false, + "IFeatureDeviceDriveError": false, + "IFeatureDeviceDriveModeError": false, + "IFeatureDeviceIdentify": false, + "IFeatureDeviceOverheated": false, + "IFeatureDeviceOverloaded": false, + "IFeatureDeviceParticulateMatterSensorCommunicationError": false, + "IFeatureDeviceParticulateMatterSensorError": false, + "IFeatureDevicePowerFailure": false, + "IFeatureDeviceSensorCommunicationError": true, + "IFeatureDeviceSensorError": true, + "IFeatureDeviceTemperatureHumiditySensorCommunicationError": false, + "IFeatureDeviceTemperatureHumiditySensorError": false, + "IFeatureDeviceTemperatureOutOfRange": false, + "IFeatureDeviceUndervoltage": false, + "IFeatureMulticastRouter": false, + "IFeaturePowerShortCircuit": false, + "IFeatureProfilePeriodLimit": false, + "IFeatureRssiValue": true, + "IFeatureShortCircuitDataLine": false, + "IOptionalFeatureDefaultLinkedGroup": false, + "IOptionalFeatureDeviceErrorLockJammed": false, + "IOptionalFeatureDeviceOperationMode": false, + "IOptionalFeatureDisplayContrast": false, + "IOptionalFeatureDutyCycle": true, + "IOptionalFeatureLowBat": true, + "IOptionalFeatureMountingOrientation": false + }, + "temperatureHumiditySensorCommunicationError": null, + "temperatureHumiditySensorError": null, + "temperatureOutOfRange": false, + "unreach": false + }, + "1": { + "channelRole": "ENERGY_SENSOR", + "connectedEnergySensorType": "ES_GAS", + "currentGasFlow": 1.03, + "currentPowerConsumption": null, + "deviceId": "3014F7110000000000ESIGAS", + "energyCounterOne": null, + "energyCounterOneType": "UNKNOWN", + "energyCounterThree": null, + "energyCounterThreeType": "UNKNOWN", + "energyCounterTwo": null, + "energyCounterTwoType": "UNKNOWN", + "functionalChannelType": "ENERGY_SENSORS_INTERFACE_CHANNEL", + "gasVolume": 1019.26, + "gasVolumePerImpulse": 0.01, + "groupIndex": 1, + "groups": ["00000000-0000-0000-0000-000000000077"], + "impulsesPerKWH": 10000, + "index": 1, + "label": "", + "supportedOptionalFeatures": { + "IOptionalFeatureCounterOffset": true, + "IOptionalFeatureCurrentGasFlow": true, + "IOptionalFeatureCurrentPowerConsumption": false, + "IOptionalFeatureEnergyCounterOne": false, + "IOptionalFeatureEnergyCounterThree": false, + "IOptionalFeatureEnergyCounterTwo": false, + "IOptionalFeatureGasVolume": true, + "IOptionalFeatureGasVolumePerImpulse": true, + "IOptionalFeatureImpulsesPerKWH": false + } + } + }, + "homeId": "00000000-0000-0000-0000-000000000001", + "id": "3014F7110000000000ESIGAS", + "label": "esi_gas", + "lastStatusUpdate": 1708880308351, + "liveUpdateState": "LIVE_UPDATE_NOT_SUPPORTED", + "manuallyUpdateForced": false, + "manufacturerCode": 1, + "measuredAttributes": { + "1": { + "currentGasFlow": true, + "gasVolume": true + } + }, + "modelId": 509, + "modelType": "HmIP-ESI", + "oem": "eQ-3", + "permanentlyReachable": false, + "serializedGlobalTradeItemNumber": "3014F7110000000000ESIGAS", + "type": "ENERGY_SENSORS_INTERFACE", + "updateState": "UP_TO_DATE" + }, + "3014F7110000000000ESIIEC": { + "availableFirmwareVersion": "0.0.0", + "connectionType": "HMIP_RF", + "deviceArchetype": "HMIP", + "firmwareVersion": "1.0.6", + "firmwareVersionInteger": 65542, + "functionalChannels": { + "0": { + "busConfigMismatch": null, + "coProFaulty": false, + "coProRestartNeeded": false, + "coProUpdateFailure": false, + "configPending": false, + "controlsMountingOrientation": null, + "daliBusState": null, + "defaultLinkedGroup": [], + "deviceCommunicationError": null, + "deviceDriveError": null, + "deviceDriveModeError": null, + "deviceId": "3014F7110000000000ESIIEC", + "deviceOperationMode": null, + "deviceOverheated": false, + "deviceOverloaded": false, + "devicePowerFailureDetected": false, + "deviceUndervoltage": false, + "displayContrast": null, + "dutyCycle": false, + "functionalChannelType": "DEVICE_BASE", + "groupIndex": 0, + "groups": ["00000000-0000-0000-0000-000000000031"], + "index": 0, + "label": "", + "lockJammed": null, + "lowBat": false, + "mountingOrientation": null, + "multicastRoutingEnabled": false, + "particulateMatterSensorCommunicationError": null, + "particulateMatterSensorError": null, + "powerShortCircuit": null, + "profilePeriodLimitReached": null, + "routerModuleEnabled": false, + "routerModuleSupported": false, + "rssiDeviceValue": -94, + "rssiPeerValue": null, + "sensorCommunicationError": false, + "sensorError": true, + "shortCircuitDataLine": null, + "supportedOptionalFeatures": { + "IFeatureBusConfigMismatch": false, + "IFeatureDeviceCoProError": false, + "IFeatureDeviceCoProRestart": false, + "IFeatureDeviceCoProUpdate": false, + "IFeatureDeviceCommunicationError": false, + "IFeatureDeviceDaliBusError": false, + "IFeatureDeviceDriveError": false, + "IFeatureDeviceDriveModeError": false, + "IFeatureDeviceIdentify": false, + "IFeatureDeviceOverheated": false, + "IFeatureDeviceOverloaded": false, + "IFeatureDeviceParticulateMatterSensorCommunicationError": false, + "IFeatureDeviceParticulateMatterSensorError": false, + "IFeatureDevicePowerFailure": false, + "IFeatureDeviceSensorCommunicationError": true, + "IFeatureDeviceSensorError": true, + "IFeatureDeviceTemperatureHumiditySensorCommunicationError": false, + "IFeatureDeviceTemperatureHumiditySensorError": false, + "IFeatureDeviceTemperatureOutOfRange": false, + "IFeatureDeviceUndervoltage": false, + "IFeatureMulticastRouter": false, + "IFeaturePowerShortCircuit": false, + "IFeatureProfilePeriodLimit": false, + "IFeatureRssiValue": true, + "IFeatureShortCircuitDataLine": false, + "IOptionalFeatureDefaultLinkedGroup": false, + "IOptionalFeatureDeviceErrorLockJammed": false, + "IOptionalFeatureDeviceOperationMode": false, + "IOptionalFeatureDisplayContrast": false, + "IOptionalFeatureDutyCycle": true, + "IOptionalFeatureLowBat": true, + "IOptionalFeatureMountingOrientation": false + }, + "temperatureHumiditySensorCommunicationError": null, + "temperatureHumiditySensorError": null, + "temperatureOutOfRange": false, + "unreach": false + }, + "1": { + "channelRole": null, + "connectedEnergySensorType": "ES_IEC", + "currentGasFlow": null, + "currentPowerConsumption": 432, + "deviceId": "3014F7110000000000ESIIEC", + "energyCounterOne": 194.0, + "energyCounterOneType": "ENERGY_COUNTER_USAGE_HIGH_TARIFF", + "energyCounterThree": 3.0, + "energyCounterThreeType": "ENERGY_COUNTER_INPUT_SINGLE_TARIFF", + "energyCounterTwo": 0.0, + "energyCounterTwoType": "ENERGY_COUNTER_USAGE_LOW_TARIFF", + "functionalChannelType": "ENERGY_SENSORS_INTERFACE_CHANNEL", + "gasVolume": null, + "gasVolumePerImpulse": 0.01, + "groupIndex": 1, + "groups": ["00000000-0000-0000-0000-000000000051"], + "impulsesPerKWH": 10000, + "index": 1, + "label": "", + "supportedOptionalFeatures": { + "IOptionalFeatureCounterOffset": false, + "IOptionalFeatureCurrentGasFlow": false, + "IOptionalFeatureCurrentPowerConsumption": true, + "IOptionalFeatureEnergyCounterOne": true, + "IOptionalFeatureEnergyCounterThree": true, + "IOptionalFeatureEnergyCounterTwo": true, + "IOptionalFeatureGasVolume": false, + "IOptionalFeatureGasVolumePerImpulse": false, + "IOptionalFeatureImpulsesPerKWH": false + } + } + }, + "homeId": "00000000-0000-0000-0000-000000000001", + "id": "3014F7110000000000ESIIEC", + "label": "esi_iec", + "lastStatusUpdate": 1702420986697, + "liveUpdateState": "LIVE_UPDATE_NOT_SUPPORTED", + "manuallyUpdateForced": false, + "manufacturerCode": 1, + "measuredAttributes": {}, + "modelId": 509, + "modelType": "HmIP-ESI", + "oem": "eQ-3", + "permanentlyReachable": false, + "serializedGlobalTradeItemNumber": "3014F7110000000000ESIIEC", + "type": "ENERGY_SENSORS_INTERFACE", + "updateState": "UP_TO_DATE" + }, + "3014F711000000000ESIIEC2": { + "availableFirmwareVersion": "0.0.0", + "connectionType": "HMIP_RF", + "deviceArchetype": "HMIP", + "firmwareVersion": "1.0.6", + "firmwareVersionInteger": 65542, + "functionalChannels": { + "0": { + "busConfigMismatch": null, + "coProFaulty": false, + "coProRestartNeeded": false, + "coProUpdateFailure": false, + "configPending": false, + "controlsMountingOrientation": null, + "daliBusState": null, + "defaultLinkedGroup": [], + "deviceCommunicationError": null, + "deviceDriveError": null, + "deviceDriveModeError": null, + "deviceId": "3014F711000000000ESIIEC2", + "deviceOperationMode": null, + "deviceOverheated": false, + "deviceOverloaded": false, + "devicePowerFailureDetected": false, + "deviceUndervoltage": false, + "displayContrast": null, + "dutyCycle": false, + "functionalChannelType": "DEVICE_BASE", + "groupIndex": 0, + "groups": ["00000000-0000-0000-0000-000000000031"], + "index": 0, + "label": "", + "lockJammed": null, + "lowBat": false, + "mountingOrientation": null, + "multicastRoutingEnabled": false, + "particulateMatterSensorCommunicationError": null, + "particulateMatterSensorError": null, + "powerShortCircuit": null, + "profilePeriodLimitReached": null, + "routerModuleEnabled": false, + "routerModuleSupported": false, + "rssiDeviceValue": -94, + "rssiPeerValue": null, + "sensorCommunicationError": false, + "sensorError": true, + "shortCircuitDataLine": null, + "supportedOptionalFeatures": { + "IFeatureBusConfigMismatch": false, + "IFeatureDeviceCoProError": false, + "IFeatureDeviceCoProRestart": false, + "IFeatureDeviceCoProUpdate": false, + "IFeatureDeviceCommunicationError": false, + "IFeatureDeviceDaliBusError": false, + "IFeatureDeviceDriveError": false, + "IFeatureDeviceDriveModeError": false, + "IFeatureDeviceIdentify": false, + "IFeatureDeviceOverheated": false, + "IFeatureDeviceOverloaded": false, + "IFeatureDeviceParticulateMatterSensorCommunicationError": false, + "IFeatureDeviceParticulateMatterSensorError": false, + "IFeatureDevicePowerFailure": false, + "IFeatureDeviceSensorCommunicationError": true, + "IFeatureDeviceSensorError": true, + "IFeatureDeviceTemperatureHumiditySensorCommunicationError": false, + "IFeatureDeviceTemperatureHumiditySensorError": false, + "IFeatureDeviceTemperatureOutOfRange": false, + "IFeatureDeviceUndervoltage": false, + "IFeatureMulticastRouter": false, + "IFeaturePowerShortCircuit": false, + "IFeatureProfilePeriodLimit": false, + "IFeatureRssiValue": true, + "IFeatureShortCircuitDataLine": false, + "IOptionalFeatureDefaultLinkedGroup": false, + "IOptionalFeatureDeviceErrorLockJammed": false, + "IOptionalFeatureDeviceOperationMode": false, + "IOptionalFeatureDisplayContrast": false, + "IOptionalFeatureDutyCycle": true, + "IOptionalFeatureLowBat": true, + "IOptionalFeatureMountingOrientation": false + }, + "temperatureHumiditySensorCommunicationError": null, + "temperatureHumiditySensorError": null, + "temperatureOutOfRange": false, + "unreach": false + }, + "1": { + "channelRole": null, + "connectedEnergySensorType": "ES_IEC", + "currentGasFlow": null, + "currentPowerConsumption": 432, + "deviceId": "3014F711000000000ESIIEC2", + "energyCounterOne": 194.0, + "energyCounterOneType": "ENERGY_COUNTER_USAGE_HIGH_TARIFF", + "energyCounterThree": 3.0, + "energyCounterThreeType": "UNKNOWN", + "energyCounterTwo": 0.0, + "energyCounterTwoType": "ENERGY_COUNTER_USAGE_LOW_TARIFF", + "functionalChannelType": "ENERGY_SENSORS_INTERFACE_CHANNEL", + "gasVolume": null, + "gasVolumePerImpulse": 0.01, + "groupIndex": 1, + "groups": ["00000000-0000-0000-0000-000000000051"], + "impulsesPerKWH": 10000, + "index": 1, + "label": "", + "supportedOptionalFeatures": { + "IOptionalFeatureCounterOffset": false, + "IOptionalFeatureCurrentGasFlow": false, + "IOptionalFeatureCurrentPowerConsumption": true, + "IOptionalFeatureEnergyCounterOne": true, + "IOptionalFeatureEnergyCounterThree": true, + "IOptionalFeatureEnergyCounterTwo": true, + "IOptionalFeatureGasVolume": false, + "IOptionalFeatureGasVolumePerImpulse": false, + "IOptionalFeatureImpulsesPerKWH": false + } + } + }, + "homeId": "00000000-0000-0000-0000-000000000001", + "id": "3014F711000000000ESIIEC2", + "label": "esi_iec2", + "lastStatusUpdate": 1702420986697, + "liveUpdateState": "LIVE_UPDATE_NOT_SUPPORTED", + "manuallyUpdateForced": false, + "manufacturerCode": 1, + "measuredAttributes": {}, + "modelId": 509, + "modelType": "HmIP-ESI", + "oem": "eQ-3", + "permanentlyReachable": false, + "serializedGlobalTradeItemNumber": "3014F711000000000ESIIEC2", + "type": "ENERGY_SENSORS_INTERFACE", + "updateState": "UP_TO_DATE" } }, "groups": { diff --git a/tests/components/homematicip_cloud/test_device.py b/tests/components/homematicip_cloud/test_device.py index fb7fe7d7deb..348171b3187 100644 --- a/tests/components/homematicip_cloud/test_device.py +++ b/tests/components/homematicip_cloud/test_device.py @@ -26,7 +26,7 @@ async def test_hmip_load_all_supported_devices( test_devices=None, test_groups=None ) - assert len(mock_hap.hmip_device_by_entity_id) == 278 + assert len(mock_hap.hmip_device_by_entity_id) == 290 async def test_hmip_remove_device( diff --git a/tests/components/homematicip_cloud/test_sensor.py b/tests/components/homematicip_cloud/test_sensor.py index 3089bb062e5..6951b750b2f 100644 --- a/tests/components/homematicip_cloud/test_sensor.py +++ b/tests/components/homematicip_cloud/test_sensor.py @@ -511,3 +511,126 @@ async def test_hmip_passage_detector_delta_counter( await async_manipulate_test_data(hass, hmip_device, "leftRightCounterDelta", 190) ha_state = hass.states.get(entity_id) assert ha_state.state == "190" + + +async def test_hmip_esi_iec_current_power_consumption( + hass: HomeAssistant, default_mock_hap_factory +) -> None: + """Test ESI-IEC currentPowerConsumption Sensor.""" + entity_id = "sensor.esi_iec_currentPowerConsumption" + entity_name = "esi_iec CurrentPowerConsumption" + device_model = "HmIP-ESI" + mock_hap = await default_mock_hap_factory.async_get_mock_hap( + test_devices=["esi_iec"] + ) + + ha_state, hmip_device = get_and_check_entity_basics( + hass, mock_hap, entity_id, entity_name, device_model + ) + + assert ha_state.state == "432" + + +async def test_hmip_esi_iec_energy_counter_usage_high_tariff( + hass: HomeAssistant, default_mock_hap_factory +) -> None: + """Test ESI-IEC ENERGY_COUNTER_USAGE_HIGH_TARIFF.""" + entity_id = "sensor.esi_iec_energy_counter_usage_high_tariff" + entity_name = "esi_iec ENERGY_COUNTER_USAGE_HIGH_TARIFF" + device_model = "HmIP-ESI" + mock_hap = await default_mock_hap_factory.async_get_mock_hap( + test_devices=["esi_iec"] + ) + + ha_state, hmip_device = get_and_check_entity_basics( + hass, mock_hap, entity_id, entity_name, device_model + ) + + assert ha_state.state == "194.0" + + +async def test_hmip_esi_iec_energy_counter_usage_low_tariff( + hass: HomeAssistant, default_mock_hap_factory +) -> None: + """Test ESI-IEC ENERGY_COUNTER_USAGE_LOW_TARIFF.""" + entity_id = "sensor.esi_iec_energy_counter_usage_low_tariff" + entity_name = "esi_iec ENERGY_COUNTER_USAGE_LOW_TARIFF" + device_model = "HmIP-ESI" + mock_hap = await default_mock_hap_factory.async_get_mock_hap( + test_devices=["esi_iec"] + ) + + ha_state, hmip_device = get_and_check_entity_basics( + hass, mock_hap, entity_id, entity_name, device_model + ) + + assert ha_state.state == "0.0" + + +async def test_hmip_esi_iec_energy_counter_input_single_tariff( + hass: HomeAssistant, default_mock_hap_factory +) -> None: + """Test ESI-IEC ENERGY_COUNTER_INPUT_SINGLE_TARIFF.""" + entity_id = "sensor.esi_iec_energy_counter_input_single_tariff" + entity_name = "esi_iec ENERGY_COUNTER_INPUT_SINGLE_TARIFF" + device_model = "HmIP-ESI" + mock_hap = await default_mock_hap_factory.async_get_mock_hap( + test_devices=["esi_iec"] + ) + + ha_state, hmip_device = get_and_check_entity_basics( + hass, mock_hap, entity_id, entity_name, device_model + ) + + assert ha_state.state == "3.0" + + +async def test_hmip_esi_iec_unknown_channel( + hass: HomeAssistant, default_mock_hap_factory +) -> None: + """Test devices are loaded partially.""" + not_existing_entity_id = "sensor.esi_iec2_energy_counter_input_single_tariff" + existing_entity_id = "sensor.esi_iec2_energy_counter_usage_high_tariff" + await default_mock_hap_factory.async_get_mock_hap(test_devices=["esi_iec2"]) + + not_existing_ha_state = hass.states.get(not_existing_entity_id) + existing_ha_state = hass.states.get(existing_entity_id) + + assert not_existing_ha_state is None + assert existing_ha_state.state == "194.0" + + +async def test_hmip_esi_gas_current_gas_flow( + hass: HomeAssistant, default_mock_hap_factory +) -> None: + """Test ESI-IEC CurrentGasFlow.""" + entity_id = "sensor.esi_gas_currentgasflow" + entity_name = "esi_gas CurrentGasFlow" + device_model = "HmIP-ESI" + mock_hap = await default_mock_hap_factory.async_get_mock_hap( + test_devices=["esi_gas"] + ) + + ha_state, hmip_device = get_and_check_entity_basics( + hass, mock_hap, entity_id, entity_name, device_model + ) + + assert ha_state.state == "1.03" + + +async def test_hmip_esi_gas_gas_volume( + hass: HomeAssistant, default_mock_hap_factory +) -> None: + """Test ESI-IEC GasVolume.""" + entity_id = "sensor.esi_gas_gasvolume" + entity_name = "esi_gas GasVolume" + device_model = "HmIP-ESI" + mock_hap = await default_mock_hap_factory.async_get_mock_hap( + test_devices=["esi_gas"] + ) + + ha_state, hmip_device = get_and_check_entity_basics( + hass, mock_hap, entity_id, entity_name, device_model + ) + + assert ha_state.state == "1019.26"