Skip to content

Commit 07532ad

Browse files
Matter Window Covering: Update preset handling (#2295)
This change utilizes the setPresetPosition command that was recently added to the windowCoveringPreset capability to set the preset rather than using an embedded preference.
1 parent 8a193a8 commit 07532ad

File tree

8 files changed

+63
-30
lines changed

8 files changed

+63
-30
lines changed

drivers/SmartThings/matter-window-covering/profiles/window-covering-battery.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,5 @@ components:
1717
categories:
1818
- name: Blind
1919
preferences:
20-
- preferenceId: presetPosition
21-
explicit: true
2220
- preferenceId: reverse
2321
explicit: true

drivers/SmartThings/matter-window-covering/profiles/window-covering-batteryLevel.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,5 @@ components:
1717
categories:
1818
- name: Blind
1919
preferences:
20-
- preferenceId: presetPosition
21-
explicit: true
2220
- preferenceId: reverse
2321
explicit: true

drivers/SmartThings/matter-window-covering/profiles/window-covering-profile.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,5 @@ components:
1818
categories:
1919
- name: Blind
2020
preferences:
21-
- preferenceId: presetPosition
22-
explicit: true
2321
- preferenceId: reverse
2422
explicit: true

drivers/SmartThings/matter-window-covering/profiles/window-covering-tilt-battery.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,5 @@ components:
1919
categories:
2020
- name: Blind
2121
preferences:
22-
- preferenceId: presetPosition
23-
explicit: true
2422
- preferenceId: reverse
2523
explicit: true

drivers/SmartThings/matter-window-covering/profiles/window-covering-tilt.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,5 @@ components:
1717
categories:
1818
- name: Blind
1919
preferences:
20-
- preferenceId: presetPosition
21-
explicit: true
2220
- preferenceId: reverse
2321
explicit: true

drivers/SmartThings/matter-window-covering/profiles/window-covering.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,5 @@ components:
1515
categories:
1616
- name: Blind
1717
preferences:
18-
- preferenceId: presetPosition
19-
explicit: true
2018
- preferenceId: reverse
2119
explicit: true

drivers/SmartThings/matter-window-covering/src/init.lua

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ local battery_support = {
2828
BATTERY_PERCENTAGE = "BATTERY_PERCENTAGE"
2929
}
3030
local REVERSE_POLARITY = "__reverse_polarity"
31+
local PRESET_LEVEL_KEY = "__preset_level_key"
32+
local PRESET_LEVEL = 50
3133

3234
local function find_default_endpoint(device, cluster)
3335
local res = device.MATTER_DEFAULT_ENDPOINT
@@ -69,6 +71,17 @@ end
6971

7072
local function device_init(driver, device)
7173
device:set_component_to_endpoint_fn(component_to_endpoint)
74+
if device:supports_capability_by_id(capabilities.windowShadePreset.ID) and
75+
device:get_latest_state("main", capabilities.windowShadePreset.ID, capabilities.windowShadePreset.position.NAME) == nil then
76+
-- These should only ever be nil once (and at the same time) for already-installed devices
77+
-- It can be removed after migration is complete
78+
device:emit_event(capabilities.windowShadePreset.supportedCommands({"presetPosition", "setPresetPosition"}, {visibility = {displayed = false}}))
79+
local preset_position = device:get_field(PRESET_LEVEL_KEY) or
80+
(device.preferences ~= nil and device.preferences.presetPosition) or
81+
PRESET_LEVEL
82+
device:emit_event(capabilities.windowShadePreset.position(preset_position, {visibility = {displayed = false}}))
83+
device:set_field(PRESET_LEVEL_KEY, preset_position, {persist = true})
84+
end
7285
device:subscribe()
7386
end
7487

@@ -122,22 +135,29 @@ local function handle_preset(driver, device, cmd)
122135
local lift_eps = device:get_endpoints(clusters.WindowCovering.ID, {feature_bitmap = clusters.WindowCovering.types.Feature.LIFT})
123136
local tilt_eps = device:get_endpoints(clusters.WindowCovering.ID, {feature_bitmap = clusters.WindowCovering.types.Feature.TILT})
124137
if #lift_eps > 0 then
125-
local lift_value = 100 - device.preferences.presetPosition
126-
local hundredths_lift_percent = lift_value * 100
138+
local lift_value = device:get_latest_state(
139+
"main", capabilities.windowShadePreset.ID, capabilities.windowShadePreset.position.NAME
140+
) or PRESET_LEVEL
141+
local hundredths_lift_percent = (100 - lift_value) * 100
127142
local req = clusters.WindowCovering.server.commands.GoToLiftPercentage(
128143
device, endpoint_id, hundredths_lift_percent
129144
)
130145
device:send(req)
131146
end
132147
if #tilt_eps > 0 then
133-
-- Use default preset tilt percentage to 50 until a canonical preference is created for preset tilt position
134148
local req = clusters.WindowCovering.server.commands.GoToTiltPercentage(
135-
device, endpoint_id, 50 * 100
149+
device, endpoint_id, PRESET_LEVEL * 100
136150
)
137151
device:send(req)
138152
end
139153
end
140154

155+
local function handle_set_preset(driver, device, cmd)
156+
local endpoint_id = device:component_to_endpoint(cmd.component)
157+
device:set_field(PRESET_LEVEL_KEY, cmd.args.position)
158+
device:emit_event_for_endpoint(endpoint_id, capabilities.windowShadePreset.position(cmd.args.position))
159+
end
160+
141161
-- close covering
142162
local function handle_close(driver, device, cmd)
143163
local endpoint_id = device:component_to_endpoint(cmd.component)
@@ -345,6 +365,7 @@ local matter_driver_template = {
345365
capability_handlers = {
346366
[capabilities.windowShadePreset.ID] = {
347367
[capabilities.windowShadePreset.commands.presetPosition.NAME] = handle_preset,
368+
[capabilities.windowShadePreset.commands.setPresetPosition.NAME] = handle_set_preset,
348369
},
349370
[capabilities.windowShade.ID] = {
350371
[capabilities.windowShade.commands.close.NAME] = handle_close,

drivers/SmartThings/matter-window-covering/src/test/test_matter_window_covering.lua

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ local mock_device = test.mock_device.build_test_matter_device(
2626
{
2727
profile = t_utils.get_profile_definition("window-covering-tilt-battery.yml"),
2828
manufacturer_info = {vendor_id = 0x0000, product_id = 0x0000},
29-
preferences = { presetPosition = 30 },
3029
endpoints = {
3130
{
3231
endpoint_id = 2,
@@ -58,7 +57,6 @@ local mock_device_mains_powered = test.mock_device.build_test_matter_device(
5857
{
5958
profile = t_utils.get_profile_definition("window-covering.yml"),
6059
manufacturer_info = {vendor_id = 0x0000, product_id = 0x0000},
61-
preferences = { presetPosition = 30 },
6260
endpoints = {
6361
{
6462
endpoint_id = 2,
@@ -100,6 +98,19 @@ local CLUSTER_SUBSCRIBE_LIST_NO_BATTERY = {
10098
WindowCovering.server.attributes.OperationalStatus,
10199
}
102100

101+
local function set_preset(device)
102+
test.socket.capability:__expect_send(
103+
device:generate_test_message(
104+
"main", capabilities.windowShadePreset.supportedCommands({"presetPosition", "setPresetPosition"}, {visibility = {displayed = false}})
105+
)
106+
)
107+
test.socket.capability:__expect_send(
108+
device:generate_test_message(
109+
"main", capabilities.windowShadePreset.position(50, {visibility = {displayed = false}})
110+
)
111+
)
112+
end
113+
103114
local function test_init()
104115
test.mock_device.add_test_device(mock_device)
105116
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" })
@@ -111,6 +122,7 @@ local function test_init()
111122
)
112123

113124
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "init" })
125+
set_preset(mock_device)
114126
local subscribe_request = CLUSTER_SUBSCRIBE_LIST[1]:subscribe(mock_device)
115127
for i, clus in ipairs(CLUSTER_SUBSCRIBE_LIST) do
116128
if i > 1 then subscribe_request:merge(clus:subscribe(mock_device)) end
@@ -134,6 +146,7 @@ local function test_init_mains_powered()
134146
)
135147

136148
test.socket.device_lifecycle:__queue_receive({ mock_device_mains_powered.id, "init" })
149+
set_preset(mock_device_mains_powered)
137150
local subscribe_request = CLUSTER_SUBSCRIBE_LIST_NO_BATTERY[1]:subscribe(mock_device_mains_powered)
138151
for i, clus in ipairs(CLUSTER_SUBSCRIBE_LIST_NO_BATTERY) do
139152
if i > 1 then subscribe_request:merge(clus:subscribe(mock_device_mains_powered)) end
@@ -756,20 +769,31 @@ test.register_coroutine_test("OperationalStatus report contains current position
756769
)
757770
end)
758771

759-
test.register_coroutine_test("Handle windowcoveringPreset", function()
760-
test.socket.capability:__queue_receive(
761-
{
772+
test.register_coroutine_test(
773+
"Handle preset commands",
774+
function()
775+
local PRESET_LEVEL = 30
776+
test.socket.capability:__queue_receive({
777+
mock_device.id,
778+
{capability = "windowShadePreset", component = "main", command = "setPresetPosition", args = { PRESET_LEVEL }},
779+
})
780+
test.socket.capability:__expect_send(
781+
mock_device:generate_test_message(
782+
"main", capabilities.windowShadePreset.position(PRESET_LEVEL)
783+
)
784+
)
785+
test.socket.capability:__queue_receive({
762786
mock_device.id,
763787
{capability = "windowShadePreset", component = "main", command = "presetPosition", args = {}},
764-
}
765-
)
766-
test.socket.matter:__expect_send(
767-
{mock_device.id, WindowCovering.server.commands.GoToLiftPercentage(mock_device, 10, 7000)}
768-
)
769-
test.socket.matter:__expect_send(
770-
{mock_device.id, WindowCovering.server.commands.GoToTiltPercentage(mock_device, 10, 5000)}
771-
)
772-
end)
788+
})
789+
test.socket.matter:__expect_send(
790+
{mock_device.id, WindowCovering.server.commands.GoToLiftPercentage(mock_device, 10, (100 - PRESET_LEVEL) * 100)}
791+
)
792+
test.socket.matter:__expect_send(
793+
{mock_device.id, WindowCovering.server.commands.GoToTiltPercentage(mock_device, 10, 5000)}
794+
)
795+
end
796+
)
773797

774798
test.register_coroutine_test(
775799
"Test profile change to window-covering-battery when battery percent remaining attribute (attribute ID 12) is available",

0 commit comments

Comments
 (0)