Skip to content
Merged
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
30 changes: 30 additions & 0 deletions drivers/Aqara/aqara-lock/src/credential_utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,31 @@ local lockCredentialInfo = capabilities["stse.lockCredentialInfo"]

local credential_utils = {}
local HOST_COUNT = "__host_count"
local PERSIST_DATA = "__persist_area"

credential_utils.eventResource = function(table)
local credentialResource = {}
for key, value in pairs(table) do
credentialResource[key] = value
end
return credentialResource
end

credential_utils.backup_data = function(device) -- Back up data the persistent
local credentialInfoTable = utils.deep_copy(device:get_latest_state("main", lockCredentialInfo.ID,
lockCredentialInfo.credentialInfo.NAME, {}))
device:set_field(PERSIST_DATA, credentialInfoTable, { persist = true })
end

credential_utils.sync = function(driver, device)
local table = device:get_field(PERSIST_DATA) or nil
if table ~= nil then
device:emit_event(lockCredentialInfo.credentialInfo(credential_utils.eventResource(table),
{ visibility = { displayed = false } }))
else
credential_utils.backup_data(device)
end
end

credential_utils.save_data = function(driver)
driver.datastore:save()
Expand All @@ -28,6 +53,7 @@ credential_utils.update_remote_control_status = function(driver, device, added)
end

device:set_field(HOST_COUNT, host_cnt, { persist = true })
credential_utils.backup_data(device)
credential_utils.save_data(driver)
end

Expand All @@ -38,6 +64,7 @@ credential_utils.sync_all_credential_info = function(driver, device, command)
end
end
device:emit_event(lockCredentialInfo.credentialInfo(command.args.credentialInfo, { visibility = { displayed = false } }))
credential_utils.backup_data(device)
credential_utils.save_data(driver)
end

Expand Down Expand Up @@ -73,6 +100,7 @@ credential_utils.upsert_credential_info = function(driver, device, command)
end

device:emit_event(lockCredentialInfo.credentialInfo(credentialInfoTable, { visibility = { displayed = false } }))
credential_utils.backup_data(device)
credential_utils.save_data(driver)
end

Expand All @@ -95,6 +123,7 @@ credential_utils.delete_user = function(driver, device, command)
end

device:emit_event(lockCredentialInfo.credentialInfo(credentialInfoTable, { visibility = { displayed = false } }))
credential_utils.backup_data(device)
credential_utils.save_data(driver)
end

Expand All @@ -116,6 +145,7 @@ credential_utils.delete_credential = function(driver, device, command)
end

device:emit_event(lockCredentialInfo.credentialInfo(credentialInfoTable, { visibility = { displayed = false } }))
credential_utils.backup_data(device)
credential_utils.save_data(driver)
end

Expand Down
1 change: 1 addition & 0 deletions drivers/Aqara/aqara-lock/src/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ local function device_init(self, device)
end
device:emit_event(capabilities.battery.quantity(battery_quantity))
device:emit_event(capabilities.batteryLevel.quantity(battery_quantity))
credential_utils.sync(self, device)
end

local function device_added(self, device)
Expand Down
77 changes: 77 additions & 0 deletions drivers/Aqara/aqara-lock/src/test/test_aqara_lock_L100.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
local test = require "integration_test"
local t_utils = require "integration_test.utils"
local capabilities = require "st.capabilities"
local zigbee_test_utils = require "integration_test.zigbee_test_utils"

local remoteControlStatus = capabilities.remoteControlStatus
local antiLockStatus = capabilities["stse.antiLockStatus"]
test.add_package_capability("antiLockStatus.yaml")
local lockCredentialInfo = capabilities["stse.lockCredentialInfo"]
test.add_package_capability("lockCredentialInfo.yaml")
local lockAlarm = capabilities["lockAlarm"]
test.add_package_capability("lockAlarm.yaml")
local Battery = capabilities.battery
local BatteryLevel = capabilities.batteryLevel
local Lock = capabilities.lock

local PRI_CLU = 0xFCC0

local HOST_COUNT = "__host_count"
local PERSIST_DATA = "__persist_area"

local mock_device = test.mock_device.build_test_zigbee_device(
{
profile = t_utils.get_profile_definition("aqara-lock-battery.yml"),
fingerprinted_endpoint_id = 0x01,
zigbee_endpoints = {
[1] = {
id = 1,
manufacturer = "Lumi",
model = "aqara.lock.akr001",
server_clusters = { PRI_CLU }
}
}
}
)

zigbee_test_utils.prepare_zigbee_env_info()
local function test_init()
local SUPPORTED_ALARM_VALUES = { "damaged", "forcedOpeningAttempt", "unableToLockTheDoor", "notClosedForALongTime",
"highTemperature", "attemptsExceeded" }
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
lockAlarm.supportedAlarmValues(SUPPORTED_ALARM_VALUES, { visibility = { displayed = false } })))
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
Lock.supportedUnlockDirections({"fromInside", "fromOutside"}, { visibility = { displayed = false } })))
test.socket.capability:__expect_send(mock_device:generate_test_message("main", Battery.type("AA")))
test.socket.capability:__expect_send(mock_device:generate_test_message("main", BatteryLevel.type("AA")))
test.socket.capability:__expect_send(mock_device:generate_test_message("main", Battery.quantity(6)))
test.socket.capability:__expect_send(mock_device:generate_test_message("main", BatteryLevel.quantity(6)))
local credentialInfoData = {
{ credentialId = 1, credentialType = "keypad", userId = "1", userLabel = "june", userType = "host" }
}
mock_device:set_field(PERSIST_DATA, credentialInfoData, { persist = true })
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
lockCredentialInfo.credentialInfo(credentialInfoData, { visibility = { displayed = false } })))
test.mock_device.add_test_device(mock_device)
end
test.set_test_init_function(test_init)

