Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions tests/test_schneiderelectric.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

from unittest import mock

import pytest
from zigpy.zcl import foundation
from zigpy.zcl import ClusterType, foundation
from zigpy.zcl.clusters.closures import WindowCovering
from zigpy.zcl.clusters.smartenergy import Metering

from tests.common import ClusterListener
import zhaquirks
from zhaquirks.schneiderelectric import SE_MANUF_NAME
import zhaquirks.schneiderelectric.outlet

zhaquirks.setup()

Expand Down Expand Up @@ -86,10 +85,13 @@ async def test_1gang_shutter_1_lift_percentage_updates(zigpy_device_from_v2_quir
assert len(cluster_listener.cluster_commands) == 0


@pytest.mark.parametrize("quirk", (zhaquirks.schneiderelectric.outlet.SocketOutlet,))
async def test_schneider_device_temp(zigpy_device_from_quirk, quirk):
async def test_schneider_device_temp(zigpy_device_from_v2_quirk):
"""Test that instant demand is divided by 1000."""
device = zigpy_device_from_quirk(quirk)
device = zigpy_device_from_v2_quirk(
manufacturer=SE_MANUF_NAME,
model="SOCKET/OUTLET/1",
cluster_ids={6: {Metering.cluster_id: ClusterType.Server}},
)

metering_cluster = device.endpoints[6].smartenergy_metering
metering_listener = ClusterListener(metering_cluster)
Expand Down
187 changes: 90 additions & 97 deletions zhaquirks/schneiderelectric/outlet.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,63 @@
"""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.schneiderelectric import SE_MANUF_NAME
from typing import Final

from zigpy import types as t
from zigpy.quirks import CustomCluster
from zigpy.quirks.v2 import QuirkBuilder
from zigpy.zcl.clusters.smartenergy import Metering
from zigpy.zcl.foundation import DataTypeId, ZCLAttributeDef

from zhaquirks.schneiderelectric import SE_MANUF_NAME, SEBasic


class SEIndicatorMode(t.enum8):
"""Indicator mode."""

InverseOfOutput = 0x00
FollowsOutput = 0x01
AlwaysOff = 0x02
AlwaysOn = 0x03


class SELocalControlMode(t.enum8):
"""Local control mode."""

class MeteringCluster(CustomCluster, Metering):
Active = 0x00
Inactive = 0x01


class SEOutletConfiguration(CustomCluster):
"""Schneider Electric Outlet Configuration cluster."""

cluster_id = 0xFC04
name = "SEOutletConfiguration"

class AttributeDefs(CustomCluster.AttributeDefs):
"""Attribute definitions."""

se_indicator_luminance_level: Final = ZCLAttributeDef(
id=0x0000,
type=t.uint8_t,
access="rw",
is_manufacturer_specific=True,
)
se_indicator_mode: Final = ZCLAttributeDef(
id=0x0002,
type=SEIndicatorMode,
zcl_type=DataTypeId.uint8,
access="rw",
is_manufacturer_specific=True,
)
se_local_control_mode: Final = ZCLAttributeDef(
id=0x0050,
type=SELocalControlMode,
access="rw",
is_manufacturer_specific=True,
)


class SEMeteringCluster(CustomCluster, Metering):
"""Custom Metering cluster to fix instantaneous demand value multiplied by 1000."""

def _update_attribute(self, attrid, value):
Expand All @@ -34,76 +66,37 @@ def _update_attribute(self, attrid, value):
super()._update_attribute(attrid, value)


class SocketOutlet(CustomDevice):
"""Schneider Electric Socket outlet WDE002182, WDE002172."""

signature = {
MODELS_INFO: [
(SE_MANUF_NAME, "SOCKET/OUTLET/1"),
(SE_MANUF_NAME, "SOCKET/OUTLET/2"),
],
ENDPOINTS: {
# <SimpleDescriptor endpoint=1 profile=260 device_type=9
# device_version=0
# input_clusters=[0, 3, 4, 5, 6, 1794, 1800, 2820, 2821, 64516] output_clusters=[25]>
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,
],
},
},
}
(
QuirkBuilder(SE_MANUF_NAME, "SOCKET/OUTLET/1")
.applies_to(SE_MANUF_NAME, "SOCKET/OUTLET/2")
.replaces(SEBasic, endpoint_id=6)
.replaces(SEMeteringCluster, endpoint_id=6)
.replaces(SEOutletConfiguration, endpoint_id=6)
.number(
cluster_id=SEOutletConfiguration.cluster_id,
endpoint_id=6,
attribute_name=SEOutletConfiguration.AttributeDefs.se_indicator_luminance_level.name,
min_value=0,
max_value=5,
step=1,
translation_key="indicator_luminance_level",
fallback_name="Indicator luminance level",
)
.enum(
cluster_id=SEOutletConfiguration.cluster_id,
endpoint_id=6,
attribute_name=SEOutletConfiguration.AttributeDefs.se_indicator_mode.name,
enum_class=SEIndicatorMode,
translation_key="indicator_mode",
fallback_name="Indicator mode",
)
.enum(
cluster_id=SEOutletConfiguration.cluster_id,
endpoint_id=6,
attribute_name=SEOutletConfiguration.AttributeDefs.se_local_control_mode.name,
enum_class=SELocalControlMode,
translation_key="local_control_mode",
fallback_name="Local control mode",
)
.add_to_registry()
)
Loading