Skip to content

Commit 43463ba

Browse files
Add Xiaomi LYWSD03MMC temp sensor with custom Zigbee firmware (#3329)
Co-authored-by: TheJulianJES <[email protected]>
1 parent a1c0b1e commit 43463ba

File tree

3 files changed

+183
-0
lines changed

3 files changed

+183
-0
lines changed

tests/test_xiaomi.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2165,6 +2165,35 @@ def test_aqara_acn014_signature_match(assert_signature_matches_quirk):
21652165
)
21662166

21672167

2168+
def test_custom_z03mmc_signature_match(assert_signature_matches_quirk):
2169+
"""Test signature."""
2170+
signature = {
2171+
"node_descriptor": "NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>, manufacturer_code=56085, maximum_buffer_size=74, maximum_incoming_transfer_size=404, server_mask=10752, maximum_outgoing_transfer_size=404, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False)",
2172+
"endpoints": {
2173+
"1": {
2174+
"profile_id": 0x0104,
2175+
"device_type": "0x0302",
2176+
"in_clusters": [
2177+
"0x0000",
2178+
"0x0001",
2179+
"0x0003",
2180+
"0x0204",
2181+
"0x0402",
2182+
"0x0405",
2183+
],
2184+
"out_clusters": ["0x0019"],
2185+
}
2186+
},
2187+
"manufacturer": "Xiaomi",
2188+
"model": "LYWSD03MMC",
2189+
"class": "zigpy.device.Device",
2190+
}
2191+
2192+
assert_signature_matches_quirk(
2193+
zhaquirks.xiaomi.custom.z03mmc.DevbisLYWSD03MMC, signature
2194+
)
2195+
2196+
21682197
@pytest.mark.parametrize(
21692198
"occupancy_value, expected_occ_status, motion_value, expected_motion_status",
21702199
[
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Module for Xiaomi custom firmware quirks implementations."""

zhaquirks/xiaomi/custom/z03mmc.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
"""Xiaomi LYWSD03MMC Bluetooth temperature and humidity sensor with custom firmware."""
2+
3+
from zigpy.profiles import zha
4+
from zigpy.quirks import CustomDevice
5+
from zigpy.types import Bool, int16s, uint16_t
6+
from zigpy.zcl.clusters.general import Basic, Identify, Ota, PowerConfiguration
7+
from zigpy.zcl.clusters.hvac import UserInterface
8+
from zigpy.zcl.clusters.measurement import RelativeHumidity, TemperatureMeasurement
9+
from zigpy.zcl.foundation import ZCLAttributeDef
10+
11+
from zhaquirks import CustomCluster
12+
from zhaquirks.const import (
13+
DEVICE_TYPE,
14+
ENDPOINTS,
15+
INPUT_CLUSTERS,
16+
MODELS_INFO,
17+
OUTPUT_CLUSTERS,
18+
PROFILE_ID,
19+
)
20+
21+
22+
class TemperatureMeasurementCustom(CustomCluster, TemperatureMeasurement):
23+
"""Temperature Measurement Cluster with calibration attribute."""
24+
25+
class AttributeDefs(TemperatureMeasurement.AttributeDefs):
26+
"""Attribute Definitions."""
27+
28+
# A value in 0.01ºC offset to fix up incorrect values from sensor
29+
temperature_calibration = ZCLAttributeDef(
30+
id=0x0010,
31+
type=int16s,
32+
access="rw",
33+
is_manufacturer_specific=True,
34+
)
35+
36+
37+
class RelativeHumidityCustom(CustomCluster, RelativeHumidity):
38+
"""Relative Humidity Cluster with calibration attribute."""
39+
40+
class AttributeDefs(RelativeHumidity.AttributeDefs):
41+
"""Attribute Definitions."""
42+
43+
# A value in 0.01%RH offset to fix up incorrect values from sensor
44+
humidity_calibration = ZCLAttributeDef(
45+
id=0x0010,
46+
type=int16s,
47+
access="rw",
48+
is_manufacturer_specific=True,
49+
)
50+
51+
52+
class UserInterfaceCustom(CustomCluster, UserInterface):
53+
"""Custom User Interface Cluster with smiley control."""
54+
55+
class AttributeDefs(UserInterface.AttributeDefs):
56+
"""Attribute Definitions."""
57+
58+
# of the 3 ZCL Thermostat User Interface spec attributes,
59+
# only the first one (TemperatureDisplayMode) is implemented fully.
60+
# KeypadLockout is implemented but completely unused in the device firmware
61+
# and ScheduleProgrammingVisibility is not implemented at all
62+
# https://github.com/devbis/z03mmc/blob/1.1.0/src/sensorEpCfg.c#L256
63+
64+
# 0 - smiley is off, 1 - smiley is on (according to comfort values)
65+
smiley = ZCLAttributeDef(
66+
id=0x0010,
67+
type=Bool,
68+
access="rw",
69+
is_manufacturer_specific=True,
70+
)
71+
72+
# display. 0 - display is off, 1 - display is on
73+
display = ZCLAttributeDef(
74+
id=0x0011,
75+
type=Bool,
76+
access="rw",
77+
is_manufacturer_specific=True,
78+
)
79+
80+
# comfort temperature min: A value in 0.01ºC to set minimum comfort temperature for happy face
81+
comfort_temperature_min = ZCLAttributeDef(
82+
id=0x0102,
83+
type=int16s,
84+
access="rw",
85+
is_manufacturer_specific=True,
86+
)
87+
88+
# comfort temperature max: A value in 0.01ºC to set maximum comfort temperature for happy face
89+
comfort_temperature_max = ZCLAttributeDef(
90+
id=0x0103,
91+
type=int16s,
92+
access="rw",
93+
is_manufacturer_specific=True,
94+
)
95+
96+
# comfort humidity min: A value in 0.01%RH to set minimum comfort humidity for happy face
97+
comfort_humidity_min = ZCLAttributeDef(
98+
id=0x0104,
99+
type=uint16_t,
100+
access="rw",
101+
is_manufacturer_specific=True,
102+
)
103+
104+
# comfort humidity max: A value in 0.01%RH to set maximum comfort humidity for happy face
105+
comfort_humidity_max = ZCLAttributeDef(
106+
id=0x0105,
107+
type=uint16_t,
108+
access="rw",
109+
is_manufacturer_specific=True,
110+
)
111+
112+
113+
# https://github.com/devbis/z03mmc
114+
# defined by 1.1.0 firmware (0x11003001)
115+
# see README.md in the repo for more info
116+
class DevbisLYWSD03MMC(CustomDevice):
117+
"""LYWSD03MMC sensor with devbis custom firmware."""
118+
119+
signature = {
120+
MODELS_INFO: [("Xiaomi", "LYWSD03MMC")],
121+
ENDPOINTS: {
122+
1: {
123+
PROFILE_ID: zha.PROFILE_ID,
124+
DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,
125+
INPUT_CLUSTERS: [
126+
Basic.cluster_id,
127+
Identify.cluster_id,
128+
PowerConfiguration.cluster_id,
129+
RelativeHumidity.cluster_id,
130+
TemperatureMeasurement.cluster_id,
131+
UserInterface.cluster_id,
132+
],
133+
OUTPUT_CLUSTERS: [Ota.cluster_id],
134+
},
135+
},
136+
}
137+
replacement = {
138+
ENDPOINTS: {
139+
1: {
140+
PROFILE_ID: zha.PROFILE_ID,
141+
DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,
142+
INPUT_CLUSTERS: [
143+
Basic.cluster_id,
144+
Identify.cluster_id,
145+
PowerConfiguration.cluster_id,
146+
RelativeHumidityCustom,
147+
TemperatureMeasurementCustom,
148+
UserInterfaceCustom,
149+
],
150+
OUTPUT_CLUSTERS: [Ota.cluster_id],
151+
},
152+
},
153+
}

0 commit comments

Comments
 (0)