Skip to content

Commit

Permalink
Tuya gas sensor support
Browse files Browse the repository at this point in the history
  • Loading branch information
pInksenberg committed Oct 28, 2024
1 parent 3fdc6c3 commit ef43e0a
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 0 deletions.
6 changes: 6 additions & 0 deletions drivers/SmartThings/matter-sensor/fingerprints.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ matterManufacturer:
vendorId: 0x142B
productId: 0x0002
deviceProfileName: motion-illuminance-temperature-humidity
# Tuya
- id: "4701/49"
deviceLabel: Tuya Gas Sensor
vendorId: 0x125D
productId: 0x0031
deviceProfileName: tuya-gas
matterGeneric:
- id: "matter/contact/sensor"
deviceLabel: Matter Contact Sensor
Expand Down
12 changes: 12 additions & 0 deletions drivers/SmartThings/matter-sensor/profiles/tuya-gas.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: tuya-gas
components:
- id: main
capabilities:
- id: gasDetector
version: 1
- id: firmwareUpdate
version: 1
- id: refresh
version: 1
categories:
- name: SmokeDetector
3 changes: 3 additions & 0 deletions drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ local matter_smoke_co_alarm_handler = {
clusters.SmokeCoAlarm.attributes.BatteryAlert,
}
},
sub_drivers = {
require("tuya-smoke-co-alarm")
},
can_handle = is_matter_smoke_co_alarm
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
-- Copyright 2024 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 capabilities = require "st.capabilities"
local t_utils = require "integration_test.utils"
local SinglePrecisionFloat = require "st.matter.data_types.SinglePrecisionFloat"

local clusters = require "st.matter.clusters"
clusters.SmokeCoAlarm = require "SmokeCoAlarm"
local version = require "version"
if version.api < 10 then
clusters.SmokeCoAlarm = require "SmokeCoAlarm"
clusters.CarbonMonoxideConcentrationMeasurement = require "CarbonMonoxideConcentrationMeasurement"
end

local mock_device = test.mock_device.build_test_matter_device({
profile = t_utils.get_profile_definition("tuya-gas.yml"),
manufacturer_info = {
vendor_id = 0x125D,
product_id = 0x0031,
},
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.SmokeCoAlarm.ID, cluster_type = "SERVER", feature_map = clusters.SmokeCoAlarm.types.Feature.CO_ALARM | clusters.SmokeCoAlarm.types.Feature.SMOKE_ALARM},
},
device_types = {
{device_type_id = 0x0076, device_type_revision = 1} -- Smoke CO Alarm
}
}
}
})

local cluster_subscribe_list = {
clusters.SmokeCoAlarm.attributes.COState,
}

local function test_init()
local subscribe_request = cluster_subscribe_list[1]:subscribe(mock_device)
for i, cluster in ipairs(cluster_subscribe_list) do
if i > 1 then
subscribe_request:merge(cluster:subscribe(mock_device))
end
end
test.socket.matter:__expect_send({mock_device.id, subscribe_request})
test.mock_device.add_test_device(mock_device)
mock_device:expect_metadata_update({ profile = "tuya-gas.yml" })
end

test.set_test_init_function(test_init)

test.register_message_test(
"Test CO state handler",
{
{
channel = "matter",
direction = "receive",
message = {
mock_device.id,
clusters.SmokeCoAlarm.attributes.COState:build_test_report_data(mock_device, 1, clusters.SmokeCoAlarm.attributes.COState.NORMAL)
}
},
{
channel = "capability",
direction = "send",
message = mock_device:generate_test_message("main", capabilities.gasDetector.gas.clear())
},
{
channel = "matter",
direction = "receive",
message = {
mock_device.id,
clusters.SmokeCoAlarm.attributes.COState:build_test_report_data(mock_device, 1, clusters.SmokeCoAlarm.attributes.COState.WARNING)
}
},
{
channel = "capability",
direction = "send",
message = mock_device:generate_test_message("main", capabilities.gasDetector.gas.detected())
},
{
channel = "matter",
direction = "receive",
message = {
mock_device.id,
clusters.SmokeCoAlarm.attributes.COState:build_test_report_data(mock_device, 1, clusters.SmokeCoAlarm.attributes.COState.CRITICAL)
}
},
{
channel = "capability",
direction = "send",
message = mock_device:generate_test_message("main", capabilities.gasDetector.gas.detected())
}
}
)

test.run_registered_tests()
82 changes: 82 additions & 0 deletions drivers/SmartThings/matter-sensor/src/tuya-smoke-co-alarm/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
-- Copyright 2024 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 capabilities = require "st.capabilities"
local clusters = require "st.matter.clusters"
local cluster_base = require "st.matter.cluster_base"

local SMOKE_CO_ALARM_DEVICE_TYPE_ID = 0x0076
local TUYA_CO_MANUFACTURER_ID = 0x125D

local version = require "version"

if version.api < 10 then
clusters.SmokeCoAlarm = require "SmokeCoAlarm"
end

local function is_tuya_smoke_co_alarm(opts, driver, device)
for _, ep in ipairs(device.endpoints) do
for _, dt in ipairs(ep.device_types) do
if dt.device_type_id == SMOKE_CO_ALARM_DEVICE_TYPE_ID and device.manufacturer_info.vendor_id == TUYA_CO_MANUFACTURER_ID then
return true
end
end
end
return false
end


local function device_init(driver, device, ib)
device:send(
cluster_base.subscribe(device, ib.endpoint_id, clusters.SmokeCoAlarm.ID, clusters.SmokeCoAlarm.attributes.COState.ID, nil)
)
-- device:subscribe()
end

local function info_changed(self, device, event, args)
-- resubscribe to new attributes as needed if a profile switch occured
if device.profile.id ~= args.old_st_store.profile.id then
device:subscribe()
end
end

-- Matter Handlers --
local function binary_state_handler_factory(zeroEvent, nonZeroEvent)
return function(driver, device, ib, response)
if ib.data.value == 0 and zeroEvent ~= nil then
device:emit_event_for_endpoint(ib.endpoint_id, zeroEvent)
elseif nonZeroEvent ~= nil then
device:emit_event_for_endpoint(ib.endpoint_id, nonZeroEvent)
end
end
end

local matter_tuya_smoke_co_alarm_handler = {
NAME = "matter-tyua-smoke-co-alarm",
lifecycle_handlers = {
-- added = device_added,
init = device_init,
infoChanged = info_changed
},
matter_handlers = {
attr = {
[clusters.SmokeCoAlarm.ID] = {
[clusters.SmokeCoAlarm.attributes.COState.ID] = binary_state_handler_factory(capabilities.gasDetector.gas.clear(), capabilities.gasDetector.gas.detected()),
}
},
},
can_handle = is_tuya_smoke_co_alarm
}

return matter_tuya_smoke_co_alarm_handler

0 comments on commit ef43e0a

Please sign in to comment.