Skip to content

Commit 447740d

Browse files
committed
fix-an-issue-of-window-covering-status-inconsistency
1 parent bd1cc72 commit 447740d

File tree

1 file changed

+38
-69
lines changed
  • drivers/SmartThings/matter-window-covering/src

1 file changed

+38
-69
lines changed

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

Lines changed: 38 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,10 @@ local log = require "log"
1919
local clusters = require "st.matter.clusters"
2020
local MatterDriver = require "st.matter.driver"
2121

22-
local DEFAULT_LEVEL = 0
2322
local PROFILE_MATCHED = "__profile_matched"
24-
local IS_MOVING = "__is_moving"
25-
local EVENT_STATE = "__event_state"
26-
27-
local WindowCoveringEventEnum = {
28-
NO_EVENT = 0x00,
29-
CURRENT_POSITION_EVENT = 0x01,
30-
OPERATIONAL_STATE_EVENT = 0x02
31-
}
23+
local CURRENT_POSITION = "__current_position"
24+
local TARGET_POSITION = "__target_position"
25+
local Initial_Status_Display = "__initial_status_display"
3226

3327
local function find_default_endpoint(device, cluster)
3428
local res = device.MATTER_DEFAULT_ENDPOINT
@@ -62,13 +56,12 @@ local function match_profile(device)
6256
end
6357

6458
local function device_init(driver, device)
65-
device:set_field(EVENT_STATE, WindowCoveringEventEnum.NO_EVENT)
66-
device:set_field(IS_MOVING, false)
6759
if not device:get_field(PROFILE_MATCHED) then
6860
match_profile(device)
6961
end
7062
device:set_component_to_endpoint_fn(component_to_endpoint)
7163
device:subscribe()
64+
device:set_field(Initial_Status_Display, true)
7265
end
7366

7467
local function info_changed(driver, device, event, args)
@@ -135,6 +128,19 @@ local function handle_shade_level(driver, device, cmd)
135128
device:send(req)
136129
end
137130

131+
-- to decide the status of window covering
132+
local function decide_status(device, ib, position)
133+
if position == 0 then
134+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.closed())
135+
elseif position == 100 then
136+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.open())
137+
elseif position > 0 and position < 100 then
138+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.partially_open())
139+
else
140+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.unknown())
141+
end
142+
end
143+
138144
-- current lift percentage, changed to 100ths percent
139145
local function current_pos_handler(driver, device, ib, response)
140146
local position = 0
@@ -144,69 +150,30 @@ local function current_pos_handler(driver, device, ib, response)
144150
ib.endpoint_id, capabilities.windowShadeLevel.shadeLevel(position)
145151
)
146152
end
147-
if device:get_field(EVENT_STATE) == WindowCoveringEventEnum.OPERATIONAL_STATE_EVENT then
148-
if not device:get_field(IS_MOVING) then
149-
if position == 0 then
150-
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.closed())
151-
elseif position == 100 then
152-
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.open())
153-
elseif position > 0 and position < 100 then
154-
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.partially_open())
155-
else
156-
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.unknown())
157-
end
158-
device:set_field(EVENT_STATE, WindowCoveringEventEnum.NO_EVENT)
159-
end
160-
else
161-
device:set_field(EVENT_STATE, WindowCoveringEventEnum.CURRENT_POSITION_EVENT)
153+
device:set_field(CURRENT_POSITION, position)
154+
if device:get_field(Initial_Status_Display) == true then
155+
-- Emiting window status during initialization
156+
decide_status(device, ib, position)
157+
device:set_field(Initial_Status_Display, false)
158+
elseif device:get_field(TARGET_POSITION) == position and device:get_field(Initial_Status_Display) == false then
159+
-- Emiting window status after arriving to the target position
160+
decide_status(device, ib, position)
162161
end
163162
end
164163

