Support additional Camera device types#2590
Conversation
|
Duplicate profile check: Passed - no duplicate profiles detected. |
|
Invitation URL: |
Test Results 72 files 492 suites 0s ⏱️ Results for commit a19ba8c. ♻️ This comment has been updated with latest results. |
|
Minimum allowed coverage is Generated by 🐒 cobertura-action against a19ba8c |
samadDotDev
left a comment
There was a problem hiding this comment.
Will need to re-evaluate after rebase
| for _, ep in ipairs(device.endpoints) do | ||
| for _, dt in ipairs(ep.device_types) do | ||
| if dt.device_type_id == device_type_id then | ||
| if type(device_type_id) == "table" then |
There was a problem hiding this comment.
this function will have to be rebased a bit carefully- there have been updates here since this PR was created.
There was a problem hiding this comment.
Thanks for the callout - I updated this function a bit in the last force push
96ccae6 to
67332b9
Compare
e012e2a to
a25f0c7
Compare
| end | ||
|
|
||
| -- get a list of endpoints for a specified device type. | ||
| -- get a list of endpoints for a specified device type or list of device types |
There was a problem hiding this comment.
can we add a proper lua doc here, like:
--- @param device ...
--- @param device_type_id number|table a specified device type or list of device types
--- @param opts ....
--- @return table ...
I think there's enough variation in return and input here to warrant proper use docs.
| table.insert(dt_eps, ep) | ||
| else | ||
| table.insert(dt_eps, ep.endpoint_id) | ||
| if type(device_type_id) == "table" then |
There was a problem hiding this comment.
Rather than check for a table in the loop body, maybe at the top do something like:
if device_type_id == nil then return end
device_type_id = device_type_id and type(device_type_id) == "table" or { device_type_id }
Then we can ensure the type + an added nil check before we event start the loop?
| camera_subscribed_attributes[capabilities.audioMute.ID] = { | ||
| clusters.Chime.attributes.Enabled | ||
| } |
There was a problem hiding this comment.
can we just add this to the table?
There was a problem hiding this comment.
Adding this to the table revealed an issue in populate_subscribe_request_for_device. I noticed that the standalone Chime mock device in test_matter_camera.lua was subscribing to the other attributes listed for audioMute in the camera_subscribed_attributes table (clusters.CameraAvStreamManagement.attributes.SpeakerMuted & clusters.CameraAvStreamManagement.attributes.MicrophoneMuted), even though the mock device does not support the CAVSM cluster.
The issue is that populate_subscribe_request_for_device does not perform a check to make sure the device supports a given cluster before subscribing to the attributes like add_subscribed_attribute does. I added a check in 0542fb3. Let me know if you have thoughts on this approach!
Note that adding this check lead to failures in test_matter_sensor_offset_preferences.lua because it was missing some endpoint definitions in its mock device and therefore no longer subscribing to certain attributes.
There was a problem hiding this comment.
Yeah this works! Maybe let's also add an else log like else log.warn_with({ hub_logs = true }, string.format("Device does not support cluster 0x%04X, not adding subscribed event", cluster_id)) end
drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/fields.lua
Outdated
Show resolved
Hide resolved
| @@ -6,116 +6,166 @@ local dkjson = require "dkjson" | |||
| local clusters = require "st.matter.clusters" | |||
|
|
|||
| local mock_device = test.mock_device.build_test_matter_device({ | |||
There was a problem hiding this comment.
Mentioned elsewhere, but after making the changes in 0542fb3 the tests here began to fail because they expect subscriptions to the button events yet no endpoints with the Switch cluster were present in the mock device. I added the endpoints and also fixed the tabbing in this file which is why the diff looks so large
31bd85e to
164095f
Compare
| dpUri: "plugin://com.samsung.android.plugin.camera" | ||
| metadata: | ||
| mnmn: SmartThingsEdge | ||
| vid: matter-camera |
There was a problem hiding this comment.
| vid: matter-camera | |
| vid: matter-av-doorbell |
| } | ||
| }) | ||
|
|
||
| local mock_device_doorbell = test.mock_device.build_test_matter_device({ |
There was a problem hiding this comment.
Probably worth creating one for video doorbell too due to the superset device type nuances
| if status_light_brightness_present then | ||
| table.insert(status_led_component_capabilities, capabilities.mode.ID) | ||
| end | ||
| if #device:get_endpoints(clusters.Chime.ID, {cluster_type = "SERVER"}) > 0 then |
There was a problem hiding this comment.
SERVER or BOTH? Basically reuse logic similar to has_server_cluster_type()
There was a problem hiding this comment.
Done in b082796, does that look alright? It uses the first endpoint containing the Chime cluster, but I wasn't sure if the client and server clusters would necessarily be on the same endpoint or not
b1faa74 to
297c2e3
Compare
| --- @param subscribed_events table key-value pairs mapping capability ids to subscribed events | ||
| function utils.populate_subscribe_request_for_device(checked_device, subscribe_request, capabilities_seen, attributes_seen, events_seen, subscribed_attributes, subscribed_events) | ||
| for _, component in pairs(checked_device.st_store.profile.components) do | ||
| function utils.populate_subscribe_request_for_device(checked_device, parent_device, subscribe_request, capabilities_seen, attributes_seen, events_seen, subscribed_attributes, subscribed_events) |
There was a problem hiding this comment.
Before merging, let's document a little testing here, since this change does affect our subscription logic. LGTM, but I think it's still worth ensuring we haven't missed something
| BRIDGED_NODE = 0x0013, | ||
| CAMERA = 0x0142, | ||
| CAMERA = { | ||
| INTERCOM = 0x0140, |
There was a problem hiding this comment.
This isn't a camera really?
There was a problem hiding this comment.
Intercoms are grouped with Camera in the spec and since intercoms create an audio connection they use CAVSM and other camera related clusters I think it makes sense to leave it here. (unlike doorbell and chime, neither of which include camera related clusters)
| AUDIO_DOORBELL = 0x0141, | ||
| CAMERA = 0x0142, | ||
| VIDEO_DOORBELL = 0x0143, | ||
| FLOODLIGHT_CAMERA = 0x0144, |
There was a problem hiding this comment.
Do we need to define Floodlight camera now? Since this is a composite device type is there any unique handling that would require this device type?
There was a problem hiding this comment.
Similar question for VIDEO_DOORBELL? It appears that all current handling exist by separating out CAMERA and DOORBELL explicitly?
I guess I'm not sure what should be done, but to me it feels like it would be good to clarify and either 1. just remove this/these references to device types that we don't use, or 2. add explicit handling for these device type configurations instead of handling a "if one exists but not the other, elseif " case-by-case basis kind of thing.
There was a problem hiding this comment.
For video doorbell, we need the device type listed here in order to differentiate between CAMERA and VIDEO_DOORBELL so we match to the proper profile (av-doorbell). And same with Audio DoorBell. We don't necessarily need Floodlight Camera since it would currently use the camera profile rather than a distinct one, but I don't see harm in leaving it here since we may create a new category/icon and profile for it eventually
There was a problem hiding this comment.
Due to the device type requirements being different between floodlight camera (composed of on/off light and camera device type) and the snapshot camera (a standalone device type - doesn't contain camera device type), I think we should just avoid clustering these together. This also makes it less confusing when trying to access CAMERA.CAMERA for the base camera device type id
| CAMERA = 0x0142, | ||
| CAMERA = { | ||
| INTERCOM = 0x0140, | ||
| AUDIO_DOORBELL = 0x0141, |
There was a problem hiding this comment.
This also isn't really a camera?
| -- Licensed under the Apache License, Version 2.0 | ||
|
|
||
| local clusters = require "st.matter.clusters" | ||
| local switch_fields = require "switch_utils.fields" |
| AUDIO_DOORBELL = 0x0141, | ||
| CAMERA = 0x0142, | ||
| VIDEO_DOORBELL = 0x0143, | ||
| FLOODLIGHT_CAMERA = 0x0144, |
There was a problem hiding this comment.
Due to the device type requirements being different between floodlight camera (composed of on/off light and camera device type) and the snapshot camera (a standalone device type - doesn't contain camera device type), I think we should just avoid clustering these together. This also makes it less confusing when trying to access CAMERA.CAMERA for the base camera device type id
|
|
||
| if #camera_endpoints > 0 then | ||
| local camera_ep = switch_utils.get_endpoint_info(device, camera_endpoints[1]) | ||
| local camera_ep = switch_utils.get_endpoint_info(device, av_stream_ep_ids[1] or camera_endpoints[1]) |
There was a problem hiding this comment.
Unless a separate category is needed based on device types (which is already covered later by keyeing off doorbell), the endpoints look up here should be specific to the cluster itself to avoid undefined scenarios where device type doesn't match and the cluster could be on a separate endpoint.
| local camera_ep = switch_utils.get_endpoint_info(device, av_stream_ep_ids[1] or camera_endpoints[1]) | |
| local av_stream_ep = switch_utils.get_endpoint_info(device, av_stream_ep_ids[1]) |
You'll also need to do the same for CameraAvSettingsUserLevelManagement.
There was a problem hiding this comment.
Done, see 17d5bb3. This helped clean up some of the profiling logic as well
| end | ||
| if clus_has_feature(clusters.CameraAvStreamManagement.types.Feature.VIDEO) then | ||
| if switch_utils.find_cluster_on_ep(camera_ep, clusters.PushAvStreamTransport.ID, "SERVER") then | ||
| if #device:get_endpoints(clusters.PushAvStreamTransport.ID, {cluster_type = "SERVER"}) > 0 then |
There was a problem hiding this comment.
Same thing is needed for the PushAV gating of audioRecording
This adds support for the following device types: * 0x0140 Intercom * 0x0141 Audio Doorbell * 0x0142 Camera * 0x0143 Video Doorbell * 0x0144 Floodlight Camera * 0x0145 Snapshot Camera * 0x0146 Chime * 0x0148 DoorBell
Fix populate_subscribe_request_for_device incorrectly filtering out cluster subscriptions for child devices. The function previously derived parent_device internally via checked_device.parent_device or checked_device, which falls back to the child itself when .parent_device is nil, as is the case with mock child devices in tests. This caused the #device:get_endpoints(cluster_id) > 0 check (introduced in the previous commit) to drop subscriptions for clusters that only exist on the parent's endpoints. Also fix test_matter_sensor_offset_preferences.lua, which had an incomplete mock device endpoint table.
On devices with multiple camera related endpoints (e.g. a Video Doorbell with separate Video Doorbell (0x143) and Camera (0x142) device type endpoints), camera_endpoints[1] could resolve to the Video Doorbell endpoint, which does not contain the CAVSM cluster, causing the cluster feature inspection loop to find nothing and leave main_component_capabilities empty. Fix by resolving the camera endpoint via device:get_endpoints() on the CAVSM cluster directly.
PushAvStreamTransport may not be on the same endpoint as CAVSM so we should check the fill device rather than just the CAVSM endpoint for this cluster.
1cd867b to
d845bcb
Compare
63e0a39 to
17d5bb3
Compare
This adds support for the following device types: