Skip to content
Open
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
59 changes: 39 additions & 20 deletions drivers/SmartThings/matter-switch/src/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ function SwitchLifecycleHandlers.do_configure(driver, device)
if device.network_type == device_lib.NETWORK_TYPE_MATTER and not switch_utils.detect_bridge(device) then
switch_cfg.set_device_control_options(device)
device_cfg.match_profile(driver, device)
elseif device.network_type == device_lib.NETWORK_TYPE_CHILD then
-- because get_parent_device() may cause race conditions if used in init, an initial child subscribe is handled in doConfigure.
-- all future calls to subscribe will be handled by the parent device in init
device:subscribe()
end
end

Expand Down Expand Up @@ -80,25 +84,7 @@ function SwitchLifecycleHandlers.device_init(driver, device)
if device:get_field(fields.IS_PARENT_CHILD_DEVICE) then
device:set_find_child(switch_utils.find_child)
end
local default_endpoint_id = switch_utils.find_default_endpoint(device)
-- ensure subscription to all endpoint attributes- including those mapped to child devices
for _, ep in ipairs(device.endpoints) do
if ep.endpoint_id ~= default_endpoint_id then
local id = 0
for _, dt in ipairs(ep.device_types) do
id = math.max(id, dt.device_type_id)
end
for _, attr in pairs(fields.device_type_attribute_map[id] or {}) do
if id == fields.DEVICE_TYPE_ID.GENERIC_SWITCH and
attr ~= clusters.PowerSource.attributes.BatPercentRemaining and
attr ~= clusters.PowerSource.attributes.BatChargeLevel then
device:add_subscribed_event(attr)
else
device:add_subscribed_attribute(attr)
end
end
end
end
device:extend_device("subscribe", switch_utils.subscribe)
device:subscribe()

-- device energy reporting must be handled cumulatively, periodically, or by both simulatanously.
Expand Down Expand Up @@ -298,7 +284,40 @@ local matter_driver_template = {
[capabilities.valve.commands.open.NAME] = capability_handlers.handle_valve_open,
},
},
supported_capabilities = fields.supported_capabilities,
supported_capabilities = {
capabilities.audioMute,
capabilities.audioRecording,
capabilities.audioVolume,
capabilities.battery,
capabilities.batteryLevel,
capabilities.button,
capabilities.cameraPrivacyMode,
capabilities.cameraViewportSettings,
capabilities.colorControl,
capabilities.colorTemperature,
capabilities.energyMeter,
capabilities.fanMode,
capabilities.fanSpeedPercent,
capabilities.hdr,
capabilities.illuminanceMeasurement,
capabilities.imageControl,
capabilities.level,
capabilities.localMediaStorage,
capabilities.mechanicalPanTiltZoom,
capabilities.motionSensor,
capabilities.nightVision,
capabilities.powerMeter,
capabilities.powerConsumptionReport,
capabilities.relativeHumidityMeasurement,
capabilities.sounds,
capabilities.switch,
capabilities.switchLevel,
capabilities.temperatureMeasurement,
capabilities.valve,
capabilities.videoStreamSettings,
capabilities.webrtc,
capabilities.zoneManagement
},
sub_drivers = {
switch_utils.lazy_load_if_possible("sub_drivers.aqara_cube"),
switch_utils.lazy_load("sub_drivers.camera"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ function CameraUtils.subscribe(device)
clusters.CameraAvStreamManagement.attributes.StatusLightBrightness
},
[capabilities.switch.ID] = {
clusters.CameraAvStreamManagement.attributes.StatusLightEnabled
clusters.CameraAvStreamManagement.attributes.StatusLightEnabled,
clusters.OnOff.attributes.OnOff
},
[capabilities.videoStreamSettings.ID] = {
clusters.CameraAvStreamManagement.attributes.RateDistortionTradeOffPoints,
Expand Down Expand Up @@ -223,8 +224,26 @@ function CameraUtils.subscribe(device)
},
[capabilities.motionSensor.ID] = {
clusters.OccupancySensing.attributes.Occupancy
}
},
[capabilities.switchLevel.ID] = {
clusters.LevelControl.attributes.CurrentLevel,
clusters.LevelControl.attributes.MaxLevel,
clusters.LevelControl.attributes.MinLevel,
},
[capabilities.colorControl.ID] = {
clusters.ColorControl.attributes.ColorMode,
clusters.ColorControl.attributes.CurrentHue,
clusters.ColorControl.attributes.CurrentSaturation,
clusters.ColorControl.attributes.CurrentX,
clusters.ColorControl.attributes.CurrentY,
},
[capabilities.colorTemperature.ID] = {
clusters.ColorControl.attributes.ColorTemperatureMireds,
clusters.ColorControl.attributes.ColorTempPhysicalMaxMireds,
clusters.ColorControl.attributes.ColorTempPhysicalMinMireds,
},
}

