Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
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 @@ -16,6 +16,3 @@ components:
version: 1
categories:
- name: Blind
preferences:
- preferenceId: presetPosition
explicit: true
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,4 @@ components:
- id: firmwareUpdate
version: 1
categories:
- name: Blind
preferences:
- preferenceId: presetPosition
explicit: true
- name: Blind
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,4 @@ components:
- id: refresh
version: 1
categories:
- name: Blind
preferences:
- preferenceId: presetPosition
explicit: true
- name: Blind
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,3 @@ components:
version: 1
categories:
- name: Blind
preferences:
- preferenceId: presetPosition
explicit: true

Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,3 @@ components:
preferences:
- preferenceId: reverse
explicit: true
- preferenceId: presetPosition
explicit: true
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ local clusters = require "st.zigbee.zcl.clusters"
local cluster_base = require "st.zigbee.cluster_base"
local data_types = require "st.zigbee.data_types"
local aqara_utils = require "aqara/aqara_utils"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"

local Groups = clusters.Groups
local Basic = clusters.Basic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ local clusters = require "st.zigbee.zcl.clusters"
local cluster_base = require "st.zigbee.cluster_base"
local data_types = require "st.zigbee.data_types"
local aqara_utils = require "aqara/aqara_utils"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"

local Basic = clusters.Basic
local WindowCovering = clusters.WindowCovering
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ local cluster_base = require "st.zigbee.cluster_base"
local FrameCtrl = require "st.zigbee.zcl.frame_ctrl"
local data_types = require "st.zigbee.data_types"
local aqara_utils = require "aqara/aqara_utils"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"

local Basic = clusters.Basic
local WindowCovering = clusters.WindowCovering
Expand Down
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
5 changes: 3 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,9 +14,10 @@

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"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"

local Basic = zcl_clusters.Basic
local Level = zcl_clusters.Level
Expand Down Expand Up @@ -50,7 +51,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,6 +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_shade_utils = require "window_shade_utils"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"

local TUYA_CLUSTER = 0xEF00
Expand Down Expand Up @@ -148,7 +149,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
19 changes: 19 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,24 @@
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

-- These should only ever be nil once (and at the same time) for already-installed devices
-- It can be relocated to `added` after migration is complete
device:emit_event(capabilities.windowShadePreset.supportedCommands({"presetPosition", "setPresetPosition"}, { visibility = { displayed = false }}))

local preset_position = device:get_field(window_preset_defaults.PRESET_LEVEL_KEY) or
(device.preferences ~= nil and device.preferences.presetPosition) or
window_preset_defaults.PRESET_LEVEL

device:emit_event(capabilities.windowShadePreset.position(preset_position, { visibility = {displayed = false}}))
device:set_field(window_preset_defaults.PRESET_LEVEL_KEY, preset_position, {persist = true})
end
end

local function added_handler(self, device)
device:emit_event(capabilities.windowShade.supportedWindowShadeCommands({"open", "close", "pause"}, { visibility = { displayed = false }}))
Expand All @@ -40,6 +58,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,9 +15,10 @@
-- 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"
local window_preset_defaults = require "st.zigbee.defaults.windowShadePreset_defaults"

local Basic = clusters.Basic
local WindowCovering = clusters.WindowCovering
Expand Down Expand Up @@ -52,9 +53,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 @@ -37,7 +37,14 @@ local mock_device = test.mock_device.build_test_zigbee_device(

zigbee_test_utils.prepare_zigbee_env_info()
local function test_init()
test.mock_device.add_test_device(mock_device)end
test.mock_device.add_test_device(mock_device)
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.windowShadePreset.supportedCommands({"presetPosition", "setPresetPosition"}, {visibility = {displayed=false}}))
)
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.windowShadePreset.position(50, {visibility = {displayed=false}}))
)
end

test.set_test_init_function(test_init)

Expand Down Expand Up @@ -162,7 +169,13 @@ test.register_coroutine_test(
test.register_coroutine_test(
"windowShadePreset capability should be handled",
function()
test.socket.device_lifecycle():__queue_receive(mock_device:generate_info_changed({preferences = {presetPosition = 30}}))
test.socket.capability:__queue_receive(
{
mock_device.id,
{ capability = "windowShadePreset", component = "main", command = "setPresetPosition", args = {30}}
}
)
test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.windowShadePreset.position(30)))
test.wait_for_events()
test.socket.capability:__queue_receive(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,14 @@ end

zigbee_test_utils.prepare_zigbee_env_info()
local function test_init()
test.mock_device.add_test_device(mock_device)end
test.mock_device.add_test_device(mock_device)
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.windowShadePreset.supportedCommands({"presetPosition", "setPresetPosition"}, {visibility = {displayed=false}}))
)
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.windowShadePreset.position(50, {visibility = {displayed=false}}))
)
end

test.set_test_init_function(test_init)

Expand Down Expand Up @@ -136,9 +143,10 @@ test.register_coroutine_test(
{ capability = "windowShadePreset", component = "main", command = "presetPosition", args = {} }
}
)
-- newly added devices will ignore the preference
test.socket.zigbee:__expect_send({
mock_device.id,
WindowCovering.server.commands.GoToLiftPercentage(mock_device, 70)
WindowCovering.server.commands.GoToLiftPercentage(mock_device, 50)
})
end
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@ local mock_device = test.mock_device.build_test_zigbee_device(

zigbee_test_utils.prepare_zigbee_env_info()
local function test_init()
test.mock_device.add_test_device(mock_device)end
test.mock_device.add_test_device(mock_device)
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.windowShadePreset.supportedCommands({"presetPosition", "setPresetPosition"}, {visibility = {displayed=false}}))
)
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.windowShadePreset.position(50, {visibility = {displayed=false}}))
)
end

test.set_test_init_function(test_init)

Expand Down Expand Up @@ -219,7 +226,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 @@ -43,7 +43,14 @@ local mock_device = test.mock_device.build_test_zigbee_device(

zigbee_test_utils.prepare_zigbee_env_info()
local function test_init()
test.mock_device.add_test_device(mock_device)end
test.mock_device.add_test_device(mock_device)
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.windowShadePreset.supportedCommands({"presetPosition", "setPresetPosition"}, {visibility = {displayed=false}}))
)
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.windowShadePreset.position(50, {visibility = {displayed=false}}))
)
end

test.set_test_init_function(test_init)

Expand Down Expand Up @@ -458,16 +465,17 @@ test.register_coroutine_test(
}
)
test.socket.capability:__set_channel_ordering("relaxed")
-- freshly joined devices will ignore the preference value
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.windowShadeLevel.shadeLevel(30))
mock_device:generate_test_message("main", capabilities.windowShadeLevel.shadeLevel(50))
)
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.windowShade.windowShade.opening())
)
test.socket.zigbee:__expect_send(
{
mock_device.id,
WindowCovering.server.commands.GoToLiftPercentage(mock_device, 100 - 30)
WindowCovering.server.commands.GoToLiftPercentage(mock_device, 100 - 50)
}
)
end
Expand Down
Loading
Loading