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
20 changes: 20 additions & 0 deletions drivers/SmartThings/matter-switch/fingerprints.yml
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,26 @@ matterManufacturer:
vendorId: 0x1285
productId: 0x0009
deviceProfileName: 4-button-batteryLevel
- id: "4741/5"
deviceLabel: Hager Switch 1G
vendorId: 0x1285
productId: 0x0005
deviceProfileName: matter-bridge
- id: "4741/6"
deviceLabel: Hager Switch 2G
vendorId: 0x1285
productId: 0x0006
deviceProfileName: matter-bridge
- id: "4741/7"
deviceLabel: Hager PIR 1.1M
vendorId: 0x1285
productId: 0x0007
deviceProfileName: matter-bridge
- id: "4741/10"
deviceLabel: Hager PIR 2.2M
vendorId: 0x1285
productId: 0x000A
deviceProfileName: matter-bridge
# HAOJAI
- id: "5530/4113"
deviceLabel: HAOJAI Smart Switch 3-key
Expand Down
14 changes: 14 additions & 0 deletions drivers/SmartThings/matter-switch/profiles/motion-illuminance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: motion-illuminance
components:
- id: main
capabilities:
- id: motionSensor
version: 1
- id: illuminanceMeasurement
version: 1
- id: firmwareUpdate
version: 1
- id: refresh
version: 1
categories:
- name: MotionSensor
21 changes: 21 additions & 0 deletions drivers/SmartThings/matter-switch/profiles/window-covering.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: window-covering
components:
- id: main
capabilities:
- id: windowShade
version: 1
- id: windowShadePreset
version: 1
- id: windowShadeLevel
version: 1
- id: firmwareUpdate
version: 1
- id: refresh
version: 1
categories:
- name: Blind
preferences:
- preferenceId: presetPosition
explicit: true
- preferenceId: reverse
explicit: true
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

local cluster_base = require "st.matter.cluster_base"
local DescriptorServerAttributes = require "embedded_clusters.Descriptor.server.attributes"
local DescriptorTypes = require "embedded_clusters.Descriptor.types"

local Descriptor = {}

Expand All @@ -11,9 +12,11 @@ Descriptor.NAME = "Descriptor"
Descriptor.server = {}
Descriptor.client = {}
Descriptor.server.attributes = DescriptorServerAttributes:set_parent_cluster(Descriptor)
Descriptor.types = DescriptorTypes

function Descriptor:get_attribute_by_id(attr_id)
local attr_id_map = {
[0x0000] = "DeviceTypeList",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should still ensure this actually points to something

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can test that this will work by pointing your local lua libs to 0.58. Currently, if you do that, the tests will crash

[0x0003] = "PartsList",
}
local attr_name = attr_id_map[attr_id]
Expand All @@ -33,6 +36,7 @@ function Descriptor:get_server_command_by_id(command_id)
end

