Skip to content
24 changes: 18 additions & 6 deletions drivers/SmartThings/matter-switch/src/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,15 @@ function SwitchLifecycleHandlers.device_added(driver, device)
device:send(clusters.OnOff.attributes.OnOff:read(device))
end

-- call device init in case init is not called after added due to device caching
SwitchLifecycleHandlers.device_init(driver, device)
-- The device init event is guaranteed in FW versions 58+, so this is only needed for older hubs
if version.rpc < 10 then
-- call device init in case init is not called after added due to device caching
SwitchLifecycleHandlers.device_init(driver, device)
end
end

function SwitchLifecycleHandlers.do_configure(driver, device)
if device.network_type == device_lib.NETWORK_TYPE_MATTER and not switch_utils.detect_bridge(device) then
if device.network_type == device_lib.NETWORK_TYPE_MATTER then
switch_cfg.set_device_control_options(device)
device_cfg.match_profile(driver, device)
elseif device.network_type == device_lib.NETWORK_TYPE_CHILD then
Expand All @@ -54,7 +57,7 @@ function SwitchLifecycleHandlers.do_configure(driver, device)
end

function SwitchLifecycleHandlers.driver_switched(driver, device)
if device.network_type == device_lib.NETWORK_TYPE_MATTER and not switch_utils.detect_bridge(device) then
if device.network_type == device_lib.NETWORK_TYPE_MATTER then
device_cfg.match_profile(driver, device)
end
end
Expand All @@ -66,12 +69,16 @@ function SwitchLifecycleHandlers.info_changed(driver, device, event, args)
button_cfg.configure_buttons(device,
device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH})
)
if version.api >= 16 and version.rpc >= 10 then
local camera_cfg = require "sub_drivers.camera.camera_utils.device_configuration"
camera_cfg.initialize_select_camera_capabilities(device)
end
elseif device.network_type == device_lib.NETWORK_TYPE_CHILD then
device:get_parent_device():subscribe() -- parent device required to send subscription requests
end
end

if device.network_type == device_lib.NETWORK_TYPE_MATTER and not switch_utils.detect_bridge(device) then
if device.network_type == device_lib.NETWORK_TYPE_MATTER then
if device.matter_version.software ~= args.old_st_store.matter_version.software then
device_cfg.match_profile(driver, device)
end
Expand All @@ -95,11 +102,16 @@ function SwitchLifecycleHandlers.device_init(driver, device)
switch_utils.check_field_name_updates(device)
device:set_component_to_endpoint_fn(switch_utils.component_to_endpoint)
device:set_endpoint_to_component_fn(switch_utils.endpoint_to_component)
device:extend_device("emit_event_for_endpoint", switch_utils.emit_event_for_endpoint)
if device:get_field(fields.IS_PARENT_CHILD_DEVICE) then
device:set_find_child(switch_utils.find_child)
end
if #device:get_endpoints(clusters.PowerSource.ID, {feature_bitmap = clusters.PowerSource.types.PowerSourceFeature.BATTERY}) == 0 then
device:set_field(fields.profiling_data.BATTERY_SUPPORT, fields.battery_support.NO_BATTERY, {persist = true})
switch_utils.set_preprofiling_data(device, fields.profiling_data.BATTERY_SUPPORT, fields.battery_support.NO_BATTERY)
end
if version.api < 16 or version.rpc < 10 or #device:get_endpoints(clusters.CameraAvStreamManagement.ID) == 0 then
switch_utils.set_preprofiling_data(device, fields.profiling_data.STATUS_LIGHT_ENABLED_PRESENT, false)
switch_utils.set_preprofiling_data(device, fields.profiling_data.STATUS_LIGHT_BRIGHTNESS_PRESENT, false)
end
switch_utils.handle_electrical_sensor_info(device)
device:extend_device("subscribe", switch_utils.subscribe)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
-- Copyright © 2025 SmartThings, Inc.
-- Licensed under the Apache License, Version 2.0

local camera_fields = require "sub_drivers.camera.camera_utils.fields"
local camera_utils = require "sub_drivers.camera.camera_utils.utils"
local capabilities = require "st.capabilities"
local clusters = require "st.matter.clusters"
local camera_cfg = require "sub_drivers.camera.camera_utils.device_configuration"
local fields = require "switch_utils.fields"
local utils = require "st.utils"
local camera_fields = require "sub_drivers.camera.camera_utils.fields"
local camera_utils = require "sub_drivers.camera.camera_utils.utils"
local st_utils = require "st.utils"

