Skip to content

Commit cc34662

Browse files
Merge branch 'main' into matter-switch-support-fan-light
2 parents 7715580 + 6c8b8d5 commit cc34662

File tree

66 files changed

+375
-413
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+375
-413
lines changed

drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua

+6
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,15 @@ local NEW_MATTER_LOCK_PRODUCTS = {
3333
{0x115f, 0x2802}, -- AQARA, U200
3434
{0x115f, 0x2801}, -- AQARA, U300
3535
{0x147F, 0x0001}, -- U-tec
36+
{0x144F, 0x4002}, -- Yale, Linus Smart Lock L2
3637
{0x1533, 0x0001}, -- eufy, E31
3738
{0x1533, 0x0002}, -- eufy, E30
3839
{0x1533, 0x0003}, -- eufy, C34
40+
{0x135D, 0x00B1}, -- Nuki, Smart Lock Pro
41+
{0x135D, 0x00B2}, -- Nuki, Smart Lock
42+
{0x135D, 0x00C1}, -- Nuki, Smart Lock
43+
{0x135D, 0x00A1}, -- Nuki, Smart Lock
44+
{0x135D, 0x00B0}, -- Nuki, Smart Lock
3945
{0x10E1, 0x2002} -- VDA
4046
}
4147

drivers/SmartThings/matter-sensor/fingerprints.yml

+5
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,8 @@ matterGeneric:
230230
deviceTypes:
231231
- id: 0x0043
232232
deviceProfileName: leak-battery
233+
- id: "matter/flow/sensor"
234+
deviceLabel: Matter Flow Sensor
235+
deviceTypes:
236+
- id: 0x0306
237+
deviceProfileName: flow-battery
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: flow-battery
2+
components:
3+
- id: main
4+
capabilities:
5+
- id: flowMeasurement
6+
version: 1
7+
- id: battery
8+
version: 1
9+
- id: firmwareUpdate
10+
version: 1
11+
- id: refresh
12+
version: 1
13+
categories:
14+
- name: FlowSensor
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: flow-batteryLevel
2+
components:
3+
- id: main
4+
capabilities:
5+
- id: flowMeasurement
6+
version: 1
7+
- id: batteryLevel
8+
version: 1
9+
- id: firmwareUpdate
10+
version: 1
11+
- id: refresh
12+
version: 1
13+
categories:
14+
- name: FlowSensor
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: flow
2+
components:
3+
- id: main
4+
capabilities:
5+
- id: flowMeasurement
6+
version: 1
7+
- id: firmwareUpdate
8+
version: 1
9+
- id: refresh
10+
version: 1
11+
categories:
12+
- name: FlowSensor

drivers/SmartThings/matter-sensor/src/init.lua

+51-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- Copyright 2022 SmartThings
1+
-- Copyright 2025 SmartThings
22
--
33
-- Licensed under the Apache License, Version 2.0 (the "License");
44
-- you may not use this file except in compliance with the License.
@@ -51,6 +51,9 @@ end
5151
local TEMP_BOUND_RECEIVED = "__temp_bound_received"
5252
local TEMP_MIN = "__temp_min"
5353
local TEMP_MAX = "__temp_max"
54+
local FLOW_BOUND_RECEIVED = "__flow_bound_received"
55+
local FLOW_MIN = "__flow_min"
56+
local FLOW_MAX = "__flow_max"
5457

