Skip to content

Commit

Permalink
Support power/energy for more Aqara (H1) switches, add devices (#2784)
Browse files Browse the repository at this point in the history
* Have `OppleCluster` in `opple_remote.py` inherit `XiaomiAqaraE1Cluster`

* Add `MODELS_INFO` to `XiaomiOpple2ButtonSwitchFace1`, `XiaomiOpple2ButtonSwitchFace2`

These are the only models I found online.

* Add power and energy support for `lumi.switch.n2aeu1`, `lumi.switch.b2naus01`

Seems to be supported

* Add alternative signature for `lumi.switch.n1aeu1`, support power/energy, refactor

* Remove redundant `XiaomiMeteringCluster`

* Use `LUMI` constant for `MODELS_INFO`

* Remove cluster ID comments for opple_switch.py

* Remove redundant device_automation_triggers assignment

* Rename `switch_h1.py` to `switch_h1_single.py`, add comment

* Add `switch_h1_double.py` and move H1 double switch quirk from `opple_switch.py`

* Remove cluster ID comments from `XiaomiOpple2ButtonSwitchFace2`

* Rename `lumi.switch.n2aeu1` quirk to `AqaraH1DoubleRockerSwitchWithNeutral`

* Change imports slightly

* Add support for `lumi.switch.l2aeu1`, `lumi.switch.l2aeu1`

* Improve docstring for opple_switch.py
  • Loading branch information
TheJulianJES authored Nov 29, 2023
1 parent d35fc05 commit 4f5abdd
Show file tree
Hide file tree
Showing 7 changed files with 559 additions and 330 deletions.
2 changes: 0 additions & 2 deletions tests/test_quirks.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,6 @@ def _check_range(cluster: zcl.Cluster) -> bool:
# Some quirks do not yet have model info:
zhaquirks.xbee.xbee_io.XBeeSensor,
zhaquirks.xbee.xbee3_io.XBee3Sensor,
zhaquirks.xiaomi.aqara.opple_switch.XiaomiOpple2ButtonSwitchFace2,
zhaquirks.xiaomi.aqara.opple_switch.XiaomiOpple2ButtonSwitchFace1,
zhaquirks.tuya.ts0201.MoesTemperatureHumidtySensorWithScreen,
zhaquirks.smartthings.tag_v4.SmartThingsTagV4,
zhaquirks.smartthings.multi.SmartthingsMultiPurposeSensor,
Expand Down
4 changes: 0 additions & 4 deletions zhaquirks/xiaomi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,10 +542,6 @@ class DeviceTemperatureCluster(LocalDataCluster, DeviceTemperature):
"""Device Temperature Cluster."""


class XiaomiMeteringCluster(LocalDataCluster, Metering):
"""Xiaomi Metering Cluster."""


class TemperatureMeasurementCluster(CustomCluster, TemperatureMeasurement):
"""Temperature cluster that filters out invalid temperature readings."""

Expand Down
12 changes: 7 additions & 5 deletions zhaquirks/xiaomi/aqara/opple_remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@
VALUE,
ZHA_SEND_EVENT,
)
from zhaquirks.xiaomi import LUMI, BasicCluster, XiaomiCustomDevice
from zhaquirks.xiaomi import (
LUMI,
BasicCluster,
XiaomiAqaraE1Cluster,
XiaomiCustomDevice,
)

PRESS_TYPES = {0: "hold", 1: "single", 2: "double", 3: "triple", 255: "release"}
STATUS_TYPE_ATTR = 0x0055 # decimal = 85
Expand Down Expand Up @@ -91,7 +96,6 @@
COMMAND_6_HOLD = "6_hold"
COMMAND_6_RELEASE = "6_release"

OPPLE_CLUSTER_ID = 0xFCC0
OPPLE_MFG_CODE = 0x115F


Expand Down Expand Up @@ -129,11 +133,9 @@ def _update_attribute(self, attrid, value):
super()._update_attribute(0, action)


class OppleCluster(CustomCluster):
class OppleCluster(XiaomiAqaraE1Cluster):
"""Opple cluster."""

