Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,8 @@ function CameraAttributeHandlers.triggers_handler(driver, device, ib, response)
augmentationDuration = trigger.augmentation_duration.value,
maxDuration = trigger.max_duration.value,
blindDuration = trigger.blind_duration.value,
sensitivity = camera_utils.feature_supported(device, clusters.ZoneManagement.ID, clusters.ZoneManagement.types.Feature.PER_ZONE_SENSITIVITY) and trigger.sensitivity.value
sensitivity = camera_utils.feature_supported(device, clusters.ZoneManagement.ID,
clusters.ZoneManagement.types.Feature.PER_ZONE_SENSITIVITY) and trigger.sensitivity.value or nil
})
end
device:emit_event_for_endpoint(ib, capabilities.zoneManagement.triggers(triggers))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,11 @@ function CameraCapabilityHandlers.handle_remove_zone(driver, device, cmd)
end

function CameraCapabilityHandlers.handle_create_or_update_trigger(driver, device, cmd)
local per_zone_sensitivity_supported = camera_utils.feature_supported(
device, clusters.ZoneManagement.ID, clusters.ZoneManagement.types.Feature.PER_ZONE_SENSITIVITY
)
if not cmd.args.augmentationDuration or not cmd.args.maxDuration or not cmd.args.blindDuration or
(camera_utils.feature_supported(device, clusters.ZoneManagement.ID, clusters.ZoneManagement.types.Feature.PER_ZONE_SENSITIVITY) and
not cmd.args.sensitivity) then
(per_zone_sensitivity_supported and not cmd.args.sensitivity) then
local triggers = device:get_latest_state(
camera_fields.profile_components.main, capabilities.zoneManagement.ID, capabilities.zoneManagement.triggers.NAME
) or {}
Expand All @@ -284,8 +286,7 @@ function CameraCapabilityHandlers.handle_create_or_update_trigger(driver, device
if not cmd.args.augmentationDuration then cmd.args.augmentationDuration = v.augmentationDuration end
if not cmd.args.maxDuration then cmd.args.maxDuration = v.maxDuration end
if not cmd.args.blindDuration then cmd.args.blindDuration = v.blindDuration end
if camera_utils.feature_supported(device, clusters.ZoneManagement.ID, clusters.ZoneManagement.types.Feature.PER_ZONE_SENSITIVITY) and
not cmd.args.sensitivity then
if per_zone_sensitivity_supported and not cmd.args.sensitivity then
cmd.args.sensitivity = v.sensitivity
end
found_trigger = true
Expand All @@ -306,7 +307,7 @@ function CameraCapabilityHandlers.handle_create_or_update_trigger(driver, device
augmentation_duration = cmd.args.augmentationDuration,
max_duration = cmd.args.maxDuration,
blind_duration = cmd.args.blindDuration,
sensitivity = cmd.args.sensitivity
sensitivity = per_zone_sensitivity_supported and cmd.args.sensitivity or nil -- omit even if provided by client if per-zone sensitivity is not supported
}
)
))
Expand All @@ -320,7 +321,7 @@ end
function CameraCapabilityHandlers.handle_set_sensitivity(driver, device, cmd)
local endpoint_id = device:component_to_endpoint(cmd.component)
if not camera_utils.feature_supported(device, clusters.ZoneManagement.ID, clusters.ZoneManagement.types.Feature.PER_ZONE_SENSITIVITY) then
device:send(clusters.ZoneManagement.attributes.Sensitivity:write(device, endpoint_id, cmd.args.id))
device:send(clusters.ZoneManagement.attributes.Sensitivity:write(device, endpoint_id, cmd.args.sensitivity))
else
device.log.warn(string.format("Can't set global zone sensitivity setting, per zone sensitivity enabled."))
end
Expand Down
185 changes: 185 additions & 0 deletions drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,45 @@ local mock_device = test.mock_device.build_test_matter_device({
}
})

