Add missing ZHA metering device types (#109126)

* Update smartenergy.py metering_device_type enums

* Added missing enum 127

* Enum 127 is also electric metering type

* Meter type constants and status enums in smartenergy cluster handler

Addresses 
https://github.com/home-assistant/core/pull/109126#discussion_r1471383887

Whilst I have the code open I've also added status handlers for the non-electrical meter types.

* New tests for different metering device type statuses
This commit is contained in:
Jack 2024-01-30 20:09:15 +00:00 committed by GitHub
parent bcb9a10d5a
commit 4ec3a17ed0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 122 additions and 7 deletions

View File

@ -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

View File

@ -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 ("<bitmap8.32: 32>", "32")