Skip to content

Commit 090ac00

Browse files
committed
add MultiIR Smart button MIR-SO100
1 parent 310e7e0 commit 090ac00

File tree

7 files changed

+206
-0
lines changed

7 files changed

+206
-0
lines changed

drivers/SmartThings/zigbee-button/fingerprints.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,11 @@ zigbeeManufacturer:
262262
manufacturer: WALL HERO
263263
model: ACL-401SCA4
264264
deviceProfileName: thirty-buttons
265+
- id: "MultIR/MIR-SO100"
266+
deviceLabel: MultiIR Smart button MIR-SO100
267+
manufacturer: MultIR
268+
model: MIR-SO100
269+
deviceProfileName: one-button-battery
265270
zigbeeGeneric:
266271
- id: "generic-button-sensor"
267272
deviceLabel: "Zigbee Generic Button"
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-SO100" }
6+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
-- Copyright 2026 SmartThings, Inc.
2+
-- Licensed under the Apache License, Version 2.0
3+
4+
5+
local zcl_clusters = require "st.zigbee.zcl.clusters"
6+
local capabilities = require "st.capabilities"
7+
local button_utils = require "button_utils"
8+
local log = require "log"
9+
10+
local IASZone = zcl_clusters.IASZone
11+
local PRIVATE_CMD_ID = 0xF1
12+
13+
local function ias_zone_private_cmd_handler(self, device, zb_rx)
14+
local cmd_data = zb_rx.body.zcl_body.body_bytes:byte(1)
15+
if cmd_data == 0 then
16+
device:emit_event(capabilities.button.button.pushed({state_change = true}))
17+
elseif cmd_data == 1 then
18+
device:emit_event(capabilities.button.button.double({state_change = true}))
19+
elseif cmd_data == 0x80 then
20+
device:emit_event(capabilities.button.button.held({state_change = true}))
21+
else
22+
log.info("ias_zone_private_cmd Unknown value",zb_rx.body.zcl_body.body_bytes:byte(1))
23+
end
24+
end
25+
26+
local function added_handler(self, device)
27+
device:emit_event(capabilities.button.supportedButtonValues({"pushed","double","held"}, {visibility = { displayed = false }}))
28+
device:emit_event(capabilities.button.numberOfButtons({value = 1}, {visibility = { displayed = false }}))
29+
button_utils.emit_event_if_latest_state_missing(device, "main", capabilities.button, capabilities.button.button.NAME, capabilities.button.button.pushed({state_change = false}))
30+
end
31+
32+
local MultiIR_Emergency_Button = {
33+
NAME = "MultiIR Emergency Button",
34+
lifecycle_handlers = {
35+
added = added_handler,
36+
},
37+
zigbee_handlers = {
38+
cluster = {
39+
[IASZone.ID] = {
40+
[PRIVATE_CMD_ID] = ias_zone_private_cmd_handler
41+
}
42+
}
43+
},
44+
sub_drivers = {},
45+
can_handle = require("MultiIR.can_handle"),
46+
}
47+
48+
return MultiIR_Emergency_Button

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ local sub_drivers = {
1313
lazy_load_if_possible("ewelink"),
1414
lazy_load_if_possible("thirdreality"),
1515
lazy_load_if_possible("ezviz"),
16+
lazy_load_if_possible("MultiIR"),
1617
}
1718
return sub_drivers
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
-- Copyright 2026 SmartThings, Inc.
2+
-- Licensed under the Apache License, Version 2.0
3+
4+
-- Mock out globals
5+
local capabilities = require "st.capabilities"
6+
local clusters = require "st.zigbee.zcl.clusters"
7+
local t_utils = require "integration_test.utils"
8+
local test = require "integration_test"
9+
local zigbee_test_utils = require "integration_test.zigbee_test_utils"
10+
11+
local IASZone = clusters.IASZone
12+
13+
local button_attr = capabilities.button.button
14+
local PRIVATE_CMD_ID = 0xF1
15+
16+
local mock_device = test.mock_device.build_test_zigbee_device(
17+
{
18+
profile = t_utils.get_profile_definition("one-button-battery.yml"),
19+
zigbee_endpoints = {
20+
[1] = {
21+
id = 1,
22+
manufacturer = "MultIR",
23+
model = "MIR-SO100",
24+
server_clusters = {0x0000, 0x0001, 0x0003, 0x0020, 0x0500, 0x0B05}
25+
}
26+
}
27+
}
28+
)
29+
30+
zigbee_test_utils.prepare_zigbee_env_info()
31+
local function test_init()
32+
test.mock_device.add_test_device(mock_device)end
33+
34+
test.set_test_init_function(test_init)
35+
36+
37+
38+
test.register_coroutine_test(
39+
"added lifecycle event",
40+
function()
41+
-- The initial button pushed event should be send during the device's first time onboarding
42+
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" })
43+
test.socket.capability:__set_channel_ordering("relaxed")
44+
test.socket.capability:__expect_send(
45+
mock_device:generate_test_message(
46+
"main",
47+
capabilities.button.supportedButtonValues({ "pushed","double","held" }, { visibility = { displayed = false } })
48+
)
49+
)
50+
test.socket.capability:__expect_send(
51+
mock_device:generate_test_message(
52+
"main",
53+
capabilities.button.numberOfButtons({ value = 1 }, { visibility = { displayed = false } })
54+
)
55+
)
56+
test.socket.capability:__expect_send({
57+
mock_device.id,
58+
{
59+
capability_id = "button", component_id = "main",
60+
attribute_id = "button", state = { value = "pushed" }
61+
}
62+
})
63+
-- Avoid sending the initial button pushed event after driver switch-over, as the switch-over event itself re-triggers the added lifecycle.
64+
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" })
65+
test.socket.capability:__set_channel_ordering("relaxed")
66+
test.socket.capability:__expect_send(
67+
mock_device:generate_test_message(
68+
"main",
69+
capabilities.button.supportedButtonValues({ "pushed","double","held" }, { visibility = { displayed = false } })
70+
)
71+
)
72+
test.socket.capability:__expect_send(
73+
mock_device:generate_test_message(
74+
"main",
75+
capabilities.button.numberOfButtons({ value = 1 }, { visibility = { displayed = false } })
76+
)
77+
)
78+
end,
79+
{
80+
min_api_version = 19
81+
}
82+
)
83+
84+
test.register_message_test(
85+
"IASZone cmd 0xF1 0x00 are handled",
86+
{
87+
{
88+
channel = "zigbee",
89+
direction = "receive",
90+
message = { mock_device.id, zigbee_test_utils.build_custom_command_id(mock_device, IASZone.ID, PRIVATE_CMD_ID, 0x0000, "\x00", 0x01) }
91+
},
92+
{
93+
channel = "capability",
94+
direction = "send",
95+
message = mock_device:generate_test_message("main", capabilities.button.button.pushed({state_change = true}))
96+
}
97+
}
98+
)
99+
100+
test.register_message_test(
101+
"IASZone cmd 0xF1 0x01 are handled",
102+
{
103+
{
104+
channel = "zigbee",
105+
direction = "receive",
106+
message = { mock_device.id, zigbee_test_utils.build_custom_command_id(mock_device, IASZone.ID, PRIVATE_CMD_ID, 0x0000, "\x01", 0x01) }
107+
},
108+
{
109+
channel = "capability",
110+
direction = "send",
111+
message = mock_device:generate_test_message("main", capabilities.button.button.double({state_change = true}))
112+
}
113+
}
114+
)
115+
116+
test.register_message_test(
117+
"IASZone cmd 0xF1 0x01 are handled",
118+
{
119+
{
120+
channel = "zigbee",
121+
direction = "receive",
122+
message = { mock_device.id, zigbee_test_utils.build_custom_command_id(mock_device, IASZone.ID, PRIVATE_CMD_ID, 0x0000, "\x80", 0x01) }
123+
},
124+
{
125+
channel = "capability",
126+
direction = "send",
127+
message = mock_device:generate_test_message("main", capabilities.button.button.held({state_change = true}))
128+
}
129+
}
130+
)
131+
132+
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 Smart button MIR-SO100",麦乐克智能按钮MIR-SO100

0 commit comments

Comments
 (0)