33
44local capabilities = require " st.capabilities"
55local st_utils = require " st.utils"
6+ local constants = require " st.zigbee.constants"
67local clusters = require " st.zigbee.zcl.clusters"
78local switch_utils = require " switch_utils"
89
@@ -11,19 +12,47 @@ local DEFAULT_MIRED_MAX_BOUND = 370 -- 2700 Kelvin (Mireds are the inverse of Ke
1112local DEFAULT_MIRED_MIN_BOUND = 154 -- 6500 Kelvin (Mireds are the inverse of Kelvin)
1213
1314-- Transition Time: The time that shall be taken to perform the step change, in units of 1/10ths of a second.
15+ -- Specific fields can store custom transition times for stateless capabilities
16+ local SWITCH_LEVEL_STEP_TRANSITION_TIME = " __switch_level_step_transition_time"
17+ local COLOR_TEMP_STEP_TRANSITION_TIME = " __color_temp_step_transition_time"
1418local DEFAULT_STEP_TRANSITION_TIME = 3 -- 0.3 seconds
1519
1620-- Options Mask & Override: Indicates which options are being overridden by the Level/ColorControl cluster commands
1721local OPTIONS_MASK = 0x01 -- default: The `ExecuteIfOff` option is overriden
1822local IGNORE_COMMAND_IF_OFF = 0x00 -- default: the command will not be executed if the device is off
1923
24+ -- Indicates whether a delayed refresh for ZLL devices is in progress, to prevent multiple refreshes in a quick series of step commands
25+ local IS_REFRESH_CALLBACK_QUEUED = " __is_refresh_callback_queued"
26+ -- Stores a timer object, which is required to cancel a timer early
27+ local REFRESH_CALLBACK_TIMER = " __refresh_callback_timer"
28+
29+ -- Note: These commands' native handlers do not match the driver's ZLL behavior 1-1.
30+ -- Instead, they will queue a 2s timer and read refresh for each command, in all cases.
31+ local function trigger_delayed_refresh_if_zll (device )
32+ if device :get_profile_id () ~= constants .ZLL_PROFILE_ID then
33+ return
34+ end
35+
36+ -- If a refresh callback is already queued, cancel it and create a new one with the updated time
37+ if device :get_field (IS_REFRESH_CALLBACK_QUEUED ) then
38+ device .thread :cancel_timer (device :get_field (REFRESH_CALLBACK_TIMER ))
39+ end
40+ local delay_s = 2
41+ local new_timer = device .thread :call_with_delay (delay_s , function ()
42+ device :refresh ()
43+ device :set_field (IS_REFRESH_CALLBACK_QUEUED , nil )
44+ end )
45+ device :set_field (REFRESH_CALLBACK_TIMER , new_timer )
46+ device :set_field (IS_REFRESH_CALLBACK_QUEUED , true )
47+ end
48+
2049local function step_color_temperature_by_percent_handler (driver , device , cmd )
2150 if type (device .register_native_capability_cmd_handler ) == " function" then
2251 device :register_native_capability_cmd_handler (cmd .capability , cmd .command )
2352 end
2453 local step_percent_change = cmd .args and cmd .args .stepSize or 0
2554 if step_percent_change == 0 then return end
26- local transition_time = device :get_field (switch_utils . COLOR_TEMP_STEP_TRANSITION_TIME ) or DEFAULT_STEP_TRANSITION_TIME
55+ local transition_time = device :get_field (COLOR_TEMP_STEP_TRANSITION_TIME ) or DEFAULT_STEP_TRANSITION_TIME
2756 -- Reminder, stepSize > 0 == Kelvin UP == Mireds DOWN. stepSize < 0 == Kelvin DOWN == Mireds UP
2857 local step_mode = (step_percent_change > 0 ) and clusters .ColorControl .types .CcStepMode .DOWN or clusters .ColorControl .types .CcStepMode .UP
2958 -- note: the field containing the color temp bounds will be associated with a parent device
@@ -37,6 +66,7 @@ local function step_color_temperature_by_percent_handler(driver, device, cmd)
3766 end
3867 local step_size_in_mireds = st_utils .round ((max_mireds - min_mireds ) * (math.abs (step_percent_change )/ 100.0 ))
3968 device :send (clusters .ColorControl .server .commands .StepColorTemperature (device , step_mode , step_size_in_mireds , transition_time , min_mireds , max_mireds , OPTIONS_MASK , IGNORE_COMMAND_IF_OFF ))
69+ trigger_delayed_refresh_if_zll (device )
4070end
4171
4272local function step_level_handler (driver , device , cmd )
@@ -45,9 +75,10 @@ local function step_level_handler(driver, device, cmd)
4575 end
4676 local step_size = st_utils .round ((cmd .args and cmd .args .stepSize or 0 )/ 100.0 * 254 )
4777 if step_size == 0 then return end
48- local transition_time = device :get_field (switch_utils . SWITCH_LEVEL_STEP_TRANSITION_TIME ) or DEFAULT_STEP_TRANSITION_TIME
78+ local transition_time = device :get_field (SWITCH_LEVEL_STEP_TRANSITION_TIME ) or DEFAULT_STEP_TRANSITION_TIME
4979 local step_mode = (step_size > 0 ) and clusters .Level .types .MoveStepMode .UP or clusters .Level .types .MoveStepMode .DOWN
5080 device :send (clusters .Level .server .commands .Step (device , step_mode , math.abs (step_size ), transition_time , OPTIONS_MASK , IGNORE_COMMAND_IF_OFF ))
81+ trigger_delayed_refresh_if_zll (device )
5182end
5283
5384local stateless_handlers = {
0 commit comments