From 0ecff797ed30774b0e49ee77e39d39ffb9a7a193 Mon Sep 17 00:00:00 2001 From: Abdul Samad Date: Mon, 23 Mar 2026 21:54:19 -0500 Subject: [PATCH] Reprofile on SW change of camera --- .../src/sub_drivers/camera/init.lua | 7 ++ .../src/test/test_matter_bridge.lua | 84 +++++++++++++++++++ .../src/test/test_matter_camera.lua | 59 +++++++++++++ 3 files changed, 150 insertions(+) diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua index 24ca154950..91ebe03ebc 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua @@ -47,6 +47,13 @@ function CameraLifecycleHandlers.driver_switched(driver, device) end function CameraLifecycleHandlers.info_changed(driver, device, event, args) + local software_version_changed = device.matter_version ~= nil and args.old_st_store.matter_version ~= nil and + device.matter_version.software ~= args.old_st_store.matter_version.software + + if software_version_changed then + camera_cfg.match_profile(device, false, false) + end + if not switch_utils.deep_equals(device.profile, args.old_st_store.profile, { ignore_functions = true }) then camera_cfg.initialize_camera_capabilities(device) device:subscribe() diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_bridge.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_bridge.lua index 75830d55a7..42ec81e888 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_bridge.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_bridge.lua @@ -59,6 +59,26 @@ local mock_bridge = test.mock_device.build_test_matter_device({ } }) +local mock_basic_bridge = test.mock_device.build_test_matter_device({ + profile = t_utils.get_profile_definition("matter-bridge.yml"), + matter_version = { hardware = 1, software = 1 }, + manufacturer_info = { + vendor_id = 0x0000, + product_id = 0x0000, + }, + endpoints = { + { + endpoint_id = 0, + clusters = { + { cluster_id = clusters.Basic.ID, cluster_type = "SERVER" }, + }, + device_types = { + { device_type_id = 0x000E, device_type_revision = 1 } -- Aggregator + } + } + } +}) + local function test_init_mock_bridge() test.mock_device.add_test_device(mock_bridge) test.socket.device_lifecycle:__queue_receive({ mock_bridge.id, "added" }) @@ -67,6 +87,14 @@ local function test_init_mock_bridge() mock_bridge:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end +local function test_init_mock_basic_bridge() + test.mock_device.add_test_device(mock_basic_bridge) + test.socket.device_lifecycle:__queue_receive({ mock_basic_bridge.id, "added" }) + test.socket.device_lifecycle:__queue_receive({ mock_basic_bridge.id, "init" }) + test.socket.device_lifecycle:__queue_receive({ mock_basic_bridge.id, "doConfigure" }) + mock_basic_bridge:expect_metadata_update({ provisioning_state = "PROVISIONED" }) +end + test.register_coroutine_test( "Profile should not change for devices with aggregator device type (bridges)", function() @@ -77,4 +105,60 @@ test.register_coroutine_test( } ) +test.register_coroutine_test( + "Camera reprofiling should happen after software version change when camera endpoint appears", + function() + local updated_endpoints = { + { + endpoint_id = 0, + clusters = { + { cluster_id = clusters.Basic.ID, cluster_type = "SERVER" }, + }, + device_types = { + { device_type_id = 0x000E, device_type_revision = 1 } -- Aggregator + } + }, + { + endpoint_id = 1, + clusters = { + { + cluster_id = clusters.CameraAvStreamManagement.ID, + feature_map = clusters.CameraAvStreamManagement.types.Feature.VIDEO, + cluster_type = "SERVER" + }, + { cluster_id = clusters.PushAvStreamTransport.ID, cluster_type = "SERVER" } + }, + device_types = { + { device_type_id = 0x0142, device_type_revision = 1 } -- Camera + } + } + } + + test.socket.device_lifecycle:__queue_receive( + mock_basic_bridge:generate_info_changed({ + matter_version = { hardware = 1, software = 2 }, + endpoints = updated_endpoints + }) + ) + + mock_basic_bridge:expect_metadata_update({ + profile = "camera", + optional_component_capabilities = { + { + "main", + { + "videoCapture2", + "cameraViewportSettings", + "videoStreamSettings" + } + } + } + }) + end, + { + test_init = test_init_mock_basic_bridge, + min_api_version = 19 + } +) + test.run_registered_tests() diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua index 2eee0b778e..a11f7f944b 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua @@ -346,6 +346,65 @@ end -- Matter Handler UTs +test.register_coroutine_test( + "Software version change should trigger camera reprofiling when camera endpoint is present", + function() + test.socket.device_lifecycle:__queue_receive( + mock_device:generate_info_changed({ matter_version = { hardware = 1, software = 2 } }) + ) + + mock_device:expect_metadata_update({ + optional_component_capabilities = { + { + "main", + { + "videoCapture2", + "cameraViewportSettings", + "videoStreamSettings", + "localMediaStorage", + "audioRecording", + "cameraPrivacyMode", + "imageControl", + "hdr", + "nightVision", + "mechanicalPanTiltZoom", + "zoneManagement", + "webrtc", + "motionSensor", + "sounds" + } + }, + { + "speaker", + { + "audioMute", + "audioVolume" + } + }, + { + "microphone", + { + "audioMute", + "audioVolume" + } + }, + { + "doorbell", + { + "button" + } + } + }, + profile = "camera" + }) + + test.socket.matter:__expect_send({mock_device.id, clusters.Switch.attributes.MultiPressMax:read(mock_device, DOORBELL_EP)}) + end, + { + min_api_version = 19 + } +) + test.register_coroutine_test( "Reports mapping to EnabledState capability data type should generate appropriate events", function()