165164
-- checks the current position of the shade
166-
local function current_status_handler(driver, device, ib, response)
165+
local function target_pos_handler(driver, device, ib, response)
167166
local attr = capabilities.windowShade.windowShade
168-
local position = device:get_latest_state(
169-
"main", capabilities.windowShadeLevel.ID,
170-
capabilities.windowShadeLevel.shadeLevel.NAME
171-
) or DEFAULT_LEVEL
172-
for _, rb in ipairs(response.info_blocks) do
173-
if rb.info_block.attribute_id == clusters.WindowCovering.attributes.CurrentPositionLiftPercent100ths.ID and
174-
rb.info_block.cluster_id == clusters.WindowCovering.ID and
175-
rb.info_block.data.value ~= nil then
176-
position = 100 - math.floor((rb.info_block.data.value / 100))
177-
end
178-
end
179-
local state = ib.data.value & clusters.WindowCovering.types.OperationalStatus.GLOBAL --Could use LIFT instead
180-
if device:get_field(EVENT_STATE) == WindowCoveringEventEnum.CURRENT_POSITION_EVENT then
181-
if state == 0 then -- not moving
182-
if position == 100 then -- open
183-
device:emit_event_for_endpoint(ib.endpoint_id, attr.open())
184-
elseif position == 0 then -- closed
185-
device:emit_event_for_endpoint(ib.endpoint_id, attr.closed())
186-
else
187-
device:emit_event_for_endpoint(ib.endpoint_id, attr.partially_open())
188-
end
189-
device:set_field(IS_MOVING, false)
190-
elseif state == 1 then -- opening
191-
device:emit_event_for_endpoint(ib.endpoint_id, attr.opening())
192-
elseif state == 2 then -- closing
193-
device:emit_event_for_endpoint(ib.endpoint_id, attr.closing())
194-
else
195-
device:emit_event_for_endpoint(ib.endpoint_id, attr.unknown())
196-
end
197-
device:set_field(EVENT_STATE, WindowCoveringEventEnum.NO_EVENT)
198-
else
199-
if state == 1 then -- opening
200-
device:emit_event_for_endpoint(ib.endpoint_id, attr.opening())
201-
device:set_field(IS_MOVING, true)
202-
elseif state == 2 then -- closing
203-
device:emit_event_for_endpoint(ib.endpoint_id, attr.closing())
204-
device:set_field(IS_MOVING, true)
205-
else
206-
device:set_field(IS_MOVING, false)
207-
device:set_field(EVENT_STATE, WindowCoveringEventEnum.OPERATIONAL_STATE_EVENT)
208-
end
167+
local target_position
168+
if ib.data.value ~= nil then
169+
target_position = 100 - math.floor((ib.data.value / 100))
209170
end
171+
device:set_field(TARGET_POSITION, target_position)
172+
if device:get_field(CURRENT_POSITION) > target_position then
173+
device:emit_event_for_endpoint(ib.endpoint_id, attr.closing())
174+
elseif device:get_field(CURRENT_POSITION) < target_position then
175+
device:emit_event_for_endpoint(ib.endpoint_id, attr.opening())
176+
end
210177
end
211178

212179
local function level_attr_handler(driver, device, ib, response)
@@ -235,7 +202,8 @@ local matter_driver_template = {
235202
[clusters.WindowCovering.ID] = {
236203
--uses percent100ths more often
237204
[clusters.WindowCovering.attributes.CurrentPositionLiftPercent100ths.ID] = current_pos_handler,
238-
[clusters.WindowCovering.attributes.OperationalStatus.ID] = current_status_handler,
205+
[clusters.WindowCovering.attributes.TargetPositionLiftPercent100ths.ID] = target_pos_handler,
206+
-- [clusters.WindowCovering.attributes.OperationalStatus.ID] = current_status_handler,
239207
},
240208
[clusters.PowerSource.ID] = {
241209
[clusters.PowerSource.attributes.BatPercentRemaining.ID] = battery_percent_remaining_attr_handler,
@@ -249,6 +217,7 @@ local matter_driver_template = {
249217
[capabilities.windowShadeLevel.ID] = {
250218
clusters.LevelControl.attributes.CurrentLevel,
251219
clusters.WindowCovering.attributes.CurrentPositionLiftPercent100ths,
220+
clusters.WindowCovering.attributes.TargetPositionLiftPercent100ths,
252221
},
253222
[capabilities.battery.ID] = {
254223
clusters.PowerSource.attributes.BatPercentRemaining

0 commit comments

Comments
 (0)