Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
3cc5dbf
WWSTCERT-13182 Govee Strip Light 2 (#3196)
cbaumler Aug 27, 2026
dd29cc8
WWSTCERT-11168 Smart Radiator Thermostat X (#2949)
cbaumler Aug 27, 2026
72b71ab
WWSTCERT-13051 Govee Monitor Light Bar (#3178)
cbaumler Aug 27, 2026
e0f54fb
WWSTCERT-13508 Onvis Outlet T20 (#3199)
cbaumler Aug 27, 2026
6b8a9cf
Fix profile name in fingerprint for Govee COB Strip Light (#3200)
samadDotDev Aug 28, 2026
ab67316
GHA: Validate Fingerprints
hcarter-775 Jul 22, 2026
e02beac
Merge pull request #3140 from SmartThingsCommunity/validate/fingerpri…
hcarter-775 Aug 31, 2026
8cf0b50
WWSTCERT-13411 Z-Wave Smart Plug (#3207)
cbaumler Aug 31, 2026
f46b647
Fix hard privacy mode presence in `supportedAttributes` (#3201)
samadDotDev Aug 31, 2026
7d5651e
Matter Switch: restrict Eve sub driver to specific PIDS (#3213)
ctowns Sep 8, 2026
71bbd3d
Handle nil in PTZ command for axis clamping (#3217)
samadDotDev Sep 8, 2026
8d5cac5
Adjust tests to handle trustworthy child_ids change
varzac Sep 8, 2026
3aae773
Merge pull request #3218 from SmartThingsCommunity/child_ids_trustwor…
varzac Sep 10, 2026
4e27079
Merge pull request #3211 from SmartThingsCommunity/main
ctowns Sep 10, 2026
37e3766
WWSTCERT-13643 Linkind Light Stick T19 (#3221)
cbaumler Sep 10, 2026
ea9d3f4
add CLAUDE.md
hcarter-775 Sep 10, 2026
25ab114
Merge pull request #3226 from SmartThingsCommunity/add/claude-file
hcarter-775 Sep 10, 2026
19bb6f9
Fix addUser() -> addCredential() issue (#3220)
HunsupJung Sep 11, 2026
80e5285
WWSTCERT-13701 Lowes - Utilitech A19 Smart Bulb (#3228)
cbaumler Sep 14, 2026
6434162
WWSTCERT-13745 Govee Christmas 2-in-1 String Lights (#3234)
cbaumler Sep 15, 2026
87c61ad
WWSTCERT-13738 Utilitech 17 Smart Flush Mount - Full Color (#3235)
cbaumler Sep 15, 2026
f73d361
Merge pull request #3236 from SmartThingsCommunity/main
aleclorimer Sep 16, 2026
1673928
Updated CredentialId for CN Prod
aleclorimer Sep 16, 2026
bfc591b
Merge pull request #3238 from SmartThingsCommunity/CN-credentials-id-…
aleclorimer Sep 17, 2026
3f8f6e5
Fix hager driver delay
JanJakubiszyn Sep 1, 2026
7be1945
WWSTCERT-13529 SwitchBot RGBIC Wire Neon Rope Light (#3208)
cbaumler Sep 21, 2026
db0ec25
Update pairs table emptiness checks
hcarter-775 Sep 9, 2026
9274833
Merge pull request #3223 from SmartThingsCommunity/fix/incorrect-tabl…
hcarter-775 Sep 21, 2026
9309282
Merge pull request #3210 from JanJakubiszyn/hager-delay-fix
hcarter-775 Sep 21, 2026
31cd2c9
WWSTCERT-13832 Blinds motor (#3244)
cbaumler Sep 22, 2026
4a77e6f
WWSTCERT-13815 Utilitech 1x4 Smart Panel - Full Color (#3243)
cbaumler Sep 22, 2026
5703703
sonos: fix offline grouped speakers
NoahCornell Sep 22, 2026
6cbdd73
Merge pull request #3245 from SmartThingsCommunity/bugfix/CHAD-19246
NoahCornell Sep 23, 2026
5183653
Revert "Fix hager driver delay" (#3247)
JanJakubiszyn Sep 23, 2026
9d99e75
WWSTCERT-13716 Photoelectric Smoke Alarm (#3229)
cbaumler Sep 23, 2026
e530097
Merge pull request #3248 from SmartThingsCommunity/main
hcarter-775 Sep 23, 2026
84d83ed
Matter Camera: Exclude `audioVolume` on unusable volume range (#3242)
samadDotDev Sep 28, 2026
6773dc0
[WWSTCERT-13880, WWSTCERT-13884, WWSTCERT-13888] adds new fingerprint…
KKlimczukS Sep 29, 2026
1bc6ae9
Fix: Reorder delay and increase to 3 seconds
JanJakubiszyn Sep 23, 2026
81a89ae
Merge pull request #3249 from JanJakubiszyn/fix/hager-increase-delay
hcarter-775 Sep 30, 2026
e31a836
Merge pull request #3254 from SmartThingsCommunity/main
cjswedes Sep 30, 2026
7ae0937
WWSTCERT-13927 Linkind Smart Outdoor Plug (#3256)
cbaumler Oct 2, 2026
43f4750
WWSTCERT-13921 Linkind Smart Light Bulb (#3258)
cbaumler Oct 5, 2026
1c9f8b2
Merge branch 'production' into beta
ctowns Oct 7, 2026
b864b02
Merge pull request #3261 from SmartThingsCommunity/main
ctowns Oct 7, 2026
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
35 changes: 35 additions & 0 deletions drivers/SmartThings/matter-switch/fingerprints.yml
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,41 @@ matterManufacturer:
vendorId: 0x1396
productId: 0x11DE
deviceProfileName: light-color-level
- id: "5014/4224"
deviceLabel: Linkind Smart Light Bulb
vendorId: 0x1396
productId: 0x1080
deviceProfileName: light-color-level
- id: "5014/4223"
deviceLabel: Linkind Smart Light Bulb
vendorId: 0x1396
productId: 0x107F
deviceProfileName: light-color-level
- id: "5014/4227"
deviceLabel: Linkind Smart Light Bulb
vendorId: 0x1396
productId: 0x1083
deviceProfileName: light-color-level
- id: "5014/4218"
deviceLabel: Linkind Smart Filament Bulb
vendorId: 0x1396
productId: 0x107A
deviceProfileName: light-color-level
- id: "5014/4220"
deviceLabel: Linkind Smart Filament Bulb
vendorId: 0x1396
productId: 0x107C
deviceProfileName: light-color-level
- id: "5014/4221"
deviceLabel: Linkind Smart Filament Bulb
vendorId: 0x1396
productId: 0x107D
deviceProfileName: light-color-level
- id: "5014/4713"
deviceLabel: Linkind Smart Outdoor Plug
vendorId: 0x1396
productId: 0x1269
deviceProfileName: plug-binary
#Bosch Smart Home
- id: "4617/12310"
deviceLabel: Plug Compact [M]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ CameraAttributeHandlers.enabled_state_factory = function(attribute)
camera_utils.update_supported_attributes(device, ib, capabilities.imageControl, "imageFlipHorizontal")
elseif attribute == capabilities.imageControl.imageFlipVertical then
camera_utils.update_supported_attributes(device, ib, capabilities.imageControl, "imageFlipVertical")
elseif attribute == capabilities.cameraPrivacyMode.hardPrivacyMode then
camera_utils.update_supported_attributes(device, ib, capabilities.cameraPrivacyMode, "hardPrivacyMode")
end
end
end
Expand Down Expand Up @@ -59,34 +57,48 @@ end

function CameraAttributeHandlers.volume_level_handler(driver, device, ib, response)
local component = device:endpoint_to_component(ib)
local max_volume = device:get_field(camera_fields.MAX_VOLUME_LEVEL .. "_" .. component) or camera_fields.ABS_VOL_MAX
local min_volume = device:get_field(camera_fields.MIN_VOLUME_LEVEL .. "_" .. component) or camera_fields.ABS_VOL_MIN
-- Convert from [min_volume, max_volume] to [0, 100] before emitting capability
local max_volume = camera_utils.get_field_for_component(device, camera_fields.MAX_VOLUME_LEVEL, component) or camera_fields.ABS_VOL_MAX
local min_volume = camera_utils.get_field_for_component(device, camera_fields.MIN_VOLUME_LEVEL, component) or camera_fields.ABS_VOL_MIN
local limited_range = max_volume - min_volume
if limited_range <= 0 then
device:emit_event_for_endpoint(ib, capabilities.audioVolume.volume(0))
return
end
-- Convert from [min_volume, max_volume] to [0, 100] before emitting capability
local normalized_volume = utils.round((ib.data.value - min_volume) * 100.0 / limited_range)
device:emit_event_for_endpoint(ib, capabilities.audioVolume.volume(normalized_volume))
end

function CameraAttributeHandlers.max_volume_level_handler(driver, device, ib, response)
local component = device:endpoint_to_component(ib)
local max_volume = ib.data.value
local min_volume = device:get_field(camera_fields.MIN_VOLUME_LEVEL .. "_" .. component)
if max_volume > camera_fields.ABS_VOL_MAX or (min_volume and max_volume <= min_volume) then
local min_volume = camera_utils.get_field_for_component(device, camera_fields.MIN_VOLUME_LEVEL, component)
-- min == max is a valid (non-adjustable) range per the Matter spec, so only max < min is malformed;
-- an out-of-bounds value is clamped, but a malformed relationship is only logged and left as-is,
-- since volume_level_handler already guards against a non-positive range.
if max_volume > camera_fields.ABS_VOL_MAX then
device.log.warn(string.format("Device reported invalid maximum (%d) %s volume level range value", ib.data.value, component))
max_volume = camera_fields.ABS_VOL_MAX
elseif min_volume and max_volume < min_volume then
device.log.warn(string.format("Device reported invalid maximum (%d) %s volume level range value", ib.data.value, component))
end
device:set_field(camera_fields.MAX_VOLUME_LEVEL .. "_" .. component, max_volume)
camera_utils.set_field_for_component(device, camera_fields.MAX_VOLUME_LEVEL, component, max_volume)
camera_cfg.reconcile_profile_and_capabilities(device)
end

function CameraAttributeHandlers.min_volume_level_handler(driver, device, ib, response)
local component = device:endpoint_to_component(ib)
local min_volume = ib.data.value
local max_volume = device:get_field(camera_fields.MAX_VOLUME_LEVEL .. "_" .. component)
if min_volume < camera_fields.ABS_VOL_MIN or (max_volume and min_volume >= max_volume) then
local max_volume = camera_utils.get_field_for_component(device, camera_fields.MAX_VOLUME_LEVEL, component)
-- See max_volume_level_handler: min == max is valid, only min > max is malformed and only logged.
if min_volume < camera_fields.ABS_VOL_MIN then
device.log.warn(string.format("Device reported invalid minimum (%d) %s volume level range value", ib.data.value, component))
min_volume = camera_fields.ABS_VOL_MIN
elseif max_volume and min_volume > max_volume then
device.log.warn(string.format("Device reported invalid minimum (%d) %s volume level range value", ib.data.value, component))
end
device:set_field(camera_fields.MIN_VOLUME_LEVEL .. "_" .. component, min_volume)
camera_utils.set_field_for_component(device, camera_fields.MIN_VOLUME_LEVEL, component, min_volume)
camera_cfg.reconcile_profile_and_capabilities(device)
end

function CameraAttributeHandlers.status_light_enabled_handler(driver, device, ib, response)
Expand Down Expand Up @@ -450,7 +462,7 @@ end

function CameraAttributeHandlers.camera_av_stream_management_attribute_list_handler(driver, device, ib, response)
if not ib.data.elements then return end
local status_light_enabled_present, status_light_brightness_present = false, false
local status_light_enabled_present, status_light_brightness_present, hard_privacy_mode_present = false, false, false
local attribute_ids = {}
for _, attr in ipairs(ib.data.elements) do
if attr.value == clusters.CameraAvStreamManagement.attributes.StatusLightEnabled.ID then
Expand All @@ -459,6 +471,8 @@ function CameraAttributeHandlers.camera_av_stream_management_attribute_list_hand
elseif attr.value == clusters.CameraAvStreamManagement.attributes.StatusLightBrightness.ID then
status_light_brightness_present = true
table.insert(attribute_ids, clusters.CameraAvStreamManagement.attributes.StatusLightBrightness.ID)
elseif attr.value == clusters.CameraAvStreamManagement.attributes.HardPrivacyModeOn.ID then
hard_privacy_mode_present = true
end
end
local component_map = device:get_field(fields.COMPONENT_TO_ENDPOINT_MAP) or {}
Expand All @@ -469,6 +483,7 @@ function CameraAttributeHandlers.camera_av_stream_management_attribute_list_hand
}
device:set_field(fields.COMPONENT_TO_ENDPOINT_MAP, component_map, {persist=true})
camera_cfg.update_status_light_attribute_presence(device, status_light_enabled_present, status_light_brightness_present)
camera_cfg.update_hard_privacy_mode_attribute_presence(device, hard_privacy_mode_present)
camera_cfg.reconcile_profile_and_capabilities(device)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ end

function CameraCapabilityHandlers.handle_set_volume(driver, device, cmd)
local endpoint_id = device:component_to_endpoint(cmd.component)
local max_volume = device:get_field(camera_fields.MAX_VOLUME_LEVEL .. "_" .. cmd.component) or camera_fields.ABS_VOL_MAX
local min_volume = device:get_field(camera_fields.MIN_VOLUME_LEVEL .. "_" .. cmd.component) or camera_fields.ABS_VOL_MIN
local max_volume = camera_utils.get_field_for_component(device, camera_fields.MAX_VOLUME_LEVEL, cmd.component) or camera_fields.ABS_VOL_MAX
local min_volume = camera_utils.get_field_for_component(device, camera_fields.MIN_VOLUME_LEVEL, cmd.component) or camera_fields.ABS_VOL_MIN
-- Convert from [0, 100] to [min_volume, max_volume] before writing attribute
local volume_range = max_volume - min_volume
local volume = utils.round(cmd.args.volume * volume_range / 100.0 + min_volume)
Expand All @@ -75,8 +75,8 @@ end

function CameraCapabilityHandlers.handle_volume_up(driver, device, cmd)
local endpoint_id = device:component_to_endpoint(cmd.component)
local max_volume = device:get_field(camera_fields.MAX_VOLUME_LEVEL .. "_" .. cmd.component) or camera_fields.ABS_VOL_MAX
local min_volume = device:get_field(camera_fields.MIN_VOLUME_LEVEL .. "_" .. cmd.component) or camera_fields.ABS_VOL_MIN
local max_volume = camera_utils.get_field_for_component(device, camera_fields.MAX_VOLUME_LEVEL, cmd.component) or camera_fields.ABS_VOL_MAX
local min_volume = camera_utils.get_field_for_component(device, camera_fields.MIN_VOLUME_LEVEL, cmd.component) or camera_fields.ABS_VOL_MIN
local volume = device:get_latest_state(cmd.component, capabilities.audioVolume.ID, capabilities.audioVolume.volume.NAME)
if not volume or volume >= max_volume then return end
-- Convert from [0, 100] to [min_volume, max_volume] before writing attribute
Expand All @@ -91,8 +91,8 @@ end

function CameraCapabilityHandlers.handle_volume_down(driver, device, cmd)
local endpoint_id = device:component_to_endpoint(cmd.component)
local max_volume = device:get_field(camera_fields.MAX_VOLUME_LEVEL .. "_" .. cmd.component) or camera_fields.ABS_VOL_MAX
local min_volume = device:get_field(camera_fields.MIN_VOLUME_LEVEL .. "_" .. cmd.component) or camera_fields.ABS_VOL_MIN
local max_volume = camera_utils.get_field_for_component(device, camera_fields.MAX_VOLUME_LEVEL, cmd.component) or camera_fields.ABS_VOL_MAX
local min_volume = camera_utils.get_field_for_component(device, camera_fields.MIN_VOLUME_LEVEL, cmd.component) or camera_fields.ABS_VOL_MIN
local volume = device:get_latest_state(cmd.component, capabilities.audioVolume.ID, capabilities.audioVolume.volume.NAME)
if not volume or volume <= min_volume then return end
-- Convert from [0, 100] to [min_volume, max_volume] before writing attribute
Expand Down Expand Up @@ -157,9 +157,15 @@ CameraCapabilityHandlers.ptz_set_position_factory = function(command)
-- a single-axis command should only set (and clamp) the axis it targets.
local pan, tilt, zoom
if command == capabilities.mechanicalPanTiltZoom.commands.setPanTiltZoom then
pan = utils.clamp_value(cmd.args.pan, ptz_map[camera_fields.PAN_IDX].range.minimum, ptz_map[camera_fields.PAN_IDX].range.maximum)
tilt = utils.clamp_value(cmd.args.tilt, ptz_map[camera_fields.TILT_IDX].range.minimum, ptz_map[camera_fields.TILT_IDX].range.maximum)
zoom = utils.clamp_value(cmd.args.zoom, ptz_map[camera_fields.ZOOM_IDX].range.minimum, ptz_map[camera_fields.ZOOM_IDX].range.maximum)
if cmd.args.pan ~= nil then
pan = utils.clamp_value(cmd.args.pan, ptz_map[camera_fields.PAN_IDX].range.minimum, ptz_map[camera_fields.PAN_IDX].range.maximum)
end
if cmd.args.tilt ~= nil then
tilt = utils.clamp_value(cmd.args.tilt, ptz_map[camera_fields.TILT_IDX].range.minimum, ptz_map[camera_fields.TILT_IDX].range.maximum)
end
if cmd.args.zoom ~= nil then
zoom = utils.clamp_value(cmd.args.zoom, ptz_map[camera_fields.ZOOM_IDX].range.minimum, ptz_map[camera_fields.ZOOM_IDX].range.maximum)
end
elseif command == capabilities.mechanicalPanTiltZoom.commands.setPan then
pan = utils.clamp_value(cmd.args.pan, ptz_map[camera_fields.PAN_IDX].range.minimum, ptz_map[camera_fields.PAN_IDX].range.maximum)
elseif command == capabilities.mechanicalPanTiltZoom.commands.setTilt then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,27 @@ local function set_status_light_presence(device, status_light_enabled_present, s
device:set_field(camera_fields.STATUS_LIGHT_BRIGHTNESS_PRESENT, status_light_brightness_present == true, { persist = true })
end

local function get_hard_privacy_mode_presence(device)
return device:get_field(camera_fields.HARD_PRIVACY_MODE_PRESENT)
end

local function set_hard_privacy_mode_presence(device, hard_privacy_mode_present)
device:set_field(camera_fields.HARD_PRIVACY_MODE_PRESENT, hard_privacy_mode_present == true, { persist = true })
end

--- Leaves audioVolume as-is if the min/max levels aren't both known yet instead of guessing;
--- otherwise requires max > min to include it.
--- @param component string a profile component name
--- @return should_include boolean whether audioVolume belongs on the component argument.
local function should_include_volume_capability(device, component)
local min_volume = camera_utils.get_field_for_component(device, camera_fields.MIN_VOLUME_LEVEL, component)
local max_volume = camera_utils.get_field_for_component(device, camera_fields.MAX_VOLUME_LEVEL, component)
if min_volume == nil or max_volume == nil then
return device:supports_capability(capabilities.audioVolume, component)
end
return max_volume > min_volume
end

local function build_webrtc_supported_features()
return {
bundle = true,
Expand Down Expand Up @@ -100,12 +121,32 @@ local function build_video_stream_settings_supported_features(device)
return supported_features
end

local function build_camera_privacy_supported_attributes()
return { "softRecordingPrivacyMode", "softLivestreamPrivacyMode" }
local function camera_privacy_feature_supported(device)
return camera_utils.feature_supported(device, clusters.CameraAvStreamManagement.ID, clusters.CameraAvStreamManagement.types.Feature.PRIVACY)
end

local function build_camera_privacy_supported_commands()
return { "setSoftRecordingPrivacyMode", "setSoftLivestreamPrivacyMode" }
-- SoftRecordingPrivacyModeEnabled/SoftLivestreamPrivacyModeEnabled are conditionally mandatory on the PRIV
-- feature, while HardPrivacyModeOn has independent optional conformance.
-- A device can support either, both, or neither, so each is built independently.
local function build_camera_privacy_supported_attributes(device)
local supported_attributes = {}
if camera_privacy_feature_supported(device) then
table.insert(supported_attributes, "softRecordingPrivacyMode")
table.insert(supported_attributes, "softLivestreamPrivacyMode")
end
if get_hard_privacy_mode_presence(device) then
table.insert(supported_attributes, "hardPrivacyMode")
end
return supported_attributes
end

local function build_camera_privacy_supported_commands(device)
local supported_commands = {}
if camera_privacy_feature_supported(device) then
table.insert(supported_commands, "setSoftRecordingPrivacyMode")
table.insert(supported_commands, "setSoftLivestreamPrivacyMode")
end
return supported_commands
end

local function capabilities_needing_reinit(device)
Expand Down Expand Up @@ -155,8 +196,8 @@ local function capabilities_needing_reinit(device)
capabilities_to_reinit.video_stream_settings = true
end

if should_init(capabilities.cameraPrivacyMode, capabilities.cameraPrivacyMode.supportedAttributes, build_camera_privacy_supported_attributes()) or
should_init(capabilities.cameraPrivacyMode, capabilities.cameraPrivacyMode.supportedCommands, build_camera_privacy_supported_commands()) then
if should_init(capabilities.cameraPrivacyMode, capabilities.cameraPrivacyMode.supportedAttributes, build_camera_privacy_supported_attributes(device)) or
should_init(capabilities.cameraPrivacyMode, capabilities.cameraPrivacyMode.supportedCommands, build_camera_privacy_supported_commands(device)) then
capabilities_to_reinit.camera_privacy_mode = true
end

Expand Down Expand Up @@ -194,6 +235,7 @@ end

function CameraDeviceConfiguration.match_profile(device)
local status_light_enabled_present, status_light_brightness_present = get_status_light_presence(device)
local hard_privacy_mode_present = get_hard_privacy_mode_presence(device)
local profile_update_requested = false
local optional_supported_component_capabilities = {}
local main_component_capabilities = {}
Expand Down Expand Up @@ -229,17 +271,21 @@ function CameraDeviceConfiguration.match_profile(device)
table.insert(main_component_capabilities, capabilities.audioRecording.ID)
end
table.insert(microphone_component_capabilities, capabilities.audioMute.ID)
table.insert(microphone_component_capabilities, capabilities.audioVolume.ID)
if should_include_volume_capability(device, camera_fields.profile_components.microphone) then
table.insert(microphone_component_capabilities, capabilities.audioVolume.ID)
end
end
if clus_has_feature(clusters.CameraAvStreamManagement.types.Feature.SNAPSHOT) then
table.insert(main_component_capabilities, capabilities.imageCapture.ID)
end
if clus_has_feature(clusters.CameraAvStreamManagement.types.Feature.PRIVACY) then
if clus_has_feature(clusters.CameraAvStreamManagement.types.Feature.PRIVACY) or hard_privacy_mode_present then
table.insert(main_component_capabilities, capabilities.cameraPrivacyMode.ID)
end
if clus_has_feature(clusters.CameraAvStreamManagement.types.Feature.SPEAKER) then
table.insert(speaker_component_capabilities, capabilities.audioMute.ID)
table.insert(speaker_component_capabilities, capabilities.audioVolume.ID)
if should_include_volume_capability(device, camera_fields.profile_components.speaker) then
table.insert(speaker_component_capabilities, capabilities.audioVolume.ID)
end
end
if clus_has_feature(clusters.CameraAvStreamManagement.types.Feature.IMAGE_CONTROL) then
table.insert(main_component_capabilities, capabilities.imageControl.ID)
Expand Down Expand Up @@ -361,8 +407,8 @@ end
local function init_camera_privacy_mode(device)
if device:supports_capability(capabilities.cameraPrivacyMode) then
local av_stream_management_ep_ids = device:get_endpoints(clusters.CameraAvStreamManagement.ID)
device:emit_event_for_endpoint(av_stream_management_ep_ids[1], capabilities.cameraPrivacyMode.supportedAttributes(build_camera_privacy_supported_attributes()))
device:emit_event_for_endpoint(av_stream_management_ep_ids[1], capabilities.cameraPrivacyMode.supportedCommands(build_camera_privacy_supported_commands()))
device:emit_event_for_endpoint(av_stream_management_ep_ids[1], capabilities.cameraPrivacyMode.supportedAttributes(build_camera_privacy_supported_attributes(device)))
device:emit_event_for_endpoint(av_stream_management_ep_ids[1], capabilities.cameraPrivacyMode.supportedCommands(build_camera_privacy_supported_commands(device)))
end
end

Expand Down Expand Up @@ -442,6 +488,10 @@ function CameraDeviceConfiguration.update_status_light_attribute_presence(device
set_status_light_presence(device, status_light_enabled_present, status_light_brightness_present)
end

function CameraDeviceConfiguration.update_hard_privacy_mode_attribute_presence(device, hard_privacy_mode_present)
set_hard_privacy_mode_presence(device, hard_privacy_mode_present)
end

function CameraDeviceConfiguration.reinitialize_changed_camera_capabilities_and_subscriptions(device, old_profile, new_profile)
local changed_capabilities = changed_capabilities_from_profiles(old_profile, new_profile)
initialize_selected_camera_capabilities(device, changed_capabilities)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ CameraFields.TRIGGERED_ZONES = "__triggered_zones"
CameraFields.DPTZ_VIEWPORTS = "__dptz_viewports"
CameraFields.STATUS_LIGHT_ENABLED_PRESENT = "__status_light_enabled_present"
CameraFields.STATUS_LIGHT_BRIGHTNESS_PRESENT = "__status_light_brightness_present"
CameraFields.HARD_PRIVACY_MODE_PRESENT = "__hard_privacy_mode_present"

CameraFields.CameraAVSMFeatureMapAttr = { ID = 0xFFFC, cluster = clusters.CameraAvStreamManagement.ID }
CameraFields.CameraAVSULMFeatureMapAttr = { ID = 0xFFFC, cluster = clusters.CameraAvSettingsUserLevelManagement.ID }
Expand Down
Loading
Loading