ep_attribute = "opple_cluster"
cluster_id = OPPLE_CLUSTER_ID
attributes = {
0x0009: ("mode", types.uint8_t, True),
}
Expand Down
142 changes: 49 additions & 93 deletions zhaquirks/xiaomi/aqara/opple_switch.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Xiaomi aqara single key wall switch devices."""
"""Xiaomi Aqara wall switch devices. Also see switch_h1 files similar H1 rocker switches."""
import copy
from enum import Enum

Expand Down Expand Up @@ -33,18 +33,22 @@
ENDPOINT_ID,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PRESS_TYPE,
PROFILE_ID,
VALUE,
ZHA_SEND_EVENT,
)
from zhaquirks.xiaomi import (
LUMI,
AnalogInputCluster,
BasicCluster,
DeviceTemperatureCluster,
ElectricalMeasurementCluster,
MeteringCluster,
OnOffCluster,
XiaomiCustomDevice,
XiaomiMeteringCluster,
)

from .opple_remote import MultistateInputCluster, OppleCluster
Expand Down Expand Up @@ -85,7 +89,6 @@ class OppleSwitchCluster(OppleCluster):
"""Xiaomi mfg cluster implementation."""

attributes = copy.deepcopy(OppleCluster.attributes)

attributes.update(
{
0x0002: ("power_outage_count", t.uint8_t, True),
Expand Down Expand Up @@ -124,28 +127,29 @@ class XiaomiOpple2ButtonSwitchBase(XiaomiCustomDevice):
DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
INPUT_CLUSTERS: [
BasicCluster,
DeviceTemperatureCluster, # 2
Identify.cluster_id, # 3
Groups.cluster_id, # 4
Scenes.cluster_id, # 5
OnOffCluster, # 6
Alarms.cluster_id, # 9
MultistateInputCluster, # 18
XiaomiMeteringCluster, # 0x0702
OppleSwitchCluster, # 0xFCC0 / 64704
DeviceTemperatureCluster,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOffCluster,
Alarms.cluster_id,
MultistateInputCluster,
MeteringCluster,
ElectricalMeasurementCluster,
OppleSwitchCluster,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
2: {
DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
INPUT_CLUSTERS: [
BasicCluster,
Identify.cluster_id, # 3
Groups.cluster_id, # 4
Scenes.cluster_id, # 5
OnOffCluster, # 6
MultistateInputCluster, # 18
OppleSwitchCluster, # 0xFCC0 / 64704
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOffCluster,
MultistateInputCluster,
OppleSwitchCluster,
],
OUTPUT_CLUSTERS: [],
},
Expand All @@ -154,7 +158,7 @@ class XiaomiOpple2ButtonSwitchBase(XiaomiCustomDevice):
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
AnalogInput.cluster_id, # 12
AnalogInputCluster,
],
OUTPUT_CLUSTERS: [],
},
Expand All @@ -163,7 +167,7 @@ class XiaomiOpple2ButtonSwitchBase(XiaomiCustomDevice):
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
AnalogInput.cluster_id, # 12
AnalogInput.cluster_id,
],
OUTPUT_CLUSTERS: [],
},
Expand All @@ -172,7 +176,7 @@ class XiaomiOpple2ButtonSwitchBase(XiaomiCustomDevice):
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
MultistateInputCluster, # 18
MultistateInputCluster,
],
OUTPUT_CLUSTERS: [],
},
Expand All @@ -181,7 +185,7 @@ class XiaomiOpple2ButtonSwitchBase(XiaomiCustomDevice):
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
MultistateInputCluster, # 18
MultistateInputCluster,
],
OUTPUT_CLUSTERS: [],
},
Expand All @@ -190,7 +194,7 @@ class XiaomiOpple2ButtonSwitchBase(XiaomiCustomDevice):
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
MultistateInputCluster, # 18
MultistateInputCluster,
],
OUTPUT_CLUSTERS: [],
},
Expand All @@ -199,7 +203,7 @@ class XiaomiOpple2ButtonSwitchBase(XiaomiCustomDevice):
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
MultistateInputCluster, # 18
MultistateInputCluster,
],
OUTPUT_CLUSTERS: [],
},
Expand Down Expand Up @@ -273,23 +277,22 @@ class XiaomiOpple2ButtonSwitchBase(XiaomiCustomDevice):
class XiaomiOpple2ButtonSwitchFace1(XiaomiOpple2ButtonSwitchBase):
"""Xiaomi Opple 2 Button Switch. Face 1."""

device_automation_triggers = XiaomiOpple2ButtonSwitchBase.device_automation_triggers

signature = {
MODELS_INFO: [(LUMI, "lumi.switch.b2naus01")],
ENDPOINTS: {
# input_clusters=[0, 2, 3, 4, 5, 6, 18, 64704], output_clusters=[10, 25]
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id, # 0
DeviceTemperatureCluster.cluster_id, # 2
Identify.cluster_id, # 3
Groups.cluster_id, # 4
Scenes.cluster_id, # 5
OnOff.cluster_id, # 6
MultistateInputCluster.cluster_id, # 18
OppleSwitchCluster.cluster_id, # 0xFCC0 / 64704
Basic.cluster_id,
DeviceTemperatureCluster.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
MultistateInputCluster.cluster_id,
OppleSwitchCluster.cluster_id,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
Expand All @@ -298,13 +301,13 @@ class XiaomiOpple2ButtonSwitchFace1(XiaomiOpple2ButtonSwitchBase):
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id, # 0
Identify.cluster_id, # 3
Groups.cluster_id, # 4
Scenes.cluster_id, # 5
OnOff.cluster_id, # 6
MultistateInputCluster.cluster_id, # 18
OppleSwitchCluster.cluster_id, # 0xFCC0 / 64704
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
MultistateInputCluster.cluster_id,
OppleSwitchCluster.cluster_id,
],
OUTPUT_CLUSTERS: [],
},
Expand All @@ -313,7 +316,7 @@ class XiaomiOpple2ButtonSwitchFace1(XiaomiOpple2ButtonSwitchBase):
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
AnalogInput.cluster_id, # 12
AnalogInput.cluster_id,
],
OUTPUT_CLUSTERS: [],
},
Expand All @@ -322,7 +325,7 @@ class XiaomiOpple2ButtonSwitchFace1(XiaomiOpple2ButtonSwitchBase):
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
AnalogInput.cluster_id, # 12
AnalogInput.cluster_id,
],
OUTPUT_CLUSTERS: [],
},
Expand All @@ -331,7 +334,7 @@ class XiaomiOpple2ButtonSwitchFace1(XiaomiOpple2ButtonSwitchBase):
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
MultistateInputCluster.cluster_id, # 18
MultistateInputCluster.cluster_id,
],
OUTPUT_CLUSTERS: [],
},
Expand All @@ -340,7 +343,7 @@ class XiaomiOpple2ButtonSwitchFace1(XiaomiOpple2ButtonSwitchBase):
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
MultistateInputCluster.cluster_id, # 18
MultistateInputCluster.cluster_id,
],
OUTPUT_CLUSTERS: [],
},
Expand All @@ -349,54 +352,7 @@ class XiaomiOpple2ButtonSwitchFace1(XiaomiOpple2ButtonSwitchBase):
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
MultistateInputCluster.cluster_id, # 18
],
OUTPUT_CLUSTERS: [],
},
242: {
PROFILE_ID: zgp.PROFILE_ID,
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}


class XiaomiOpple2ButtonSwitchFace2(XiaomiOpple2ButtonSwitchBase):
"""Xiaomi Opple 2 Button Switch. Face 2."""

device_automation_triggers = XiaomiOpple2ButtonSwitchBase.device_automation_triggers

signature = {
ENDPOINTS: {
# input_clusters=[0, 2, 3, 4, 5, 6, 18, 64704], output_clusters=[10, 25]
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id, # 0
DeviceTemperatureCluster.cluster_id, # 2
Identify.cluster_id, # 3
Groups.cluster_id, # 4
Scenes.cluster_id, # 5
OnOff.cluster_id, # 6
Alarms.cluster_id, # 9
XiaomiMeteringCluster.cluster_id, # 0x0702
0x0B04,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
# input_clusters=[0, 3, 4, 5, 6, 18, 64704], output_clusters=[]
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id, # 0
Identify.cluster_id, # 3
Groups.cluster_id, # 4
Scenes.cluster_id, # 5
OnOff.cluster_id, # 6
MultistateInputCluster.cluster_id,
],
OUTPUT_CLUSTERS: [],
},
Expand Down
Loading

0 comments on commit 4f5abdd

Please sign in to comment.