Descriptor.attribute_direction_map = {
["DeviceTypeList"] = "server",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To actually use this def, we'll need to conditionally include it in your init.lua file. See how this is done in the main driver for examples.

["PartsList"] = "server",
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
-- Copyright © 2026 SmartThings, Inc.
-- Licensed under the Apache License, Version 2.0

local cluster_base = require "st.matter.cluster_base"
local data_types = require "st.matter.data_types"
local TLVParser = require "st.matter.TLV.TLVParser"

local DeviceTypeList = {
ID = 0x0000,
NAME = "DeviceTypeList",
base_type = require "st.matter.data_types.Array",
element_type = require "embedded_clusters.Descriptor.types.DeviceTypeStruct",
}

function DeviceTypeList:augment_type(data_type_obj)
for i, v in ipairs(data_type_obj.elements) do
data_type_obj.elements[i] = data_types.validate_or_build_type(v, DeviceTypeList.element_type)
end
end

function DeviceTypeList:new_value(...)
local o = self.base_type(table.unpack({ ... }))
return o
end

function DeviceTypeList:read(device, endpoint_id)
return cluster_base.read(
device,
endpoint_id,
self._cluster.ID,
self.ID,
nil
)
end

function DeviceTypeList:subscribe(device, endpoint_id)
return cluster_base.subscribe(
device,
endpoint_id,
self._cluster.ID,
self.ID,
nil
)
end

function DeviceTypeList:set_parent_cluster(cluster)
self._cluster = cluster
return self
end

function DeviceTypeList:build_test_report_data(
device,
endpoint_id,
value,
status
)
local data = data_types.validate_or_build_type(value, self.base_type)
self:augment_type(data)

return cluster_base.build_test_report_data(
device,
endpoint_id,
self._cluster.ID,
self.ID,
data,
status
)
end

function DeviceTypeList:deserialize(tlv_buf)
local data = TLVParser.decode_tlv(tlv_buf)
self:augment_type(data)
return data
end

setmetatable(DeviceTypeList, { __call = DeviceTypeList.new_value, __index = DeviceTypeList.base_type })
return DeviceTypeList

Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
-- Copyright 2026 SmartThings
-- Licensed under the Apache License, Version 2.0

local data_types = require "st.matter.data_types"
local StructureABC = require "st.matter.data_types.base_defs.StructureABC"

local DeviceTypeStruct = {}
local new_mt = StructureABC.new_mt({ NAME = "DeviceTypeStruct", ID = data_types.name_to_id_map["Structure"] })

DeviceTypeStruct.field_defs = {
{
name = "device_type",
field_id = 0,
is_nullable = false,
is_optional = false,
data_type = require "st.matter.data_types.Uint32",
},
{
name = "revision",
field_id = 1,
is_nullable = false,
is_optional = false,
data_type = require "st.matter.data_types.Uint16",
},
}

DeviceTypeStruct.init = function(cls, tbl)
local o = {}
o.elements = {}
o.num_elements = 0
setmetatable(o, new_mt)
for _idx, field_def in ipairs(cls.field_defs) do
-- Note: _idx is 1 when field_id is 0
if (not field_def.is_optional and not field_def.is_nullable) and not tbl[field_def.name] then
error("Missing non optional or non_nullable field: " .. field_def.name)
elseif not (field_def.is_optional and tbl[field_def.name] == nil) then
o.elements[field_def.name] = data_types.validate_or_build_type(tbl[field_def.name], field_def.data_type, field_def.name)
o.elements[field_def.name].field_id = field_def.field_id
o.num_elements = o.num_elements + 1
end
end
return o
end

DeviceTypeStruct.serialize = function(self, buf, include_control, tag)
return data_types['Structure'].serialize(self.elements, buf, include_control, tag)
end

new_mt.__call = DeviceTypeStruct.init
new_mt.__index.serialize = DeviceTypeStruct.serialize

DeviceTypeStruct.augment_type = function(self, val)
local elems = {}
local num_elements = 0
for _, v in pairs(val.elements) do
for _, field_def in ipairs(self.field_defs) do
if field_def.field_id == v.field_id and
field_def.is_nullable and
(v.value == nil and v.elements == nil) then
elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name)
num_elements = num_elements + 1
elseif field_def.field_id == v.field_id and not
(field_def.is_optional and v.value == nil and v.elements == nil) then
elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name)
num_elements = num_elements + 1
if field_def.element_type ~= nil then
for i, e in ipairs(elems[field_def.name].elements) do
elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type)
end
end
end
end
end
val.elements = elems
val.num_elements = num_elements
setmetatable(val, new_mt)
end

setmetatable(DeviceTypeStruct, new_mt)

return DeviceTypeStruct

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-- Copyright 2026 SmartThings
-- Licensed under the Apache License, Version 2.0

local types_mt = {}
types_mt.__types_cache = {}
types_mt.__index = function(self, key)
if types_mt.__types_cache[key] == nil then
types_mt.__types_cache[key] = require("embedded_clusters.Descriptor.types." .. key)
end
return types_mt.__types_cache[key]
end

local DescriptorTypes = {}

setmetatable(DescriptorTypes, types_mt)

return DescriptorTypes
1 change: 1 addition & 0 deletions drivers/SmartThings/matter-switch/src/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ local matter_driver_template = {
switch_utils.lazy_load_if_possible("sub_drivers.aqara_cube"),
switch_utils.lazy_load("sub_drivers.camera"),
switch_utils.lazy_load_if_possible("sub_drivers.eve_energy"),
switch_utils.lazy_load_if_possible("sub_drivers.hager"),
switch_utils.lazy_load_if_possible("sub_drivers.ikea_scroll"),
switch_utils.lazy_load_if_possible("sub_drivers.third_reality_garage_door"),
switch_utils.lazy_load_if_possible("sub_drivers.third_reality_mk1")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- Copyright © 2026 SmartThings, Inc.
-- Licensed under the Apache License, Version 2.0

return function(opts, driver, device, ...)
local device_lib = require "st.device"
local get_product_override_field = require "switch_utils.utils".get_product_override_field

local checked_device = device.network_type == device_lib.NETWORK_TYPE_MATTER and device or device:get_parent_device()
if get_product_override_field(checked_device, "needs_hager_subdriver") then
return true, require("sub_drivers.hager")
end
return false
end
Loading
Loading