Conversation
Signed-off-by: Hunsup Jung <hunsup.jung@samsung.com>
|
Duplicate profile check: Warning - duplicate profiles detected. |
|
Invitation URL: |
Test Results 72 files 489 suites 0s ⏱️ For more details on these failures, see this check. Results for commit 8843cef. ♻️ This comment has been updated with latest results. |
|
Minimum allowed coverage is Generated by 🐒 cobertura-action against 8843cef |
|
@HunsupJung can you look at the unit test failure and also add new unit tests for the DPS functionality? |
| [DoorStateEnum.DOOR_UNSPECIFIED_ERROR] = doorState.unspecifiedError, | ||
| [DoorStateEnum.DOOR_AJAR] = doorState.ajar | ||
| } | ||
| device:emit_event(DOOR_STATE_MAP[ib.data.value]()) |
There was a problem hiding this comment.
DoorState is a nullable attribute so you should check for nil here
| local clus_has_feature = function(feature_bitmap) | ||
| return DoorLock.are_features_supported(feature_bitmap, ep_cluster.feature_map) | ||
| end | ||
| if clus_has_feature(DoorLock.types.Feature.DOOR_POSITION_SENSOR) then |
There was a problem hiding this comment.
I know that at least some locks will set the DOOR_POSITION_SENSOR feature flag by default even if a door sensor is not configured. They will report NULL for the DoorState attribute until one has been configured. So I think we should check DoorState and the DPS flag and if they are non-NULL and the flag is set then we can say doorState is supported on this lock.
There was a problem hiding this comment.
@tpmanley
I am sorry for the late reply and thank you for the review.
Do you mean to read DoorLock cluster's AttributeList and set the flag if there is DoorState attribute?
There was a problem hiding this comment.
No problem @HunsupJung . I mean reading the DoorState attribute to confirm it's a non-null value.
There was a problem hiding this comment.
@tpmanley
How about setting to unspecifiedError with logging when DoorState attribute is nil?
I think It's not easy to change profile when device start sending the normal value for DoorState after continuously sending nil value.
There was a problem hiding this comment.
I think you can do something similar to #2828 by setting a field like profiling_data.DOOR_STATE_NON_NULL when the DoorState attribute is reported as a non-null value. When that field changes from not being set to being set, then that will trigger the re-profile.
There was a problem hiding this comment.
@hcarter-775 @nickolas-deboom
Could you review it?
There was a problem hiding this comment.
Since we wouldn't include the capability by default, Hunsup is right that we'd need to do a read, which would probably be fine. However, to avoid the problem of reads failing I think we could just add DoorState as a subscribed attribute in device_init with add_subscribed_attribute, and then if we get a non-null value reported back, then do what Tom suggested within door_state_handler with some logic like this to re-profile the device:
if ib.data.value ~= nil and device:get_latest_state("main", capabilities.doorState.ID, capabilities.doorState.supportedDoorStates.NAME) == nil then
device:set_field(profiling_data.DOOR_STATE_NON_NULL, true)
match_profile(driver, device)
end
Then within match_profile, check for the presence of the profiling_data.DOOR_STATE_NON_NULL as the basis for including doorState in the profile.
There was a problem hiding this comment.
Actually, since it's not a mandatory attribute, maybe create a new separate field rather than putting this field within profiling_data, otherwise locks that don't support DPS would be blocked here.
There was a problem hiding this comment.
Here is my recomendation:
Using my PR here as a blueprint,
we should update this table:
local profiling_data = {
BATTERY_SUPPORT = "__BATTERY_SUPPORT",
ENABLE_DOOR_STATE = "__ENABLE_DOOR_STATE"
}
Then, in device_init:
local function device_init(driver, device)
device:set_component_to_endpoint_fn(component_to_endpoint)
if #device:get_endpoints(clusters.DoorLock.ID, {feature_bitmap = clusters.DoorLock.types.Feature.DOOR_POSITION_SENSOR}) == 0 and device:supports_capability(capabilities.doorState) == false then
device:set_field(profiling_data.ENABLE_DOOR_STATE, false, {persist = true})
else
device:add_subscribed_attribute(clusters.DoorLock.attributes.DoorState)
end
... rest of function ...
end
Next, in door_state_handler:
local function door_state_handler(driver, device, ib, response)
if ib.data.value == nil then
-- early return on nil data. Also, if ENABLE_DOOR_STATE is unset, set it to false and attempt profile matching.
if device:get_field(profiling_data.ENABLE_DOOR_STATE) == nil then
device:set_field(profiling_data.ENABLE_DOOR_STATE, false)
match_profile(driver, device)
end
return
elseif device:supports_capability(capabilities.doorState) == false then
-- if a non-nil report comes in and the doorState capability is unsupported, set ENABLE_DOOR_STATE to true and attempt profile matching.
device:set_field(profiling_data.ENABLE_DOOR_STATE, true)
match_profile(driver, device)
return
end
... rest of function ...
end
Finally, in do_configure, we can remove this section:
if clus_has_feature(DoorLock.types.Feature.DOOR_POSITION_SENSOR) then
table.insert(main_component_capabilities, capabilities.doorState.ID)
device.thread:call_with_delay(5, function(t)
device:emit_event(capabilities.doorState.supportedDoorStates({"open", "closed"}, {visibility = {displayed = false}})) -- open and closed are mandatory
end)
end
and we can replace it with the following logic:
... rest of code ...
if device:get_field(profiling_data.DOOR_STATE_ENABLED) or device:supports_capability(capabilities.doorState) then
table.insert(main_component_capabilities, capabilities.doorState.ID)
end
... rest of code ...
probably over by the BATTERY_SUPPORT logic.
This ensures that whether the DOOR_POSITION_SENSOR flag is set and whether the DoorState is populated, the profiling will occur as expected. It also ensures that if the doorState capability is ever set, it will never be unset. Finally, it ensures that if the DOOR_POSITION_SENSOR is ever enabled during the device's lifetime, we will re-attempt a device profile matching (at least on driver restart).
There was a problem hiding this comment.
Also, to ensure that any re-profiling works as expected, we should generally add gating like this for all modular capability insertions:
if clus_has_feature(DoorLock.types.Feature.USER) or device:supports_capability(capabilities.lockUsers) then
table.insert(main_component_capabilities, capabilities.lockUsers.ID)
end
to ensure that if an optional capability is already supported, we continue to enable it.
Signed-off-by: Hunsup Jung <hunsup.jung@samsung.com>
| device.thread:call_with_delay(5, function(t) | ||
| device:emit_event(capabilities.doorState.supportedDoorStates({"open", "closed"}, {visibility = {displayed = false}})) -- open and closed are mandatory | ||
| end) |
There was a problem hiding this comment.
I think we should handle this in infoChanged, gated behind a profile change, since this has the possibility of failing (if a profile change does not occur in <5 seconds)
Type of Change
Checklist
Description of Change
Summary of Completed Tests