local mock_device_no_per_zone_sensitivity = test.mock_device.build_test_matter_device({
profile = t_utils.get_profile_definition("camera.yml"),
manufacturer_info = {vendor_id = 0x0000, product_id = 0x0000},
matter_version = {hardware = 1, software = 1},
endpoints = {
{
endpoint_id = 0,
clusters = {
{ cluster_id = clusters.Basic.ID, cluster_type = "SERVER" }
},
device_types = {
{ device_type_id = 0x0016, device_type_revision = 1 } -- RootNode
}
},
{
endpoint_id = CAMERA_EP,
clusters = {
{
cluster_id = clusters.CameraAvStreamManagement.ID,
feature_map = clusters.CameraAvStreamManagement.types.Feature.VIDEO,
cluster_type = "SERVER"
},
{
cluster_id = clusters.ZoneManagement.ID,
feature_map = clusters.ZoneManagement.types.Feature.TWO_DIMENSIONAL_CARTESIAN_ZONE,
cluster_type = "SERVER"
},
{
cluster_id = clusters.PushAvStreamTransport.ID,
cluster_type = "SERVER"
}
},
device_types = {
{device_type_id = 0x0142, device_type_revision = 1} -- Camera
}
}
}
})

local subscribe_request
local subscribed_attributes = {
clusters.CameraAvStreamManagement.attributes.AttributeList,
Expand Down Expand Up @@ -169,6 +208,27 @@ end

test.set_test_init_function(test_init)


local subscribe_request_no_per_zone_sensitivity
local subscribed_attributes_no_per_zone_sensitivity = {
clusters.CameraAvStreamManagement.attributes.AttributeList,
}

local function test_init_no_per_zone_sensitivity()
test.mock_device.add_test_device(mock_device_no_per_zone_sensitivity)
test.socket.device_lifecycle:__queue_receive({ mock_device_no_per_zone_sensitivity.id, "added" })
test.socket.device_lifecycle:__queue_receive({ mock_device_no_per_zone_sensitivity.id, "init" })
subscribe_request_no_per_zone_sensitivity = subscribed_attributes_no_per_zone_sensitivity[1]:subscribe(mock_device_no_per_zone_sensitivity)
subscribe_request_no_per_zone_sensitivity:merge(cluster_base.subscribe(mock_device_no_per_zone_sensitivity, nil, camera_fields.CameraAVSMFeatureMapAttr.cluster, camera_fields.CameraAVSMFeatureMapAttr.ID))
subscribe_request_no_per_zone_sensitivity:merge(cluster_base.subscribe(mock_device_no_per_zone_sensitivity, nil, camera_fields.ZoneManagementFeatureMapAttr.cluster, camera_fields.ZoneManagementFeatureMapAttr.ID))
for i, attr in ipairs(subscribed_attributes_no_per_zone_sensitivity) do
if i > 1 then subscribe_request_no_per_zone_sensitivity:merge(attr:subscribe(mock_device_no_per_zone_sensitivity)) end
end
test.socket.matter:__expect_send({mock_device_no_per_zone_sensitivity.id, subscribe_request_no_per_zone_sensitivity})
test.socket.device_lifecycle:__queue_receive({ mock_device_no_per_zone_sensitivity.id, "doConfigure" })
mock_device_no_per_zone_sensitivity:expect_metadata_update({ provisioning_state = "PROVISIONED" })
end

local additional_subscribed_attributes = {
clusters.CameraAvStreamManagement.attributes.HDRModeEnabled,
clusters.CameraAvStreamManagement.attributes.ImageRotation,
Expand Down Expand Up @@ -349,6 +409,83 @@ local function update_device_profile()
test.socket.capability:__expect_send(mock_device:generate_test_message("doorbell", capabilities.button.button.pushed({state_change = false})))
end

local additional_subscribed_attributes_no_per_zone_sensitivity = {
clusters.CameraAvStreamManagement.attributes.StatusLightBrightness,
clusters.CameraAvStreamManagement.attributes.StatusLightEnabled,
clusters.CameraAvStreamManagement.attributes.RateDistortionTradeOffPoints,
clusters.CameraAvStreamManagement.attributes.MaxEncodedPixelRate,
clusters.CameraAvStreamManagement.attributes.VideoSensorParams,
clusters.CameraAvStreamManagement.attributes.AllocatedVideoStreams,
clusters.CameraAvSettingsUserLevelManagement.attributes.DPTZStreams,
clusters.CameraAvStreamManagement.attributes.MinViewportResolution,
clusters.CameraAvStreamManagement.attributes.Viewport,
clusters.CameraAvStreamManagement.attributes.AttributeList,
clusters.ZoneManagement.attributes.MaxZones,
clusters.ZoneManagement.attributes.Zones,
clusters.ZoneManagement.attributes.Triggers,
clusters.ZoneManagement.attributes.SensitivityMax,
clusters.ZoneManagement.attributes.Sensitivity,
clusters.ZoneManagement.events.ZoneTriggered,
clusters.ZoneManagement.events.ZoneStopped,
clusters.OnOff.attributes.OnOff,
}

local function update_device_profile_no_per_zone_sensitivity()
local expected_metadata = {
optional_component_capabilities = {
{
"main",
{
"videoCapture2",
"cameraViewportSettings",
"videoStreamSettings",
"zoneManagement",
}
},
{
"statusLed",
{
"switch",
"mode"
}
}
},
profile = "camera"
}

test.socket.matter:__queue_receive({
mock_device_no_per_zone_sensitivity.id,
clusters.CameraAvStreamManagement.attributes.AttributeList:build_test_report_data(mock_device_no_per_zone_sensitivity, CAMERA_EP, {
uint32(clusters.CameraAvStreamManagement.attributes.StatusLightEnabled.ID),
uint32(clusters.CameraAvStreamManagement.attributes.StatusLightBrightness.ID)
})
})
mock_device_no_per_zone_sensitivity:expect_metadata_update(expected_metadata)
test.wait_for_events()
local updated_device_profile = t_utils.get_profile_definition(
"camera.yml", {enabled_optional_capabilities = expected_metadata.optional_component_capabilities}
)
test.wait_for_events()
test.socket.device_lifecycle:__queue_receive(mock_device_no_per_zone_sensitivity:generate_info_changed({ profile = updated_device_profile }))

test.socket.capability:__expect_send(
mock_device_no_per_zone_sensitivity:generate_test_message("main", capabilities.zoneManagement.supportedFeatures(
{"triggerAugmentation"}
))
)

test.socket.capability:__expect_send(
mock_device_no_per_zone_sensitivity:generate_test_message("main", capabilities.videoStreamSettings.supportedFeatures(
{"liveStreaming", "clipRecording", "perStreamViewports"}
))
)

for _, attr in ipairs(additional_subscribed_attributes_no_per_zone_sensitivity) do
subscribe_request_no_per_zone_sensitivity:merge(attr:subscribe(mock_device_no_per_zone_sensitivity))
end
test.socket.matter:__expect_send({mock_device_no_per_zone_sensitivity.id, subscribe_request_no_per_zone_sensitivity})
end

-- Matter Handler UTs

test.register_coroutine_test(
Expand Down Expand Up @@ -3008,5 +3145,53 @@ test.register_coroutine_test(
}
)

test.register_coroutine_test(
"Zone Management trigger reports should omit sensitivity when per-zone sensitivity is unsupported, even if provided by client",
function()
update_device_profile_no_per_zone_sensitivity()
test.wait_for_events()
-- Create a trigger with
test.socket.capability:__queue_receive({
mock_device_no_per_zone_sensitivity.id,
{ capability = "zoneManagement", component = "main", command = "createOrUpdateTrigger", args = {
1, 10, 3, 15, 3, 5
}}
})
test.socket.matter:__expect_send({
mock_device_no_per_zone_sensitivity.id, clusters.ZoneManagement.server.commands.CreateOrUpdateTrigger(mock_device_no_per_zone_sensitivity, CAMERA_EP, {
zone_id = 1,
initial_duration = 10,
augmentation_duration = 3,
max_duration = 15,
blind_duration = 3
})
})
end,
{
test_init = test_init_no_per_zone_sensitivity,
min_api_version = 17
}
)

test.register_coroutine_test(
"Zone Management setSensitivity command should handle global sensitivity when per-zone sensitivity is unsupported",
function()
update_device_profile_no_per_zone_sensitivity()
test.wait_for_events()
test.socket.capability:__queue_receive({
mock_device_no_per_zone_sensitivity.id,
{ capability = "zoneManagement", component = "main", command = "setSensitivity", args = { 5 } }
})
test.socket.matter:__expect_send({
mock_device_no_per_zone_sensitivity.id,
clusters.ZoneManagement.attributes.Sensitivity:write(mock_device_no_per_zone_sensitivity, CAMERA_EP, 5)
})
end,
{
test_init = test_init_no_per_zone_sensitivity,
min_api_version = 17
}
)

-- run the tests
test.run_registered_tests()
Loading