diff --git a/tests/test_schneider.py b/tests/test_schneider.py new file mode 100644 index 0000000000..186c43f311 --- /dev/null +++ b/tests/test_schneider.py @@ -0,0 +1,33 @@ +"""Tests for Schneider.""" + +import pytest +from zigpy.zcl.clusters.smartenergy import Metering + +import zhaquirks.schneider.outlet + +from tests.common import ClusterListener + +zhaquirks.setup() + + +@pytest.mark.parametrize("quirk", (zhaquirks.schneider.outlet.SocketOutlet,)) +async def test_schneider_device_temp(zigpy_device_from_quirk, quirk): + """Test that instant demand is divided by 1000.""" + device = zigpy_device_from_quirk(quirk) + + metering_cluster = device.endpoints[6].smartenergy_metering + metering_listener = ClusterListener(metering_cluster) + instantaneous_demand_attr_id = Metering.AttributeDefs.instantaneous_demand.id + summation_delivered_attr_id = Metering.AttributeDefs.current_summ_delivered.id + + # verify instant demand is divided by 1000 + metering_cluster.update_attribute(instantaneous_demand_attr_id, 25000) + assert len(metering_listener.attribute_updates) == 1 + assert metering_listener.attribute_updates[0][0] == instantaneous_demand_attr_id + assert metering_listener.attribute_updates[0][1] == 25 # divided by 1000 + + # verify other attributes are not modified + metering_cluster.update_attribute(summation_delivered_attr_id, 25) + assert len(metering_listener.attribute_updates) == 2 + assert metering_listener.attribute_updates[1][0] == summation_delivered_attr_id + assert metering_listener.attribute_updates[1][1] == 25 # not modified diff --git a/zhaquirks/schneider/__init__.py b/zhaquirks/schneider/__init__.py new file mode 100644 index 0000000000..610b5c6cbc --- /dev/null +++ b/zhaquirks/schneider/__init__.py @@ -0,0 +1,3 @@ +"""Quirks for Schneider devices.""" + +SCHNEIDER = "Schneider Electric" diff --git a/zhaquirks/schneider/outlet.py b/zhaquirks/schneider/outlet.py new file mode 100644 index 0000000000..c4e4ce0688 --- /dev/null +++ b/zhaquirks/schneider/outlet.py @@ -0,0 +1,108 @@ +"""Schneider Electric (Wiser) Outlet Quirks.""" +from zigpy.profiles import zgp, zha +from zigpy.quirks import CustomCluster, CustomDevice +from zigpy.zcl.clusters.general import ( + Basic, + GreenPowerProxy, + Groups, + Identify, + OnOff, + Ota, + Scenes, +) +from zigpy.zcl.clusters.homeautomation import Diagnostic, ElectricalMeasurement +from zigpy.zcl.clusters.smartenergy import DeviceManagement, Metering + +from zhaquirks.const import ( + DEVICE_TYPE, + ENDPOINTS, + INPUT_CLUSTERS, + MODELS_INFO, + OUTPUT_CLUSTERS, + PROFILE_ID, +) +from zhaquirks.schneider import SCHNEIDER + + +class MeteringCluster(CustomCluster, Metering): + """Custom Metering cluster to fix instantaneous demand value multiplied by 1000.""" + + def _update_attribute(self, attrid, value): + if attrid == self.AttributeDefs.instantaneous_demand.id: + value = value / 1000 + super()._update_attribute(attrid, value) + + +class SocketOutlet(CustomDevice): + """Schneider Electric Socket outlet WDE002182, WDE002172.""" + + signature = { + MODELS_INFO: [ + (SCHNEIDER, "SOCKET/OUTLET/1"), + (SCHNEIDER, "SOCKET/OUTLET/2"), + ], + ENDPOINTS: { + # + 6: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.MAIN_POWER_OUTLET, + INPUT_CLUSTERS: [ + Basic.cluster_id, + Identify.cluster_id, + Groups.cluster_id, + Scenes.cluster_id, + OnOff.cluster_id, + Metering.cluster_id, + DeviceManagement.cluster_id, + ElectricalMeasurement.cluster_id, + Diagnostic.cluster_id, + 0xFC04, + ], + OUTPUT_CLUSTERS: [ + Ota.cluster_id, + ], + }, + 242: { + PROFILE_ID: zgp.PROFILE_ID, + DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC, + INPUT_CLUSTERS: [], + OUTPUT_CLUSTERS: [ + GreenPowerProxy.cluster_id, + ], + }, + }, + } + + replacement = { + ENDPOINTS: { + 6: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.MAIN_POWER_OUTLET, + INPUT_CLUSTERS: [ + Basic.cluster_id, + Identify.cluster_id, + Groups.cluster_id, + Scenes.cluster_id, + OnOff.cluster_id, + MeteringCluster, + DeviceManagement.cluster_id, + ElectricalMeasurement.cluster_id, + Diagnostic.cluster_id, + 0xFC04, + ], + OUTPUT_CLUSTERS: [ + Ota.cluster_id, + ], + }, + 242: { + PROFILE_ID: zgp.PROFILE_ID, + DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC, + INPUT_CLUSTERS: [], + OUTPUT_CLUSTERS: [ + GreenPowerProxy.cluster_id, + ], + }, + }, + }