test.register_coroutine_test(
"Handle added lifecycle - only regular user",
function()
mock_device:set_field(HOST_COUNT, 1, { persist = true })
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" })

test.socket.capability:__expect_send(mock_device:generate_test_message("main",
remoteControlStatus.remoteControlEnabled('true', { visibility = { displayed = false } })))
test.socket.capability:__expect_send(mock_device:generate_test_message("main", Battery.battery(100)))
test.socket.capability:__expect_send(mock_device:generate_test_message("main", BatteryLevel.battery("normal")))
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
lockAlarm.alarm.clear({ visibility = { displayed = false } })))
test.socket.capability:__expect_send(mock_device:generate_test_message("main",
antiLockStatus.antiLockStatus('unknown', { visibility = { displayed = false } })))
test.socket.capability:__expect_send(mock_device:generate_test_message("main", Lock.lock("locked")))
end
)

test.run_registered_tests()
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ deviceConfig:
- component: main
capability: battery
version: 1
- component: main
capability: refresh
version: 1
- component: button2
capability: button
version: 1
Expand Down
49 changes: 3 additions & 46 deletions drivers/SmartThings/matter-switch/profiles/ikea-scroll.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,49 +33,6 @@ components:
version: 1
categories:
- name: Button
deviceConfig:
icons:
- group: main
iconUrl: 'icon://button_wheel'
dashboard:
states:
- component: main
capability: button
version: 1
detailView:
- component: main
capability: button
version: 1
- component: main
capability: knob
version: 1
- component: main
capability: battery
version: 1
- component: group2
capability: button
version: 1
- component: group2
capability: knob
version: 1
- component: group3
capability: button
version: 1
- component: group3
capability: knob
version: 1
automation:
conditions:
- component: main
capability: button
version: 1
- component: main
capability: battery
version: 1
- component: group2
capability: button
version: 1
- component: group3
capability: button
version: 1
actions: []
metadata:
mnmn: SmartThingsEdge
vid: ikea-scroll
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,13 @@ zigbeeManufacturer:
manufacturer: HEIMAN
model: COSensor-EM
deviceProfileName: carbonMonoxide-battery
- id: "frient A/S/SCAZB-143"
deviceLabel: Frient Carbon Monoxide Detector
manufacturer: frient A/S
model: SCAZB-143
deviceProfileName: frient-smoke-co-temperature-battery
- id: "frient A/S/SCAZB-141"
deviceLabel: Frient Carbon Monoxide Detector
manufacturer: frient A/S
model: SCAZB-141
deviceProfileName: frient-smoke-co-temperature-battery
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: frient-smoke-co-temperature-battery
components:
- id: main
capabilities:
- id: smokeDetector
version: 1
- id: carbonMonoxideDetector
version: 1
- id: carbonMonoxideMeasurement
version: 1
- id: tamperAlert
version: 1
- id: temperatureMeasurement
version: 1
- id: battery
version: 1
- id: firmwareUpdate
version: 1
- id: refresh
version: 1
- id: alarm
version: 1
config:
values:
- key: "alarm.value"
enabledValues:
- off
- siren
- key: "{{enumCommands}}"
enabledValues:
- off
- siren
categories:
- name: SmokeDetector
preferences:
- title: "Max alarm duration (s)"
name: maxWarningDuration
description: "After how many seconds should the alarm turn off"
required: false
preferenceType: integer
definition:
minimum: 0
maximum: 65534
default: 240
- preferenceId: tempOffset
explicit: true
- title: "Temperature Sensitivity (°C)"
name: temperatureSensitivity
description: "Minimum change in temperature to report"
required: false
preferenceType: number
definition:
minimum: 0.1
maximum: 2.0
default: 1.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- Copyright 2026 SmartThings, Inc.
-- Licensed under the Apache License, Version 2.0

local is_frient_smoke_carbon_monoxide = function(opts, driver, device)
local FINGERPRINTS = require("frient.fingerprints")
for _, fingerprint in ipairs(FINGERPRINTS) do
if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then
return true, require("frient")
end
end

return false
end

return is_frient_smoke_carbon_monoxide
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- Copyright 2026 SmartThings, Inc.
-- Licensed under the Apache License, Version 2.0

local FRIENT_SMOKE_CARBON_MONOXIDE_FINGERPRINTS = {
{ mfr = "frient A/S", model = "SCAZB-141" },
{ mfr = "frient A/S", model = "SCAZB-143" }
}

return FRIENT_SMOKE_CARBON_MONOXIDE_FINGERPRINTS
Loading
Loading