Skip to content

Commit 549aceb

Browse files
committed
add MultiIR contact sensor MIR_MC100
1 parent 98114d8 commit 549aceb

8 files changed

Lines changed: 239 additions & 0 deletions

File tree

drivers/SmartThings/zigbee-contact/fingerprints.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,11 @@ zigbeeManufacturer:
219219
manufacturer: Aug. Winkhaus SE
220220
model: FM.V.ZB
221221
deviceProfileName: contact-battery-profile
222+
- id: "MultIR/MIR-MC100"
223+
deviceLabel: MultiIR Contact Sensor MIR-MC100
224+
manufacturer: MultIR
225+
model: MIR-MC100
226+
deviceProfileName: contact-battery-tamper-no-fw-update
222227
zigbeeGeneric:
223228
- id: "contact-generic"
224229
deviceLabel: "Zigbee Contact Sensor"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: contact-battery-tamper-no-fw-update
2+
components:
3+
- id: main
4+
capabilities:
5+
- id: contactSensor
6+
version: 1
7+
- id: battery
8+
version: 1
9+
- id: tamperAlert
10+
version: 1
11+
- id: refresh
12+
version: 1
13+
categories:
14+
- name: ContactSensor
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- Copyright 2026 SmartThings, Inc.
2+
-- Licensed under the Apache License, Version 2.0
3+
4+
return function(opts, driver, device, ...)
5+
local FINGERPRINTS = require "MultiIR.fingerprints"
6+
for _, fingerprint in ipairs(FINGERPRINTS) do
7+
if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then
8+
local subdriver = require("MultiIR")
9+
return true, subdriver
10+
end
11+
end
12+
return false
13+
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- Copyright 2026 SmartThings, Inc.
2+
-- Licensed under the Apache License, Version 2.0
3+
4+
return {
5+
{ mfr = "MultIR", model = "MIR-MC100" }
6+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
-- Copyright 2026 SmartThings, Inc.
2+
-- Licensed under the Apache License, Version 2.0
3+
4+
5+
local clusters = require "st.zigbee.zcl.clusters"
6+
local capabilities = require "st.capabilities"
7+
local IASZone = clusters.IASZone
8+
9+
local function generate_event_from_zone_status(driver, device, zone_status, zb_rx)
10+
device:emit_event(zone_status:is_alarm1_set() and capabilities.contactSensor.contact.open() or capabilities.contactSensor.contact.closed())
11+
if device:supports_capability_by_id(capabilities.tamperAlert.ID) then
12+
device:emit_event(zone_status:is_tamper_set() and capabilities.tamperAlert.tamper.detected() or capabilities.tamperAlert.tamper.clear())
13+
end
14+
end
15+
16+
local function ias_zone_status_attr_handler(driver, device, attr_val, zb_rx)
17+
generate_event_from_zone_status(driver, device, attr_val, zb_rx)
18+
end
19+
20+
local function ias_zone_status_change_handler(driver, device, zb_rx)
21+
generate_event_from_zone_status(driver, device, zb_rx.body.zcl_body.zone_status, zb_rx)
22+
end
23+
24+
local function added_handler(driver, device)
25+
device:emit_event(capabilities.battery.battery(100))
26+
device:emit_event(capabilities.contactSensor.contact.closed())
27+
if device:supports_capability_by_id(capabilities.tamperAlert.ID) then
28+
device:emit_event(capabilities.tamperAlert.tamper.clear())
29+
end
30+
end
31+
32+
local MultiIR_sensor = {
33+
NAME = "MultiIR Contact Sensor",
34+
lifecycle_handlers = {
35+
added = added_handler
36+
},
37+
zigbee_handlers = {
38+
cluster = {
39+
[IASZone.ID] = {
40+
[IASZone.client.commands.ZoneStatusChangeNotification.ID] = ias_zone_status_change_handler,
41+
}
42+
},
43+
attr = {
44+
[IASZone.ID] = {
45+
[IASZone.attributes.ZoneStatus.ID] = ias_zone_status_attr_handler,
46+
}
47+
}
48+
},
49+
can_handle = require("MultiIR.can_handle")
50+
}
51+
52+
return MultiIR_sensor

drivers/SmartThings/zigbee-contact/src/sub_drivers.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ local sub_drivers = {
1010
lazy_load_if_possible("smartsense-multi"),
1111
lazy_load_if_possible("sengled"),
1212
lazy_load_if_possible("frient"),
13+
lazy_load_if_possible("MultiIR"),
1314
}
1415
return sub_drivers
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
-- Copyright 2026 SmartThings, Inc.
2+
-- Licensed under the Apache License, Version 2.0
3+
4+
local test = require "integration_test"
5+
local clusters = require "st.zigbee.zcl.clusters"
6+
local capabilities = require "st.capabilities"
7+
local t_utils = require "integration_test.utils"
8+
local zigbee_test_utils = require "integration_test.zigbee_test_utils"
9+
10+
local IASZone = clusters.IASZone
11+
12+
local mock_device = test.mock_device.build_test_zigbee_device(
13+
{ profile = t_utils.get_profile_definition("contact-battery-tamper-no-fw-update.yml"),
14+
zigbee_endpoints = {
15+
[0x01] = {
16+
id = 0x01,
17+
manufacturer = "MultIR",
18+
model = "MIR-MC100",
19+
server_clusters = { 0x0001, 0x0500 }
20+
}
21+
}
22+
}
23+
)
24+
25+
zigbee_test_utils.prepare_zigbee_env_info()
26+
27+
local function test_init()
28+
test.mock_device.add_test_device(mock_device)
29+
end
30+
31+
test.set_test_init_function(test_init)
32+
33+
test.register_coroutine_test(
34+
"Handle added lifecycle",
35+
function()
36+
test.socket.zigbee:__set_channel_ordering("relaxed")
37+
test.socket.capability:__set_channel_ordering("relaxed")
38+
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" })
39+
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
40+
capabilities.battery.battery(100)))
41+
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
42+
capabilities.contactSensor.contact.closed()))
43+
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
44+
capabilities.tamperAlert.tamper.clear()))
45+
end,
46+
{
47+
min_api_version = 19
48+
}
49+
)
50+
51+
test.register_message_test(
52+
"Reported ZoneStatus should be handled: contact/closed tamper/clear",
53+
{
54+
{
55+
channel = "zigbee",
56+
direction = "receive",
57+
message = { mock_device.id, IASZone.attributes.ZoneStatus:build_test_attr_report(mock_device, 0x0000) }
58+
},
59+
{
60+
channel = "capability",
61+
direction = "send",
62+
message = mock_device:generate_test_message("main", capabilities.contactSensor.contact.closed())
63+
},
64+
{
65+
channel = "capability",
66+
direction = "send",
67+
message = mock_device:generate_test_message("main", capabilities.tamperAlert.tamper.clear())
68+
}
69+
},
70+
{
71+
min_api_version = 19
72+
}
73+
)
74+
75+
test.register_message_test(
76+
"Reported ZoneStatus should be handled: contact/open tamper/detected",
77+
{
78+
{
79+
channel = "zigbee",
80+
direction = "receive",
81+
message = { mock_device.id, IASZone.attributes.ZoneStatus:build_test_attr_report(mock_device, 0x0005) }
82+
},
83+
{
84+
channel = "capability",
85+
direction = "send",
86+
message = mock_device:generate_test_message("main", capabilities.contactSensor.contact.open())
87+
},
88+
{
89+
channel = "capability",
90+
direction = "send",
91+
message = mock_device:generate_test_message("main", capabilities.tamperAlert.tamper.detected())
92+
}
93+
},
94+
{
95+
min_api_version = 19
96+
}
97+
)
98+
99+
test.register_message_test(
100+
"ZoneStatusChangeNotification should be handled: contact/open tamper/detected",
101+
{
102+
{
103+
channel = "zigbee",
104+
direction = "receive",
105+
message = { mock_device.id, IASZone.client.commands.ZoneStatusChangeNotification.build_test_rx(mock_device, 0x0005, 0x00) }
106+
},
107+
{
108+
channel = "capability",
109+
direction = "send",
110+
message = mock_device:generate_test_message("main", capabilities.contactSensor.contact.open())
111+
},
112+
{
113+
channel = "capability",
114+
direction = "send",
115+
message = mock_device:generate_test_message("main", capabilities.tamperAlert.tamper.detected())
116+
}
117+
},
118+
{
119+
min_api_version = 19
120+
}
121+
)
122+
123+
test.register_message_test(
124+
"ZoneStatusChangeNotification should be handled: contact/closed tamper/clear",
125+
{
126+
{
127+
channel = "zigbee",
128+
direction = "receive",
129+
message = { mock_device.id, IASZone.client.commands.ZoneStatusChangeNotification.build_test_rx(mock_device, 0x0000, 0x00) }
130+
},
131+
{
132+
channel = "capability",
133+
direction = "send",
134+
message = mock_device:generate_test_message("main", capabilities.contactSensor.contact.closed())
135+
},
136+
{
137+
channel = "capability",
138+
direction = "send",
139+
message = mock_device:generate_test_message("main", capabilities.tamperAlert.tamper.clear())
140+
}
141+
},
142+
{
143+
min_api_version = 19
144+
}
145+
)
146+
147+
test.run_registered_tests()

tools/localizations/cn.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,4 @@ Aqara Wireless Mini Switch T1,Aqara 无线开关 T1
134134
"WISTAR WSCMXJ Smart Curtain Motor",威仕达智能开合帘电机 WSCMXJ
135135
"HAOJAI Smart Switch 3-key",好家智能三键开关
136136
"HAOJAI Smart Switch 6-key",好家智能六键开关
137+
"MultiIR Contact Sensor MIR-MC100",麦乐克门窗开关传感器MIR-MC100

0 commit comments

Comments
 (0)