Skip to content

Commit

Permalink
Matter-sensor add support for mains powered sensors
Browse files Browse the repository at this point in the history
  • Loading branch information
ctowns committed Sep 26, 2023
1 parent fad8e69 commit e0e43ac
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 5 deletions.
6 changes: 3 additions & 3 deletions drivers/SmartThings/matter-sensor/fingerprints.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ matterManufacturer:
deviceLabel: Eve Motion
vendorId: 0x130a
productId: 0x0059
deviceProfileName: matter-motion-battery-illuminance
deviceProfileName: motion-illuminance-battery
- id: "Eve/DoorAndWindow"
deviceLabel: Eve Door and Window
vendorId: 0x130a
Expand Down Expand Up @@ -49,12 +49,12 @@ matterGeneric:
deviceTypes:
- id: 0x0107 # Occupancy Sensor
- id: 0x0106 # Light Sensor
deviceProfileName: matter-motion-battery-illuminance
deviceProfileName: motion-illuminance-battery
- id: "matter/motion-sensor"
deviceLabel: Matter Motion Sensor
deviceTypes:
- id: 0x0107 # Occupancy Sensor
deviceProfileName: matter-motion-battery
deviceProfileName: motion-battery
- id: "matter/motion-sensor/contact"
deviceLabel: Matter Motion/Contact Sensor
deviceTypes:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: matter-motion-battery
components:
- id: main
capabilities:
- id: motionSensor
version: 1
- id: battery
version: 1
- id: firmwareUpdate
version: 1
- id: refresh
version: 1
categories:
- name: MotionSensor
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: matter-motion-battery
name: motion-battery
components:
- id: main
capabilities:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: motion-illuminance-battery
components:
- id: main
capabilities:
- id: motionSensor
version: 1
- id: battery
version: 1
- id: illuminanceMeasurement
version: 1
- id: firmwareUpdate
version: 1
- id: refresh
version: 1
categories:
- name: MotionSensor
44 changes: 43 additions & 1 deletion drivers/SmartThings/matter-sensor/src/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,46 @@ local function device_init(driver, device)
device:subscribe()
end

local function do_configure(driver, device)
local battery_eps = device:get_endpoints(clusters.PowerSource.ID, {feature_bitmap = clusters.PowerSource.types.PowerSourceFeature.BATTERY})
local profile_name = ""

if device:supports_capability(capabilities.motionSensor) then
profile_name = profile_name .. "-motion"
end

if device:supports_capability(capabilities.contactSensor) then
profile_name = profile_name .. "-contact"
end

if device:supports_capability(capabilities.illuminanceMeasurement) then
profile_name = profile_name .. "-illuminance"
end

if device:supports_capability(capabilities.temperatureMeasurement) then
profile_name = profile_name .. "-temperature"
end

if device:supports_capability(capabilities.relativeHumidityMeasurement) then
profile_name = profile_name .. "-humidity"
end

if #battery_eps > 0 then
profile_name = profile_name .. "-battery"
end

-- remove leading "-"
profile_name = string.sub(profile_name, 2)

device:try_update_metadata({profile = profile_name})
end

local function info_changed(driver, device, event, args)
if device.profile.id ~= args.old_st_store.profile.id then
device:subscribe()
end
end

local function illuminance_attr_handler(driver, device, ib, response)
local lux = math.floor(10 ^ ((ib.data.value - 1) / 10000))
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.illuminanceMeasurement.illuminance(lux))
Expand Down Expand Up @@ -60,7 +100,9 @@ end