local camera_subscribed_events = {
[capabilities.zoneManagement.ID] = {
clusters.ZoneManagement.events.ZoneTriggered,
Expand All @@ -238,56 +257,26 @@ function CameraUtils.subscribe(device)
}
}

for capability, attr_list in pairs(camera_subscribed_attributes) do
if device:supports_capability_by_id(capability) then
for _, attr in pairs(attr_list) do
device:add_subscribed_attribute(attr)
end
end
end
for capability, event_list in pairs(camera_subscribed_events) do
if device:supports_capability_by_id(capability) then
for _, event in pairs(event_list) do
device:add_subscribed_event(event)
end
end
end
local im = require "st.matter.interaction_model"

local subscribe_request = im.InteractionRequest(im.InteractionRequest.RequestType.SUBSCRIBE, {})
local devices_seen, capabilities_seen, attributes_seen, events_seen = {}, {}, {}, {}

-- match_profile is called from the CameraAvStreamManagement AttributeList handler,
-- so the subscription needs to be added here first
if #device:get_endpoints(clusters.CameraAvStreamManagement.ID) > 0 then
device:add_subscribed_attribute(clusters.CameraAvStreamManagement.attributes.AttributeList)
local ib = im.InteractionInfoBlock(nil, clusters.CameraAvStreamManagement.ID, clusters.CameraAvStreamManagement.attributes.AttributeList.ID)
subscribe_request:with_info_block(ib)
end

-- Add subscription for attributes specific to child devices
if device:get_field(fields.IS_PARENT_CHILD_DEVICE) then
for _, ep in ipairs(device.endpoints or {}) do
local id = 0
for _, dt in ipairs(ep.device_types or {}) do
if dt.device_type_id ~= fields.DEVICE_TYPE_ID.GENERIC_SWITCH then
id = math.max(id, dt.device_type_id)
end
end
for _, attr in pairs(fields.device_type_attribute_map[id] or {}) do
device:add_subscribed_attribute(attr)
end
for _, endpoint_info in ipairs(device.endpoints) do
local checked_device = switch_utils.find_child(device, endpoint_info.endpoint_id) or device
if not devices_seen[checked_device.id] then
switch_utils.populate_subscribe_request_for_device(checked_device, subscribe_request, capabilities_seen, attributes_seen, events_seen,
camera_subscribed_attributes, camera_subscribed_events
)
devices_seen[checked_device.id] = true -- only loop through any device once
end
end

local im = require "st.matter.interaction_model"
local subscribed_attributes = device:get_field("__subscribed_attributes") or {}
local subscribed_events = device:get_field("__subscribed_events") or {}
local subscribe_request = im.InteractionRequest(im.InteractionRequest.RequestType.SUBSCRIBE, {})
for _, attributes in pairs(subscribed_attributes) do
for _, ib in pairs(attributes) do
subscribe_request:with_info_block(ib)
end
end
for _, events in pairs(subscribed_events) do
for _, ib in pairs(events) do
subscribe_request:with_info_block(ib)
end
end
if #subscribe_request.info_blocks > 0 then
device:send(subscribe_request)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ end
function CameraLifecycleHandlers.info_changed(driver, device, event, args)
if camera_utils.profile_changed(device.profile.components, args.old_st_store.profile.components) then
camera_cfg.initialize_camera_capabilities(device)
device:subscribe()
if #switch_utils.get_endpoints_by_device_type(device, fields.DEVICE_TYPE_ID.DOORBELL) > 0 then
button_cfg.configure_buttons(device)
end
device:subscribe()
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,15 @@ end
-- [[ COLOR CONTROL CLUSTER ATTRIBUTES ]] --

