Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ lua_libs-api_*
tools/test_output/*
tools/coverage_output/*
.DS_Store
.venv/
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
-- limitations under the License.

local capabilities = require "st.capabilities"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"
local window_shade_utils = require "window_shade_utils"
local zcl_clusters = require "st.zigbee.zcl.clusters"
local utils = require "st.utils"

Expand Down Expand Up @@ -52,7 +52,7 @@ local function window_shade_level_cmd_handler(driver, device, command)
end

local function window_shade_preset_cmd(driver, device, command)
local level = device.preferences and device.preferences.presetPosition or window_preset_defaults.PRESET_LEVEL
local level = window_shade_utils.get_preset_level(device, command.component)
window_shade_set_level(device, command, level)
end

Expand Down
4 changes: 2 additions & 2 deletions drivers/SmartThings/zigbee-window-treatment/src/axis/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

local capabilities = require "st.capabilities"
local device_management = require "st.zigbee.device_management"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"
local window_shade_utils = require "window_shade_utils"
local zcl_clusters = require "st.zigbee.zcl.clusters"
local utils = require "st.utils"

Expand Down Expand Up @@ -50,7 +50,7 @@ local function window_shade_level_cmd_handler(driver, device, command)
end

local function window_shade_preset_cmd(driver, device, command)
local level = device.preferences and device.preferences.presetPosition or window_preset_defaults.PRESET_LEVEL
local level = window_shade_utils.get_preset_level(device, command.component)
window_shade_set_level(device, command, level)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

local capabilities = require "st.capabilities"
local zcl_clusters = require "st.zigbee.zcl.clusters"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"
local window_shade_utils = require "window_shade_utils"
local window_shade_defaults = require "st.zigbee.defaults.windowShade_defaults"
local device_management = require "st.zigbee.device_management"
local Level = zcl_clusters.Level
Expand Down Expand Up @@ -50,7 +50,7 @@ local function level_attr_handler(driver, device, value, zb_rx)
end

local function window_shade_preset_cmd(driver, device, command)
local level = device.preferences.presetPosition or device:get_field(window_preset_defaults.PRESET_LEVEL_KEY) or window_preset_defaults.PRESET_LEVEL
local level = window_shade_utils.get_preset_level(device, command.component)
set_shade_level(device, level, command.component)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ local Messages = require "st.zigbee.messages"
local data_types = require "st.zigbee.data_types"
local ZigbeeConstants = require "st.zigbee.constants"
local generic_body = require "st.zigbee.generic_body"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"
local window_shade_utils = require "window_shade_utils"

local TUYA_CLUSTER = 0xEF00
local DP_TYPE_VALUE = "\x02"
Expand Down Expand Up @@ -148,7 +148,7 @@ local function SetShadeLevelHandler(driver, device, capability_command)
end

local function PresetPositionHandler(driver, device, capability_command)
local level = device.preferences.presetPosition or device:get_field(window_preset_defaults.PRESET_LEVEL_KEY) or window_preset_defaults.PRESET_LEVEL
local level = window_shade_utils.get_preset_level(device, capability_command.component)
SetShadeLevelHandler(driver, device, {args = { shadeLevel = level }})
end

Expand Down
18 changes: 18 additions & 0 deletions drivers/SmartThings/zigbee-window-treatment/src/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,23 @@
local capabilities = require "st.capabilities"
local ZigbeeDriver = require "st.zigbee"
local defaults = require "st.zigbee.defaults"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"

local function init_handler(self, device)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like I mentioned in the CHAD-15784, we need this.
device:emit_event(capabilities.windowShadePreset.supportedCommands({"presetPosition", "setPresetPosition"}, { visibility = { displayed = false }})) in init handler.

Copy link
Contributor

@inasail inasail Jul 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if device:supports_capability_by_id(capabilities.windowShadePreset.ID) and
device:get_latest_state("main", capabilities.windowShadePreset.ID, capabilities.windowShadePreset.position.NAME) == nil then

local preset_position = device:get_field(window_preset_defaults.PRESET_LEVEL_KEY)
if preset_position == nil and device.preferences ~= nil and device.preferences.presetPosition ~= nil then
preset_position = device.preferences.presetPosition
device:set_field(window_preset_defaults.PRESET_LEVEL_KEY, device.preferences.presetPosition, {persist = true})
end

if preset_position ~= nil then
device:emit_event(capabilities.windowShadePreset.position(preset_position, { visibility = {displayed = false}}))
end
end
end

local function added_handler(self, device)
device:emit_event(capabilities.windowShade.supportedWindowShadeCommands({"open", "close", "pause"}, { visibility = { displayed = false }}))
Expand All @@ -40,6 +57,7 @@ local zigbee_window_treatment_driver_template = {
require("hanssem"),
require("screen-innovations")},
lifecycle_handlers = {
init = init_handler,
added = added_handler
},
health_check = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

local capabilities = require "st.capabilities"
local zcl_clusters = require "st.zigbee.zcl.clusters"
local window_shade_utils = require "window_shade_utils"

local WindowCovering = zcl_clusters.WindowCovering

Expand Down Expand Up @@ -75,9 +76,8 @@ local function window_shade_level_cmd(driver, device, command)
end

local function window_shade_preset_cmd(driver, device, command)
if device.preferences ~= nil and device.preferences.presetPosition ~= nil then
set_shade_level(device, device.preferences.presetPosition, command)
end
local level = window_shade_utils.get_preset_level(device, command.component)
set_shade_level(device, level, command)
end

local ikea_window_treatment = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
-- require st provided libraries
local capabilities = require "st.capabilities"
local clusters = require "st.zigbee.zcl.clusters"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"
local window_shade_utils = require "window_shade_utils"
local device_management = require "st.zigbee.device_management"
local utils = require "st.utils"

Expand Down Expand Up @@ -52,9 +52,9 @@ end

-- this is window_shade_preset_cmd
local function window_shade_preset_cmd(driver, device, command)
local go_to_level = device.preferences.presetPosition or device:get_field(window_preset_defaults.PRESET_LEVEL_KEY) or window_preset_defaults.PRESET_LEVEL
local level = window_shade_utils.get_preset_level(device, command.component)
-- send levels without inverting as: 0% closed (i.e., open) to 100% closed
device:send_to_component(command.component, WindowCovering.server.commands.GoToLiftPercentage(device, go_to_level))
device:send_to_component(command.component, WindowCovering.server.commands.GoToLiftPercentage(device, level))
end

-- this is device_added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

local capabilities = require "st.capabilities"
local utils = require "st.utils"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"
local window_shade_utils = require "window_shade_utils"
local zcl_clusters = require "st.zigbee.zcl.clusters"
local WindowCovering = zcl_clusters.WindowCovering

Expand Down Expand Up @@ -109,7 +109,7 @@ local function window_shade_level_cmd(driver, device, command)
end

local function window_shade_preset_cmd(driver, device, command)
local level = device.preferences.presetPosition or device:get_field(window_preset_defaults.PRESET_LEVEL_KEY) or window_preset_defaults.PRESET_LEVEL
local level = window_shade_utils.get_preset_level(device, command.component)
command.args.shadeLevel = level
window_shade_level_cmd(driver, device, command)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,42 @@ test.register_message_test(
mock_device.id,
clusters.WindowCovering.server.commands.GoToLiftPercentage(mock_device, 50)
}
}
},
{
channel = "capability",
direction = "receive",
message = {
mock_device.id,
{
capability = "windowShadePreset", component = "main",
command = "setPresetPosition", args = {20}
}
}
},
{
channel = "capability",
direction = "send",
message = mock_device:generate_test_message("main", capabilities.windowShadePreset.position(20))
},
{
channel = "capability",
direction = "receive",
message = {
mock_device.id,
{
capability = "windowShadePreset", component = "main",
command = "presetPosition", args = {}
}
}
},
{
channel = "zigbee",
direction = "send",
message = {
mock_device.id,
clusters.WindowCovering.server.commands.GoToLiftPercentage(mock_device, 20)
}
},
}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,16 @@ test.register_coroutine_test(
test.register_coroutine_test(
"windowShadePreset capability should be handled with preset value = 1 ",
function()
test.socket.device_lifecycle():__queue_receive(mock_device:generate_info_changed({preferences = {presetPosition = 1}}))
test.socket.device_lifecycle():__queue_receive(mock_device:generate_info_changed({preferences = {presetPosition = 10}}))
test.socket.capability:__queue_receive(
{
mock_device.id,
{ capability = "windowShadePreset", component = "main", command = "setPresetPosition", args = {1} }
}
)
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.windowShadePreset.position(1))
)
test.wait_for_events()
test.socket.capability:__queue_receive(
{
Expand All @@ -285,7 +294,16 @@ test.register_coroutine_test(
test.register_coroutine_test(
"windowShadePreset capability should be handled with a positive preset value of < 1",
function()
test.socket.device_lifecycle():__queue_receive(mock_device:generate_info_changed({preferences = {presetPosition = 0}}))
test.socket.device_lifecycle():__queue_receive(mock_device:generate_info_changed({preferences = {presetPosition = 1}}))
test.socket.capability:__queue_receive(
{
mock_device.id,
{ capability = "windowShadePreset", component = "main", command = "setPresetPosition", args = {0} }
}
)
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.windowShadePreset.position(0))
)
test.wait_for_events()
test.socket.capability:__queue_receive(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

local capabilities = require "st.capabilities"
local utils = require "st.utils"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"
local window_shade_utils = require "window_shade_utils"
local zcl_clusters = require "st.zigbee.zcl.clusters"
local WindowCovering = zcl_clusters.WindowCovering
local windowShade = capabilities.windowShade.windowShade
Expand Down Expand Up @@ -124,7 +124,7 @@ end

-- COMMAND HANDLER for PresetPosition
local function window_shade_preset_handler(driver, device, command)
local level = device.preferences.presetPosition or device:get_field(window_preset_defaults.PRESET_LEVEL_KEY) or window_preset_defaults.PRESET_LEVEL
local level = window_shade_utils.get_preset_level(device, command.component)
command.args.shadeLevel = level
window_shade_set_level_handler(driver, device, command)
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-- Copyright 2025 SmartThings
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"

local utils = {}

utils.get_preset_level = function(device, component)
local level = device:get_latest_state(component, "windowShadePreset", "position") or
device:get_field(window_preset_defaults.PRESET_LEVEL_KEY) or
(device.preferences ~= nil and device.preferences.presetPosition) or
window_preset_defaults.PRESET_LEVEL

return level
end

return utils
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ local zcl_clusters = require "st.zigbee.zcl.clusters"
local zcl_global_commands = require "st.zigbee.zcl.global_commands"
local Status = require "st.zigbee.generated.types.ZclStatus"
local WindowCovering = zcl_clusters.WindowCovering
local window_shade_utils = require "window_shade_utils"

local device_management = require "st.zigbee.device_management"

Expand Down Expand Up @@ -79,7 +80,8 @@ local function window_shade_level_cmd(driver, device, command)
end

local function window_shade_preset_cmd(driver, device, command)
set_shade_level(driver, device, device.preferences.presetPosition, command)
local level = window_shade_utils.get_preset_level(device, command.component)
set_shade_level(driver, device, level, command)
end

local function set_window_shade_level(level)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ test.register_coroutine_test(
test.socket.capability:__queue_receive(
{
mock_fibaro_roller_shutter.id,
{ capability = "windowShadePreset", command = "presetPosition", args = {} }
{ capability = "windowShadePreset", component = "main", command = "presetPosition", args = {} }
}
)
test.socket.zwave:__expect_send(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ test.register_coroutine_test(
test.socket.capability:__queue_receive(
{
mock_qubino_flush_shutter.id,
{ capability = "windowShadePreset", command = "presetPosition", args = {} }
{ capability = "windowShadePreset", component = "main", command = "presetPosition", args = {} }
}
)
test.socket.zwave:__expect_send(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ test.register_coroutine_test(
test.socket.capability:__queue_receive(
{
mock_blind.id,
{ capability = "windowShadePreset", command = "presetPosition", args = {} }
{ capability = "windowShadePreset", component = "main", command = "presetPosition", args = {} }
}
)
test.socket.capability:__expect_send(
Expand Down Expand Up @@ -251,7 +251,7 @@ test.register_coroutine_test(
test.socket.capability:__queue_receive(
{
mock_blind.id,
{ capability = "windowShadePreset", command = "presetPosition", args = {} }
{ capability = "windowShadePreset", component = "main", command = "presetPosition", args = {} }
}
)
test.socket.capability:__expect_send(
Expand Down Expand Up @@ -374,7 +374,7 @@ test.register_coroutine_test(
test.socket.capability:__queue_receive(
{
mock_blind_v3.id,
{ capability = "windowShadePreset", command = "presetPosition", args = {} }
{ capability = "windowShadePreset", component = "main", command = "presetPosition", args = {} }
}
)
test.socket.capability:__expect_send(
Expand Down Expand Up @@ -415,7 +415,7 @@ test.register_coroutine_test(
test.socket.capability:__queue_receive(
{
mock_blind_v3.id,
{ capability = "windowShadePreset", command = "presetPosition", args = {} }
{ capability = "windowShadePreset", component = "main", command = "presetPosition", args = {} }
}
)
test.socket.capability:__expect_send(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ test.register_coroutine_test(
test.socket.capability:__queue_receive(
{
mock_springs_window_fashion_shade.id,
{ capability = "windowShadePreset", command = "presetPosition", args = {} }
{ capability = "windowShadePreset", component = "main", command = "presetPosition", args = {} }
}
)
test.socket.zwave:__expect_send(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ test.register_coroutine_test(
test.socket.capability:__queue_receive(
{
mock_window_shade_switch_multilevel.id,
{ capability = "windowShadePreset", command = "presetPosition", args = {} }
{ capability = "windowShadePreset", component = "main", command = "presetPosition", args = {} }
}
)
test.socket.zwave:__expect_send(
Expand Down
5 changes: 4 additions & 1 deletion drivers/Unofficial/tuya-zigbee/src/curtain/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ local function window_shade_level(driver, device, command)
end

local function window_shade_preset(driver, device)
local level = device.preferences and device.preferences.presetPosition or window_preset_defaults.PRESET_LEVEL
local level = device:get_latest_state("main", "windowShadePreset", "position") or
device:get_field(window_preset_defaults.PRESET_LEVEL_KEY) or
(device.preferences ~= nil and device.preferences.presetPosition) or
window_preset_defaults.PRESET_LEVEL
tuya_utils.send_tuya_command(device, '\x02', tuya_utils.DP_TYPE_VALUE, '\x00\x00'..string.pack(">I2", level), packet_id)
packet_id = increase_packet_id(packet_id)
end
Expand Down
Loading