66local capabilities = require " st.capabilities"
77local im = require " st.matter.interaction_model"
88local clusters = require " st.matter.clusters"
9+ local device_lib = require " st.device"
910local MatterDriver = require " st.matter.driver"
1011local utils = require " st.utils"
1112
@@ -41,6 +42,22 @@ local TARGET_TILT_PERCENT = {
4142
4243local TARGET_REACH_TOLERANCE = 0.5
4344
45+ local function get_field_for_endpoint (device , field , endpoint )
46+ local field_device = device
47+ if device .network_type == device_lib .NETWORK_TYPE_CHILD then
48+ field_device = device :get_parent_device ()
49+ end
50+ return field_device :get_field (string.format (" %s_%d" , field , endpoint ))
51+ end
52+
53+ local function set_field_for_endpoint (device , field , endpoint , value , additional_params )
54+ local field_device = device
55+ if device .network_type == device_lib .NETWORK_TYPE_CHILD then
56+ field_device = device :get_parent_device ()
57+ end
58+ field_device :set_field (string.format (" %s_%d" , field , endpoint ), value , additional_params )
59+ end
60+
4461local function find_child (parent_device , ep_id )
4562 local assigned_key = parent_device :get_field (string.format (" %s_%d" , ASSIGNED_CHILD_KEY , ep_id )) or ep_id
4663 return parent_device :get_child_by_parent_assigned_key (string.format (" %d" , assigned_key ))
@@ -102,22 +119,22 @@ end
102119--- Clears the cached target percentage and cancels any associated timeout.
103120--- @param device any a Matter device object
104121--- @param op_fields table a table containing operational field constants used for caching target percentages and timeouts.
105- local function clear_cached_data (device , op_fields )
106- local current_timer = device : get_field ( op_fields .TIMEOUT )
122+ local function clear_cached_data (device , op_fields , ep )
123+ local current_timer = get_field_for_endpoint ( device , op_fields .TIMEOUT , ep )
107124 if current_timer then
108125 device .thread :cancel_timer (current_timer )
109126 end
110- device : set_field ( op_fields .STATE , nil )
111- device : set_field ( op_fields .TIMEOUT , nil )
127+ set_field_for_endpoint ( device , op_fields .STATE , ep , nil )
128+ set_field_for_endpoint ( device , op_fields .TIMEOUT , ep , nil )
112129end
113130
114131--- Tries to emit the idle window shade status if no target percentages are set.
115132--- @param device any a Matter device object
116133local function try_emit_idle_window_shade_status (device , ep )
117- if not device : get_field ( TARGET_LIFT_PERCENT .STATE ) and
118- not device : get_field ( TARGET_TILT_PERCENT .STATE ) then
134+ if not get_field_for_endpoint ( device , TARGET_LIFT_PERCENT .STATE , ep ) and
135+ not get_field_for_endpoint ( device , TARGET_TILT_PERCENT .STATE , ep ) then
119136 --- gets child device if one exists for this endpoint
120- local status_device = ep and find_child (device , ep ) or device
137+ local status_device = find_child (device , ep ) or device
121138 status_device :emit_event (get_idle_window_shade_status (status_device ))
122139 end
123140end
@@ -126,18 +143,18 @@ end
126143--- @param device any a Matter device object
127144--- @param data number the target percentage to cache
128145--- @param op_fields table a table containing operational field constants used for caching target percentages and timeouts.
129- local function cache_data_with_timeout (device , data , op_fields )
130- device : set_field ( op_fields .STATE , data )
131- local previous_timer = device : get_field ( op_fields .TIMEOUT )
146+ local function cache_data_with_timeout (device , data , op_fields , ep )
147+ set_field_for_endpoint ( device , op_fields .STATE , ep , data )
148+ local previous_timer = get_field_for_endpoint ( device , op_fields .TIMEOUT , ep )
132149 if previous_timer then
133150 device .thread :cancel_timer (previous_timer )
134151 end
135152 local new_timer = device .thread :call_with_delay (op_fields .TIMEOUT_DELAY_S , function ()
136- device : set_field ( op_fields .STATE , nil )
137- device : set_field ( op_fields .TIMEOUT , nil )
138- try_emit_idle_window_shade_status (device , nil )
153+ set_field_for_endpoint ( device , op_fields .STATE , ep , nil )
154+ set_field_for_endpoint ( device , op_fields .TIMEOUT , ep , nil )
155+ try_emit_idle_window_shade_status (device , ep )
139156 end )
140- device : set_field ( op_fields .TIMEOUT , new_timer )
157+ set_field_for_endpoint ( device , op_fields .TIMEOUT , ep , new_timer )
141158end
142159
143160local function is_target_value_reached (current_value , target_value )
@@ -266,15 +283,15 @@ end
266283
267284-- capability handlers
268285local function handle_preset (driver , device , cmd )
286+ local endpoint_id = device :component_to_endpoint (cmd .component )
269287 local preset_target_percent = device :get_latest_state (
270288 " main" ,
271289 capabilities .windowShadePreset .ID ,
272290 capabilities .windowShadePreset .position .NAME ,
273291 DEFAULT_PRESET_LEVEL
274292 )
275- cache_data_with_timeout (device , preset_target_percent , TARGET_LIFT_PERCENT )
293+ cache_data_with_timeout (device , preset_target_percent , TARGET_LIFT_PERCENT , endpoint_id )
276294 local hundredths_lift_percent = (100 - preset_target_percent ) * 100
277- local endpoint_id = device :component_to_endpoint (cmd .component )
278295 device :send (clusters .WindowCovering .server .commands .GoToLiftPercentage (
279296 device , endpoint_id , hundredths_lift_percent
280297 ))
@@ -288,10 +305,10 @@ end
288305local function handle_close (driver , device , cmd )
289306 local endpoint_id = device :component_to_endpoint (cmd .component )
290307 if # device :get_endpoints (clusters .WindowCovering .ID , {feature_bitmap = clusters .WindowCovering .types .Feature .LIFT }) > 0 then
291- cache_data_with_timeout (device , device .preferences .reverse and 100 or 0 , TARGET_LIFT_PERCENT )
308+ cache_data_with_timeout (device , device .preferences .reverse and 100 or 0 , TARGET_LIFT_PERCENT , endpoint_id )
292309 end
293310 if # device :get_endpoints (clusters .WindowCovering .ID , {feature_bitmap = clusters .WindowCovering .types .Feature .TILT }) > 0 then
294- cache_data_with_timeout (device , device .preferences .reverse and 100 or 0 , TARGET_TILT_PERCENT )
311+ cache_data_with_timeout (device , device .preferences .reverse and 100 or 0 , TARGET_TILT_PERCENT , endpoint_id )
295312 end
296313 device :send (device .preferences .reverse and
297314 clusters .WindowCovering .server .commands .UpOrOpen (device , endpoint_id ) or
@@ -302,10 +319,10 @@ end
302319local function handle_open (driver , device , cmd )
303320 local endpoint_id = device :component_to_endpoint (cmd .component )
304321 if # device :get_endpoints (clusters .WindowCovering .ID , {feature_bitmap = clusters .WindowCovering .types .Feature .LIFT }) > 0 then
305- cache_data_with_timeout (device , device .preferences .reverse and 0 or 100 , TARGET_LIFT_PERCENT )
322+ cache_data_with_timeout (device , device .preferences .reverse and 0 or 100 , TARGET_LIFT_PERCENT , endpoint_id )
306323 end
307324 if # device :get_endpoints (clusters .WindowCovering .ID , {feature_bitmap = clusters .WindowCovering .types .Feature .TILT }) > 0 then
308- cache_data_with_timeout (device , device .preferences .reverse and 0 or 100 , TARGET_TILT_PERCENT )
325+ cache_data_with_timeout (device , device .preferences .reverse and 0 or 100 , TARGET_TILT_PERCENT , endpoint_id )
309326 end
310327 device :send (device .preferences .reverse and
311328 clusters .WindowCovering .server .commands .DownOrClose (device , endpoint_id ) or
@@ -322,23 +339,24 @@ end
322339local function handle_shade_level (driver , device , cmd )
323340 local endpoint_id = device :component_to_endpoint (cmd .component )
324341 local hundredths_lift_percentage = (100 - cmd .args .shadeLevel ) * 100
325- cache_data_with_timeout (device , cmd .args .shadeLevel , TARGET_LIFT_PERCENT )
342+ cache_data_with_timeout (device , cmd .args .shadeLevel , TARGET_LIFT_PERCENT , endpoint_id )
326343 device :send (clusters .WindowCovering .server .commands .GoToLiftPercentage (
327344 device , endpoint_id , hundredths_lift_percentage
328345 ))
329346end
330347
331348local function handle_step_shade_level (driver , device , cmd )
349+ local endpoint_id = device :component_to_endpoint (cmd .component )
332350 local step = cmd .args .stepSize
333351 local latest_lift_percentage = device :get_latest_state (
334352 " main" ,
335353 capabilities .windowShadeLevel .ID ,
336354 capabilities .windowShadeLevel .shadeLevel .NAME ,
337355 0
338356 )
339- local target_lift_percent = device : get_field ( TARGET_LIFT_PERCENT .STATE ) or latest_lift_percentage
357+ local target_lift_percent = get_field_for_endpoint ( device , TARGET_LIFT_PERCENT .STATE , endpoint_id ) or latest_lift_percentage
340358 local updated_target_lift = utils .clamp_value (target_lift_percent + step , 0 , 100 )
341- cache_data_with_timeout (device , updated_target_lift , TARGET_LIFT_PERCENT )
359+ cache_data_with_timeout (device , updated_target_lift , TARGET_LIFT_PERCENT , endpoint_id )
342360 driver :inject_capability_command (device , {
343361 capability = capabilities .windowShadeLevel .ID ,
344362 component = cmd .component ,
351369local function handle_shade_tilt_level (driver , device , cmd )
352370 local endpoint_id = device :component_to_endpoint (cmd .component )
353371 local hundredths_tilt_percentage = (100 - cmd .args .level ) * 100
354- cache_data_with_timeout (device , cmd .args .level , TARGET_TILT_PERCENT )
372+ cache_data_with_timeout (device , cmd .args .level , TARGET_TILT_PERCENT , endpoint_id )
355373 device :send (clusters .WindowCovering .server .commands .GoToTiltPercentage (
356374 device , endpoint_id , hundredths_tilt_percentage
357375 ))
@@ -362,9 +380,8 @@ local function current_position_lift_percent_100ths_handler(driver, device, ib,
362380 if not ib .data .value then return end
363381 local lift_percent = 100 - math.floor (ib .data .value / 100 )
364382 device :emit_event_for_endpoint (ib .endpoint_id , capabilities .windowShadeLevel .shadeLevel (lift_percent ))
365-
366- if is_target_value_reached (lift_percent , device :get_field (TARGET_LIFT_PERCENT .STATE )) then
367- clear_cached_data (device , TARGET_LIFT_PERCENT )
383+ if is_target_value_reached (lift_percent , get_field_for_endpoint (device , TARGET_LIFT_PERCENT .STATE , ib .endpoint_id )) then
384+ clear_cached_data (device , TARGET_LIFT_PERCENT , ib .endpoint_id )
368385 try_emit_idle_window_shade_status (device , ib .endpoint_id )
369386 end
370387end
@@ -373,9 +390,8 @@ local function current_position_tilt_percent_100ths_handler(driver, device, ib,
373390 if not ib .data .value then return end
374391 local tilt_percent = 100 - math.floor (ib .data .value / 100 )
375392 device :emit_event_for_endpoint (ib .endpoint_id , capabilities .windowShadeTiltLevel .shadeTiltLevel (tilt_percent ))
376-
377- if is_target_value_reached (tilt_percent , device :get_field (TARGET_TILT_PERCENT .STATE )) then
378- clear_cached_data (device , TARGET_TILT_PERCENT )
393+ if is_target_value_reached (tilt_percent , get_field_for_endpoint (device , TARGET_TILT_PERCENT .STATE , ib .endpoint_id )) then
394+ clear_cached_data (device , TARGET_TILT_PERCENT , ib .endpoint_id )
379395 try_emit_idle_window_shade_status (device , ib .endpoint_id )
380396 end
381397end
@@ -389,10 +405,10 @@ local function target_position_lift_percent_100ths_handler(driver, device, ib, r
389405 capabilities .windowShadeLevel .shadeLevel .NAME
390406 )
391407 if latest_lift_percentage and is_target_value_reached (latest_lift_percentage , target_lift_percent ) then
392- clear_cached_data (device , TARGET_LIFT_PERCENT )
408+ clear_cached_data (device , TARGET_LIFT_PERCENT , ib . endpoint_id )
393409 try_emit_idle_window_shade_status (device , ib .endpoint_id )
394410 else
395- cache_data_with_timeout (device , target_lift_percent , TARGET_LIFT_PERCENT )
411+ cache_data_with_timeout (device , target_lift_percent , TARGET_LIFT_PERCENT , ib . endpoint_id )
396412 end
397413 end
398414end
@@ -406,10 +422,10 @@ local function target_position_tilt_percent_100ths_handler(driver, device, ib, r
406422 capabilities .windowShadeTiltLevel .shadeTiltLevel .NAME
407423 )
408424 if latest_tilt_percent and is_target_value_reached (latest_tilt_percent , target_tilt_percent ) then
409- clear_cached_data (device , TARGET_TILT_PERCENT )
425+ clear_cached_data (device , TARGET_TILT_PERCENT , ib . endpoint_id )
410426 try_emit_idle_window_shade_status (device , ib .endpoint_id )
411427 else
412- cache_data_with_timeout (device , target_tilt_percent , TARGET_TILT_PERCENT )
428+ cache_data_with_timeout (device , target_tilt_percent , TARGET_TILT_PERCENT , ib . endpoint_id )
413429 end
414430 end
415431end
0 commit comments