Skip to content

Commit 7c97195

Browse files
committed
add support for matter hrap device types
1 parent fcdc5f8 commit 7c97195

File tree

22 files changed

+1567
-0
lines changed

22 files changed

+1567
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
name: 'Matter HRAP'
2+
packageKey: 'matter-hrap'
3+
permissions:
4+
matter: {}
5+
description: "SmartThings driver for Matter HRAP devices"
6+
vendorSupportInformation: "https://support.smartthings.com"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
matterGeneric:
2+
- id: "matter/network-manager"
3+
deviceLabel: Matter Network Infrastructure Manager
4+
deviceTypes:
5+
- id: 0x0090 # NIM
6+
deviceProfileName: network-infrastructure-manager
7+
- id: "matter/thread-border-router"
8+
deviceLabel: Matter Thread Border Router
9+
deviceTypes:
10+
- id: 0x0091 # TBR
11+
deviceProfileName: thread-border-router
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: network-infrastructure-manager
2+
components:
3+
- id: main
4+
capabilities:
5+
- id: threadBorderRouter
6+
version: 1
7+
- id: threadNetwork
8+
version: 1
9+
- id: wifiInformation
10+
version: 1
11+
- id: firmwareUpdate
12+
version: 1
13+
- id: refresh
14+
version: 1
15+
categories:
16+
- name: Networking
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: thread-border-router
2+
components:
3+
- id: main
4+
capabilities:
5+
- id: threadBorderRouter
6+
version: 1
7+
- id: threadNetwork
8+
version: 1
9+
- id: firmwareUpdate
10+
version: 1
11+
- id: refresh
12+
version: 1
13+
categories:
14+
- name: Networking
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
local data_types = require "st.matter.data_types"
2+
local TLVParser = require "st.matter.TLV.TLVParser"
3+
4+
local DatasetResponse = {}
5+
6+
DatasetResponse.NAME = "DatasetResponse"
7+
DatasetResponse.ID = 0x0002
8+
DatasetResponse.field_defs = {
9+
{
10+
name = "dataset",
11+
field_id = 0,
12+
is_nullable = false,
13+
is_optional = false,
14+
data_type = require "st.matter.data_types.OctetString1",
15+
},
16+
}
17+
18+
function DatasetResponse:augment_type(base_type_obj)
19+
local elems = {}
20+
for _, v in ipairs(base_type_obj.elements) do
21+
for _, field_def in ipairs(self.field_defs) do
22+
if field_def.field_id == v.field_id and
23+
field_def.is_nullable and
24+
(v.value == nil and v.elements == nil) then
25+
elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name)
26+
elseif field_def.field_id == v.field_id and not
27+
(field_def.is_optional and v.value == nil) then
28+
elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name)
29+
if field_def.element_type ~= nil then
30+
for i, e in ipairs(elems[field_def.name].elements) do
31+
elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type)
32+
end
33+
end
34+
end
35+
end
36+
end
37+
base_type_obj.elements = elems
38+
end
39+
40+
function DatasetResponse:build_test_command_response(device, endpoint_id, dataset, interaction_status)
41+
local function init(self, device, endpoint_id, dataset)
42+
local out = {}
43+
local args = {dataset}
44+
if #args > #self.field_defs then
45+
error(self.NAME .. " received too many arguments")
46+
end
47+
for i,v in ipairs(self.field_defs) do
48+
if v.is_optional and args[i] == nil then
49+
out[v.name] = nil
50+
elseif v.is_nullable and args[i] == nil then
51+
out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name)
52+
out[v.name].field_id = v.field_id
53+
elseif not v.is_optional and args[i] == nil then
54+
out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name)
55+
out[v.name].field_id = v.field_id
56+
else
57+
out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name)
58+
out[v.name].field_id = v.field_id
59+
end
60+
end
61+
setmetatable(out, {
62+
__index = DatasetResponse,
63+
__tostring = DatasetResponse.pretty_print
64+
})
65+
return self._cluster:build_cluster_command(
66+
device,
67+
out,
68+
endpoint_id,
69+
self._cluster.ID,
70+
self.ID,
71+
false,
72+
true
73+
)
74+
end
75+
local self_request = init(self, device, endpoint_id, dataset)
76+
return self._cluster:build_test_command_response(
77+
device,
78+
endpoint_id,
79+
self._cluster.ID,
80+
self.ID,
81+
self_request.info_blocks[1].tlv,
82+
interaction_status
83+
)
84+
end
85+
86+
function DatasetResponse:init()
87+
return nil
88+
end
89+
90+
function DatasetResponse:set_parent_cluster(cluster)
91+
self._cluster = cluster
92+
return self
93+
end
94+
95+
function DatasetResponse:deserialize(tlv_buf)
96+
local data = TLVParser.decode_tlv(tlv_buf)
97+
self:augment_type(data)
98+
return data
99+
end
100+
101+
setmetatable(DatasetResponse, {__call = DatasetResponse.init})
102+
103+
return DatasetResponse
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
local command_mt = {}
2+
command_mt.__command_cache = {}
3+
command_mt.__index = function(self, key)
4+
if command_mt.__command_cache[key] == nil then
5+
local req_loc = string.format("ThreadBorderRouterManagement.client.commands.%s", key)
6+
local raw_def = require(req_loc)
7+
local cluster = rawget(self, "_cluster")
8+
command_mt.__command_cache[key] = raw_def:set_parent_cluster(cluster)
9+
end
10+
return command_mt.__command_cache[key]
11+
end
12+
13+
local ThreadBorderRouterManagementClientCommands = {}
14+
15+
function ThreadBorderRouterManagementClientCommands:set_parent_cluster(cluster)
16+
self._cluster = cluster
17+
return self
18+
end
19+
20+
setmetatable(ThreadBorderRouterManagementClientCommands, command_mt)
21+
22+
return ThreadBorderRouterManagementClientCommands
23+
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
local cluster_base = require "st.matter.cluster_base"
2+
local ThreadBorderRouterManagementServerAttributes = require "ThreadBorderRouterManagement.server.attributes"
3+
local ThreadBorderRouterManagementServerCommands = require "ThreadBorderRouterManagement.server.commands"
4+
local ThreadBorderRouterManagementClientCommands = require "ThreadBorderRouterManagement.client.commands"
5+
local ThreadBorderRouterManagementTypes = require "ThreadBorderRouterManagement.types"
6+
7+
local ThreadBorderRouterManagement = {}
8+
9+
ThreadBorderRouterManagement.ID = 0x0452
10+
ThreadBorderRouterManagement.NAME = "ThreadBorderRouterManagement"
11+
ThreadBorderRouterManagement.server = {}
12+
ThreadBorderRouterManagement.client = {}
13+
ThreadBorderRouterManagement.server.attributes = ThreadBorderRouterManagementServerAttributes:set_parent_cluster(ThreadBorderRouterManagement)
14+
ThreadBorderRouterManagement.server.commands = ThreadBorderRouterManagementServerCommands:set_parent_cluster(ThreadBorderRouterManagement)
15+
ThreadBorderRouterManagement.client.commands = ThreadBorderRouterManagementClientCommands:set_parent_cluster(ThreadBorderRouterManagement)
16+
ThreadBorderRouterManagement.types = ThreadBorderRouterManagementTypes
17+
18+
function ThreadBorderRouterManagement:get_attribute_by_id(attr_id)
19+
local attr_id_map = {
20+
[0x0000] = "BorderRouterName",
21+
[0x0001] = "BorderAgentID",
22+
[0x0002] = "ThreadVersion",
23+
[0x0003] = "InterfaceEnabled",
24+
[0x0004] = "ActiveDatasetTimestamp",
25+
[0x0005] = "PendingDatasetTimestamp",
26+
[0xFFF9] = "AcceptedCommandList",
27+
[0xFFFA] = "EventList",
28+
[0xFFFB] = "AttributeList",
29+
}
30+
local attr_name = attr_id_map[attr_id]
31+
if attr_name ~= nil then
32+
return self.attributes[attr_name]
33+
end
34+
return nil
35+
end
36+
37+
function ThreadBorderRouterManagement:get_server_command_by_id(command_id)
38+
local server_id_map = {
39+
[0x0000] = "GetActiveDatasetRequest",
40+
[0x0001] = "GetPendingDatasetRequest",
41+
[0x0003] = "SetActiveDatasetRequest",
42+
[0x0004] = "SetPendingDatasetRequest",
43+
}
44+
if server_id_map[command_id] ~= nil then
45+
return self.server.commands[server_id_map[command_id]]
46+
end
47+
return nil
48+
end
49+
50+
function ThreadBorderRouterManagement:get_client_command_by_id(command_id)
51+
local client_id_map = {
52+
[0x0002] = "DatasetResponse",
53+
}
54+
if client_id_map[command_id] ~= nil then
55+
return self.client.commands[client_id_map[command_id]]
56+
end
57+
return nil
58+
end
59+
60+
ThreadBorderRouterManagement.attribute_direction_map = {
61+
["BorderRouterName"] = "server",
62+
["BorderAgentID"] = "server",
63+
["ThreadVersion"] = "server",
64+
["InterfaceEnabled"] = "server",
65+
["ActiveDatasetTimestamp"] = "server",
66+
["PendingDatasetTimestamp"] = "server",
67+
["AcceptedCommandList"] = "server",
68+
["EventList"] = "server",
69+
["AttributeList"] = "server",
70+
}
71+
72+
do
73+
local has_aliases, aliases = pcall(require, "st.matter.clusters.aliases.ThreadBorderRouterManagement.server.attributes")
74+
if has_aliases then
75+
for alias, _ in pairs(aliases) do
76+
ThreadBorderRouterManagement.attribute_direction_map[alias] = "server"
77+
end
78+
end
79+
end
80+
81+
ThreadBorderRouterManagement.command_direction_map = {
82+
["GetActiveDatasetRequest"] = "server",
83+
["GetPendingDatasetRequest"] = "server",
84+
["SetActiveDatasetRequest"] = "server",
85+
["SetPendingDatasetRequest"] = "server",
86+
["DatasetResponse"] = "client",
87+
}
88+
89+
do
90+
local has_aliases, aliases = pcall(require, "st.matter.clusters.aliases.ThreadBorderRouterManagement.server.commands")
91+
if has_aliases then
92+
for alias, _ in pairs(aliases) do
93+
ThreadBorderRouterManagement.command_direction_map[alias] = "server"
94+
end
95+
end
96+
end
97+
98+
do
99+
local has_aliases, aliases = pcall(require, "st.matter.clusters.aliases.ThreadBorderRouterManagement.client.commands")
100+
if has_aliases then
101+
for alias, _ in pairs(aliases) do
102+
ThreadBorderRouterManagement.command_direction_map[alias] = "client"
103+
end
104+
end
105+
end
106+
107+
ThreadBorderRouterManagement.FeatureMap = ThreadBorderRouterManagement.types.Feature
108+
109+
function ThreadBorderRouterManagement.are_features_supported(feature, feature_map)
110+
if (ThreadBorderRouterManagement.FeatureMap.bits_are_valid(feature)) then
111+
return (feature & feature_map) == feature
112+
end
113+
return false
114+
end
115+
116+
local attribute_helper_mt = {}
117+
attribute_helper_mt.__index = function(self, key)
118+
local direction = ThreadBorderRouterManagement.attribute_direction_map[key]
119+
if direction == nil then
120+
error(string.format("Referenced unknown attribute %s on cluster %s", key, ThreadBorderRouterManagement.NAME))
121+
end
122+
return ThreadBorderRouterManagement[direction].attributes[key]
123+
end
124+
ThreadBorderRouterManagement.attributes = {}
125+
setmetatable(ThreadBorderRouterManagement.attributes, attribute_helper_mt)
126+
127+
local command_helper_mt = {}
128+
command_helper_mt.__index = function(self, key)
129+
local direction = ThreadBorderRouterManagement.command_direction_map[key]
130+
if direction == nil then
131+
error(string.format("Referenced unknown command %s on cluster %s", key, ThreadBorderRouterManagement.NAME))
132+
end
133+
return ThreadBorderRouterManagement[direction].commands[key]
134+
end
135+
ThreadBorderRouterManagement.commands = {}
136+
setmetatable(ThreadBorderRouterManagement.commands, command_helper_mt)
137+
138+
local event_helper_mt = {}
139+
event_helper_mt.__index = function(self, key)
140+
return ThreadBorderRouterManagement.server.events[key]
141+
end
142+
ThreadBorderRouterManagement.events = {}
143+
setmetatable(ThreadBorderRouterManagement.events, event_helper_mt)
144+
145+
setmetatable(ThreadBorderRouterManagement, {__index = cluster_base})
146+
147+
return ThreadBorderRouterManagement
148+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
local cluster_base = require "st.matter.cluster_base"
2+
local data_types = require "st.matter.data_types"
3+
local TLVParser = require "st.matter.TLV.TLVParser"
4+
5+
local ActiveDatasetTimestamp = {
6+
ID = 0x0004,
7+
NAME = "ActiveDatasetTimestamp",
8+
base_type = require "st.matter.data_types.Uint64",
9+
}
10+
11+
function ActiveDatasetTimestamp:new_value(...)
12+
local o = self.base_type(table.unpack({...}))
13+
14+
return o
15+
end
16+
17+
function ActiveDatasetTimestamp:read(device, endpoint_id)
18+
return cluster_base.read(
19+
device,
20+
endpoint_id,
21+
self._cluster.ID,
22+
self.ID,
23+
nil
24+
)
25+
end
26+
27+
function ActiveDatasetTimestamp:subscribe(device, endpoint_id)
28+
return cluster_base.subscribe(
29+
device,
30+
endpoint_id,
31+
self._cluster.ID,
32+
self.ID,
33+
nil
34+
)
35+
end
36+
37+
function ActiveDatasetTimestamp:set_parent_cluster(cluster)
38+
self._cluster = cluster
39+
return self
40+
end
41+
42+
function ActiveDatasetTimestamp:build_test_report_data(
43+
device,
44+
endpoint_id,
45+
value,
46+
status
47+
)
48+
local data = data_types.validate_or_build_type(value, self.base_type)
49+
50+
return cluster_base.build_test_report_data(
51+
device,
52+
endpoint_id,
53+
self._cluster.ID,
54+
self.ID,
55+
data,
56+
status
57+
)
58+
end
59+
60+
function ActiveDatasetTimestamp:deserialize(tlv_buf)
61+
local data = TLVParser.decode_tlv(tlv_buf)
62+
63+
return data
64+
end
65+
66+
setmetatable(ActiveDatasetTimestamp, {__call = ActiveDatasetTimestamp.new_value, __index = ActiveDatasetTimestamp.base_type})
67+
return ActiveDatasetTimestamp
68+

0 commit comments

Comments
 (0)