local CameraAttributeHandlers = {}

Expand Down Expand Up @@ -37,7 +35,7 @@ CameraAttributeHandlers.night_vision_factory = function(attribute)
end

function CameraAttributeHandlers.image_rotation_handler(driver, device, ib, response)
local degrees = utils.clamp_value(ib.data.value, 0, 359)
local degrees = st_utils.clamp_value(ib.data.value, 0, 359)
device:emit_event_for_endpoint(ib, capabilities.imageControl.imageRotation(degrees))
camera_utils.update_supported_attributes(device, ib, capabilities.imageControl, "imageRotation")
end
Expand All @@ -63,7 +61,7 @@ function CameraAttributeHandlers.volume_level_handler(driver, device, ib, respon
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 limited_range = max_volume - min_volume
local normalized_volume = utils.round((ib.data.value - min_volume) * 100.0 / limited_range)
local normalized_volume = st_utils.round((ib.data.value - min_volume) * 100.0 / limited_range)
device:emit_event_for_endpoint(ib, capabilities.audioVolume.volume(normalized_volume))
end

Expand Down Expand Up @@ -296,7 +294,7 @@ function CameraAttributeHandlers.ptz_position_handler(driver, device, ib, respon
local emit_event = function(idx, value)
if value ~= ptz_map[idx].current then
device:emit_event_for_endpoint(ib, ptz_map[idx].attribute(
utils.clamp_value(value, ptz_map[idx].range.minimum, ptz_map[idx].range.maximum)
st_utils.clamp_value(value, ptz_map[idx].range.minimum, ptz_map[idx].range.maximum)
))
end
end
Expand Down Expand Up @@ -447,31 +445,35 @@ function CameraAttributeHandlers.selected_chime_handler(driver, device, ib, resp
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 attribute_ids = {}
for _, attr in ipairs(ib.data.elements) do
local status_light_attribute_ids = {}
for _, attr in ipairs(ib.data.elements or {}) do
if attr.value == clusters.CameraAvStreamManagement.attributes.StatusLightEnabled.ID then
status_light_enabled_present = true
table.insert(attribute_ids, clusters.CameraAvStreamManagement.attributes.StatusLightEnabled.ID)
table.insert(status_light_attribute_ids, clusters.CameraAvStreamManagement.attributes.StatusLightEnabled.ID)
elseif attr.value == clusters.CameraAvStreamManagement.attributes.StatusLightBrightness.ID then
status_light_brightness_present = true
table.insert(attribute_ids, clusters.CameraAvStreamManagement.attributes.StatusLightBrightness.ID)
table.insert(status_light_attribute_ids, clusters.CameraAvStreamManagement.attributes.StatusLightBrightness.ID)
end
end
local component_map = device:get_field(fields.COMPONENT_TO_ENDPOINT_MAP) or {}
component_map.statusLed = {
endpoint_id = ib.endpoint_id,
cluster_id = ib.cluster_id,
attribute_ids = attribute_ids,
}
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.reconcile_profile_and_capabilities(device)
if #status_light_attribute_ids > 0 then
camera_utils.update_component_to_endpoint_map(device, camera_fields.profile_components.statusLed, {
endpoint_id = ib.endpoint_id,
cluster_id = ib.cluster_id,
attribute_ids = status_light_attribute_ids,
})
end
local camera_cfg = require "sub_drivers.camera.camera_utils.device_configuration"
local utils = require "switch_utils.utils"
local fields = require "switch_utils.fields"
utils.set_preprofiling_data(device, fields.profiling_data.STATUS_LIGHT_ENABLED_PRESENT, status_light_enabled_present)
utils.set_preprofiling_data(device, fields.profiling_data.STATUS_LIGHT_BRIGHTNESS_PRESENT, status_light_brightness_present)
camera_cfg.reconcile_profile_and_capabilities(driver, device)
end

function CameraAttributeHandlers.camera_feature_map_handler(driver, device, ib, response)
camera_cfg.reconcile_profile_and_capabilities(device)
local camera_cfg = require "sub_drivers.camera.camera_utils.device_configuration"
camera_cfg.reconcile_profile_and_capabilities(driver, device)
end

return CameraAttributeHandlers
Loading
Loading