diff --git a/homeassistant/components/zha/core/cluster_handlers/smartenergy.py b/homeassistant/components/zha/core/cluster_handlers/smartenergy.py index 4d3c1759cdc..577da25332d 100644 --- a/homeassistant/components/zha/core/cluster_handlers/smartenergy.py +++ b/homeassistant/components/zha/core/cluster_handlers/smartenergy.py @@ -129,24 +129,67 @@ class MeteringClusterHandler(ClusterHandler): Metering.AttributeDefs.unit_of_measure.name: True, } + METERING_DEVICE_TYPES_ELECTRIC = { + 0, + 7, + 8, + 9, + 10, + 11, + 13, + 14, + 15, + 127, + 134, + 135, + 136, + 137, + 138, + 140, + 141, + 142, + } + METERING_DEVICE_TYPES_GAS = {1, 128} + METERING_DEVICE_TYPES_WATER = {2, 129} + METERING_DEVICE_TYPES_HEATING_COOLING = {3, 5, 6, 130, 132, 133} + metering_device_type = { 0: "Electric Metering", 1: "Gas Metering", 2: "Water Metering", - 3: "Thermal Metering", + 3: "Thermal Metering", # depreciated 4: "Pressure Metering", 5: "Heat Metering", 6: "Cooling Metering", + 7: "End Use Measurement Device (EUMD) for metering electric vehicle charging", + 8: "PV Generation Metering", + 9: "Wind Turbine Generation Metering", + 10: "Water Turbine Generation Metering", + 11: "Micro Generation Metering", + 12: "Solar Hot Water Generation Metering", + 13: "Electric Metering Element/Phase 1", + 14: "Electric Metering Element/Phase 2", + 15: "Electric Metering Element/Phase 3", + 127: "Mirrored Electric Metering", 128: "Mirrored Gas Metering", 129: "Mirrored Water Metering", - 130: "Mirrored Thermal Metering", + 130: "Mirrored Thermal Metering", # depreciated 131: "Mirrored Pressure Metering", 132: "Mirrored Heat Metering", 133: "Mirrored Cooling Metering", + 134: "Mirrored End Use Measurement Device (EUMD) for metering electric vehicle charging", + 135: "Mirrored PV Generation Metering", + 136: "Mirrored Wind Turbine Generation Metering", + 137: "Mirrored Water Turbine Generation Metering", + 138: "Mirrored Micro Generation Metering", + 139: "Mirrored Solar Hot Water Generation Metering", + 140: "Mirrored Electric Metering Element/Phase 1", + 141: "Mirrored Electric Metering Element/Phase 2", + 142: "Mirrored Electric Metering Element/Phase 3", } class DeviceStatusElectric(enum.IntFlag): - """Metering Device Status.""" + """Electric Metering Device Status.""" NO_ALARMS = 0 CHECK_METER = 1 @@ -158,6 +201,45 @@ class MeteringClusterHandler(ClusterHandler): SERVICE_DISCONNECT = 64 RESERVED = 128 + class DeviceStatusGas(enum.IntFlag): + """Gas Metering Device Status.""" + + NO_ALARMS = 0 + CHECK_METER = 1 + LOW_BATTERY = 2 + TAMPER_DETECT = 4 + NOT_DEFINED = 8 + LOW_PRESSURE = 16 + LEAK_DETECT = 32 + SERVICE_DISCONNECT = 64 + REVERSE_FLOW = 128 + + class DeviceStatusWater(enum.IntFlag): + """Water Metering Device Status.""" + + NO_ALARMS = 0 + CHECK_METER = 1 + LOW_BATTERY = 2 + TAMPER_DETECT = 4 + PIPE_EMPTY = 8 + LOW_PRESSURE = 16 + LEAK_DETECT = 32 + SERVICE_DISCONNECT = 64 + REVERSE_FLOW = 128 + + class DeviceStatusHeatingCooling(enum.IntFlag): + """Heating and Cooling Metering Device Status.""" + + NO_ALARMS = 0 + CHECK_METER = 1 + LOW_BATTERY = 2 + TAMPER_DETECT = 4 + TEMPERATURE_SENSOR = 8 + BURST_DETECT = 16 + LEAK_DETECT = 32 + SERVICE_DISCONNECT = 64 + REVERSE_FLOW = 128 + class DeviceStatusDefault(enum.IntFlag): """Metering Device Status.""" @@ -198,9 +280,18 @@ class MeteringClusterHandler(ClusterHandler): """Return metering device status.""" if (status := self.cluster.get(Metering.AttributeDefs.status.name)) is None: return None - if self.cluster.get(Metering.AttributeDefs.metering_device_type.name) == 0: - # Electric metering device type + + metering_device_type = self.cluster.get( + Metering.AttributeDefs.metering_device_type.name + ) + if metering_device_type in self.METERING_DEVICE_TYPES_ELECTRIC: return self.DeviceStatusElectric(status) + if metering_device_type in self.METERING_DEVICE_TYPES_GAS: + return self.DeviceStatusGas(status) + if metering_device_type in self.METERING_DEVICE_TYPES_WATER: + return self.DeviceStatusWater(status) + if metering_device_type in self.METERING_DEVICE_TYPES_HEATING_COOLING: + return self.DeviceStatusHeatingCooling(status) return self.DeviceStatusDefault(status) @property diff --git a/tests/components/zha/test_sensor.py b/tests/components/zha/test_sensor.py index c5940a7b689..48651df082d 100644 --- a/tests/components/zha/test_sensor.py +++ b/tests/components/zha/test_sensor.py @@ -155,9 +155,33 @@ async def async_test_metering(hass: HomeAssistant, cluster, entity_id): ) await send_attributes_report( - hass, cluster, {"status": 32, "metering_device_type": 1} + hass, cluster, {"status": 64 + 8, "metering_device_type": 1} + ) + assert hass.states.get(entity_id).attributes["status"] in ( + "SERVICE_DISCONNECT|NOT_DEFINED", + "NOT_DEFINED|SERVICE_DISCONNECT", + ) + + await send_attributes_report( + hass, cluster, {"status": 64 + 8, "metering_device_type": 2} + ) + assert hass.states.get(entity_id).attributes["status"] in ( + "SERVICE_DISCONNECT|PIPE_EMPTY", + "PIPE_EMPTY|SERVICE_DISCONNECT", + ) + + await send_attributes_report( + hass, cluster, {"status": 64 + 8, "metering_device_type": 5} + ) + assert hass.states.get(entity_id).attributes["status"] in ( + "SERVICE_DISCONNECT|TEMPERATURE_SENSOR", + "TEMPERATURE_SENSOR|SERVICE_DISCONNECT", + ) + + # Status for other meter types + await send_attributes_report( + hass, cluster, {"status": 32, "metering_device_type": 4} ) - # currently only statuses for electric meters are supported assert hass.states.get(entity_id).attributes["status"] in ("", "32")