5558
local battery_support = {
5659
NO_BATTERY = "NO_BATTERY",
@@ -148,6 +151,10 @@ local function match_profile(driver, device, battery_supported)
148151
profile_name = profile_name .. "-leak"
149152
end
150153

154+
if device:supports_capability(capabilities.flowMeasurement) then
155+
profile_name = profile_name .. "-flow"
156+
end
157+
151158
if battery_supported == battery_support.BATTERY_PERCENTAGE then
152159
profile_name = profile_name .. "-battery"
153160
elseif battery_supported == battery_support.BATTERY_LEVEL then
@@ -356,6 +363,37 @@ local function pressure_attr_handler(driver, device, ib, response)
356363
end
357364
end
358365

366+
local function flow_attr_handler(driver, device, ib, response)
367+
local measured_value = ib.data.value
368+
if measured_value ~= nil then
369+
local flow = measured_value / 10.0
370+
local unit = "m^3/h"
371+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.flowMeasurement.flow({value = flow, unit = unit}))
372+
end
373+
end
374+
375+
local flow_attr_handler_factory = function(minOrMax)
376+
return function(driver, device, ib, response)
377+
if ib.data.value == nil then
378+
return
379+
end
380+
local flow_bound = ib.data.value / 10.0
381+
local unit = "m^3/h"
382+
set_field_for_endpoint(device, FLOW_BOUND_RECEIVED..minOrMax, ib.endpoint_id, flow_bound)
383+
local min = get_field_for_endpoint(device, FLOW_BOUND_RECEIVED..FLOW_MIN, ib.endpoint_id)
384+
local max = get_field_for_endpoint(device, FLOW_BOUND_RECEIVED..FLOW_MAX, ib.endpoint_id)
385+
if min ~= nil and max ~= nil then
386+
if min < max then
387+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.flowMeasurement.flowRange({ value = { minimum = min, maximum = max }, unit = unit }))
388+
set_field_for_endpoint(device, FLOW_BOUND_RECEIVED..FLOW_MIN, ib.endpoint_id, nil)
389+
set_field_for_endpoint(device, FLOW_BOUND_RECEIVED..FLOW_MAX, ib.endpoint_id, nil)
390+
else
391+
device.log.warn_with({hub_logs = true}, string.format("Device reported a min flow measurement %d that is not lower than the reported max flow measurement %d", min, max))
392+
end
393+
end
394+
end
395+
end
396+
359397
local matter_driver_template = {
360398
lifecycle_handlers = {
361399
init = device_init,
@@ -395,6 +433,11 @@ local matter_driver_template = {
395433
},
396434
[clusters.Thermostat.ID] = {
397435
[clusters.Thermostat.attributes.LocalTemperature.ID] = temperature_attr_handler
436+
},
437+
[clusters.FlowMeasurement.ID] = {
438+
[clusters.FlowMeasurement.attributes.MeasuredValue.ID] = flow_attr_handler,
439+
[clusters.FlowMeasurement.attributes.MinMeasuredValue.ID] = flow_attr_handler_factory(FLOW_MIN),
440+
[clusters.FlowMeasurement.attributes.MaxMeasuredValue.ID] = flow_attr_handler_factory(FLOW_MAX)
398441
}
399442
}
400443
},
@@ -525,6 +568,11 @@ local matter_driver_template = {
525568
[capabilities.rainSensor.ID] = {
526569
clusters.BooleanState.attributes.StateValue,
527570
},
571+
[capabilities.flowMeasurement.ID] = {
572+
clusters.FlowMeasurement.attributes.MeasuredValue,
573+
clusters.FlowMeasurement.attributes.MinMeasuredValue,
574+
clusters.FlowMeasurement.attributes.MaxMeasuredValue
575+
},
528576
},
529577
capability_handlers = {
530578
},
@@ -540,7 +588,8 @@ local matter_driver_template = {
540588
capabilities.waterSensor,
541589
capabilities.temperatureAlarm,
542590
capabilities.rainSensor,
543-
capabilities.hardwareFault
591+
capabilities.hardwareFault,
592+
capabilities.flowMeasurement
544593
},
545594
sub_drivers = {
546595
require("air-quality-sensor"),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
-- Copyright 2025 SmartThings
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
local test = require "integration_test"
16+
local capabilities = require "st.capabilities"
17+
18+
local t_utils = require "integration_test.utils"
19+
local clusters = require "st.matter.clusters"
20+
21+
local mock_device= test.mock_device.build_test_matter_device({
22+
profile = t_utils.get_profile_definition("flow.yml"),
23+
manufacturer_info = {
24+
vendor_id = 0x0000,
25+
product_id = 0x0000,
26+
},
27+
endpoints = {
28+
{
29+
endpoint_id = 0,
30+
clusters = {
31+
{cluster_id = clusters.Basic.ID, cluster_type = "SERVER"},
32+
},
33+
device_types = {
34+
{device_type_id = 0x0016, device_type_revision = 1} -- RootNode
35+
}
36+
},
37+
{
38+
endpoint_id = 1,
39+
clusters = {
40+
{cluster_id = clusters.FlowMeasurement.ID, cluster_type = "SERVER"},
41+
},
42+
device_types = {
43+
{device_type_id = 0x0306, device_type_revision = 1} -- Flow Sensor
44+
}
45+
}
46+
}
47+
})
48+
49+
local subscribed_attributes = {
50+
clusters.FlowMeasurement.attributes.MeasuredValue,
51+
clusters.FlowMeasurement.attributes.MinMeasuredValue,
52+
clusters.FlowMeasurement.attributes.MaxMeasuredValue
53+
}
54+
55+
local function test_init()
56+
local subscribe_request = subscribed_attributes[1]:subscribe(mock_device)
57+
for i, cluster in ipairs(subscribed_attributes) do
58+
if i > 1 then
59+
subscribe_request:merge(cluster:subscribe(mock_device))
60+
end
61+
end
62+
test.socket.matter:__expect_send({mock_device.id, subscribe_request})
63+
test.mock_device.add_test_device(mock_device)
64+
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" })
65+
end
66+
test.set_test_init_function(test_init)
67+
68+
test.register_message_test(
69+
"Flow reports should generate correct messages",
70+
{
71+
{
72+
channel = "matter",
73+
direction = "receive",
74+
message = {
75+
mock_device.id,
76+
clusters.FlowMeasurement.server.attributes.MeasuredValue:build_test_report_data(mock_device, 1, 20*10)
77+
}
78+
},
79+
{
80+
channel = "capability",
81+
direction = "send",
82+
message = mock_device:generate_test_message("main", capabilities.flowMeasurement.flow({ value = 20.0, unit = "m^3/h" }))
83+
}
84+
}
85+
)
86+
87+
test.register_message_test(
88+
"Min and max flow attributes set capability constraint",
89+
{
90+
{
91+
channel = "matter",
92+
direction = "receive",
93+
message = {
94+
mock_device.id,
95+
clusters.FlowMeasurement.attributes.MinMeasuredValue:build_test_report_data(mock_device, 1, 20)
96+
}
97+
},
98+
{
99+
channel = "matter",
100+
direction = "receive",
101+
message = {
102+
mock_device.id,
103+
clusters.FlowMeasurement.attributes.MaxMeasuredValue:build_test_report_data(mock_device, 1, 5000)
104+
}
105+
},
106+
{
107+
channel = "capability",
108+
direction = "send",
109+
message = mock_device:generate_test_message("main", capabilities.flowMeasurement.flowRange({ value = { minimum = 2.0, maximum = 500.0 }, unit = "m^3/h" }))
110+
}
111+
}
112+
)
113+
114+
local function refresh_commands(dev)
115+
local req = clusters.FlowMeasurement.attributes.MeasuredValue:read(dev)
116+
req:merge(clusters.FlowMeasurement.attributes.MinMeasuredValue:read(dev))
117+
req:merge(clusters.FlowMeasurement.attributes.MaxMeasuredValue:read(dev))
118+
return req
119+
end
120+
121+
test.register_message_test(
122+
"Handle received refresh.",
123+
{
124+
{
125+
channel = "capability",
126+
direction = "receive",
127+
message = {
128+
mock_device.id,
129+
{ capability = "refresh", component = "main", command = "refresh", args = { } }
130+
}
131+
},
132+
{
133+
channel = "matter",
134+
direction = "send",
135+
message = {
136+
mock_device.id,
137+
refresh_commands(mock_device)
138+
}
139+
},
140+
}
141+
)
142+
143+
test.run_registered_tests()

drivers/SmartThings/matter-switch/fingerprints.yml

+5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ matterManufacturer:
2020
vendorId: 0x115F
2121
productId: 0x1806
2222
deviceProfileName: light-level-colorTemperature-2700K-6500K
23+
- id: "4447/8196"
24+
deviceLabel: Climate Sensor W100
25+
vendorId: 0x115F
26+
productId: 0x2004
27+
deviceProfileName: 3-button-battery-temperature-humidity
2328
#AiDot
2429
- id: "Linkind/Smart/Light/Bulb/A19/RGBTW"
2530
deviceLabel: Linkind Smart Light Bulb A19 RGBTW

drivers/SmartThings/matter-switch/src/test/test_matter_light_fan.lua

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
-- Copyright 2025 SmartThings
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
115
local capabilities = require "st.capabilities"
216
local clusters = require "st.matter.generated.zap_clusters"
317
local t_utils = require "integration_test.utils"

drivers/SmartThings/matter-thermostat/profiles/air-purifier-hepa-ac-rock-wind-thermostat-humidity-fan-heating-only-nostate-nobattery-aqs-pm10-pm25-ch2o-meas-pm10-pm25-ch2o-no2-tvoc-level.yml

-5
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,6 @@ components:
4949
version: 1
5050
categories:
5151
- name: AirPurifier
52-
preferences:
53-
- preferenceId: tempOffset
54-
explicit: true
55-
- preferenceId: humidityOffset
56-
explicit: true
5752
- id: hepaFilter
5853
label: Hepa Filter
5954
capabilities:

drivers/SmartThings/matter-thermostat/profiles/room-air-conditioner-fan-heating-cooling-nostate.yml

-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,3 @@ components:
2222
version: 1
2323
categories:
2424
- name: AirConditioner
25-
preferences:
26-
- preferenceId: tempOffset
27-
explicit: true

drivers/SmartThings/matter-thermostat/profiles/room-air-conditioner-fan-heating-cooling.yml

-3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,3 @@ components:
3131
version: 1
3232
categories:
3333
- name: AirConditioner
34-
preferences:
35-
- preferenceId: tempOffset
36-
explicit: true

drivers/SmartThings/matter-thermostat/profiles/room-air-conditioner-fan-wind-heating-cooling.yml

-3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,3 @@ components:
3333
version: 1
3434
categories:
3535
- name: AirConditioner
36-
preferences:
37-
- preferenceId: tempOffset
38-
explicit: true

drivers/SmartThings/matter-thermostat/profiles/room-air-conditioner-heating-cooling.yml

-3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,3 @@ components:
2727
version: 1
2828
categories:
2929
- name: AirConditioner
30-
preferences:
31-
- preferenceId: tempOffset
32-
explicit: true

drivers/SmartThings/matter-thermostat/profiles/room-air-conditioner-humidity-fan-heating-cooling.yml

-5
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,3 @@ components:
3333
version: 1
3434
categories:
3535
- name: AirConditioner
36-
preferences:
37-
- preferenceId: tempOffset
38-
explicit: true
39-
- preferenceId: humidityOffset
40-
explicit: true

0 commit comments

Comments
 (0)