Skip to content

Commit 821eb23

Browse files
committed
add HOPOsmart window opener A2230011
1 parent cc30d98 commit 821eb23

File tree

7 files changed

+337
-1
lines changed

7 files changed

+337
-1
lines changed

drivers/SmartThings/zigbee-window-treatment/fingerprints.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ zigbeeManufacturer:
128128
manufacturer: VIVIDSTORM
129129
model: VWSDSTUST120H
130130
deviceProfileName: projector-screen-VWSDSTUST120H
131+
- id: "HOPOsmart/A2230011"
132+
deviceLabel: HOPOsmart Window Opener A2230011
133+
manufacturer: HOPOsmart
134+
model: A2230011
135+
deviceProfileName: window-shade-only-HOPOsmart
131136

132137
zigbeeGeneric:
133138
- id: "genericShade"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: window-shade-only-HOPOsmart
2+
components:
3+
- id: main
4+
capabilities:
5+
- id: windowShade
6+
version: 1
7+
- id: firmwareUpdate
8+
version: 1
9+
- id: refresh
10+
version: 1
11+
categories:
12+
- name: WindowOpener
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
-- Copyright 2025 SmartThings
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
local data_types = require "st.zigbee.data_types"
16+
17+
local custom_clusters = {
18+
motor = {
19+
id = 0xFCC8,
20+
mfg_specific_code = 0x1235,
21+
attributes = {
22+
state_value = {
23+
id = 0x0000,
24+
value_type = data_types.Uint8,
25+
}
26+
}
27+
}
28+
}
29+
30+
return custom_clusters
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
-- Copyright 2025 SmartThings
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
local capabilities = require "st.capabilities"
16+
local custom_clusters = require "HOPOsmart/custom_clusters"
17+
local cluster_base = require "st.zigbee.cluster_base"
18+
19+
local ZIGBEE_WINDOW_SHADE_FINGERPRINTS = {
20+
{ mfr = "HOPOsmart", model = "A2230011" }
21+
}
22+
23+
24+
local is_zigbee_window_shade = function(opts, driver, device)
25+
for _, fingerprint in ipairs(ZIGBEE_WINDOW_SHADE_FINGERPRINTS) do
26+
if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then
27+
return true
28+
end
29+
end
30+
return false
31+
end
32+
33+
local function send_read_attr_request(device, cluster, attr)
34+
device:send(
35+
cluster_base.read_manufacturer_specific_attribute(
36+
device,
37+
cluster.id,
38+
attr.id,
39+
cluster.mfg_specific_code
40+
)
41+
)
42+
end
43+
44+
local function state_value_attr_handler(driver, device, value, zb_rx)
45+
if value.value == 0 then
46+
device:emit_event(capabilities.windowShade.windowShade.open())
47+
elseif value.value == 1 then
48+
device:emit_event(capabilities.windowShade.windowShade.opening())
49+
elseif value.value == 2 then
50+
device:emit_event(capabilities.windowShade.windowShade.closed())
51+
elseif value.value == 3 then
52+
device:emit_event(capabilities.windowShade.windowShade.closing())
53+
elseif value.value == 4 then
54+
device:emit_event(capabilities.windowShade.windowShade.partially_open())
55+
end
56+
end
57+
58+
local function do_refresh(driver, device)
59+
send_read_attr_request(device, custom_clusters.motor, custom_clusters.motor.attributes.state_value)
60+
end
61+
62+
local function added_handler(self, device)
63+
do_refresh(self, device)
64+
end
65+
66+
local HOPOsmart_handler = {
67+
NAME = "HOPOsmart Device Handler",
68+
supported_capabilities = {
69+
capabilities.refresh
70+
},
71+
lifecycle_handlers = {
72+
added = added_handler
73+
},
74+
capability_handlers = {
75+
[capabilities.refresh.ID] = {
76+
[capabilities.refresh.commands.refresh.NAME] = do_refresh
77+
}
78+
},
79+
zigbee_handlers = {
80+
attr = {
81+
[custom_clusters.motor.id] = {
82+
[custom_clusters.motor.attributes.state_value.id] = state_value_attr_handler
83+
}
84+
}
85+
},
86+
can_handle = is_zigbee_window_shade,
87+
}
88+
89+
return HOPOsmart_handler