function AttributeHandlers.current_hue_handler(driver, device, ib, response)
if device:get_field(fields.COLOR_MODE) == fields.X_Y_COLOR_MODE or ib.data.value == nil then
if device:get_field(fields.COLOR_MODE) == clusters.ColorControl.types.ColorMode.CURRENTX_AND_CURRENTY or ib.data.value == nil then
return
end
local hue = math.floor((ib.data.value / 0xFE * 100) + 0.5)
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.colorControl.hue(hue))
end

function AttributeHandlers.current_saturation_handler(driver, device, ib, response)
if device:get_field(fields.COLOR_MODE) == fields.X_Y_COLOR_MODE or ib.data.value == nil then
if device:get_field(fields.COLOR_MODE) == clusters.ColorControl.types.ColorMode.CURRENTX_AND_CURRENTY or ib.data.value == nil then
return
end
local sat = math.floor((ib.data.value / 0xFE * 100) + 0.5)
Expand Down Expand Up @@ -132,7 +132,7 @@ function AttributeHandlers.color_temperature_mireds_handler(driver, device, ib,
end

function AttributeHandlers.current_x_handler(driver, device, ib, response)
if device:get_field(fields.COLOR_MODE) == fields.HUE_SAT_COLOR_MODE then
if device:get_field(fields.COLOR_MODE) == clusters.ColorControl.types.ColorMode.CURRENT_HUE_AND_CURRENT_SATURATION then
return
end
local y = device:get_field(fields.RECEIVED_Y)
Expand All @@ -150,7 +150,7 @@ function AttributeHandlers.current_x_handler(driver, device, ib, response)
end

function AttributeHandlers.current_y_handler(driver, device, ib, response)
if device:get_field(fields.COLOR_MODE) == fields.HUE_SAT_COLOR_MODE then
if device:get_field(fields.COLOR_MODE) == clusters.ColorControl.types.ColorMode.CURRENT_HUE_AND_CURRENT_SATURATION then
return
end
local x = device:get_field(fields.RECEIVED_X)
Expand All @@ -166,15 +166,17 @@ function AttributeHandlers.current_y_handler(driver, device, ib, response)
end

function AttributeHandlers.color_mode_handler(driver, device, ib, response)
if ib.data.value == device:get_field(fields.COLOR_MODE) or (ib.data.value ~= fields.HUE_SAT_COLOR_MODE and ib.data.value ~= fields.X_Y_COLOR_MODE) then
return
if ib.data.value == device:get_field(fields.COLOR_MODE)
or (ib.data.value ~= clusters.ColorControl.types.ColorMode.CURRENT_HUE_AND_CURRENT_SATURATION
and ib.data.value ~= clusters.ColorControl.types.ColorMode.CURRENTX_AND_CURRENTY) then
return
end
device:set_field(fields.COLOR_MODE, ib.data.value)
local req = im.InteractionRequest(im.InteractionRequest.RequestType.READ, {})
if ib.data.value == fields.HUE_SAT_COLOR_MODE then
if ib.data.value == clusters.ColorControl.types.ColorMode.CURRENT_HUE_AND_CURRENT_SATURATION then
req:merge(clusters.ColorControl.attributes.CurrentHue:read())
req:merge(clusters.ColorControl.attributes.CurrentSaturation:read())
elseif ib.data.value == fields.X_Y_COLOR_MODE then
elseif ib.data.value == clusters.ColorControl.types.ColorMode.CURRENTX_AND_CURRENTY then
req:merge(clusters.ColorControl.attributes.CurrentX:read())
req:merge(clusters.ColorControl.attributes.CurrentY:read())
end
Expand Down
Loading
Loading