Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Aqara Ceiling Light T1M (acn032) #3070

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
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
49 changes: 49 additions & 0 deletions tests/test_xiaomi.py
Original file line number Diff line number Diff line change
Expand Up @@ -1756,3 +1756,52 @@ def test_aqara_acn014_signature_match(assert_signature_matches_quirk):
assert_signature_matches_quirk(
zhaquirks.xiaomi.aqara.light_acn.LumiLightAcn014, signature
)


def test_aqara_acn032_signature_match(assert_signature_matches_quirk):
"""Test signature."""
signature = {
"node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4447, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
"endpoints": {
"1": {
"profile_id": 0x0104,
"device_type": "0x0102",
"in_clusters": [
"0x0000",
"0x0003",
"0x0004",
"0x0005",
"0x0006",
"0x0008",
"0x0300",
"0xfcc0"
],
"out_clusters": [
"0x000a",
"0x0019"
]
},
"2": {
"profile_id": 0x0104,
"device_type": "0x0102",
"in_clusters": [
"0x0003",
"0x0004",
"0x0005",
"0x0006",
"0x0008",
"0x0300",
"0xfcc0"
],
"out_clusters": []
}
},
"manufacturer": "Aqara",
"model": "lumi.light.acn032",
"class": "aqara_light.LumiLightAcn032"
}

assert_signature_matches_quirk(
zhaquirks.xiaomi.aqara.light_acn.LumiLightAcn032, signature
)

108 changes: 108 additions & 0 deletions zhaquirks/xiaomi/aqara/light_acn.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from zigpy.zcl.clusters.homeautomation import ElectricalMeasurement
from zigpy.zcl.clusters.lighting import Color
from zigpy.zcl.clusters.smartenergy import Metering
from zigpy.zcl.foundation import ZCLAttributeDef

from zhaquirks.const import (
DEVICE_TYPE,
Expand All @@ -37,6 +38,17 @@
)


class LumiPowerOnBehaviorMode(t.uint8_t):
"""Power on behavior mode."""

On = 0x00
"""Will be turned on after power outage."""
PreserveState = 0x01
"""Will keep the state it was before power outage."""
Off = 0x02
"""Will be turned off after power outage."""


class OppleClusterLight(XiaomiAqaraE1Cluster):
"""Add Opple cluster for power outage memory attribute."""

Expand All @@ -45,6 +57,18 @@ class OppleClusterLight(XiaomiAqaraE1Cluster):
}


class LumiClusterLight(XiaomiAqaraE1Cluster):
"""Add power on behavior management for Lumi devices."""

manufacturer_id_override = 4447

attributes = XiaomiAqaraE1Cluster.attributes.copy()
attributes[0x0517] = ZCLAttributeDef(
id=0x0517, type=LumiPowerOnBehaviorMode, is_manufacturer_specific=True,
name="power_on_behavior"
)


class LumiLightAcn003(XiaomiCustomDevice):
"""Quirk for Aqara ceiling light L1-350 also known as Xiaomi ZNXDD01LM.

Expand Down Expand Up @@ -200,3 +224,87 @@ class LumiLightAcn014(XiaomiCustomDevice):
},
}
}


class LumiLightAcn032(XiaomiCustomDevice):
"""Aqara Light T1M (ceiling light with RGB ring).

This quirk adds support for power on behavior by adding the power_outage_memory attribute, the rest works out
of the box.

It MIGHT also work for the Model T1 (acn031) but it has not been tested.
"""

signature = {
MODELS_INFO: [("Aqara", "lumi.light.acn032"), ],
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COLOR_DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
BasicCluster.cluster_id, # 0x0000
Identify.cluster_id, # 0x0003
Groups.cluster_id, # 0x0004
Scenes.cluster_id, # 0x0005
OnOff.cluster_id, # 0x0006
LevelControl.cluster_id, # 0x0008
Color.cluster_id, # 0x0300
LumiClusterLight.cluster_id, # 0xFCC0 - manufacturer specific
],
OUTPUT_CLUSTERS: [
Time.cluster_id, # 0x000A
Ota.cluster_id, # 0x0019
],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COLOR_DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Identify.cluster_id, # 0x0003
Groups.cluster_id, # 0x0004
Scenes.cluster_id, # 0x0005
OnOff.cluster_id, # 0x0006
LevelControl.cluster_id, # 0x0008
Color.cluster_id, # 0x0300
LumiClusterLight.cluster_id, # 0xFCC0 - manufacturer specific
],
OUTPUT_CLUSTERS: [],
}
}
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COLOR_DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
BasicCluster.cluster_id,
Identify.cluster_id, # 0x0003
Groups.cluster_id, # 0x0004
Scenes.cluster_id, # 0x0005
OnOff.cluster_id, # 0x0006
LevelControl.cluster_id, # 0x0008
Color.cluster_id, # 0x0300
LumiClusterLight,
],
OUTPUT_CLUSTERS: [
Time.cluster_id, # 0x000A
Ota.cluster_id, # 0x0019
],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COLOR_DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Identify.cluster_id, # 0x0003
Groups.cluster_id, # 0x0004
Scenes.cluster_id, # 0x0005
OnOff.cluster_id, # 0x0006
LevelControl.cluster_id, # 0x0008
Color.cluster_id, # 0x0300
LumiClusterLight.cluster_id, # 0xFCC0 - manufacturer specific
],
OUTPUT_CLUSTERS: [],
}
}
}
Loading