Skip to content

Commit c84e68b

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

File tree

1 file changed

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

1 file changed

+40
-69
lines changed

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

Lines changed: 40 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 First_Time_Onboarding = "__first_time_onboarding"
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(First_Time_Onboarding, true)
7265
end
7366

7467
local function info_changed(driver, device, event, args)
@@ -144,69 +137,45 @@ local function current_pos_handler(driver, device, ib, response)
144137
ib.endpoint_id, capabilities.windowShadeLevel.shadeLevel(position)
145138
)
146139
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)
140+
device:set_field(CURRENT_POSITION, position)
141+
if device:get_field(TARGET_POSITION) == position then
142+
if position == 0 then
143+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.closed())
144+
elseif position == 100 then
145+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.open())
146+
elseif position > 0 and position < 100 then
147+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.partially_open())
148+
else
149+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.unknown())
150+
end
151+
end
152+
if device:get_field(First_Time_Onboarding) == true then
153+
if position == 0 then
154+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.closed())
155+
elseif position == 100 then
156+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.open())
157+
elseif position > 0 and position < 100 then
158+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.partially_open())
159+
else
160+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.windowShade.windowShade.unknown())
161+
end
162+
device:set_field(First_Time_Onboarding, false)
162163
end
163164
end
164165

165166
-- checks the current position of the shade
166-
local function current_status_handler(driver, device, ib, response)
167+
local function target_pos_handler(driver, device, ib, response)
167168
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
169+
local target_position
170+
if ib.data.value ~= nil then
171+
target_position = 100 - math.floor((ib.data.value / 100))
209172
end
173+
device:set_field(TARGET_POSITION, target_position)
174+
if device:get_field(CURRENT_POSITION) > target_position then
175+
device:emit_event_for_endpoint(ib.endpoint_id, attr.closing())
176+
elseif device:get_field(CURRENT_POSITION) < target_position then
177+
device:emit_event_for_endpoint(ib.endpoint_id, attr.opening())
178+
end
210179
end
211180

212181
local function level_attr_handler(driver, device, ib, response)
@@ -235,7 +204,8 @@ local matter_driver_template = {
235204
[clusters.WindowCovering.ID] = {
236205
--uses percent100ths more often
237206
[clusters.WindowCovering.attributes.CurrentPositionLiftPercent100ths.ID] = current_pos_handler,
238-
[clusters.WindowCovering.attributes.OperationalStatus.ID] = current_status_handler,
207+
[clusters.WindowCovering.attributes.TargetPositionLiftPercent100ths.ID] = target_pos_handler,
208+
-- [clusters.WindowCovering.attributes.OperationalStatus.ID] = current_status_handler,
239209
},
240210
[clusters.PowerSource.ID] = {
241211
[clusters.PowerSource.attributes.BatPercentRemaining.ID] = battery_percent_remaining_attr_handler,
@@ -249,6 +219,7 @@ local matter_driver_template = {
249219
[capabilities.windowShadeLevel.ID] = {
250220
clusters.LevelControl.attributes.CurrentLevel,
251221
clusters.WindowCovering.attributes.CurrentPositionLiftPercent100ths,
222+
clusters.WindowCovering.attributes.TargetPositionLiftPercent100ths,
252223
},
253224
[capabilities.battery.ID] = {
254225
clusters.PowerSource.attributes.BatPercentRemaining

0 commit comments

Comments
 (0)