local matter_driver_template = {
lifecycle_handlers = {
init = device_init
init = device_init,
doConfigure = do_configure,
infoChanged = info_changed
},
matter_handlers = {
attr = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
-- Copyright 2023 SmartThings
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.

local test = require "integration_test"
local t_utils = require "integration_test.utils"
local clusters = require "st.matter.clusters"

local mock_device_humidity_battery = test.mock_device.build_test_matter_device({
profile = t_utils.get_profile_definition("humidity-battery.yml"),
manufacturer_info = {
vendor_id = 0x0000,
product_id = 0x0000,
},
endpoints = {
{
endpoint_id = 0,
clusters = {
{cluster_id = clusters.Basic.ID, cluster_type = "SERVER"},
},
device_types = {
device_type_id = 0x0016, device_type_revision = 1, -- RootNode
}
},
{
endpoint_id = 1,
clusters = {
{cluster_id = clusters.RelativeHumidityMeasurement.ID, cluster_type = "SERVER"},
}
},
{
endpoint_id = 2,
clusters = {
{cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER", feature_map = 2},
}
}
}
})

local mock_device_humidity_no_battery = test.mock_device.build_test_matter_device({
profile = t_utils.get_profile_definition("humidity-battery.yml"),
manufacturer_info = {
vendor_id = 0x0000,
product_id = 0x0000,
},
endpoints = {
{
endpoint_id = 0,
clusters = {
{cluster_id = clusters.Basic.ID, cluster_type = "SERVER"},
},
device_types = {
device_type_id = 0x0016, device_type_revision = 1, -- RootNode
}
},
{
endpoint_id = 1,
clusters = {
{cluster_id = clusters.RelativeHumidityMeasurement.ID, cluster_type = "SERVER"},
}
}
}
})

local mock_device_temp_humidity = test.mock_device.build_test_matter_device({
profile = t_utils.get_profile_definition("temperature-humidity.yml"),
manufacturer_info = {
vendor_id = 0x0000,
product_id = 0x0000,
},
endpoints = {
{
endpoint_id = 0,
clusters = {
{cluster_id = clusters.Basic.ID, cluster_type = "SERVER"},
},
device_types = {
device_type_id = 0x0016, device_type_revision = 1, -- RootNode
}
},
{
endpoint_id = 1,
clusters = {
{cluster_id = clusters.RelativeHumidityMeasurement.ID, cluster_type = "SERVER"},
}
},
{
endpoint_id = 2,
clusters = {
{cluster_id = clusters.TemperatureMeasurement.ID, cluster_type = "BOTH"},
}
}
}
})

local cluster_subscribe_list_humidity_battery = {
clusters.RelativeHumidityMeasurement.attributes.MeasuredValue,
clusters.PowerSource.attributes.BatPercentRemaining
}

local cluster_subscribe_list_humidity_no_battery = {
clusters.RelativeHumidityMeasurement.attributes.MeasuredValue
}

local cluster_subscribe_list_temp_humidity = {
clusters.RelativeHumidityMeasurement.attributes.MeasuredValue,
clusters.TemperatureMeasurement.attributes.MeasuredValue
}

local function test_init_humidity_battery()
local subscribe_request_humidity_battery = cluster_subscribe_list_humidity_battery[1]:subscribe(mock_device_humidity_battery)
for i, cluster in ipairs(cluster_subscribe_list_humidity_battery) do
if i > 1 then
subscribe_request_humidity_battery:merge(cluster:subscribe(mock_device_humidity_battery))
end
end

test.socket.matter:__expect_send({mock_device_humidity_battery.id, subscribe_request_humidity_battery})
test.mock_device.add_test_device(mock_device_humidity_battery)
end

local function test_init_humidity_no_battery()
local subscribe_request_humidity_no_battery = cluster_subscribe_list_humidity_no_battery[1]:subscribe(mock_device_humidity_no_battery)
for i, cluster in ipairs(cluster_subscribe_list_humidity_no_battery) do
if i > 1 then
subscribe_request_humidity_no_battery:merge(cluster:subscribe(mock_device_humidity_no_battery))
end
end

test.socket.matter:__expect_send({mock_device_humidity_no_battery.id, subscribe_request_humidity_no_battery})
test.mock_device.add_test_device(mock_device_humidity_no_battery)
end

local function test_init_temp_humidity()
local subscribe_request_temp_humidity = cluster_subscribe_list_temp_humidity[1]:subscribe(mock_device_temp_humidity)
for i, cluster in ipairs(cluster_subscribe_list_temp_humidity) do
if i > 1 then
subscribe_request_temp_humidity:merge(cluster:subscribe(mock_device_temp_humidity))
end
end

test.socket.matter:__expect_send({mock_device_temp_humidity.id, subscribe_request_temp_humidity})
test.mock_device.add_test_device(mock_device_temp_humidity)
end

test.register_coroutine_test(
"Profile remains the same for battery-supported devices on doConfigure lifecycle event due to cluster feature map",
function()
test.socket.device_lifecycle:__queue_receive({ mock_device_humidity_battery.id, "doConfigure" })
mock_device_humidity_battery:expect_metadata_update({ profile = "humidity-battery" })
mock_device_humidity_battery:expect_metadata_update({ provisioning_state = "PROVISIONED" })
end,
{ test_init = test_init_humidity_battery }
)

test.register_coroutine_test(
"Profile change to non-battery profile on doConfigure lifecycle event due to cluster feature map",
function()
test.socket.device_lifecycle:__queue_receive({ mock_device_humidity_no_battery.id, "doConfigure" })
mock_device_humidity_no_battery:expect_metadata_update({ profile = "humidity" })
mock_device_humidity_no_battery:expect_metadata_update({ provisioning_state = "PROVISIONED" })
end,
{ test_init = test_init_humidity_no_battery }
)

test.register_coroutine_test(
"Profile change to non-battery profile on doConfigure lifecycle event due to cluster feature map",
function()
test.socket.device_lifecycle:__queue_receive({ mock_device_temp_humidity.id, "doConfigure" })
mock_device_temp_humidity:expect_metadata_update({ profile = "temperature-humidity" })
mock_device_temp_humidity:expect_metadata_update({ provisioning_state = "PROVISIONED" })
end,
{ test_init = test_init_temp_humidity }
)

test.run_registered_tests()

0 comments on commit e0e43ac

Please sign in to comment.