drivers/SmartThings/zigbee-window-treatment/src/init.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ local zigbee_window_treatment_driver_template = {
5757
require("yoolax"),
5858
require("hanssem"),
5959
require("screen-innovations"),
60-
require("VIVIDSTORM")},
60+
require("VIVIDSTORM"),
61+
require("HOPOsmart")},
6162
lifecycle_handlers = {
6263
init = init_handler,
6364
added = added_handler
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
-- Copyright 2025 SmartThings
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
-- Mock out globals
16+
local test = require "integration_test"
17+
local zigbee_test_utils = require "integration_test.zigbee_test_utils"
18+
local clusters = require "st.zigbee.zcl.clusters"
19+
local capabilities = require "st.capabilities"
20+
local t_utils = require "integration_test.utils"
21+
local data_types = require "st.zigbee.data_types"
22+
local cluster_base = require "st.zigbee.cluster_base"
23+
24+
local PRIVATE_CLUSTER_ID = 0xFCC8
25+
local MFG_CODE = 0x1235
26+
27+
local mock_device = test.mock_device.build_test_zigbee_device(
28+
{ profile = t_utils.get_profile_definition("window-shade-only-HOPOsmart.yml"),
29+
fingerprinted_endpoint_id = 0x01,
30+
zigbee_endpoints = {
31+
[1] = {
32+
id = 1,
33+
manufacturer = "HOPOsmart",
34+
model = "A2230011",
35+
server_clusters = {0x0000, 0xFCC8}
36+
}
37+
}
38+
}
39+
)
40+
41+
zigbee_test_utils.prepare_zigbee_env_info()
42+
local function test_init()
43+
test.mock_device.add_test_device(mock_device)
44+
zigbee_test_utils.init_noop_health_check_timer()
45+
end
46+
47+
test.set_test_init_function(test_init)
48+
49+
test.register_coroutine_test(
50+
"lifecycle - added test",
51+
function()
52+
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" })
53+
54+
local read_0x0000_messge = cluster_base.read_manufacturer_specific_attribute(mock_device, PRIVATE_CLUSTER_ID, 0x0000, MFG_CODE)
55+
test.socket.zigbee:__expect_send({mock_device.id, read_0x0000_messge})
56+
end
57+
)
58+
59+
test.register_message_test(
60+
"Handle Window shade open command",
61+
{
62+
{
63+
channel = "capability",
64+
direction = "receive",
65+
message = {
66+
mock_device.id,
67+
{
68+
capability = "windowShade", component = "main", command = "open", args = {}
69+
}
70+
}
71+
},
72+
{
73+
channel = "zigbee",
74+
direction = "send",
75+
message = { mock_device.id, clusters.WindowCovering.server.commands.UpOrOpen(mock_device) }
76+
}
77+
}
78+
)
79+
80+
test.register_message_test(
81+
"Handle Window shade close command",
82+
{
83+
{
84+
channel = "capability",
85+
direction = "receive",
86+
message = {
87+
mock_device.id,
88+
{
89+
capability = "windowShade", component = "main", command = "close", args = {}
90+
}
91+
}
92+
},
93+
{
94+
channel = "zigbee",
95+
direction = "send",
96+
message = {
97+
mock_device.id,
98+
clusters.WindowCovering.server.commands.DownOrClose(mock_device)
99+
}
100+
}
101+
}
102+
)
103+
104+
test.register_message_test(
105+
"Handle Window shade pause command",
106+
{
107+
{
108+
channel = "capability",
109+
direction = "receive",
110+
message = { mock_device.id, { capability = "windowShade", component = "main", command = "pause", args = {} } }
111+
},
112+
{
113+
channel = "zigbee",
114+
direction = "send",
115+
message = {
116+
mock_device.id,
117+
clusters.WindowCovering.server.commands.Stop(mock_device)
118+
}
119+
}
120+
}
121+
)
122+
123+
test.register_coroutine_test(
124+
"Device reported 0 and driver emit windowShade.open",
125+
function()
126+
local attr_report_data = {
127+
{ 0x0000, data_types.Uint8.ID, 0 }
128+
}
129+
test.socket.zigbee:__queue_receive({
130+
mock_device.id,
131+
zigbee_test_utils.build_attribute_report(mock_device, PRIVATE_CLUSTER_ID, attr_report_data, MFG_CODE)
132+
})
133+
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
134+
capabilities.windowShade.windowShade.open()))
135+
end
136+
)
137+
138+
test.register_coroutine_test(
139+
"Device reported 1 and driver emit windowShade.opening",
140+
function()
141+
local attr_report_data = {
142+
{ 0x0000, data_types.Uint8.ID, 1 }
143+
}
144+
test.socket.zigbee:__queue_receive({
145+
mock_device.id,
146+
zigbee_test_utils.build_attribute_report(mock_device, PRIVATE_CLUSTER_ID, attr_report_data, MFG_CODE)
147+
})
148+
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
149+
capabilities.windowShade.windowShade.opening()))
150+
end
151+
)
152+
153+
test.register_coroutine_test(
154+
"Device reported 2 and driver emit windowShade.closed",
155+
function()
156+
local attr_report_data = {
157+
{ 0x0000, data_types.Uint8.ID, 2 }
158+
}
159+
test.socket.zigbee:__queue_receive({
160+
mock_device.id,
161+
zigbee_test_utils.build_attribute_report(mock_device, PRIVATE_CLUSTER_ID, attr_report_data, MFG_CODE)
162+
})
163+
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
164+
capabilities.windowShade.windowShade.closed()))
165+
end
166+
)
167+
168+
test.register_coroutine_test(
169+
"Device reported 3 and driver emit windowShade.closeing",
170+
function()
171+
local attr_report_data = {
172+
{ 0x0000, data_types.Uint8.ID, 3 }
173+
}
174+
test.socket.zigbee:__queue_receive({
175+
mock_device.id,
176+
zigbee_test_utils.build_attribute_report(mock_device, PRIVATE_CLUSTER_ID, attr_report_data, MFG_CODE)
177+
})
178+
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
179+
capabilities.windowShade.windowShade.closing()))
180+
end
181+
)
182+
183+
test.register_coroutine_test(
184+
"Device reported 4 and driver emit windowShade.partially_open",
185+
function()
186+
local attr_report_data = {
187+
{ 0x0000, data_types.Uint8.ID, 4 }
188+
}
189+
test.socket.zigbee:__queue_receive({
190+
mock_device.id,
191+
zigbee_test_utils.build_attribute_report(mock_device, PRIVATE_CLUSTER_ID, attr_report_data, MFG_CODE)
192+
})
193+
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
194+
capabilities.windowShade.windowShade.partially_open()))
195+
end
196+
)
197+
198+
test.run_registered_tests()

tools/localizations/cn.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,4 @@ Aqara Wireless Mini Switch T1,Aqara 无线开关 T1
117117
"WISTAR WSERD50-T Smart Tubular Motor",威仕达智能管状电机 WSERD50-T
118118
"WISTAR WSER60 Smart Tubular Motor",威仕达智能管状电机 WSER60
119119
"VIVIDSTORM Smart Screen VWSDSTUST120H",VIVIDSTORM智能幕布 VWSDSTUST120H
120+
"HOPOsmart Window Opener A2230011",HOPOsmart链式开窗器 A2230011

0 commit comments

Comments
 (0)