From 06dfee3c703c738071f23a83ec3a73bc3b59ea27 Mon Sep 17 00:00:00 2001 From: zmguko <160391709+zmguko@users.noreply.github.com> Date: Fri, 10 Apr 2026 22:28:16 +0800 Subject: [PATCH 01/29] WWSTCERT-10696 - add new zigbee-humididt-sensor SNZB-02DR2 (#2573) * add new zigbee-humididt-sensor SNZB-02DR2 --- drivers/SmartThings/zigbee-humidity-sensor/fingerprints.yml | 5 +++++ .../zigbee-humidity-sensor/src/configurations.lua | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/SmartThings/zigbee-humidity-sensor/fingerprints.yml b/drivers/SmartThings/zigbee-humidity-sensor/fingerprints.yml index e5ad9e571a..d897ca7ecf 100644 --- a/drivers/SmartThings/zigbee-humidity-sensor/fingerprints.yml +++ b/drivers/SmartThings/zigbee-humidity-sensor/fingerprints.yml @@ -83,6 +83,11 @@ zigbeeManufacturer: manufacturer: eWeLink model: SNZB-02P deviceProfileName: humidity-temp-battery + - id: "SONOFF/SNZB-02DR2" + deviceLabel: "SONOFF SNZB-02DR2" + manufacturer: SONOFF + model: SNZB-02DR2 + deviceProfileName: humidity-temp-battery - id: "Third Reality/3RTHS24BZ" deviceLabel: ThirdReality Temperature and Humidity Sensor manufacturer: Third Reality, Inc diff --git a/drivers/SmartThings/zigbee-humidity-sensor/src/configurations.lua b/drivers/SmartThings/zigbee-humidity-sensor/src/configurations.lua index 8bc35c8765..043359768f 100644 --- a/drivers/SmartThings/zigbee-humidity-sensor/src/configurations.lua +++ b/drivers/SmartThings/zigbee-humidity-sensor/src/configurations.lua @@ -56,7 +56,8 @@ local devices = { EWELINK_HUMIDITY_TEMP_SENSOR = { FINGERPRINTS = { { mfr = "eWeLink", model = "TH01" }, - { mfr = "eWeLink", model = "SNZB-02P" } + { mfr = "eWeLink", model = "SNZB-02P" }, + { mfr = "SONOFF", model = "SNZB-02DR2" } }, CONFIGURATION = { { From 5f33fa11460de86685a18642e5c3021c0da887b8 Mon Sep 17 00:00:00 2001 From: JerryYang01 <40193349+JerryYang01@users.noreply.github.com> Date: Fri, 10 Apr 2026 04:37:55 +0800 Subject: [PATCH 02/29] Fix pad19 fingerprint (#2878) * Add fingerprint for PAD19 dimmer * Add fingerprint for PAD19 dimmer * Add fingerprint for PAD19 dimmer --- drivers/SmartThings/zwave-switch/fingerprints.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/SmartThings/zwave-switch/fingerprints.yml b/drivers/SmartThings/zwave-switch/fingerprints.yml index 46faa7d106..ccd11184d5 100644 --- a/drivers/SmartThings/zwave-switch/fingerprints.yml +++ b/drivers/SmartThings/zwave-switch/fingerprints.yml @@ -916,6 +916,12 @@ zwaveManufacturer: manufacturerId: 0x010F productType: 0x0102 deviceProfileName: fibaro-dimmer-2 + - id: 013C/0005/008A + deviceLabel: Philio Dimmer Switch PAD19 + manufacturerId: 0x013C + productType: 0x0005 + productId: 0x008A + deviceProfileName: switch-level #Zooz - id: "Zooz/ZEN05" deviceLabel: Zooz Outdoor Plug ZEN05 From 298ecc6c5c8c1619d34ef464fca4ae6ed180bbed Mon Sep 17 00:00:00 2001 From: Harrison Carter <137556605+hcarter-775@users.noreply.github.com> Date: Fri, 3 Apr 2026 11:52:13 -0500 Subject: [PATCH 03/29] Sonos: Remove Hardcoded Ports (#2855) --- drivers/SmartThings/sonos/src/api/sonos_connection.lua | 6 ++++-- .../SmartThings/sonos/src/api/sonos_ssdp_discovery.lua | 9 ++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/SmartThings/sonos/src/api/sonos_connection.lua b/drivers/SmartThings/sonos/src/api/sonos_connection.lua index 471c3a04fb..6a131c3b0c 100644 --- a/drivers/SmartThings/sonos/src/api/sonos_connection.lua +++ b/drivers/SmartThings/sonos/src/api/sonos_connection.lua @@ -487,9 +487,11 @@ function SonosConnection.new(driver, device) return end - local url_ip = lb_utils.force_url_table(coordinator_player.player.websocket_url).host + local url_table = lb_utils.force_url_table(coordinator_player.player.websocket_url) + local url_ip = url_table.host + local url_port = url_table.port or SonosApi.DEFAULT_SONOS_PORT local base_url = lb_utils.force_url_table( - string.format("https://%s:%s", url_ip, SonosApi.DEFAULT_SONOS_PORT) + string.format("https://%s:%s", url_ip, url_port) ) local _, api_key = driver:check_auth(device) local maybe_token = driver:get_oauth_token() diff --git a/drivers/SmartThings/sonos/src/api/sonos_ssdp_discovery.lua b/drivers/SmartThings/sonos/src/api/sonos_ssdp_discovery.lua index ddc1d0842d..21cbdcd62c 100644 --- a/drivers/SmartThings/sonos/src/api/sonos_ssdp_discovery.lua +++ b/drivers/SmartThings/sonos/src/api/sonos_ssdp_discovery.lua @@ -421,12 +421,11 @@ function sonos_ssdp.spawn_persistent_ssdp_task() if is_new_information then local headers = SonosApi.make_headers() - local discovery_info, err = SonosApi.RestApi.get_player_info( - net_url.parse( - string.format("https://%s:%s", sonos_ssdp_info.ip, SonosApi.DEFAULT_SONOS_PORT) - ), - headers + local parsed_wss_url = net_url.parse(sonos_ssdp_info.wss_url) or {} + local base_url = net_url.parse( + string.format("https://%s:%s", parsed_wss_url.host, parsed_wss_url.port or SonosApi.DEFAULT_SONOS_PORT) ) + local discovery_info, err = SonosApi.RestApi.get_player_info(base_url, headers) if not discovery_info then log.error(string.format("Error getting discovery info from SSDP response: %s", err)) elseif discovery_info._objectType == "globalError" then From 14c5216c96125d74452a2b58a93443cea448dd3e Mon Sep 17 00:00:00 2001 From: haedo-doo Date: Wed, 8 Apr 2026 06:52:56 +0900 Subject: [PATCH 04/29] Aqara Wireless Knob Switch H1 (#2844) * add Aqara Wireless Knob Switch H1 * fix copyright year * refactor and add rotation test cases * fix indentation and address review comments * fix whitespace warnings --- .../zigbee-button/fingerprints.yml | 5 + .../profiles/aqara-knob-switch.yml | 19 ++ .../src/aqara-knob/can_handle.lua | 13 + .../zigbee-button/src/aqara-knob/init.lua | 141 +++++++++ .../zigbee-button/src/sub_drivers.lua | 1 + .../src/test/test_aqara_knob_switch.lua | 287 ++++++++++++++++++ 6 files changed, 466 insertions(+) create mode 100644 drivers/SmartThings/zigbee-button/profiles/aqara-knob-switch.yml create mode 100644 drivers/SmartThings/zigbee-button/src/aqara-knob/can_handle.lua create mode 100644 drivers/SmartThings/zigbee-button/src/aqara-knob/init.lua create mode 100644 drivers/SmartThings/zigbee-button/src/test/test_aqara_knob_switch.lua diff --git a/drivers/SmartThings/zigbee-button/fingerprints.yml b/drivers/SmartThings/zigbee-button/fingerprints.yml index c73109ebca..f256e0584c 100644 --- a/drivers/SmartThings/zigbee-button/fingerprints.yml +++ b/drivers/SmartThings/zigbee-button/fingerprints.yml @@ -34,6 +34,11 @@ zigbeeManufacturer: manufacturer: LUMI model: lumi.remote.b28ac1 deviceProfileName: aqara-double-buttons-mode + - id: "lumi/lumi.remote.rkba01" + deviceLabel: "Aqara Wireless Smart Knob H1" + manufacturer: LUMI + model: lumi.remote.rkba01 + deviceProfileName: aqara-knob-switch - id: "HEIMAN/SOS-EM" deviceLabel: HEIMAN Button manufacturer: HEIMAN diff --git a/drivers/SmartThings/zigbee-button/profiles/aqara-knob-switch.yml b/drivers/SmartThings/zigbee-button/profiles/aqara-knob-switch.yml new file mode 100644 index 0000000000..1c197504bb --- /dev/null +++ b/drivers/SmartThings/zigbee-button/profiles/aqara-knob-switch.yml @@ -0,0 +1,19 @@ +name: aqara-knob-switch +components: + - id: main + capabilities: + - id: button + version: 1 + - id: knob + version: 1 + - id: batteryLevel + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: Button +preferences: + - preferenceId: stse.knobSensitivity + explicit: true diff --git a/drivers/SmartThings/zigbee-button/src/aqara-knob/can_handle.lua b/drivers/SmartThings/zigbee-button/src/aqara-knob/can_handle.lua new file mode 100644 index 0000000000..a5a48f6cb9 --- /dev/null +++ b/drivers/SmartThings/zigbee-button/src/aqara-knob/can_handle.lua @@ -0,0 +1,13 @@ +-- Copyright 2026 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local is_aqara_products = function(opts, driver, device, ...) + local FINGERPRINTS = { mfr = "LUMI", model = "lumi.remote.rkba01" } + + if device:get_manufacturer() == FINGERPRINTS.mfr and device:get_model() == FINGERPRINTS.model then + return true, require("aqara-knob") + end + return false +end + +return is_aqara_products diff --git a/drivers/SmartThings/zigbee-button/src/aqara-knob/init.lua b/drivers/SmartThings/zigbee-button/src/aqara-knob/init.lua new file mode 100644 index 0000000000..3b979baa24 --- /dev/null +++ b/drivers/SmartThings/zigbee-button/src/aqara-knob/init.lua @@ -0,0 +1,141 @@ +-- Copyright 2026 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local battery_defaults = require "st.zigbee.defaults.battery_defaults" +local clusters = require "st.zigbee.zcl.clusters" +local cluster_base = require "st.zigbee.cluster_base" +local data_types = require "st.zigbee.data_types" +local capabilities = require "st.capabilities" +local utils = require "st.utils" +local button_utils = require "button_utils" + +local PowerConfiguration = clusters.PowerConfiguration +local PRIVATE_CLUSTER_ID = 0xFCC0 +local PRIVATE_ATTRIBUTE_ID = 0x0009 +local MFG_CODE = 0x115F +local MULTISTATE_INPUT_CLUSTER_ID = 0x0012 +local PRESENT_ATTRIBUTE_ID = 0x0055 +local ROTATION_MONITOR_ID = 0x0232 + +local AQARA_KNOB = { + ["lumi.remote.rkba01"] = { mfr = "LUMI", type = "CR2032", quantity = 2 }, -- Aqara Wireless Knob Switch H1 +} + +local function device_init(driver, device) + local configuration = { + { + cluster = PowerConfiguration.ID, + attribute = PowerConfiguration.attributes.BatteryVoltage.ID, + minimum_interval = 30, + maximum_interval = 3600, + data_type = PowerConfiguration.attributes.BatteryVoltage.base_type, + reportable_change = 1 + } + } + + battery_defaults.build_linear_voltage_init(2.6, 3.0)(driver, device) + for _, attribute in ipairs(configuration) do + device:add_configured_attribute(attribute) + end +end + +local function device_added(self, device) + local model = device:get_model() + local type = AQARA_KNOB[model].type or "CR2032" + local quantity = AQARA_KNOB[model].quantity or 1 + + device:emit_event(capabilities.button.supportedButtonValues({ "pushed", "held", "double" }, { visibility = { displayed = false } })) + device:emit_event(capabilities.button.numberOfButtons({ value = 1 })) + button_utils.emit_event_if_latest_state_missing(device, "main", capabilities.button, + capabilities.button.button.NAME, capabilities.button.button.pushed({state_change = false})) + device:emit_event(capabilities.batteryLevel.battery.normal()) + device:emit_event(capabilities.batteryLevel.type(type)) + device:emit_event(capabilities.batteryLevel.quantity(quantity)) + device:emit_event(capabilities.knob.rotateAmount(0)) + device:emit_event(capabilities.knob.heldRotateAmount(0)) +end + +local function do_configure(driver, device) + device:configure() + -- Set manufacturer-specific attribute to enable "Operation Mode" for rotation reports + device:send(cluster_base.write_manufacturer_specific_attribute(device, + PRIVATE_CLUSTER_ID, PRIVATE_ATTRIBUTE_ID, MFG_CODE, data_types.Uint8, 1)) + device:emit_event(capabilities.knob.supportedAttributes({"rotateAmount", "heldRotateAmount"}, {state_change = true})) +end + +local function button_monitor_handler(driver, device, value, zb_rx) + local val = value.value + + if val == 1 then -- push + device:emit_event(capabilities.button.button.pushed({ state_change = true })) + elseif val == 2 then -- double push + device:emit_event(capabilities.button.button.double({ state_change = true })) + elseif val == 0 then -- down_hold + device:emit_event(capabilities.button.button.held({ state_change = true })) + end +end + +local function rotation_monitor_per_handler(driver, device, value, zb_rx) + local SENSITIVITY_KEY = "stse.knobSensitivity" + local SENSITIVITY_FACTORS = {0.5, 1.0, 2.0} + + local end_point = zb_rx.address_header.src_endpoint.value + local raw_val = utils.round(value.value) + + if raw_val > 0x7FFF then + raw_val = raw_val - 0x10000 + end + + local sensitivity = tonumber(device.preferences[SENSITIVITY_KEY]) + local factor = SENSITIVITY_FACTORS[sensitivity] or 1.0 + local intermediate_val = raw_val * factor + local sign = (intermediate_val > 0 and 1) or (intermediate_val < 0 and -1) or 0 + local val = math.floor(math.abs(intermediate_val) + 0.5) * sign + val = math.max(-100, math.min(100, val)) + + if val == 0 then + return + elseif end_point == 0x47 then -- normal + device:emit_event(capabilities.knob.rotateAmount({value = val}, {state_change = true})) + elseif end_point == 0x48 then -- press + device:emit_event(capabilities.knob.heldRotateAmount({value = val}, {state_change = true})) + end +end + +local function battery_level_handler(driver, device, value, zb_rx) + local voltage = value.value + local batteryLevel = "normal" + + if voltage <= 25 then + batteryLevel = "critical" + elseif voltage < 28 then + batteryLevel = "warning" + end + + device:emit_event(capabilities.batteryLevel.battery(batteryLevel)) +end + +local aqara_knob_switch_handler = { + NAME = "Aqara Wireless Knob Switch Handler", + lifecycle_handlers = { + init = device_init, + added = device_added, + doConfigure = do_configure + }, + zigbee_handlers = { + attr = { + [MULTISTATE_INPUT_CLUSTER_ID] = { + [PRESENT_ATTRIBUTE_ID] = button_monitor_handler + }, + [PRIVATE_CLUSTER_ID] = { + [ROTATION_MONITOR_ID] = rotation_monitor_per_handler + }, + [PowerConfiguration.ID] = { + [PowerConfiguration.attributes.BatteryVoltage.ID] = battery_level_handler + }, + } + }, + can_handle = require("aqara-knob.can_handle"), +} + +return aqara_knob_switch_handler \ No newline at end of file diff --git a/drivers/SmartThings/zigbee-button/src/sub_drivers.lua b/drivers/SmartThings/zigbee-button/src/sub_drivers.lua index 47fe5ff9c4..bec1f76ac1 100644 --- a/drivers/SmartThings/zigbee-button/src/sub_drivers.lua +++ b/drivers/SmartThings/zigbee-button/src/sub_drivers.lua @@ -4,6 +4,7 @@ local lazy_load_if_possible = require "lazy_load_subdriver" local sub_drivers = { lazy_load_if_possible("aqara"), + lazy_load_if_possible("aqara-knob"), lazy_load_if_possible("pushButton"), lazy_load_if_possible("frient"), lazy_load_if_possible("zigbee-multi-button"), diff --git a/drivers/SmartThings/zigbee-button/src/test/test_aqara_knob_switch.lua b/drivers/SmartThings/zigbee-button/src/test/test_aqara_knob_switch.lua new file mode 100644 index 0000000000..69ae937aff --- /dev/null +++ b/drivers/SmartThings/zigbee-button/src/test/test_aqara_knob_switch.lua @@ -0,0 +1,287 @@ +-- Copyright 2026 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local test = require "integration_test" +local t_utils = require "integration_test.utils" +local zigbee_test_utils = require "integration_test.zigbee_test_utils" +local capabilities = require "st.capabilities" +local clusters = require "st.zigbee.zcl.clusters" +local cluster_base = require "st.zigbee.cluster_base" +local data_types = require "st.zigbee.data_types" + + +local MULTISTATE_INPUT_CLUSTER_ID = 0x0012 +local PRESENT_ATTRIBUTE_ID = 0x0055 +local PowerConfiguration = clusters.PowerConfiguration + +local MFG_CODE = 0x115F +local PRIVATE_CLUSTER_ID = 0xFCC0 +local PRIVATE_ATTRIBUTE_ID = 0x0009 + +local mock_device = test.mock_device.build_test_zigbee_device( + { + profile = t_utils.get_profile_definition("aqara-knob-switch.yml"), + zigbee_endpoints = { + [1] = { + id = 1, + manufacturer = "LUMI", + model = "lumi.remote.rkba01", + server_clusters = { 0x0001 } + } + } + } +) +mock_device:set_field("preferences", {["stse.knobSensitivity"] = 2}, {persist = true}) + +zigbee_test_utils.prepare_zigbee_env_info() +local function test_init() + test.mock_device.add_test_device(mock_device) +end + +test.set_test_init_function(test_init) + +test.register_coroutine_test( + "Handle added lifecycle", + function() + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.button.supportedButtonValues({ "pushed", "held", "double" }, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.button.numberOfButtons({ value = 1 }))) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.button.button.pushed({ state_change = false }))) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.batteryLevel.battery.normal())) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.batteryLevel.type("CR2032"))) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.batteryLevel.quantity(2))) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.knob.rotateAmount(0))) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.knob.heldRotateAmount(0))) + end +) + +test.register_coroutine_test( + "Handle doConfigure lifecycle", + function() + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) + test.socket.zigbee:__expect_send({ + mock_device.id, + zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, PowerConfiguration.ID) + }) + test.socket.zigbee:__expect_send({ + mock_device.id, + PowerConfiguration.attributes.BatteryVoltage:configure_reporting(mock_device, 30, 3600, 1) + }) + test.socket.zigbee:__expect_send({ mock_device.id, + cluster_base.write_manufacturer_specific_attribute(mock_device, PRIVATE_CLUSTER_ID, PRIVATE_ATTRIBUTE_ID, + MFG_CODE, + data_types.Uint8, 1) }) + mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.knob.supportedAttributes({"rotateAmount", "heldRotateAmount"}, {state_change = true}))) + end +) + +test.register_coroutine_test( + "rotation_monitor_per_handler - normal", + function() + local attr_report_data = { + { 0x0232, data_types.Uint16.ID, 0x0001 } + } + test.socket.zigbee:__queue_receive({ + mock_device.id, + zigbee_test_utils.build_attribute_report(mock_device, PRIVATE_CLUSTER_ID, + attr_report_data, MFG_CODE):from_endpoint(0x47) + }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.knob.rotateAmount({value = 1}, {state_change = true}))) + end +) + +test.register_coroutine_test( + "rotation_monitor_per_handler - max clamp at 100", + function() + local attr_report_data = {{ 0x0232, data_types.Uint16.ID, 200 }} + test.socket.zigbee:__queue_receive({ + mock_device.id, + zigbee_test_utils.build_attribute_report(mock_device, PRIVATE_CLUSTER_ID, + attr_report_data, MFG_CODE):from_endpoint(0x47) + }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.knob.rotateAmount({value = 100}, {state_change = true}))) + end +) + +test.register_coroutine_test( + "rotation_monitor_per_handler - min clamp at -100", + function() + local attr_report_data = {{ 0x0232, data_types.Uint16.ID, 65386 }} + test.socket.zigbee:__queue_receive({ + mock_device.id, + zigbee_test_utils.build_attribute_report(mock_device, PRIVATE_CLUSTER_ID, + attr_report_data, MFG_CODE):from_endpoint(0x47) + }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.knob.rotateAmount({value = -100}, {state_change = true}))) + end +) + +test.register_coroutine_test( + "rotation_monitor_per_handler - sensitivity 0.5x", + function() + mock_device:set_field("preferences", {["stse.knobSensitivity"] = 1}) + local attr_report_data = {{ 0x0232, data_types.Uint16.ID, 3 }} + test.socket.zigbee:__queue_receive({ + mock_device.id, + zigbee_test_utils.build_attribute_report(mock_device, PRIVATE_CLUSTER_ID, + attr_report_data, MFG_CODE):from_endpoint(0x47) + }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.knob.rotateAmount({value = 3}, {state_change = true}))) + end +) + +test.register_coroutine_test( + "rotation_monitor_per_handler - sensitivity 2.0x", + function() + mock_device:set_field("preferences", {["stse.knobSensitivity"] = 3}) + local attr_report_data = {{ 0x0232, data_types.Uint16.ID, 5 }} + test.socket.zigbee:__queue_receive({ + mock_device.id, + zigbee_test_utils.build_attribute_report(mock_device, PRIVATE_CLUSTER_ID, + attr_report_data, MFG_CODE):from_endpoint(0x47) + }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.knob.rotateAmount({value = 5}, {state_change = true}))) + end +) + +test.register_coroutine_test( + "rotation_monitor_per_handler - held rotate amount", + function() + mock_device:set_field("preferences", {["stse.knobSensitivity"] = 2}) + local attr_report_data = {{ 0x0232, data_types.Uint16.ID, 15 }} + test.socket.zigbee:__queue_receive({ + mock_device.id, + zigbee_test_utils.build_attribute_report(mock_device, PRIVATE_CLUSTER_ID, + attr_report_data, MFG_CODE):from_endpoint(0x48) + }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.knob.heldRotateAmount({value = 15}, {state_change = true}))) + end +) + +test.register_coroutine_test( + "rotation_monitor_per_handler - press", + function() + local attr_report_data = { + { 0x0232, data_types.Uint16.ID, 0x0001 } + } + test.socket.zigbee:__queue_receive({ + mock_device.id, + zigbee_test_utils.build_attribute_report(mock_device, PRIVATE_CLUSTER_ID, + attr_report_data, MFG_CODE):from_endpoint(0x48) + }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.knob.heldRotateAmount({value = 1}, {state_change = true}))) + end +) + +test.register_coroutine_test( + "Reported button should be handled: pushed true", + function() + local attr_report_data = { + { PRESENT_ATTRIBUTE_ID, data_types.Uint16.ID, 0x0001 } + } + test.socket.zigbee:__queue_receive({ + mock_device.id, + zigbee_test_utils.build_attribute_report(mock_device, MULTISTATE_INPUT_CLUSTER_ID, + attr_report_data, MFG_CODE) + }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.button.button.pushed({ state_change = true }))) + end +) + +test.register_coroutine_test( + "Reported button should be handled: double true", + function() + local attr_report_data = { + { PRESENT_ATTRIBUTE_ID, data_types.Uint16.ID, 0x0002 } + } + test.socket.zigbee:__queue_receive({ + mock_device.id, + zigbee_test_utils.build_attribute_report(mock_device, MULTISTATE_INPUT_CLUSTER_ID, + attr_report_data, MFG_CODE) + }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.button.button.double({ state_change = true }))) + end +) + +test.register_coroutine_test( + "Reported button should be handled: held true", + function() + local attr_report_data = { + { PRESENT_ATTRIBUTE_ID, data_types.Uint16.ID, 0x0000 } + } + test.socket.zigbee:__queue_receive({ + mock_device.id, + zigbee_test_utils.build_attribute_report(mock_device, MULTISTATE_INPUT_CLUSTER_ID, + attr_report_data, MFG_CODE) + }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.button.button.held({ state_change = true }))) + end +) + +test.register_message_test( + "Battery Level - Normal", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device.id, PowerConfiguration.attributes.BatteryVoltage:build_test_attr_report(mock_device, 30) } + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message("main", capabilities.batteryLevel.battery("normal")) + } + } +) +test.register_message_test( + "Battery Level - Warning", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device.id, PowerConfiguration.attributes.BatteryVoltage:build_test_attr_report(mock_device, 27) } + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message("main", capabilities.batteryLevel.battery("warning")) + } + } +) +test.register_message_test( + "Battery Level - Critical", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device.id, PowerConfiguration.attributes.BatteryVoltage:build_test_attr_report(mock_device, 20) } + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message("main", capabilities.batteryLevel.battery("critical")) + } + } +) + +test.run_registered_tests() From 92b37fa8141dd2d263587ba7ae93f9a74d7a1d42 Mon Sep 17 00:00:00 2001 From: Alec Lorimer Date: Wed, 1 Apr 2026 11:10:55 -0500 Subject: [PATCH 05/29] Updating permissions for statuses --- .github/workflows/jenkins-driver-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/jenkins-driver-tests.yml b/.github/workflows/jenkins-driver-tests.yml index ec96330d39..26b3e2c79b 100644 --- a/.github/workflows/jenkins-driver-tests.yml +++ b/.github/workflows/jenkins-driver-tests.yml @@ -4,6 +4,9 @@ on: paths: - 'drivers/**' +permissions: + statuses: write + jobs: trigger-driver-test: strategy: From aee3191a3e4da6fdb2a09c4197180e7ef5e96dcc Mon Sep 17 00:00:00 2001 From: Steven Green Date: Tue, 24 Mar 2026 09:55:07 -0700 Subject: [PATCH 06/29] WWSTCERT-10572 Decora Smart Wi-Fi (2ndGen) Fan Speed Controller (#2833) * WWSTCERT-10572 Decora Smart Wi-Fi (2ndGen) Fan Speed Controller --------- Co-authored-by: Chris Baumler --- drivers/SmartThings/matter-thermostat/fingerprints.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/SmartThings/matter-thermostat/fingerprints.yml b/drivers/SmartThings/matter-thermostat/fingerprints.yml index 82be079601..cd1e7c5cbd 100644 --- a/drivers/SmartThings/matter-thermostat/fingerprints.yml +++ b/drivers/SmartThings/matter-thermostat/fingerprints.yml @@ -49,6 +49,12 @@ matterManufacturer: vendorId: 0x1527 productId: 0x0002 deviceProfileName: thermostat-heating-only-batteryLevel + #Leviton + - id: "4251/4101" + deviceLabel: Decora Smart Wi-Fi (2ndGen) Fan Speed Controller + vendorId: 0x109B + productId: 0x1005 + deviceProfileName: fan-generic #Lux - id: "4614/1" deviceLabel: LUX TQ1 Smart Thermostat From 3d7843be8cd49316422dac9164b8e19a43d3dee9 Mon Sep 17 00:00:00 2001 From: Alec Lorimer Date: Tue, 31 Mar 2026 15:53:59 -0500 Subject: [PATCH 07/29] Script for and updating min_api_version of tests. Updated to run PRs against 59 Conflicts: drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_aliro.lua drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua Aliro functionality not yet in production https://github.com/SmartThingsCommunity/SmartThingsEdgeDrivers/pull/2816 not yet in production --- .github/workflows/jenkins-driver-tests.yml | 2 +- .../src/test/test_cook_top.lua | 8 +- .../src/test/test_dishwasher.lua | 16 +- .../src/test/test_extractor_hood.lua | 22 +- .../src/test/test_laundry_dryer.lua | 18 +- .../src/test/test_laundry_washer.lua | 4 +- .../src/test/test_matter_appliance_rpc_5.lua | 24 +- .../src/test/test_microwave_oven.lua | 10 +- .../matter-appliance/src/test/test_oven.lua | 20 +- .../src/test/test_refrigerator.lua | 10 +- .../src/test/test_matter_button.lua | 20 +- .../test/test_matter_button_parent_child.lua | 16 +- .../src/test/test_matter_multi_button.lua | 38 +-- .../src/test/test_battery_storage.lua | 10 +- .../matter-energy/src/test/test_evse.lua | 24 +- .../src/test/test_evse_energy_meas.lua | 4 +- .../src/test/test_solar_power.lua | 6 +- .../test_thread_border_router_network.lua | 14 +- .../src/test/test_aqara_matter_lock.lua | 16 +- .../src/test/test_bridged_matter_lock.lua | 4 +- .../matter-lock/src/test/test_matter_lock.lua | 22 +- .../src/test/test_matter_lock_battery.lua | 6 +- .../test/test_matter_lock_batteryLevel.lua | 2 +- .../src/test/test_matter_lock_codes.lua | 36 +-- .../src/test/test_matter_lock_cota.lua | 26 +- .../src/test/test_matter_lock_modular.lua | 14 +- .../src/test/test_matter_lock_unlatch.lua | 18 +- .../src/test/test_new_matter_lock.lua | 92 +++---- .../src/test/test_new_matter_lock_battery.lua | 24 +- .../src/test/test_matter_media_speaker.lua | 10 +- .../test/test_matter_media_video_player.lua | 18 +- .../matter-rvc/src/test/test_matter_rvc.lua | 38 +-- .../test/test_matter_air_quality_sensor.lua | 22 +- ...test_matter_air_quality_sensor_modular.lua | 4 +- .../test/test_matter_bosch_button_contact.lua | 14 +- .../src/test/test_matter_flow_sensor.lua | 6 +- .../test/test_matter_freeze_leak_sensor.lua | 12 +- .../src/test/test_matter_pressure_sensor.lua | 6 +- .../src/test/test_matter_rain_sensor.lua | 4 +- .../src/test/test_matter_sensor.lua | 18 +- .../src/test/test_matter_sensor_battery.lua | 6 +- .../test/test_matter_sensor_featuremap.lua | 6 +- .../src/test/test_matter_sensor_rpc.lua | 2 +- .../src/test/test_matter_smoke_co_alarm.lua | 22 +- .../test_matter_smoke_co_alarm_battery.lua | 6 +- .../test/test_aqara_climate_sensor_w100.lua | 28 +- .../src/test/test_aqara_cube.lua | 4 +- .../src/test/test_aqara_light_switch_h2.lua | 4 +- .../src/test/test_electrical_sensor_set.lua | 22 +- .../src/test/test_electrical_sensor_tree.lua | 12 +- .../src/test/test_eve_energy.lua | 26 +- .../src/test/test_ikea_scroll.lua | 18 +- .../test/test_light_illuminance_motion.lua | 28 +- .../src/test/test_matter_bridge.lua | 4 +- .../src/test/test_matter_button.lua | 28 +- .../src/test/test_matter_camera.lua | 80 +++--- .../src/test/test_matter_light_fan.lua | 12 +- .../src/test/test_matter_multi_button.lua | 48 ++-- .../test/test_matter_multi_button_motion.lua | 40 +-- .../test_matter_multi_button_switch_mcd.lua | 20 +- .../test_matter_sensor_offset_preferences.lua | 4 +- .../src/test/test_matter_switch.lua | 54 ++-- .../test/test_matter_switch_device_types.lua | 26 +- .../src/test/test_matter_water_valve.lua | 16 +- .../src/test/test_multi_switch_mcd.lua | 6 +- .../test_multi_switch_parent_child_lights.lua | 22 +- .../test_multi_switch_parent_child_plugs.lua | 20 +- .../src/test/test_stateless_step.lua | 4 +- .../src/test/test_third_reality_mk1.lua | 2 +- .../src/test/test_matter_air_purifier.lua | 26 +- .../test/test_matter_air_purifier_api9.lua | 26 +- .../test/test_matter_air_purifier_modular.lua | 4 +- .../src/test/test_matter_fan.lua | 4 +- .../src/test/test_matter_heat_pump.lua | 26 +- .../src/test/test_matter_room_ac.lua | 16 +- .../src/test/test_matter_room_ac_modular.lua | 4 +- .../src/test/test_matter_thermo_battery.lua | 6 +- .../test/test_matter_thermo_featuremap.lua | 8 +- ...st_matter_thermo_multiple_device_types.lua | 6 +- .../test_matter_thermo_setpoint_limits.lua | 20 +- ...test_matter_thermo_setpoint_limits_rpc.lua | 6 +- .../src/test/test_matter_thermostat.lua | 48 ++-- ...est_matter_thermostat_composed_bridged.lua | 42 +-- .../test/test_matter_thermostat_modular.lua | 2 +- .../src/test/test_matter_thermostat_rpc5.lua | 2 +- .../src/test/test_matter_water_heater.lua | 14 +- .../src/test/test_matter_window_covering.lua | 66 ++--- .../src/test/test_virtual_switch.lua | 14 +- .../test_MultiIR_air_quality_detector.lua | 44 +-- .../src/test/test_shus_mattress.lua | 112 ++++---- .../src/test/test_SLED_button.lua | 6 +- .../src/test/test_aduro_button.lua | 6 +- .../src/test/test_aqara_button.lua | 22 +- .../src/test/test_centralite_button.lua | 10 +- .../src/test/test_dimming_remote.lua | 12 +- .../src/test/test_ewelink_button.lua | 10 +- .../src/test/test_ezviz_button.lua | 12 +- .../src/test/test_frient_button.lua | 18 +- .../src/test/test_heiman_button.lua | 16 +- .../src/test/test_ikea_on_off.lua | 10 +- .../src/test/test_ikea_open_close.lua | 10 +- .../src/test/test_ikea_remote_control.lua | 10 +- .../src/test/test_iris_button.lua | 18 +- .../test/test_linxura_aura_smart_button.lua | 8 +- ...est_linxura_smart_controller_4x_button.lua | 8 +- .../src/test/test_push_only_button.lua | 12 +- .../src/test/test_robb_4x_button.lua | 14 +- .../src/test/test_robb_8x_button.lua | 14 +- .../src/test/test_samjin_button.lua | 4 +- .../src/test/test_shinasystem_button.lua | 10 +- .../src/test/test_somfy_situo_1_button.lua | 10 +- .../src/test/test_somfy_situo_4_button.lua | 8 +- .../src/test/test_thirdreality_button.lua | 8 +- .../src/test/test_vimar_button.lua | 12 +- .../src/test/test_wallhero_button.lua | 4 +- .../src/test/test_zigbee_button.lua | 24 +- .../src/test/test_zigbee_ecosmart_button.lua | 14 +- .../src/test/test_zunzunbee_8_button.lua | 8 +- ...test_climax_technology_carbon_monoxide.lua | 2 +- .../src/test/test_zigbee_carbon_monoxide.lua | 12 +- .../src/test/test_aqara_contact_sensor.lua | 18 +- .../src/test/test_aurora_contact_sensor.lua | 4 +- .../src/test/test_centralite_multi_sensor.lua | 16 +- .../test/test_contact_temperature_sensor.lua | 8 +- .../src/test/test_ecolink_contact.lua | 8 +- .../src/test/test_ewelink_heiman_sensor.lua | 4 +- .../src/test/test_frient_contact_sensor.lua | 18 +- .../test/test_frient_contact_sensor_2_pro.lua | 22 +- .../test/test_frient_contact_sensor_pro.lua | 22 +- .../src/test/test_frient_vibration_sensor.lua | 20 +- .../src/test/test_orvibo_contact_sensor.lua | 4 +- .../src/test/test_samjin_multi_sensor.lua | 8 +- .../src/test/test_sengled_contact_sensor.lua | 4 +- .../src/test/test_smartsense_multi.lua | 52 ++-- .../test/test_smartthings_multi_sensor.lua | 26 +- .../src/test/test_third_reality_contact.lua | 4 +- .../test/test_thirdreality_multi_sensor.lua | 6 +- .../src/test/test_zigbee_contact.lua | 18 +- .../src/test/test_zigbee_contact_battery.lua | 6 +- .../src/test/test_zigbee_contact_tyco.lua | 6 +- .../src/test/test_zigbee_accessory_dimmer.lua | 34 +-- .../test_zigbee_battery_accessory_dimmer.lua | Bin 29143 -> 29143 bytes .../zigbee-fan/src/test/test_fan_light.lua | 42 +-- .../src/test/test_aqara_sensor.lua | 20 +- .../src/test/test_centralite_sensor.lua | 6 +- .../src/test/test_ewelink_sensor.lua | 4 +- .../test/test_frient_air_quality_sensor.lua | 18 +- .../src/test/test_frient_sensor.lua | 14 +- .../src/test/test_heiman_sensor.lua | 4 +- .../src/test/test_humidity_battery_sensor.lua | 8 +- .../src/test/test_humidity_plaid_systems.lua | 18 +- .../src/test/test_humidity_temperature.lua | 10 +- .../test_humidity_temperature_battery.lua | 10 +- .../test/test_humidity_temperature_sensor.lua | 8 +- .../src/test/test_illuminance_sensor.lua | 6 +- .../test/test_illuminance_sensor_aqara.lua | 12 +- .../zigbee-lock/src/test/test_c2o_lock.lua | 16 +- .../src/test/test_generic_lock_migration.lua | 2 +- ..._yale_fingerprint_bad_battery_reporter.lua | 2 +- .../zigbee-lock/src/test/test_zigbee_lock.lua | 56 ++-- .../test/test_zigbee_lock_code_migration.lua | 10 +- .../src/test/test_zigbee_lock_v10.lua | 48 ++-- .../src/test/test_zigbee_samsungsds.lua | 112 ++++---- .../test_zigbee_yale-bad-battery-reporter.lua | 2 +- .../test_zigbee_yale-fingerprint-lock.lua | 2 +- .../zigbee-lock/src/test/test_zigbee_yale.lua | 22 +- .../test_all_capabilities_zigbee_motion.lua | 24 +- .../src/test/test_aqara_high_precision.lua | 18 +- .../test/test_aqara_motion_illuminance.lua | 12 +- .../src/test/test_aurora_motion.lua | 12 +- .../src/test/test_battery_voltage_motion.lua | 2 +- .../src/test/test_centralite_motion.lua | 4 +- .../src/test/test_compacta_motion.lua | 4 +- .../src/test/test_frient_motion_sensor.lua | 12 +- .../test/test_frient_motion_sensor2_pet.lua | 14 +- .../test/test_frient_motion_sensor_pro.lua | 22 +- .../src/test/test_gator_motion.lua | 18 +- .../src/test/test_ikea_motion.lua | 14 +- .../src/test/test_samjin_sensor.lua | 4 +- .../src/test/test_sengled_motion.lua | 4 +- .../test/test_smartsense_motion_sensor.lua | 16 +- .../src/test/test_smartthings_motion.lua | 2 +- .../src/test/test_thirdreality_sensor.lua | 10 +- .../src/test/test_zigbee_motion_iris.lua | 4 +- .../src/test/test_zigbee_motion_nyce.lua | 6 +- .../src/test/test_zigbee_motion_orvibo.lua | 12 +- .../test/test_zigbee_plugin_motion_sensor.lua | 8 +- .../src/test/test_zigbee_power_meter.lua | 14 +- .../src/test/test_zigbee_power_meter_1p.lua | 20 +- .../src/test/test_zigbee_power_meter_2p.lua | 16 +- .../src/test/test_zigbee_power_meter_3p.lua | 22 +- ...e_power_meter_consumption_report_sihas.lua | 12 +- .../src/test/test_zigbee_power_meter_ezex.lua | 8 +- .../test/test_zigbee_power_meter_frient.lua | 2 +- .../test/test_aqara_presence_sensor_fp1.lua | 20 +- .../src/test/test_st_arrival_sensor_v1.lua | 16 +- .../src/test/test_zigbee_presence_sensor.lua | 26 +- .../test_frient_zigbee_range_extender.lua | 18 +- .../src/test/test_zigbee_extend.lua | 2 +- .../src/test/test_zigbee_sensor.lua | 66 ++--- .../src/test/test_frient_siren.lua | 46 ++-- .../src/test/test_frient_siren_tamper.lua | 42 +-- .../zigbee-siren/src/test/test_ozom_siren.lua | 6 +- .../src/test/test_zigbee_siren.lua | 28 +- .../src/test/test_aqara_gas_detector.lua | 34 +-- .../src/test/test_aqara_smoke_detector.lua | 22 +- .../src/test/test_frient_heat_detector.lua | 32 +-- .../src/test/test_frient_smoke_detector.lua | 36 +-- .../src/test/test_zigbee_smoke_detector.lua | 14 +- .../src/test/test_zigbee_sound_sensor.lua | 16 +- .../test/test_all_capability_zigbee_bulb.lua | 28 +- .../src/test/test_aqara_led_bulb.lua | 8 +- .../src/test/test_aqara_light.lua | 16 +- .../src/test/test_aqara_smart_plug.lua | 28 +- .../src/test/test_aqara_smart_plug_t1.lua | 30 +- .../src/test/test_aqara_switch_module.lua | 18 +- .../test_aqara_switch_module_no_power.lua | 16 +- .../src/test/test_aqara_switch_no_power.lua | 32 +-- .../src/test/test_aqara_switch_power.lua | 34 +-- .../src/test/test_aqara_wall_switch.lua | 22 +- .../src/test/test_aurora_relay.lua | 8 +- .../src/test/test_bad_data_type.lua | 2 +- .../src/test/test_bad_device_kind.lua | 4 +- .../zigbee-switch/src/test/test_cree_bulb.lua | 8 +- .../test/test_duragreen_color_temp_bulb.lua | 8 +- .../test/test_enbrighten_metering_dimmer.lua | 14 +- .../src/test/test_frient_IO_module.lua | 10 +- .../src/test/test_frient_switch.lua | 20 +- .../src/test/test_ge_link_bulb.lua | 14 +- .../src/test/test_hanssem_switch.lua | 50 ++-- .../src/test/test_inovelli_vzm30_sn.lua | 28 +- .../src/test/test_inovelli_vzm30_sn_child.lua | 12 +- .../test_inovelli_vzm30_sn_preferences.lua | 16 +- .../src/test/test_inovelli_vzm31_sn.lua | 22 +- .../src/test/test_inovelli_vzm31_sn_child.lua | 12 +- .../test_inovelli_vzm31_sn_preferences.lua | 16 +- .../src/test/test_inovelli_vzm32_sn.lua | 30 +- .../src/test/test_inovelli_vzm32_sn_child.lua | 12 +- .../test_inovelli_vzm32_sn_preferences.lua | 12 +- .../src/test/test_jasco_switch.lua | 10 +- .../src/test/test_laisiao_bath_heather.lua | 64 ++--- .../src/test/test_multi_switch.lua | 10 +- .../src/test/test_multi_switch_no_master.lua | 28 +- .../src/test/test_multi_switch_power.lua | 32 +-- .../src/test/test_on_off_zigbee_bulb.lua | 10 +- .../src/test/test_osram_iqbr30_light.lua | 8 +- .../src/test/test_osram_light.lua | 6 +- .../zigbee-switch/src/test/test_rgb_bulb.lua | 10 +- .../zigbee-switch/src/test/test_rgbw_bulb.lua | 14 +- .../test/test_robb_smarrt_2-wire_dimmer.lua | 10 +- .../src/test/test_robb_smarrt_knob_dimmer.lua | 8 +- .../src/test/test_sengled_color_temp_bulb.lua | 6 +- ...sengled_dimmer_bulb_with_motion_sensor.lua | 16 +- .../src/test/test_sinope_dimmer.lua | 18 +- .../src/test/test_sinope_switch.lua | 6 +- .../src/test/test_switch_power.lua | 8 +- .../src/test/test_tuya_multi.lua | 2 +- .../src/test/test_tuya_multi_switch.lua | 10 +- .../src/test/test_wallhero_switch.lua | 48 ++-- .../src/test/test_white_color_temp_bulb.lua | 6 +- .../src/test/test_yanmi_switch.lua | 24 +- .../src/test/test_zigbee_ezex_switch.lua | 10 +- ...metering_plug_power_consumption_report.lua | 6 +- .../test_zigbee_metering_plug_rexense.lua | 4 +- .../src/test/test_zll_color_temp_bulb.lua | 12 +- .../src/test/test_zll_dimmer.lua | 10 +- .../src/test/test_zll_dimmer_bulb.lua | 14 +- .../src/test/test_zll_rgb_bulb.lua | 258 +++++++++++------- .../src/test/test_zll_rgbw_bulb.lua | 20 +- .../src/test/test_aqara_thermostat.lua | 24 +- .../src/test/test_centralite_thermostat.lua | 10 +- .../src/test/test_danfoss_thermostat.lua | 12 +- .../src/test/test_fidure_thermostat.lua | 4 +- .../src/test/test_leviton_rc.lua | 28 +- .../src/test/test_popp_thermostat.lua | 30 +- .../src/test/test_resideo_dt300st_m000.lua | 100 +++---- .../test/test_sinope_th1300_thermostat.lua | 8 +- .../test/test_sinope_th1400_thermostat.lua | 8 +- .../src/test/test_sinope_thermostat.lua | 10 +- .../test_stelpro_ki_zigbee_thermostat.lua | 36 +-- .../src/test/test_stelpro_thermostat.lua | 38 +-- .../src/test/test_vimar_thermostat.lua | 38 +-- .../src/test/test_zenwithin_thermostat.lua | 22 +- .../src/test/test_zigbee_thermostat.lua | 52 ++-- .../zigbee-valve/src/test/test_ezex_valve.lua | 26 +- .../src/test/test_sinope_valve.lua | 12 +- .../src/test/test_zigbee_valve.lua | 24 +- .../zigbee-vent/src/test/test_zigbee_vent.lua | 22 +- .../src/test/test_aqara_water_leak_sensor.lua | 8 +- .../test_centralite_water_leak_sensor.lua | 18 +- .../test/test_frient_water_leak_sensor.lua | 18 +- .../src/test/test_leaksmart_water.lua | 14 +- .../test/test_samjin_water_leak_sensor.lua | 14 +- .../test/test_sengled_water_leak_sensor.lua | 4 +- .../src/test/test_sinope_zigbee_water.lua | 18 +- .../test_smartthings_water_leak_sensor.lua | 12 +- .../test_thirdreality_water_leak_sensor.lua | 12 +- .../src/test/test_zigbee_water.lua | 18 +- .../src/test/test_zigbee_water_freeze.lua | 10 +- .../test/test_thirdreality_watering_kit.lua | 32 +-- .../test_zigbee_window_shade_battery_ikea.lua | 20 +- ...est_zigbee_window_shade_battery_yoolax.lua | 22 +- ...est_zigbee_window_shade_only_HOPOsmart.lua | 18 +- .../src/test/test_zigbee_window_treatment.lua | 18 +- ..._zigbee_window_treatment_VWSDSTUST120H.lua | 34 +-- .../test_zigbee_window_treatment_aqara.lua | 40 +-- ...ndow_treatment_aqara_curtain_driver_e1.lua | 30 +- ...ow_treatment_aqara_roller_shade_rotate.lua | 32 +-- .../test_zigbee_window_treatment_axis.lua | 34 +-- .../test_zigbee_window_treatment_feibit.lua | 28 +- .../test_zigbee_window_treatment_hanssem.lua | 14 +- .../test_zigbee_window_treatment_rooms.lua | 26 +- ...ee_window_treatment_screen_innovations.lua | 28 +- .../test_zigbee_window_treatment_somfy.lua | 38 +-- .../test_zigbee_window_treatment_vimar.lua | 26 +- .../src/test/test_aeon_multiwhite_bulb.lua | 36 +-- .../src/test/test_aeotec_led_bulb_6.lua | 6 +- .../src/test/test_fibaro_rgbw_controller.lua | 24 +- .../zwave-bulb/src/test/test_zwave_bulb.lua | 20 +- .../src/test/test_zwave_aeotec_minimote.lua | 20 +- .../test/test_zwave_aeotec_nanomote_one.lua | 2 +- .../src/test/test_zwave_button.lua | 12 +- .../src/test/test_zwave_fibaro_button.lua | 2 +- .../src/test/test_zwave_multi_button.lua | 44 +-- .../src/test/test_aeon_meter.lua | 8 +- .../src/test/test_aeotec_gen5_meter.lua | 8 +- .../src/test/test_qubino_3_phase_meter.lua | 8 +- .../src/test/test_qubino_smart_meter.lua | 8 +- .../src/test/test_zwave_electric_meter.lua | 6 +- .../src/test/test_zwave_fan_3_speed.lua | 10 +- .../src/test/test_zwave_fan_4_speed.lua | 10 +- .../test_ecolink_garage_door_operator.lua | 22 +- .../src/test/test_mimolite_garage_door.lua | 24 +- .../test/test_zwave_garage_door_opener.lua | 14 +- .../zwave-lock/src/test/test_keywe_lock.lua | 6 +- .../zwave-lock/src/test/test_lock_battery.lua | 10 +- .../zwave-lock/src/test/test_samsung_lock.lua | 10 +- .../zwave-lock/src/test/test_schlage_lock.lua | 16 +- .../zwave-lock/src/test/test_zwave_lock.lua | 48 ++-- .../test/test_zwave_lock_code_migration.lua | 10 +- .../src/test/test_zwave_mouse_trap.lua | 24 +- .../src/test/test_aeon_multisensor.lua | 4 +- .../src/test/test_aeotec_multisensor_6.lua | 22 +- .../src/test/test_aeotec_multisensor_7.lua | 12 +- .../src/test/test_aeotec_multisensor_gen5.lua | 2 +- .../src/test/test_aeotec_water_sensor.lua | 24 +- .../src/test/test_aeotec_water_sensor_7.lua | 12 +- .../src/test/test_enerwave_motion_sensor.lua | 6 +- .../src/test/test_everpsring_sp817.lua | 4 +- .../src/test/test_everspring_PIR_sensor.lua | 12 +- .../src/test/test_everspring_ST814.lua | 2 +- .../test_everspring_illuminance_sensor.lua | 2 +- .../test_everspring_motion_light_sensor.lua | 2 +- .../test_ezmultipli_multipurpose_sensor.lua | 10 +- .../test/test_fibaro_door_window_sensor.lua | 14 +- .../test/test_fibaro_door_window_sensor_1.lua | 22 +- .../test/test_fibaro_door_window_sensor_2.lua | 20 +- ...ro_door_window_sensor_with_temperature.lua | 20 +- .../src/test/test_fibaro_flood_sensor.lua | 24 +- .../src/test/test_fibaro_flood_sensor_zw5.lua | 2 +- .../src/test/test_fibaro_motion_sensor.lua | 26 +- .../test/test_fibaro_motion_sensor_zw5.lua | 4 +- .../src/test/test_firmware_version.lua | 6 +- .../src/test/test_generic_sensor.lua | 118 ++++---- .../test_glentronics_water_leak_sensor.lua | 14 +- .../src/test/test_homeseer_multi_sensor.lua | 10 +- .../src/test/test_no_wakeup_poll.lua | 2 +- .../src/test/test_sensative_strip.lua | 6 +- .../test_smartthings_water_leak_sensor.lua | 24 +- .../src/test/test_v1_contact_event.lua | 6 +- .../src/test/test_vision_motion_detector.lua | 12 +- .../src/test/test_zooz_4_in_1_sensor.lua | 20 +- .../test/test_zwave_motion_light_sensor.lua | 22 +- .../test_zwave_motion_temp_light_sensor.lua | 18 +- .../src/test/test_zwave_sensor.lua | 54 ++-- .../src/test/test_zwave_water_sensor.lua | 24 +- .../zwave-siren/src/test/test_aeon_siren.lua | 20 +- .../src/test/test_aeotec_doorbell_siren.lua | 160 +++++------ .../src/test/test_ecolink_wireless_siren.lua | 30 +- .../src/test/test_fortrezz_siren.lua | 8 +- .../src/test/test_philio_sound_siren.lua | 36 +-- .../src/test/test_utilitech_siren.lua | 4 +- .../zwave-siren/src/test/test_yale_siren.lua | 18 +- .../src/test/test_zipato_siren.lua | 10 +- .../test/test_zwave_multifunctional-siren.lua | 10 +- .../test/test_zwave_notification_siren.lua | 8 +- .../zwave-siren/src/test/test_zwave_siren.lua | 28 +- .../src/test/test_zwave_sound_sensor.lua | 6 +- .../src/test/test_fibaro_co_sensor_zw5.lua | 28 +- .../src/test/test_fibaro_smoke_sensor.lua | 6 +- .../src/test/test_zwave_alarm_v1.lua | 14 +- .../src/test/test_zwave_co_detector.lua | 14 +- .../src/test/test_zwave_smoke_detector.lua | 30 +- .../src/test/test_aeon_smart_strip.lua | 32 +-- .../src/test/test_aeotec_dimmer_switch.lua | 22 +- ..._aeotec_dual_nano_switch_configuration.lua | 2 +- .../test/test_aeotec_heavy_duty_switch.lua | 36 +-- ...t_aeotec_metering_switch_configuration.lua | 2 +- .../src/test/test_aeotec_nano_dimmer.lua | 22 +- .../test_aeotec_nano_dimmer_preferences.lua | 2 +- .../src/test/test_aeotec_smart_switch.lua | 4 +- .../test/test_aeotec_smart_switch_7_eu.lua | 12 +- .../test/test_aeotec_smart_switch_7_us.lua | 12 +- .../test/test_aeotec_smart_switch_gen5.lua | 2 +- .../src/test/test_dawon_smart_plug.lua | 4 +- .../src/test/test_dawon_wall_smart_switch.lua | 20 +- .../src/test/test_eaton_5_scene_keypad.lua | 26 +- .../src/test/test_eaton_accessory_dimmer.lua | 16 +- .../src/test/test_eaton_anyplace_switch.lua | 12 +- .../src/test/test_eaton_rf_dimmer.lua | 2 +- .../src/test/test_ecolink_switch.lua | 18 +- .../src/test/test_fibaro_double_switch.lua | 20 +- .../src/test/test_fibaro_single_switch.lua | 42 +-- .../src/test/test_fibaro_wall_plug_eu.lua | 2 +- ...test_fibaro_wall_plug_uk_configuration.lua | 2 +- .../src/test/test_fibaro_wall_plug_us.lua | 16 +- .../test_fibaro_walli_dimmer_preferences.lua | 14 +- .../test/test_fibaro_walli_double_switch.lua | 30 +- ...fibaro_walli_double_switch_preferences.lua | 12 +- .../src/test/test_generic_zwave_device1.lua | 16 +- ...go_control_plug_in_switch_configuraton.lua | 2 +- .../src/test/test_honeywell_dimmer.lua | 2 +- .../test_inovelli_2_channel_smart_plug.lua | 36 +-- .../src/test/test_inovelli_button.lua | 8 +- .../src/test/test_inovelli_dimmer.lua | 14 +- .../src/test/test_inovelli_dimmer_led.lua | 4 +- .../test_inovelli_dimmer_power_energy.lua | 18 +- .../test/test_inovelli_dimmer_preferences.lua | 10 +- .../src/test/test_inovelli_dimmer_scenes.lua | 22 +- .../src/test/test_inovelli_vzw32_sn.lua | 14 +- .../src/test/test_inovelli_vzw32_sn_child.lua | 12 +- .../test_inovelli_vzw32_sn_preferences.lua | 10 +- .../src/test/test_multi_metering_switch.lua | 36 +-- .../src/test/test_multichannel_device.lua | 118 ++++---- .../test_popp_outdoor_plug_configuration.lua | 2 +- .../src/test/test_qubino_din_dimmer.lua | 24 +- .../test_qubino_din_dimmer_preferences.lua | 14 +- .../test_qubino_flush_1_relay_preferences.lua | 10 +- ...test_qubino_flush_1d_relay_preferences.lua | 6 +- .../src/test/test_qubino_flush_2_relay.lua | 34 +-- .../test_qubino_flush_2_relay_preferences.lua | 10 +- .../src/test/test_qubino_flush_dimmer.lua | 24 +- ..._qubino_flush_dimmer_0_10V_preferences.lua | 14 +- .../test_qubino_flush_dimmer_preferences.lua | 18 +- .../test_qubino_mini_dimmer_preferences.lua | 16 +- ...t_qubino_temperature_sensor_with_power.lua | 18 +- ...ubino_temperature_sensor_without_power.lua | 12 +- .../test_shelly_multi_metering_switch.lua | 34 +-- .../zwave-switch/src/test/test_wyfy_touch.lua | 22 +- .../test/test_wyfy_touch_configuration.lua | 2 +- .../src/test/test_zooz_double_plug.lua | 30 +- .../src/test/test_zooz_power_strip.lua | 66 ++--- .../test/test_zooz_zen_30_dimmer_relay.lua | 80 +++--- ...t_zooz_zen_30_dimmer_relay_preferences.lua | 2 +- .../test/test_zwave_dimmer_power_energy.lua | 18 +- .../src/test/test_zwave_dual_switch.lua | 36 +-- .../test/test_zwave_dual_switch_migration.lua | 4 +- .../src/test/test_zwave_switch.lua | 20 +- .../src/test/test_zwave_switch_battery.lua | 6 +- .../test/test_zwave_switch_electric_meter.lua | 8 +- .../test/test_zwave_switch_energy_meter.lua | 10 +- .../src/test/test_zwave_switch_level.lua | 4 +- .../test/test_zwave_switch_power_meter.lua | 8 +- .../test/test_aeotec_radiator_thermostat.lua | 16 +- .../src/test/test_ct100_thermostat.lua | 20 +- .../src/test/test_fibaro_heat_controller.lua | 22 +- .../test/test_popp_radiator_thermostat.lua | 12 +- .../src/test/test_qubino_flush_thermostat.lua | 30 +- .../src/test/test_stelpro_ki_thermostat.lua | 20 +- .../test/test_thermostat_heating_battery.lua | 28 +- .../src/test/test_zwave_thermostat.lua | 44 +-- .../src/test/test_inverse.valve.lua | 12 +- .../zwave-valve/src/test/test_zwave_valve.lua | 16 +- .../test_zwave_virtual_momentary_switch.lua | 14 +- .../src/test/test_fibaro_roller_shutter.lua | 60 ++-- .../src/test/test_qubino_flush_shutter.lua | 50 ++-- .../test/test_zwave_aeotec_nano_shutter.lua | 24 +- .../test_zwave_iblinds_window_treatment.lua | 30 +- .../test_zwave_springs_window_treatment.lua | 2 +- .../src/test/test_zwave_window_treatment.lua | 36 +-- tools/update_min_tags.py | 100 +++++++ 481 files changed, 4628 insertions(+), 4470 deletions(-) mode change 100755 => 100644 drivers/SmartThings/zigbee-air-quality-detector/src/test/test_MultiIR_air_quality_detector.lua mode change 100755 => 100644 drivers/SmartThings/zigbee-bed/src/test/test_shus_mattress.lua mode change 100755 => 100644 drivers/SmartThings/zigbee-switch/src/test/test_laisiao_bath_heather.lua mode change 100755 => 100644 drivers/SmartThings/zigbee-switch/src/test/test_sinope_switch.lua mode change 100755 => 100644 drivers/SmartThings/zigbee-switch/src/test/test_tuya_multi.lua mode change 100755 => 100644 drivers/SmartThings/zigbee-switch/src/test/test_yanmi_switch.lua mode change 100755 => 100644 drivers/SmartThings/zigbee-window-treatment/src/test/test_zigbee_window_shade_only_HOPOsmart.lua mode change 100755 => 100644 drivers/SmartThings/zigbee-window-treatment/src/test/test_zigbee_window_treatment_VWSDSTUST120H.lua mode change 100755 => 100644 drivers/SmartThings/zigbee-window-treatment/src/test/test_zigbee_window_treatment_axis.lua mode change 100755 => 100644 drivers/SmartThings/zigbee-window-treatment/src/test/test_zigbee_window_treatment_vimar.lua mode change 100755 => 100644 drivers/SmartThings/zwave-thermostat/src/test/test_aeotec_radiator_thermostat.lua mode change 100755 => 100644 drivers/SmartThings/zwave-thermostat/src/test/test_popp_radiator_thermostat.lua create mode 100644 tools/update_min_tags.py diff --git a/.github/workflows/jenkins-driver-tests.yml b/.github/workflows/jenkins-driver-tests.yml index 26b3e2c79b..1e29ea8afc 100644 --- a/.github/workflows/jenkins-driver-tests.yml +++ b/.github/workflows/jenkins-driver-tests.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: version: - [ 60 ] + [ 59, 60 ] runs-on: ubuntu-latest steps: diff --git a/drivers/SmartThings/matter-appliance/src/test/test_cook_top.lua b/drivers/SmartThings/matter-appliance/src/test/test_cook_top.lua index 99d56a5869..0321d956ce 100644 --- a/drivers/SmartThings/matter-appliance/src/test/test_cook_top.lua +++ b/drivers/SmartThings/matter-appliance/src/test/test_cook_top.lua @@ -91,7 +91,7 @@ test.register_coroutine_test( assert(component_to_endpoint_map["cookSurfaceTwo"] == COOK_SURFACE_TWO_ENDPOINT, "Cook Surface Two Endpoint must be 3") end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -117,7 +117,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -157,7 +157,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -192,7 +192,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-appliance/src/test/test_dishwasher.lua b/drivers/SmartThings/matter-appliance/src/test/test_dishwasher.lua index 0cfeb19f07..6819815506 100644 --- a/drivers/SmartThings/matter-appliance/src/test/test_dishwasher.lua +++ b/drivers/SmartThings/matter-appliance/src/test/test_dishwasher.lua @@ -103,7 +103,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -171,7 +171,7 @@ test.register_message_test( }, -- on receiving NO ERROR we don't do anything. }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -239,7 +239,7 @@ test.register_message_test( }, -- on receiving NO ERROR we don't do anything. }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -307,7 +307,7 @@ test.register_message_test( }, -- on receiving NO ERROR we don't do anything. }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -386,7 +386,7 @@ test.register_message_test( }, -- on receiving NO ERROR we don't do anything. }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -450,7 +450,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -490,7 +490,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -549,7 +549,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-appliance/src/test/test_extractor_hood.lua b/drivers/SmartThings/matter-appliance/src/test/test_extractor_hood.lua index ca85e49214..d176352f80 100644 --- a/drivers/SmartThings/matter-appliance/src/test/test_extractor_hood.lua +++ b/drivers/SmartThings/matter-appliance/src/test/test_extractor_hood.lua @@ -176,7 +176,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -250,7 +250,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -339,7 +339,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) test.register_message_test( @@ -452,7 +452,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -490,7 +490,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -531,7 +531,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -592,7 +592,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -653,7 +653,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -666,7 +666,7 @@ test.register_coroutine_test( end, { test_init = test_init_onoff, - min_api_version = 19 + min_api_version = 17 } ) @@ -692,7 +692,7 @@ test.register_coroutine_test( end, { test_init = test_init_onoff, - min_api_version = 19 + min_api_version = 17 } ) @@ -716,7 +716,7 @@ test.register_coroutine_test( end, { test_init = test_init_onoff, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-appliance/src/test/test_laundry_dryer.lua b/drivers/SmartThings/matter-appliance/src/test/test_laundry_dryer.lua index 5c01970d7b..ba1440af85 100644 --- a/drivers/SmartThings/matter-appliance/src/test/test_laundry_dryer.lua +++ b/drivers/SmartThings/matter-appliance/src/test/test_laundry_dryer.lua @@ -102,7 +102,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -170,7 +170,7 @@ test.register_message_test( }, -- on receiving NO ERROR we don't do anything. }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -238,7 +238,7 @@ test.register_message_test( }, -- on receiving NO ERROR we don't do anything. }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -306,7 +306,7 @@ test.register_message_test( }, -- on receiving NO ERROR we don't do anything. }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -385,7 +385,7 @@ test.register_message_test( }, -- on receiving NO ERROR we don't do anything. }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -449,7 +449,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -489,7 +489,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -548,7 +548,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -591,7 +591,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-appliance/src/test/test_laundry_washer.lua b/drivers/SmartThings/matter-appliance/src/test/test_laundry_washer.lua index a0df2e229b..6aba845a27 100644 --- a/drivers/SmartThings/matter-appliance/src/test/test_laundry_washer.lua +++ b/drivers/SmartThings/matter-appliance/src/test/test_laundry_washer.lua @@ -135,7 +135,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -178,7 +178,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-appliance/src/test/test_matter_appliance_rpc_5.lua b/drivers/SmartThings/matter-appliance/src/test/test_matter_appliance_rpc_5.lua index 4df43c94fc..7e59d7925f 100644 --- a/drivers/SmartThings/matter-appliance/src/test/test_matter_appliance_rpc_5.lua +++ b/drivers/SmartThings/matter-appliance/src/test/test_matter_appliance_rpc_5.lua @@ -458,7 +458,7 @@ test.register_coroutine_test( end, { test_init = test_init_dishwasher, - min_api_version = 19 + min_api_version = 17 } ) @@ -500,7 +500,7 @@ test.register_coroutine_test( end, { test_init = test_init_dishwasher, - min_api_version = 19 + min_api_version = 17 } ) @@ -542,7 +542,7 @@ test.register_coroutine_test( end, { test_init = test_init_washer, - min_api_version = 19 + min_api_version = 17 } ) @@ -584,7 +584,7 @@ test.register_coroutine_test( end, { test_init = test_init_washer, - min_api_version = 19 + min_api_version = 17 } ) @@ -626,7 +626,7 @@ test.register_coroutine_test( end, { test_init = test_init_dryer, - min_api_version = 19 + min_api_version = 17 } ) @@ -668,7 +668,7 @@ test.register_coroutine_test( end, { test_init = test_init_dryer, - min_api_version = 19 + min_api_version = 17 } ) @@ -710,7 +710,7 @@ test.register_coroutine_test( end, { test_init = test_init_oven, - min_api_version = 19 + min_api_version = 17 } ) @@ -752,7 +752,7 @@ test.register_coroutine_test( end, { test_init = test_init_oven, - min_api_version = 19 + min_api_version = 17 } ) @@ -794,7 +794,7 @@ test.register_coroutine_test( end, { test_init = test_init_refrigerator, - min_api_version = 19 + min_api_version = 17 } ) @@ -836,7 +836,7 @@ test.register_coroutine_test( end, { test_init = test_init_refrigerator, - min_api_version = 19 + min_api_version = 17 } ) @@ -878,7 +878,7 @@ test.register_coroutine_test( end, { test_init = test_init_refrigerator, - min_api_version = 19 + min_api_version = 17 } ) @@ -920,7 +920,7 @@ test.register_coroutine_test( end, { test_init = test_init_refrigerator, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-appliance/src/test/test_microwave_oven.lua b/drivers/SmartThings/matter-appliance/src/test/test_microwave_oven.lua index 14402c5157..cf69721714 100644 --- a/drivers/SmartThings/matter-appliance/src/test/test_microwave_oven.lua +++ b/drivers/SmartThings/matter-appliance/src/test/test_microwave_oven.lua @@ -174,7 +174,7 @@ test.register_message_test( }, -- on receiving NO ERROR we don't do anything. }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -258,7 +258,7 @@ test.register_message_test( test_init() init_supported_microwave_oven_modes() end, - min_api_version = 19 + min_api_version = 17 } ) @@ -338,7 +338,7 @@ test.register_message_test( }, -- on receiving NO ERROR we don't do anything. }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -453,7 +453,7 @@ test.register_message_test( }, -- on receiving NO ERROR we don't do anything. }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -479,7 +479,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-appliance/src/test/test_oven.lua b/drivers/SmartThings/matter-appliance/src/test/test_oven.lua index 8c146f2bd5..905f34d666 100644 --- a/drivers/SmartThings/matter-appliance/src/test/test_oven.lua +++ b/drivers/SmartThings/matter-appliance/src/test/test_oven.lua @@ -143,7 +143,7 @@ test.register_coroutine_test( "Cook Surface Two Endpoint must be 6") end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -228,7 +228,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -287,7 +287,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -371,7 +371,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -411,7 +411,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -437,7 +437,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -475,7 +475,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -513,7 +513,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -535,7 +535,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -557,7 +557,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-appliance/src/test/test_refrigerator.lua b/drivers/SmartThings/matter-appliance/src/test/test_refrigerator.lua index 3158f69298..1210819d51 100644 --- a/drivers/SmartThings/matter-appliance/src/test/test_refrigerator.lua +++ b/drivers/SmartThings/matter-appliance/src/test/test_refrigerator.lua @@ -147,7 +147,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -206,7 +206,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -249,7 +249,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -308,7 +308,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -351,7 +351,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-button/src/test/test_matter_button.lua b/drivers/SmartThings/matter-button/src/test/test_matter_button.lua index 0c703c642d..dfc32bc7cb 100644 --- a/drivers/SmartThings/matter-button/src/test/test_matter_button.lua +++ b/drivers/SmartThings/matter-button/src/test/test_matter_button.lua @@ -71,7 +71,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -109,7 +109,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -148,7 +148,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -196,7 +196,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -220,7 +220,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -244,7 +244,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -268,7 +268,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -308,7 +308,7 @@ test.register_message_test( }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -348,7 +348,7 @@ test.register_message_test( }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -373,7 +373,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) -- run the tests diff --git a/drivers/SmartThings/matter-button/src/test/test_matter_button_parent_child.lua b/drivers/SmartThings/matter-button/src/test/test_matter_button_parent_child.lua index 64396e46f4..01d3b103c7 100644 --- a/drivers/SmartThings/matter-button/src/test/test_matter_button_parent_child.lua +++ b/drivers/SmartThings/matter-button/src/test/test_matter_button_parent_child.lua @@ -136,7 +136,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -170,7 +170,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -213,7 +213,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -237,7 +237,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -261,7 +261,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -295,7 +295,7 @@ test.register_message_test( }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -329,7 +329,7 @@ test.register_message_test( }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -354,7 +354,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) -- run the tests diff --git a/drivers/SmartThings/matter-button/src/test/test_matter_multi_button.lua b/drivers/SmartThings/matter-button/src/test/test_matter_multi_button.lua index 2549698c61..91f3a06494 100644 --- a/drivers/SmartThings/matter-button/src/test/test_matter_multi_button.lua +++ b/drivers/SmartThings/matter-button/src/test/test_matter_multi_button.lua @@ -136,7 +136,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -169,7 +169,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -194,7 +194,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("button2", button_attr.held({state_change = true}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -219,7 +219,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("button3", button_attr.pushed({state_change = true}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -243,7 +243,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -283,7 +283,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("button4", button_attr.double({state_change = true}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -311,7 +311,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -339,7 +339,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -377,7 +377,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -416,7 +416,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -464,7 +464,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -488,7 +488,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -512,7 +512,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -536,7 +536,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -576,7 +576,7 @@ test.register_message_test( }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -616,7 +616,7 @@ test.register_message_test( }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -641,7 +641,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -686,7 +686,7 @@ test.register_message_test( -- no double event }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -744,7 +744,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) -- run the tests diff --git a/drivers/SmartThings/matter-energy/src/test/test_battery_storage.lua b/drivers/SmartThings/matter-energy/src/test/test_battery_storage.lua index a9c652f661..329daa6bd7 100644 --- a/drivers/SmartThings/matter-energy/src/test/test_battery_storage.lua +++ b/drivers/SmartThings/matter-energy/src/test/test_battery_storage.lua @@ -104,7 +104,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) test.register_coroutine_test( @@ -162,7 +162,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -179,7 +179,7 @@ test.register_coroutine_test( capabilities.powerMeter.power({ value = 30.0, unit = "W" }))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -196,7 +196,7 @@ test.register_coroutine_test( capabilities.powerMeter.power({ value = 30.0, unit = "W" }))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -301,7 +301,7 @@ test.register_coroutine_test( test_init = function() test_init() end, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-energy/src/test/test_evse.lua b/drivers/SmartThings/matter-energy/src/test/test_evse.lua index 0aeed44209..5614b0be18 100644 --- a/drivers/SmartThings/matter-energy/src/test/test_evse.lua +++ b/drivers/SmartThings/matter-energy/src/test/test_evse.lua @@ -120,7 +120,7 @@ test.register_coroutine_test( "Device Energy Management Endpoint must be 3") end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -150,7 +150,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -201,7 +201,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -225,7 +225,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -248,7 +248,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -271,7 +271,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -294,7 +294,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -317,7 +317,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -340,7 +340,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -364,7 +364,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -438,7 +438,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -541,7 +541,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-energy/src/test/test_evse_energy_meas.lua b/drivers/SmartThings/matter-energy/src/test/test_evse_energy_meas.lua index ba5d6d6101..f3b3b6c700 100644 --- a/drivers/SmartThings/matter-energy/src/test/test_evse_energy_meas.lua +++ b/drivers/SmartThings/matter-energy/src/test/test_evse_energy_meas.lua @@ -118,7 +118,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -152,7 +152,7 @@ test.register_coroutine_test( test_init = function() test_init() end, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-energy/src/test/test_solar_power.lua b/drivers/SmartThings/matter-energy/src/test/test_solar_power.lua index 0e248624d9..8e4e3c4e9a 100644 --- a/drivers/SmartThings/matter-energy/src/test/test_solar_power.lua +++ b/drivers/SmartThings/matter-energy/src/test/test_solar_power.lua @@ -124,7 +124,7 @@ test.register_coroutine_test( capabilities.powerMeter.power({ value = 35.0, unit = "W" }))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -172,7 +172,7 @@ test.register_coroutine_test( test_init = function() test_init() end, - min_api_version = 19 + min_api_version = 17 } ) @@ -197,7 +197,7 @@ test.register_coroutine_test( clusters.ElectricalEnergyMeasurement.types.EnergyMeasurementStruct({ energy = 100000, start_timestamp = 0, end_timestamp = 0, start_systime = 0, end_systime = 0, apparent_energy = 0, reactive_energy = 0 })) }) --100Wh end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-hrap/src/test/test_thread_border_router_network.lua b/drivers/SmartThings/matter-hrap/src/test/test_thread_border_router_network.lua index f4d2450c58..af8315375f 100644 --- a/drivers/SmartThings/matter-hrap/src/test/test_thread_border_router_network.lua +++ b/drivers/SmartThings/matter-hrap/src/test/test_thread_border_router_network.lua @@ -108,7 +108,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -143,7 +143,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -191,7 +191,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -213,7 +213,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -230,7 +230,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -247,7 +247,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -356,7 +356,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua b/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua index e8a8c3ce24..7752991e47 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua @@ -92,7 +92,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -116,7 +116,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -138,7 +138,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -160,7 +160,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -182,7 +182,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -208,7 +208,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -307,7 +307,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -324,7 +324,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-lock/src/test/test_bridged_matter_lock.lua b/drivers/SmartThings/matter-lock/src/test/test_bridged_matter_lock.lua index 12872290e0..bb7454d27d 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_bridged_matter_lock.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_bridged_matter_lock.lua @@ -93,7 +93,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -104,7 +104,7 @@ test.register_coroutine_test( mock_device_level:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-lock/src/test/test_matter_lock.lua b/drivers/SmartThings/matter-lock/src/test/test_matter_lock.lua index da6a13ecad..2477e2745b 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_matter_lock.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_matter_lock.lua @@ -71,7 +71,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -95,7 +95,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -118,7 +118,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -141,7 +141,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -164,7 +164,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -187,7 +187,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -212,7 +212,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -239,7 +239,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -308,7 +308,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -348,7 +348,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -363,7 +363,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_battery.lua b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_battery.lua index 135cb84c37..18bf34d3b9 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_battery.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_battery.lua @@ -121,7 +121,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "base-lock" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -149,7 +149,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "base-lock-batteryLevel" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -159,7 +159,7 @@ test.register_coroutine_test( end, { test_init = test_init_no_battery, - min_api_version = 19 + min_api_version = 17 } ) test.run_registered_tests() diff --git a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_batteryLevel.lua b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_batteryLevel.lua index 16787f10e5..8bb78f3fce 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_batteryLevel.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_batteryLevel.lua @@ -94,7 +94,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_codes.lua b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_codes.lua index 6bfc5e5bfb..a0a603c6b3 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_codes.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_codes.lua @@ -225,7 +225,7 @@ test.register_coroutine_test( expect_reload_all_codes_messages(mock_device) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -241,7 +241,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -265,7 +265,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -289,7 +289,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -313,7 +313,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -335,7 +335,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -360,7 +360,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -375,7 +375,7 @@ test.register_coroutine_test( expect_reload_all_codes_messages(mock_device) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -420,7 +420,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -458,7 +458,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -564,7 +564,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -613,7 +613,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -673,7 +673,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -708,7 +708,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) test.register_coroutine_test( @@ -742,7 +742,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -784,7 +784,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -827,7 +827,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -906,7 +906,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_cota.lua b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_cota.lua index 143c04763e..72d905d1db 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_cota.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_cota.lua @@ -145,7 +145,7 @@ test.register_coroutine_test( expect_kick_off_cota_process(mock_device) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -162,7 +162,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -179,7 +179,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -214,7 +214,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -238,7 +238,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -340,7 +340,7 @@ test.register_coroutine_test( test.socket.matter:__expect_send({mock_device.id, read_attribute_list}) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -438,7 +438,7 @@ test.register_coroutine_test( test.socket.matter:__expect_send({mock_device.id, read_attribute_list}) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -529,7 +529,7 @@ test.register_coroutine_test( test.socket.matter:__expect_send({mock_device.id, read_attribute_list}) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -589,7 +589,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -629,7 +629,7 @@ test.register_coroutine_test( test.mock_time.advance_time(2) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -710,7 +710,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -745,7 +745,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -753,7 +753,7 @@ test.register_coroutine_test( "Delay setting COTA cred if another cred is already being set.", function() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_modular.lua b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_modular.lua index 842dc9cf63..47b55fb72c 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_modular.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_modular.lua @@ -385,7 +385,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "lock-modular", optional_component_capabilities = {{"main", {"batteryLevel"}}} }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -420,7 +420,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "lock-modular", optional_component_capabilities = {{"main", {"battery"}}} }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -489,7 +489,7 @@ test.register_coroutine_test( end, { test_init = test_init_unlatch, - min_api_version = 19 + min_api_version = 17 } ) @@ -525,7 +525,7 @@ test.register_coroutine_test( end, { test_init = test_init_unlatch, - min_api_version = 19 + min_api_version = 17 } ) @@ -561,7 +561,7 @@ test.register_coroutine_test( end, { test_init = test_init_user_pin, - min_api_version = 19 + min_api_version = 17 } ) @@ -598,7 +598,7 @@ test.register_coroutine_test( end, { test_init = test_init_user_pin_schedule_unlatch, - min_api_version = 19 + min_api_version = 17 } ) @@ -674,7 +674,7 @@ test.register_coroutine_test( end, { test_init = test_init_modular, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_unlatch.lua b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_unlatch.lua index d8d2b9f137..9c1d6bb3a8 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_unlatch.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_unlatch.lua @@ -103,7 +103,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -154,7 +154,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -175,7 +175,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -199,7 +199,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -223,7 +223,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -245,7 +245,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -267,7 +267,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -289,7 +289,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -378,7 +378,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) test.run_registered_tests() diff --git a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua index 4388c61a4a..3742e16e04 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua @@ -112,7 +112,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -163,7 +163,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -183,7 +183,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -203,7 +203,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -223,7 +223,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -243,7 +243,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -263,7 +263,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -283,7 +283,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -354,7 +354,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -435,7 +435,7 @@ function() test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -452,7 +452,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -472,7 +472,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -491,7 +491,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -512,7 +512,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -536,7 +536,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -558,7 +558,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -580,7 +580,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -602,7 +602,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -628,7 +628,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -727,7 +727,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -954,7 +954,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -971,7 +971,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1040,7 +1040,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1067,7 +1067,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1111,7 +1111,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1160,7 +1160,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1187,7 +1187,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1253,7 +1253,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1280,7 +1280,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1346,7 +1346,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1373,7 +1373,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1438,7 +1438,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1467,7 +1467,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1523,7 +1523,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1586,7 +1586,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1642,7 +1642,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1698,7 +1698,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1727,7 +1727,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1781,7 +1781,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1810,7 +1810,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1882,7 +1882,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1911,7 +1911,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1982,7 +1982,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -2011,7 +2011,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -2061,7 +2061,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -2093,7 +2093,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_battery.lua b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_battery.lua index 373c4184ed..d54cb8a0ca 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_battery.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_battery.lua @@ -293,7 +293,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "lock" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -324,7 +324,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "lock-batteryLevel" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -356,7 +356,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "lock-battery" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -387,7 +387,7 @@ test.register_coroutine_test( end, { test_init = test_init_unlatch, - min_api_version = 19 + min_api_version = 17 } ) @@ -419,7 +419,7 @@ test.register_coroutine_test( end, { test_init = test_init_unlatch, - min_api_version = 19 + min_api_version = 17 } ) @@ -452,7 +452,7 @@ test.register_coroutine_test( end, { test_init = test_init_unlatch, - min_api_version = 19 + min_api_version = 17 } ) @@ -483,7 +483,7 @@ test.register_coroutine_test( end, { test_init = test_init_user_pin, - min_api_version = 19 + min_api_version = 17 } ) @@ -515,7 +515,7 @@ test.register_coroutine_test( end, { test_init = test_init_user_pin, - min_api_version = 19 + min_api_version = 17 } ) @@ -548,7 +548,7 @@ test.register_coroutine_test( end, { test_init = test_init_user_pin, - min_api_version = 19 + min_api_version = 17 } ) @@ -579,7 +579,7 @@ test.register_coroutine_test( end, { test_init = test_init_user_pin_schedule_unlatch, - min_api_version = 19 + min_api_version = 17 } ) @@ -611,7 +611,7 @@ test.register_coroutine_test( end, { test_init = test_init_user_pin_schedule_unlatch, - min_api_version = 19 + min_api_version = 17 } ) @@ -644,7 +644,7 @@ test.register_coroutine_test( end, { test_init = test_init_user_pin_schedule_unlatch, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-media/src/test/test_matter_media_speaker.lua b/drivers/SmartThings/matter-media/src/test/test_matter_media_speaker.lua index 80b0c33ff8..b795f6438a 100644 --- a/drivers/SmartThings/matter-media/src/test/test_matter_media_speaker.lua +++ b/drivers/SmartThings/matter-media/src/test/test_matter_media_speaker.lua @@ -126,7 +126,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -167,7 +167,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -213,7 +213,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -335,7 +335,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -366,7 +366,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) test.run_registered_tests() diff --git a/drivers/SmartThings/matter-media/src/test/test_matter_media_video_player.lua b/drivers/SmartThings/matter-media/src/test/test_matter_media_video_player.lua index 296d203b41..dc3a4e4c08 100644 --- a/drivers/SmartThings/matter-media/src/test/test_matter_media_video_player.lua +++ b/drivers/SmartThings/matter-media/src/test/test_matter_media_video_player.lua @@ -240,7 +240,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -278,7 +278,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -316,7 +316,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -354,7 +354,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -395,7 +395,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -436,7 +436,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -605,7 +605,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -638,7 +638,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -671,7 +671,7 @@ test.register_coroutine_test( mock_device_variable_speed:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-rvc/src/test/test_matter_rvc.lua b/drivers/SmartThings/matter-rvc/src/test/test_matter_rvc.lua index 431a6e1c8e..3b03b1a2e1 100644 --- a/drivers/SmartThings/matter-rvc/src/test/test_matter_rvc.lua +++ b/drivers/SmartThings/matter-rvc/src/test/test_matter_rvc.lua @@ -230,7 +230,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -261,7 +261,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -289,7 +289,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -317,7 +317,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -344,7 +344,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -365,7 +365,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -406,7 +406,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -444,7 +444,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -508,7 +508,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -562,7 +562,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -619,7 +619,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -676,7 +676,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -730,7 +730,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -784,7 +784,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1019,7 +1019,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1055,7 +1055,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1081,7 +1081,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1107,7 +1107,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1192,7 +1192,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_air_quality_sensor.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_air_quality_sensor.lua index 734aaad66b..8d3bd462a5 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_air_quality_sensor.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_air_quality_sensor.lua @@ -499,7 +499,7 @@ test.register_coroutine_test( test_aqs_device_type_do_configure(mock_device, "aqs-temp-humidity-all-level-all-meas") end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -510,7 +510,7 @@ test.register_coroutine_test( end, { test_init = test_init_common, - min_api_version = 19 + min_api_version = 17 } ) @@ -521,7 +521,7 @@ test.register_coroutine_test( end, { test_init = test_init_level, - min_api_version = 19 + min_api_version = 17 } ) @@ -533,7 +533,7 @@ test.register_coroutine_test( end, { test_init = test_init_co_co2, - min_api_version = 19 + min_api_version = 17 } ) @@ -544,7 +544,7 @@ test.register_coroutine_test( end, { test_init = test_init_tvoc, - min_api_version = 19 + min_api_version = 17 } ) @@ -568,7 +568,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -590,7 +590,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -625,7 +625,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -695,7 +695,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -720,7 +720,7 @@ test.register_coroutine_test( end, { test_init = test_init_common, - min_api_version = 19 + min_api_version = 17 } ) @@ -828,7 +828,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_air_quality_sensor_modular.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_air_quality_sensor_modular.lua index 28e5d8dc66..ccbcbc74a0 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_air_quality_sensor_modular.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_air_quality_sensor_modular.lua @@ -387,7 +387,7 @@ test.register_coroutine_test( end, { test_init = test_init_all, - min_api_version = 19 + min_api_version = 17 } ) @@ -417,7 +417,7 @@ test.register_coroutine_test( end, { test_init = test_init_common, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_bosch_button_contact.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_bosch_button_contact.lua index b999ac44f9..644c4088e1 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_bosch_button_contact.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_bosch_button_contact.lua @@ -82,7 +82,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -120,7 +120,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -168,7 +168,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -192,7 +192,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -232,7 +232,7 @@ test.register_message_test( }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -257,7 +257,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -292,7 +292,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_flow_sensor.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_flow_sensor.lua index 220ac3c51e..dd4eb87252 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_flow_sensor.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_flow_sensor.lua @@ -71,7 +71,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -101,7 +101,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -133,7 +133,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_freeze_leak_sensor.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_freeze_leak_sensor.lua index 0c05271917..02e5815c06 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_freeze_leak_sensor.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_freeze_leak_sensor.lua @@ -99,7 +99,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -135,7 +135,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -170,7 +170,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -191,7 +191,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -211,7 +211,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -244,7 +244,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_pressure_sensor.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_pressure_sensor.lua index 24659a2426..13bd93ed70 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_pressure_sensor.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_pressure_sensor.lua @@ -94,7 +94,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -116,7 +116,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -148,7 +148,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) test.run_registered_tests() diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_rain_sensor.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_rain_sensor.lua index b25ca9ff96..2b942c6f0c 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_rain_sensor.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_rain_sensor.lua @@ -96,7 +96,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -131,7 +131,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor.lua index 06f7f40fb8..d6024f61be 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor.lua @@ -163,7 +163,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -185,7 +185,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -207,7 +207,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -242,7 +242,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -264,7 +264,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -299,7 +299,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -336,7 +336,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -366,7 +366,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -381,7 +381,7 @@ test.register_coroutine_test( end, { test_init = test_init_presence_sensor, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor_battery.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor_battery.lua index 46b3819baf..0709be6a31 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor_battery.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor_battery.lua @@ -88,7 +88,7 @@ test.register_coroutine_test( mock_device_humidity_battery:expect_metadata_update({ profile = "humidity-battery" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -116,7 +116,7 @@ test.register_coroutine_test( mock_device_humidity_battery:expect_metadata_update({ profile = "humidity-batteryLevel" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -142,7 +142,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor_featuremap.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor_featuremap.lua index b617e317a0..0a02bbb27f 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor_featuremap.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor_featuremap.lua @@ -171,7 +171,7 @@ test.register_coroutine_test( end, { test_init = test_init_humidity_battery, - min_api_version = 19 + min_api_version = 17 } ) @@ -181,7 +181,7 @@ test.register_coroutine_test( end, { test_init = test_init_humidity_no_battery, - min_api_version = 19 + min_api_version = 17 } ) @@ -191,7 +191,7 @@ test.register_coroutine_test( end, { test_init = test_init_temp_humidity, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor_rpc.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor_rpc.lua index cfc6455813..6ca73351c9 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor_rpc.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_sensor_rpc.lua @@ -71,7 +71,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_smoke_co_alarm.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_smoke_co_alarm.lua index 634c9750d7..aeef7b15f9 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_smoke_co_alarm.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_smoke_co_alarm.lua @@ -124,7 +124,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -172,7 +172,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -220,7 +220,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -281,7 +281,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -342,7 +342,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -390,7 +390,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -435,7 +435,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -470,7 +470,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -492,7 +492,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -527,7 +527,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -578,7 +578,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_smoke_co_alarm_battery.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_smoke_co_alarm_battery.lua index b5a3fd9f39..3c8102064e 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_smoke_co_alarm_battery.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_smoke_co_alarm_battery.lua @@ -92,7 +92,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "smoke-co-temp-humidity-comeas-battery" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -107,7 +107,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -127,7 +127,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_aqara_climate_sensor_w100.lua b/drivers/SmartThings/matter-switch/src/test/test_aqara_climate_sensor_w100.lua index 357c1171dd..305c7e682e 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_aqara_climate_sensor_w100.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_aqara_climate_sensor_w100.lua @@ -164,7 +164,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -189,7 +189,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -217,7 +217,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -236,7 +236,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -261,7 +261,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -286,7 +286,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -327,7 +327,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(aqara_mock_device:generate_test_message("button2", capabilities.button.button.double({state_change = true}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -356,7 +356,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -385,7 +385,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -404,7 +404,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -423,7 +423,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -448,7 +448,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -471,7 +471,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -494,7 +494,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_aqara_cube.lua b/drivers/SmartThings/matter-switch/src/test/test_aqara_cube.lua index 5a5eb23b0f..dbda0c35fc 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_aqara_cube.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_aqara_cube.lua @@ -235,7 +235,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -270,7 +270,7 @@ test.register_coroutine_test( end, { test_init = test_init_exhausted, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_aqara_light_switch_h2.lua b/drivers/SmartThings/matter-switch/src/test/test_aqara_light_switch_h2.lua index 9f21039519..667e68ec16 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_aqara_light_switch_h2.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_aqara_light_switch_h2.lua @@ -269,7 +269,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -349,7 +349,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_electrical_sensor_set.lua b/drivers/SmartThings/matter-switch/src/test/test_electrical_sensor_set.lua index ec972534b3..180604431b 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_electrical_sensor_set.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_electrical_sensor_set.lua @@ -231,7 +231,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -264,7 +264,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -294,7 +294,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -362,7 +362,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -387,7 +387,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -449,7 +449,7 @@ test.register_coroutine_test( end, { test_init = test_init_periodic, - min_api_version = 19 + min_api_version = 17 } ) @@ -474,7 +474,7 @@ test.register_coroutine_test( end, { test_init = test_init, - min_api_version = 19 + min_api_version = 17 } ) @@ -489,7 +489,7 @@ test.register_coroutine_test( end, { test_init = test_init_periodic, - min_api_version = 19 + min_api_version = 17 } ) @@ -607,7 +607,7 @@ test.register_coroutine_test( end, { test_init = test_init, - min_api_version = 19 + min_api_version = 17 } ) @@ -678,7 +678,7 @@ test.register_coroutine_test( end, { test_init = test_init_periodic, - min_api_version = 19 + min_api_version = 17 } ) @@ -761,7 +761,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_electrical_sensor_tree.lua b/drivers/SmartThings/matter-switch/src/test/test_electrical_sensor_tree.lua index 37524e4a03..f618389ba6 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_electrical_sensor_tree.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_electrical_sensor_tree.lua @@ -163,7 +163,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -196,7 +196,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -226,7 +226,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -294,7 +294,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -320,7 +320,7 @@ test.register_coroutine_test( end, { test_init = test_init, - min_api_version = 19 + min_api_version = 17 } ) @@ -403,7 +403,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_eve_energy.lua b/drivers/SmartThings/matter-switch/src/test/test_eve_energy.lua index 2f40904cd8..5fa58ce8d3 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_eve_energy.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_eve_energy.lua @@ -182,7 +182,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -215,7 +215,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -235,7 +235,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -250,7 +250,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -283,7 +283,7 @@ test.register_coroutine_test( test.timer.__create_and_queue_test_time_advance_timer(60, "interval", "create_poll_schedule") end, - min_api_version = 19 + min_api_version = 17 } ) @@ -302,7 +302,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -329,7 +329,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -356,7 +356,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -395,7 +395,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -423,7 +423,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -450,7 +450,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -486,7 +486,7 @@ test.register_coroutine_test( test.timer.__create_and_queue_test_time_advance_timer(60 * 15, "interval", "create_poll_report_schedule") test.timer.__create_and_queue_test_time_advance_timer(60, "interval", "create_poll_schedule") end, - min_api_version = 19 + min_api_version = 17 } ) @@ -580,7 +580,7 @@ test.register_coroutine_test( end, { test_init = test_init_electrical_sensor, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_ikea_scroll.lua b/drivers/SmartThings/matter-switch/src/test/test_ikea_scroll.lua index 6e1e0206bc..e07edf6fc9 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_ikea_scroll.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_ikea_scroll.lua @@ -237,7 +237,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -361,7 +361,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -485,7 +485,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -541,7 +541,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -597,7 +597,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -653,7 +653,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -709,7 +709,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -743,7 +743,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -777,7 +777,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_light_illuminance_motion.lua b/drivers/SmartThings/matter-switch/src/test/test_light_illuminance_motion.lua index 36624197b1..ccf952a824 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_light_illuminance_motion.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_light_illuminance_motion.lua @@ -154,7 +154,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -187,7 +187,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -270,7 +270,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -300,7 +300,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -386,7 +386,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -411,7 +411,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -436,7 +436,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -482,7 +482,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -514,7 +514,7 @@ test.register_coroutine_test( end, { test_init = test_init_x_y_color_mode, - min_api_version = 19 + min_api_version = 17 } ) @@ -546,7 +546,7 @@ test.register_coroutine_test( end, { test_init = test_init_x_y_color_mode, - min_api_version = 19 + min_api_version = 17 } ) @@ -578,7 +578,7 @@ test.register_coroutine_test( end, { test_init = test_init_x_y_color_mode, - min_api_version = 19 + min_api_version = 17 } ) @@ -595,7 +595,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -617,7 +617,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -652,7 +652,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_bridge.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_bridge.lua index 42ec81e888..6cb679796d 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_bridge.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_bridge.lua @@ -101,7 +101,7 @@ test.register_coroutine_test( end, { test_init = test_init_mock_bridge, - min_api_version = 19 + min_api_version = 17 } ) @@ -157,7 +157,7 @@ test.register_coroutine_test( end, { test_init = test_init_mock_basic_bridge, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_button.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_button.lua index 7de587d93f..86ce8185bf 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_button.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_button.lua @@ -172,7 +172,7 @@ test.register_coroutine_test( end, { test_init = test_init_battery, - min_api_version = 19 + min_api_version = 17 } ) @@ -196,7 +196,7 @@ test.register_coroutine_test( end, { test_init = test_init_battery, - min_api_version = 19 + min_api_version = 17 } ) @@ -219,7 +219,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -257,7 +257,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -296,7 +296,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -344,7 +344,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -368,7 +368,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -392,7 +392,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -416,7 +416,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -455,7 +455,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -494,7 +494,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -516,7 +516,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -537,7 +537,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "button-batteryLevel" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -558,7 +558,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "button-battery" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua index 1903dc50b7..904a1a3c0a 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua @@ -401,7 +401,7 @@ test.register_coroutine_test( test.socket.matter:__expect_send({mock_device.id, clusters.Switch.attributes.MultiPressMax:read(mock_device, DOORBELL_EP)}) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -451,7 +451,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -494,7 +494,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -523,7 +523,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -567,7 +567,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -598,7 +598,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -648,7 +648,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -673,7 +673,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -726,7 +726,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -850,7 +850,7 @@ test.register_coroutine_test( emit_supported_resolutions() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -868,7 +868,7 @@ test.register_coroutine_test( emit_supported_resolutions() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -886,7 +886,7 @@ test.register_coroutine_test( emit_supported_resolutions() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -941,7 +941,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -965,7 +965,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -983,7 +983,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1001,7 +1001,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1049,7 +1049,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1087,7 +1087,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1113,7 +1113,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1142,7 +1142,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.sounds.selectedSound(2))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1185,7 +1185,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1211,7 +1211,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1251,7 +1251,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1287,7 +1287,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1312,7 +1312,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1379,7 +1379,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1487,7 +1487,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1513,7 +1513,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1538,7 +1538,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1570,7 +1570,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1651,7 +1651,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1683,7 +1683,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1708,7 +1708,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1782,7 +1782,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1855,7 +1855,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1931,7 +1931,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -2037,7 +2037,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -2113,7 +2113,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -2716,7 +2716,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -2758,7 +2758,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("doorbell", capabilities.button.button.pushed({state_change = false}))) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_light_fan.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_light_fan.lua index eb38e516ee..6a8ab5657a 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_light_fan.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_light_fan.lua @@ -218,7 +218,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -264,7 +264,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -313,7 +313,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -349,7 +349,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -374,7 +374,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -399,7 +399,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button.lua index f929b93745..2225ed129b 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button.lua @@ -294,7 +294,7 @@ test.register_coroutine_test( end, { test_init = test_init_battery, - min_api_version = 19 + min_api_version = 17 } ) @@ -318,7 +318,7 @@ test.register_coroutine_test( end, { test_init = test_init_battery, - min_api_version = 19 + min_api_version = 17 } ) @@ -341,7 +341,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -374,7 +374,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -399,7 +399,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("button2", button_attr.held({state_change = true}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -424,7 +424,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("button3", button_attr.pushed({state_change = true}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -448,7 +448,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -488,7 +488,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("button5", button_attr.double({state_change = true}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -516,7 +516,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -544,7 +544,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -582,7 +582,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -621,7 +621,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -669,7 +669,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -693,7 +693,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -717,7 +717,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -741,7 +741,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -780,7 +780,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -819,7 +819,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -843,7 +843,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -887,7 +887,7 @@ test.register_message_test( -- no double event }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -945,7 +945,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -967,7 +967,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -988,7 +988,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "5-button-batteryLevel" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1009,7 +1009,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "5-button-battery" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button_motion.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button_motion.lua index 071c897a35..68fc7e8339 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button_motion.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button_motion.lua @@ -197,7 +197,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -230,7 +230,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -255,7 +255,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("button2", button_attr.held({state_change = true}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -280,7 +280,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("button3", button_attr.pushed({state_change = true}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -304,7 +304,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -344,7 +344,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("button6", button_attr.double({state_change = true}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -372,7 +372,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -391,7 +391,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.motionSensor.motion.inactive())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -419,7 +419,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -457,7 +457,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -496,7 +496,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -544,7 +544,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -568,7 +568,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -592,7 +592,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -616,7 +616,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -656,7 +656,7 @@ test.register_message_test( }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -696,7 +696,7 @@ test.register_message_test( }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -720,7 +720,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -764,7 +764,7 @@ test.register_message_test( -- no double event }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -822,7 +822,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) -- run the tests diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button_switch_mcd.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button_switch_mcd.lua index 2cf394a356..0c4b314791 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button_switch_mcd.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_multi_button_switch_mcd.lua @@ -282,7 +282,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -305,7 +305,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -338,7 +338,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -363,7 +363,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("button3", button_attr.pushed({state_change = true}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -392,7 +392,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_child:generate_test_message("main", capabilities.colorTemperature.colorTemperature(1800))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -457,7 +457,7 @@ test.register_coroutine_test( end, { test_init = test_init_mcd_unsupported_switch_device_type, - min_api_version = 19 + min_api_version = 17 } ) @@ -477,7 +477,7 @@ test.register_coroutine_test( expect_configure_buttons() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -495,7 +495,7 @@ test.register_coroutine_test( expect_configure_buttons() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -509,7 +509,7 @@ test.register_coroutine_test( expect_configure_buttons() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -529,7 +529,7 @@ test.register_coroutine_test( test.socket.device_lifecycle:__queue_receive({ mock_child.id, "doConfigure" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_sensor_offset_preferences.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_sensor_offset_preferences.lua index 642610e88a..3b3cefd8e3 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_sensor_offset_preferences.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_sensor_offset_preferences.lua @@ -102,7 +102,7 @@ test.register_coroutine_test("Read appropriate attribute values after tempOffset }))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -125,7 +125,7 @@ test.register_coroutine_test("Read appropriate attribute values after humidityOf }))) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_switch.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_switch.lua index 189d95d2e9..a1b60be357 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_switch.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_switch.lua @@ -265,7 +265,7 @@ test.register_message_test( {}, { test_init = test_init_color_temp, - min_api_version = 19 + min_api_version = 17 } ) @@ -274,7 +274,7 @@ test.register_message_test( {}, { test_init = test_init_extended_color, - min_api_version = 19 + min_api_version = 17 } ) @@ -307,7 +307,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -340,7 +340,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -424,7 +424,7 @@ test.register_message_test( }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -454,7 +454,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -503,7 +503,7 @@ test.register_coroutine_test( end, { test_init = test_init_no_hue_sat, - min_api_version = 19 + min_api_version = 17 } ) @@ -589,7 +589,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -674,7 +674,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -701,7 +701,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -726,7 +726,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -772,7 +772,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -804,7 +804,7 @@ test.register_coroutine_test( end, { test_init = test_init_x_y_color_mode, - min_api_version = 19 + min_api_version = 17 } ) @@ -836,7 +836,7 @@ test.register_coroutine_test( end, { test_init = test_init_x_y_color_mode, - min_api_version = 19 + min_api_version = 17 } ) @@ -868,7 +868,7 @@ test.register_coroutine_test( end, { test_init = test_init_x_y_color_mode, - min_api_version = 19 + min_api_version = 17 } ) @@ -885,7 +885,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -915,7 +915,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -945,7 +945,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1001,7 +1001,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1063,7 +1063,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1088,7 +1088,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1113,7 +1113,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1143,7 +1143,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1168,7 +1168,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1226,7 +1226,7 @@ test.register_coroutine_test( end, { test_init = test_init_x_y_color_mode, - min_api_version = 19 + min_api_version = 17 } ) @@ -1271,7 +1271,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1289,7 +1289,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_switch_device_types.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_switch_device_types.lua index b45219adca..37b5ec8ca5 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_switch_device_types.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_switch_device_types.lua @@ -676,7 +676,7 @@ test.register_coroutine_test( end, { test_init = test_init_onoff, - min_api_version = 19 + min_api_version = 17 } ) @@ -686,7 +686,7 @@ test.register_coroutine_test( end, { test_init = test_init_dimmer, - min_api_version = 19 + min_api_version = 17 } ) @@ -696,7 +696,7 @@ test.register_coroutine_test( end, { test_init = test_init_color_dimmer, - min_api_version = 19 + min_api_version = 17 } ) @@ -706,7 +706,7 @@ test.register_coroutine_test( end, { test_init = test_init_onoff_client, - min_api_version = 19 + min_api_version = 17 } ) @@ -716,7 +716,7 @@ test.register_coroutine_test( end, { test_init = test_init_switch_vendor_override, - min_api_version = 19 + min_api_version = 17 } ) @@ -726,7 +726,7 @@ test.register_coroutine_test( end, { test_init = test_init_mounted_on_off_control, - min_api_version = 19 + min_api_version = 17 } ) @@ -736,7 +736,7 @@ test.register_coroutine_test( end, { test_init = test_init_mounted_dimmable_load_control, - min_api_version = 19 + min_api_version = 17 } ) @@ -746,7 +746,7 @@ test.register_coroutine_test( end, { test_init = test_init_water_valve, - min_api_version = 19 + min_api_version = 17 } ) @@ -756,7 +756,7 @@ test.register_coroutine_test( end, { test_init = test_init_parent_client_child_server, - min_api_version = 19 + min_api_version = 17 } ) @@ -766,7 +766,7 @@ test.register_coroutine_test( end, { test_init = test_init_parent_child_switch_types, - min_api_version = 19 + min_api_version = 17 } ) @@ -776,7 +776,7 @@ test.register_coroutine_test( end, { test_init = test_init_parent_child_different_types, - min_api_version = 19 + min_api_version = 17 } ) @@ -786,7 +786,7 @@ test.register_coroutine_test( end, { test_init = test_init_parent_child_unsupported_device_type, - min_api_version = 19 + min_api_version = 17 } ) @@ -796,7 +796,7 @@ test.register_coroutine_test( end, { test_init = test_init_light_level_motion, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_water_valve.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_water_valve.lua index 03cf8ee407..338acd58c7 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_water_valve.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_water_valve.lua @@ -87,7 +87,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -112,7 +112,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -137,7 +137,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -162,7 +162,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -184,7 +184,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -206,7 +206,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -228,7 +228,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -250,7 +250,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_multi_switch_mcd.lua b/drivers/SmartThings/matter-switch/src/test/test_multi_switch_mcd.lua index 2fabc37408..7976b27a4a 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_multi_switch_mcd.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_multi_switch_mcd.lua @@ -206,7 +206,7 @@ test.register_message_test( }, { test_init = test_init_mock_3switch, - min_api_version = 19 + min_api_version = 17 } ) @@ -233,7 +233,7 @@ test.register_message_test( }, { test_init = test_init_mock_2switch, - min_api_version = 19 + min_api_version = 17 } ) @@ -260,7 +260,7 @@ test.register_message_test( }, { test_init = test_init_mock_3switch_non_sequential, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_lights.lua b/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_lights.lua index efbb7c4545..8102c61865 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_lights.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_lights.lua @@ -350,7 +350,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -404,7 +404,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -458,7 +458,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -488,7 +488,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -534,7 +534,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -569,7 +569,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -628,7 +628,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -679,7 +679,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -709,7 +709,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -719,7 +719,7 @@ test.register_coroutine_test( end, { test_init = test_init_parent_child_endpoints_non_sequential, - min_api_version = 19 + min_api_version = 17 } ) @@ -732,7 +732,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "light-binary" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_plugs.lua b/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_plugs.lua index edbc775df8..9beed1805e 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_plugs.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_multi_switch_parent_child_plugs.lua @@ -343,7 +343,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -397,7 +397,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -451,7 +451,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -481,7 +481,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -527,7 +527,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -562,7 +562,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -621,7 +621,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -672,7 +672,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -702,7 +702,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -712,7 +712,7 @@ test.register_coroutine_test( end, { test_init = test_init_parent_child_endpoints_non_sequential, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_stateless_step.lua b/drivers/SmartThings/matter-switch/src/test/test_stateless_step.lua index 345d8ad232..8d05070efc 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_stateless_step.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_stateless_step.lua @@ -104,7 +104,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -162,7 +162,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-switch/src/test/test_third_reality_mk1.lua b/drivers/SmartThings/matter-switch/src/test/test_third_reality_mk1.lua index 77c7d7843c..82a8d4d641 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_third_reality_mk1.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_third_reality_mk1.lua @@ -234,7 +234,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_air_purifier.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_air_purifier.lua index 8c0ddad122..0a97b12181 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_air_purifier.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_air_purifier.lua @@ -432,7 +432,7 @@ test.register_coroutine_test( end, { test_init = test_init_ap_aqs, - min_api_version = 19 + min_api_version = 17 } ) @@ -448,7 +448,7 @@ test.register_coroutine_test( end, { test_init = test_init_ap_thermo_aqs, - min_api_version = 19 + min_api_version = 17 } ) @@ -473,7 +473,7 @@ test.register_coroutine_test( end, { test_init = test_init_ap_thermo_aqs_preconfigured, - min_api_version = 19 + min_api_version = 17 } ) @@ -530,7 +530,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -574,7 +574,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -612,7 +612,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -660,7 +660,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -721,7 +721,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -777,7 +777,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -799,7 +799,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -870,7 +870,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -888,7 +888,7 @@ test.register_coroutine_test( end, { test_init = test_init_ap_thermo_aqs_preconfigured, - min_api_version = 19 + min_api_version = 17 } ) @@ -914,7 +914,7 @@ test.register_coroutine_test( end, { test_init = test_init_ap_thermo_aqs_preconfigured, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_air_purifier_api9.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_air_purifier_api9.lua index d16833eda1..8bb8a6c920 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_air_purifier_api9.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_air_purifier_api9.lua @@ -432,7 +432,7 @@ test.register_coroutine_test( end, { test_init = test_init_ap_aqs, - min_api_version = 19 + min_api_version = 17 } ) @@ -448,7 +448,7 @@ test.register_coroutine_test( end, { test_init = test_init_ap_thermo_aqs, - min_api_version = 19 + min_api_version = 17 } ) @@ -473,7 +473,7 @@ test.register_coroutine_test( end, { test_init = test_init_ap_thermo_aqs_preconfigured, - min_api_version = 19 + min_api_version = 17 } ) @@ -530,7 +530,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -574,7 +574,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -612,7 +612,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -660,7 +660,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -721,7 +721,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -778,7 +778,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -800,7 +800,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -872,7 +872,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -890,7 +890,7 @@ test.register_coroutine_test( end, { test_init = test_init_ap_thermo_aqs_preconfigured, - min_api_version = 19 + min_api_version = 17 } ) @@ -916,7 +916,7 @@ test.register_coroutine_test( end, { test_init = test_init_ap_thermo_aqs_preconfigured, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_air_purifier_modular.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_air_purifier_modular.lua index 7ee1a966d4..6aefcb5045 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_air_purifier_modular.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_air_purifier_modular.lua @@ -317,7 +317,7 @@ test.register_coroutine_test( end, { test_init = test_init_basic, - min_api_version = 19 + min_api_version = 17 } ) @@ -394,7 +394,7 @@ test.register_coroutine_test( end, { test_init = test_init_ap_thermo_aqs_preconfigured, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_fan.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_fan.lua index 975a192d9d..91d3303f78 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_fan.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_fan.lua @@ -113,7 +113,7 @@ test.register_coroutine_test( end, { test_init = test_init, - min_api_version = 19 + min_api_version = 17 } ) @@ -128,7 +128,7 @@ test.register_coroutine_test( end, { test_init = test_init_generic, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_heat_pump.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_heat_pump.lua index 8bfd026c24..66c6e593ed 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_heat_pump.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_heat_pump.lua @@ -148,7 +148,7 @@ test.register_coroutine_test( assert(component_to_endpoint_map["thermostatTwo"] == THERMOSTAT_TWO_EP, string.format("Thermostat Two Endpoint must be %d", THERMOSTAT_TWO_EP)) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -193,7 +193,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -238,7 +238,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -279,7 +279,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -320,7 +320,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -387,7 +387,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -475,7 +475,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -546,7 +546,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -613,7 +613,7 @@ test.register_message_test( }, { test_init = test_init_auto, - min_api_version = 19 + min_api_version = 17 } ) @@ -637,7 +637,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -662,7 +662,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -710,7 +710,7 @@ test.register_coroutine_test( test_init = function() test_init() end, - min_api_version = 19 + min_api_version = 17 } ) @@ -763,7 +763,7 @@ test.register_coroutine_test( test_init = function() test_init() end, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_room_ac.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_room_ac.lua index 6dfe993c27..2f7085bff2 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_room_ac.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_room_ac.lua @@ -296,7 +296,7 @@ test.register_coroutine_test( end, { test_init = test_init_configure, - min_api_version = 19 + min_api_version = 17 } ) @@ -317,7 +317,7 @@ test.register_coroutine_test( end, { test_init = test_init_nostate, - min_api_version = 19 + min_api_version = 17 } ) @@ -355,7 +355,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -411,7 +411,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -459,7 +459,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -495,7 +495,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -544,7 +544,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -584,7 +584,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_room_ac_modular.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_room_ac_modular.lua index 6ecbe049aa..aac1ecd4bc 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_room_ac_modular.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_room_ac_modular.lua @@ -314,7 +314,7 @@ test.register_coroutine_test( end, { test_init = test_init_basic, - min_api_version = 19 + min_api_version = 17 } ) @@ -342,7 +342,7 @@ test.register_coroutine_test( end, { test_init = test_init_no_state, - min_api_version = 19 + min_api_version = 17 } ) test.run_registered_tests() diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_battery.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_battery.lua index bb9c637714..5352a65a9d 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_battery.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_battery.lua @@ -107,7 +107,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "thermostat-cooling-only-nostate" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -129,7 +129,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "thermostat-cooling-only-nostate-batteryLevel" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -144,7 +144,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_featuremap.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_featuremap.lua index 328ea848cf..377725fba0 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_featuremap.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_featuremap.lua @@ -228,7 +228,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "thermostat-humidity-fan-heating-only" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -252,7 +252,7 @@ test.register_coroutine_test( test.socket.device_lifecycle:__queue_receive(mock_device:generate_info_changed(updates)) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -277,7 +277,7 @@ test.register_coroutine_test( mock_device_simple:expect_metadata_update({ profile = "thermostat-cooling-only-nostate" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -294,7 +294,7 @@ test.register_coroutine_test( mock_device_no_battery:expect_metadata_update({ profile = "thermostat-cooling-only-nostate-nobattery" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_multiple_device_types.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_multiple_device_types.lua index e9f92b6d2c..4e7704feb1 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_multiple_device_types.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_multiple_device_types.lua @@ -240,7 +240,7 @@ test.register_coroutine_test( get_subscribe_request(mock_device, new_cluster_subscribe_list)) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -252,7 +252,7 @@ test.register_coroutine_test( end, { test_init = test_init_disorder_endpoints, - min_api_version = 19 + min_api_version = 17 } ) @@ -286,7 +286,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_setpoint_limits.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_setpoint_limits.lua index 6f8f7d6412..1d772fb2f1 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_setpoint_limits.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_setpoint_limits.lua @@ -150,7 +150,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -179,7 +179,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -208,7 +208,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -237,7 +237,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -259,7 +259,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -281,7 +281,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -297,7 +297,7 @@ test.register_coroutine_test( assert(min_setpoint_deadband_checked == true, "min_setpoint_deadband_checked is True") end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -327,7 +327,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -357,7 +357,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -387,7 +387,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_setpoint_limits_rpc.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_setpoint_limits_rpc.lua index 3163303942..3dd153d270 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_setpoint_limits_rpc.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_setpoint_limits_rpc.lua @@ -101,7 +101,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -126,7 +126,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -151,7 +151,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat.lua index 4125e20649..d1373c036d 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat.lua @@ -169,7 +169,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -191,7 +191,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -213,7 +213,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -240,7 +240,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -267,7 +267,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -289,7 +289,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -311,7 +311,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -333,7 +333,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -355,7 +355,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -392,7 +392,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -441,7 +441,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -490,7 +490,7 @@ test.register_message_test( }, { test_init = test_init_auto, - min_api_version = 19 + min_api_version = 17 } ) @@ -530,7 +530,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -571,7 +571,7 @@ test.register_message_test( }, { test_init = test_init_auto, - min_api_version = 19 + min_api_version = 17 } ) @@ -623,7 +623,7 @@ test.register_message_test( }, { test_init = test_init_auto, - min_api_version = 19 + min_api_version = 17 } ) @@ -680,7 +680,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -716,7 +716,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -741,7 +741,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -766,7 +766,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -791,7 +791,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -832,7 +832,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -857,7 +857,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -878,7 +878,7 @@ test.register_coroutine_test("Battery percent reports should generate correct me test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -933,7 +933,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat_composed_bridged.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat_composed_bridged.lua index 9e38f59b09..af44bf73f6 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat_composed_bridged.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat_composed_bridged.lua @@ -98,7 +98,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -121,7 +121,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -144,7 +144,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -173,7 +173,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -202,7 +202,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -225,7 +225,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -248,7 +248,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -271,7 +271,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -294,7 +294,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -329,7 +329,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -382,7 +382,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -424,7 +424,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -474,7 +474,7 @@ test.register_message_test( }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -512,7 +512,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -537,7 +537,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -562,7 +562,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -587,7 +587,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -628,7 +628,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -653,7 +653,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -674,7 +674,7 @@ test.register_coroutine_test("Battery percent reports should generate correct me test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -729,7 +729,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat_modular.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat_modular.lua index ed7ffe510f..9108d96096 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat_modular.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat_modular.lua @@ -179,7 +179,7 @@ test.register_coroutine_test( end, { test_init = test_init, - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat_rpc5.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat_rpc5.lua index 0ae634cbc4..f7078703ac 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat_rpc5.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermostat_rpc5.lua @@ -137,7 +137,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_water_heater.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_water_heater.lua index 552715c3bf..b4336beeb4 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_water_heater.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_water_heater.lua @@ -117,7 +117,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -142,7 +142,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -204,7 +204,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -236,7 +236,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -261,7 +261,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -331,7 +331,7 @@ test.register_coroutine_test( test_init = function() test_init() end, - min_api_version = 19 + min_api_version = 17 } ) @@ -433,7 +433,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/matter-window-covering/src/test/test_matter_window_covering.lua b/drivers/SmartThings/matter-window-covering/src/test/test_matter_window_covering.lua index 20f01b6f99..062b199ea1 100644 --- a/drivers/SmartThings/matter-window-covering/src/test/test_matter_window_covering.lua +++ b/drivers/SmartThings/matter-window-covering/src/test/test_matter_window_covering.lua @@ -189,7 +189,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -222,7 +222,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -255,7 +255,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -288,7 +288,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -321,7 +321,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -354,7 +354,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -387,7 +387,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -420,7 +420,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -453,7 +453,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -486,7 +486,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -519,7 +519,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -552,7 +552,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -589,7 +589,7 @@ test.register_coroutine_test("WindowCovering OperationalStatus opening", functio ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -626,7 +626,7 @@ test.register_coroutine_test("WindowCovering OperationalStatus closing", functio ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -663,7 +663,7 @@ test.register_coroutine_test("WindowCovering OperationalStatus unknown", functio ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -681,7 +681,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -699,7 +699,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -717,7 +717,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -749,7 +749,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -765,7 +765,7 @@ test.register_coroutine_test("WindowShade setShadeLevel cmd handler", function() ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -781,7 +781,7 @@ test.register_coroutine_test("WindowShade setShadeTiltLevel cmd handler", functi ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -799,7 +799,7 @@ test.register_coroutine_test("LevelControl CurrentLevel handler", function() ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -821,7 +821,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -844,7 +844,7 @@ test.register_coroutine_test("OperationalStatus report contains current position ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -870,7 +870,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -886,7 +886,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ profile = "window-covering-tilt-battery" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -901,7 +901,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -911,7 +911,7 @@ test.register_coroutine_test( end, { test_init = test_init_mains_powered, - min_api_version = 19 + min_api_version = 17 } ) @@ -926,7 +926,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({profile = "window-covering-tilt-battery"}) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1038,7 +1038,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1112,7 +1112,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1170,7 +1170,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1228,7 +1228,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/virtual-switch/src/test/test_virtual_switch.lua b/drivers/SmartThings/virtual-switch/src/test/test_virtual_switch.lua index 00264417b1..5c284b1e6b 100644 --- a/drivers/SmartThings/virtual-switch/src/test/test_virtual_switch.lua +++ b/drivers/SmartThings/virtual-switch/src/test/test_virtual_switch.lua @@ -46,7 +46,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -65,7 +65,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -84,7 +84,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -104,7 +104,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -123,7 +123,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -148,7 +148,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -169,7 +169,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_simple_device:generate_test_message("main", capabilities.switch.switch.on())) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-air-quality-detector/src/test/test_MultiIR_air_quality_detector.lua b/drivers/SmartThings/zigbee-air-quality-detector/src/test/test_MultiIR_air_quality_detector.lua old mode 100755 new mode 100644 index 73920bcd34..606b716dff --- a/drivers/SmartThings/zigbee-air-quality-detector/src/test/test_MultiIR_air_quality_detector.lua +++ b/drivers/SmartThings/zigbee-air-quality-detector/src/test/test_MultiIR_air_quality_detector.lua @@ -73,7 +73,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({mock_device.id, read_AQI_messge}) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -95,7 +95,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -117,7 +117,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -137,7 +137,7 @@ test.register_coroutine_test( capabilities.carbonDioxideHealthConcern.carbonDioxideHealthConcern({value = "good"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -157,7 +157,7 @@ test.register_coroutine_test( capabilities.fineDustHealthConcern.fineDustHealthConcern.good())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -177,7 +177,7 @@ test.register_coroutine_test( capabilities.veryFineDustHealthConcern.veryFineDustHealthConcern.good())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -197,7 +197,7 @@ test.register_coroutine_test( capabilities.dustHealthConcern.dustHealthConcern.good())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -215,7 +215,7 @@ test.register_coroutine_test( capabilities.formaldehydeMeasurement.formaldehydeLevel({value = 1000.0, unit = "mg/m^3"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -235,7 +235,7 @@ test.register_coroutine_test( capabilities.tvocHealthConcern.tvocHealthConcern({value = "unhealthy"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -253,7 +253,7 @@ test.register_coroutine_test( capabilities.airQualityHealthConcern.airQualityHealthConcern({value = "good"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -271,7 +271,7 @@ test.register_coroutine_test( capabilities.airQualityHealthConcern.airQualityHealthConcern({value = "moderate"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -289,7 +289,7 @@ test.register_coroutine_test( capabilities.airQualityHealthConcern.airQualityHealthConcern({value = "slightlyUnhealthy"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -307,7 +307,7 @@ test.register_coroutine_test( capabilities.airQualityHealthConcern.airQualityHealthConcern({value = "unhealthy"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -325,7 +325,7 @@ test.register_coroutine_test( capabilities.airQualityHealthConcern.airQualityHealthConcern({value = "veryUnhealthy"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -343,7 +343,7 @@ test.register_coroutine_test( capabilities.airQualityHealthConcern.airQualityHealthConcern({value = "hazardous"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -363,7 +363,7 @@ test.register_coroutine_test( capabilities.carbonDioxideHealthConcern.carbonDioxideHealthConcern({value = "moderate"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -383,7 +383,7 @@ test.register_coroutine_test( capabilities.carbonDioxideHealthConcern.carbonDioxideHealthConcern({value = "unhealthy"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -403,7 +403,7 @@ test.register_coroutine_test( capabilities.fineDustHealthConcern.fineDustHealthConcern({value = "moderate"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -423,7 +423,7 @@ test.register_coroutine_test( capabilities.fineDustHealthConcern.fineDustHealthConcern({value = "unhealthy"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -443,7 +443,7 @@ test.register_coroutine_test( capabilities.veryFineDustHealthConcern.veryFineDustHealthConcern({value = "unhealthy"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -463,7 +463,7 @@ test.register_coroutine_test( capabilities.dustHealthConcern.dustHealthConcern({value = "unhealthy"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -483,7 +483,7 @@ test.register_coroutine_test( capabilities.tvocHealthConcern.tvocHealthConcern({value = "good"}))) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-bed/src/test/test_shus_mattress.lua b/drivers/SmartThings/zigbee-bed/src/test/test_shus_mattress.lua old mode 100755 new mode 100644 index bc19893cc6..50c7512838 --- a/drivers/SmartThings/zigbee-bed/src/test/test_shus_mattress.lua +++ b/drivers/SmartThings/zigbee-bed/src/test/test_shus_mattress.lua @@ -85,7 +85,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({mock_device.id, read_0x0011_messge}) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -130,7 +130,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({mock_device.id, read_0x0011_messge}) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -148,7 +148,7 @@ test.register_coroutine_test( custom_capabilities.left_control.leftback.idle({ visibility = { displayed = false }}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -166,7 +166,7 @@ test.register_coroutine_test( custom_capabilities.left_control.leftback.idle({ visibility = { displayed = false }}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -184,7 +184,7 @@ test.register_coroutine_test( custom_capabilities.left_control.leftwaist.idle({ visibility = { displayed = false }}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -202,7 +202,7 @@ test.register_coroutine_test( custom_capabilities.left_control.leftwaist.idle({ visibility = { displayed = false }}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -220,7 +220,7 @@ test.register_coroutine_test( custom_capabilities.left_control.lefthip.idle({ visibility = { displayed = false }}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -238,7 +238,7 @@ test.register_coroutine_test( custom_capabilities.left_control.lefthip.idle({ visibility = { displayed = false }}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -256,7 +256,7 @@ test.register_coroutine_test( custom_capabilities.right_control.rightback.idle({ visibility = { displayed = false }}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -274,7 +274,7 @@ test.register_coroutine_test( custom_capabilities.right_control.rightback.idle({ visibility = { displayed = false }}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -292,7 +292,7 @@ test.register_coroutine_test( custom_capabilities.right_control.rightwaist.idle({ visibility = { displayed = false }}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -310,7 +310,7 @@ test.register_coroutine_test( custom_capabilities.right_control.rightwaist.idle({ visibility = { displayed = false }}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -328,7 +328,7 @@ test.register_coroutine_test( custom_capabilities.right_control.righthip.idle({ visibility = { displayed = false }}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -346,7 +346,7 @@ test.register_coroutine_test( custom_capabilities.right_control.righthip.idle({ visibility = { displayed = false }}))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -364,7 +364,7 @@ test.register_coroutine_test( custom_capabilities.mattressHardness.leftBackHardness(1))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -382,7 +382,7 @@ test.register_coroutine_test( custom_capabilities.mattressHardness.leftWaistHardness(1))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -400,7 +400,7 @@ test.register_coroutine_test( custom_capabilities.mattressHardness.leftHipHardness(1))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -418,7 +418,7 @@ test.register_coroutine_test( custom_capabilities.mattressHardness.rightBackHardness(1))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -436,7 +436,7 @@ test.register_coroutine_test( custom_capabilities.mattressHardness.rightWaistHardness(1))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -454,7 +454,7 @@ test.register_coroutine_test( custom_capabilities.mattressHardness.rightHipHardness(1))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -472,7 +472,7 @@ test.register_coroutine_test( custom_capabilities.yoga.state.both())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -490,7 +490,7 @@ test.register_coroutine_test( custom_capabilities.yoga.state.right())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -508,7 +508,7 @@ test.register_coroutine_test( custom_capabilities.yoga.state.left())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -526,7 +526,7 @@ test.register_coroutine_test( custom_capabilities.yoga.state.stop())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -544,7 +544,7 @@ test.register_coroutine_test( custom_capabilities.ai_mode.left.off())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -562,7 +562,7 @@ test.register_coroutine_test( custom_capabilities.ai_mode.left.on())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -580,7 +580,7 @@ test.register_coroutine_test( custom_capabilities.ai_mode.right.on())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -598,7 +598,7 @@ test.register_coroutine_test( custom_capabilities.ai_mode.right.off())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -616,7 +616,7 @@ test.register_coroutine_test( custom_capabilities.auto_inflation.inflationState.off())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -634,7 +634,7 @@ test.register_coroutine_test( custom_capabilities.auto_inflation.inflationState.on())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -652,7 +652,7 @@ test.register_coroutine_test( custom_capabilities.strong_exp_mode.expState.off())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -670,7 +670,7 @@ test.register_coroutine_test( custom_capabilities.strong_exp_mode.expState.on())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -688,7 +688,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -705,7 +705,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -722,7 +722,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -739,7 +739,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -756,7 +756,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -773,7 +773,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -790,7 +790,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -807,7 +807,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -826,7 +826,7 @@ test.register_coroutine_test( custom_capabilities.left_control.leftback.soft())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -845,7 +845,7 @@ test.register_coroutine_test( custom_capabilities.left_control.leftwaist.soft())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -864,7 +864,7 @@ test.register_coroutine_test( custom_capabilities.left_control.lefthip.soft())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -883,7 +883,7 @@ test.register_coroutine_test( custom_capabilities.left_control.leftback.hard())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -902,7 +902,7 @@ test.register_coroutine_test( custom_capabilities.left_control.leftwaist.hard())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -921,7 +921,7 @@ test.register_coroutine_test( custom_capabilities.left_control.lefthip.hard())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -940,7 +940,7 @@ test.register_coroutine_test( custom_capabilities.right_control.rightback.soft())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -959,7 +959,7 @@ test.register_coroutine_test( custom_capabilities.right_control.rightwaist.soft())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -978,7 +978,7 @@ test.register_coroutine_test( custom_capabilities.right_control.righthip.soft())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -997,7 +997,7 @@ test.register_coroutine_test( custom_capabilities.right_control.rightback.hard())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1016,7 +1016,7 @@ test.register_coroutine_test( custom_capabilities.right_control.rightwaist.hard())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1035,7 +1035,7 @@ test.register_coroutine_test( custom_capabilities.right_control.righthip.hard())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1052,7 +1052,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1069,7 +1069,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1086,7 +1086,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -1111,7 +1111,7 @@ test.register_coroutine_test( custom_capabilities.left_control.leftback("idle", { visibility = { displayed = false }}))) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_SLED_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_SLED_button.lua index 6e4ad5793e..342a62a5c7 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_SLED_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_SLED_button.lua @@ -50,7 +50,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -74,7 +74,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -89,7 +89,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_aduro_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_aduro_button.lua index 2d89507a07..808eb0a764 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_aduro_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_aduro_button.lua @@ -93,7 +93,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -131,7 +131,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -179,7 +179,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_aqara_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_aqara_button.lua index d15ea394b4..49883cd275 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_aqara_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_aqara_button.lua @@ -99,7 +99,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -131,7 +131,7 @@ test.register_coroutine_test( mock_device_e1:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -166,7 +166,7 @@ test.register_coroutine_test( mock_device_h1_double_rocker:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -187,7 +187,7 @@ test.register_coroutine_test( capabilities.button.button.pushed({ state_change = true }))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -208,7 +208,7 @@ test.register_coroutine_test( capabilities.button.button.double({ state_change = true }))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -229,7 +229,7 @@ test.register_coroutine_test( capabilities.button.button.held({ state_change = true }))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -248,7 +248,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) test.register_message_test( @@ -266,7 +266,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) test.register_message_test( @@ -284,7 +284,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -328,7 +328,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -350,7 +350,7 @@ test.register_coroutine_test( capabilities.batteryLevel.quantity(1))) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_centralite_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_centralite_button.lua index f1e0b28ebd..be95f76cce 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_centralite_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_centralite_button.lua @@ -95,7 +95,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -152,7 +152,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -191,7 +191,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -205,7 +205,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -253,7 +253,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_dimming_remote.lua b/drivers/SmartThings/zigbee-button/src/test/test_dimming_remote.lua index d04587e2f0..db9bad6ea9 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_dimming_remote.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_dimming_remote.lua @@ -55,7 +55,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -86,7 +86,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -117,7 +117,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -159,7 +159,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -173,7 +173,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -275,7 +275,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_ewelink_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_ewelink_button.lua index 43d6f95d84..773021ac20 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_ewelink_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_ewelink_button.lua @@ -64,7 +64,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -79,7 +79,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -95,7 +95,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -111,7 +111,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -151,7 +151,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_ezviz_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_ezviz_button.lua index 53242a2e2c..07652b0e0e 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_ezviz_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_ezviz_button.lua @@ -55,7 +55,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -99,7 +99,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -118,7 +118,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -137,7 +137,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -173,7 +173,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({ mock_device_ezviz_button.id, ZoneStatusAttribute:read(mock_device_ezviz_button) }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -199,7 +199,7 @@ test.register_coroutine_test( end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_frient_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_frient_button.lua index 0204586c8a..40d74e503c 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_frient_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_frient_button.lua @@ -88,7 +88,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -113,7 +113,7 @@ test.register_message_test("Refresh should read all necessary attributes", { }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -149,7 +149,7 @@ test.register_coroutine_test("panicAlarm should be triggered and cleared", funct end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -184,7 +184,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -226,7 +226,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -253,7 +253,7 @@ function() test.socket.zigbee:__expect_send({mock_device.id, buttonDelay_msg}) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -286,7 +286,7 @@ test.register_coroutine_test(" Configuration and Switching to button-profile-pan --test.socket.capability:__expect_send({mock_device.id, capabilities.panicAlarm.panicAlarm.clear({state_change = true})}) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -302,7 +302,7 @@ test.register_coroutine_test("Switching from button-profile-panic-frient to butt test.socket.zigbee:__expect_send({mock_device_panic.id, cluster_base.write_manufacturer_specific_attribute(mock_device_panic,BasicInput.ID,0x8000,DEVELCO_MANUFACTURER_CODE,data_types.Uint16,0xFFFF)}) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -324,7 +324,7 @@ test.register_coroutine_test("New preferences after switching the profile should test.socket.zigbee:__expect_send({mock_device_panic.id, cluster_base.write_manufacturer_specific_attribute(mock_device_panic, IASZone.ID,0x8005,DEVELCO_MANUFACTURER_CODE,data_types.Enum8, 1)}) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_heiman_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_heiman_button.lua index 6761cf263c..7e9448ed7e 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_heiman_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_heiman_button.lua @@ -92,7 +92,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -127,7 +127,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -174,7 +174,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -198,7 +198,7 @@ test.register_coroutine_test( mock_device_hs6ssb:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -279,7 +279,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -313,7 +313,7 @@ test.register_coroutine_test( mock_device_hs6ssb:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -361,7 +361,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -409,7 +409,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_ikea_on_off.lua b/drivers/SmartThings/zigbee-button/src/test/test_ikea_on_off.lua index 87e225ae16..4a772c5ab0 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_ikea_on_off.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_ikea_on_off.lua @@ -75,7 +75,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -119,7 +119,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -143,7 +143,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_add_hub_to_group(0xB9F2) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -205,7 +205,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -304,7 +304,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_ikea_open_close.lua b/drivers/SmartThings/zigbee-button/src/test/test_ikea_open_close.lua index a3eb2ef195..d350567294 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_ikea_open_close.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_ikea_open_close.lua @@ -55,7 +55,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -100,7 +100,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -124,7 +124,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_add_hub_to_group(0xB9F2) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -149,7 +149,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({mock_device.id, Groups.commands.AddGroup(mock_device, 0x0000) }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -247,7 +247,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_ikea_remote_control.lua b/drivers/SmartThings/zigbee-button/src/test/test_ikea_remote_control.lua index 6c77739952..1fc0e9d8e6 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_ikea_remote_control.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_ikea_remote_control.lua @@ -109,7 +109,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -154,7 +154,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -179,7 +179,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_add_hub_to_group(0xB9F2) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -286,7 +286,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -305,7 +305,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_iris_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_iris_button.lua index 88fae6eeb2..81e68a52da 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_iris_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_iris_button.lua @@ -47,7 +47,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -63,7 +63,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -105,7 +105,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -123,7 +123,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -177,7 +177,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -198,7 +198,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -219,7 +219,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -240,7 +240,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -261,7 +261,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_linxura_aura_smart_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_linxura_aura_smart_button.lua index 244969abbb..a70d3b52a2 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_linxura_aura_smart_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_linxura_aura_smart_button.lua @@ -57,7 +57,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -76,7 +76,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -95,7 +95,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -115,7 +115,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_linxura_smart_controller_4x_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_linxura_smart_controller_4x_button.lua index 2f22a129c4..35ad7aae08 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_linxura_smart_controller_4x_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_linxura_smart_controller_4x_button.lua @@ -57,7 +57,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -76,7 +76,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -95,7 +95,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -115,7 +115,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_push_only_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_push_only_button.lua index 218bb10615..2f6deceb70 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_push_only_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_push_only_button.lua @@ -48,7 +48,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) test.register_message_test( @@ -61,7 +61,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -80,7 +80,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -99,7 +99,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -164,7 +164,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -219,7 +219,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_robb_4x_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_robb_4x_button.lua index 3f0d63d75b..bbe5cbaf86 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_robb_4x_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_robb_4x_button.lua @@ -81,7 +81,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -124,7 +124,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -169,7 +169,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -212,7 +212,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -326,7 +326,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -368,7 +368,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -386,7 +386,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_robb_8x_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_robb_8x_button.lua index ac1d7f4362..8c291f8483 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_robb_8x_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_robb_8x_button.lua @@ -126,7 +126,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -203,7 +203,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -284,7 +284,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -329,7 +329,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -444,7 +444,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -486,7 +486,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -504,7 +504,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_samjin_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_samjin_button.lua index 4560daa1a0..72bcd2009c 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_samjin_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_samjin_button.lua @@ -90,7 +90,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -140,7 +140,7 @@ test.register_coroutine_test( -- }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_shinasystem_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_shinasystem_button.lua index a0810072f8..d5eed5d55f 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_shinasystem_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_shinasystem_button.lua @@ -85,7 +85,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -142,7 +142,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -199,7 +199,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -239,7 +239,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -287,7 +287,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_somfy_situo_1_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_somfy_situo_1_button.lua index f1339d6155..2793a6de1b 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_somfy_situo_1_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_somfy_situo_1_button.lua @@ -65,7 +65,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -116,7 +116,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -140,7 +140,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_add_hub_to_group(0xB9F2) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -202,7 +202,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -250,7 +250,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_somfy_situo_4_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_somfy_situo_4_button.lua index 2422763c25..9e209541ff 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_somfy_situo_4_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_somfy_situo_4_button.lua @@ -94,7 +94,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -163,7 +163,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -187,7 +187,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_add_hub_to_group(0xB9F2) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -235,7 +235,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_thirdreality_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_thirdreality_button.lua index 560f59940e..f4ee2e0aed 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_thirdreality_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_thirdreality_button.lua @@ -48,7 +48,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -65,7 +65,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.button.button.pushed({ state_change = true }))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -82,7 +82,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.button.button.double({ state_change = true }))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -99,7 +99,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.button.button.held({ state_change = true }))) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_vimar_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_vimar_button.lua index 3e8fc77797..c76d080a01 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_vimar_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_vimar_button.lua @@ -77,7 +77,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -95,7 +95,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -113,7 +113,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -139,7 +139,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -165,7 +165,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -213,7 +213,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_wallhero_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_wallhero_button.lua index 2c95ffe855..93c6d26139 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_wallhero_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_wallhero_button.lua @@ -306,7 +306,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -347,7 +347,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_zigbee_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_zigbee_button.lua index ad7b45ef95..db4f6b9a43 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_zigbee_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_zigbee_button.lua @@ -39,7 +39,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -58,7 +58,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -77,7 +77,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -91,7 +91,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -110,7 +110,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -129,7 +129,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -148,7 +148,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -167,7 +167,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -187,7 +187,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -213,7 +213,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -296,7 +296,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -373,7 +373,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_zigbee_ecosmart_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_zigbee_ecosmart_button.lua index d14c324ff5..1b3078f637 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_zigbee_ecosmart_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_zigbee_ecosmart_button.lua @@ -50,7 +50,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -98,7 +98,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -123,7 +123,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -141,7 +141,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -167,7 +167,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -212,7 +212,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -261,7 +261,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_zunzunbee_8_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_zunzunbee_8_button.lua index eb7e222bcb..13479d4e8b 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_zunzunbee_8_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_zunzunbee_8_button.lua @@ -81,7 +81,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -142,7 +142,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -170,7 +170,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -199,7 +199,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-carbon-monoxide-detector/src/test/test_climax_technology_carbon_monoxide.lua b/drivers/SmartThings/zigbee-carbon-monoxide-detector/src/test/test_climax_technology_carbon_monoxide.lua index 9e74007faa..b0df2ffaa4 100644 --- a/drivers/SmartThings/zigbee-carbon-monoxide-detector/src/test/test_climax_technology_carbon_monoxide.lua +++ b/drivers/SmartThings/zigbee-carbon-monoxide-detector/src/test/test_climax_technology_carbon_monoxide.lua @@ -42,7 +42,7 @@ test.register_message_test( }, { inner_block_ordering = "relaxed", - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-carbon-monoxide-detector/src/test/test_zigbee_carbon_monoxide.lua b/drivers/SmartThings/zigbee-carbon-monoxide-detector/src/test/test_zigbee_carbon_monoxide.lua index abbe814c8e..1b67dc8ee6 100644 --- a/drivers/SmartThings/zigbee-carbon-monoxide-detector/src/test/test_zigbee_carbon_monoxide.lua +++ b/drivers/SmartThings/zigbee-carbon-monoxide-detector/src/test/test_zigbee_carbon_monoxide.lua @@ -44,7 +44,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -71,7 +71,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -99,7 +99,7 @@ test.register_message_test( }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -126,7 +126,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -145,7 +145,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -216,7 +216,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_aqara_contact_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_aqara_contact_sensor.lua index 4243db2bcf..8f6c5ecfdd 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_aqara_contact_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_aqara_contact_sensor.lua @@ -66,7 +66,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -90,7 +90,7 @@ test.register_coroutine_test( capabilities.batteryLevel.battery("normal"))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -108,7 +108,7 @@ test.register_coroutine_test( capabilities.batteryLevel.battery("normal"))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -126,7 +126,7 @@ test.register_coroutine_test( capabilities.batteryLevel.battery("critical"))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -144,7 +144,7 @@ test.register_coroutine_test( capabilities.batteryLevel.battery("normal"))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -162,7 +162,7 @@ test.register_coroutine_test( capabilities.batteryLevel.battery("warning"))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -180,7 +180,7 @@ test.register_coroutine_test( capabilities.batteryLevel.battery("critical"))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -198,7 +198,7 @@ test.register_coroutine_test( capabilities.contactSensor.contact.closed())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -216,7 +216,7 @@ test.register_coroutine_test( capabilities.contactSensor.contact.open())) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_aurora_contact_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_aurora_contact_sensor.lua index dbb8b48dff..a2bcfdf612 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_aurora_contact_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_aurora_contact_sensor.lua @@ -44,7 +44,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({ mock_device.id, PowerConfiguration.attributes.BatteryVoltage:read(mock_device) }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -95,7 +95,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_centralite_multi_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_centralite_multi_sensor.lua index 560356b3d4..b13d48fc2e 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_centralite_multi_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_centralite_multi_sensor.lua @@ -108,7 +108,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({300, 200, 100})) ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -134,7 +134,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.accelerationSensor.acceleration.inactive()) ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -170,7 +170,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.contactSensor.contact.open())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -197,7 +197,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -221,7 +221,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -282,7 +282,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -307,7 +307,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -333,7 +333,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_contact_temperature_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_contact_temperature_sensor.lua index 288856d99d..62e0eee71b 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_contact_temperature_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_contact_temperature_sensor.lua @@ -46,7 +46,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({ mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:read(mock_device) }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -108,7 +108,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -127,7 +127,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -146,7 +146,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_ecolink_contact.lua b/drivers/SmartThings/zigbee-contact/src/test/test_ecolink_contact.lua index 946d7ddad3..e092666737 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_ecolink_contact.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_ecolink_contact.lua @@ -47,7 +47,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({ mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:read(mock_device) }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -117,7 +117,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -136,7 +136,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -155,7 +155,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_ewelink_heiman_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_ewelink_heiman_sensor.lua index 121ac601f2..f3b94929b6 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_ewelink_heiman_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_ewelink_heiman_sensor.lua @@ -45,7 +45,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({ mock_device.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device) }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -96,7 +96,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_frient_contact_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_frient_contact_sensor.lua index a7ae12f907..8be3dd430a 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_frient_contact_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_frient_contact_sensor.lua @@ -48,7 +48,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({ mock_device.id, PowerConfiguration.attributes.BatteryVoltage:read(mock_device) }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -135,7 +135,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -154,7 +154,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -173,7 +173,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -207,7 +207,7 @@ test.register_message_test( }, { inner_block_ordering = "relaxed", - min_api_version = 19 + min_api_version = 17 } ) @@ -226,7 +226,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -245,7 +245,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -264,7 +264,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -283,7 +283,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_frient_contact_sensor_2_pro.lua b/drivers/SmartThings/zigbee-contact/src/test/test_frient_contact_sensor_2_pro.lua index fe875d95f6..f6a2e0ebd9 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_frient_contact_sensor_2_pro.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_frient_contact_sensor_2_pro.lua @@ -56,7 +56,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({ mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:read(mock_device) }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -178,7 +178,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -205,7 +205,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -224,7 +224,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -243,7 +243,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -322,7 +322,7 @@ test.register_message_test( }, { inner_block_ordering = "relaxed", - min_api_version = 19 + min_api_version = 17 } ) @@ -341,7 +341,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -360,7 +360,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -379,7 +379,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -398,7 +398,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -426,7 +426,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_frient_contact_sensor_pro.lua b/drivers/SmartThings/zigbee-contact/src/test/test_frient_contact_sensor_pro.lua index 89f1e00d4e..66881f9f0b 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_frient_contact_sensor_pro.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_frient_contact_sensor_pro.lua @@ -56,7 +56,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({ mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:read(mock_device) }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -178,7 +178,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -205,7 +205,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -224,7 +224,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -243,7 +243,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -322,7 +322,7 @@ test.register_message_test( }, { inner_block_ordering = "relaxed", - min_api_version = 19 + min_api_version = 17 } ) @@ -346,7 +346,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -370,7 +370,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -394,7 +394,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -418,7 +418,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -446,7 +446,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_frient_vibration_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_frient_vibration_sensor.lua index 27dca9b220..7829e32736 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_frient_vibration_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_frient_vibration_sensor.lua @@ -300,7 +300,7 @@ test.register_coroutine_test( mock_device_contact:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -328,7 +328,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -347,7 +347,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -366,7 +366,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -407,7 +407,7 @@ function() }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -431,7 +431,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -455,7 +455,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -477,7 +477,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -505,7 +505,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -533,7 +533,7 @@ test.register_coroutine_test( ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_orvibo_contact_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_orvibo_contact_sensor.lua index 8d75babbb6..6ebb00d45e 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_orvibo_contact_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_orvibo_contact_sensor.lua @@ -44,7 +44,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({ mock_device.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device) }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -95,7 +95,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_samjin_multi_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_samjin_multi_sensor.lua index f564e4dd7e..d4082723c7 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_samjin_multi_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_samjin_multi_sensor.lua @@ -95,7 +95,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -119,7 +119,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -180,7 +180,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -222,7 +222,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_sengled_contact_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_sengled_contact_sensor.lua index 78398bd78e..fc48ab8eaa 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_sengled_contact_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_sengled_contact_sensor.lua @@ -44,7 +44,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({ mock_device.id, PowerConfiguration.attributes.BatteryVoltage:read(mock_device) }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -95,7 +95,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_smartsense_multi.lua b/drivers/SmartThings/zigbee-contact/src/test/test_smartsense_multi.lua index b9d19e6f13..4713e6eb41 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_smartsense_multi.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_smartsense_multi.lua @@ -116,7 +116,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.accelerationSensor.acceleration.active())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -134,7 +134,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(60))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -152,7 +152,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(60))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -170,7 +170,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(60))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -188,7 +188,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(60))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -206,7 +206,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(60))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -224,7 +224,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(60))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -242,7 +242,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(60))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -260,7 +260,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(60))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -278,7 +278,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(97))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -296,7 +296,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(60))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -314,7 +314,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(60))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -332,7 +332,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(0))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -350,7 +350,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(0))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -368,7 +368,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(0))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -383,7 +383,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({1050, 3, 9})) ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -398,7 +398,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({-1050, -3, -9})) ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -413,7 +413,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({10, 1020, 7})) ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -428,7 +428,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({-10, -1020, -7})) ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -443,7 +443,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({116, 4, 1003})) ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -458,7 +458,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({-116, -4, -1003})) ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -491,7 +491,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.contactSensor.contact.open())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -510,7 +510,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -529,7 +529,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -548,7 +548,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -567,7 +567,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_smartthings_multi_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_smartthings_multi_sensor.lua index 1337e696c2..da87c0aee2 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_smartthings_multi_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_smartthings_multi_sensor.lua @@ -89,7 +89,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -108,7 +108,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -134,7 +134,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.accelerationSensor.acceleration.inactive()) ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -151,7 +151,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.accelerationSensor.acceleration.active()) ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -170,7 +170,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({300, 100, -200})) ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -206,7 +206,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.contactSensor.contact.open())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -236,7 +236,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -255,7 +255,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -274,7 +274,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -301,7 +301,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -325,7 +325,7 @@ test.register_coroutine_test( }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -390,7 +390,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -434,7 +434,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_third_reality_contact.lua b/drivers/SmartThings/zigbee-contact/src/test/test_third_reality_contact.lua index 5e6bb70e7d..c03ab49dde 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_third_reality_contact.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_third_reality_contact.lua @@ -44,7 +44,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({ mock_device.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device) }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -95,7 +95,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_thirdreality_multi_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_thirdreality_multi_sensor.lua index 74a6375b01..92f7274365 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_thirdreality_multi_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_thirdreality_multi_sensor.lua @@ -54,7 +54,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.accelerationSensor.acceleration.inactive()) ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -71,7 +71,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.accelerationSensor.acceleration.active()) ) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -90,7 +90,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({200, 100, 300})) ) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact.lua b/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact.lua index de9f7d97ee..f27743d4ee 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact.lua @@ -46,7 +46,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -73,7 +73,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -102,7 +102,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -131,7 +131,7 @@ test.register_message_test( }, }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -159,7 +159,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -185,7 +185,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -205,7 +205,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -250,7 +250,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({ mock_device.id, IASZone.attributes.ZoneStatus:read(mock_device) }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -344,7 +344,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact_battery.lua b/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact_battery.lua index 4f12bdb22c..d908aedba6 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact_battery.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact_battery.lua @@ -88,7 +88,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -108,7 +108,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -128,7 +128,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact_tyco.lua b/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact_tyco.lua index 62151b9baa..6b482996de 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact_tyco.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact_tyco.lua @@ -56,7 +56,7 @@ test.register_coroutine_test( end end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -84,7 +84,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -105,7 +105,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-dimmer-remote/src/test/test_zigbee_accessory_dimmer.lua b/drivers/SmartThings/zigbee-dimmer-remote/src/test/test_zigbee_accessory_dimmer.lua index 6c628b7047..75773fdfea 100644 --- a/drivers/SmartThings/zigbee-dimmer-remote/src/test/test_zigbee_accessory_dimmer.lua +++ b/drivers/SmartThings/zigbee-dimmer-remote/src/test/test_zigbee_accessory_dimmer.lua @@ -61,7 +61,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -83,7 +83,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -102,7 +102,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -121,7 +121,7 @@ test.register_message_test( } }, { - min_api_version = 19 + min_api_version = 17 } ) @@ -137,7 +137,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.switch.switch.on())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -153,7 +153,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.switch.switch.on())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -168,7 +168,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.switchLevel.level(90))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -183,7 +183,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.switchLevel.level(100))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -200,7 +200,7 @@ test.register_coroutine_test( ))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -216,7 +216,7 @@ test.register_coroutine_test( ))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -246,7 +246,7 @@ test.register_coroutine_test( mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -259,7 +259,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.switch.switch.off())) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -276,7 +276,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.switchLevel.level(0))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -293,7 +293,7 @@ test.register_coroutine_test( test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.switchLevel.level(100))) end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -308,7 +308,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -324,7 +324,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) @@ -341,7 +341,7 @@ test.register_coroutine_test( test.wait_for_events() end, { - min_api_version = 19 + min_api_version = 17 } ) diff --git a/drivers/SmartThings/zigbee-dimmer-remote/src/test/test_zigbee_battery_accessory_dimmer.lua b/drivers/SmartThings/zigbee-dimmer-remote/src/test/test_zigbee_battery_accessory_dimmer.lua index a5729b649223637c7620d064eba82a049bfd19a0..b3a1073fe22735c0eacfca41eb835f2c15383a67 100644 GIT binary patch delta 308 zcmccqnDP2!#tnyg7|kbdR8^mRmXB}qPo6c55box)e0x!un+t>zWuTHj_0B;g#WvqF zIK~7P1u^v)H{X^oW1JjsrVJ6Ae9u65a=bn3}+fL5|#9r~&}zQgPn^ delta 282 zcmccqnDP2!#tnygCT~#Hn0%IxZ}U%{HH;w6=CgczQ5c+?D}*9tz*0Z;&Vi)FH{UZj z#sp>PF>bysU&c5&-b@)JGWni?@Z@-V*2yO=WjCKQI|Eh*6Wn~#GKUqWYID3jGc$|> z)S|n2r_&Bp str: + command = f"python3 tools/run_driver_tests.py -v".split(" ") + if test_filter != None: + command = f"python3 tools/run_driver_tests.py --filter {test_filter} -v".split(" ") + + print(f"Running command: {command}") + proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + print(f"Done") + return proc.stdout.decode('utf-8') + +def get_results_from_output(output:str) -> dict: + passing = {} + failing = {} + while (m := re.search(TEST_FILE_REGEX,output)): + # print(m.group(1)) + output = output[m.end():] + + passed = [] + failed = [] + while True: + eot_index = len(output) + if eot := (re.search(r"#{10,}", output) or re.search(TEST_FILE_REGEX, output)): + eot_index = eot.start() + + if t := re.search(TEST_RESULT_REGEX,output[:eot_index]): + if t.group(2) == 'PASSED': + passed.append(t.group(1)) + else: + failed.append(t.group(1)) + output = output[t.end():] + else: + output = output[eot_index:] + break + if len(passed) > 0: + passing[m.group(1)] = passed + if len(failed) > 0: + failing[m.group(1)] = failed + return (passing,failing) + +def show_failing_tests(failing): + for filename in failing: + tests = failing[filename] + print(f"Failing tests for: {filename}") + for tn in tests: + print(f" {tn}") + +def update_passing_tests(passing): + for filename in passing: + # print(f"Parsing file: {filename}") + fn = filename + passing_tests = list(passing[filename]) + + def replace_function(match): + if match.group(2) in passing_tests and int(match.group(3)) > LIBS_VERSION: + return f"{match.group(1)}{LIBS_VERSION}{match.group(4)}" + else: + return match.group(0) + + + with open(filename,'r') as fd: + file_contents = fd.read() + + updated_test_file = re.sub(TEST_CODE_REGEX,replace_function,file_contents) + + with open(filename + ".new", 'w') as fd: + fd.write(updated_test_file) + + os.replace(filename + ".new", filename) + print(f"Updated: {filename}") + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description="""Runs driver tests against lua libs, parses the output of the tests results, + and updates the min_api_version of the tests that successfully passed if the test version is + less than the test's min_api_version.NOTE: this CAN NOT be done if test filtering is active. + If enabled, disable this by temporarily removing the code or commenting it out.""") + parser.add_argument("--filter", "-f", help="Filter of tests to run and update min_api_version for. Argument is passed into the tools/run_driver_tests.py --filter ",default=None) + args = parser.parse_args() + + test_output = capture_test_output(args.filter) + passing, failing = get_results_from_output(test_output) + update_passing_tests(passing) + show_failing_tests(failing) + From 1f6bba99b39987e5a78b9c46e4f7a8cf9a66d574 Mon Sep 17 00:00:00 2001 From: Abdul Samad Date: Thu, 9 Apr 2026 00:08:38 -0500 Subject: [PATCH 08/29] Reinit capabilities upon feature change when profile is unchanged --- .../camera_utils/device_configuration.lua | 4 ++ .../src/sub_drivers/camera/init.lua | 6 +- .../src/test/test_matter_camera.lua | 65 +++++++++++++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua index f709d25420..88b3ccd1b7 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua @@ -42,6 +42,7 @@ function CameraDeviceConfiguration.create_child_devices(driver, device) end function CameraDeviceConfiguration.match_profile(device, status_light_enabled_present, status_light_brightness_present) + local profile_update_requested = false local optional_supported_component_capabilities = {} local main_component_capabilities = {} local status_led_component_capabilities = {} @@ -145,12 +146,15 @@ function CameraDeviceConfiguration.match_profile(device, status_light_enabled_pr end if camera_utils.optional_capabilities_list_changed(optional_supported_component_capabilities, device.profile.components) then + profile_update_requested = true device:try_update_metadata({profile = "camera", optional_component_capabilities = optional_supported_component_capabilities}) if #doorbell_endpoints > 0 then CameraDeviceConfiguration.update_doorbell_component_map(device, doorbell_endpoints[1]) button_cfg.configure_buttons(device, device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH})) end end + + return profile_update_requested end local function init_webrtc(device) diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua index 91ebe03ebc..1dbad05698 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua @@ -49,12 +49,14 @@ end function CameraLifecycleHandlers.info_changed(driver, device, event, args) local software_version_changed = device.matter_version ~= nil and args.old_st_store.matter_version ~= nil and device.matter_version.software ~= args.old_st_store.matter_version.software + local profile_update_requested = false + local profile_changed = not switch_utils.deep_equals(device.profile, args.old_st_store.profile, { ignore_functions = true }) if software_version_changed then - camera_cfg.match_profile(device, false, false) + profile_update_requested = camera_cfg.match_profile(device, false, false) end - if not switch_utils.deep_equals(device.profile, args.old_st_store.profile, { ignore_functions = true }) then + if profile_changed or (software_version_changed and not profile_update_requested) then camera_cfg.initialize_camera_capabilities(device) device:subscribe() if #switch_utils.get_endpoints_by_device_type(device, fields.DEVICE_TYPE_ID.DOORBELL) > 0 then diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua index 904a1a3c0a..bdb2fe468b 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua @@ -405,6 +405,71 @@ test.register_coroutine_test( } ) +test.register_coroutine_test( + "Software version change should initialize camera capabilities when profile is unchanged", + function() + local camera_handler = require "sub_drivers.camera" + local camera_cfg = require "sub_drivers.camera.camera_utils.device_configuration" + local button_cfg = require("switch_utils.device_configuration").ButtonCfg + + local match_profile_called = false + local init_called = false + local subscribe_called = false + local configure_buttons_called = false + + local fake_device = { + matter_version = { hardware = 1, software = 3 }, + profile = { id = "camera" }, + endpoints = { + { + endpoint_id = CAMERA_EP, + device_types = { + {device_type_id = 0x0142, device_type_revision = 1} -- Camera + } + }, + { + endpoint_id = DOORBELL_EP, + device_types = { + {device_type_id = 0x0143, device_type_revision = 1} -- Doorbell + } + } + }, + subscribe = function() subscribe_called = true end, + get_endpoints = function() return { DOORBELL_EP } end, + } + + local original_match_profile = camera_cfg.match_profile + local original_init = camera_cfg.initialize_camera_capabilities + local original_configure_buttons = button_cfg.configure_buttons + + camera_cfg.match_profile = function() + match_profile_called = true + return false + end + camera_cfg.initialize_camera_capabilities = function() init_called = true end + button_cfg.configure_buttons = function() configure_buttons_called = true end + + camera_handler.lifecycle_handlers.infoChanged(nil, fake_device, nil, { + old_st_store = { + matter_version = { hardware = 1, software = 1 }, + profile = fake_device.profile, + } + }) + + camera_cfg.match_profile = original_match_profile + camera_cfg.initialize_camera_capabilities = original_init + button_cfg.configure_buttons = original_configure_buttons + + assert(match_profile_called, "match_profile should be called on software version change") + assert(init_called, "initialize_camera_capabilities should be called") + assert(subscribe_called, "subscribe should be called") + assert(configure_buttons_called, "configure_buttons should be called") + end, + { + min_api_version = 17 + } +) + test.register_coroutine_test( "Reports mapping to EnabledState capability data type should generate appropriate events", function() From 13abb8c0286fbb3c1e5962c0e70984a5390134d3 Mon Sep 17 00:00:00 2001 From: Abdul Samad Date: Thu, 9 Apr 2026 13:02:41 -0500 Subject: [PATCH 09/29] Handle FeatureMap change, fix profile matching & reinit --- .../camera_handlers/attribute_handlers.lua | 7 +- .../camera_utils/device_configuration.lua | 302 ++++++++++++++---- .../camera/camera_utils/fields.lua | 6 + .../sub_drivers/camera/camera_utils/utils.lua | 25 +- .../src/sub_drivers/camera/init.lua | 27 +- .../src/test/test_matter_camera.lua | 47 ++- 6 files changed, 328 insertions(+), 86 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_handlers/attribute_handlers.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_handlers/attribute_handlers.lua index 140ba6d313..b32b1dd55c 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_handlers/attribute_handlers.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_handlers/attribute_handlers.lua @@ -466,7 +466,12 @@ function CameraAttributeHandlers.camera_av_stream_management_attribute_list_hand attribute_ids = attribute_ids, } device:set_field(fields.COMPONENT_TO_ENDPOINT_MAP, component_map, {persist=true}) - camera_cfg.match_profile(device, status_light_enabled_present, status_light_brightness_present) + camera_cfg.update_status_light_attribute_presence(device, status_light_enabled_present, status_light_brightness_present) + camera_cfg.reconcile_profile_and_capabilities(device) +end + +function CameraAttributeHandlers.camera_feature_map_handler(driver, device, ib, response) + camera_cfg.reconcile_profile_and_capabilities(device) end return CameraAttributeHandlers diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua index 88b3ccd1b7..c2ea259aa1 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua @@ -12,6 +12,152 @@ local switch_utils = require "switch_utils.utils" local CameraDeviceConfiguration = {} +local managed_capability_map = { + { key = "webrtc", capability = capabilities.webrtc }, + { key = "ptz", capability = capabilities.mechanicalPanTiltZoom }, + { key = "zone_management", capability = capabilities.zoneManagement }, + { key = "local_media_storage", capability = capabilities.localMediaStorage }, + { key = "audio_recording", capability = capabilities.audioRecording }, + { key = "video_stream_settings", capability = capabilities.videoStreamSettings }, + { key = "camera_privacy_mode", capability = capabilities.cameraPrivacyMode }, +} + +local function get_status_light_presence(device) + return device:get_field(camera_fields.STATUS_LIGHT_ENABLED_PRESENT), + device:get_field(camera_fields.STATUS_LIGHT_BRIGHTNESS_PRESENT) +end + +local function set_status_light_presence(device, status_light_enabled_present, status_light_brightness_present) + device:set_field(camera_fields.STATUS_LIGHT_ENABLED_PRESENT, status_light_enabled_present == true, { persist = true }) + device:set_field(camera_fields.STATUS_LIGHT_BRIGHTNESS_PRESENT, status_light_brightness_present == true, { persist = true }) +end + +local function build_webrtc_supported_features() + return { + bundle = true, + order = "audio/video", + audio = "sendrecv", + video = "recvonly", + turnSource = "player", + supportTrickleICE = true + } +end + +local function build_ptz_supported_attributes(device) + local supported_attributes = {} + if camera_utils.feature_supported(device, clusters.CameraAvSettingsUserLevelManagement.ID, clusters.CameraAvSettingsUserLevelManagement.types.Feature.MPAN) then + table.insert(supported_attributes, "pan") + table.insert(supported_attributes, "panRange") + end + if camera_utils.feature_supported(device, clusters.CameraAvSettingsUserLevelManagement.ID, clusters.CameraAvSettingsUserLevelManagement.types.Feature.MTILT) then + table.insert(supported_attributes, "tilt") + table.insert(supported_attributes, "tiltRange") + end + if camera_utils.feature_supported(device, clusters.CameraAvSettingsUserLevelManagement.ID, clusters.CameraAvSettingsUserLevelManagement.types.Feature.MZOOM) then + table.insert(supported_attributes, "zoom") + table.insert(supported_attributes, "zoomRange") + end + if camera_utils.feature_supported(device, clusters.CameraAvSettingsUserLevelManagement.ID, clusters.CameraAvSettingsUserLevelManagement.types.Feature.MPRESETS) then + table.insert(supported_attributes, "presets") + table.insert(supported_attributes, "maxPresets") + end + return supported_attributes +end + +local function build_zone_management_supported_features(device) + local supported_features = { "triggerAugmentation" } + if camera_utils.feature_supported(device, clusters.ZoneManagement.ID, clusters.ZoneManagement.types.Feature.PER_ZONE_SENSITIVITY) then + table.insert(supported_features, "perZoneSensitivity") + end + return supported_features +end + +local function build_local_media_storage_supported_attributes(device) + local supported_attributes = {} + if camera_utils.feature_supported(device, clusters.CameraAvStreamManagement.ID, clusters.CameraAvStreamManagement.types.Feature.VIDEO) then + table.insert(supported_attributes, "localVideoRecording") + end + if camera_utils.feature_supported(device, clusters.CameraAvStreamManagement.ID, clusters.CameraAvStreamManagement.types.Feature.SNAPSHOT) then + table.insert(supported_attributes, "localSnapshotRecording") + end + return supported_attributes +end + +local function build_video_stream_settings_supported_features(device) + local supported_features = {} + if camera_utils.feature_supported(device, clusters.CameraAvStreamManagement.ID, clusters.CameraAvStreamManagement.types.Feature.VIDEO) then + table.insert(supported_features, "liveStreaming") + table.insert(supported_features, "clipRecording") + table.insert(supported_features, "perStreamViewports") + end + if camera_utils.feature_supported(device, clusters.CameraAvStreamManagement.ID, clusters.CameraAvStreamManagement.types.Feature.WATERMARK) then + table.insert(supported_features, "watermark") + end + if camera_utils.feature_supported(device, clusters.CameraAvStreamManagement.ID, clusters.CameraAvStreamManagement.types.Feature.ON_SCREEN_DISPLAY) then + table.insert(supported_features, "onScreenDisplay") + end + return supported_features +end + +local function build_camera_privacy_supported_attributes() + return { "softRecordingPrivacyMode", "softLivestreamPrivacyMode" } +end + +local function build_camera_privacy_supported_commands() + return { "setSoftRecordingPrivacyMode", "setSoftLivestreamPrivacyMode" } +end + +local function capabilities_needing_reinit(device) + local main = camera_fields.profile_components.main + + local capabilities_to_reinit = {} + + local function state_differs(capability, attribute_name, expected) + local current = device:get_latest_state(main, capability.ID, attribute_name) + return not switch_utils.deep_equals(current, expected, { ignore_functions = true }) + end + + if device:supports_capability(capabilities.webrtc) and + state_differs(capabilities.webrtc, capabilities.webrtc.supportedFeatures.NAME, build_webrtc_supported_features()) then + capabilities_to_reinit.webrtc = true + end + + if device:supports_capability(capabilities.mechanicalPanTiltZoom) and + state_differs(capabilities.mechanicalPanTiltZoom, capabilities.mechanicalPanTiltZoom.supportedAttributes.NAME, build_ptz_supported_attributes(device)) then + capabilities_to_reinit.ptz = true + end + + if device:supports_capability(capabilities.zoneManagement) and + state_differs(capabilities.zoneManagement, capabilities.zoneManagement.supportedFeatures.NAME, build_zone_management_supported_features(device)) then + capabilities_to_reinit.zone_management = true + end + + if device:supports_capability(capabilities.localMediaStorage) and + state_differs(capabilities.localMediaStorage, capabilities.localMediaStorage.supportedAttributes.NAME, build_local_media_storage_supported_attributes(device)) then + capabilities_to_reinit.local_media_storage = true + end + + if device:supports_capability(capabilities.audioRecording) then + local audio_enabled_state = device:get_latest_state(main, capabilities.audioRecording.ID, capabilities.audioRecording.audioRecording.NAME) + if audio_enabled_state == nil then + capabilities_to_reinit.audio_recording = true + end + end + + if device:supports_capability(capabilities.videoStreamSettings) and + state_differs(capabilities.videoStreamSettings, capabilities.videoStreamSettings.supportedFeatures.NAME, build_video_stream_settings_supported_features(device)) then + capabilities_to_reinit.video_stream_settings = true + end + + if device:supports_capability(capabilities.cameraPrivacyMode) and + (state_differs(capabilities.cameraPrivacyMode, capabilities.cameraPrivacyMode.supportedAttributes.NAME, build_camera_privacy_supported_attributes()) or + state_differs(capabilities.cameraPrivacyMode, capabilities.cameraPrivacyMode.supportedCommands.NAME, build_camera_privacy_supported_commands())) then + capabilities_to_reinit.camera_privacy_mode = true + end + + return capabilities_to_reinit +end + function CameraDeviceConfiguration.create_child_devices(driver, device) local num_floodlight_eps = 0 local parent_child_device = false @@ -41,7 +187,8 @@ function CameraDeviceConfiguration.create_child_devices(driver, device) end end -function CameraDeviceConfiguration.match_profile(device, status_light_enabled_present, status_light_brightness_present) +function CameraDeviceConfiguration.match_profile(device) + local status_light_enabled_present, status_light_brightness_present = get_status_light_presence(device) local profile_update_requested = false local optional_supported_component_capabilities = {} local main_component_capabilities = {} @@ -159,68 +306,29 @@ end local function init_webrtc(device) if device:supports_capability(capabilities.webrtc) then - -- TODO: Check for individual audio/video and talkback features local transport_provider_ep_ids = device:get_endpoints(clusters.WebRTCTransportProvider.ID) - device:emit_event_for_endpoint(transport_provider_ep_ids[1], capabilities.webrtc.supportedFeatures({ - value = { - bundle = true, - order = "audio/video", - audio = "sendrecv", - video = "recvonly", - turnSource = "player", - supportTrickleICE = true - } - })) + device:emit_event_for_endpoint(transport_provider_ep_ids[1], capabilities.webrtc.supportedFeatures(build_webrtc_supported_features())) end end local function init_ptz(device) if device:supports_capability(capabilities.mechanicalPanTiltZoom) then - local supported_attributes = {} - if camera_utils.feature_supported(device, clusters.CameraAvSettingsUserLevelManagement.ID, clusters.CameraAvSettingsUserLevelManagement.types.Feature.MPAN) then - table.insert(supported_attributes, "pan") - table.insert(supported_attributes, "panRange") - end - if camera_utils.feature_supported(device, clusters.CameraAvSettingsUserLevelManagement.ID, clusters.CameraAvSettingsUserLevelManagement.types.Feature.MTILT) then - table.insert(supported_attributes, "tilt") - table.insert(supported_attributes, "tiltRange") - end - if camera_utils.feature_supported(device, clusters.CameraAvSettingsUserLevelManagement.ID, clusters.CameraAvSettingsUserLevelManagement.types.Feature.MZOOM) then - table.insert(supported_attributes, "zoom") - table.insert(supported_attributes, "zoomRange") - end - if camera_utils.feature_supported(device, clusters.CameraAvSettingsUserLevelManagement.ID, clusters.CameraAvSettingsUserLevelManagement.types.Feature.MPRESETS) then - table.insert(supported_attributes, "presets") - table.insert(supported_attributes, "maxPresets") - end local av_settings_ep_ids = device:get_endpoints(clusters.CameraAvSettingsUserLevelManagement.ID) - device:emit_event_for_endpoint(av_settings_ep_ids[1], capabilities.mechanicalPanTiltZoom.supportedAttributes(supported_attributes)) + device:emit_event_for_endpoint(av_settings_ep_ids[1], capabilities.mechanicalPanTiltZoom.supportedAttributes(build_ptz_supported_attributes(device))) end end local function init_zone_management(device) if device:supports_capability(capabilities.zoneManagement) then - local supported_features = {} - table.insert(supported_features, "triggerAugmentation") - if camera_utils.feature_supported(device, clusters.ZoneManagement.ID, clusters.ZoneManagement.types.Feature.PER_ZONE_SENSITIVITY) then - table.insert(supported_features, "perZoneSensitivity") - end local zone_management_ep_ids = device:get_endpoints(clusters.ZoneManagement.ID) - device:emit_event_for_endpoint(zone_management_ep_ids[1], capabilities.zoneManagement.supportedFeatures(supported_features)) + device:emit_event_for_endpoint(zone_management_ep_ids[1], capabilities.zoneManagement.supportedFeatures(build_zone_management_supported_features(device))) end end local function init_local_media_storage(device) if device:supports_capability(capabilities.localMediaStorage) then - local supported_attributes = {} - if camera_utils.feature_supported(device, clusters.CameraAvStreamManagement.ID, clusters.CameraAvStreamManagement.types.Feature.VIDEO) then - table.insert(supported_attributes, "localVideoRecording") - end - if camera_utils.feature_supported(device, clusters.CameraAvStreamManagement.ID, clusters.CameraAvStreamManagement.types.Feature.SNAPSHOT) then - table.insert(supported_attributes, "localSnapshotRecording") - end local av_stream_management_ep_ids = device:get_endpoints(clusters.CameraAvStreamManagement.ID) - device:emit_event_for_endpoint(av_stream_management_ep_ids[1], capabilities.localMediaStorage.supportedAttributes(supported_attributes)) + device:emit_event_for_endpoint(av_stream_management_ep_ids[1], capabilities.localMediaStorage.supportedAttributes(build_local_media_storage_supported_attributes(device))) end end @@ -239,33 +347,16 @@ end local function init_video_stream_settings(device) if device:supports_capability(capabilities.videoStreamSettings) then - local supported_features = {} - if camera_utils.feature_supported(device, clusters.CameraAvStreamManagement.ID, clusters.CameraAvStreamManagement.types.Feature.VIDEO) then - table.insert(supported_features, "liveStreaming") - table.insert(supported_features, "clipRecording") - table.insert(supported_features, "perStreamViewports") - end - if camera_utils.feature_supported(device, clusters.CameraAvStreamManagement.ID, clusters.CameraAvStreamManagement.types.Feature.WATERMARK) then - table.insert(supported_features, "watermark") - end - if camera_utils.feature_supported(device, clusters.CameraAvStreamManagement.ID, clusters.CameraAvStreamManagement.types.Feature.ON_SCREEN_DISPLAY) then - table.insert(supported_features, "onScreenDisplay") - end local av_stream_management_ep_ids = device:get_endpoints(clusters.CameraAvStreamManagement.ID) - device:emit_event_for_endpoint(av_stream_management_ep_ids[1], capabilities.videoStreamSettings.supportedFeatures(supported_features)) + device:emit_event_for_endpoint(av_stream_management_ep_ids[1], capabilities.videoStreamSettings.supportedFeatures(build_video_stream_settings_supported_features(device))) end end local function init_camera_privacy_mode(device) if device:supports_capability(capabilities.cameraPrivacyMode) then - local supported_attributes, supported_commands = {}, {} - table.insert(supported_attributes, "softRecordingPrivacyMode") - table.insert(supported_attributes, "softLivestreamPrivacyMode") - table.insert(supported_commands, "setSoftRecordingPrivacyMode") - table.insert(supported_commands, "setSoftLivestreamPrivacyMode") local av_stream_management_ep_ids = device:get_endpoints(clusters.CameraAvStreamManagement.ID) - device:emit_event_for_endpoint(av_stream_management_ep_ids[1], capabilities.cameraPrivacyMode.supportedAttributes(supported_attributes)) - device:emit_event_for_endpoint(av_stream_management_ep_ids[1], capabilities.cameraPrivacyMode.supportedCommands(supported_commands)) + device:emit_event_for_endpoint(av_stream_management_ep_ids[1], capabilities.cameraPrivacyMode.supportedAttributes(build_camera_privacy_supported_attributes())) + device:emit_event_for_endpoint(av_stream_management_ep_ids[1], capabilities.cameraPrivacyMode.supportedCommands(build_camera_privacy_supported_commands())) end end @@ -279,6 +370,89 @@ function CameraDeviceConfiguration.initialize_camera_capabilities(device) init_camera_privacy_mode(device) end +function CameraDeviceConfiguration.initialize_camera_capabilities_and_subscriptions(device) + CameraDeviceConfiguration.initialize_camera_capabilities(device) + device:subscribe() + if #switch_utils.get_endpoints_by_device_type(device, fields.DEVICE_TYPE_ID.DOORBELL) > 0 then + button_cfg.configure_buttons(device, device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH})) + end +end + +local function initialize_selected_camera_capabilities(device, capabilities_to_reinit) + local reinit_targets = capabilities_to_reinit or {} + + if reinit_targets.webrtc then + init_webrtc(device) + end + if reinit_targets.ptz then + init_ptz(device) + end + if reinit_targets.zone_management then + init_zone_management(device) + end + if reinit_targets.local_media_storage then + init_local_media_storage(device) + end + if reinit_targets.audio_recording then + init_audio_recording(device) + end + if reinit_targets.video_stream_settings then + init_video_stream_settings(device) + end + if reinit_targets.camera_privacy_mode then + init_camera_privacy_mode(device) + end +end + +local function profile_capability_set(profile) + local capability_set = {} + for _, component in pairs((profile or {}).components or {}) do + for _, capability in ipairs(component.capabilities or {}) do + if capability.id ~= nil then + capability_set[capability.id] = true + end + end + end + return capability_set +end + +local function changed_capabilities_from_profiles(old_profile, new_profile) + local flags = {} + local old_set = profile_capability_set(old_profile) + local new_set = profile_capability_set(new_profile) + + for _, managed in ipairs(managed_capability_map) do + local id = managed.capability.ID + if old_set[id] ~= new_set[id] and new_set[id] == true then + flags[managed.key] = true + end + end + + return flags +end + +function CameraDeviceConfiguration.reconcile_profile_and_capabilities(device) + local profile_update_requested = CameraDeviceConfiguration.match_profile(device) + if not profile_update_requested then + local capabilities_to_reinit = capabilities_needing_reinit(device) + initialize_selected_camera_capabilities(device, capabilities_to_reinit) + end + return profile_update_requested +end + +function CameraDeviceConfiguration.update_status_light_attribute_presence(device, status_light_enabled_present, status_light_brightness_present) + set_status_light_presence(device, status_light_enabled_present, status_light_brightness_present) +end + +function CameraDeviceConfiguration.reinitialize_changed_camera_capabilities_and_subscriptions(device, old_profile, new_profile) + local changed_capabilities = changed_capabilities_from_profiles(old_profile, new_profile) + initialize_selected_camera_capabilities(device, changed_capabilities) + device:subscribe() + if #switch_utils.get_endpoints_by_device_type(device, fields.DEVICE_TYPE_ID.DOORBELL) > 0 then + button_cfg.configure_buttons(device, device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH})) + end +end + function CameraDeviceConfiguration.update_doorbell_component_map(device, ep) local component_map = device:get_field(fields.COMPONENT_TO_ENDPOINT_MAP) or {} component_map.doorbell = ep diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/fields.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/fields.lua index 000008fa51..c88f177707 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/fields.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/fields.lua @@ -14,6 +14,12 @@ CameraFields.MAX_RESOLUTION = "__max_resolution" CameraFields.MIN_RESOLUTION = "__min_resolution" CameraFields.TRIGGERED_ZONES = "__triggered_zones" CameraFields.DPTZ_VIEWPORTS = "__dptz_viewports" +CameraFields.STATUS_LIGHT_ENABLED_PRESENT = "__status_light_enabled_present" +CameraFields.STATUS_LIGHT_BRIGHTNESS_PRESENT = "__status_light_brightness_present" + +CameraFields.CameraAVSMFeatureMapAttr = { ID = 0xFFFC, cluster = clusters.CameraAvStreamManagement.ID } +CameraFields.CameraAVSULMFeatureMapAttr = { ID = 0xFFFC, cluster = clusters.CameraAvSettingsUserLevelManagement.ID } +CameraFields.ZoneManagementFeatureMapAttr = { ID = 0xFFFC, cluster = clusters.ZoneManagement.ID } CameraFields.PAN_IDX = "PAN" CameraFields.TILT_IDX = "TILT" diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/utils.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/utils.lua index 5793c1d9fc..f3b92aa3b6 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/utils.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/utils.lua @@ -6,6 +6,7 @@ local capabilities = require "st.capabilities" local clusters = require "st.matter.clusters" local fields = require "switch_utils.fields" local switch_utils = require "switch_utils.utils" +local cluster_base = require "st.matter.cluster_base" local CameraUtils = {} @@ -297,10 +298,19 @@ function CameraUtils.subscribe(device) local subscribe_request = im.InteractionRequest(im.InteractionRequest.RequestType.SUBSCRIBE, {}) local devices_seen, capabilities_seen, attributes_seen, events_seen = {}, {}, {}, {} + local additional_attributes = {} if #device:get_endpoints(clusters.CameraAvStreamManagement.ID) > 0 then - local ib = im.InteractionInfoBlock(nil, clusters.CameraAvStreamManagement.ID, clusters.CameraAvStreamManagement.attributes.AttributeList.ID) - subscribe_request:with_info_block(ib) + table.insert(additional_attributes, clusters.CameraAvStreamManagement.attributes.AttributeList) + table.insert(additional_attributes, camera_fields.CameraAVSMFeatureMapAttr) + end + + if #device:get_endpoints(clusters.CameraAvSettingsUserLevelManagement.ID) > 0 then + table.insert(additional_attributes, camera_fields.CameraAVSULMFeatureMapAttr) + end + + if #device:get_endpoints(clusters.ZoneManagement.ID) > 0 then + table.insert(additional_attributes, camera_fields.ZoneManagementFeatureMapAttr) end for _, endpoint_info in ipairs(device.endpoints) do @@ -313,6 +323,17 @@ function CameraUtils.subscribe(device) end end + for _, attr in ipairs(additional_attributes) do + local cluster_id = attr.cluster or attr._cluster.ID + local attr_id = attr.ID or attr.attribute + if not attributes_seen[cluster_id] or not attributes_seen[cluster_id][attr_id] then + local ib = im.InteractionInfoBlock(nil, cluster_id, attr_id) + subscribe_request:with_info_block(ib) + attributes_seen[cluster_id] = attributes_seen[cluster_id] or {} + attributes_seen[cluster_id][attr_id] = ib + end + end + if #subscribe_request.info_blocks > 0 then device:send(subscribe_request) end diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua index 1dbad05698..a72aa0b234 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua @@ -6,7 +6,6 @@ ------------------------------------------------------------------------------------- local attribute_handlers = require "sub_drivers.camera.camera_handlers.attribute_handlers" -local button_cfg = require("switch_utils.device_configuration").ButtonCfg local camera_cfg = require "sub_drivers.camera.camera_utils.device_configuration" local camera_fields = require "sub_drivers.camera.camera_utils.fields" local camera_utils = require "sub_drivers.camera.camera_utils.utils" @@ -33,7 +32,7 @@ end function CameraLifecycleHandlers.do_configure(driver, device) camera_utils.update_camera_component_map(device) if #device:get_endpoints(clusters.CameraAvStreamManagement.ID) == 0 then - camera_cfg.match_profile(device, false, false) + camera_cfg.match_profile(device) end camera_cfg.create_child_devices(driver, device) camera_cfg.initialize_camera_capabilities(device) @@ -42,26 +41,19 @@ end function CameraLifecycleHandlers.driver_switched(driver, device) camera_utils.update_camera_component_map(device) if #device:get_endpoints(clusters.CameraAvStreamManagement.ID) == 0 then - camera_cfg.match_profile(device, false, false) + camera_cfg.match_profile(device) end end function CameraLifecycleHandlers.info_changed(driver, device, event, args) local software_version_changed = device.matter_version ~= nil and args.old_st_store.matter_version ~= nil and device.matter_version.software ~= args.old_st_store.matter_version.software - local profile_update_requested = false local profile_changed = not switch_utils.deep_equals(device.profile, args.old_st_store.profile, { ignore_functions = true }) if software_version_changed then - profile_update_requested = camera_cfg.match_profile(device, false, false) - end - - if profile_changed or (software_version_changed and not profile_update_requested) then - camera_cfg.initialize_camera_capabilities(device) - device:subscribe() - if #switch_utils.get_endpoints_by_device_type(device, fields.DEVICE_TYPE_ID.DOORBELL) > 0 then - button_cfg.configure_buttons(device, device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH})) - end + camera_cfg.reconcile_profile_and_capabilities(device) + elseif profile_changed then + camera_cfg.reinitialize_changed_camera_capabilities_and_subscriptions(device, args.old_st_store.profile, device.profile) end end @@ -107,7 +99,8 @@ local camera_handler = { [clusters.CameraAvStreamManagement.attributes.Viewport.ID] = attribute_handlers.viewport_handler, [clusters.CameraAvStreamManagement.attributes.LocalSnapshotRecordingEnabled.ID] = attribute_handlers.enabled_state_factory(capabilities.localMediaStorage.localSnapshotRecording), [clusters.CameraAvStreamManagement.attributes.LocalVideoRecordingEnabled.ID] = attribute_handlers.enabled_state_factory(capabilities.localMediaStorage.localVideoRecording), - [clusters.CameraAvStreamManagement.attributes.AttributeList.ID] = attribute_handlers.camera_av_stream_management_attribute_list_handler + [clusters.CameraAvStreamManagement.attributes.AttributeList.ID] = attribute_handlers.camera_av_stream_management_attribute_list_handler, + [camera_fields.CameraAVSMFeatureMapAttr.ID] = attribute_handlers.camera_feature_map_handler }, [clusters.CameraAvSettingsUserLevelManagement.ID] = { [clusters.CameraAvSettingsUserLevelManagement.attributes.MPTZPosition.ID] = attribute_handlers.ptz_position_handler, @@ -118,14 +111,16 @@ local camera_handler = { [clusters.CameraAvSettingsUserLevelManagement.attributes.PanMin.ID] = attribute_handlers.pt_range_handler_factory(capabilities.mechanicalPanTiltZoom.panRange, camera_fields.pt_range_fields[camera_fields.PAN_IDX].min), [clusters.CameraAvSettingsUserLevelManagement.attributes.TiltMax.ID] = attribute_handlers.pt_range_handler_factory(capabilities.mechanicalPanTiltZoom.tiltRange, camera_fields.pt_range_fields[camera_fields.TILT_IDX].max), [clusters.CameraAvSettingsUserLevelManagement.attributes.TiltMin.ID] = attribute_handlers.pt_range_handler_factory(capabilities.mechanicalPanTiltZoom.tiltRange, camera_fields.pt_range_fields[camera_fields.TILT_IDX].min), - [clusters.CameraAvSettingsUserLevelManagement.attributes.DPTZStreams.ID] = attribute_handlers.dptz_streams_handler + [clusters.CameraAvSettingsUserLevelManagement.attributes.DPTZStreams.ID] = attribute_handlers.dptz_streams_handler, + [camera_fields.CameraAVSULMFeatureMapAttr.ID] = attribute_handlers.camera_feature_map_handler }, [clusters.ZoneManagement.ID] = { [clusters.ZoneManagement.attributes.MaxZones.ID] = attribute_handlers.max_zones_handler, [clusters.ZoneManagement.attributes.Zones.ID] = attribute_handlers.zones_handler, [clusters.ZoneManagement.attributes.Triggers.ID] = attribute_handlers.triggers_handler, [clusters.ZoneManagement.attributes.SensitivityMax.ID] = attribute_handlers.sensitivity_max_handler, - [clusters.ZoneManagement.attributes.Sensitivity.ID] = attribute_handlers.sensitivity_handler + [clusters.ZoneManagement.attributes.Sensitivity.ID] = attribute_handlers.sensitivity_handler, + [camera_fields.ZoneManagementFeatureMapAttr.ID] = attribute_handlers.camera_feature_map_handler }, [clusters.Chime.ID] = { [clusters.Chime.attributes.InstalledChimeSounds.ID] = attribute_handlers.installed_chime_sounds_handler, diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua index bdb2fe468b..c948dd0a79 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua @@ -2,7 +2,9 @@ -- Licensed under the Apache License, Version 2.0 local capabilities = require "st.capabilities" +local cluster_base = require "st.matter.cluster_base" local clusters = require "st.matter.clusters" +local camera_fields = require "sub_drivers.camera.camera_utils.fields" local t_utils = require "integration_test.utils" local test = require "integration_test" local uint32 = require "st.matter.data_types.Uint32" @@ -154,6 +156,9 @@ local function test_init() parent_assigned_child_key = string.format("%d", FLOODLIGHT_EP) }) subscribe_request = subscribed_attributes[1]:subscribe(mock_device) + subscribe_request:merge(cluster_base.subscribe(mock_device, nil, camera_fields.CameraAVSMFeatureMapAttr.cluster, camera_fields.CameraAVSMFeatureMapAttr.ID)) + subscribe_request:merge(cluster_base.subscribe(mock_device, nil, camera_fields.CameraAVSULMFeatureMapAttr.cluster, camera_fields.CameraAVSULMFeatureMapAttr.ID)) + subscribe_request:merge(cluster_base.subscribe(mock_device, nil, camera_fields.ZoneManagementFeatureMapAttr.cluster, camera_fields.ZoneManagementFeatureMapAttr.ID)) for i, attr in ipairs(subscribed_attributes) do if i > 1 then subscribe_request:merge(attr:subscribe(mock_device)) end end @@ -435,6 +440,7 @@ test.register_coroutine_test( } }, subscribe = function() subscribe_called = true end, + supports_capability = function() return false end, get_endpoints = function() return { DOORBELL_EP } end, } @@ -461,9 +467,36 @@ test.register_coroutine_test( button_cfg.configure_buttons = original_configure_buttons assert(match_profile_called, "match_profile should be called on software version change") - assert(init_called, "initialize_camera_capabilities should be called") - assert(subscribe_called, "subscribe should be called") - assert(configure_buttons_called, "configure_buttons should be called") + assert(not init_called, "initialize_camera_capabilities should not be called when capability state is unchanged") + assert(not subscribe_called, "subscribe should not be called when capability state is unchanged") + assert(not configure_buttons_called, "configure_buttons should not be called when capability state is unchanged") + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "Camera FeatureMap change should reinitialize capabilities when profile is unchanged", + function() + local camera_cfg = require "sub_drivers.camera.camera_utils.device_configuration" + + local reconcile_called = false + local original_reconcile = camera_cfg.reconcile_profile_and_capabilities + + camera_cfg.reconcile_profile_and_capabilities = function(_) + reconcile_called = true + return false + end + + test.socket.matter:__queue_receive({ + mock_device.id, + cluster_base.build_test_report_data(mock_device, CAMERA_EP, camera_fields.CameraAVSMFeatureMapAttr.cluster, camera_fields.CameraAVSMFeatureMapAttr.ID, uint32(0)) + }) + test.wait_for_events() + + camera_cfg.reconcile_profile_and_capabilities = original_reconcile + assert(reconcile_called, "reconcile_profile_and_capabilities should be called") end, { min_api_version = 17 @@ -2772,6 +2805,11 @@ test.register_coroutine_test( function() update_device_profile() test.wait_for_events() + + local camera_cfg = require("sub_drivers.camera.camera_utils.device_configuration") + local original_reconcile = camera_cfg.reconcile_profile_and_capabilities + camera_cfg.reconcile_profile_and_capabilities = function(...) return false end + test.socket.matter:__queue_receive({ mock_device.id, clusters.CameraAvStreamManagement.attributes.AttributeList:build_test_report_data(mock_device, CAMERA_EP, { @@ -2779,6 +2817,9 @@ test.register_coroutine_test( uint32(clusters.CameraAvStreamManagement.attributes.StatusLightBrightness.ID) }) }) + test.wait_for_events() + + camera_cfg.reconcile_profile_and_capabilities = original_reconcile end, { min_api_version = 17 From 9943a8d600b0c7b4b2e26f06fd25aa646ca07821 Mon Sep 17 00:00:00 2001 From: Abdul Samad Date: Mon, 13 Apr 2026 11:54:26 -0500 Subject: [PATCH 10/29] Deep copy latest state, use `pairs` to handle map-like capability tables keyed by strings Co-authored-by: Harrison Carter --- .../camera_utils/device_configuration.lua | 39 +++++++-------- .../src/test/test_matter_camera.lua | 48 +++++++++++++++++++ 2 files changed, 68 insertions(+), 19 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua index c2ea259aa1..068bee2344 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua @@ -6,6 +6,7 @@ local camera_fields = require "sub_drivers.camera.camera_utils.fields" local camera_utils = require "sub_drivers.camera.camera_utils.utils" local capabilities = require "st.capabilities" local clusters = require "st.matter.clusters" +local st_utils = require "st.utils" local device_cfg = require "switch_utils.device_configuration" local fields = require "switch_utils.fields" local switch_utils = require "switch_utils.utils" @@ -108,32 +109,34 @@ local function build_camera_privacy_supported_commands() end local function capabilities_needing_reinit(device) - local main = camera_fields.profile_components.main - local capabilities_to_reinit = {} - local function state_differs(capability, attribute_name, expected) - local current = device:get_latest_state(main, capability.ID, attribute_name) - return not switch_utils.deep_equals(current, expected, { ignore_functions = true }) + local function should_init(capability, attribute, expected) + if device:supports_capability(capability) then + local current = st_utils.deep_copy(device:get_latest_state( + camera_fields.profile_components.main, + capability.ID, + attribute.NAME, + {} + )) + return not switch_utils.deep_equals(current, expected) + end + return false end - if device:supports_capability(capabilities.webrtc) and - state_differs(capabilities.webrtc, capabilities.webrtc.supportedFeatures.NAME, build_webrtc_supported_features()) then + if should_init(capabilities.webrtc, capabilities.webrtc.supportedFeatures, build_webrtc_supported_features()) then capabilities_to_reinit.webrtc = true end - if device:supports_capability(capabilities.mechanicalPanTiltZoom) and - state_differs(capabilities.mechanicalPanTiltZoom, capabilities.mechanicalPanTiltZoom.supportedAttributes.NAME, build_ptz_supported_attributes(device)) then + if should_init(capabilities.mechanicalPanTiltZoom, capabilities.mechanicalPanTiltZoom.supportedAttributes, build_ptz_supported_attributes(device)) then capabilities_to_reinit.ptz = true end - if device:supports_capability(capabilities.zoneManagement) and - state_differs(capabilities.zoneManagement, capabilities.zoneManagement.supportedFeatures.NAME, build_zone_management_supported_features(device)) then + if should_init(capabilities.zoneManagement, capabilities.zoneManagement.supportedFeatures, build_zone_management_supported_features(device)) then capabilities_to_reinit.zone_management = true end - if device:supports_capability(capabilities.localMediaStorage) and - state_differs(capabilities.localMediaStorage, capabilities.localMediaStorage.supportedAttributes.NAME, build_local_media_storage_supported_attributes(device)) then + if should_init(capabilities.localMediaStorage, capabilities.localMediaStorage.supportedAttributes, build_local_media_storage_supported_attributes(device)) then capabilities_to_reinit.local_media_storage = true end @@ -144,14 +147,12 @@ local function capabilities_needing_reinit(device) end end - if device:supports_capability(capabilities.videoStreamSettings) and - state_differs(capabilities.videoStreamSettings, capabilities.videoStreamSettings.supportedFeatures.NAME, build_video_stream_settings_supported_features(device)) then + if should_init(capabilities.videoStreamSettings, capabilities.videoStreamSettings.supportedFeatures, build_video_stream_settings_supported_features(device)) then capabilities_to_reinit.video_stream_settings = true end - if device:supports_capability(capabilities.cameraPrivacyMode) and - (state_differs(capabilities.cameraPrivacyMode, capabilities.cameraPrivacyMode.supportedAttributes.NAME, build_camera_privacy_supported_attributes()) or - state_differs(capabilities.cameraPrivacyMode, capabilities.cameraPrivacyMode.supportedCommands.NAME, build_camera_privacy_supported_commands())) then + if should_init(capabilities.cameraPrivacyMode, capabilities.cameraPrivacyMode.supportedAttributes, build_camera_privacy_supported_attributes()) or + should_init(capabilities.cameraPrivacyMode, capabilities.cameraPrivacyMode.supportedCommands, build_camera_privacy_supported_commands()) then capabilities_to_reinit.camera_privacy_mode = true end @@ -407,7 +408,7 @@ end local function profile_capability_set(profile) local capability_set = {} for _, component in pairs((profile or {}).components or {}) do - for _, capability in ipairs(component.capabilities or {}) do + for _, capability in pairs(component.capabilities or {}) do if capability.id ~= nil then capability_set[capability.id] = true end diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua index c948dd0a79..626d5b0b8a 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua @@ -503,6 +503,54 @@ test.register_coroutine_test( } ) +test.register_coroutine_test( + "Camera privacy mode state compare should ignore table metatable differences", + function() + local camera_cfg = require "sub_drivers.camera.camera_utils.device_configuration" + + local init_event_count = 0 + local original_match_profile = camera_cfg.match_profile + + camera_cfg.match_profile = function() + return false + end + + local fake_device = { + supports_capability = function(_, capability) + return capability == capabilities.cameraPrivacyMode + end, + get_latest_state = function(_, _, _, attribute_name) + if attribute_name == capabilities.cameraPrivacyMode.supportedAttributes.NAME then + return { "softRecordingPrivacyMode", "softLivestreamPrivacyMode" } + elseif attribute_name == capabilities.cameraPrivacyMode.supportedCommands.NAME then + local commands = { "setSoftRecordingPrivacyMode", "setSoftLivestreamPrivacyMode" } + setmetatable(commands, { + __index = function() + return nil + end + }) + return commands + end + return nil + end, + get_endpoints = function() + return { CAMERA_EP } + end, + emit_event_for_endpoint = function() + init_event_count = init_event_count + 1 + end + } + + camera_cfg.reconcile_profile_and_capabilities(fake_device) + camera_cfg.match_profile = original_match_profile + + assert(init_event_count == 0, "cameraPrivacyMode should not be reinitialized for equal values with metatable differences") + end, + { + min_api_version = 17 + } +) + test.register_coroutine_test( "Reports mapping to EnabledState capability data type should generate appropriate events", function() From c5ca63ece03f4c3b7ff59b0d704ec202c92923f2 Mon Sep 17 00:00:00 2001 From: Abdul Samad Date: Mon, 13 Apr 2026 12:00:16 -0500 Subject: [PATCH 11/29] Fix luacheck lints --- .../camera/camera_utils/device_configuration.lua | 6 +++++- .../src/sub_drivers/camera/camera_utils/utils.lua | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua index 068bee2344..a31473f993 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua @@ -141,7 +141,11 @@ local function capabilities_needing_reinit(device) end if device:supports_capability(capabilities.audioRecording) then - local audio_enabled_state = device:get_latest_state(main, capabilities.audioRecording.ID, capabilities.audioRecording.audioRecording.NAME) + local audio_enabled_state = device:get_latest_state( + camera_fields.profile_components.main, + capabilities.audioRecording.ID, + capabilities.audioRecording.audioRecording.NAME + ) if audio_enabled_state == nil then capabilities_to_reinit.audio_recording = true end diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/utils.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/utils.lua index f3b92aa3b6..78792b94b3 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/utils.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/utils.lua @@ -6,7 +6,6 @@ local capabilities = require "st.capabilities" local clusters = require "st.matter.clusters" local fields = require "switch_utils.fields" local switch_utils = require "switch_utils.utils" -local cluster_base = require "st.matter.cluster_base" local CameraUtils = {} From 8acc2bbbb9f701dc615273011a6a74126d01a0e2 Mon Sep 17 00:00:00 2001 From: Abdul Samad Date: Tue, 14 Apr 2026 11:43:52 -0500 Subject: [PATCH 12/29] Remove unused init function Co-authored-by: Nick DeBoom --- .../camera/camera_utils/device_configuration.lua | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua index a31473f993..398150d063 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua @@ -375,14 +375,6 @@ function CameraDeviceConfiguration.initialize_camera_capabilities(device) init_camera_privacy_mode(device) end -function CameraDeviceConfiguration.initialize_camera_capabilities_and_subscriptions(device) - CameraDeviceConfiguration.initialize_camera_capabilities(device) - device:subscribe() - if #switch_utils.get_endpoints_by_device_type(device, fields.DEVICE_TYPE_ID.DOORBELL) > 0 then - button_cfg.configure_buttons(device, device:get_endpoints(clusters.Switch.ID, {feature_bitmap=clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH})) - end -end - local function initialize_selected_camera_capabilities(device, capabilities_to_reinit) local reinit_targets = capabilities_to_reinit or {} From 86cdb1dd0276db5babcce6c53d7b691d5e7fc873 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Mon, 13 Apr 2026 14:45:09 -0500 Subject: [PATCH 13/29] add nil check handling for electrical sensor handlers --- .../src/switch_handlers/attribute_handlers.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/SmartThings/matter-switch/src/switch_handlers/attribute_handlers.lua b/drivers/SmartThings/matter-switch/src/switch_handlers/attribute_handlers.lua index b16610cf25..20bd92881e 100644 --- a/drivers/SmartThings/matter-switch/src/switch_handlers/attribute_handlers.lua +++ b/drivers/SmartThings/matter-switch/src/switch_handlers/attribute_handlers.lua @@ -321,6 +321,10 @@ function AttributeHandlers.available_endpoints_handler(driver, device, ib, respo return end local set_topology_eps = device:get_field(fields.ELECTRICAL_SENSOR_EPS) + if set_topology_eps == nil then + device.log.warn("Received an AvailableEndpoints response but no Electrical Sensor endpoints have been identified as supporting the Power Topology cluster with SET feature. Ignoring this response.") + return + end for i, set_ep_info in pairs(set_topology_eps or {}) do if ib.endpoint_id == set_ep_info.endpoint_id then -- since EP response is being handled here, remove it from the ELECTRICAL_SENSOR_EPS table @@ -350,6 +354,10 @@ function AttributeHandlers.parts_list_handler(driver, device, ib, response) return end local tree_topology_eps = device:get_field(fields.ELECTRICAL_SENSOR_EPS) + if tree_topology_eps == nil then + device.log.warn("Received a PartsList response but no Electrical Sensor endpoints have been identified as supporting the Power Topology cluster with TREE feature. Ignoring this response.") + return + end for i, tree_ep_info in pairs(tree_topology_eps or {}) do if ib.endpoint_id == tree_ep_info.endpoint_id then -- since EP response is being handled here, remove it from the ELECTRICAL_SENSOR_EPS table From 1101206297a0f77e5cc041534036901a1404e880 Mon Sep 17 00:00:00 2001 From: Jeff Page Date: Thu, 9 Apr 2026 15:49:33 -0500 Subject: [PATCH 14/29] WWSTCERT-9857 Add Zooz ZSE50 to zwave-siren (for WWST Cert) (#2681) * Add Zooz ZSE50 to zwave-siren --- .../SmartThings/zwave-siren/fingerprints.yml | 8 +- .../zwave-siren/profiles/zooz-zse50.yml | 309 ++++++++ drivers/SmartThings/zwave-siren/src/init.lua | 3 +- .../zwave-siren/src/preferences.lua | 28 +- .../zwave-siren/src/sub_drivers.lua | 1 + .../zwave-siren/src/test/test_zooz_zse50.lua | 717 ++++++++++++++++++ .../zwave-siren/src/zooz-zse50/can_handle.lua | 14 + .../src/zooz-zse50/fingerprints.lua | 8 + .../zwave-siren/src/zooz-zse50/init.lua | 367 +++++++++ 9 files changed, 1452 insertions(+), 3 deletions(-) create mode 100644 drivers/SmartThings/zwave-siren/profiles/zooz-zse50.yml create mode 100644 drivers/SmartThings/zwave-siren/src/test/test_zooz_zse50.lua create mode 100644 drivers/SmartThings/zwave-siren/src/zooz-zse50/can_handle.lua create mode 100644 drivers/SmartThings/zwave-siren/src/zooz-zse50/fingerprints.lua create mode 100644 drivers/SmartThings/zwave-siren/src/zooz-zse50/init.lua diff --git a/drivers/SmartThings/zwave-siren/fingerprints.yml b/drivers/SmartThings/zwave-siren/fingerprints.yml index 1e36e4af81..4b25211366 100644 --- a/drivers/SmartThings/zwave-siren/fingerprints.yml +++ b/drivers/SmartThings/zwave-siren/fingerprints.yml @@ -1,10 +1,16 @@ zwaveManufacturer: - - id: "Zooz" + - id: "Zooz/ZSE19" deviceLabel: Zooz Multisiren manufacturerId: 0x027A productType: 0x000C productId: 0x0003 deviceProfileName: multifunctional-siren + - id: "Zooz/ZSE50" + deviceLabel: Zooz ZSE50 Siren and Chime + manufacturerId: 0x027A + productType: 0x0004 + productId: 0x0369 + deviceProfileName: zooz-zse50 - id: "Everspring" deviceLabel: Everspring Siren manufacturerId: 0x0060 diff --git a/drivers/SmartThings/zwave-siren/profiles/zooz-zse50.yml b/drivers/SmartThings/zwave-siren/profiles/zooz-zse50.yml new file mode 100644 index 0000000000..866b88f436 --- /dev/null +++ b/drivers/SmartThings/zwave-siren/profiles/zooz-zse50.yml @@ -0,0 +1,309 @@ +# Zooz ZSE50 Siren/Chime +# With deviceConfig - allows setting a tone from routines +name: zooz-zse50 +components: + - id: main + capabilities: + - id: alarm + version: 1 + - id: chime + version: 1 + - id: mode + version: 1 + - id: powerSource + version: 1 + - id: audioVolume + version: 1 + - id: battery + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: Siren +### PREFERENCES ### +preferences: + #param 1 + - name: "playbackMode" + title: "Playback Mode" + description: "* = Default; Set siren playback mode: once (0), loop for x seconds (1), loop x times (2), loop until cancel (3), no sound (4)." + required: false + preferenceType: enumeration + definition: + options: + 0: "Play once *" + 1: "Play in loop for set duration" + 2: "Play in loop for set number" + 3: "Play in loop until stopped" + 4: "No sound, LED only" + default: 0 + #param 2 + - name: "playbackDuration" + title: "Playback Duration" + description: "Default: 180; Set playback duration for the siren (in seconds) when the siren is in playback mode 1." + required: false + preferenceType: integer + definition: + minimum: 1 + maximum: 900 + default: 180 + #param 3 + - name: "playbackLoop" + title: "Playback Loop Count" + description: "Default: 1; Set the number of playback loops for the selected tone when the siren is in playback mode 2." + required: false + preferenceType: integer + definition: + minimum: 1 + maximum: 99 + default: 1 + #param 4 + - name: "playbackTone" + title: "Playback Tone" + description: "Set the default tone for the siren playback. Choose the number of the file in the library as value. Check the 'modes' list for the id numbers" + required: false + preferenceType: integer + definition: + minimum: 1 + maximum: 50 + default: 1 + #param 5 - playbackVolume ## Handled with volume command + #param 6 + - name: "ledMode" + title: "LED Indicator Mode" + description: "* = Default; Set the LED indicator mode for the siren: off (0), strobe (1), police strobe (2), pulse (3), solid on (4). See documentation for details." + required: false + preferenceType: enumeration + definition: + options: + 0: "LED always off" + 1: "LED strobe single color *" + 2: "LED strobe red and blue" + 3: "LED pulse single color" + 4: "LED solid on single color" + default: 1 + #param 7 + - name: "ledColor" + title: "LED Indicator Color" + description: "Default: 0; Set the LED indicator color: red (0), yellow (42), green (85), indigo (127), blue (170), purple (212), or white (255). More colors available through custom values corresponding to the color wheel. See advanced documentation for details." + required: false + preferenceType: integer + definition: + minimum: 0 + maximum: 255 + default: 0 + #param 8 + - name: "lowBattery" + title: "Low Battery Report" + description: "Which % level should the device report low battery to the hub." + required: false + preferenceType: enumeration + definition: + options: + 10: "10% [DEFAULT]" + 15: "15%" + 20: "20%" + 25: "25%" + 30: "30%" + 35: "35%" + 40: "40%" + default: 10 + #param 9 + - name: "ledBatteryMode" + title: "LED In Back-Up Battery Mode" + description: "* = Default; Set the LED indicator in back-up battery mode: off (0), regular LED mode (1), pulse white for full battery and red for low battery (2)." + required: false + preferenceType: enumeration + definition: + options: + 0: "LED off" + 1: "Regular LED mode *" + 2: "Pulse white for full, red for low" + default: 1 + #param 10 + - name: "btnToneSelection" + title: "Button Tone Selection" + description: "Disable tone selection from physical buttons on the siren (0). When disabled, you'll only be able to program tones using the advanced parameters in the Z-Wave UI. Expert users only, see documentation for details." + required: false + preferenceType: enumeration + definition: + options: + 0: "Disabled" + 1: "Enabled [DEFAULT]" + default: 1 + #param 11 + - name: "btnVolSelection" + title: "Button Volume Selection" + description: "Disable volume adjustment from physical buttons on the siren (0). When disabled, you'll only be able to adjust volume using the advanced parameters in the Z-Wave UI. Expert users only, see documentation for details." + required: false + preferenceType: enumeration + definition: + options: + 0: "Disabled" + 1: "Enabled [DEFAULT]" + default: 1 + #param 13 + - name: "systemVolume" + title: "System Message Volume" + description: "Default: 50; Set system message volume (0-100, 0 – mute)." + required: false + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 50 + #param 14 + - name: "ledBrightness" + title: "LED Indicator Brightness" + description: "Default: 5; Choose the LED indicator's brightness level (0 – off, 10 – high brightness)." + required: false + preferenceType: integer + definition: + minimum: 0 + maximum: 10 + default: 5 + #param 15 + - name: "batteryFrequency" + title: "Battery Reporting Frequency" + description: "Default: 12; Set the reporting interval for battery (1-84 hours)." + required: false + preferenceType: integer + definition: + minimum: 1 + maximum: 84 + default: 12 + #param 16 + - name: "batteryThreshold" + title: "Battery Reporting Threshold" + description: "Default: 0; Set the threshold for battery reporting in % changes. Set to 0 to disable reporting based on threshold." + required: false + preferenceType: integer + definition: + minimum: 0 + maximum: 20 + default: 0 + +### DEVICE CONFIG ### +deviceConfig: + dashboard: + states: + - component: main + capability: chime + version: 1 + actions: + - component: main + capability: chime + version: 1 + basicPlus: [ ] + detailView: + - component: main + capability: alarm + version: 1 + values: + - key: alarm.value + enabledValues: + - 'off' + - 'both' + - key: "{{enumCommands}}" + enabledValues: + - 'off' + - 'both' + - component: main + capability: chime + version: 1 + - component: main + capability: mode + version: 1 + - component: main + capability: powerSource + version: 1 + values: + - key: powerSource.value + enabledValues: + - 'battery' + - 'mains' + - component: main + capability: audioVolume + version: 1 + - component: main + capability: battery + version: 1 + - component: main + capability: refresh + version: 1 + automation: + conditions: + - component: main + capability: alarm + version: 1 + values: + - key: alarm.value + enabledValues: + - 'off' + - 'both' + - component: main + capability: chime + version: 1 + - component: main + capability: mode + version: 1 + patch: + - op: replace + path: /0/displayType + value: dynamicList + - op: add + path: /0/dynamicList + value: + value: mode.value + command: setMode + supportedValues: + value: supportedArguments.value + - op: remove + path: /0/list + - component: main + capability: powerSource + version: 1 + values: + - key: powerSource.value + enabledValues: + - 'battery' + - 'mains' + step: 1 + - component: main + capability: audioVolume + version: 1 + - component: main + capability: battery + version: 1 + actions: + - component: main + capability: alarm + version: 1 + values: + - key: "{{enumCommands}}" + enabledValues: + - 'off' + - 'both' + - component: main + capability: chime + version: 1 + - component: main + capability: mode + version: 1 + patch: + - op: replace + path: /0/displayType + value: dynamicList + - op: add + path: /0/dynamicList + value: + value: mode.value + command: setMode + supportedValues: + value: supportedArguments.value + - op: remove + path: /0/list + - component: main + capability: audioVolume + version: 1 diff --git a/drivers/SmartThings/zwave-siren/src/init.lua b/drivers/SmartThings/zwave-siren/src/init.lua index b682ea77b7..52ccaba6b9 100644 --- a/drivers/SmartThings/zwave-siren/src/init.lua +++ b/drivers/SmartThings/zwave-siren/src/init.lua @@ -80,7 +80,8 @@ local driver_template = { capabilities.tamperAlert, capabilities.temperatureMeasurement, capabilities.relativeHumidityMeasurement, - capabilities.chime + capabilities.chime, + capabilities.powerSource }, sub_drivers = require("sub_drivers"), lifecycle_handlers = { diff --git a/drivers/SmartThings/zwave-siren/src/preferences.lua b/drivers/SmartThings/zwave-siren/src/preferences.lua index 2c10de6fcb..3cf2fe91b5 100644 --- a/drivers/SmartThings/zwave-siren/src/preferences.lua +++ b/drivers/SmartThings/zwave-siren/src/preferences.lua @@ -46,7 +46,32 @@ local devices = { PARAMETERS = { alarmLength = {parameter_number = 1, size = 2} } - } + }, + ZOOZ_ZSE50_SIREN = { + MATCHING_MATRIX = { + mfrs = 0x027A, + product_types = 0x0004, + product_ids = 0x0369 + }, + PARAMETERS = { + playbackMode = { parameter_number = 1, size = 1 }, + playbackDuration = { parameter_number = 2, size = 2 }, + playbackLoop = { parameter_number = 3, size = 1 }, + playbackTone = { parameter_number = 4, size = 1 }, + playbackVolume = { parameter_number = 5, size = 1 }, + ledMode = { parameter_number = 6, size = 1 }, + ledColor = { parameter_number = 7, size = 1 }, + lowBattery = { parameter_number = 8, size = 1 }, + ledBatteryMode = { parameter_number = 9, size = 1 }, + btnToneSelection = { parameter_number = 10, size = 1 }, + btnVolSelection = { parameter_number = 11, size = 1 }, + basicSetGrp2 = { parameter_number = 12, size = 1 }, --Not Used + systemVolume = { parameter_number = 13, size = 1 }, + ledBrightness = { parameter_number = 14, size = 1 }, + batteryFrequency = { parameter_number = 15, size = 1 }, + batteryThreshold = { parameter_number = 16, size = 1 } + } + }, } local preferences = {} @@ -70,4 +95,5 @@ preferences.to_numeric_value = function(new_value) end return numeric end + return preferences diff --git a/drivers/SmartThings/zwave-siren/src/sub_drivers.lua b/drivers/SmartThings/zwave-siren/src/sub_drivers.lua index a20d559e44..12ce423ba5 100644 --- a/drivers/SmartThings/zwave-siren/src/sub_drivers.lua +++ b/drivers/SmartThings/zwave-siren/src/sub_drivers.lua @@ -4,6 +4,7 @@ local lazy_load_if_possible = require "lazy_load_subdriver" local sub_drivers = { lazy_load_if_possible("multifunctional-siren"), + lazy_load_if_possible("zooz-zse50"), lazy_load_if_possible("zwave-sound-sensor"), lazy_load_if_possible("ecolink-wireless-siren"), lazy_load_if_possible("philio-sound-siren"), diff --git a/drivers/SmartThings/zwave-siren/src/test/test_zooz_zse50.lua b/drivers/SmartThings/zwave-siren/src/test/test_zooz_zse50.lua new file mode 100644 index 0000000000..1454458687 --- /dev/null +++ b/drivers/SmartThings/zwave-siren/src/test/test_zooz_zse50.lua @@ -0,0 +1,717 @@ +-- Copyright 2026 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local test = require "integration_test" +local capabilities = require "st.capabilities" +local zw = require "st.zwave" +local zw_test_utils = require "integration_test.zwave_test_utils" +local Basic = (require "st.zwave.CommandClass.Basic")({ version = 1 }) +local Configuration = (require "st.zwave.CommandClass.Configuration")({ version = 4 }) +local SoundSwitch = (require "st.zwave.CommandClass.SoundSwitch")({ version = 1 }) +local Notification = (require "st.zwave.CommandClass.Notification")({ version = 8 }) +local Version = (require "st.zwave.CommandClass.Version")({ version = 1 }) +local t_utils = require "integration_test.utils" + +local siren_endpoints = { + { + command_classes = { + { value = zw.SOUND_SWITCH }, + { value = zw.NOTIFICATION }, + { value = zw.VERSION }, + { value = zw.BASIC } + } + } +} + +--- { manufacturerId = 0x027A, productType = 0x0004, productId = 0x0369 } -- Zooz ZSE50 Siren & Chime +local mock_siren = test.mock_device.build_test_zwave_device({ + profile = t_utils.get_profile_definition("zooz-zse50.yml"), + zwave_endpoints = siren_endpoints, + zwave_manufacturer_id = 0x027A, + zwave_product_type = 0x0004, + zwave_product_id = 0x0369, +}) + +local tones_list = { + [1] = { name = "test_tone1", duration = 2 }, + [2] = { name = "test_tone2", duration = 4 } +} + +local function test_init() + -- Initialize some fields to help with testing + mock_siren:set_field("TONE_DEFAULT", 1, { persist = true }) + mock_siren:set_field("TOTAL_TONES", 2, { persist = true }) + mock_siren:set_field("TONES_LIST", tones_list, { persist = true }) + + test.mock_device.add_test_device(mock_siren) +end + +test.set_test_init_function(test_init) + +test.register_coroutine_test( + "init should rebuild tones when tone cache is missing", + function() + mock_siren:set_field("TONES_LIST", nil) + mock_siren:set_field("TONE_DEFAULT", nil) + + test.socket.device_lifecycle:__queue_receive({ mock_siren.id, "init" }) + test.socket.capability:__expect_send( + mock_siren:generate_test_message("main", capabilities.mode.mode("Rebuild List")) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonesNumberGet({}) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "added should set startup volume and refresh", + function() + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + test.socket.zwave:__set_channel_ordering("relaxed") + + test.socket.device_lifecycle:__queue_receive({ mock_siren.id, "added" }) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:ConfigurationSet({ volume = 10 }) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + Basic:Get({}) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + Version:Get({}) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + Notification:Get({ + notification_type = Notification.notification_type.POWER_MANAGEMENT, + event = Notification.event.power_management.STATE_IDLE, + v1_alarm_type = 0 + }) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:ConfigurationGet({}) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlayGet({}) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "infoChanged should update config and send delayed Basic Set", + function() + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + + test.socket.device_lifecycle:__queue_receive( + mock_siren:generate_info_changed({ preferences = { ledColor = 255 } }) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + Configuration:Set({ parameter_number = 7, size = 1, configuration_value = -1 }) + ) + ) + + test.mock_time.advance_time(1) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + Basic:Set({ value = 0x00 }) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "infoChanged should update playbackDuration and send delayed Basic Set", + function() + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + + test.socket.device_lifecycle:__queue_receive( + mock_siren:generate_info_changed({ preferences = { playbackDuration = 90 } }) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + Configuration:Set({ parameter_number = 2, size = 2, configuration_value = 90 }) + ) + ) + + test.mock_time.advance_time(1) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + Basic:Set({ value = 0x00 }) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_message_test( + "Version report should update firmware version", + { + { + channel = "zwave", + direction = "receive", + message = { mock_siren.id, zw_test_utils.zwave_test_build_receive_command(Version:Report({ + application_version = 2, + application_sub_version = 5 + })) } + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.firmwareUpdate.currentVersion({ value = "2.05" })) + } + }, + { + min_api_version = 17 + } +) + +test.register_message_test( + "Notification report AC_MAINS_DISCONNECTED should set power source to battery", + { + { + channel = "zwave", + direction = "receive", + message = { mock_siren.id, zw_test_utils.zwave_test_build_receive_command(Notification:Report({ + notification_type = Notification.notification_type.POWER_MANAGEMENT, + event = Notification.event.power_management.AC_MAINS_DISCONNECTED + })) } + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.powerSource.powerSource.battery()) + } + }, + { + min_api_version = 17 + } +) + +test.register_message_test( + "Notification report AC_MAINS_RE_CONNECTED should set power source to mains", + { + { + channel = "zwave", + direction = "receive", + message = { mock_siren.id, zw_test_utils.zwave_test_build_receive_command(Notification:Report({ + notification_type = Notification.notification_type.POWER_MANAGEMENT, + event = Notification.event.power_management.AC_MAINS_RE_CONNECTED + })) } + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.powerSource.powerSource.mains()) + } + }, + { + min_api_version = 17 + } +) + +test.register_message_test( + "SoundSwitch ConfigurationReport should update volume", + { + { + channel = "zwave", + direction = "receive", + message = { mock_siren.id, zw_test_utils.zwave_test_build_receive_command(SoundSwitch:ConfigurationReport({ + volume = 75, + default_tone_identifer = 5 + })) } + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.audioVolume.volume(75)) + } + }, + { + min_api_version = 17 + } +) + +test.register_message_test( + "SoundSwitch TonesNumberReport should request info on each tone", + { + { + channel = "zwave", + direction = "receive", + message = { mock_siren.id, zw_test_utils.zwave_test_build_receive_command(SoundSwitch:TonesNumberReport({ + supported_tones = 2 + })) } + }, + { + channel = "zwave", + direction = "send", + message = zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:ToneInfoGet({ tone_identifier = 1 }) + ) + }, + { + channel = "zwave", + direction = "send", + message = zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:ToneInfoGet({ tone_identifier = 2 }) + ) + } + }, + { + min_api_version = 17 + } +) + +test.register_message_test( + "SoundSwitch ToneInfoReport should update supported modes when all tones received", + { + { + channel = "zwave", + direction = "receive", + message = { mock_siren.id, zw_test_utils.zwave_test_build_receive_command(SoundSwitch:ToneInfoReport({ + tone_identifier = 1, + name = "test_tone1", + tone_duration = 2 + })) } + }, + { + channel = "zwave", + direction = "receive", + message = { mock_siren.id, zw_test_utils.zwave_test_build_receive_command(SoundSwitch:ToneInfoReport({ + tone_identifier = 2, + name = "test_tone2", + tone_duration = 4 + })) } + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.mode.supportedModes({ "Rebuild List", "Off", "1: test_tone1 (2s)", "2: test_tone2 (4s)" })) + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.mode.supportedArguments({ "Off", "1: test_tone1 (2s)", "2: test_tone2 (4s)" })) + }, + { + channel = "zwave", + direction = "send", + message = zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlayGet({}) + ) + } + }, + { + min_api_version = 17 + } +) + +test.register_message_test( + "SoundSwitch TonePlayReport for tone 1 should set alarm on, chime on, and mode to tone name", + { + { + channel = "zwave", + direction = "receive", + message = { mock_siren.id, zw_test_utils.zwave_test_build_receive_command(SoundSwitch:TonePlayReport({ + tone_identifier = 1 + })) } + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.alarm.alarm.both()) + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.chime.chime.chime()) + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.mode.mode("1: test_tone1 (2s)")) + } + }, + { + min_api_version = 17 + } +) + +test.register_message_test( + "SoundSwitch TonePlayReport for tone 0 should set alarm off, chime off, and mode Off", + { + { + channel = "zwave", + direction = "receive", + message = { mock_siren.id, zw_test_utils.zwave_test_build_receive_command(SoundSwitch:TonePlayReport({ + tone_identifier = 0 + })) } + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.alarm.alarm.off()) + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.chime.chime.off()) + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.mode.mode("Off")) + } + }, + { + min_api_version = 17 + } +) + +test.register_message_test( + "Basic report 0x00 should be handled as alarm off, chime off, and mode Off", + { + { + channel = "zwave", + direction = "receive", + message = { + mock_siren.id, + zw_test_utils.zwave_test_build_receive_command(Basic:Report({ value = 0 })) } + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.alarm.alarm.off()) + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.chime.chime.off()) + }, + { + channel = "capability", + direction = "send", + message = mock_siren:generate_test_message("main", capabilities.mode.mode("Off")) + } + }, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "volumeUp should increase volume by 2", + function() + test.socket.capability:__queue_receive({ + mock_siren.id, + { capability = "audioVolume", component = "main", command = "volumeUp", args = {} } + }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:ConfigurationSet({ volume = 52 }) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "volumeUp should decrease volume by 2", + function() + test.socket.capability:__queue_receive({ + mock_siren.id, + { capability = "audioVolume", component = "main", command = "volumeDown", args = {} } + }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:ConfigurationSet({ volume = 48 }) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "setVolume should set volume to specified value", + function() + test.socket.capability:__queue_receive({ + mock_siren.id, + { capability = "audioVolume", component = "main", command = "setVolume", args = { 75 } } + }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:ConfigurationSet({ volume = 75 }) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "alarm.both() should send TonePlaySet with default tone and TonePlayGet", + function() + test.socket.capability:__queue_receive({ + mock_siren.id, + { capability = "alarm", component = "main", command = "both", args = {} } + }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlaySet({ tone_identifier = 0xFF }) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlayGet({}) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "alarm.off() should send TonePlaySet with tone 0x00 and TonePlayGet", + function() + test.socket.capability:__queue_receive({ + mock_siren.id, + { capability = "alarm", component = "main", command = "off", args = {} } + }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlaySet({ tone_identifier = 0x00 }) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlayGet({}) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "chime.chime() should send TonePlaySet with default tone and TonePlayGet", + function() + test.socket.capability:__queue_receive({ + mock_siren.id, + { capability = "chime", component = "main", command = "chime", args = {} } + }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlaySet({ tone_identifier = 0xFF }) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlayGet({}) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "chime.off() should send TonePlaySet with tone 0x00 and TonePlayGet", + function() + test.socket.capability:__queue_receive({ + mock_siren.id, + { capability = "chime", component = "main", command = "off", args = {} } + }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlaySet({ tone_identifier = 0x00 }) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlayGet({}) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "setMode should play the specified tone", + function() + test.socket.capability:__queue_receive({ + mock_siren.id, + { capability = "mode", component = "main", command = "setMode", args = { "1: test_tone1 (2s)" } } + }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlaySet({ tone_identifier = 1 }) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlayGet({}) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "setMode to Off should turn off the tone", + function() + test.socket.capability:__queue_receive({ + mock_siren.id, + { capability = "mode", component = "main", command = "setMode", args = { "Off" } } + }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlaySet({ tone_identifier = 0x00 }) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlayGet({}) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "setMode to Rebuild List should emit mode and send TonesNumberGet", + function() + test.socket.capability:__queue_receive({ + mock_siren.id, + { capability = "mode", component = "main", command = "setMode", args = { "Rebuild List" } } + }) + test.socket.capability:__expect_send( + mock_siren:generate_test_message("main", capabilities.mode.mode("Rebuild List")) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonesNumberGet({}) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "refresh should send a series of Z-Wave Gets", + function() + test.socket.capability:__queue_receive({ + mock_siren.id, + { capability = "refresh", component = "main", command = "refresh", args = {} } + }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + Basic:Get({}) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + Version:Get({}) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + Notification:Get({ + notification_type = Notification.notification_type.POWER_MANAGEMENT, + event = Notification.event.power_management.STATE_IDLE, + v1_alarm_type = 0 + }) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:ConfigurationGet({}) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_siren, + SoundSwitch:TonePlayGet({}) + ) + ) + end, + { + min_api_version = 17 + } +) + +test.run_registered_tests() diff --git a/drivers/SmartThings/zwave-siren/src/zooz-zse50/can_handle.lua b/drivers/SmartThings/zwave-siren/src/zooz-zse50/can_handle.lua new file mode 100644 index 0000000000..90ce30f76b --- /dev/null +++ b/drivers/SmartThings/zwave-siren/src/zooz-zse50/can_handle.lua @@ -0,0 +1,14 @@ +-- Copyright 2026 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local function can_handle_multifunctional_siren(opts, driver, device, ...) + local FINGERPRINTS = require("zooz-zse50.fingerprints") + for _, fingerprint in ipairs(FINGERPRINTS) do + if device:id_match(fingerprint.manufacturerId, fingerprint.productType, fingerprint.productId) then + return true, require("zooz-zse50") + end + end + return false +end + +return can_handle_multifunctional_siren diff --git a/drivers/SmartThings/zwave-siren/src/zooz-zse50/fingerprints.lua b/drivers/SmartThings/zwave-siren/src/zooz-zse50/fingerprints.lua new file mode 100644 index 0000000000..a8c37a04e6 --- /dev/null +++ b/drivers/SmartThings/zwave-siren/src/zooz-zse50/fingerprints.lua @@ -0,0 +1,8 @@ +-- Copyright 2026 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local ZSE50_FINGERPRINTS = { + { manufacturerId = 0x027A, productType = 0x0004, productId = 0x0369 } -- Zooz ZSE50 Siren & Chime +} + +return ZSE50_FINGERPRINTS diff --git a/drivers/SmartThings/zwave-siren/src/zooz-zse50/init.lua b/drivers/SmartThings/zwave-siren/src/zooz-zse50/init.lua new file mode 100644 index 0000000000..a1d58b262a --- /dev/null +++ b/drivers/SmartThings/zwave-siren/src/zooz-zse50/init.lua @@ -0,0 +1,367 @@ +-- Copyright 2026 SmartThings +-- Licensed under the Apache License, Version 2.0 + +local preferencesMap = require "preferences" + +local log = require "log" +local st_utils = require "st.utils" +local capabilities = require "st.capabilities" +local defaults = require "st.zwave.defaults" + +local cc = require "st.zwave.CommandClass" +local Basic = (require "st.zwave.CommandClass.Basic")({ version = 1 }) +local Configuration = (require "st.zwave.CommandClass.Configuration")({ version = 4 }) +local Notification = (require "st.zwave.CommandClass.Notification")({ version = 8 }) +local SoundSwitch = (require "st.zwave.CommandClass.SoundSwitch")({ version = 1 }) +local Version = (require "st.zwave.CommandClass.Version")({ version = 1 }) + +--- @param self st.zwave.Driver +--- @param device st.zwave.Device +local function update_firmwareUpdate_capability(self, device, component, major, minor) + if device:supports_capability_by_id(capabilities.firmwareUpdate.ID, component.id) then + local fmtFirmwareVersion = string.format("%d.%02d", major, minor) + device:emit_component_event(component, capabilities.firmwareUpdate.currentVersion({ value = fmtFirmwareVersion })) + end +end + +--- Update the built in capability firmwareUpdate's currentVersion attribute with the +--- Zwave version information received during pairing of the device. +--- @param self st.zwave.Driver +--- @param device st.zwave.Device +local function updateFirmwareVersion(self, device) + local fw_major = (((device.st_store or {}).zwave_version or {}).firmware or {}).major + local fw_minor = (((device.st_store or {}).zwave_version or {}).firmware or {}).minor + if fw_major and fw_minor then + update_firmwareUpdate_capability(self, device, device.profile.components.main, fw_major, fw_minor) + else + device.log.warn("Firmware major or minor version not available.") + end +end + +local function getModeName(toneId, toneInfo) + return string.format("%s: %s (%ss)", toneId, toneInfo.name, toneInfo.duration) +end + +local function playTone(device, tone_id) + local tones_list = device:get_field("TONES_LIST") + local default_tone = device:get_field("TONE_DEFAULT") or 1 + local playbackMode = tonumber(device.preferences.playbackMode) + local duration = 0 + + if playbackMode == 1 then + duration = device.preferences.playbackDuration + elseif playbackMode == 2 then + duration = duration * device.preferences.playbackLoop + elseif tones_list ~= nil and tone_id > 0 then + if tone_id == 0xFF then + duration = tones_list[tonumber(default_tone)].duration + else + duration = tones_list[tonumber(tone_id)].duration + end + end + + log.info(string.format("Playing Tone: %s, playbackMode %s, duration %ss", tone_id, playbackMode, duration)) + + device:send(SoundSwitch:TonePlaySet({ tone_identifier = tone_id })) + device:send(SoundSwitch:TonePlayGet({})) + + local soundSwitch_refresh = function() + local chime = device:get_latest_state("main", capabilities.chime.ID, capabilities.chime.chime.NAME) + local mode = device:get_latest_state("main", capabilities.mode.ID, capabilities.mode.mode.NAME) + log.info(string.format("Running SoundSwitch Refresh: %s | %s", chime, mode)) + if chime ~= "off" or mode ~= "Off" then + device:send(SoundSwitch:TonePlayGet({})) + end + end + + if tone_id > 0 and playbackMode <= 2 then + local minDuration = math.max(duration, 4) + device.thread:call_with_delay(minDuration + 0.5, soundSwitch_refresh) + device.thread:call_with_delay(minDuration + 4, soundSwitch_refresh) + end + +end + +local function rebuildTones(device) + device:emit_event(capabilities.mode.mode("Rebuild List")) + device:send(SoundSwitch:TonesNumberGet({})) +end + +local function refresh_handler(self, device) + device:default_refresh() + device:send(Version:Get({})) + device:send(Notification:Get({ + notification_type = Notification.notification_type.POWER_MANAGEMENT, + event = Notification.event.power_management.STATE_IDLE, + v1_alarm_type = 0 + })) + device:send(SoundSwitch:ConfigurationGet({})) + device:send(SoundSwitch:TonePlayGet({})) +end + +local function setMode_handler(self, device, command) + local mode_value = command.args.mode + local mode_split = string.find(mode_value, ":") + + if mode_split ~= nil then + mode_value = string.sub(mode_value, 1, mode_split - 1) + end + log.info(string.format("Command: setMode (%s)", mode_value)) + + if mode_value == 'Rebuild List' then + rebuildTones(device) + elseif mode_value == 'Off' then + playTone(device, 0x00) + else + playTone(device, tonumber(mode_value)) + end +end + +local function setVolume_handler(self, device, cmd) + local new_volume = st_utils.clamp_value(cmd.args.volume, 0, 100) + device:send(SoundSwitch:ConfigurationSet({ volume = new_volume })) +end + +local function volumeUp_handler(self, device, cmd) + local volume = device:get_latest_state("main", capabilities.audioVolume.ID, capabilities.audioVolume.volume.NAME) or 50 + volume = st_utils.clamp_value(volume + 2, 0, 100) + device:send(SoundSwitch:ConfigurationSet({ volume = volume })) +end + +local function volumeDown_handler(self, device, cmd) + local volume = device:get_latest_state("main", capabilities.audioVolume.ID, capabilities.audioVolume.volume.NAME) or 50 + volume = st_utils.clamp_value(volume - 2, 0, 100) + device:send(SoundSwitch:ConfigurationSet({ volume = volume })) +end + +local function tone_on(self, device) + playTone(device, 0xFF) +end + +local function tone_off(self, device) + playTone(device, 0x00) +end + +local function tones_number_report_handler(self, device, cmd) + local total_tones = cmd.args.supported_tones + + --Max 50 tones per Zooz settings + if total_tones > 50 then + total_tones = 50 + end + + local tones_list = { } + device:set_field("TOTAL_TONES", total_tones) + device:set_field("TONES_LIST_TMP", tones_list) + + --Get info on all tones + for tone = 1, total_tones do + device:send(SoundSwitch:ToneInfoGet({ tone_identifier = tone })) + end +end + +local function tone_info_report_handler(self, device, cmd) + local tone_id = tonumber(cmd.args.tone_identifier) + local tone_name = cmd.args.name + local duration = cmd.args.tone_duration + local total_tones = device:get_field("TOTAL_TONES") + local tones_list = device:get_field("TONES_LIST_TMP") or {} + + tones_list[tone_id] = { name = tone_name, duration = duration } + device:set_field("TONES_LIST_TMP", tones_list) + + if tone_id >= total_tones or #tones_list >= total_tones then + log.info(string.format("Received info on all tones: tone_id %s, #tones_list %s, total_tones %s", tone_id, #tones_list, total_tones)) + + local tones_arguments = { "Off" } + for il, vl in ipairs(tones_list) do + table.insert(tones_arguments, getModeName(il, vl)) + end + + device:set_field("TONES_LIST", tones_list, { persist = true }) + device:emit_event(capabilities.mode.supportedModes({ "Rebuild List", table.unpack(tones_arguments) })) + device:emit_event(capabilities.mode.supportedArguments(tones_arguments)) + device:send(SoundSwitch:TonePlayGet({})) + end +end + +--- Handle when tone is played (TONE_PLAY_REPORT or BASIC_REPORT) +local function tone_playing(self, device, tone_id) + local tones_list = device:get_field("TONES_LIST") + + if tones_list == nil or tones_list == {} then + rebuildTones(device) + end + + if tone_id == 0 then + device:emit_event(capabilities.alarm.alarm.off()) + device:emit_event(capabilities.chime.chime.off()) + device:emit_event(capabilities.mode.mode("Off")) + else + local toneInfo = (tones_list or {})[tone_id] or { name = "Unknown", duration = "0" } + local modeName = getModeName(tone_id, toneInfo) + device:emit_event(capabilities.alarm.alarm.both()) + device:emit_event(capabilities.chime.chime.chime()) + device:emit_event(capabilities.mode.mode(modeName)) + end +end + +local function tone_play_report_handler(self, device, cmd) + local tone_id = tonumber(cmd.args.tone_identifier) + tone_playing(self, device, tone_id) +end + +local function basic_report_handler(self, device, cmd) + local tone_id = tonumber(cmd.args.value) + tone_playing(self, device, tone_id) +end + +--- Handle SoundSwitch Config Reports (volume) +local function soundSwitch_configuration_report(self, device, cmd) + local volume = st_utils.clamp_value(cmd.args.volume, 0, 100) + local default_tone = cmd.args.default_tone_identifer + device:emit_event(capabilities.audioVolume.volume(volume)) + device:set_field("TONE_DEFAULT", default_tone, { persist = true }) +end + +--- Handle power source changes +local function notification_report_handler(self, device, cmd) + if cmd.args.notification_type == Notification.notification_type.POWER_MANAGEMENT then + local event = cmd.args.event + local powerManagement = Notification.event.power_management + + if event == powerManagement.AC_MAINS_DISCONNECTED then + device:emit_event(capabilities.powerSource.powerSource.battery()) + elseif event == powerManagement.AC_MAINS_RE_CONNECTED or event == powerManagement.STATE_IDLE then + device:emit_event(capabilities.powerSource.powerSource.mains()) + end + end +end + +--- @param driver st.zwave.Driver +--- @param device st.zwave.Device +--- @param cmd st.zwave.CommandClass.Version.Report +local function version_report_handler(driver, device, cmd) + local major = cmd.args.application_version + local minor = cmd.args.application_sub_version + + -- Update the built in firmware capability, if available + update_firmwareUpdate_capability(driver, device, device.profile.components.main, major, minor) +end + +--- @param driver st.zwave.Driver +--- @param device st.zwave.Device +local function device_init(driver, device) + if (device:get_field("TONES_LIST") == nil or device:get_field("TONE_DEFAULT") == nil) then + rebuildTones(device) + end +end + +--- @param driver st.zwave.Driver +--- @param device st.zwave.Device +local function device_added(driver, device) + device:send(SoundSwitch:ConfigurationSet({ volume = 10 })) + updateFirmwareVersion(driver, device) + device:refresh() +end + +--- Handle preference changes (same as default but added hack for unsigned parameters) +--- @param driver st.zwave.Driver +--- @param device st.zwave.Device +--- @param event table +--- @param args +local function info_changed(driver, device, event, args) + local preferences = preferencesMap.get_device_parameters(device) + + if preferences then + local did_configuration_change = false + for id, value in pairs(device.preferences) do + if args.old_st_store.preferences[id] ~= value and preferences[id] then + local new_parameter_value = preferencesMap.to_numeric_value(device.preferences[id]) + --Hack to convert to signed integer + local size_factor = math.floor(256 ^ preferences[id].size) + if new_parameter_value >= (size_factor / 2) then + new_parameter_value = new_parameter_value - size_factor + end + --END Hack + device:send(Configuration:Set({ parameter_number = preferences[id].parameter_number, size = preferences[id].size, configuration_value = new_parameter_value })) + did_configuration_change = true + end + end + + if did_configuration_change then + local delayed_command = function() + device:send(Basic:Set({ value = 0x00 })) + end + device.thread:call_with_delay(1, delayed_command) + end + + end +end + +local zooz_zse50 = { + NAME = "Zooz ZSE50", + can_handle = require("zooz-zse50.can_handle"), + + supported_capabilities = { + capabilities.battery, + capabilities.chime, + capabilities.mode, + capabilities.audioVolume, + capabilities.powerSource, + capabilities.firmwareUpdate, + capabilities.configuration, + capabilities.refresh + }, + + zwave_handlers = { + [cc.BASIC] = { + [Basic.REPORT] = basic_report_handler + }, + [cc.SOUND_SWITCH] = { + [SoundSwitch.TONES_NUMBER_REPORT] = tones_number_report_handler, + [SoundSwitch.TONE_INFO_REPORT] = tone_info_report_handler, + [SoundSwitch.TONE_PLAY_REPORT] = tone_play_report_handler, + [SoundSwitch.CONFIGURATION_REPORT] = soundSwitch_configuration_report + }, + [cc.NOTIFICATION] = { + [Notification.REPORT] = notification_report_handler + }, + [cc.VERSION] = { + [Version.REPORT] = version_report_handler + } + }, + + capability_handlers = { + [capabilities.mode.ID] = { + [capabilities.mode.commands.setMode.NAME] = setMode_handler + }, + [capabilities.audioVolume.ID] = { + [capabilities.audioVolume.commands.setVolume.NAME] = setVolume_handler, + [capabilities.audioVolume.commands.volumeUp.NAME] = volumeUp_handler, + [capabilities.audioVolume.commands.volumeDown.NAME] = volumeDown_handler + }, + [capabilities.refresh.ID] = { + [capabilities.refresh.commands.refresh.NAME] = refresh_handler + }, + [capabilities.alarm.ID] = { + [capabilities.alarm.commands.both.NAME] = tone_on, + [capabilities.alarm.commands.off.NAME] = tone_off + }, + [capabilities.chime.ID] = { + [capabilities.chime.commands.chime.NAME] = tone_on, + [capabilities.chime.commands.off.NAME] = tone_off + }, + + }, + + lifecycle_handlers = { + init = device_init, + added = device_added, + infoChanged = info_changed + } +} + +defaults.register_for_default_handlers(zooz_zse50, zooz_zse50.supported_capabilities) + +return zooz_zse50 From 8b4ae58e494ee07f198fd9a9ab05eda222cd922e Mon Sep 17 00:00:00 2001 From: Inovelli <37669481+InovelliUSA@users.noreply.github.com> Date: Thu, 9 Apr 2026 14:34:04 -0600 Subject: [PATCH 15/29] WWSTCERT-9786 Inovelli - adding vzw31 red series dimmer switch (#2654) * Inovelli - adding vzw31 red series dimmer switch * needed to add multilevel report handler to pass test suite * adding tests for vzw31 * removing extra code for button value init --- .../SmartThings/zwave-switch/fingerprints.yml | 6 + .../profiles/inovelli-dimmer-vzw31-sn.yml | 284 +++++++++++++++ .../zwave-switch/src/inovelli/can_handle.lua | 3 +- .../zwave-switch/src/inovelli/sub_drivers.lua | 1 + .../src/inovelli/vzw31-sn/can_handle.lua | 19 + .../src/inovelli/vzw31-sn/init.lua | 77 ++++ .../zwave-switch/src/preferences.lua | 27 ++ .../src/test/test_inovelli_vzw31_sn.lua | 287 +++++++++++++++ .../src/test/test_inovelli_vzw31_sn_child.lua | 335 ++++++++++++++++++ .../test_inovelli_vzw31_sn_preferences.lua | 151 ++++++++ 10 files changed, 1189 insertions(+), 1 deletion(-) create mode 100644 drivers/SmartThings/zwave-switch/profiles/inovelli-dimmer-vzw31-sn.yml create mode 100644 drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/can_handle.lua create mode 100644 drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/init.lua create mode 100644 drivers/SmartThings/zwave-switch/src/test/test_inovelli_vzw31_sn.lua create mode 100644 drivers/SmartThings/zwave-switch/src/test/test_inovelli_vzw31_sn_child.lua create mode 100644 drivers/SmartThings/zwave-switch/src/test/test_inovelli_vzw31_sn_preferences.lua diff --git a/drivers/SmartThings/zwave-switch/fingerprints.yml b/drivers/SmartThings/zwave-switch/fingerprints.yml index ccd11184d5..d0d10f2e5a 100644 --- a/drivers/SmartThings/zwave-switch/fingerprints.yml +++ b/drivers/SmartThings/zwave-switch/fingerprints.yml @@ -56,6 +56,12 @@ zwaveManufacturer: productType: 0x0003 productId: 0x0001 deviceProfileName: inovelli-dimmer + - id: "Inovelli/VZW31-SN" + deviceLabel: Inovelli Dimmer Red Series + manufacturerId: 0x031E + productType: 0x0015 + productId: 0x0001 + deviceProfileName: inovelli-dimmer-vzw31-sn - id: "Inovelli/VZW32-SN" deviceLabel: Inovelli mmWave Dimmer Red Series manufacturerId: 0x031E diff --git a/drivers/SmartThings/zwave-switch/profiles/inovelli-dimmer-vzw31-sn.yml b/drivers/SmartThings/zwave-switch/profiles/inovelli-dimmer-vzw31-sn.yml new file mode 100644 index 0000000000..e2da4a3239 --- /dev/null +++ b/drivers/SmartThings/zwave-switch/profiles/inovelli-dimmer-vzw31-sn.yml @@ -0,0 +1,284 @@ +name: inovelli-dimmer-vzw31-sn +components: +- id: main + capabilities: + - id: switch + version: 1 + - id: switchLevel + version: 1 + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + - id: refresh + version: 1 + categories: + - name: Switch +- id: button1 + label: Down Button + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController +- id: button2 + label: Up Button + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController +- id: button3 + label: Config Button + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController +preferences: + - name: "notificationChild" + title: "Add Child Device - Notification" + description: "Create Separate Child Device for Notification Control" + required: false + preferenceType: boolean + definition: + default: false + - name: "notificationType" + title: "Notification Effect" + description: "This is the notification effect used by the notification child device" + required: false + preferenceType: enumeration + definition: + options: + "255": "Clear" + "1": "Solid" + "2": "Fast Blink" + "3": "Slow Blink" + "4": "Pulse" + "5": "Chase" + "6": "Open/Close" + "7": "Small-to-Big" + "8": "Aurora" + "9": "Slow Falling" + "10": "Medium Falling" + "11": "Fast Falling" + "12": "Slow Rising" + "13": "Medium Rising" + "14": "Fast Rising" + "15": "Medium Blink" + "16": "Slow Chase" + "17": "Fast Chase" + "18": "Fast Siren" + "19": "Slow Siren" + default: 1 + - name: "parameter158" + title: "158. Switch Mode" + description: "Use as a Dimmer or an On/Off switch" + required: true + preferenceType: enumeration + definition: + options: + "0": "Dimmer (default)" + "1": "On/Off" + default: 0 + - name: "parameter52" + title: "52. Smart Bulb Mode" + description: "For use with Smart Bulbs that need constant power and are controlled via commands rather than power. Smart Bulb Mode does not work in Dumb 3-Way Switch mode." + required: true + preferenceType: enumeration + definition: + options: + "0": "Disabled (default)" + "1": "Smart Bulb Mode" + default: 0 + - name: "parameter22" + title: "22. Aux Switch Type" + description: "Set the Aux switch type. Smart Bulb Mode does not work in Dumb 3-Way Switch mode." + required: true + preferenceType: enumeration + definition: + options: + "0": "None (default)" + "1": "3-Way Dumb Switch" + "2": "3-Way Aux Switch" + "3": "Single Pole Full Sine Wave" + default: 0 + - name: "parameter1" + title: "1. Dimming Speed (Remote)" + description: "This changes the speed that the light dims up when controlled from the hub. A setting of '0' turns the light immediately on. Increasing the value slows down the transition speed. Value is multiplied by 100ms. + Default=25 (2500ms or 2.5s)" + required: false + preferenceType: number + definition: + minimum: 0 + maximum: 255 + default: 25 + - name: "parameter2" + title: "2. Dimming Speed (Local)" + description: "This changes the speed that the light dims up when controlled at the switch. A setting of '0' turns the light immediately on. Increasing the value slows down the transition speed. Value is multiplied by 100ms. + (i.e 25 = 2500ms or 2.5s) Default=255 (Sync with parameter 1)" + required: false + preferenceType: number + definition: + minimum: 0 + maximum: 255 + default: 255 + - name: "parameter3" + title: "3. Ramp Rate (Remote)" + description: "This changes the speed that the light turns on when controlled from the hub. A setting of '0' turns the light immediately on. Increasing the value slows down the transition speed. Value is multiplied by 100ms. + (i.e 25 = 2500ms or 2.5s) Default=255 (Sync with parameter 1)" + required: false + preferenceType: number + definition: + minimum: 0 + maximum: 255 + default: 255 + - name: "parameter4" + title: "4. Ramp Rate (Local)" + description: "This changes the speed that the light turns on when controlled at the switch. A setting of '0' turns the light immediately on. Increasing the value slows down the transition speed. Value is multiplied by 100ms. + (i.e 25 = 2500ms or 2.5s) Default=255 (Sync with parameter 3)" + required: false + preferenceType: number + definition: + minimum: 0 + maximum: 255 + default: 255 + - name: "parameter9" + title: "9. Minimum Level" + description: "The minimum level that the light can be dimmed. Useful when the user has a light that does not turn on or flickers at a lower level." + required: true + preferenceType: number + definition: + minimum: 1 + maximum: 99 + default: 1 + - name: "parameter10" + title: "10. Maximum Level" + description: "The maximum level that the light can be dimmed. Useful when the user wants to limit the maximum brighness." + required: true + preferenceType: number + definition: + minimum: 2 + maximum: 100 + default: 100 + - name: "parameter15" + title: "15. Level After Power Restored" + description: "The level the switch will return to when power is restored after power failure. + 0=Off + 1-100=Set Level + 101=Use previous level." + required: true + preferenceType: number + definition: + minimum: 0 + maximum: 101 + default: 101 + - name: "parameter18" + title: "18. Active Power Reports" + description: "Power level change that will result in a new power report being sent. + 0 = Disabled + 1-32767 = 0.1W-3276.7W." + required: true + preferenceType: number + definition: + minimum: 0 + maximum: 32767 + default: 100 + - name: "parameter19" + title: "19. Periodic Power & Energy Reports" + description: "Time period between consecutive power & energy reports being sent (in seconds). The timer is reset after each report is sent." + required: true + preferenceType: number + definition: + minimum: 0 + maximum: 32767 + default: 3600 + - name: "parameter20" + title: "20. Active Energy Reports" + description: "Energy level change that will result in a new energy report being sent. + 0 = Disabled + 1-32767 = 0.01kWh-327.67kWh." + required: true + preferenceType: number + definition: + minimum: 0 + maximum: 32767 + default: 100 + - name: "parameter50" + title: "50. Button Press Delay" + description: "Adjust the delay used in scene control. 0=no delay (disables multi-tap scenes), 1=100ms, 2=200ms, 3=300ms, etc." + required: true + preferenceType: enumeration + definition: + options: + "0": "0ms" + "1": "100ms" + "2": "200ms" + "3": "300ms" + "4": "400ms" + "5": "500ms (default)" + "6": "600ms" + "7": "700ms" + "8": "800ms" + "9": "900ms" + default: 5 + - name: "parameter95" + title: "95. LED Indicator Color (w/On)" + description: "Set the color of the Full LED Indicator when the load is on." + required: true + preferenceType: enumeration + definition: + options: + "0": "Red" + "7": "Orange" + "28": "Lemon" + "64": "Lime" + "85": "Green" + "106": "Teal" + "127": "Cyan" + "148": "Aqua" + "170": "Blue (default)" + "190": "Violet" + "212": "Magenta" + "234": "Pink" + "255": "White" + default: 170 + - name: "parameter96" + title: "96. LED Indicator Color (w/Off)" + description: "Set the color of the Full LED Indicator when the load is off." + required: true + preferenceType: enumeration + definition: + options: + "0": "Red" + "7": "Orange" + "28": "Lemon" + "64": "Lime" + "85": "Green" + "106": "Teal" + "127": "Cyan" + "148": "Aqua" + "170": "Blue (default)" + "190": "Violet" + "212": "Magenta" + "234": "Pink" + "255": "White" + default: 170 + - name: "parameter97" + title: "97. LED Indicator Intensity (w/On)" + description: "Set the intensity of the Full LED Indicator when the load is on." + required: true + preferenceType: number + definition: + minimum: 0 + maximum: 100 + default: 50 + - name: "parameter98" + title: "98. LED Indicator Intensity (w/Off)" + description: "Set the intensity of the Full LED Indicator when the load is off." + required: true + preferenceType: number + definition: + minimum: 0 + maximum: 100 + default: 5 \ No newline at end of file diff --git a/drivers/SmartThings/zwave-switch/src/inovelli/can_handle.lua b/drivers/SmartThings/zwave-switch/src/inovelli/can_handle.lua index 7c0f6be77b..c8ba7ac681 100644 --- a/drivers/SmartThings/zwave-switch/src/inovelli/can_handle.lua +++ b/drivers/SmartThings/zwave-switch/src/inovelli/can_handle.lua @@ -3,6 +3,7 @@ local INOVELLI_FINGERPRINTS = { { mfr = 0x031E, prod = 0x0017, model = 0x0001 }, -- Inovelli VZW32-SN + { mfr = 0x031E, prod = 0x0015, model = 0x0001 }, -- Inovelli VZW31-SN { mfr = 0x031E, prod = 0x0001, model = 0x0001 }, -- Inovelli LZW31SN { mfr = 0x031E, prod = 0x0003, model = 0x0001 }, -- Inovelli LZW31 } @@ -17,4 +18,4 @@ local function can_handle_inovelli(opts, driver, device, ...) return false end -return can_handle_inovelli +return can_handle_inovelli \ No newline at end of file diff --git a/drivers/SmartThings/zwave-switch/src/inovelli/sub_drivers.lua b/drivers/SmartThings/zwave-switch/src/inovelli/sub_drivers.lua index e182120ece..2fdea81379 100644 --- a/drivers/SmartThings/zwave-switch/src/inovelli/sub_drivers.lua +++ b/drivers/SmartThings/zwave-switch/src/inovelli/sub_drivers.lua @@ -5,5 +5,6 @@ local lazy_load = require "lazy_load_subdriver" return { lazy_load("inovelli.lzw31-sn"), + lazy_load("inovelli.vzw31-sn"), lazy_load("inovelli.vzw32-sn") } diff --git a/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/can_handle.lua b/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/can_handle.lua new file mode 100644 index 0000000000..2446c06dde --- /dev/null +++ b/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/can_handle.lua @@ -0,0 +1,19 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local INOVELLI_MANUFACTURER_ID = 0x031E +local INOVELLI_VZW31_SN_PRODUCT_TYPE = 0x0015 +local INOVELLI_DIMMER_PRODUCT_ID = 0x0001 + +local function can_handle_vzw31_sn(opts, driver, device, ...) + if device:id_match( + INOVELLI_MANUFACTURER_ID, + INOVELLI_VZW31_SN_PRODUCT_TYPE, + INOVELLI_DIMMER_PRODUCT_ID + ) then + return true, require("inovelli.vzw31-sn") + end + return false +end + +return can_handle_vzw31_sn diff --git a/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/init.lua b/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/init.lua new file mode 100644 index 0000000000..1dec88e745 --- /dev/null +++ b/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/init.lua @@ -0,0 +1,77 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local capabilities = require "st.capabilities" +--- @type st.zwave.CommandClass.SwitchMultilevel +local SwitchMultilevel = (require "st.zwave.CommandClass.SwitchMultilevel")({version=4}) +--- @type st.zwave.CommandClass.Meter +local Meter = (require "st.zwave.CommandClass.Meter")({ version = 3 }) +--- @type st.zwave.CommandClass.Association +local Association = (require "st.zwave.CommandClass.Association")({ version = 1 }) +--- @type st.device +local st_device = require "st.device" +local cc = require "st.zwave.CommandClass" + + +local supported_button_values = {"pushed","held","down_hold","pushed_2x","pushed_3x","pushed_4x","pushed_5x"} + + +local function refresh_handler(driver, device) + device:send(SwitchMultilevel:Get({})) + device:send(Meter:Get({ scale = Meter.scale.electric_meter.WATTS })) + device:send(Meter:Get({ scale = Meter.scale.electric_meter.KILOWATT_HOURS })) +end + +local function device_added(driver, device) + if device.network_type ~= st_device.NETWORK_TYPE_CHILD then + device:send(Association:Set({grouping_identifier = 1, node_ids = {driver.environment_info.hub_zwave_id}})) + for _, component in pairs(device.profile.components) do + if component.id ~= "main" and component.id ~= "LEDColorConfiguration" then + device:emit_component_event( + component, + capabilities.button.supportedButtonValues( + supported_button_values, + { visibility = { displayed = false } } + ) + ) + device:emit_component_event( + component, + capabilities.button.numberOfButtons({value = 1}, { visibility = { displayed = false } }) + ) + end + end + refresh_handler(driver, device) + else + device:emit_event(capabilities.colorControl.hue(1)) + device:emit_event(capabilities.colorControl.saturation(1)) + device:emit_event(capabilities.colorTemperature.colorTemperatureRange({ value = {minimum = 2700, maximum = 6500} })) + device:emit_event(capabilities.switchLevel.level(100)) + device:emit_event(capabilities.switch.switch("off")) + end +end + +local function onoff_level_report_handler(driver, device, cmd) + local value = cmd.args.target_value and cmd.args.target_value or cmd.args.value + device:emit_event(value == 0 and capabilities.switch.switch.off() or capabilities.switch.switch.on()) + device:emit_event(capabilities.switchLevel.level(value)) +end + +local vzw31_sn = { + NAME = "Inovelli VZW31-SN Dimmer", + lifecycle_handlers = { + added = device_added, + }, + zwave_handlers = { + [cc.SWITCH_MULTILEVEL] = { + [SwitchMultilevel.REPORT] = onoff_level_report_handler + } + }, + capability_handlers = { + [capabilities.refresh.ID] = { + [capabilities.refresh.commands.refresh.NAME] = refresh_handler + } + }, + can_handle = require("inovelli.vzw31-sn.can_handle") +} + +return vzw31_sn \ No newline at end of file diff --git a/drivers/SmartThings/zwave-switch/src/preferences.lua b/drivers/SmartThings/zwave-switch/src/preferences.lua index 798efaddf0..09155cdd7d 100644 --- a/drivers/SmartThings/zwave-switch/src/preferences.lua +++ b/drivers/SmartThings/zwave-switch/src/preferences.lua @@ -59,6 +59,33 @@ local devices = { switchType = {parameter_number = 22, size = 1} } }, + INOVELLI_VZW31_SN = { + MATCHING_MATRIX = { + mfrs = 0x031E, + product_types = {0x0015}, + product_ids = 0x0001 + }, + PARAMETERS = { + parameter158 = {parameter_number = 158, size = 1}, + parameter52 = {parameter_number = 52, size = 1}, + parameter1 = {parameter_number = 1, size = 1}, + parameter2 = {parameter_number = 2, size = 1}, + parameter3 = {parameter_number = 3, size = 1}, + parameter4 = {parameter_number = 4, size = 1}, + parameter9 = {parameter_number = 9, size = 1}, + parameter10 = {parameter_number = 10, size = 1}, + parameter15 = {parameter_number = 15, size = 1}, + parameter18 = {parameter_number = 18, size = 1}, + parameter19 = {parameter_number = 19, size = 2}, + parameter20 = {parameter_number = 20, size = 2}, + parameter22 = {parameter_number = 22, size = 1}, + parameter50 = {parameter_number = 50, size = 1}, + parameter95 = {parameter_number = 95, size = 1}, + parameter96 = {parameter_number = 96, size = 1}, + parameter97 = {parameter_number = 97, size = 1}, + parameter98 = {parameter_number = 98, size = 1}, + } + }, INOVELLI_VZW32_SN = { MATCHING_MATRIX = { mfrs = 0x031E, diff --git a/drivers/SmartThings/zwave-switch/src/test/test_inovelli_vzw31_sn.lua b/drivers/SmartThings/zwave-switch/src/test/test_inovelli_vzw31_sn.lua new file mode 100644 index 0000000000..a372a94eec --- /dev/null +++ b/drivers/SmartThings/zwave-switch/src/test/test_inovelli_vzw31_sn.lua @@ -0,0 +1,287 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local test = require "integration_test" +local capabilities = require "st.capabilities" +local zw = require "st.zwave" +local zw_test_utils = require "integration_test.zwave_test_utils" +local SwitchBinary = (require "st.zwave.CommandClass.SwitchBinary")({version=2}) +local SwitchMultilevel = (require "st.zwave.CommandClass.SwitchMultilevel")({version=4}) +local Basic = (require "st.zwave.CommandClass.Basic")({version=1}) +local CentralScene = (require "st.zwave.CommandClass.CentralScene")({version=3}) +local Association = (require "st.zwave.CommandClass.Association")({version=1}) +local Meter = (require "st.zwave.CommandClass.Meter")({version=3}) +local t_utils = require "integration_test.utils" + +-- Inovelli VZW31-SN device identifiers +local INOVELLI_MANUFACTURER_ID = 0x031E +local INOVELLI_VZW31_SN_PRODUCT_TYPE = 0x0015 +local INOVELLI_VZW31_SN_PRODUCT_ID = 0x0001 +local LED_BAR_COMPONENT_NAME = "LEDColorConfiguration" + +-- Device endpoints with supported command classes +local inovelli_vzw31_sn_endpoints = { + { + command_classes = { + {value = zw.SWITCH_BINARY}, + {value = zw.SWITCH_MULTILEVEL}, + {value = zw.BASIC}, + {value = zw.CONFIGURATION}, + {value = zw.CENTRAL_SCENE}, + {value = zw.ASSOCIATION}, + {value = zw.METER}, + } + } +} + +-- Create mock device +local mock_inovelli_vzw31_sn = test.mock_device.build_test_zwave_device({ + profile = t_utils.get_profile_definition("inovelli-dimmer-vzw31-sn.yml"), + zwave_endpoints = inovelli_vzw31_sn_endpoints, + zwave_manufacturer_id = INOVELLI_MANUFACTURER_ID, + zwave_product_type = INOVELLI_VZW31_SN_PRODUCT_TYPE, + zwave_product_id = INOVELLI_VZW31_SN_PRODUCT_ID +}) + +local function test_init() + test.mock_device.add_test_device(mock_inovelli_vzw31_sn) +end +test.set_test_init_function(test_init) + +local supported_button_values = {"pushed","held","down_hold","pushed_2x","pushed_3x","pushed_4x","pushed_5x"} + +-- Test device initialization +test.register_coroutine_test( + "Device should initialize properly on added lifecycle event", + function() + test.socket.capability:__set_channel_ordering("relaxed") + test.socket.device_lifecycle:__queue_receive({ mock_inovelli_vzw31_sn.id, "added" }) + + for button_name, _ in pairs(mock_inovelli_vzw31_sn.profile.components) do + if button_name ~= "main" and button_name ~= LED_BAR_COMPONENT_NAME then + test.socket.capability:__expect_send( + mock_inovelli_vzw31_sn:generate_test_message( + button_name, + capabilities.button.supportedButtonValues( + supported_button_values, + { visibility = { displayed = false } } + ) + ) + ) + test.socket.capability:__expect_send( + mock_inovelli_vzw31_sn:generate_test_message( + button_name, + capabilities.button.numberOfButtons({ value = 1 }, { visibility = { displayed = false } }) + ) + ) + end + end + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + Association:Set({ + grouping_identifier = 1, + node_ids = {}, -- Mock hub Z-Wave ID + payload = "\x01", -- Should contain grouping_identifier = 1 + }) + ) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + SwitchMultilevel:Get({}) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + Meter:Get({ scale = Meter.scale.electric_meter.WATTS }) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + Meter:Get({ scale = Meter.scale.electric_meter.KILOWATT_HOURS }) + ) + ) + end +) + +-- Test switch on command +test.register_coroutine_test( + "Switch on command should send Basic Set with ON value", + function() + test.timer.__create_and_queue_test_time_advance_timer(3, "oneshot") + test.socket.capability:__queue_receive({ + mock_inovelli_vzw31_sn.id, + { capability = "switch", command = "on", args = {} } + }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + Basic:Set({ value = SwitchBinary.value.ON_ENABLE }) + ) + ) + test.wait_for_events() + test.mock_time.advance_time(3) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + SwitchMultilevel:Get({}) + ) + ) + end +) + +-- Test switch off command +test.register_coroutine_test( + "Switch off command should send Basic Set with OFF value", + function() + test.timer.__create_and_queue_test_time_advance_timer(3, "oneshot") + test.socket.capability:__queue_receive({ + mock_inovelli_vzw31_sn.id, + { capability = "switch", command = "off", args = {} } + }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + Basic:Set({ value = SwitchBinary.value.OFF_DISABLE }) + ) + ) + test.wait_for_events() + test.mock_time.advance_time(3) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + SwitchMultilevel:Get({}) + ) + ) + end +) + +-- Test switch level command +test.register_coroutine_test( + "Switch level command should send SwitchMultilevel Set", + function() + test.timer.__create_and_queue_test_time_advance_timer(3, "oneshot") + + test.socket.capability:__queue_receive({ + mock_inovelli_vzw31_sn.id, + { capability = "switchLevel", command = "setLevel", args = { 50 } } + }) + + local expected_command = SwitchMultilevel:Set({ value = 50, duration = "default" }) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + expected_command + ) + ) + + test.wait_for_events() + test.mock_time.advance_time(3) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + SwitchMultilevel:Get({}) + ) + ) + end +) + +-- Test central scene notifications +test.register_message_test( + "Central scene notification should emit button events", + { + { + channel = "zwave", + direction = "receive", + message = { mock_inovelli_vzw31_sn.id, zw_test_utils.zwave_test_build_receive_command(CentralScene:Notification({ + scene_number = 1, + key_attributes=CentralScene.key_attributes.KEY_PRESSED_1_TIME + })) } + }, + { + channel = "capability", + direction = "send", + message = mock_inovelli_vzw31_sn:generate_test_message("button1", capabilities.button.button.pushed({ + state_change = true + })) + }, + }, + { + inner_block_ordering = "relaxed" + } +) + +-- Test central scene notifications - button2 pressed 4 times +test.register_message_test( + "Central scene notification button2 pressed 4 times should emit button events", + { + { + channel = "zwave", + direction = "receive", + message = { mock_inovelli_vzw31_sn.id, zw_test_utils.zwave_test_build_receive_command(CentralScene:Notification({ + scene_number = 2, + key_attributes=CentralScene.key_attributes.KEY_PRESSED_4_TIMES + })) } + }, + { + channel = "capability", + direction = "send", + message = mock_inovelli_vzw31_sn:generate_test_message("button2", capabilities.button.button.pushed_4x({ + state_change = true + })) + }, + }, + { + inner_block_ordering = "relaxed" + } +) + +-- Test refresh capability +test.register_message_test( + "Refresh capability should request switch level and meter data", + { + { + channel = "capability", + direction = "receive", + message = { + mock_inovelli_vzw31_sn.id, + { capability = "refresh", command = "refresh", args = {} } + } + }, + { + channel = "zwave", + direction = "send", + message = zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + SwitchMultilevel:Get({}) + ) + }, + { + channel = "zwave", + direction = "send", + message = zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + Meter:Get({ scale = Meter.scale.electric_meter.WATTS }) + ) + }, + { + channel = "zwave", + direction = "send", + message = zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + Meter:Get({ scale = Meter.scale.electric_meter.KILOWATT_HOURS }) + ) + }, + }, + { + inner_block_ordering = "relaxed" + } +) + +test.run_registered_tests() diff --git a/drivers/SmartThings/zwave-switch/src/test/test_inovelli_vzw31_sn_child.lua b/drivers/SmartThings/zwave-switch/src/test/test_inovelli_vzw31_sn_child.lua new file mode 100644 index 0000000000..dea43715ab --- /dev/null +++ b/drivers/SmartThings/zwave-switch/src/test/test_inovelli_vzw31_sn_child.lua @@ -0,0 +1,335 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local test = require "integration_test" +local capabilities = require "st.capabilities" +local zw = require "st.zwave" +local zw_test_utils = require "integration_test.zwave_test_utils" +local Configuration = (require "st.zwave.CommandClass.Configuration")({version=4}) +local t_utils = require "integration_test.utils" +local st_device = require "st.device" + +-- Inovelli VZW31-SN device identifiers +local INOVELLI_MANUFACTURER_ID = 0x031E +local INOVELLI_VZW31_SN_PRODUCT_TYPE = 0x0015 +local INOVELLI_VZW31_SN_PRODUCT_ID = 0x0001 + +-- Device endpoints with supported command classes +local inovelli_vzw31_sn_endpoints = { + { + command_classes = { + {value = zw.SWITCH_BINARY}, + {value = zw.SWITCH_MULTILEVEL}, + {value = zw.BASIC}, + {value = zw.CONFIGURATION}, + {value = zw.CENTRAL_SCENE}, + {value = zw.ASSOCIATION}, + } + } +} + +-- Create mock parent device +local mock_parent_device = test.mock_device.build_test_zwave_device({ + profile = t_utils.get_profile_definition("inovelli-dimmer-vzw31-sn.yml"), + zwave_endpoints = inovelli_vzw31_sn_endpoints, + zwave_manufacturer_id = INOVELLI_MANUFACTURER_ID, + zwave_product_type = INOVELLI_VZW31_SN_PRODUCT_TYPE, + zwave_product_id = INOVELLI_VZW31_SN_PRODUCT_ID +}) + +-- Create mock child device (notification device) +local mock_child_device = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition("rgbw-bulb.yml"), + parent_device_id = mock_parent_device.id, + parent_assigned_child_key = "notification" +}) + +-- Set child device network type +mock_child_device.network_type = st_device.NETWORK_TYPE_CHILD + +local function test_init() + test.mock_device.add_test_device(mock_parent_device) + test.mock_device.add_test_device(mock_child_device) +end +test.set_test_init_function(test_init) + +-- Test child device initialization +test.register_message_test( + "Child device should initialize with default color values", + { + { + channel = "device_lifecycle", + direction = "receive", + message = { mock_child_device.id, "added" }, + }, + { + channel = "capability", + direction = "send", + message = mock_child_device:generate_test_message("main", capabilities.colorControl.hue(1)) + }, + { + channel = "capability", + direction = "send", + message = mock_child_device:generate_test_message("main", capabilities.colorControl.saturation(1)) + }, + { + channel = "capability", + direction = "send", + message = mock_child_device:generate_test_message("main", capabilities.colorTemperature.colorTemperatureRange({ value = {minimum = 2700, maximum = 6500} })) + }, + { + channel = "capability", + direction = "send", + message = mock_child_device:generate_test_message("main", capabilities.switchLevel.level(100)) + }, + { + channel = "capability", + direction = "send", + message = mock_child_device:generate_test_message("main", capabilities.switch.switch("off")) + }, + }, + { + inner_block_ordering = "relaxed" + } +) + +-- Test child device switch on command (Gen3 uses parameter 99, same as vzw32) +test.register_coroutine_test( + "Child device switch on should emit events and send configuration to parent", + function() + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + + -- Calculate expected configuration value using the same logic as getNotificationValue (Gen3) + local function huePercentToValue(value) + if value <= 2 then + return 0 + elseif value >= 98 then + return 255 + else + return math.floor(value / 100 * 255 + 0.5) -- utils.round equivalent + end + end + + local notificationValue = 0 + local level = 100 -- Default level for child devices + local color = 100 -- Default color for child devices (since device starts with no hue state) + local effect = 1 -- Default notificationType + + notificationValue = notificationValue + (effect * 16777216) + notificationValue = notificationValue + (huePercentToValue(color) * 65536) + notificationValue = notificationValue + (level * 256) + notificationValue = notificationValue + (255 * 1) + + test.socket.capability:__queue_receive({ + mock_child_device.id, + { capability = "switch", command = "on", args = {} } + }) + + test.socket.capability:__expect_send( + mock_child_device:generate_test_message("main", capabilities.switch.switch("on")) + ) + + test.wait_for_events() + test.mock_time.advance_time(1) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent_device, + Configuration:Set({ + parameter_number = 99, + configuration_value = notificationValue, + size = 4 + }) + ) + ) + end +) + +-- Test child device switch off command +test.register_coroutine_test( + "Child device switch off should emit events and send configuration to parent", + function() + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + + test.socket.capability:__queue_receive({ + mock_child_device.id, + { capability = "switch", command = "off", args = {} } + }) + + test.socket.capability:__expect_send( + mock_child_device:generate_test_message("main", capabilities.switch.switch("off")) + ) + + test.wait_for_events() + test.mock_time.advance_time(1) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent_device, + Configuration:Set({ + parameter_number = 99, + configuration_value = 0, -- Switch off sends 0 + size = 4 + }) + ) + ) + end +) + +-- Test child device level command +test.register_coroutine_test( + "Child device level command should emit events and send configuration to parent", + function() + local level = math.random(1, 99) + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + + -- Calculate expected configuration value using the same logic as getNotificationValue (Gen3) + local function huePercentToValue(value) + if value <= 2 then + return 0 + elseif value >= 98 then + return 255 + else + return math.floor(value / 100 * 255 + 0.5) -- utils.round equivalent + end + end + + local notificationValue = 0 + local effect = 1 -- Default notificationType + local color = 100 -- Default color for child devices (since device starts with no hue state) + + notificationValue = notificationValue + (effect * 16777216) + notificationValue = notificationValue + (huePercentToValue(color) * 65536) + notificationValue = notificationValue + (level * 256) -- Use the actual level from command + notificationValue = notificationValue + (255 * 1) + + test.socket.capability:__queue_receive({ + mock_child_device.id, + { capability = "switchLevel", command = "setLevel", args = { level } } + }) + + test.socket.capability:__expect_send( + mock_child_device:generate_test_message("main", capabilities.switchLevel.level(level)) + ) + + test.socket.capability:__expect_send( + mock_child_device:generate_test_message("main", capabilities.switch.switch("on")) + ) + + test.wait_for_events() + test.mock_time.advance_time(1) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent_device, + Configuration:Set({ + parameter_number = 99, + configuration_value = notificationValue, + size = 4 + }) + ) + ) + end +) + +-- Test child device color command +test.register_coroutine_test( + "Child device color command should emit events and send configuration to parent", + function() + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + + -- Calculate expected configuration value using the same logic as getNotificationValue (Gen3) + local function huePercentToValue(value) + if value <= 2 then + return 0 + elseif value >= 98 then + return 255 + else + return math.floor(value / 100 * 255 + 0.5) -- utils.round equivalent + end + end + + local notificationValue = 0 + local level = 100 -- Default level for child devices + local color = math.random(0, 100) + local effect = 1 -- Default notificationType + + notificationValue = notificationValue + (effect * 16777216) + notificationValue = notificationValue + (huePercentToValue(color) * 65536) + notificationValue = notificationValue + (level * 256) + notificationValue = notificationValue + (255 * 1) + + test.socket.capability:__queue_receive({ + mock_child_device.id, + { capability = "colorControl", command = "setColor", args = {{ hue = color, saturation = 100 }} } + }) + + test.socket.capability:__expect_send( + mock_child_device:generate_test_message("main", capabilities.colorControl.hue(color)) + ) + + test.socket.capability:__expect_send( + mock_child_device:generate_test_message("main", capabilities.colorControl.saturation(100)) + ) + + test.socket.capability:__expect_send( + mock_child_device:generate_test_message("main", capabilities.switch.switch("on")) + ) + + test.wait_for_events() + test.mock_time.advance_time(1) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent_device, + Configuration:Set({ + parameter_number = 99, + configuration_value = notificationValue, + size = 4 + }) + ) + ) + end +) + +-- Test child device color temperature command +test.register_coroutine_test( + "Child device color temperature command should emit events and send configuration to parent", + function() + local temp = math.random(2700, 6500) + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + + test.socket.capability:__queue_receive({ + mock_child_device.id, + { capability = "colorTemperature", command = "setColorTemperature", args = { temp } } + }) + + test.socket.capability:__expect_send( + mock_child_device:generate_test_message("main", capabilities.colorControl.hue(100)) + ) + + test.socket.capability:__expect_send( + mock_child_device:generate_test_message("main", capabilities.colorTemperature.colorTemperature(temp)) + ) + + test.socket.capability:__expect_send( + mock_child_device:generate_test_message("main", capabilities.switch.switch("on")) + ) + + test.wait_for_events() + test.mock_time.advance_time(1) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent_device, + Configuration:Set({ + parameter_number = 99, + configuration_value = 33514751, -- Calculated: effect(1)*16777216 + hue(255)*65536 + level(100)*256 + 255 + size = 4 + }) + ) + ) + end +) + +test.run_registered_tests() diff --git a/drivers/SmartThings/zwave-switch/src/test/test_inovelli_vzw31_sn_preferences.lua b/drivers/SmartThings/zwave-switch/src/test/test_inovelli_vzw31_sn_preferences.lua new file mode 100644 index 0000000000..2b4812ad7b --- /dev/null +++ b/drivers/SmartThings/zwave-switch/src/test/test_inovelli_vzw31_sn_preferences.lua @@ -0,0 +1,151 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local test = require "integration_test" +local zw = require "st.zwave" +local zw_test_utils = require "integration_test.zwave_test_utils" +local Configuration = (require "st.zwave.CommandClass.Configuration")({ version=4 }) +local t_utils = require "integration_test.utils" + +-- Inovelli VZW31-SN device identifiers +local INOVELLI_MANUFACTURER_ID = 0x031E +local INOVELLI_VZW31_SN_PRODUCT_TYPE = 0x0015 +local INOVELLI_VZW31_SN_PRODUCT_ID = 0x0001 + +-- Device endpoints with supported command classes +local inovelli_vzw31_sn_endpoints = { + { + command_classes = { + { value = zw.SWITCH_BINARY }, + { value = zw.SWITCH_MULTILEVEL }, + { value = zw.BASIC }, + { value = zw.CONFIGURATION }, + { value = zw.CENTRAL_SCENE }, + { value = zw.ASSOCIATION }, + } + } +} + +-- Create mock device +local mock_inovelli_vzw31_sn = test.mock_device.build_test_zwave_device({ + profile = t_utils.get_profile_definition("inovelli-dimmer-vzw31-sn.yml"), + zwave_endpoints = inovelli_vzw31_sn_endpoints, + zwave_manufacturer_id = INOVELLI_MANUFACTURER_ID, + zwave_product_type = INOVELLI_VZW31_SN_PRODUCT_TYPE, + zwave_product_id = INOVELLI_VZW31_SN_PRODUCT_ID +}) + +local function test_init() + test.mock_device.add_test_device(mock_inovelli_vzw31_sn) +end +test.set_test_init_function(test_init) + +-- Test parameter 1 (example preference) +do + local new_param_value = 10 + test.register_coroutine_test( + "Parameter 1 should be updated in the device configuration after change", + function() + test.socket.device_lifecycle:__queue_receive(mock_inovelli_vzw31_sn:generate_info_changed({preferences = {parameter1 = new_param_value}})) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + Configuration:Set({ + parameter_number = 1, + configuration_value = new_param_value, + size = 1 + }) + ) + ) + end + ) +end + +-- Test parameter 52 (example preference) +do + local new_param_value = 25 + test.register_coroutine_test( + "Parameter 52 should be updated in the device configuration after change", + function() + test.socket.device_lifecycle:__queue_receive(mock_inovelli_vzw31_sn:generate_info_changed({preferences = {parameter52 = new_param_value}})) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + Configuration:Set({ + parameter_number = 52, + configuration_value = new_param_value, + size = 1 + }) + ) + ) + end + ) +end + +-- Test parameter 158 (example preference) +do + local new_param_value = 5 + test.register_coroutine_test( + "Parameter 158 should be updated in the device configuration after change", + function() + test.socket.device_lifecycle:__queue_receive(mock_inovelli_vzw31_sn:generate_info_changed({preferences = {parameter158 = new_param_value}})) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + Configuration:Set({ + parameter_number = 158, + configuration_value = new_param_value, + size = 1 + }) + ) + ) + end + ) +end + +-- Test parameter 19 (2-byte parameter); must be non-default (default 3600) or driver won't send Configuration:Set +do + local new_param_value = 1800 + test.register_coroutine_test( + "Parameter 19 should be updated in the device configuration after change", + function() + test.socket.device_lifecycle:__queue_receive(mock_inovelli_vzw31_sn:generate_info_changed({preferences = {parameter19 = new_param_value}})) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_inovelli_vzw31_sn, + Configuration:Set({ + parameter_number = 19, + configuration_value = new_param_value, + size = 2, + }) + ) + ) + end + ) +end + +-- Test notificationChild preference (special case for child device creation) +do + local new_param_value = true + test.register_coroutine_test( + "notificationChild preference should create child device when enabled", + function() + test.socket.device_lifecycle:__queue_receive(mock_inovelli_vzw31_sn:generate_info_changed({preferences = {notificationChild = new_param_value}})) + + -- Expect child device creation + mock_inovelli_vzw31_sn:expect_device_create({ + type = "EDGE_CHILD", + label = "nil Notification", -- This will be the parent label + "Notification" + profile = "rgbw-bulb", + parent_device_id = mock_inovelli_vzw31_sn.id, + parent_assigned_child_key = "notification" + }) + end + ) +end + +test.run_registered_tests() From 4faf053a170604b343c69db246759e100b0d39f9 Mon Sep 17 00:00:00 2001 From: Konrad K <33450498+KKlimczukS@users.noreply.github.com> Date: Tue, 14 Apr 2026 16:40:48 +0200 Subject: [PATCH 16/29] WWSTCERT-8045 - Aeotec Home Energy Meter Gen8 (Revert + fixes) (#2791) WWSTCERT-8045 - Aeotec Home Energy Meter Gen8 --- .../zwave-electric-meter/fingerprints.yml | 16 + ...tec-home-energy-meter-gen8-1-phase-con.yml | 107 +++ ...tec-home-energy-meter-gen8-1-phase-pro.yml | 22 + ...tec-home-energy-meter-gen8-2-phase-con.yml | 148 ++++ ...tec-home-energy-meter-gen8-2-phase-pro.yml | 31 + ...tec-home-energy-meter-gen8-3-phase-con.yml | 189 +++++ ...tec-home-energy-meter-gen8-3-phase-pro.yml | 40 + ...aeotec-home-energy-meter-gen8-sald-con.yml | 13 + ...aeotec-home-energy-meter-gen8-sald-pro.yml | 13 + .../1-phase/can_handle.lua | 18 + .../1-phase/init.lua | 123 +++ .../2-phase/can_handle.lua | 17 + .../2-phase/init.lua | 123 +++ .../3-phase/can_handle.lua | 18 + .../3-phase/init.lua | 123 +++ .../can_handle.lua | 22 + .../aeotec-home-energy-meter-gen8/init.lua | 49 ++ .../power_consumption.lua | 32 + .../sub_drivers.lua | 10 + .../zwave-electric-meter/src/init.lua | 21 + .../zwave-electric-meter/src/preferences.lua | 95 +++ .../zwave-electric-meter/src/sub_drivers.lua | 1 + ..._aeotec_home_energy_meter_gen8_1_phase.lua | 560 +++++++++++++ ..._aeotec_home_energy_meter_gen8_2_phase.lua | 654 +++++++++++++++ ..._aeotec_home_energy_meter_gen8_3_phase.lua | 749 ++++++++++++++++++ 25 files changed, 3194 insertions(+) create mode 100644 drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-1-phase-con.yml create mode 100644 drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-1-phase-pro.yml create mode 100644 drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-2-phase-con.yml create mode 100644 drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-2-phase-pro.yml create mode 100644 drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-3-phase-con.yml create mode 100644 drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-3-phase-pro.yml create mode 100644 drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-sald-con.yml create mode 100644 drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-sald-pro.yml create mode 100644 drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/1-phase/can_handle.lua create mode 100644 drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/1-phase/init.lua create mode 100644 drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/2-phase/can_handle.lua create mode 100644 drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/2-phase/init.lua create mode 100644 drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/3-phase/can_handle.lua create mode 100644 drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/3-phase/init.lua create mode 100644 drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/can_handle.lua create mode 100644 drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/init.lua create mode 100644 drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/power_consumption.lua create mode 100644 drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/sub_drivers.lua create mode 100644 drivers/SmartThings/zwave-electric-meter/src/preferences.lua create mode 100644 drivers/SmartThings/zwave-electric-meter/src/test/test_aeotec_home_energy_meter_gen8_1_phase.lua create mode 100644 drivers/SmartThings/zwave-electric-meter/src/test/test_aeotec_home_energy_meter_gen8_2_phase.lua create mode 100644 drivers/SmartThings/zwave-electric-meter/src/test/test_aeotec_home_energy_meter_gen8_3_phase.lua diff --git a/drivers/SmartThings/zwave-electric-meter/fingerprints.yml b/drivers/SmartThings/zwave-electric-meter/fingerprints.yml index 7c32d646e3..c580510daa 100644 --- a/drivers/SmartThings/zwave-electric-meter/fingerprints.yml +++ b/drivers/SmartThings/zwave-electric-meter/fingerprints.yml @@ -35,6 +35,22 @@ zwaveManufacturer: productType: 0x0002 productId: 0x0001 deviceProfileName: base-electric-meter + - id: "0x0371/0x0003/0x0033" #HEM Gen8 1 Phase EU, AU + deviceLabel: Aeotec Home Energy Meter Gen8 Consumption + manufacturerId: 0x0371 + productId: 0x0033 + deviceProfileName: aeotec-home-energy-meter-gen8-1-phase-con + - id: "0x0371/0x0003/0x0034" # HEM Gen8 3 Phase EU, AU + deviceLabel: Aeotec Home Energy Meter Gen8 Consumption + manufacturerId: 0x0371 + productId: 0x0034 + deviceProfileName: aeotec-home-energy-meter-gen8-3-phase-con + - id: "0x0371/0x0103/0x002E" # HEM Gen8 2 Phase US + deviceLabel: Aeotec Home Energy Meter Gen8 Consumption + manufacturerId: 0x0371 + productType: 0x0103 + productId: 0x002E + deviceProfileName: aeotec-home-energy-meter-gen8-2-phase-con zwaveGeneric: - id: "GenericEnergyMeter" deviceLabel: Energy Monitor diff --git a/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-1-phase-con.yml b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-1-phase-con.yml new file mode 100644 index 0000000000..b4de02cb6a --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-1-phase-con.yml @@ -0,0 +1,107 @@ +name: aeotec-home-energy-meter-gen8-1-phase-con +components: +- id: main + label: "Sum Consumption" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + - id: powerConsumptionReport + version: 1 + - id: refresh + version: 1 + categories: + - name: PowerMeasurementSensor +- id: clamp1 + label: "Clamp 1" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + categories: + - name: PowerMeasurementSensor +preferences: + - name: thresholdCheck + title: "3. Threshold Check Enable/Disable" + description: "Enable selective reporting only when power change reaches a certain threshold or percentage set in 4 -19 below. This is used to reduce network traffic." + preferenceType: enumeration + definition: + options: + 0: "Disable" + 1: "Enable" + default: 1 + - name: imWThresholdTotal + title: "4. Import W threshold (total)" + description: "Threshold change in import wattage to induce an automatic report (Whole HEM)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: imWThresholdPhaseA + title: "5. Import W threshold (Phase A)" + description: "Threshold change in import wattage to induce an automatic report (Phase A)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: exWThresholdTotal + title: "8. Export W threshold (total)" + description: "Threshold change in export wattage to induce an automatic report (Whole HEM)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: exWThresholdPhaseA + title: "9. Export W threshold (Phase A)" + description: "Threshold change in export wattage to induce an automatic report (Phase A)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: imWPctThresholdTotal + title: "12. Import W threshold (total)" + description: "Percentage change in import wattage to induce an automatic report (Whole HEM)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: imWPctThresholdPhaseA + title: "13. Import W threshold (Phase A)" + description: "Percentage change in import wattage to induce an automatic report (Phase A)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: exWPctThresholdTotal + title: "16. Export W threshold (total)" + description: "Percentage change in export wattage to induce an automatic report (Whole HEM)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: exWPctThresholdPhaseA + title: "17. Export W threshold (Phase A)" + description: "Percentage change in export wattage to induce an automatic report (Phase A)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: autoRootDeviceReport + title: "32. Auto report of root device" + description: "Enable automatic report of root device." + preferenceType: enumeration + definition: + options: + 0: "Disable" + 1: "Enable" + default: 0 diff --git a/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-1-phase-pro.yml b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-1-phase-pro.yml new file mode 100644 index 0000000000..9510e27037 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-1-phase-pro.yml @@ -0,0 +1,22 @@ +name: aeotec-home-energy-meter-gen8-1-phase-pro +components: +- id: main + label: "Sum Production" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + - id: refresh + version: 1 + categories: + - name: PowerMeasurementSensor +- id: clamp2 + label: "Clamp 1" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + categories: + - name: PowerMeasurementSensor \ No newline at end of file diff --git a/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-2-phase-con.yml b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-2-phase-con.yml new file mode 100644 index 0000000000..64b2a510f9 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-2-phase-con.yml @@ -0,0 +1,148 @@ +name: aeotec-home-energy-meter-gen8-2-phase-con +components: +- id: main + label: "Sum Consumption" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + - id: powerConsumptionReport + version: 1 + - id: refresh + version: 1 + categories: + - name: PowerMeasurementSensor +- id: clamp1 + label: "Clamp 1" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + categories: + - name: PowerMeasurementSensor +- id: clamp3 + label: "Clamp 2" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + categories: + - name: PowerMeasurementSensor +preferences: + - name: thresholdCheck + title: "3. Threshold Check Enable/Disable" + description: "Enable selective reporting only when power change reaches a certain threshold or percentage set in 4 -19 below. This is used to reduce network traffic." + preferenceType: enumeration + definition: + options: + 0: "Disable" + 1: "Enable" + default: 1 + - name: imWThresholdTotal + title: "4. Import W threshold (total)" + description: "Threshold change in import wattage to induce an automatic report (Whole HEM)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: imWThresholdPhaseA + title: "5. Import W threshold (Phase A)" + description: "Threshold change in import wattage to induce an automatic report (Phase A)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: imWhresholdPhaseB + title: "6. Import W threshold (Phase B)" + description: "Threshold change in import wattage to induce an automatic report (Phase B)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: exWhresholdTotal + title: "8. Export W threshold (total)" + description: "Threshold change in export wattage to induce an automatic report (Whole HEM)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: exWThresholdPhaseA + title: "9. Export W threshold (Phase A)" + description: "Threshold change in export wattage to induce an automatic report (Phase A)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: exWThresholdPhaseB + title: "10. Export W threshold (Phase B)" + description: "Threshold change in export wattage to induce an automatic report (Phase B)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: imWPctThresholdTotal + title: "12. Import W threshold (total)" + description: "Percentage change in import wattage to induce an automatic report (Whole HEM)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: imWPctThresholdPhaseA + title: "13. Import W threshold (Phase A)" + description: "Percentage change in import wattage to induce an automatic report (Phase A)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: imWPctThresholdPhaseB + title: "14. Import W threshold (Phase B)." + description: "Percentage change in import wattage to induce an automatic report (Phase B)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: exWPctThresholdTotal + title: "16. Export W threshold (total)" + description: "Percentage change in export wattage to induce an automatic report (Whole HEM)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: exWPctThresholdPhaseA + title: "17. Export W threshold (Phase A)" + description: "Percentage change in export wattage to induce an automatic report (Phase A)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: exWPctThresholdPhaseB + title: "18. Export W threshold (Phase B)" + description: "Percentage change in export wattage to induce an automatic report (Phase B)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: autoRootDeviceReport + title: "32. Auto report of root device" + description: "Enable automatic report of root device." + preferenceType: enumeration + definition: + options: + 0: "Disable" + 1: "Enable" + default: 0 diff --git a/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-2-phase-pro.yml b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-2-phase-pro.yml new file mode 100644 index 0000000000..be4adf21c5 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-2-phase-pro.yml @@ -0,0 +1,31 @@ +name: aeotec-home-energy-meter-gen8-2-phase-pro +components: +- id: main + label: "Sum Production" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + - id: refresh + version: 1 + categories: + - name: PowerMeasurementSensor +- id: clamp2 + label: "Clamp 1" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + categories: + - name: PowerMeasurementSensor +- id: clamp4 + label: "Clamp 2" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + categories: + - name: PowerMeasurementSensor \ No newline at end of file diff --git a/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-3-phase-con.yml b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-3-phase-con.yml new file mode 100644 index 0000000000..e1d44731bf --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-3-phase-con.yml @@ -0,0 +1,189 @@ +name: aeotec-home-energy-meter-gen8-3-phase-con +components: +- id: main + label: "Sum Consumption" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + - id: powerConsumptionReport + version: 1 + - id: refresh + version: 1 + categories: + - name: PowerMeasurementSensor +- id: clamp1 + label: "Clamp 1" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + categories: + - name: PowerMeasurementSensor +- id: clamp3 + label: "Clamp 2" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + categories: + - name: PowerMeasurementSensor +- id: clamp5 + label: "Clamp 3" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + categories: + - name: PowerMeasurementSensor +preferences: + - name: thresholdCheck + title: "3. Threshold Check Enable/Disable" + description: "Enable selective reporting only when power change reaches a certain threshold or percentage set in 4 -19 below. This is used to reduce network traffic." + preferenceType: enumeration + definition: + options: + 0: "Disable" + 1: "Enable" + default: 1 + - name: imWThresholdTotal + title: "4. Import W threshold (total)" + description: "Threshold change in import wattage to induce an automatic report (Whole HEM)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: imWThresholdPhaseA + title: "5. Import W threshold (Phase A)" + description: "Threshold change in import wattage to induce an automatic report (Phase A)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: imWhresholdPhaseB + title: "6. Import W threshold (Phase B)" + description: "Threshold change in import wattage to induce an automatic report (Phase B)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: imtWThresholdPhaseC + title: "7. Import W threshold (Phase C)" + description: "Threshold change in import wattage to induce an automatic report (Phase C)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: exWhresholdTotal + title: "8. Export W threshold (total)" + description: "Threshold change in export wattage to induce an automatic report (Whole HEM)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: exWThresholdPhaseA + title: "9. Export W threshold (Phase A)" + description: "Threshold change in export wattage to induce an automatic report (Phase A)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: exWThresholdPhaseB + title: "10. Export W threshold (Phase B)" + description: "Threshold change in export wattage to induce an automatic report (Phase B)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: exWThresholdPhaseC + title: "11. Export W threshold (Phase C)" + description: "Threshold change in export wattage to induce an automatic report (Phase C)." + preferenceType: integer + definition: + minimum: 0 + maximum: 60000 + default: 50 + - name: imWPctThresholdTotal + title: "12. Import W threshold (total)" + description: "Percentage change in import wattage to induce an automatic report (Whole HEM)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: imWPctThresholdPhaseA + title: "13. Import W threshold (Phase A)" + description: "Percentage change in import wattage to induce an automatic report (Phase A)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: imWPctThresholdPhaseB + title: "14. Import W threshold (Phase B)" + description: "Percentage change in import wattage to induce an automatic report (Phase B)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: imWPctThresholdPhaseC + title: "15. Import W threshold (Phase C)" + description: "Percentage change in import wattage to induce an automatic report (Phase C)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: exWPctThresholdTotal + title: "16. Export W threshold (total)" + description: "Percentage change in export wattage to induce an automatic report (Whole HEM)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: exWPctThresholdPhaseA + title: "17. Export W threshold (Phase A)" + description: "Percentage change in export wattage to induce an automatic report (Phase A)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: exWPctThresholdPhaseB + title: "18. Export W threshold (Phase B)" + description: "Percentage change in export wattage to induce an automatic report (Phase B)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: exWPctThresholdPhaseC + title: "19. Export W threshold (Phase C)" + description: "Percentage change in export wattage to induce an automatic report (Phase C)." + preferenceType: integer + definition: + minimum: 0 + maximum: 100 + default: 20 + - name: autoRootDeviceReport + title: "32. Auto report of root device" + description: "Enable automatic report of root device." + preferenceType: enumeration + definition: + options: + 0: "Disable" + 1: "Enable" + default: 0 diff --git a/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-3-phase-pro.yml b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-3-phase-pro.yml new file mode 100644 index 0000000000..3efa762dda --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-3-phase-pro.yml @@ -0,0 +1,40 @@ +name: aeotec-home-energy-meter-gen8-3-phase-pro +components: +- id: main + label: "Sum Production" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + - id: refresh + version: 1 + categories: + - name: PowerMeasurementSensor +- id: clamp2 + label: "Clamp 1" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + categories: + - name: PowerMeasurementSensor +- id: clamp4 + label: "Clamp 2" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + categories: + - name: PowerMeasurementSensor +- id: clamp6 + label: "Clamp 3" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + categories: + - name: PowerMeasurementSensor \ No newline at end of file diff --git a/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-sald-con.yml b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-sald-con.yml new file mode 100644 index 0000000000..f0bf405fb7 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-sald-con.yml @@ -0,0 +1,13 @@ +name: aeotec-home-energy-meter-gen8-sald-con +components: +- id: main + label: "Settled Consumption" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + - id: refresh + version: 1 + categories: + - name: PowerMeasurementSensor \ No newline at end of file diff --git a/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-sald-pro.yml b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-sald-pro.yml new file mode 100644 index 0000000000..da05330d46 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/profiles/aeotec-home-energy-meter-gen8-sald-pro.yml @@ -0,0 +1,13 @@ +name: aeotec-home-energy-meter-gen8-sald-pro +components: +- id: main + label: "Settled Production" + capabilities: + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + - id: refresh + version: 1 + categories: + - name: PowerMeasurementSensor \ No newline at end of file diff --git a/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/1-phase/can_handle.lua b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/1-phase/can_handle.lua new file mode 100644 index 0000000000..6dd02b40fe --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/1-phase/can_handle.lua @@ -0,0 +1,18 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local AEOTEC_HOME_ENERGY_METER_GEN8_FINGERPRINTS = { + { mfr = 0x0371, prod = 0x0003, model = 0x0033 }, -- HEM Gen8 1 Phase EU + { mfr = 0x0371, prod = 0x0102, model = 0x002E } -- HEM Gen8 1 Phase AU +} + +local function can_handle_aeotec_meter_gen8_1_phase(opts, driver, device, ...) + for _, fingerprint in ipairs(AEOTEC_HOME_ENERGY_METER_GEN8_FINGERPRINTS) do + if device:id_match(fingerprint.mfr, fingerprint.prod, fingerprint.model) then + return true, require("aeotec-home-energy-meter-gen8.1-phase") + end + end + return false +end + +return can_handle_aeotec_meter_gen8_1_phase diff --git a/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/1-phase/init.lua b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/1-phase/init.lua new file mode 100644 index 0000000000..db69a9d52d --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/1-phase/init.lua @@ -0,0 +1,123 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local st_device = require "st.device" +local capabilities = require "st.capabilities" +--- @type st.zwave.CommandClass.Meter +local Meter = (require "st.zwave.CommandClass.Meter")({ version=4 }) +--- @type st.zwave.CommandClass +local cc = require "st.zwave.CommandClass" +local utils = require "st.utils" +local power_consumption = require("aeotec-home-energy-meter-gen8.power_consumption") + +local POWER_UNIT_WATT = "W" +local ENERGY_UNIT_KWH = "kWh" + +local HEM8_DEVICES = { + { profile = 'aeotec-home-energy-meter-gen8-1-phase-con', name = 'Aeotec Home Energy Meter 8 Consumption', endpoints = { 1, 3 } }, + { profile = 'aeotec-home-energy-meter-gen8-1-phase-pro', name = 'Aeotec Home Energy Meter 8 Production', child_key = 'pro', endpoints = { 2, 4 } }, + { profile = 'aeotec-home-energy-meter-gen8-sald-con', name = 'Aeotec Home Energy Meter 8 Settled Consumption', child_key = 'sald-con', endpoints = { 5 } }, + { profile = 'aeotec-home-energy-meter-gen8-sald-pro', name = 'Aeotec Home Energy Meter 8 Settled Production', child_key = 'sald-pro', endpoints = { 6 } } +} + +local function find_hem8_child_device_key_by_endpoint(endpoint) + for _, child in ipairs(HEM8_DEVICES) do + if child.endpoints then + for _, e in ipairs(child.endpoints) do + if e == endpoint then + return child.child_key + end + end + end + end +end + +local function meter_report_handler(driver, device, cmd, zb_rx) + local endpoint = cmd.src_channel + local device_to_emit_with = device + local child_device_key = find_hem8_child_device_key_by_endpoint(endpoint); + local child_device = device:get_child_by_parent_assigned_key(child_device_key) + + if(child_device) then + device_to_emit_with = child_device + end + + if cmd.args.scale == Meter.scale.electric_meter.KILOWATT_HOURS then + local event_arguments = { + value = cmd.args.meter_value, + unit = ENERGY_UNIT_KWH + } + -- energyMeter + device_to_emit_with:emit_event_for_endpoint( + cmd.src_channel, + capabilities.energyMeter.energy(event_arguments) + ) + + if endpoint == 5 then + -- powerConsumptionReport + power_consumption.emit_power_consumption_report_event(device, { value = event_arguments.value }) + end + elseif cmd.args.scale == Meter.scale.electric_meter.WATTS then + local event_arguments = { + value = cmd.args.meter_value, + unit = POWER_UNIT_WATT + } + -- powerMeter + device_to_emit_with:emit_event_for_endpoint( + cmd.src_channel, + capabilities.powerMeter.power(event_arguments) + ) + end +end + +local function do_refresh(self, device) + for _, d in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(d.endpoints) do + device:send(Meter:Get({scale = Meter.scale.electric_meter.KILOWATT_HOURS}, {dst_channels = {endpoint}})) + device:send(Meter:Get({scale = Meter.scale.electric_meter.WATTS}, {dst_channels = {endpoint}})) + end + end +end + +local function device_added(driver, device) + if device.network_type == st_device.NETWORK_TYPE_ZWAVE and not (device.child_ids and utils.table_size(device.child_ids) ~= 0) then + for i, hem8_child in ipairs(HEM8_DEVICES) do + if(hem8_child["child_key"]) then + local name = hem8_child.name + local metadata = { + type = "EDGE_CHILD", + label = name, + profile = hem8_child.profile, + parent_device_id = device.id, + parent_assigned_child_key = hem8_child.child_key, + vendor_provided_label = name + } + driver:try_create_device(metadata) + end + end + end + do_refresh(driver, device) +end + +local aeotec_home_energy_meter_gen8_1_phase = { + NAME = "Aeotec Home Energy Meter Gen8", + supported_capabilities = { + capabilities.powerConsumptionReport + }, + capability_handlers = { + [capabilities.refresh.ID] = { + [capabilities.refresh.commands.refresh.NAME] = do_refresh + } + }, + zwave_handlers = { + [cc.METER] = { + [Meter.REPORT] = meter_report_handler + } + }, + lifecycle_handlers = { + added = device_added + }, + can_handle = require("aeotec-home-energy-meter-gen8.1-phase.can_handle") +} + +return aeotec_home_energy_meter_gen8_1_phase diff --git a/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/2-phase/can_handle.lua b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/2-phase/can_handle.lua new file mode 100644 index 0000000000..ec694e2708 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/2-phase/can_handle.lua @@ -0,0 +1,17 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local AEOTEC_HOME_ENERGY_METER_GEN8_FINGERPRINTS = { + { mfr = 0x0371, prod = 0x0103, model = 0x002E } -- HEM Gen8 2 Phase US +} + +local function can_handle_aeotec_meter_gen8_2_phase(opts, driver, device, ...) + for _, fingerprint in ipairs(AEOTEC_HOME_ENERGY_METER_GEN8_FINGERPRINTS) do + if device:id_match(fingerprint.mfr, fingerprint.prod, fingerprint.model) then + return true, require("aeotec-home-energy-meter-gen8.2-phase") + end + end + return false +end + +return can_handle_aeotec_meter_gen8_2_phase diff --git a/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/2-phase/init.lua b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/2-phase/init.lua new file mode 100644 index 0000000000..8d78da66f7 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/2-phase/init.lua @@ -0,0 +1,123 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local st_device = require "st.device" +local capabilities = require "st.capabilities" +--- @type st.zwave.CommandClass.Meter +local Meter = (require "st.zwave.CommandClass.Meter")({ version=4 }) +--- @type st.zwave.CommandClass +local cc = require "st.zwave.CommandClass" +local utils = require "st.utils" +local power_consumption = require("aeotec-home-energy-meter-gen8.power_consumption") + +local POWER_UNIT_WATT = "W" +local ENERGY_UNIT_KWH = "kWh" + +local HEM8_DEVICES = { + { profile = 'aeotec-home-energy-meter-gen8-3-phase-con', name = 'Aeotec Home Energy Meter 8 Consumption', endpoints = { 1, 3, 5 } }, + { profile = 'aeotec-home-energy-meter-gen8-2-phase-pro', name = 'Aeotec Home Energy Meter 8 Production', child_key = 'pro', endpoints = { 2, 4, 6 } }, + { profile = 'aeotec-home-energy-meter-gen8-sald-con', name = 'Aeotec Home Energy Meter 8 Settled Consumption', child_key = 'sald-con', endpoints = { 7 } }, + { profile = 'aeotec-home-energy-meter-gen8-sald-pro', name = 'Aeotec Home Energy Meter 8 Settled Production', child_key = 'sald-pro', endpoints = { 8 } } +} + +local function find_hem8_child_device_key_by_endpoint(endpoint) + for _, child in ipairs(HEM8_DEVICES) do + if child.endpoints then + for _, e in ipairs(child.endpoints) do + if e == endpoint then + return child.child_key + end + end + end + end +end + +local function meter_report_handler(driver, device, cmd, zb_rx) + local endpoint = cmd.src_channel + local device_to_emit_with = device + local child_device_key = find_hem8_child_device_key_by_endpoint(endpoint); + local child_device = device:get_child_by_parent_assigned_key(child_device_key) + + if(child_device) then + device_to_emit_with = child_device + end + + if cmd.args.scale == Meter.scale.electric_meter.KILOWATT_HOURS then + local event_arguments = { + value = cmd.args.meter_value, + unit = ENERGY_UNIT_KWH + } + -- energyMeter + device_to_emit_with:emit_event_for_endpoint( + cmd.src_channel, + capabilities.energyMeter.energy(event_arguments) + ) + + if endpoint == 7 then + -- powerConsumptionReport + power_consumption.emit_power_consumption_report_event(device, { value = event_arguments.value }) + end + elseif cmd.args.scale == Meter.scale.electric_meter.WATTS then + local event_arguments = { + value = cmd.args.meter_value, + unit = POWER_UNIT_WATT + } + -- powerMeter + device_to_emit_with:emit_event_for_endpoint( + cmd.src_channel, + capabilities.powerMeter.power(event_arguments) + ) + end +end + +local function do_refresh(self, device) + for _, d in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(d.endpoints) do + device:send(Meter:Get({scale = Meter.scale.electric_meter.KILOWATT_HOURS}, {dst_channels = {endpoint}})) + device:send(Meter:Get({scale = Meter.scale.electric_meter.WATTS}, {dst_channels = {endpoint}})) + end + end +end + +local function device_added(driver, device) + if device.network_type == st_device.NETWORK_TYPE_ZWAVE and not (device.child_ids and utils.table_size(device.child_ids) ~= 0) then + for i, hem8_child in ipairs(HEM8_DEVICES) do + if(hem8_child["child_key"]) then + local name = hem8_child.name + local metadata = { + type = "EDGE_CHILD", + label = name, + profile = hem8_child.profile, + parent_device_id = device.id, + parent_assigned_child_key = hem8_child.child_key, + vendor_provided_label = name + } + driver:try_create_device(metadata) + end + end + end + do_refresh(driver, device) +end + +local aeotec_home_energy_meter_gen8_2_phase = { + NAME = "Aeotec Home Energy Meter Gen8", + supported_capabilities = { + capabilities.powerConsumptionReport + }, + capability_handlers = { + [capabilities.refresh.ID] = { + [capabilities.refresh.commands.refresh.NAME] = do_refresh + } + }, + zwave_handlers = { + [cc.METER] = { + [Meter.REPORT] = meter_report_handler + } + }, + lifecycle_handlers = { + added = device_added + }, + can_handle = require("aeotec-home-energy-meter-gen8.2-phase.can_handle") +} + +return aeotec_home_energy_meter_gen8_2_phase diff --git a/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/3-phase/can_handle.lua b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/3-phase/can_handle.lua new file mode 100644 index 0000000000..9f3cc6cb03 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/3-phase/can_handle.lua @@ -0,0 +1,18 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local AEOTEC_HOME_ENERGY_METER_GEN8_FINGERPRINTS = { + { mfr = 0x0371, prod = 0x0003, model = 0x0034 }, -- HEM Gen8 3 Phase EU + { mfr = 0x0371, prod = 0x0102, model = 0x0034 } -- HEM Gen8 3 Phase AU +} + +local function can_handle_aeotec_meter_gen8_3_phase(opts, driver, device, ...) + for _, fingerprint in ipairs(AEOTEC_HOME_ENERGY_METER_GEN8_FINGERPRINTS) do + if device:id_match(fingerprint.mfr, fingerprint.prod, fingerprint.model) then + return true, require("aeotec-home-energy-meter-gen8.3-phase") + end + end + return false +end + +return can_handle_aeotec_meter_gen8_3_phase diff --git a/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/3-phase/init.lua b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/3-phase/init.lua new file mode 100644 index 0000000000..cb1c582fb6 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/3-phase/init.lua @@ -0,0 +1,123 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local st_device = require "st.device" +local capabilities = require "st.capabilities" +--- @type st.zwave.CommandClass.Meter +local Meter = (require "st.zwave.CommandClass.Meter")({ version=4 }) +--- @type st.zwave.CommandClass +local cc = require "st.zwave.CommandClass" +local utils = require "st.utils" +local power_consumption = require("aeotec-home-energy-meter-gen8.power_consumption") + +local POWER_UNIT_WATT = "W" +local ENERGY_UNIT_KWH = "kWh" + +local HEM8_DEVICES = { + { profile = 'aeotec-home-energy-meter-gen8-3-phase-con', name = 'Aeotec Home Energy Meter 8 Consumption', endpoints = { 1, 3, 5, 7 } }, + { profile = 'aeotec-home-energy-meter-gen8-3-phase-pro', name = 'Aeotec Home Energy Meter 8 Production', child_key = 'pro', endpoints = { 2, 4, 6, 8 } }, + { profile = 'aeotec-home-energy-meter-gen8-sald-con', name = 'Aeotec Home Energy Meter 8 Settled Consumption', child_key = 'sald-con', endpoints = { 9 } }, + { profile = 'aeotec-home-energy-meter-gen8-sald-pro', name = 'Aeotec Home Energy Meter 8 Settled Production', child_key = 'sald-pro', endpoints = { 10 } } +} + +local function find_hem8_child_device_key_by_endpoint(endpoint) + for _, child in ipairs(HEM8_DEVICES) do + if child.endpoints then + for _, e in ipairs(child.endpoints) do + if e == endpoint then + return child.child_key + end + end + end + end +end + +local function meter_report_handler(driver, device, cmd, zb_rx) + local endpoint = cmd.src_channel + local device_to_emit_with = device + local child_device_key = find_hem8_child_device_key_by_endpoint(endpoint); + local child_device = device:get_child_by_parent_assigned_key(child_device_key) + + if(child_device) then + device_to_emit_with = child_device + end + + if cmd.args.scale == Meter.scale.electric_meter.KILOWATT_HOURS then + local event_arguments = { + value = cmd.args.meter_value, + unit = ENERGY_UNIT_KWH + } + -- energyMeter + device_to_emit_with:emit_event_for_endpoint( + cmd.src_channel, + capabilities.energyMeter.energy(event_arguments) + ) + + if endpoint == 9 then + -- powerConsumptionReport + power_consumption.emit_power_consumption_report_event(device, { value = event_arguments.value }) + end + elseif cmd.args.scale == Meter.scale.electric_meter.WATTS then + local event_arguments = { + value = cmd.args.meter_value, + unit = POWER_UNIT_WATT + } + -- powerMeter + device_to_emit_with:emit_event_for_endpoint( + cmd.src_channel, + capabilities.powerMeter.power(event_arguments) + ) + end +end + +local function do_refresh(self, device) + for _, d in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(d.endpoints) do + device:send(Meter:Get({scale = Meter.scale.electric_meter.KILOWATT_HOURS}, {dst_channels = {endpoint}})) + device:send(Meter:Get({scale = Meter.scale.electric_meter.WATTS}, {dst_channels = {endpoint}})) + end + end +end + +local function device_added(driver, device) + if device.network_type == st_device.NETWORK_TYPE_ZWAVE and not (device.child_ids and utils.table_size(device.child_ids) ~= 0) then + for i, hem8_child in ipairs(HEM8_DEVICES) do + if(hem8_child["child_key"]) then + local name = hem8_child.name + local metadata = { + type = "EDGE_CHILD", + label = name, + profile = hem8_child.profile, + parent_device_id = device.id, + parent_assigned_child_key = hem8_child.child_key, + vendor_provided_label = name + } + driver:try_create_device(metadata) + end + end + end + do_refresh(driver, device) +end + +local aeotec_home_energy_meter_gen8_3_phase = { + NAME = "Aeotec Home Energy Meter Gen8", + supported_capabilities = { + capabilities.powerConsumptionReport + }, + capability_handlers = { + [capabilities.refresh.ID] = { + [capabilities.refresh.commands.refresh.NAME] = do_refresh + } + }, + zwave_handlers = { + [cc.METER] = { + [Meter.REPORT] = meter_report_handler + } + }, + lifecycle_handlers = { + added = device_added + }, + can_handle = require("aeotec-home-energy-meter-gen8.3-phase.can_handle") +} + +return aeotec_home_energy_meter_gen8_3_phase diff --git a/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/can_handle.lua b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/can_handle.lua new file mode 100644 index 0000000000..918e703b69 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/can_handle.lua @@ -0,0 +1,22 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local AEOTEC_HOME_ENERGY_METER_GEN8_FINGERPRINTS = { + { mfr = 0x0371, prod = 0x0003, model = 0x0033 }, -- HEM Gen8 1 Phase EU + { mfr = 0x0371, prod = 0x0003, model = 0x0034 }, -- HEM Gen8 3 Phase EU + { mfr = 0x0371, prod = 0x0103, model = 0x002E }, -- HEM Gen8 2 Phase US + { mfr = 0x0371, prod = 0x0102, model = 0x002E }, -- HEM Gen8 1 Phase AU + { mfr = 0x0371, prod = 0x0102, model = 0x0034 }, -- HEM Gen8 3 Phase AU +} + +local function can_handle_aeotec_meter_gen8(opts, driver, device, ...) + for _, fingerprint in ipairs(AEOTEC_HOME_ENERGY_METER_GEN8_FINGERPRINTS) do + if device:id_match(fingerprint.mfr, fingerprint.prod, fingerprint.model) then + local subdriver = require("aeotec-home-energy-meter-gen8") + return true, subdriver + end + end + return false +end + +return can_handle_aeotec_meter_gen8 diff --git a/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/init.lua b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/init.lua new file mode 100644 index 0000000000..10d07de685 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/init.lua @@ -0,0 +1,49 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +--- @type st.zwave.CommandClass.Configuration +local Configuration = (require "st.zwave.CommandClass.Configuration")({ version=1 }) + +local function device_added(driver, device) + device:refresh() +end + +local function component_to_endpoint(device, component_id) + local ep_num = component_id:match("clamp(%d)") + return { ep_num and tonumber(ep_num) } +end + +local function endpoint_to_component(device, ep) + local meter_comp = string.format("clamp%d", ep) + if device.profile.components[meter_comp] ~= nil then + return meter_comp + else + return "main" + end +end + +local device_init = function(self, device) + device:set_component_to_endpoint_fn(component_to_endpoint) + device:set_endpoint_to_component_fn(endpoint_to_component) +end + +local do_configure = function (self, device) + device:send(Configuration:Set({parameter_number = 111, configuration_value = 300, size = 4})) -- ...every 5 min + device:send(Configuration:Set({parameter_number = 112, configuration_value = 300, size = 4})) -- ...every 5 min + device:send(Configuration:Set({parameter_number = 113, configuration_value = 300, size = 4})) -- ...every 5 min +end + +local aeotec_home_energy_meter_gen8 = { + NAME = "Aeotec Home Energy Meter Gen8", + lifecycle_handlers = { + added = device_added, + init = device_init, + doConfigure = do_configure + }, + can_handle = require("aeotec-home-energy-meter-gen8.can_handle"), + sub_drivers = { + require("aeotec-home-energy-meter-gen8.sub_drivers") + } +} + +return aeotec_home_energy_meter_gen8 diff --git a/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/power_consumption.lua b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/power_consumption.lua new file mode 100644 index 0000000000..2c32c5c964 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/power_consumption.lua @@ -0,0 +1,32 @@ +-- Copyright 2026 SmartThings, Inc. +-- Licensed under the Apache License, Version 2. + +local capabilities = require "st.capabilities" + +local LAST_REPORT_TIME = "LAST_REPORT_TIME" + +local power_consumption = {} + +power_consumption.emit_power_consumption_report_event = function (device, value) + -- powerConsumptionReport report interval + local current_time = os.time() + local last_time = device:get_field(LAST_REPORT_TIME) or 0 + local next_time = last_time + 60 * 15 -- 15 mins, the minimum interval allowed between reports + if current_time < next_time then + return + end + device:set_field(LAST_REPORT_TIME, current_time, { persist = true }) + local raw_value = value.value * 1000 -- 'Wh' + + local delta_energy = 0.0 + local current_power_consumption = device:get_latest_state('main', capabilities.powerConsumptionReport.ID, capabilities.powerConsumptionReport.powerConsumption.NAME) + if current_power_consumption ~= nil then + delta_energy = math.max(raw_value - current_power_consumption.energy, 0.0) + end + device:emit_event(capabilities.powerConsumptionReport.powerConsumption({ + energy = raw_value, + deltaEnergy = delta_energy + })) +end + +return power_consumption \ No newline at end of file diff --git a/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/sub_drivers.lua b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/sub_drivers.lua new file mode 100644 index 0000000000..98c3fb45f8 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/aeotec-home-energy-meter-gen8/sub_drivers.lua @@ -0,0 +1,10 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local lazy_load_if_possible = require "lazy_load_subdriver" +local sub_drivers = { + lazy_load_if_possible("aeotec-home-energy-meter-gen8.1-phase"), + lazy_load_if_possible("aeotec-home-energy-meter-gen8.2-phase"), + lazy_load_if_possible("aeotec-home-energy-meter-gen8.3-phase") +} +return sub_drivers diff --git a/drivers/SmartThings/zwave-electric-meter/src/init.lua b/drivers/SmartThings/zwave-electric-meter/src/init.lua index 66205758bd..851de3096f 100644 --- a/drivers/SmartThings/zwave-electric-meter/src/init.lua +++ b/drivers/SmartThings/zwave-electric-meter/src/init.lua @@ -7,11 +7,31 @@ local capabilities = require "st.capabilities" local defaults = require "st.zwave.defaults" --- @type st.zwave.Driver local ZwaveDriver = require "st.zwave.driver" +--- @type st.zwave.CommandClass.Configuration +local Configuration = (require "st.zwave.CommandClass.Configuration")({version=1}) + +local preferencesMap = require "preferences" local device_added = function (self, device) device:refresh() end +--- Handle preference changes +--- +--- @param driver st.zwave.Driver +--- @param device st.zwave.Device +--- @param event table +--- @param args +local function info_changed(driver, device, event, args) + local preferences = preferencesMap.get_device_parameters(device) + for id, value in pairs(device.preferences) do + if args.old_st_store.preferences[id] ~= value and preferences and preferences[id] then + local new_parameter_value = preferencesMap.to_numeric_value(device.preferences[id]) + device:send(Configuration:Set({ parameter_number = preferences[id].parameter_number, size = preferences[id].size, configuration_value = new_parameter_value })) + end + end +end + local driver_template = { supported_capabilities = { capabilities.powerMeter, @@ -19,6 +39,7 @@ local driver_template = { capabilities.refresh }, lifecycle_handlers = { + infoChanged = info_changed, added = device_added }, sub_drivers = require("sub_drivers"), diff --git a/drivers/SmartThings/zwave-electric-meter/src/preferences.lua b/drivers/SmartThings/zwave-electric-meter/src/preferences.lua new file mode 100644 index 0000000000..b1f14c25bd --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/preferences.lua @@ -0,0 +1,95 @@ +local devices = { + AEOTEC_HOME_ENERGY_METER_GEN8_1_PHASE = { + MATCHING_MATRIX = { + mfrs = 0x0371, + product_types = {0x0003, 0x0102 }, + product_ids = 0x0033 + }, + PARAMETERS = { + thresholdCheck = {parameter_number = 3, size = 1}, + imWThresholdTotal = {parameter_number = 4, size = 2}, + imWThresholdPhaseA = {parameter_number = 5, size = 2}, + exWThresholdTotal = {parameter_number = 8, size = 2}, + exWThresholdPhaseA = {parameter_number = 9, size = 2}, + imtWPctThresholdTotal = {parameter_number = 12, size = 1}, + imWPctThresholdPhaseA = {parameter_number = 13, size = 1}, + exWPctThresholdTotal = {parameter_number = 16, size = 1}, + exWPctThresholdPhaseA = {parameter_number = 17, size = 1}, + autoRootDeviceReport = {parameter_number = 32, size = 1}, + } + }, + AEOTEC_HOME_ENERGY_METER_GEN8_2_PHASE = { + MATCHING_MATRIX = { + mfrs = 0x0371, + product_types = 0x0103, + product_ids = 0x002E + }, + PARAMETERS = { + thresholdCheck = {parameter_number = 3, size = 1}, + imWThresholdTotal = {parameter_number = 4, size = 2}, + imWThresholdPhaseA = {parameter_number = 5, size = 2}, + imWThresholdPhaseB = {parameter_number = 6, size = 2}, + exWThresholdTotal = {parameter_number = 8, size = 2}, + exWThresholdPhaseA = {parameter_number = 9, size = 2}, + exWThresholdPhaseB = {parameter_number = 10, size = 2}, + imtWPctThresholdTotal = {parameter_number = 12, size = 1}, + imWPctThresholdPhaseA = {parameter_number = 13, size = 1}, + imWPctThresholdPhaseB = {parameter_number = 14, size = 1}, + exWPctThresholdTotal = {parameter_number = 16, size = 1}, + exWPctThresholdPhaseA = {parameter_number = 17, size = 1}, + exWPctThresholdPhaseB = {parameter_number = 18, size = 1}, + autoRootDeviceReport = {parameter_number = 32, size = 1}, + } + }, + AEOTEC_HOME_ENERGY_METER_GEN8_3_PHASE = { + MATCHING_MATRIX = { + mfrs = 0x0371, + product_types = {0x0003, 0x0102}, + product_ids = 0x0034 + }, + PARAMETERS = { + thresholdCheck = {parameter_number = 3, size = 1}, + imWThresholdTotal = {parameter_number = 4, size = 2}, + imWThresholdPhaseA = {parameter_number = 5, size = 2}, + imWThresholdPhaseB = {parameter_number = 6, size = 2}, + imWThresholdPhaseC = {parameter_number = 7, size = 2}, + exWThresholdTotal = {parameter_number = 8, size = 2}, + exWThresholdPhaseA = {parameter_number = 9, size = 2}, + exWThresholdPhaseB = {parameter_number = 10, size = 2}, + exWThresholdPhaseC = {parameter_number = 11, size = 2}, + imtWPctThresholdTotal = {parameter_number = 12, size = 1}, + imWPctThresholdPhaseA = {parameter_number = 13, size = 1}, + imWPctThresholdPhaseB = {parameter_number = 14, size = 1}, + imWPctThresholdPhaseC = {parameter_number = 15, size = 1}, + exWPctThresholdTotal = {parameter_number = 16, size = 1}, + exWPctThresholdPhaseA = {parameter_number = 17, size = 1}, + exWPctThresholdPhaseB = {parameter_number = 18, size = 1}, + exWPctThresholdPhaseC = {parameter_number = 19, size = 1}, + autoRootDeviceReport = {parameter_number = 32, size = 1}, + } + } +} + +local preferences = {} + +preferences.get_device_parameters = function(zw_device) + for _, device in pairs(devices) do + if zw_device:id_match( + device.MATCHING_MATRIX.mfrs, + device.MATCHING_MATRIX.product_types, + device.MATCHING_MATRIX.product_ids) then + return device.PARAMETERS + end + end + return nil +end + +preferences.to_numeric_value = function(new_value) + local numeric = tonumber(new_value) + if numeric == nil then -- in case the value is boolean + numeric = new_value and 1 or 0 + end + return numeric +end + +return preferences diff --git a/drivers/SmartThings/zwave-electric-meter/src/sub_drivers.lua b/drivers/SmartThings/zwave-electric-meter/src/sub_drivers.lua index 60d4a7380b..3c0e482bda 100644 --- a/drivers/SmartThings/zwave-electric-meter/src/sub_drivers.lua +++ b/drivers/SmartThings/zwave-electric-meter/src/sub_drivers.lua @@ -6,5 +6,6 @@ local sub_drivers = { lazy_load_if_possible("qubino-meter"), lazy_load_if_possible("aeotec-gen5-meter"), lazy_load_if_possible("aeon-meter"), + lazy_load_if_possible("aeotec-home-energy-meter-gen8"), } return sub_drivers diff --git a/drivers/SmartThings/zwave-electric-meter/src/test/test_aeotec_home_energy_meter_gen8_1_phase.lua b/drivers/SmartThings/zwave-electric-meter/src/test/test_aeotec_home_energy_meter_gen8_1_phase.lua new file mode 100644 index 0000000000..f581f457df --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/test/test_aeotec_home_energy_meter_gen8_1_phase.lua @@ -0,0 +1,560 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local test = require "integration_test" +local capabilities = require "st.capabilities" +local zw = require "st.zwave" +local zw_test_utils = require "integration_test.zwave_test_utils" +local Meter = (require "st.zwave.CommandClass.Meter")({version=4}) +local Configuration = (require "st.zwave.CommandClass.Configuration")({ version=4 }) +local t_utils = require "integration_test.utils" + +local AEOTEC_MFR_ID = 0x0371 +local AEOTEC_METER_PROD_TYPE = 0x0003 +local AEOTEC_METER_PROD_ID = 0x0033 + +local LAST_REPORT_TIME = "LAST_REPORT_TIME" + +local aeotec_meter_endpoints = { + { + command_classes = { + {value = zw.METER} + } + } +} + +local HEM8_DEVICES = { + { + profile = 'aeotec-home-energy-meter-gen8-1-phase-con', + name = 'Aeotec Home Energy Meter 8 Consumption', + endpoints = { 1, 3 } + }, + { + profile = 'aeotec-home-energy-meter-gen8-1-phase-pro', + name = 'Aeotec Home Energy Meter 8 Production', + child_key = 'pro', + endpoints = { 2, 4 } + }, + { + profile = 'aeotec-home-energy-meter-gen8-sald-con', + name = 'Aeotec Home Energy Meter 8 Settled Consumption', + child_key = 'sald-con', + endpoints = { 5 } + }, + { + profile = 'aeotec-home-energy-meter-gen8-sald-pro', + name = 'Aeotec Home Energy Meter 8 Settled Production', + child_key = 'sald-pro', + endpoints = { 6 } + } +} + +local mock_parent = test.mock_device.build_test_zwave_device({ + profile = t_utils.get_profile_definition(HEM8_DEVICES[1].profile .. '.yml'), + zwave_endpoints = aeotec_meter_endpoints, + zwave_manufacturer_id = AEOTEC_MFR_ID, + zwave_product_type = AEOTEC_METER_PROD_TYPE, + zwave_product_id = AEOTEC_METER_PROD_ID +}) + +local mock_child_prod = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition(HEM8_DEVICES[2].profile .. '.yml'), + parent_device_id = mock_parent.id, + parent_assigned_child_key = HEM8_DEVICES[2].child_key +}) + +local mock_child_sald_con = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition(HEM8_DEVICES[3].profile .. '.yml'), + parent_device_id = mock_parent.id, + parent_assigned_child_key = HEM8_DEVICES[3].child_key +}) + +local mock_child_sald_prod = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition(HEM8_DEVICES[4].profile .. '.yml'), + parent_device_id = mock_parent.id, + parent_assigned_child_key = HEM8_DEVICES[4].child_key +}) + +local function test_init() + test.mock_device.add_test_device(mock_parent) + test.mock_device.add_test_device(mock_child_prod) + test.mock_device.add_test_device(mock_child_sald_con) + test.mock_device.add_test_device(mock_child_sald_prod) +end + +test.set_test_init_function(test_init) + +test.register_coroutine_test( + "Added lifecycle event should create children for parent device", + function() + test.socket.zwave:__set_channel_ordering("relaxed") + test.socket.device_lifecycle:__queue_receive({ mock_parent.id, "added" }) + + for _, child in ipairs(HEM8_DEVICES) do + if(child["child_key"]) then + mock_parent:expect_device_create( + { + type = "EDGE_CHILD", + label = child.name, + profile = child.profile, + parent_device_id = mock_parent.id, + parent_assigned_child_key = child.child_key + } + ) + end + end + -- Refresh + for _, device in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(device.endpoints) do + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Meter:Get({scale = Meter.scale.electric_meter.WATTS}, { + encap = zw.ENCAP.AUTO, + src_channel = 0, + dst_channels = { endpoint } + }) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Meter:Get({scale = Meter.scale.electric_meter.KILOWATT_HOURS}, { + encap = zw.ENCAP.AUTO, + src_channel = 0, + dst_channels = { endpoint } + }) + ) + ) + end + end + end +) + +test.register_coroutine_test( + "Configure should configure all necessary attributes", + function() + test.socket.zwave:__set_channel_ordering("relaxed") + test.socket.device_lifecycle:__queue_receive({ mock_parent.id, "doConfigure" }) + + test.socket.zwave:__expect_send(zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({parameter_number = 111, size = 4, configuration_value = 300}) + )) + test.socket.zwave:__expect_send(zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({parameter_number = 112, size = 4, configuration_value = 300}) + )) + test.socket.zwave:__expect_send(zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({parameter_number = 113, size = 4, configuration_value = 300}) + )) + mock_parent:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + end +) + +test.register_coroutine_test( + "Power meter report should be handled", + function() + for _, device in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(device.endpoints) do + local component = "main" + if endpoint ~= 3 and endpoint ~= 4 and endpoint ~= 5 and endpoint ~= 6 then + component = string.format("clamp%d", endpoint) + end + test.socket.zwave:__queue_receive({ + mock_parent.id, + Meter:Report({ + scale = Meter.scale.electric_meter.WATTS, + meter_value = 27 + }, { + encap = zw.ENCAP.AUTO, + src_channel = endpoint, + dst_channels = {0} + }) + }) + if(device["child_key"]) then + if(device["child_key"] == "pro") then + test.socket.capability:__expect_send( + mock_child_prod:generate_test_message(component, capabilities.powerMeter.power({ value = 27, unit = "W" })) + ) + elseif (device["child_key"] == "sald-pro") then + test.socket.capability:__expect_send( + mock_child_sald_prod:generate_test_message(component, capabilities.powerMeter.power({ value = 27, unit = "W" })) + ) + elseif (device["child_key"] == "sald-con") then + test.socket.capability:__expect_send( + mock_child_sald_con:generate_test_message(component, capabilities.powerMeter.power({ value = 27, unit = "W" })) + ) + end + else + test.socket.capability:__expect_send( + mock_parent:generate_test_message(component, capabilities.powerMeter.power({ value = 27, unit = "W" })) + ) + end + end + end + end +) + +test.register_coroutine_test( + "Energy meter report should be handled", + function() + for _, device in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(device.endpoints) do + local component = "main" + if endpoint ~= 3 and endpoint ~= 4 and endpoint ~= 5 and endpoint ~= 6 then + component = string.format("clamp%d", endpoint) + end + test.socket.zwave:__queue_receive({ + mock_parent.id, + Meter:Report({ + scale = Meter.scale.electric_meter.KILOWATT_HOURS, + meter_value = 5 + }, { + encap = zw.ENCAP.AUTO, + src_channel = endpoint, + dst_channels = {0} + }) + }) + if(device["child_key"]) then + if(device["child_key"] == "pro") then + test.socket.capability:__expect_send( + mock_child_prod:generate_test_message(component, capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + elseif (device["child_key"] == "sald-pro") then + test.socket.capability:__expect_send( + mock_child_sald_prod:generate_test_message(component, capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + elseif (device["child_key"] == "sald-con") then + test.socket.capability:__expect_send( + mock_child_sald_con:generate_test_message(component, capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + end + else + test.socket.capability:__expect_send( + mock_parent:generate_test_message(component, capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + end + end + end + end +) + +test.register_coroutine_test( + "Report consumption and power consumption report after 15 minutes", function() + -- set time to trigger power consumption report + local current_time = os.time() - 60 * 20 + --mock_child_sald_con:set_field(LAST_REPORT_TIME, current_time) + mock_parent:set_field(LAST_REPORT_TIME, current_time) + + test.socket.zwave:__queue_receive( + { + --mock_child_sald_con.id, + mock_parent.id, + zw_test_utils.zwave_test_build_receive_command(Meter:Report( + { + scale = Meter.scale.electric_meter.KILOWATT_HOURS, + meter_value = 5 + }, + { + encap = zw.ENCAP.AUTO, + src_channel = 5, + dst_channels = {0} + } + )) + } + ) + + test.socket.capability:__expect_send( + mock_child_sald_con:generate_test_message("main", capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + + test.socket.capability:__expect_send( + -- mock_parent + mock_parent:generate_test_message("main", + capabilities.powerConsumptionReport.powerConsumption({ deltaEnergy = 0.0, energy = 5000 })) + ) + end +) + +test.register_coroutine_test( + "Handle preference: thresholdCheck (parameter 3) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + thresholdCheck = 0 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 3, + configuration_value = 0, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWThresholdTotal (parameter 4) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWThresholdTotal = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 4, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWThresholdPhaseA (parameter 5) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWThresholdPhaseA = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 5, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWThresholdTotal (parameter 8) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWThresholdTotal = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 8, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWThresholdPhaseA (parameter 9) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWThresholdPhaseA = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 9, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imtWPctThresholdTotal (parameter 12) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imtWPctThresholdTotal = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 12, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWPctThresholdPhaseA (parameter 13) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWPctThresholdPhaseA = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 13, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWPctThresholdTotal (parameter 16) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWPctThresholdTotal = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 16, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWPctThresholdPhaseA (parameter 17) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWPctThresholdPhaseA = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 17, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: autoRootDeviceReport (parameter 32) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + autoRootDeviceReport = 1 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 32, + configuration_value = 1, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Refresh sends commands to all components including base device", + function() + -- refresh commands for zwave devices do not have guaranteed ordering + test.socket.zwave:__set_channel_ordering("relaxed") + + for _, device in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(device.endpoints) do + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Meter:Get({scale = Meter.scale.electric_meter.WATTS}, { + encap = zw.ENCAP.AUTO, + src_channel = 0, + dst_channels = { endpoint } + }) + ) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Meter:Get({scale = Meter.scale.electric_meter.KILOWATT_HOURS}, { + encap = zw.ENCAP.AUTO, + src_channel = 0, + dst_channels = { endpoint } + }) + ) + ) + end + end + + test.socket.capability:__queue_receive({ + mock_parent.id, + { capability = "refresh", component = "main", command = "refresh", args = { } } + }) + end +) + +test.run_registered_tests() \ No newline at end of file diff --git a/drivers/SmartThings/zwave-electric-meter/src/test/test_aeotec_home_energy_meter_gen8_2_phase.lua b/drivers/SmartThings/zwave-electric-meter/src/test/test_aeotec_home_energy_meter_gen8_2_phase.lua new file mode 100644 index 0000000000..43ea5cdbe3 --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/test/test_aeotec_home_energy_meter_gen8_2_phase.lua @@ -0,0 +1,654 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local test = require "integration_test" +local capabilities = require "st.capabilities" +local zw = require "st.zwave" +local zw_test_utils = require "integration_test.zwave_test_utils" +local Meter = (require "st.zwave.CommandClass.Meter")({version=4}) +local Configuration = (require "st.zwave.CommandClass.Configuration")({ version=4 }) +local t_utils = require "integration_test.utils" + +local AEOTEC_MFR_ID = 0x0371 +local AEOTEC_METER_PROD_TYPE = 0x0103 +local AEOTEC_METER_PROD_ID = 0x002E + +local LAST_REPORT_TIME = "LAST_REPORT_TIME" + +local aeotec_meter_endpoints = { + { + command_classes = { + {value = zw.METER} + } + } +} + +local HEM8_DEVICES = { + { + profile = 'aeotec-home-energy-meter-gen8-2-phase-con', + name = 'Aeotec Home Energy Meter 8 Consumption', + endpoints = { 1, 3, 5 } + }, + { + profile = 'aeotec-home-energy-meter-gen8-2-phase-pro', + name = 'Aeotec Home Energy Meter 8 Production', + child_key = 'pro', + endpoints = { 2, 4, 6 } + }, + { + profile = 'aeotec-home-energy-meter-gen8-sald-con', + name = 'Aeotec Home Energy Meter 8 Settled Consumption', + child_key = 'sald-con', + endpoints = { 7 } + }, + { + profile = 'aeotec-home-energy-meter-gen8-sald-pro', + name = 'Aeotec Home Energy Meter 8 Settled Production', + child_key = 'sald-pro', + endpoints = { 8 } + } +} + +local mock_parent = test.mock_device.build_test_zwave_device({ + profile = t_utils.get_profile_definition(HEM8_DEVICES[1].profile .. '.yml'), + zwave_endpoints = aeotec_meter_endpoints, + zwave_manufacturer_id = AEOTEC_MFR_ID, + zwave_product_type = AEOTEC_METER_PROD_TYPE, + zwave_product_id = AEOTEC_METER_PROD_ID +}) + +local mock_child_prod = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition(HEM8_DEVICES[2].profile .. '.yml'), + parent_device_id = mock_parent.id, + parent_assigned_child_key = HEM8_DEVICES[2].child_key +}) + +local mock_child_sald_con = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition(HEM8_DEVICES[3].profile .. '.yml'), + parent_device_id = mock_parent.id, + parent_assigned_child_key = HEM8_DEVICES[3].child_key +}) + +local mock_child_sald_prod = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition(HEM8_DEVICES[4].profile .. '.yml'), + parent_device_id = mock_parent.id, + parent_assigned_child_key = HEM8_DEVICES[4].child_key +}) + +local function test_init() + test.mock_device.add_test_device(mock_parent) + test.mock_device.add_test_device(mock_child_prod) + test.mock_device.add_test_device(mock_child_sald_con) + test.mock_device.add_test_device(mock_child_sald_prod) +end + +test.set_test_init_function(test_init) + +test.register_coroutine_test( + "Added lifecycle event should create children for parent device", + function() + test.socket.zwave:__set_channel_ordering("relaxed") + test.socket.device_lifecycle:__queue_receive({ mock_parent.id, "added" }) + + for _, child in ipairs(HEM8_DEVICES) do + if(child["child_key"]) then + mock_parent:expect_device_create( + { + type = "EDGE_CHILD", + label = child.name, + profile = child.profile, + parent_device_id = mock_parent.id, + parent_assigned_child_key = child.child_key + } + ) + end + end + -- Refresh + for _, device in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(device.endpoints) do + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Meter:Get({scale = Meter.scale.electric_meter.WATTS}, { + encap = zw.ENCAP.AUTO, + src_channel = 0, + dst_channels = { endpoint } + }) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Meter:Get({scale = Meter.scale.electric_meter.KILOWATT_HOURS}, { + encap = zw.ENCAP.AUTO, + src_channel = 0, + dst_channels = { endpoint } + }) + ) + ) + end + end + end +) + +test.register_coroutine_test( + "Configure should configure all necessary attributes", + function() + test.socket.zwave:__set_channel_ordering("relaxed") + test.socket.device_lifecycle:__queue_receive({ mock_parent.id, "doConfigure" }) + + test.socket.zwave:__expect_send(zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({parameter_number = 111, size = 4, configuration_value = 300}) + )) + test.socket.zwave:__expect_send(zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({parameter_number = 112, size = 4, configuration_value = 300}) + )) + test.socket.zwave:__expect_send(zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({parameter_number = 113, size = 4, configuration_value = 300}) + )) + mock_parent:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + end +) + +test.register_coroutine_test( + "Power meter report should be handled", + function() + for _, device in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(device.endpoints) do + local component = "main" + if endpoint ~= 5 and endpoint ~= 6 and endpoint ~= 7 and endpoint ~= 8 then + component = string.format("clamp%d", endpoint) + end + test.socket.zwave:__queue_receive({ + mock_parent.id, + Meter:Report({ + scale = Meter.scale.electric_meter.WATTS, + meter_value = 27 + }, { + encap = zw.ENCAP.AUTO, + src_channel = endpoint, + dst_channels = {0} + }) + }) + if(device["child_key"]) then + if(device["child_key"] == "pro") then + test.socket.capability:__expect_send( + mock_child_prod:generate_test_message(component, capabilities.powerMeter.power({ value = 27, unit = "W" })) + ) + elseif (device["child_key"] == "sald-pro") then + test.socket.capability:__expect_send( + mock_child_sald_prod:generate_test_message(component, capabilities.powerMeter.power({ value = 27, unit = "W" })) + ) + elseif (device["child_key"] == "sald-con") then + test.socket.capability:__expect_send( + mock_child_sald_con:generate_test_message(component, capabilities.powerMeter.power({ value = 27, unit = "W" })) + ) + end + else + test.socket.capability:__expect_send( + mock_parent:generate_test_message(component, capabilities.powerMeter.power({ value = 27, unit = "W" })) + ) + end + end + end + end +) + +test.register_coroutine_test( + "Energy meter report should be handled", + function() + for _, device in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(device.endpoints) do + local component = "main" + if endpoint ~= 5 and endpoint ~= 6 and endpoint ~= 7 and endpoint ~= 8 then + component = string.format("clamp%d", endpoint) + end + test.socket.zwave:__queue_receive({ + mock_parent.id, + Meter:Report({ + scale = Meter.scale.electric_meter.KILOWATT_HOURS, + meter_value = 5 + }, { + encap = zw.ENCAP.AUTO, + src_channel = endpoint, + dst_channels = {0} + }) + }) + if(device["child_key"]) then + if(device["child_key"] == "pro") then + test.socket.capability:__expect_send( + mock_child_prod:generate_test_message(component, capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + elseif (device["child_key"] == "sald-pro") then + test.socket.capability:__expect_send( + mock_child_sald_prod:generate_test_message(component, capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + elseif (device["child_key"] == "sald-con") then + test.socket.capability:__expect_send( + mock_child_sald_con:generate_test_message(component, capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + end + else + test.socket.capability:__expect_send( + mock_parent:generate_test_message(component, capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + end + end + end + end +) + +test.register_coroutine_test( + "Report consumption and power consumption report after 15 minutes", function() + -- set time to trigger power consumption report + local current_time = os.time() - 60 * 20 + --mock_child_sald_con:set_field(LAST_REPORT_TIME, current_time) + mock_parent:set_field(LAST_REPORT_TIME, current_time) + + test.socket.zwave:__queue_receive( + { + mock_parent.id, + zw_test_utils.zwave_test_build_receive_command(Meter:Report( + { + scale = Meter.scale.electric_meter.KILOWATT_HOURS, + meter_value = 5 + }, + { + encap = zw.ENCAP.AUTO, + src_channel = 7, + dst_channels = {0} + } + )) + } + ) + + test.socket.capability:__expect_send( + mock_child_sald_con:generate_test_message("main", capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + + test.socket.capability:__expect_send( + mock_parent:generate_test_message("main", + capabilities.powerConsumptionReport.powerConsumption({ deltaEnergy = 0.0, energy = 5000 })) + ) + end +) + +test.register_coroutine_test( + "Handle preference: thresholdCheck (parameter 3) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + thresholdCheck = 0 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 3, + configuration_value = 0, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWThresholdTotal (parameter 4) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWThresholdTotal = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 4, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWThresholdPhaseA (parameter 5) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWThresholdPhaseA = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 5, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWThresholdPhaseB (parameter 6) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWThresholdPhaseB = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 6, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWThresholdTotal (parameter 8) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWThresholdTotal = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 8, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWThresholdPhaseA (parameter 9) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWThresholdPhaseA = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 9, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWThresholdPhaseB (parameter 10) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWThresholdPhaseB = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 10, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imtWPctThresholdTotal (parameter 12) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imtWPctThresholdTotal = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 12, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWPctThresholdPhaseA (parameter 13) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWPctThresholdPhaseA = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 13, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWPctThresholdPhaseB (parameter 14) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWPctThresholdPhaseB = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 14, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWPctThresholdTotal (parameter 16) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWPctThresholdTotal = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 16, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWPctThresholdPhaseA (parameter 17) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWPctThresholdPhaseA = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 17, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWPctThresholdPhaseB (parameter 18) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWPctThresholdPhaseB = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 18, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: autoRootDeviceReport (parameter 32) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + autoRootDeviceReport = 1 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 32, + configuration_value = 1, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Refresh sends commands to all components including base device", + function() + -- refresh commands for zwave devices do not have guaranteed ordering + test.socket.zwave:__set_channel_ordering("relaxed") + + for _, device in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(device.endpoints) do + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Meter:Get({scale = Meter.scale.electric_meter.WATTS}, { + encap = zw.ENCAP.AUTO, + src_channel = 0, + dst_channels = { endpoint } + }) + ) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Meter:Get({scale = Meter.scale.electric_meter.KILOWATT_HOURS}, { + encap = zw.ENCAP.AUTO, + src_channel = 0, + dst_channels = { endpoint } + }) + ) + ) + end + end + + test.socket.capability:__queue_receive({ + mock_parent.id, + { capability = "refresh", component = "main", command = "refresh", args = { } } + }) + end +) + +test.run_registered_tests() diff --git a/drivers/SmartThings/zwave-electric-meter/src/test/test_aeotec_home_energy_meter_gen8_3_phase.lua b/drivers/SmartThings/zwave-electric-meter/src/test/test_aeotec_home_energy_meter_gen8_3_phase.lua new file mode 100644 index 0000000000..465e3add9f --- /dev/null +++ b/drivers/SmartThings/zwave-electric-meter/src/test/test_aeotec_home_energy_meter_gen8_3_phase.lua @@ -0,0 +1,749 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local test = require "integration_test" +local capabilities = require "st.capabilities" +local zw = require "st.zwave" +local zw_test_utils = require "integration_test.zwave_test_utils" +local Meter = (require "st.zwave.CommandClass.Meter")({version=4}) +local Configuration = (require "st.zwave.CommandClass.Configuration")({ version=1 }) +local t_utils = require "integration_test.utils" + +local AEOTEC_MFR_ID = 0x0371 +local AEOTEC_METER_PROD_TYPE = 0x0003 +local AEOTEC_METER_PROD_ID = 0x0034 + +local LAST_REPORT_TIME = "LAST_REPORT_TIME" + +local aeotec_meter_endpoints = { + { + command_classes = { + {value = zw.METER} + } + } +} + +local HEM8_DEVICES = { + { + profile = 'aeotec-home-energy-meter-gen8-3-phase-con', + name = 'Aeotec Home Energy Meter 8 Consumption', + endpoints = { 1, 3, 5, 7 } + }, + { + profile = 'aeotec-home-energy-meter-gen8-3-phase-pro', + name = 'Aeotec Home Energy Meter 8 Production', + child_key = 'pro', + endpoints = { 2, 4, 6, 8 } + }, + { + profile = 'aeotec-home-energy-meter-gen8-sald-con', + name = 'Aeotec Home Energy Meter 8 Settled Consumption', + child_key = 'sald-con', + endpoints = { 9 } + }, + { + profile = 'aeotec-home-energy-meter-gen8-sald-pro', + name = 'Aeotec Home Energy Meter 8 Settled Production', + child_key = 'sald-pro', + endpoints = { 10 } + } +} + +local mock_parent = test.mock_device.build_test_zwave_device({ + profile = t_utils.get_profile_definition(HEM8_DEVICES[1].profile .. '.yml'), + zwave_endpoints = aeotec_meter_endpoints, + zwave_manufacturer_id = AEOTEC_MFR_ID, + zwave_product_type = AEOTEC_METER_PROD_TYPE, + zwave_product_id = AEOTEC_METER_PROD_ID +}) + +local mock_child_prod = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition(HEM8_DEVICES[2].profile .. '.yml'), + parent_device_id = mock_parent.id, + parent_assigned_child_key = HEM8_DEVICES[2].child_key +}) + +local mock_child_sald_con = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition(HEM8_DEVICES[3].profile .. '.yml'), + parent_device_id = mock_parent.id, + parent_assigned_child_key = HEM8_DEVICES[3].child_key +}) + +local mock_child_sald_prod = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition(HEM8_DEVICES[4].profile .. '.yml'), + parent_device_id = mock_parent.id, + parent_assigned_child_key = HEM8_DEVICES[4].child_key +}) + +local function test_init() + test.mock_device.add_test_device(mock_parent) + test.mock_device.add_test_device(mock_child_prod) + test.mock_device.add_test_device(mock_child_sald_con) + test.mock_device.add_test_device(mock_child_sald_prod) +end + +test.set_test_init_function(test_init) + +test.register_coroutine_test( + "Added lifecycle event should create children for parent device", + function() + test.socket.zwave:__set_channel_ordering("relaxed") + test.socket.device_lifecycle:__queue_receive({ mock_parent.id, "added" }) + + for _, child in ipairs(HEM8_DEVICES) do + if(child["child_key"]) then + mock_parent:expect_device_create( + { + type = "EDGE_CHILD", + label = child.name, + profile = child.profile, + parent_device_id = mock_parent.id, + parent_assigned_child_key = child.child_key + } + ) + end + end + -- Refresh + for _, device in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(device.endpoints) do + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Meter:Get({scale = Meter.scale.electric_meter.WATTS}, { + encap = zw.ENCAP.AUTO, + src_channel = 0, + dst_channels = { endpoint } + }) + ) + ) + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Meter:Get({scale = Meter.scale.electric_meter.KILOWATT_HOURS}, { + encap = zw.ENCAP.AUTO, + src_channel = 0, + dst_channels = { endpoint } + }) + ) + ) + end + end + end +) + +test.register_coroutine_test( + "Configure should configure all necessary attributes", + function() + test.socket.zwave:__set_channel_ordering("relaxed") + test.socket.device_lifecycle:__queue_receive({ mock_parent.id, "doConfigure" }) + + test.socket.zwave:__expect_send(zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({parameter_number = 111, size = 4, configuration_value = 300}) + )) + test.socket.zwave:__expect_send(zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({parameter_number = 112, size = 4, configuration_value = 300}) + )) + test.socket.zwave:__expect_send(zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({parameter_number = 113, size = 4, configuration_value = 300}) + )) + mock_parent:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + end +) + +test.register_coroutine_test( + "Power meter report should be handled", + function() + for _, device in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(device.endpoints) do + local component = "main" + if endpoint ~= 7 and endpoint ~= 8 and endpoint ~= 9 and endpoint ~= 10 then + component = string.format("clamp%d", endpoint) + end + test.socket.zwave:__queue_receive({ + mock_parent.id, + Meter:Report({ + scale = Meter.scale.electric_meter.WATTS, + meter_value = 27 + }, { + encap = zw.ENCAP.AUTO, + src_channel = endpoint, + dst_channels = {0} + }) + }) + if(device["child_key"]) then + if(device["child_key"] == "pro") then + test.socket.capability:__expect_send( + mock_child_prod:generate_test_message(component, capabilities.powerMeter.power({ value = 27, unit = "W" })) + ) + elseif (device["child_key"] == "sald-pro") then + test.socket.capability:__expect_send( + mock_child_sald_prod:generate_test_message(component, capabilities.powerMeter.power({ value = 27, unit = "W" })) + ) + elseif (device["child_key"] == "sald-con") then + test.socket.capability:__expect_send( + mock_child_sald_con:generate_test_message(component, capabilities.powerMeter.power({ value = 27, unit = "W" })) + ) + end + else + test.socket.capability:__expect_send( + mock_parent:generate_test_message(component, capabilities.powerMeter.power({ value = 27, unit = "W" })) + ) + end + end + end + end +) + +test.register_coroutine_test( + "Energy meter report should be handled", + function() + for _, device in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(device.endpoints) do + local component = "main" + if endpoint ~= 7 and endpoint ~= 8 and endpoint ~= 9 and endpoint ~= 10 then + component = string.format("clamp%d", endpoint) + end + test.socket.zwave:__queue_receive({ + mock_parent.id, + Meter:Report({ + scale = Meter.scale.electric_meter.KILOWATT_HOURS, + meter_value = 5 + }, { + encap = zw.ENCAP.AUTO, + src_channel = endpoint, + dst_channels = {0} + }) + }) + if(device["child_key"]) then + if(device["child_key"] == "pro") then + test.socket.capability:__expect_send( + mock_child_prod:generate_test_message(component, capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + elseif (device["child_key"] == "sald-pro") then + test.socket.capability:__expect_send( + mock_child_sald_prod:generate_test_message(component, capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + elseif (device["child_key"] == "sald-con") then + test.socket.capability:__expect_send( + mock_child_sald_con:generate_test_message(component, capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + end + else + test.socket.capability:__expect_send( + mock_parent:generate_test_message(component, capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + end + end + end + end +) + +test.register_coroutine_test( + "Report consumption and power consumption report after 15 minutes", function() + -- set time to trigger power consumption report + local current_time = os.time() - 60 * 20 + -- mock_child_sald_con:set_field(LAST_REPORT_TIME, current_time) + mock_parent:set_field(LAST_REPORT_TIME, current_time) + test.socket.zwave:__queue_receive( + { + mock_parent.id, + zw_test_utils.zwave_test_build_receive_command(Meter:Report( + { + scale = Meter.scale.electric_meter.KILOWATT_HOURS, + meter_value = 5 + }, + { + encap = zw.ENCAP.AUTO, + src_channel = 9, + dst_channels = {0} + } + )) + } + ) + + test.socket.capability:__expect_send( + mock_child_sald_con:generate_test_message("main", capabilities.energyMeter.energy({ value = 5, unit = "kWh" })) + ) + + test.socket.capability:__expect_send( + mock_parent:generate_test_message("main", + capabilities.powerConsumptionReport.powerConsumption({ deltaEnergy = 0.0, energy = 5000 })) + ) + end +) + +test.register_coroutine_test( + "Handle preference: thresholdCheck (parameter 3) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + thresholdCheck = 0 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 3, + configuration_value = 0, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWThresholdTotal (parameter 4) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWThresholdTotal = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 4, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWThresholdPhaseA (parameter 5) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWThresholdPhaseA = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 5, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWThresholdPhaseB (parameter 6) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWThresholdPhaseB = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 6, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWThresholdPhaseC (parameter 7) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWThresholdPhaseC = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 7, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWThresholdTotal (parameter 8) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWThresholdTotal = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 8, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWThresholdPhaseA (parameter 9) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWThresholdPhaseA = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 9, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWThresholdPhaseB (parameter 10) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWThresholdPhaseB = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 10, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWThresholdPhaseC (parameter 11) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWThresholdPhaseC = 3500 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 11, + configuration_value = 3500, + size = 2 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imtWPctThresholdTotal (parameter 12) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imtWPctThresholdTotal = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 12, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWPctThresholdPhaseA (parameter 13) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWPctThresholdPhaseA = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 13, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWPctThresholdPhaseB (parameter 14) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWPctThresholdPhaseB = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 14, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: imWPctThresholdPhaseC (parameter 15) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + imWPctThresholdPhaseC = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 15, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWPctThresholdTotal (parameter 16) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWPctThresholdTotal = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 16, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWPctThresholdPhaseA (parameter 17) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWPctThresholdPhaseA = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 17, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: exWPctThresholdPhaseB (parameter 18) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWPctThresholdPhaseB = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 18, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: thresholdCheck (exWPctThresholdPhaseC 19) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + exWPctThresholdPhaseC = 50 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 19, + configuration_value = 50, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Handle preference: autoRootDeviceReport (parameter 32) in infoChanged", + function() + test.socket.device_lifecycle:__queue_receive( + mock_parent:generate_info_changed({ + preferences = { + autoRootDeviceReport = 1 + } + }) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Configuration:Set({ + parameter_number = 32, + configuration_value = 1, + size = 1 + }) + ) + ) + end +) + +test.register_coroutine_test( + "Refresh sends commands to all components including base device", + function() + -- refresh commands for zwave devices do not have guaranteed ordering + test.socket.zwave:__set_channel_ordering("relaxed") + + for _, device in ipairs(HEM8_DEVICES) do + for _, endpoint in ipairs(device.endpoints) do + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Meter:Get({scale = Meter.scale.electric_meter.WATTS}, { + encap = zw.ENCAP.AUTO, + src_channel = 0, + dst_channels = { endpoint } + }) + ) + ) + + test.socket.zwave:__expect_send( + zw_test_utils.zwave_test_build_send_command( + mock_parent, + Meter:Get({scale = Meter.scale.electric_meter.KILOWATT_HOURS}, { + encap = zw.ENCAP.AUTO, + src_channel = 0, + dst_channels = { endpoint } + }) + ) + ) + end + end + + test.socket.capability:__queue_receive({ + mock_parent.id, + { capability = "refresh", component = "main", command = "refresh", args = { } } + }) + end +) + +test.run_registered_tests() \ No newline at end of file From 588aaef6f4e61dad4ffa414e244cdf4f4fd8e663 Mon Sep 17 00:00:00 2001 From: HunsupJung <59987061+HunsupJung@users.noreply.github.com> Date: Thu, 19 Mar 2026 21:11:47 +0900 Subject: [PATCH 17/29] Add lockAlarm configuration to do_configure (#2763) Signed-off-by: HunsupJung --- .../matter-lock/src/new-matter-lock/init.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index 74bed0b798..f89029851d 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -301,8 +301,10 @@ local function info_changed(driver, device, event, args) end end device:subscribe() - device:emit_event(capabilities.lockAlarm.alarm.clear({state_change = true})) - device:emit_event(capabilities.lockAlarm.supportedAlarmValues({"unableToLockTheDoor"}, {visibility = {displayed = false}})) -- lockJammed is madatory + if device:get_latest_state("main", capabilities.lockAlarm.ID, capabilities.lockAlarm.supportedAlarmValues.NAME) == nil then + device:emit_event(capabilities.lockAlarm.alarm.clear({state_change = true})) + device:emit_event(capabilities.lockAlarm.supportedAlarmValues({"unableToLockTheDoor"}, {visibility = {displayed = false}})) -- lockJammed is mandatory + end end local function profiling_data_still_required(device) @@ -326,6 +328,10 @@ end local function do_configure(driver, device) match_profile(driver, device) + device.thread:call_with_delay(5, function() + device:emit_event(capabilities.lockAlarm.alarm.clear({state_change = true})) + device:emit_event(capabilities.lockAlarm.supportedAlarmValues({"unableToLockTheDoor"}, {visibility = {displayed = false}})) -- lockJammed is mandatory + end) end local function driver_switched(driver, device) From b360b525d6efc3e8b987220d9f6803019b7b9537 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Fri, 6 Mar 2026 11:49:04 -0600 Subject: [PATCH 18/29] move AttributeList read to subscribe --- .../matter-lock/src/new-matter-lock/init.lua | 40 +++++++++---------- .../src/test/test_matter_lock_modular.lua | 12 +++--- .../src/test/test_new_matter_lock_battery.lua | 9 +++-- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index f89029851d..8d50f4b94c 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -129,6 +129,11 @@ end local function device_init(driver, device) device:set_component_to_endpoint_fn(component_to_endpoint) + if #device:get_endpoints(clusters.PowerSource.ID, {feature_bitmap = clusters.PowerSource.types.PowerSourceFeature.BATTERY}) == 0 then + device:set_field(profiling_data.BATTERY_SUPPORT, battery_support.NO_BATTERY, {persist = true}) + elseif device:get_field(profiling_data.BATTERY_SUPPORT) == nil then + device:add_subscribed_attribute(clusters.PowerSource.attributes.AttributeList) + end for cap_id, attributes in pairs(subscribed_attributes) do if device:supports_capability_by_id(cap_id) then for _, attr in ipairs(attributes) do @@ -148,12 +153,6 @@ local function device_init(driver, device) local function device_added(driver, device) device:emit_event(capabilities.lockAlarm.alarm.clear({state_change = true})) - local battery_feature_eps = device:get_endpoints(clusters.PowerSource.ID, {feature_bitmap = clusters.PowerSource.types.PowerSourceFeature.BATTERY}) - if #battery_feature_eps > 0 then - device:send(clusters.PowerSource.attributes.AttributeList:read(device)) - else - device:set_field(profiling_data.BATTERY_SUPPORT, battery_support.NO_BATTERY, { persist = true }) - end end local function match_profile_modular(driver, device) @@ -634,23 +633,22 @@ end -- Power Source Attribute List -- --------------------------------- local function handle_power_source_attribute_list(driver, device, ib, response) - for _, attr in ipairs(ib.data.elements) do - -- mark if the device if BatPercentRemaining (Attribute ID 0x0C) or - -- BatChargeLevel (Attribute ID 0x0E) is present and try profiling. - if attr.value == 0x0C then - device:set_field(profiling_data.BATTERY_SUPPORT, battery_support.BATTERY_PERCENTAGE, { persist = true }) - match_profile(driver, device) - return - elseif attr.value == 0x0E then - device:set_field(profiling_data.BATTERY_SUPPORT, battery_support.BATTERY_LEVEL, { persist = true }) - match_profile(driver, device) - return + local latest_battery_support = device:get_field(profiling_data.BATTERY_SUPPORT) + for _, attr in ipairs(ib.data.elements or {}) do + if attr.value == clusters.PowerSource.attributes.BatPercentRemaining.ID then + device:set_field(profiling_data.BATTERY_SUPPORT, battery_support.BATTERY_PERCENTAGE, {persist=true}) + break -- BATTERY_PERCENTAGE is highest priority. break early if found + elseif attr.value == clusters.PowerSource.attributes.BatChargeLevel.ID then + device:set_field(profiling_data.BATTERY_SUPPORT, battery_support.BATTERY_LEVEL, {persist=true}) end end - - -- neither BatChargeLevel nor BatPercentRemaining were found. Re-profiling without battery. - device:set_field(profiling_data.BATTERY_SUPPORT, battery_support.NO_BATTERY, { persist = true }) - match_profile(driver, device) + -- in the case that 1) no battery has been set, and 2) the returned ib does not include battery attributes, ignore battery + if latest_battery_support == nil and not device:get_field(profiling_data.BATTERY_SUPPORT) then + device:set_field(profiling_data.BATTERY_SUPPORT, battery_support.NO_BATTERY, {persist=true}) + end + if latest_battery_support == nil or latest_battery_support ~= device:get_field(profiling_data.BATTERY_SUPPORT) then + match_profile(driver, device) + end end ------------------------------- diff --git a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_modular.lua b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_modular.lua index 47b55fb72c..8add29c13e 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_modular.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_modular.lua @@ -208,6 +208,8 @@ local function test_init() subscribe_request:merge(DoorLock.attributes.OperatingMode:subscribe(mock_device)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device)) + subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device)) + -- add test device test.mock_device.add_test_device(mock_device) -- actual onboarding flow @@ -215,7 +217,6 @@ local function test_init() test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockAlarm.alarm.clear({state_change = true})) ) - test.socket.matter:__expect_send({mock_device.id, clusters.PowerSource.attributes.AttributeList:read()}) test.socket.device_lifecycle:__queue_receive({ mock_device.id, "init" }) test.socket.matter:__expect_send({mock_device.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) @@ -229,6 +230,7 @@ local function test_init_unlatch() subscribe_request:merge(DoorLock.attributes.OperatingMode:subscribe(mock_device_unlatch)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_unlatch)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_unlatch)) + subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_unlatch)) -- add test device, handle initial subscribe test.mock_device.add_test_device(mock_device_unlatch) -- actual onboarding flow @@ -236,7 +238,6 @@ local function test_init_unlatch() test.socket.capability:__expect_send( mock_device_unlatch:generate_test_message("main", capabilities.lockAlarm.alarm.clear({state_change = true})) ) - test.socket.matter:__expect_send({mock_device_unlatch.id, clusters.PowerSource.attributes.AttributeList:read()}) test.socket.device_lifecycle:__queue_receive({ mock_device_unlatch.id, "init" }) test.socket.matter:__expect_send({mock_device_unlatch.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_unlatch.id, "doConfigure" }) @@ -256,6 +257,7 @@ local function test_init_user_pin() subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_user_pin)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_user_pin)) subscribe_request:merge(DoorLock.events.LockUserChange:subscribe(mock_device_user_pin)) + subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_user_pin)) -- add test device test.mock_device.add_test_device(mock_device_user_pin) -- actual onboarding flow @@ -263,7 +265,6 @@ local function test_init_user_pin() test.socket.capability:__expect_send( mock_device_user_pin:generate_test_message("main", capabilities.lockAlarm.alarm.clear({state_change = true})) ) - test.socket.matter:__expect_send({mock_device_user_pin.id, clusters.PowerSource.attributes.AttributeList:read()}) test.socket.device_lifecycle:__queue_receive({ mock_device_user_pin.id, "init" }) test.socket.matter:__expect_send({mock_device_user_pin.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_user_pin.id, "doConfigure" }) @@ -285,6 +286,7 @@ local function test_init_user_pin_schedule_unlatch() subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_user_pin_schedule_unlatch)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_user_pin_schedule_unlatch)) subscribe_request:merge(DoorLock.events.LockUserChange:subscribe(mock_device_user_pin_schedule_unlatch)) + subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_user_pin_schedule_unlatch)) -- add test device test.mock_device.add_test_device(mock_device_user_pin_schedule_unlatch) -- actual onboarding flow @@ -292,7 +294,6 @@ local function test_init_user_pin_schedule_unlatch() test.socket.capability:__expect_send( mock_device_user_pin_schedule_unlatch:generate_test_message("main", capabilities.lockAlarm.alarm.clear({state_change = true})) ) - test.socket.matter:__expect_send({mock_device_user_pin_schedule_unlatch.id, clusters.PowerSource.attributes.AttributeList:read()}) test.socket.device_lifecycle:__queue_receive({ mock_device_user_pin_schedule_unlatch.id, "init" }) test.socket.matter:__expect_send({mock_device_user_pin_schedule_unlatch.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_user_pin_schedule_unlatch.id, "doConfigure" }) @@ -306,6 +307,7 @@ local function test_init_modular() subscribe_request:merge(DoorLock.attributes.OperatingMode:subscribe(mock_device_modular)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_modular)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_modular)) + subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_modular)) -- add test device test.mock_device.add_test_device(mock_device_modular) -- actual onboarding flow @@ -313,7 +315,6 @@ local function test_init_modular() test.socket.capability:__expect_send( mock_device_modular:generate_test_message("main", capabilities.lockAlarm.alarm.clear({state_change = true})) ) - test.socket.matter:__expect_send({mock_device_modular.id, clusters.PowerSource.attributes.AttributeList:read()}) test.socket.device_lifecycle:__queue_receive({ mock_device_modular.id, "init" }) test.socket.matter:__expect_send({mock_device_modular.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_modular.id, "doConfigure" }) @@ -664,6 +665,7 @@ test.register_coroutine_test( subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_modular)) subscribe_request:merge(DoorLock.events.LockUserChange:subscribe(mock_device_modular)) subscribe_request:merge(clusters.PowerSource.attributes.BatPercentRemaining:subscribe(mock_device_modular)) + subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_modular)) test.socket.matter:__expect_send({mock_device_modular.id, subscribe_request}) test.socket.capability:__expect_send( mock_device_modular:generate_test_message("main", capabilities.lockAlarm.alarm.clear({state_change = true})) diff --git a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_battery.lua b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_battery.lua index d54cb8a0ca..1d3f18d4fd 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_battery.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_battery.lua @@ -170,6 +170,7 @@ local function test_init() subscribe_request:merge(DoorLock.attributes.OperatingMode:subscribe(mock_device)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device)) + subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device)) -- add test device, handle initial subscribe test.mock_device.add_test_device(mock_device) test.socket.matter:__expect_send({mock_device.id, subscribe_request}) @@ -178,7 +179,6 @@ local function test_init() test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.lockAlarm.alarm.clear({state_change = true})) ) - test.socket.matter:__expect_send({mock_device.id, clusters.PowerSource.attributes.AttributeList:read()}) test.socket.device_lifecycle:__queue_receive({ mock_device.id, "init" }) test.socket.matter:__expect_send({mock_device.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) @@ -192,6 +192,7 @@ local function test_init_unlatch() subscribe_request:merge(DoorLock.attributes.OperatingMode:subscribe(mock_device_unlatch)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_unlatch)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_unlatch)) + subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_unlatch)) -- add test device, handle initial subscribe test.mock_device.add_test_device(mock_device_unlatch) test.socket.matter:__expect_send({mock_device_unlatch.id, subscribe_request}) @@ -200,7 +201,6 @@ local function test_init_unlatch() test.socket.capability:__expect_send( mock_device_unlatch:generate_test_message("main", capabilities.lockAlarm.alarm.clear({state_change = true})) ) - test.socket.matter:__expect_send({mock_device_unlatch.id, clusters.PowerSource.attributes.AttributeList:read()}) test.socket.device_lifecycle:__queue_receive({ mock_device_unlatch.id, "init" }) test.socket.matter:__expect_send({mock_device_unlatch.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_unlatch.id, "doConfigure" }) @@ -220,6 +220,7 @@ local function test_init_user_pin() subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_user_pin)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_user_pin)) subscribe_request:merge(DoorLock.events.LockUserChange:subscribe(mock_device_user_pin)) + subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_user_pin)) -- add test device, handle initial subscribe test.mock_device.add_test_device(mock_device_user_pin) test.socket.matter:__expect_send({mock_device_user_pin.id, subscribe_request}) @@ -228,7 +229,6 @@ local function test_init_user_pin() test.socket.capability:__expect_send( mock_device_user_pin:generate_test_message("main", capabilities.lockAlarm.alarm.clear({state_change = true})) ) - test.socket.matter:__expect_send({mock_device_user_pin.id, clusters.PowerSource.attributes.AttributeList:read()}) test.socket.device_lifecycle:__queue_receive({ mock_device_user_pin.id, "init" }) test.socket.matter:__expect_send({mock_device_user_pin.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_user_pin.id, "doConfigure" }) @@ -250,6 +250,8 @@ local function test_init_user_pin_schedule_unlatch() subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_user_pin_schedule_unlatch)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_user_pin_schedule_unlatch)) subscribe_request:merge(DoorLock.events.LockUserChange:subscribe(mock_device_user_pin_schedule_unlatch)) + subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_user_pin_schedule_unlatch)) + -- add test device, handle initial subscribe test.mock_device.add_test_device(mock_device_user_pin_schedule_unlatch) test.socket.matter:__expect_send({mock_device_user_pin_schedule_unlatch.id, subscribe_request}) @@ -258,7 +260,6 @@ local function test_init_user_pin_schedule_unlatch() test.socket.capability:__expect_send( mock_device_user_pin_schedule_unlatch:generate_test_message("main", capabilities.lockAlarm.alarm.clear({state_change = true})) ) - test.socket.matter:__expect_send({mock_device_user_pin_schedule_unlatch.id, clusters.PowerSource.attributes.AttributeList:read()}) test.socket.device_lifecycle:__queue_receive({ mock_device_user_pin_schedule_unlatch.id, "init" }) test.socket.matter:__expect_send({mock_device_user_pin_schedule_unlatch.id, subscribe_request}) test.socket.device_lifecycle:__queue_receive({ mock_device_user_pin_schedule_unlatch.id, "doConfigure" }) From 192f9a241067cddbf697ac727e851bf74313d3dc Mon Sep 17 00:00:00 2001 From: HunsupJung <59987061+HunsupJung@users.noreply.github.com> Date: Wed, 11 Mar 2026 21:32:16 +0900 Subject: [PATCH 19/29] Limit the length of User Name (#2764) Signed-off-by: Hunsup Jung --- ...-Rename-the-variable-and-reduce-code.patch | 77 +++++++++++++++++++ .../matter-lock/src/new-matter-lock/init.lua | 40 ++++++---- .../src/test/test_new_matter_lock.lua | 8 +- 3 files changed, 104 insertions(+), 21 deletions(-) create mode 100644 0001-Rename-the-variable-and-reduce-code.patch diff --git a/0001-Rename-the-variable-and-reduce-code.patch b/0001-Rename-the-variable-and-reduce-code.patch new file mode 100644 index 0000000000..f52f7882ef --- /dev/null +++ b/0001-Rename-the-variable-and-reduce-code.patch @@ -0,0 +1,77 @@ +From f19da9191362d70a020ab6852233eb327c19f906 Mon Sep 17 00:00:00 2001 +From: Hunsup Jung +Date: Sat, 7 Mar 2026 15:36:45 +0900 +Subject: [PATCH] Rename the variable and reduce code + +Signed-off-by: Hunsup Jung +--- + .../matter-lock/src/new-matter-lock/init.lua | 25 +++++++++---------- + 1 file changed, 12 insertions(+), 13 deletions(-) + +diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +index d9b9c9f6..37a9493a 100644 +--- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua ++++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +@@ -29,7 +29,8 @@ local PowerSource = clusters.PowerSource + + local INITIAL_CREDENTIAL_INDEX = 1 + local ALL_INDEX = 0xFFFE +-local NAME_MAX_L = 10 ++-- maximum as defined by the Matter specification ++local MAX_USER_NAME_LENGTH = 10 + local MIN_EPOCH_S = 0 + local MAX_EPOCH_S = 0xffffffff + local THIRTY_YEARS_S = 946684800 -- 1970-01-01T00:00:00 ~ 2000-01-01T00:00:00 +@@ -1274,10 +1275,7 @@ local function handle_update_user(driver, device, command) + local cmdName = "updateUser" + local userIdx = command.args.userIndex + local userName = command.args.userName +- local userNameMatter = userName +- if #userNameMatter > NAME_MAX_L then +- userNameMatter = string.sub(userNameMatter, 1, NAME_MAX_L) +- end ++ local userNameMatter = string.sub(userName, 1, MAX_USER_NAME_LENGTH) + local userType = command.args.userType + local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER + if userType == "guest" then +@@ -1307,7 +1305,7 @@ local function handle_update_user(driver, device, command) + device:send( + DoorLock.server.commands.SetUser( + device, ep, +- DoorLock.types.DataOperationTypeEnum.MODIFY, -- Operation Type: Add(0), Modify(2) ++ DoorLock.types.DataOperationTypeEnum.MODIFY, + userIdx, + userNameMatter, + nil, -- Unique ID +@@ -1355,6 +1353,7 @@ local function get_user_response_handler(driver, device, ib, response) + -- Found available user index + if status == nil or status == DoorLock.types.UserStatusEnum.AVAILABLE then + local userName = device:get_field(lock_utils.USER_NAME) ++ local userNameMatter = string.sub(userName, 1, MAX_USER_NAME_LENGTH) + local userType = device:get_field(lock_utils.USER_TYPE) + local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER + if userType == "guest" then +@@ -1368,13 +1367,13 @@ local function get_user_response_handler(driver, device, ib, response) + device:send( + DoorLock.server.commands.SetUser( + device, ep, +- DoorLock.types.DataOperationTypeEnum.ADD, -- Operation Type: Add(0), Modify(2) +- userIdx, -- User Index +- userName, -- User Name +- nil, -- Unique ID +- nil, -- User Status +- userTypeMatter, -- User Type +- nil -- Credential Rule ++ DoorLock.types.DataOperationTypeEnum.ADD, ++ userIdx, ++ userNameMatter, ++ nil, -- Unique ID ++ nil, -- User Status ++ userTypeMatter, ++ nil -- Credential Rule + ) + ) + elseif userIdx >= maxUser then -- There's no available user index +-- +2.39.5 (Apple Git-154) + diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index 8d50f4b94c..7cef6fe2a7 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -18,6 +18,8 @@ local PowerSource = clusters.PowerSource local INITIAL_CREDENTIAL_INDEX = 1 local ALL_INDEX = 0xFFFE +-- maximum as defined by the Matter specification +local MAX_USER_NAME_LENGTH = 10 local MIN_EPOCH_S = 0 local MAX_EPOCH_S = 0xffffffff local THIRTY_YEARS_S = 946684800 -- 1970-01-01T00:00:00 ~ 2000-01-01T00:00:00 @@ -1264,6 +1266,7 @@ local function handle_update_user(driver, device, command) local cmdName = "updateUser" local userIdx = command.args.userIndex local userName = command.args.userName + local userNameMatter = string.sub(userName, 1, MAX_USER_NAME_LENGTH) local userType = command.args.userType local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER if userType == "guest" then @@ -1293,13 +1296,13 @@ local function handle_update_user(driver, device, command) device:send( DoorLock.server.commands.SetUser( device, ep, - DoorLock.types.DataOperationTypeEnum.MODIFY, -- Operation Type: Add(0), Modify(2) - userIdx, -- User Index - userName, -- User Name - nil, -- Unique ID - nil, -- User Status - userTypeMatter, -- User Type - nil -- Credential Rule + DoorLock.types.DataOperationTypeEnum.MODIFY, + userIdx, + userNameMatter, + nil, -- Unique ID + nil, -- User Status + userTypeMatter, + nil -- Credential Rule ) ) end @@ -1341,6 +1344,7 @@ local function get_user_response_handler(driver, device, ib, response) -- Found available user index if status == nil or status == DoorLock.types.UserStatusEnum.AVAILABLE then local userName = device:get_field(lock_utils.USER_NAME) + local userNameMatter = string.sub(userName, 1, MAX_USER_NAME_LENGTH) local userType = device:get_field(lock_utils.USER_TYPE) local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER if userType == "guest" then @@ -1354,13 +1358,13 @@ local function get_user_response_handler(driver, device, ib, response) device:send( DoorLock.server.commands.SetUser( device, ep, - DoorLock.types.DataOperationTypeEnum.ADD, -- Operation Type: Add(0), Modify(2) - userIdx, -- User Index - userName, -- User Name - nil, -- Unique ID - nil, -- User Status - userTypeMatter, -- User Type - nil -- Credential Rule + DoorLock.types.DataOperationTypeEnum.ADD, + userIdx, + userNameMatter, + nil, -- Unique ID + nil, -- User Status + userTypeMatter, + nil -- Credential Rule ) ) elseif userIdx >= maxUser then -- There's no available user index @@ -1521,14 +1525,16 @@ local function handle_add_credential(driver, device, command) -- Get parameters local cmdName = "addCredential" local userIdx = command.args.userIndex - if userIdx == 0 then - userIdx = nil - end local userType = command.args.userType local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER if userType == "guest" then userTypeMatter = DoorLock.types.UserTypeEnum.SCHEDULE_RESTRICTED_USER end + if userIdx == 0 then + userIdx = nil + else + userTypeMatter = nil + end local credential = { credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = INITIAL_CREDENTIAL_INDEX diff --git a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua index 3742e16e04..4bd863f2a7 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua @@ -1402,7 +1402,7 @@ test.register_coroutine_test( "654123", -- credential_data 1, -- user_index nil, -- user_status - DoorLock.types.DlUserType.UNRESTRICTED_USER -- user_type + nil -- user_type ), } ) @@ -1496,7 +1496,7 @@ test.register_coroutine_test( "654123", -- credential_data 1, -- user_index nil, -- user_status - DoorLock.types.DlUserType.UNRESTRICTED_USER -- user_type + nil -- user_type ), } ) @@ -1552,7 +1552,7 @@ test.register_coroutine_test( "654123", -- credential_data 1, -- user_index nil, -- user_status - DoorLock.types.DlUserType.UNRESTRICTED_USER -- user_type + nil -- user_type ), } ) @@ -1615,7 +1615,7 @@ test.register_coroutine_test( "654123", -- credential_data 1, -- user_index nil, -- user_status - DoorLock.types.DlUserType.UNRESTRICTED_USER -- user_type + nil -- user_type ), } ) From 54bdf7b7852ff816f753fc281d1f1c0e69265e14 Mon Sep 17 00:00:00 2001 From: HunsupJung <59987061+HunsupJung@users.noreply.github.com> Date: Wed, 11 Mar 2026 20:50:51 +0900 Subject: [PATCH 20/29] Postpone updating commandResult (#2765) Signed-off-by: Hunsup Jung --- .../matter-lock/src/new-matter-lock/init.lua | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index 7cef6fe2a7..b223d74ec8 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -1659,17 +1659,6 @@ local function set_pin_response_handler(driver, device, ib, response) add_credential_to_table(device, userIdx, credIdx, "pin") end - -- Update commandResult - local command_result_info = { - commandName = cmdName, - userIndex = userIdx, - credentialIndex = credIdx, - statusCode = status - } - device:emit_event(capabilities.lockCredentials.commandResult( - command_result_info, {state_change = true, visibility = {displayed = false}} - )) - -- If User Type is Guest and device support schedule, add default schedule local week_schedule_eps = device:get_endpoints(DoorLock.ID, {feature_bitmap = DoorLock.types.Feature.WEEK_DAY_ACCESS_SCHEDULES}) local year_schedule_eps = device:get_endpoints(DoorLock.ID, {feature_bitmap = DoorLock.types.Feature.YEAR_DAY_ACCESS_SCHEDULES}) @@ -1693,6 +1682,16 @@ local function set_pin_response_handler(driver, device, ib, response) ) ) else + -- Update commandResult + local command_result_info = { + commandName = cmdName, + userIndex = userIdx, + credentialIndex = credIdx, + statusCode = status + } + device:emit_event(capabilities.lockCredentials.commandResult( + command_result_info, {state_change = true, visibility = {displayed = false}} + )) device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) end return @@ -2368,6 +2367,20 @@ local function set_year_day_schedule_handler(driver, device, ib, response) end if cmdName == "defaultSchedule" then + local cmdName = "addCredential" + local credIdx = device:get_field(lock_utils.CRED_INDEX) + + -- Update commandResult + local command_result_info = { + commandName = cmdName, + userIndex = userIdx, + credentialIndex = credIdx, + statusCode = status + } + device:emit_event(capabilities.lockCredentials.commandResult( + command_result_info, {state_change = true, visibility = {displayed = false}} + )) + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) return end From 0cae95e256f2ed7108a678063c8ec108f2958bba Mon Sep 17 00:00:00 2001 From: HunsupJung <59987061+HunsupJung@users.noreply.github.com> Date: Thu, 12 Mar 2026 10:41:12 +0900 Subject: [PATCH 21/29] Remove garbage file (#2835) Signed-off-by: Hunsup Jung --- ...-Rename-the-variable-and-reduce-code.patch | 77 ------------------- 1 file changed, 77 deletions(-) delete mode 100644 0001-Rename-the-variable-and-reduce-code.patch diff --git a/0001-Rename-the-variable-and-reduce-code.patch b/0001-Rename-the-variable-and-reduce-code.patch deleted file mode 100644 index f52f7882ef..0000000000 --- a/0001-Rename-the-variable-and-reduce-code.patch +++ /dev/null @@ -1,77 +0,0 @@ -From f19da9191362d70a020ab6852233eb327c19f906 Mon Sep 17 00:00:00 2001 -From: Hunsup Jung -Date: Sat, 7 Mar 2026 15:36:45 +0900 -Subject: [PATCH] Rename the variable and reduce code - -Signed-off-by: Hunsup Jung ---- - .../matter-lock/src/new-matter-lock/init.lua | 25 +++++++++---------- - 1 file changed, 12 insertions(+), 13 deletions(-) - -diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua -index d9b9c9f6..37a9493a 100644 ---- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua -+++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua -@@ -29,7 +29,8 @@ local PowerSource = clusters.PowerSource - - local INITIAL_CREDENTIAL_INDEX = 1 - local ALL_INDEX = 0xFFFE --local NAME_MAX_L = 10 -+-- maximum as defined by the Matter specification -+local MAX_USER_NAME_LENGTH = 10 - local MIN_EPOCH_S = 0 - local MAX_EPOCH_S = 0xffffffff - local THIRTY_YEARS_S = 946684800 -- 1970-01-01T00:00:00 ~ 2000-01-01T00:00:00 -@@ -1274,10 +1275,7 @@ local function handle_update_user(driver, device, command) - local cmdName = "updateUser" - local userIdx = command.args.userIndex - local userName = command.args.userName -- local userNameMatter = userName -- if #userNameMatter > NAME_MAX_L then -- userNameMatter = string.sub(userNameMatter, 1, NAME_MAX_L) -- end -+ local userNameMatter = string.sub(userName, 1, MAX_USER_NAME_LENGTH) - local userType = command.args.userType - local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER - if userType == "guest" then -@@ -1307,7 +1305,7 @@ local function handle_update_user(driver, device, command) - device:send( - DoorLock.server.commands.SetUser( - device, ep, -- DoorLock.types.DataOperationTypeEnum.MODIFY, -- Operation Type: Add(0), Modify(2) -+ DoorLock.types.DataOperationTypeEnum.MODIFY, - userIdx, - userNameMatter, - nil, -- Unique ID -@@ -1355,6 +1353,7 @@ local function get_user_response_handler(driver, device, ib, response) - -- Found available user index - if status == nil or status == DoorLock.types.UserStatusEnum.AVAILABLE then - local userName = device:get_field(lock_utils.USER_NAME) -+ local userNameMatter = string.sub(userName, 1, MAX_USER_NAME_LENGTH) - local userType = device:get_field(lock_utils.USER_TYPE) - local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER - if userType == "guest" then -@@ -1368,13 +1367,13 @@ local function get_user_response_handler(driver, device, ib, response) - device:send( - DoorLock.server.commands.SetUser( - device, ep, -- DoorLock.types.DataOperationTypeEnum.ADD, -- Operation Type: Add(0), Modify(2) -- userIdx, -- User Index -- userName, -- User Name -- nil, -- Unique ID -- nil, -- User Status -- userTypeMatter, -- User Type -- nil -- Credential Rule -+ DoorLock.types.DataOperationTypeEnum.ADD, -+ userIdx, -+ userNameMatter, -+ nil, -- Unique ID -+ nil, -- User Status -+ userTypeMatter, -+ nil -- Credential Rule - ) - ) - elseif userIdx >= maxUser then -- There's no available user index --- -2.39.5 (Apple Git-154) - From 75395264ce5511eed9c2a7ef1e0d2bb5c9eba899 Mon Sep 17 00:00:00 2001 From: HunsupJung <59987061+HunsupJung@users.noreply.github.com> Date: Wed, 11 Mar 2026 19:15:29 +0900 Subject: [PATCH 22/29] Update digital key event (#2829) Signed-off-by: Hunsup Jung --- .../SmartThings/matter-lock/src/new-matter-lock/init.lua | 6 +++--- .../matter-lock/src/test/test_new_matter_lock.lua | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index b223d74ec8..f708dcae02 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -2512,11 +2512,11 @@ local function lock_op_event_handler(driver, device, ib, response) elseif opSource.value == Source.RFID then opSource = "rfid" elseif opSource.value == Source.BIOMETRIC then - opSource = "keypad" + opSource = nil -- It will be updated R2 elseif opSource.value == Source.ALIRO then - opSource = nil + opSource = "digitalKey" else - opSource =nil + opSource = nil end if userIdx ~= nil then diff --git a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua index 4bd863f2a7..3e59163ef5 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua @@ -921,7 +921,7 @@ test.register_message_test( message = mock_device:generate_test_message( "main", capabilities.lock.lock.unlocked( - {data = {method = "keypad", userIndex = 1}, state_change = true} + {data = {userIndex = 1}, state_change = true} ) ), }, @@ -948,7 +948,7 @@ test.register_message_test( message = mock_device:generate_test_message( "main", capabilities.lock.lock.unlocked( - {data = {userIndex = 1}, state_change = true} + {data = {method = "digitalKey", userIndex = 1}, state_change = true} ) ), } From feb4676fa221a1b0e0ef9fe670536a47d5169efb Mon Sep 17 00:00:00 2001 From: HunsupJung <59987061+HunsupJung@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:18:28 +0900 Subject: [PATCH 23/29] Support keypair generation (#2815) Conflict: drivers/SmartThings/matter-lock/src/test/test_matter_lock_modular.lua Conflict due to a test that is removed by this change. Signed-off-by: Hunsup Jung --- .../matter-lock/src/lock_utils.lua | 176 ++++- .../matter-lock/src/new-matter-lock/init.lua | 238 +++--- .../src/test/test_aqara_matter_lock.lua | 3 + .../src/test/test_matter_lock_modular.lua | 83 +-- .../src/test/test_matter_lock_unlatch.lua | 3 + .../src/test/test_new_matter_lock.lua | 3 + .../src/test/test_new_matter_lock_aliro.lua | 682 ++++++++++++++++++ .../src/test/test_new_matter_lock_battery.lua | 11 +- 8 files changed, 1026 insertions(+), 173 deletions(-) create mode 100644 drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_aliro.lua diff --git a/drivers/SmartThings/matter-lock/src/lock_utils.lua b/drivers/SmartThings/matter-lock/src/lock_utils.lua index 94e95c196f..fcea79d7f5 100644 --- a/drivers/SmartThings/matter-lock/src/lock_utils.lua +++ b/drivers/SmartThings/matter-lock/src/lock_utils.lua @@ -1,6 +1,9 @@ -- Copyright 2022 SmartThings, Inc. -- Licensed under the Apache License, Version 2.0 +local security = require "st.security" +local PUB_KEY_PREFIX = "04" + local lock_utils = { -- Lock device field names LOCK_CODES = "lockCodes", @@ -39,7 +42,11 @@ local lock_utils = { ENDPOINT_KEY_INDEX = "endpointKeyIndex", ENDPOINT_KEY_TYPE = "endpointKeyType", DEVICE_KEY_ID = "deviceKeyId", - COMMAND_REQUEST_ID = "commandRequestId" + COMMAND_REQUEST_ID = "commandRequestId", + MODULAR_PROFILE_UPDATED = "__MODULAR_PROFILE_UPDATED", + ALIRO_READER_CONFIG_UPDATED = "aliroReaderConfigUpdated", + LATEST_DOOR_LOCK_FEATURE_MAP = "latestDoorLockFeatureMap", + IS_MODULAR_PROFILE = "isModularProfile" } local capabilities = require "st.capabilities" local json = require "st.json" @@ -102,4 +109,171 @@ end -- keys are the code slots that ST uses -- user_index and credential_index are used in the matter commands -- +function lock_utils.get_field_for_endpoint(device, field, endpoint) + return device:get_field(string.format("%s_%d", field, endpoint)) +end + +function lock_utils.set_field_for_endpoint(device, field, endpoint, value, additional_params) + device:set_field(string.format("%s_%d", field, endpoint), value, additional_params) +end + +function lock_utils.optional_capabilities_list_changed(new_component_capability_list, previous_component_capability_list) + local previous_capability_map = {} + local component_sizes = {} + local previous_component_count = 0 + for component_name, component in pairs(previous_component_capability_list or {}) do + previous_capability_map[component_name] = {} + component_sizes[component_name] = 0 + for _, capability in pairs(component.capabilities or {}) do + if capability.id ~= "lock" and capability.id ~= "lockAlarm" and capability.id ~= "remoteControlStatus" and + capability.id ~= "firmwareUpdate" and capability.id ~= "refresh" then + previous_capability_map[component_name][capability.id] = true + component_sizes[component_name] = component_sizes[component_name] + 1 + end + end + previous_component_count = previous_component_count + 1 + end + + local number_of_components_counted = 0 + for _, new_component_capabilities in pairs(new_component_capability_list or {}) do + local component_name = new_component_capabilities[1] + local capability_list = new_component_capabilities[2] + number_of_components_counted = number_of_components_counted + 1 + if previous_capability_map[component_name] == nil then + return true + end + for _, capability in ipairs(capability_list) do + if previous_capability_map[component_name][capability] == nil then + return true + end + end + if #capability_list ~= component_sizes[component_name] then + return true + end + end + + if number_of_components_counted ~= previous_component_count then + return true + end + + return false +end + +-- This function check busy_state and if busy_state is false, set it to true(current time) +function lock_utils.is_busy_state_set(device) + local c_time = os.time() + local busy_state = device:get_field(lock_utils.BUSY_STATE) or false + if busy_state == false or c_time - busy_state > 10 then + device:set_field(lock_utils.BUSY_STATE, c_time, {persist = true}) + return false + else + return true + end +end + +function lock_utils.hex_string_to_octet_string(hex_string) + if hex_string == nil then + return nil + end + local octet_string = "" + for i = 1, #hex_string, 2 do + local hex = hex_string:sub(i, i + 1) + octet_string = octet_string .. string.char(tonumber(hex, 16)) + end + return octet_string +end + +function lock_utils.create_group_id_resolving_key() + math.randomseed(os.time()) + local result = string.format("%02x", math.random(0, 255)) + for i = 1, 15 do + result = result .. string.format("%02x", math.random(0, 255)) + end + return result +end + +function lock_utils.generate_keypair(device) + local request_opts = { + key_algorithm = { + type = "ec", + curve = "prime256v1" + }, + signature_algorithm = "sha256", + return_formats = { + pem = true, + der = true + }, + subject = { + common_name = "reader config" + }, + validity_days = 36500, + x509_extensions = { + key_usage = { + critical = true, + digital_signature = true + }, + certificate_policies = { + critical = true, + policy_2030_5_self_signed_client = true + } + } + } + local status = security.generate_self_signed_cert(request_opts) + if not status or not status.key_der then + device.log.error("generate_self_signed_cert returned no data") + return nil, nil + end + + local der = status.key_der + local privKey, pubKey = nil, nil + -- Helper: Parse ASN.1 length (handles 1-byte and multi-byte lengths) + local function get_length(data, start_pos) + local b = string.byte(data, start_pos) + if not b then return nil, start_pos end + + if b < 0x80 then + return b, start_pos + 1 + else + local num_bytes = b - 0x80 + local len = 0 + for i = 1, num_bytes do + len = (len * 256) + string.byte(data, start_pos + i) + end + return len, start_pos + 1 + num_bytes + end + end + -- Start parsing after the initial SEQUENCE tag (0x30) + -- Most keys start: [0x30][Length]. We find the first length to find the start of content. + local _, pos = get_length(der, 2) + + while pos < #der do + local tag = string.byte(der, pos) + local len, content_start = get_length(der, pos + 1) + if not len then break end + if tag == 0x04 then + -- PRIVATE KEY: Octet String + privKey = utils.bytes_to_hex_string(string.sub(der, content_start, content_start + len - 1)) + elseif tag == 0xA1 then + -- PUBLIC KEY Wrapper: Explicit Tag [1] + -- Inside 0xA1 is a BIT STRING (0x03) + local inner_tag = string.byte(der, content_start) + if inner_tag == 0x03 then + local bit_len, bit_start = get_length(der, content_start + 1) + -- BIT STRINGS have a "leading null byte" (unused bits indicator) + -- We skip that byte (bit_start) and the 0x04 EC prefix to get the raw X/Y coordinates + local actual_key_start = bit_start + 2 + local actual_key_len = bit_len - 2 + pubKey = PUB_KEY_PREFIX .. utils.bytes_to_hex_string(string.sub(der, actual_key_start, actual_key_start + actual_key_len - 1)) + end + end + -- Move pointer to the next tag + pos = content_start + len + end + + if not privKey or not pubKey then + device.log.error("Failed to extract keys from DER") + end + return privKey, pubKey +end + return lock_utils diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index f708dcae02..1e7d461eda 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -1,7 +1,6 @@ -- Copyright 2025 SmartThings, Inc. -- Licensed under the Apache License, Version 2.0 - local capabilities = require "st.capabilities" local clusters = require "st.matter.clusters" local im = require "st.matter.interaction_model" @@ -49,7 +48,6 @@ local ALIRO_KEY_TYPE_TO_CRED_ENUM_MAP = { ["nonEvictableEndpointKey"] = DoorLock.types.CredentialTypeEnum.ALIRO_NON_EVICTABLE_ENDPOINT_KEY } - local battery_support = { NO_BATTERY = "NO_BATTERY", BATTERY_LEVEL = "BATTERY_LEVEL", @@ -60,6 +58,7 @@ local profiling_data = { BATTERY_SUPPORT = "__BATTERY_SUPPORT", } +local DoorLockFeatureMapAttr = {ID = 0xFFFC, cluster = DoorLock.ID} local subscribed_attributes = { [capabilities.lock.ID] = { DoorLock.attributes.LockState @@ -111,7 +110,6 @@ local subscribed_events = { } } - local function find_default_endpoint(device, cluster) local res = device.MATTER_DEFAULT_ENDPOINT local eps = device:get_endpoints(cluster) @@ -143,6 +141,7 @@ local function device_init(driver, device) end end end + device:add_subscribed_attribute(DoorLockFeatureMapAttr) for cap_id, events in pairs(subscribed_events) do if device:supports_capability_by_id(cap_id) then for _, e in ipairs(events) do @@ -157,6 +156,61 @@ local function device_added(driver, device) device:emit_event(capabilities.lockAlarm.alarm.clear({state_change = true})) end +local function set_reader_config(device) + local reader_config_updated = device:get_field(lock_utils.ALIRO_READER_CONFIG_UPDATED) or nil + if reader_config_updated == "TRUE" or reader_config_updated == "IN_PROGRESS" then return end + + local cmdName = "setReaderConfig" + local groupId = lock_utils.create_group_id_resolving_key() + local groupResolvingKey = nil + local aliro_ble_uwb_eps = device:get_endpoints(DoorLock.ID, {feature_bitmap = DoorLock.types.Feature.ALIROBLEUWB}) + if #aliro_ble_uwb_eps > 0 then + groupResolvingKey = lock_utils.create_group_id_resolving_key() + end + local privKey, pubKey = lock_utils.generate_keypair(device) + if not privKey or not pubKey then + local command_result_info = { + commandName = cmdName, + statusCode = "failure" + } + device:emit_event(capabilities.lockAliro.commandResult( + command_result_info, {state_change = true, visibility = {displayed = false}} + )) + return + end + + -- Check busy state + if lock_utils.is_busy_state_set(device) then + local command_result_info = { + commandName = cmdName, + statusCode = "busy" + } + device:emit_event(capabilities.lockAliro.commandResult( + command_result_info, {state_change = true, visibility = {displayed = false}} + )) + return + end + + -- Save values to field + device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) + device:set_field(lock_utils.VERIFICATION_KEY, pubKey, {persist = true}) + device:set_field(lock_utils.GROUP_ID, groupId, {persist = true}) + device:set_field(lock_utils.GROUP_RESOLVING_KEY, groupResolvingKey, {persist = true}) + + -- Send command + local ep = find_default_endpoint(device, clusters.DoorLock.ID) + device:send( + DoorLock.server.commands.SetAliroReaderConfig( + device, ep, + lock_utils.hex_string_to_octet_string(privKey), + lock_utils.hex_string_to_octet_string(pubKey), + lock_utils.hex_string_to_octet_string(groupId), + lock_utils.hex_string_to_octet_string(groupResolvingKey) + ) + ) + device:set_field(lock_utils.ALIRO_READER_CONFIG_UPDATED, "IN_PROGRESS", {persist = true}) +end + local function match_profile_modular(driver, device) local enabled_optional_component_capability_pairs = {} local main_component_capabilities = {} @@ -165,7 +219,11 @@ local function match_profile_modular(driver, device) for _, ep_cluster in pairs(device_ep.clusters) do if ep_cluster.cluster_id == DoorLock.ID then local clus_has_feature = function(feature_bitmap) - return DoorLock.are_features_supported(feature_bitmap, ep_cluster.feature_map) + return DoorLock.are_features_supported( + feature_bitmap, + lock_utils.get_field_for_endpoint(device, lock_utils.LATEST_DOOR_LOCK_FEATURE_MAP, device_ep.endpoint_id) or + ep_cluster.feature_map + ) end if clus_has_feature(DoorLock.types.Feature.USER) then table.insert(main_component_capabilities, capabilities.lockUsers.ID) @@ -201,7 +259,9 @@ local function match_profile_modular(driver, device) end table.insert(enabled_optional_component_capability_pairs, {"main", main_component_capabilities}) - device:try_update_metadata({profile = modular_profile_name, optional_component_capabilities = enabled_optional_component_capability_pairs}) + if lock_utils.optional_capabilities_list_changed(enabled_optional_component_capability_pairs, device.profile.components) then + device:try_update_metadata({profile = modular_profile_name, optional_component_capabilities = enabled_optional_component_capability_pairs}) + end end local function match_profile_switch(driver, device) @@ -302,6 +362,9 @@ local function info_changed(driver, device, event, args) end end device:subscribe() + if device:supports_capability_by_id(capabilities.lockAliro.ID) then + set_reader_config(device) + end if device:get_latest_state("main", capabilities.lockAlarm.ID, capabilities.lockAlarm.supportedAlarmValues.NAME) == nil then device:emit_event(capabilities.lockAlarm.alarm.clear({state_change = true})) device:emit_event(capabilities.lockAlarm.supportedAlarmValues({"unableToLockTheDoor"}, {visibility = {displayed = false}})) -- lockJammed is mandatory @@ -317,18 +380,17 @@ local function profiling_data_still_required(device) return false end -local function match_profile(driver, device) +local function match_profile(driver, device, ignore_static_profiling) if profiling_data_still_required(device) then return end - if version.api >= 15 and version.rpc >= 9 then match_profile_modular(driver, device) - else + elseif ignore_static_profiling ~= true then match_profile_switch(driver, device) end end local function do_configure(driver, device) - match_profile(driver, device) + match_profile(driver, device, false) device.thread:call_with_delay(5, function() device:emit_event(capabilities.lockAlarm.alarm.clear({state_change = true})) device:emit_event(capabilities.lockAlarm.supportedAlarmValues({"unableToLockTheDoor"}, {visibility = {displayed = false}})) -- lockJammed is mandatory @@ -336,19 +398,7 @@ local function do_configure(driver, device) end local function driver_switched(driver, device) - match_profile(driver, device) -end - --- This function check busy_state and if busy_state is false, set it to true(current time) -local function is_busy_state_set(device) - local c_time = os.time() - local busy_state = device:get_field(lock_utils.BUSY_STATE) or false - if busy_state == false or c_time - busy_state > 10 then - device:set_field(lock_utils.BUSY_STATE, c_time, {persist = true}) - return false - else - return true - end + match_profile(driver, device, false) end -- Matter Handler @@ -449,7 +499,7 @@ local function set_cota_credential(device, credential_index) end -- Check Busy State - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then device.log.debug("delaying setting COTA credential since a credential is currently being set") device.thread:call_with_delay(2, function(t) set_cota_credential(device, credential_index) @@ -524,21 +574,6 @@ local function max_year_schedule_of_user_handler(driver, device, ib, response) device:emit_event(capabilities.lockSchedules.yearDaySchedulesPerUser(ib.data.value, {visibility = {displayed = false}})) end ----------------- --- Aliro Util -- ----------------- -local function hex_string_to_octet_string(hex_string) - if hex_string == nil then - return nil - end - local octet_string = "" - for i = 1, #hex_string, 2 do - local hex = hex_string:sub(i, i + 1) - octet_string = octet_string .. string.char(tonumber(hex, 16)) - end - return octet_string -end - ----------------------------------- -- Aliro Reader Verification Key -- ----------------------------------- @@ -547,6 +582,7 @@ local function aliro_reader_verification_key_handler(driver, device, ib, respons device:emit_event(capabilities.lockAliro.readerVerificationKey( utils.bytes_to_hex_string(ib.data.value), {visibility = {displayed = false}} )) + device:set_field(lock_utils.ALIRO_READER_CONFIG_UPDATED, "TRUE", {persist = true}) end end @@ -631,6 +667,18 @@ local function max_aliro_endpoint_key_handler(driver, device, ib, response) end end +------------------------------ +-- Feature Map of Door Lock -- +------------------------------ +local function door_lock_feature_map_handler(driver, device, ib, response) + if ib.data.value == nil then return end + local feature_map = lock_utils.get_field_for_endpoint(device, lock_utils.LATEST_DOOR_LOCK_FEATURE_MAP, ib.endpoint_id) or nil + if feature_map ~= ib.data.value then + lock_utils.set_field_for_endpoint(device, lock_utils.LATEST_DOOR_LOCK_FEATURE_MAP, ib.endpoint_id, ib.data.value, { persist = true }) + match_profile(driver, device, true) + end +end + --------------------------------- -- Power Source Attribute List -- --------------------------------- @@ -649,7 +697,7 @@ local function handle_power_source_attribute_list(driver, device, ib, response) device:set_field(profiling_data.BATTERY_SUPPORT, battery_support.NO_BATTERY, {persist=true}) end if latest_battery_support == nil or latest_battery_support ~= device:get_field(profiling_data.BATTERY_SUPPORT) then - match_profile(driver, device) + match_profile(driver, device, false) end end @@ -1236,7 +1284,7 @@ local function handle_add_user(driver, device, command) local userType = command.args.userType -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, statusCode = "busy" @@ -1274,7 +1322,7 @@ local function handle_update_user(driver, device, command) end -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, statusCode = "busy" @@ -1433,7 +1481,7 @@ local function handle_delete_user(driver, device, command) local userIdx = command.args.userIndex -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, statusCode = "busy" @@ -1461,7 +1509,7 @@ local function handle_delete_all_users(driver, device, command) local cmdName = "deleteAllUsers" -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, statusCode = "busy" @@ -1542,7 +1590,7 @@ local function handle_add_credential(driver, device, command) local credData = command.args.credentialData -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, statusCode = "busy" @@ -1590,7 +1638,7 @@ local function handle_update_credential(driver, device, command) local credData = command.args.credentialData -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, statusCode = "busy" @@ -1835,7 +1883,7 @@ local function set_issuer_key_response_handler(driver, device, ib, response) device, ep, DoorLock.types.DataOperationTypeEnum.ADD, credential, -- Credential - hex_string_to_octet_string(credData), -- Credential Data + lock_utils.hex_string_to_octet_string(credData), -- Credential Data userIdx, -- User Index nil, -- User Status userType -- User Type @@ -1934,7 +1982,7 @@ local function set_endpoint_key_response_handler(driver, device, ib, response) device, ep, DoorLock.types.DataOperationTypeEnum.ADD, credential, -- Credential - hex_string_to_octet_string(credData), -- Credential Data + lock_utils.hex_string_to_octet_string(credData), -- Credential Data userIdx, -- User Index nil, -- User Status userType -- User Type @@ -1983,7 +2031,7 @@ local function handle_delete_credential(driver, device, command) } -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, statusCode = "busy" @@ -2015,7 +2063,7 @@ local function handle_delete_all_credentials(driver, device, command) } -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, statusCode = "busy" @@ -2128,7 +2176,7 @@ local function handle_set_week_day_schedule(driver, device, command) local endMinute = schedule.endMinute -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, statusCode = "busy" @@ -2222,7 +2270,7 @@ local function handle_clear_week_day_schedule(driver, device, command) local userIdx = command.args.userIndex -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, statusCode = "busy" @@ -2318,7 +2366,7 @@ local function handle_set_year_day_schedule(driver, device, command) local localEndTime = command.args.schedule.localEndTime -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, statusCode = "busy" @@ -2417,7 +2465,7 @@ local function handle_clear_year_day_schedule(driver, device, command) local userIdx = command.args.userIndex -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, statusCode = "busy" @@ -2545,7 +2593,7 @@ local function handle_set_reader_config(driver, device, command) end -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, statusCode = "busy" @@ -2556,6 +2604,22 @@ local function handle_set_reader_config(driver, device, command) return end + local reader_config_updated = device:get_field(lock_utils.ALIRO_READER_CONFIG_UPDATED) or nil + if reader_config_updated == "IN_PROGRESS" then + return + elseif reader_config_updated == "TRUE" then + -- Update commandResult + local command_result_info = { + commandName = cmdName, + statusCode = "success" + } + device:emit_event(capabilities.lockAliro.commandResult( + command_result_info, {state_change = true, visibility = {displayed = false}} + )) + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) + return + end + -- Save values to field device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.VERIFICATION_KEY, verificationKey, {persist = true}) @@ -2567,54 +2631,27 @@ local function handle_set_reader_config(driver, device, command) device:send( DoorLock.server.commands.SetAliroReaderConfig( device, ep, - hex_string_to_octet_string(signingKey), - hex_string_to_octet_string(verificationKey), - hex_string_to_octet_string(groupId), -- Group identification - hex_string_to_octet_string(groupResolvingKey) -- Group resolving key + lock_utils.hex_string_to_octet_string(signingKey), + lock_utils.hex_string_to_octet_string(verificationKey), + lock_utils.hex_string_to_octet_string(groupId), + lock_utils.hex_string_to_octet_string(groupResolvingKey) ) ) + device:set_field(lock_utils.ALIRO_READER_CONFIG_UPDATED, "IN_PROGRESS", {persist = true}) end local function set_aliro_reader_config_handler(driver, device, ib, response) -- Get result local cmdName = device:get_field(lock_utils.COMMAND_NAME) - local verificationKey = device:get_field(lock_utils.VERIFICATION_KEY) - local groupId = device:get_field(lock_utils.GROUP_ID) - local groupResolvingKey = device:get_field(lock_utils.GROUP_RESOLVING_KEY) - - local status = "success" - if ib.status == DoorLock.types.DlStatus.FAILURE then - status = "failure" - elseif ib.status == DoorLock.types.DlStatus.INVALID_FIELD then - status = "invalidCommand" - elseif ib.status == DoorLock.types.DlStatus.SUCCESS then - if verificationKey ~= nil then - device:emit_event(capabilities.lockAliro.readerVerificationKey( - verificationKey, - { - state_change = true, - visibility = {displayed = false} - } - )) - end - if groupId ~= nil then - device:emit_event(capabilities.lockAliro.readerGroupIdentifier( - groupId, - { - state_change = true, - visibility = {displayed = false} - } - )) - end - if groupResolvingKey ~= nil then - device:emit_event(capabilities.lockAliro.groupResolvingKey( - groupResolvingKey, - { - state_change = true, - visibility = {displayed = false} - } - )) + local status = "failure" + if ib.status == DoorLock.types.DlStatus.SUCCESS then + status = "success" + device:set_field(lock_utils.ALIRO_READER_CONFIG_UPDATED, "TRUE", {persist = true}) + else + if ib.status == DoorLock.types.DlStatus.INVALID_FIELD then + status = "invalidCommand" end + device:set_field(lock_utils.ALIRO_READER_CONFIG_UPDATED, nil, {persist = true}) end -- Update commandResult @@ -2654,7 +2691,7 @@ local function handle_set_issuer_key(driver, device, command) end -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, userIndex = userIdx, @@ -2681,7 +2718,7 @@ local function handle_set_issuer_key(driver, device, command) device, ep, DoorLock.types.DataOperationTypeEnum.ADD, -- Data Operation Type: Add(0), Modify(2) credential, -- Credential - hex_string_to_octet_string(issuerKey), -- Credential Data + lock_utils.hex_string_to_octet_string(issuerKey), -- Credential Data userIdx, -- User Index nil, -- User Status userType -- User Type @@ -2696,7 +2733,7 @@ local function handle_clear_issuer_key(driver, device, command) local reqId = command.args.requestId -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, userIndex = userIdx, @@ -2757,7 +2794,7 @@ local function handle_set_endpoint_key(driver, device, command) end -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, userIndex = userIdx, @@ -2815,7 +2852,7 @@ local function handle_set_endpoint_key(driver, device, command) device, ep, dataOpType, -- Data Operation Type: Add(0), Modify(2) credential, -- Credential - hex_string_to_octet_string(endpointKey), -- Credential Data + lock_utils.hex_string_to_octet_string(endpointKey), -- Credential Data userIdx, -- User Index nil, -- User Status userType -- User Type @@ -2832,7 +2869,7 @@ local function handle_clear_endpoint_key(driver, device, command) local reqId = command.args.requestId -- Check busy state - if is_busy_state_set(device) then + if lock_utils.is_busy_state_set(device) then local command_result_info = { commandName = cmdName, userIndex = userIdx, @@ -2910,6 +2947,7 @@ local new_matter_lock_handler = { [DoorLock.attributes.AliroBLEAdvertisingVersion.ID] = aliro_ble_advertising_version_handler, [DoorLock.attributes.NumberOfAliroCredentialIssuerKeysSupported.ID] = max_aliro_credential_issuer_key_handler, [DoorLock.attributes.NumberOfAliroEndpointKeysSupported.ID] = max_aliro_endpoint_key_handler, + [DoorLockFeatureMapAttr.ID] = door_lock_feature_map_handler, }, [PowerSource.ID] = { [PowerSource.attributes.AttributeList.ID] = handle_power_source_attribute_list, diff --git a/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua b/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua index 7752991e47..57d7e2b71e 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua @@ -7,6 +7,7 @@ test.set_rpc_version(0) local capabilities = require "st.capabilities" local t_utils = require "integration_test.utils" local clusters = require "st.matter.clusters" +local cluster_base = require "st.matter.cluster_base" local mock_device = test.mock_device.build_test_matter_device({ profile = t_utils.get_profile_definition("lock-user-pin.yml"), @@ -42,6 +43,7 @@ local mock_device = test.mock_device.build_test_matter_device({ } }) +local DoorLockFeatureMapAttr = {ID = 0xFFFC, cluster = clusters.DoorLock.ID} local function test_init() test.disable_startup_messages() -- subscribe request @@ -52,6 +54,7 @@ local function test_init() subscribe_request:merge(clusters.DoorLock.attributes.MaxPINCodeLength:subscribe(mock_device)) subscribe_request:merge(clusters.DoorLock.attributes.MinPINCodeLength:subscribe(mock_device)) subscribe_request:merge(clusters.DoorLock.attributes.RequirePINforRemoteOperation:subscribe(mock_device)) + subscribe_request:merge(cluster_base.subscribe(mock_device, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) subscribe_request:merge(clusters.DoorLock.events.LockOperation:subscribe(mock_device)) subscribe_request:merge(clusters.DoorLock.events.DoorLockAlarm:subscribe(mock_device)) subscribe_request:merge(clusters.DoorLock.events.LockUserChange:subscribe(mock_device)) diff --git a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_modular.lua b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_modular.lua index 8add29c13e..cb22abdf7d 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_modular.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_modular.lua @@ -1,13 +1,12 @@ -- Copyright 2025 SmartThings, Inc. -- Licensed under the Apache License, Version 2.0 - local test = require "integration_test" local capabilities = require "st.capabilities" local clusters = require "st.matter.clusters" local t_utils = require "integration_test.utils" local uint32 = require "st.matter.data_types.Uint32" - +local cluster_base = require "st.matter.cluster_base" local DoorLock = clusters.DoorLock local mock_device = test.mock_device.build_test_matter_device({ @@ -200,12 +199,13 @@ local mock_device_modular = test.mock_device.build_test_matter_device({ } }) - +local DoorLockFeatureMapAttr = {ID = 0xFFFC, cluster = DoorLock.ID} local function test_init() test.disable_startup_messages() -- subscribe request local subscribe_request = DoorLock.attributes.LockState:subscribe(mock_device) subscribe_request:merge(DoorLock.attributes.OperatingMode:subscribe(mock_device)) + subscribe_request:merge(cluster_base.subscribe(mock_device, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device)) subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device)) @@ -228,9 +228,11 @@ local function test_init_unlatch() -- subscribe request local subscribe_request = DoorLock.attributes.LockState:subscribe(mock_device_unlatch) subscribe_request:merge(DoorLock.attributes.OperatingMode:subscribe(mock_device_unlatch)) + subscribe_request:merge(cluster_base.subscribe(mock_device_unlatch, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_unlatch)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_unlatch)) subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_unlatch)) + -- add test device, handle initial subscribe test.mock_device.add_test_device(mock_device_unlatch) -- actual onboarding flow @@ -254,10 +256,12 @@ local function test_init_user_pin() subscribe_request:merge(DoorLock.attributes.MaxPINCodeLength:subscribe(mock_device_user_pin)) subscribe_request:merge(DoorLock.attributes.MinPINCodeLength:subscribe(mock_device_user_pin)) subscribe_request:merge(DoorLock.attributes.RequirePINforRemoteOperation:subscribe(mock_device_user_pin)) + subscribe_request:merge(cluster_base.subscribe(mock_device_user_pin, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_user_pin)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_user_pin)) subscribe_request:merge(DoorLock.events.LockUserChange:subscribe(mock_device_user_pin)) subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_user_pin)) + -- add test device test.mock_device.add_test_device(mock_device_user_pin) -- actual onboarding flow @@ -283,10 +287,12 @@ local function test_init_user_pin_schedule_unlatch() subscribe_request:merge(DoorLock.attributes.RequirePINforRemoteOperation:subscribe(mock_device_user_pin_schedule_unlatch)) subscribe_request:merge(DoorLock.attributes.NumberOfWeekDaySchedulesSupportedPerUser:subscribe(mock_device_user_pin_schedule_unlatch)) subscribe_request:merge(DoorLock.attributes.NumberOfYearDaySchedulesSupportedPerUser:subscribe(mock_device_user_pin_schedule_unlatch)) + subscribe_request:merge(cluster_base.subscribe(mock_device_user_pin_schedule_unlatch, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_user_pin_schedule_unlatch)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_user_pin_schedule_unlatch)) subscribe_request:merge(DoorLock.events.LockUserChange:subscribe(mock_device_user_pin_schedule_unlatch)) subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_user_pin_schedule_unlatch)) + -- add test device test.mock_device.add_test_device(mock_device_user_pin_schedule_unlatch) -- actual onboarding flow @@ -305,9 +311,11 @@ local function test_init_modular() -- subscribe request local subscribe_request = DoorLock.attributes.LockState:subscribe(mock_device_modular) subscribe_request:merge(DoorLock.attributes.OperatingMode:subscribe(mock_device_modular)) + subscribe_request:merge(cluster_base.subscribe(mock_device_modular, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_modular)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_modular)) subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_modular)) + -- add test device test.mock_device.add_test_device(mock_device_modular) -- actual onboarding flow @@ -323,39 +331,6 @@ end test.set_test_init_function(test_init) -test.register_coroutine_test( - "Test lock profile change when attributes related to BAT feature is not available.", - function() - test.socket.matter:__queue_receive( - { - mock_device.id, - clusters.PowerSource.attributes.AttributeList:build_test_report_data(mock_device, 1, - { - uint32(0), - uint32(1), - uint32(2), - uint32(31), - uint32(65528), - uint32(65529), - uint32(65531), - uint32(65532), - uint32(65533), - }) - } - ) - test.socket.capability:__expect_send( - mock_device:generate_test_message("main", capabilities.lock.supportedLockValues({"locked", "unlocked", "not fully locked"}, {visibility = {displayed = false}})) - ) - test.socket.capability:__expect_send( - mock_device:generate_test_message("main", capabilities.lock.supportedLockCommands({"lock", "unlock"}, {visibility = {displayed = false}})) - ) - mock_device:expect_metadata_update({ profile = "lock-modular", optional_component_capabilities = {{"main", {}}} }) - end, - { - min_api_version = 19 - } -) - test.register_coroutine_test( "Test modular lock profile change when BatChargeLevel attribute is available", function() @@ -425,40 +400,6 @@ test.register_coroutine_test( } ) -test.register_coroutine_test( - "Test modular lock profile change with unlatch when attributes related to BAT feature is not available.", - function() - test.socket.matter:__queue_receive( - { - mock_device_unlatch.id, - clusters.PowerSource.attributes.AttributeList:build_test_report_data(mock_device_unlatch, 1, - { - uint32(0), - uint32(1), - uint32(2), - uint32(31), - uint32(65528), - uint32(65529), - uint32(65531), - uint32(65532), - uint32(65533), - }) - } - ) - test.socket.capability:__expect_send( - mock_device_unlatch:generate_test_message("main", capabilities.lock.supportedLockValues({"locked", "unlocked", "unlatched", "not fully locked"}, {visibility = {displayed = false}})) - ) - test.socket.capability:__expect_send( - mock_device_unlatch:generate_test_message("main", capabilities.lock.supportedLockCommands({"lock", "unlock", "unlatch"}, {visibility = {displayed = false}})) - ) - mock_device_unlatch:expect_metadata_update({ profile = "lock-modular-embedded-unlatch", optional_component_capabilities = {{"main", {}}} }) - end, - { - test_init = test_init_unlatch, - min_api_version = 19 - } -) - test.register_coroutine_test( "Test lock-unlatch profile change with unlatch when BatChargeLevel attribute is available", function() @@ -661,11 +602,13 @@ test.register_coroutine_test( subscribe_request:merge(DoorLock.attributes.RequirePINforRemoteOperation:subscribe(mock_device_modular)) subscribe_request:merge(DoorLock.attributes.NumberOfWeekDaySchedulesSupportedPerUser:subscribe(mock_device_modular)) subscribe_request:merge(DoorLock.attributes.NumberOfYearDaySchedulesSupportedPerUser:subscribe(mock_device_modular)) + subscribe_request:merge(cluster_base.subscribe(mock_device_modular, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_modular)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_modular)) subscribe_request:merge(DoorLock.events.LockUserChange:subscribe(mock_device_modular)) subscribe_request:merge(clusters.PowerSource.attributes.BatPercentRemaining:subscribe(mock_device_modular)) subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_modular)) + test.socket.matter:__expect_send({mock_device_modular.id, subscribe_request}) test.socket.capability:__expect_send( mock_device_modular:generate_test_message("main", capabilities.lockAlarm.alarm.clear({state_change = true})) diff --git a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_unlatch.lua b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_unlatch.lua index 9c1d6bb3a8..f040c2b26e 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_unlatch.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_unlatch.lua @@ -7,6 +7,7 @@ test.set_rpc_version(0) local capabilities = require "st.capabilities" local t_utils = require "integration_test.utils" local clusters = require "st.matter.clusters" +local cluster_base = require "st.matter.cluster_base" local DoorLock = clusters.DoorLock local types = DoorLock.types @@ -43,11 +44,13 @@ local mock_device = test.mock_device.build_test_matter_device({ } }) +local DoorLockFeatureMapAttr = {ID = 0xFFFC, cluster = DoorLock.ID} local function test_init() test.disable_startup_messages() -- subscribe_request local subscribe_request = DoorLock.attributes.LockState:subscribe(mock_device) subscribe_request:merge(DoorLock.attributes.OperatingMode:subscribe(mock_device)) + subscribe_request:merge(cluster_base.subscribe(mock_device, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device)) -- add test device, handle initial subscribe diff --git a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua index 3e59163ef5..3154e18cbd 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua @@ -7,6 +7,7 @@ test.set_rpc_version(0) local capabilities = require "st.capabilities" local t_utils = require "integration_test.utils" local clusters = require "st.matter.clusters" +local cluster_base = require "st.matter.cluster_base" local DoorLock = clusters.DoorLock local types = DoorLock.types local lock_utils = require "lock_utils" @@ -44,6 +45,7 @@ local mock_device = test.mock_device.build_test_matter_device({ } }) +local DoorLockFeatureMapAttr = {ID = 0xFFFC, cluster = DoorLock.ID} local function test_init() test.disable_startup_messages() -- subscribe request @@ -56,6 +58,7 @@ local function test_init() subscribe_request:merge(DoorLock.attributes.RequirePINforRemoteOperation:subscribe(mock_device)) subscribe_request:merge(DoorLock.attributes.NumberOfWeekDaySchedulesSupportedPerUser:subscribe(mock_device)) subscribe_request:merge(DoorLock.attributes.NumberOfYearDaySchedulesSupportedPerUser:subscribe(mock_device)) + subscribe_request:merge(cluster_base.subscribe(mock_device, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device)) subscribe_request:merge(DoorLock.events.LockUserChange:subscribe(mock_device)) diff --git a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_aliro.lua b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_aliro.lua new file mode 100644 index 0000000000..04d051b93e --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_aliro.lua @@ -0,0 +1,682 @@ +-- 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 capabilities = require "st.capabilities" +local t_utils = require "integration_test.utils" +local clusters = require "st.matter.clusters" +local cluster_base = require "st.matter.cluster_base" +local DoorLock = clusters.DoorLock +local OctetString1 = require "st.matter.data_types.OctetString1" + +local enabled_optional_component_capability_pairs = {{ + "main", + { + capabilities.lockUsers.ID, + capabilities.lockSchedules.ID, + capabilities.lockAliro.ID + } +}} +local mock_device = test.mock_device.build_test_matter_device({ + profile = t_utils.get_profile_definition( + "lock-modular.yml", + {enabled_optional_capabilities = enabled_optional_component_capability_pairs} + ), + manufacturer_info = { + vendor_id = 0x135D, + product_id = 0x00C1, + }, + endpoints = { + { + endpoint_id = 0, + clusters = { + { cluster_id = clusters.BasicInformation.ID, cluster_type = "SERVER" }, + }, + device_types = { + { device_type_id = 0x0016, device_type_revision = 1 } -- RootNode + } + }, + { + endpoint_id = 1, + clusters = { + { + cluster_id = DoorLock.ID, + cluster_type = "SERVER", + cluster_revision = 1, + feature_map = 0x2510, -- WDSCH & YDSCH & USR & ALIRO + } + }, + device_types = { + { device_type_id = 0x000A, device_type_revision = 1 } -- Door Lock + } + } + } +}) + +local DoorLockFeatureMapAttr = {ID = 0xFFFC, cluster = DoorLock.ID} +local function test_init() + test.disable_startup_messages() + test.mock_device.add_test_device(mock_device) + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" }) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lockAlarm.alarm.clear({state_change = true})) + ) + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "init" }) + local subscribe_request = DoorLock.attributes.LockState:subscribe(mock_device) + subscribe_request:merge(DoorLock.attributes.OperatingMode:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.NumberOfTotalUsersSupported:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.NumberOfWeekDaySchedulesSupportedPerUser:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.NumberOfYearDaySchedulesSupportedPerUser:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.AliroReaderVerificationKey:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.AliroReaderGroupIdentifier:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.AliroReaderGroupSubIdentifier:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.AliroExpeditedTransactionSupportedProtocolVersions:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.AliroGroupResolvingKey:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.AliroSupportedBLEUWBProtocolVersions:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.AliroBLEAdvertisingVersion:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.NumberOfAliroCredentialIssuerKeysSupported:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.NumberOfAliroEndpointKeysSupported:subscribe(mock_device)) + subscribe_request:merge(cluster_base.subscribe(mock_device, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) + subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device)) + subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device)) + subscribe_request:merge(DoorLock.events.LockUserChange:subscribe(mock_device)) + test.socket["matter"]:__expect_send({mock_device.id, subscribe_request}) + + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lock.supportedLockValues({"locked", "unlocked", "not fully locked"}, {visibility = {displayed = false}})) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lock.supportedLockCommands({"lock", "unlock"}, {visibility = {displayed = false}})) + ) + mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) +end + +test.set_test_init_function(test_init) + +test.register_coroutine_test( + "Handle received AliroReaderVerificationKey from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.AliroReaderVerificationKey:build_test_report_data( + mock_device, 1, + "\x04\xA9\xCB\xE4\x18\xEB\x09\x66\x16\x43\xE2\xA4\xA8\x46\xB8\xED\xFE\x27\x86\x98\x30\x2E\x9F\xB4\x3E\x9B\xFF\xD3\xE3\x10\xCC\x2C\x2C\x7F\xF4\x02\xE0\x6E\x40\xEA\x3C\xE1\x29\x43\x52\x73\x36\x68\x3F\xC5\xB1\xCB\x0C\x6A\x7C\x3F\x0B\x5A\xFF\x78\x35\xDF\x21\xC6\x24" + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.readerVerificationKey( + "04a9cbe418eb09661643e2a4a846b8edfe278698302e9fb43e9bffd3e310cc2c2c7ff402e06e40ea3ce12943527336683fc5b1cb0c6a7c3f0b5aff7835df21c624", + {visibility = {displayed = false}}) + ) + ) + end +) + +test.register_coroutine_test( + "Handle received AliroReaderGroupIdentifier from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.AliroReaderGroupIdentifier:build_test_report_data( + mock_device, 1, + "\xE2\x4F\x1B\x20\x5B\xA9\x23\xB3\x2C\xD1\x3D\xC0\x09\xE9\x93\xA8" + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.readerGroupIdentifier( + "e24f1b205ba923b32cd13dc009e993a8", + {visibility = {displayed = false}}) + ) + ) + end +) + +test.register_coroutine_test( + "Handle received AliroExpeditedTransactionSupportedProtocolVersions from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.AliroExpeditedTransactionSupportedProtocolVersions:build_test_report_data( + mock_device, 1, + {OctetString1("\x00\x09"), OctetString1("\x01\x00")} + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.expeditedTransactionProtocolVersions( + {"0.9", "1.0"}, + {visibility = {displayed = false}}) + ) + ) + end +) + +test.register_coroutine_test( + "Handle received AliroSupportedBLEUWBProtocolVersions from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.AliroSupportedBLEUWBProtocolVersions:build_test_report_data( + mock_device, 1, + {OctetString1("\x00\x09"), OctetString1("\x01\x00")} + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.bleUWBProtocolVersions( + {"0.9", "1.0"}, + {visibility = {displayed = false}}) + ) + ) + end +) + +test.register_coroutine_test( + "Handle received AliroReaderVerificationKey from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.NumberOfAliroCredentialIssuerKeysSupported:build_test_report_data( + mock_device, 1, + 35 + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.maxCredentialIssuerKeys( + 35, + {visibility = {displayed = false}}) + ) + ) + end +) + +test.register_coroutine_test( + "Handle received AliroGroupResolvingKey from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.AliroGroupResolvingKey:build_test_report_data( + mock_device, 1, + "\xE2\x4F\x1B\x20\x5B\xA9\x23\xB3\x2C\xD1\x3D\xC0\x09\xE9\x93\xA8" + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.groupResolvingKey( + "e24f1b205ba923b32cd13dc009e993a8", + {visibility = {displayed = false}}) + ) + ) + end +) + +test.register_coroutine_test( + "Handle received AliroBLEAdvertisingVersion from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.AliroBLEAdvertisingVersion:build_test_report_data( + mock_device, 1, + 1 + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.bleAdvertisingVersion( + "1", + {visibility = {displayed = false}}) + ) + ) + end +) + +test.register_coroutine_test( + "Handle received NumberOfAliroEndpointKeysSupported from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.NumberOfAliroEndpointKeysSupported:build_test_report_data( + mock_device, 1, + 10 + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.maxEndpointKeys( + 10, + {visibility = {displayed = false}}) + ) + ) + end +) + +test.register_coroutine_test( + "Handle Set Card Id command received from SmartThings.", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockAliro.ID, + command = "setCardId", + args = {"3icub18c8pr00"} + }, + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.cardId("3icub18c8pr00", {visibility = {displayed = false}}) + ) + ) + end +) + +test.register_coroutine_test( + "Handle Set Reader Config command received from SmartThings.", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockAliro.ID, + command = "setReaderConfig", + args = { + "1a748a78566aaee985d9141730fa72bd83bf34e7b93072a0ca7b56a79b6debac", + "041a748a78566aaee985d9141730fa72bd83bf34e7b93072a0ca7b56a79b6debac9493eded05a65701b5148517bd49a6c91c78ed6811543491eff1d257280ed809", + "e24f1b205ba923b32cd13dc009e993a8", + nil + } + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetAliroReaderConfig( + mock_device, 1, -- endpoint + "\x1A\x74\x8A\x78\x56\x6A\xAE\xE9\x85\xD9\x14\x17\x30\xFA\x72\xBD\x83\xBF\x34\xE7\xB9\x30\x72\xA0\xCA\x7B\x56\xA7\x9B\x6D\xEB\xAC", + "\x04\x1A\x74\x8A\x78\x56\x6A\xAE\xE9\x85\xD9\x14\x17\x30\xFA\x72\xBD\x83\xBF\x34\xE7\xB9\x30\x72\xA0\xCA\x7B\x56\xA7\x9B\x6D\xEB\xAC\x94\x93\xED\xED\x05\xA6\x57\x01\xB5\x14\x85\x17\xBD\x49\xA6\xC9\x1C\x78\xED\x68\x11\x54\x34\x91\xEF\xF1\xD2\x57\x28\x0E\xD8\x09", + "\xE2\x4F\x1B\x20\x5B\xA9\x23\xB3\x2C\xD1\x3D\xC0\x09\xE9\x93\xA8", + nil + ), + } + ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.server.commands.SetAliroReaderConfig:build_test_command_response( + mock_device, 1, + DoorLock.types.DlStatus.SUCCESS -- status + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.commandResult( + {commandName="setReaderConfig", statusCode="success"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Handle Set Endpoint Key command and Clear Endpoint Key command received from SmartThings.", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockAliro.ID, + command = "setEndpointKey", + args = { + 0, + "vTNt0oPoHvIvwGMHa3AuXE3ZcY+Oocv5KZ+R0yveEag=", + "nonEvictableEndpointKey", + "041a748a78566aaee985d9141730fa72bd83bf34e7b93072a0ca7b56a79b6debac9493eded05a65701b5148517bd49a6c91c78ed6811543491eff1d257280ed809", + "1f3acdf6-8930-45f7-ae3d-f0b47851c3e2" + } + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetCredential( + mock_device, 1, -- endpoint + DoorLock.types.DataOperationTypeEnum.ADD, -- operation_type + DoorLock.types.CredentialStruct( + { + credential_type = DoorLock.types.CredentialTypeEnum.ALIRO_NON_EVICTABLE_ENDPOINT_KEY, + credential_index = 1 + } + ), -- credential + "\x04\x1A\x74\x8A\x78\x56\x6A\xAE\xE9\x85\xD9\x14\x17\x30\xFA\x72\xBD\x83\xBF\x34\xE7\xB9\x30\x72\xA0\xCA\x7B\x56\xA7\x9B\x6D\xEB\xAC\x94\x93\xED\xED\x05\xA6\x57\x01\xB5\x14\x85\x17\xBD\x49\xA6\xC9\x1C\x78\xED\x68\x11\x54\x34\x91\xEF\xF1\xD2\x57\x28\x0E\xD8\x09", -- credential_data + nil, -- user_index + nil, -- user_status + DoorLock.types.DlUserType.UNRESTRICTED_USER -- user_type + ), + } + ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.client.commands.SetCredentialResponse:build_test_command_response( + mock_device, 1, + DoorLock.types.DlStatus.SUCCESS, -- status + 1, -- user_index + 2 -- next_credential_index + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.users( + {{userIndex=1, userType="adminMember"}}, + {visibility={displayed=false}} + ) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.credentials( + {{ + keyId="vTNt0oPoHvIvwGMHa3AuXE3ZcY+Oocv5KZ+R0yveEag=", + keyIndex=1, + keyType="nonEvictableEndpointKey", + userIndex=1 + }}, + {visibility={displayed=false}} + ) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.commandResult( + { + commandName="setEndpointKey", + keyId="vTNt0oPoHvIvwGMHa3AuXE3ZcY+Oocv5KZ+R0yveEag=", + requestId="1f3acdf6-8930-45f7-ae3d-f0b47851c3e2", + statusCode="success", + userIndex=1 + }, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + test.wait_for_events() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockAliro.ID, + command = "clearEndpointKey", + args = {1, "vTNt0oPoHvIvwGMHa3AuXE3ZcY+Oocv5KZ+R0yveEag=", "nonEvictableEndpointKey"} + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.ClearCredential( + mock_device, 1, -- endpoint + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.ALIRO_NON_EVICTABLE_ENDPOINT_KEY, credential_index = 1} + ) + ), + } + ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.server.commands.ClearCredential:build_test_command_response( + mock_device, 1 + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.credentials({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.users({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockSchedules.weekDaySchedules({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockSchedules.yearDaySchedules({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.commandResult( + { + commandName="clearEndpointKey", + keyId="vTNt0oPoHvIvwGMHa3AuXE3ZcY+Oocv5KZ+R0yveEag=", + statusCode="success", + userIndex=1 + }, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Handle Set Issuer Key command and Clear Issuer Key command received from SmartThings.", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockAliro.ID, + command = "setIssuerKey", + args = { + 0, + "041a748a78566aaee985d9141730fa72bd83bf34e7b93072a0ca7b56a79b6debac9493eded05a65701b5148517bd49a6c91c78ed6811543491eff1d257280ed809", + "1f3acdf6-8930-45f7-ae3d-f0b47851c3e2" + } + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetCredential( + mock_device, 1, -- endpoint + DoorLock.types.DataOperationTypeEnum.ADD, -- operation_type + DoorLock.types.CredentialStruct( + { + credential_type = DoorLock.types.CredentialTypeEnum.ALIRO_CREDENTIAL_ISSUER_KEY, + credential_index = 1 + } + ), -- credential + "\x04\x1A\x74\x8A\x78\x56\x6A\xAE\xE9\x85\xD9\x14\x17\x30\xFA\x72\xBD\x83\xBF\x34\xE7\xB9\x30\x72\xA0\xCA\x7B\x56\xA7\x9B\x6D\xEB\xAC\x94\x93\xED\xED\x05\xA6\x57\x01\xB5\x14\x85\x17\xBD\x49\xA6\xC9\x1C\x78\xED\x68\x11\x54\x34\x91\xEF\xF1\xD2\x57\x28\x0E\xD8\x09", -- credential_data + nil, -- user_index + nil, -- user_status + DoorLock.types.DlUserType.UNRESTRICTED_USER -- user_type + ), + } + ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.client.commands.SetCredentialResponse:build_test_command_response( + mock_device, 1, + DoorLock.types.DlStatus.SUCCESS, -- status + 1, -- user_index + 2 -- next_credential_index + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.users( + {{userIndex=1, userType="adminMember"}}, + {visibility={displayed=false}} + ) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.credentials( + {{ + keyIndex=1, + keyType="issuerKey", + userIndex=1 + }}, + {visibility={displayed=false}} + ) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.commandResult( + { + commandName="setIssuerKey", + requestId="1f3acdf6-8930-45f7-ae3d-f0b47851c3e2", + statusCode="success", + userIndex=1 + }, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + test.wait_for_events() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockAliro.ID, + command = "clearIssuerKey", + args = {1, "1f3acdf6-8930-45f7-ae3d-f0b47851c3e2"} + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.ClearCredential( + mock_device, 1, -- endpoint + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.ALIRO_CREDENTIAL_ISSUER_KEY, credential_index = 1} + ) + ), + } + ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.server.commands.ClearCredential:build_test_command_response( + mock_device, 1 + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.credentials({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.users({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockSchedules.weekDaySchedules({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockSchedules.yearDaySchedules({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAliro.commandResult( + { + commandName="clearIssuerKey", + requestId="1f3acdf6-8930-45f7-ae3d-f0b47851c3e2", + statusCode="success", + userIndex=1 + }, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.run_registered_tests() diff --git a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_battery.lua b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_battery.lua index 1d3f18d4fd..64f8944a43 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_battery.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock_battery.lua @@ -1,14 +1,13 @@ -- Copyright 2023 SmartThings, Inc. -- Licensed under the Apache License, Version 2.0 - local test = require "integration_test" test.set_rpc_version(0) local capabilities = require "st.capabilities" local clusters = require "st.matter.clusters" local t_utils = require "integration_test.utils" local uint32 = require "st.matter.data_types.Uint32" - +local cluster_base = require "st.matter.cluster_base" local DoorLock = clusters.DoorLock local mock_device = test.mock_device.build_test_matter_device({ @@ -163,14 +162,17 @@ local mock_device_user_pin_schedule_unlatch = test.mock_device.build_test_matter } }) +local DoorLockFeatureMapAttr = {ID = 0xFFFC, cluster = DoorLock.ID} local function test_init() test.disable_startup_messages() -- subscribe request local subscribe_request = DoorLock.attributes.LockState:subscribe(mock_device) subscribe_request:merge(DoorLock.attributes.OperatingMode:subscribe(mock_device)) + subscribe_request:merge(cluster_base.subscribe(mock_device, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device)) subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device)) + -- add test device, handle initial subscribe test.mock_device.add_test_device(mock_device) test.socket.matter:__expect_send({mock_device.id, subscribe_request}) @@ -190,9 +192,11 @@ local function test_init_unlatch() -- subscribe request local subscribe_request = DoorLock.attributes.LockState:subscribe(mock_device_unlatch) subscribe_request:merge(DoorLock.attributes.OperatingMode:subscribe(mock_device_unlatch)) + subscribe_request:merge(cluster_base.subscribe(mock_device_unlatch, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_unlatch)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_unlatch)) subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_unlatch)) + -- add test device, handle initial subscribe test.mock_device.add_test_device(mock_device_unlatch) test.socket.matter:__expect_send({mock_device_unlatch.id, subscribe_request}) @@ -217,10 +221,12 @@ local function test_init_user_pin() subscribe_request:merge(DoorLock.attributes.MaxPINCodeLength:subscribe(mock_device_user_pin)) subscribe_request:merge(DoorLock.attributes.MinPINCodeLength:subscribe(mock_device_user_pin)) subscribe_request:merge(DoorLock.attributes.RequirePINforRemoteOperation:subscribe(mock_device_user_pin)) + subscribe_request:merge(cluster_base.subscribe(mock_device_user_pin, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_user_pin)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_user_pin)) subscribe_request:merge(DoorLock.events.LockUserChange:subscribe(mock_device_user_pin)) subscribe_request:merge(clusters.PowerSource.attributes.AttributeList:subscribe(mock_device_user_pin)) + -- add test device, handle initial subscribe test.mock_device.add_test_device(mock_device_user_pin) test.socket.matter:__expect_send({mock_device_user_pin.id, subscribe_request}) @@ -247,6 +253,7 @@ local function test_init_user_pin_schedule_unlatch() subscribe_request:merge(DoorLock.attributes.RequirePINforRemoteOperation:subscribe(mock_device_user_pin_schedule_unlatch)) subscribe_request:merge(DoorLock.attributes.NumberOfWeekDaySchedulesSupportedPerUser:subscribe(mock_device_user_pin_schedule_unlatch)) subscribe_request:merge(DoorLock.attributes.NumberOfYearDaySchedulesSupportedPerUser:subscribe(mock_device_user_pin_schedule_unlatch)) + subscribe_request:merge(cluster_base.subscribe(mock_device_user_pin_schedule_unlatch, nil, DoorLockFeatureMapAttr.cluster, DoorLockFeatureMapAttr.ID)) subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device_user_pin_schedule_unlatch)) subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device_user_pin_schedule_unlatch)) subscribe_request:merge(DoorLock.events.LockUserChange:subscribe(mock_device_user_pin_schedule_unlatch)) From 4d16289354d7947bdbc5c1e6aae1593d31a1721c Mon Sep 17 00:00:00 2001 From: Chris Baumler Date: Thu, 16 Apr 2026 11:52:44 -0500 Subject: [PATCH 24/29] WWSTCERT-11013 SMART WIFI MATTER WALL SWITCH 2G (#2905) --- drivers/SmartThings/matter-switch/fingerprints.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/SmartThings/matter-switch/fingerprints.yml b/drivers/SmartThings/matter-switch/fingerprints.yml index 852a67432d..b764c79f2c 100644 --- a/drivers/SmartThings/matter-switch/fingerprints.yml +++ b/drivers/SmartThings/matter-switch/fingerprints.yml @@ -894,6 +894,11 @@ matterManufacturer: vendorId: 0x1189 productId: 0x0633 deviceProfileName: plug-binary + - id: "4489/2193" + deviceLabel: SMART WIFI MATTER WALL SWITCH 2G + vendorId: 0x1189 + productId: 0x0891 + deviceProfileName: switch-binary #Ikea - id: "4476/32768" deviceLabel: BILRESA Scroll Wheel From ec8f1069ee2e54afafffcf5ff6988913a1f68ad6 Mon Sep 17 00:00:00 2001 From: Chris Baumler Date: Fri, 10 Apr 2026 11:48:55 -0500 Subject: [PATCH 25/29] WWSTCERT-10652 ULTRALOQ Matter Door Lock (#2889) --- drivers/SmartThings/matter-lock/fingerprints.yml | 10 ++++++++++ .../matter-lock/src/new-matter-lock/fingerprints.lua | 2 ++ 2 files changed, 12 insertions(+) diff --git a/drivers/SmartThings/matter-lock/fingerprints.yml b/drivers/SmartThings/matter-lock/fingerprints.yml index 29c37dd69c..0c12932a2b 100755 --- a/drivers/SmartThings/matter-lock/fingerprints.yml +++ b/drivers/SmartThings/matter-lock/fingerprints.yml @@ -140,6 +140,16 @@ matterManufacturer: vendorId: 0x147F productId: 0x0008 deviceProfileName: lock-user-pin-battery + - id: "5247/7" + deviceLabel: ULTRALOQ Bolt Pro Smart Matter Door Lock + vendorId: 0x147F + productId: 0x0007 + deviceProfileName: lock-modular + - id: "5247/16" + deviceLabel: ULTRALOQ Latch 5 Pro Smart Matter Door Lock + vendorId: 0x147F + productId: 0x0010 + deviceProfileName: lock-modular #Yale - id: "4125/33040" deviceLabel: Yale Lock with Matter diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/fingerprints.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/fingerprints.lua index ac0352c75a..901c0ea39c 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/fingerprints.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/fingerprints.lua @@ -8,7 +8,9 @@ local NEW_MATTER_LOCK_PRODUCTS = { {0x115f, 0x2804}, -- AQARA, U400 {0x115f, 0x286A}, -- AQARA, U200 US {0x147F, 0x0001}, -- U-tec + {0x147F, 0x0007}, -- ULTRALOQ Bolt Pro Smart Matter Door Lock {0x147F, 0x0008}, -- Ultraloq, Bolt Smart Matter Door Lock + {0x147F, 0x0010}, -- ULTRALOQ Latch 5 Pro Smart Matter Door Lock {0x144F, 0x4002}, -- Yale, Linus Smart Lock L2 {0x101D, 0x8110}, -- Yale, New Lock {0x1533, 0x0001}, -- eufy, E31 From 043462c230e68dff28b80a295cb232a9dcb3f61a Mon Sep 17 00:00:00 2001 From: Chris Baumler Date: Tue, 21 Apr 2026 10:49:50 -0500 Subject: [PATCH 26/29] WWSTCERT-10993 Linkind Smart Ceiling Light (#2901) --- drivers/SmartThings/matter-switch/fingerprints.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/SmartThings/matter-switch/fingerprints.yml b/drivers/SmartThings/matter-switch/fingerprints.yml index b764c79f2c..cc975d0138 100644 --- a/drivers/SmartThings/matter-switch/fingerprints.yml +++ b/drivers/SmartThings/matter-switch/fingerprints.yml @@ -161,6 +161,11 @@ matterManufacturer: vendorId: 0x1396 productId: 0x1076 deviceProfileName: light-color-level + - id: "5014/4245" + deviceLabel: OREiN Matter smart Bathroom Fan + vendorId: 0x1396 + productId: 0x1095 + deviceProfileName: fan-modular - id: "5014/4246" deviceLabel: OREiN Matter smart Bathroom Fan vendorId: 0x1396 @@ -176,6 +181,11 @@ matterManufacturer: vendorId: 0x1396 productId: 0x1077 deviceProfileName: light-color-level + - id: "5014/4273" + deviceLabel: Linkind Smart Ceiling Light + vendorId: 0x1396 + productId: 0x10B1 + deviceProfileName: light-level-colorTemperature #Bosch Smart Home - id: "4617/12310" deviceLabel: Plug Compact [M] From 83332bddd6c3cc9dff88b40237e3aaea693d71f6 Mon Sep 17 00:00:00 2001 From: Chris Baumler Date: Tue, 21 Apr 2026 15:08:29 -0500 Subject: [PATCH 27/29] WWSTCERT-10842 ThirdReality Smart Night Light -T (#2910) --- drivers/SmartThings/matter-switch/fingerprints.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/SmartThings/matter-switch/fingerprints.yml b/drivers/SmartThings/matter-switch/fingerprints.yml index cc975d0138..132f792085 100644 --- a/drivers/SmartThings/matter-switch/fingerprints.yml +++ b/drivers/SmartThings/matter-switch/fingerprints.yml @@ -204,6 +204,11 @@ matterManufacturer: vendorId: 0x1407 productId: 0x1088 deviceProfileName: light-color-level-illuminance-motion-1000K-15000K + - id: "5127/5121" + deviceLabel: ThirdReality Smart Night Light -T + vendorId: 0x1407 + productId: 0x1401 + deviceProfileName: light-color-level-illuminance-motion - id: "5127/4744" deviceLabel: Smart Bridge MZ1 vendorId: 0x1407 From fec645b61bc08625e043cbb616e726f4661b0a8c Mon Sep 17 00:00:00 2001 From: Chris Baumler Date: Tue, 21 Apr 2026 12:53:10 -0500 Subject: [PATCH 28/29] WWSTCERT-11096 Sombra Automated Shades and Blinds (#2912) --- drivers/SmartThings/zigbee-window-treatment/fingerprints.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/SmartThings/zigbee-window-treatment/fingerprints.yml b/drivers/SmartThings/zigbee-window-treatment/fingerprints.yml index c59d96f93f..b2e918746b 100644 --- a/drivers/SmartThings/zigbee-window-treatment/fingerprints.yml +++ b/drivers/SmartThings/zigbee-window-treatment/fingerprints.yml @@ -143,6 +143,11 @@ zigbeeManufacturer: manufacturer: Sombra Shades model: WM25/L-Z deviceProfileName: window-treatment-battery + - id: "Sombra Shades/SS25/L-Z" + deviceLabel: Sombra Automated Shades and Blinds + manufacturer: Sombra Shades + model: SS25/L-Z + deviceProfileName: window-treatment-battery zigbeeGeneric: - id: "genericShade" From 25fbc466ee792eac9ad0a8ae2e8ce6c192a7aea8 Mon Sep 17 00:00:00 2001 From: Chris Baumler Date: Wed, 22 Apr 2026 15:31:35 -0500 Subject: [PATCH 29/29] WWSTCERT-11060 TOFSMYGAA Plug Black/Outdoor (#2911) --- .../matter-switch/fingerprints.yml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/SmartThings/matter-switch/fingerprints.yml b/drivers/SmartThings/matter-switch/fingerprints.yml index 132f792085..623dad6806 100644 --- a/drivers/SmartThings/matter-switch/fingerprints.yml +++ b/drivers/SmartThings/matter-switch/fingerprints.yml @@ -925,6 +925,56 @@ matterManufacturer: vendorId: 0x117C productId: 0x8001 deviceProfileName: ikea-2-button-battery + - id: "4476/36885" + deviceLabel: KAJPLATS E12 WS Globe 800lm + vendorId: 0x117C + productId: 0x9015 + deviceProfileName: light-level-colorTemperature + - id: "4476/36880" + deviceLabel: VARMBLIXT table/wall lamp + vendorId: 0x117C + productId: 0x9010 + deviceProfileName: light-color-level + - id: "4476/36881" + deviceLabel: KAJPLATS E26 450lm + vendorId: 0x117C + productId: 0x9011 + deviceProfileName: light-level-colorTemperature + - id: "4476/36882" + deviceLabel: KAJPLATS E26 1100lm + vendorId: 0x117C + productId: 0x9012 + deviceProfileName: light-level-colorTemperature + - id: "4476/36884" + deviceLabel: KAJPLATS E26 WS 1600lm + vendorId: 0x117C + productId: 0x9014 + deviceProfileName: light-level-colorTemperature + - id: "4476/36886" + deviceLabel: KAJPLATS E26 1100lm CWS + vendorId: 0x117C + productId: 0x9016 + deviceProfileName: light-color-level + - id: "4476/36887" + deviceLabel: KAJPLATS E12 CWS Globe 800lm + vendorId: 0x117C + productId: 0x9017 + deviceProfileName: light-color-level + - id: "4476/36889" + deviceLabel: KAJPLATS E12 WS B38 CL 470lm + vendorId: 0x117C + productId: 0x9019 + deviceProfileName: light-level-colorTemperature + - id: "17526/16534" + deviceLabel: GRILLPLATS plug + vendorId: 0x4476 + productId: 0x4096 + deviceProfileName: plug-power-energy-powerConsumption + - id: "17526/16535" + deviceLabel: TOFSMYGGA + vendorId: 0x4476 + productId: 0x4097 + deviceProfileName: plug-power-energy-powerConsumption #Innovation Matters - id: "4978/1" deviceLabel: M2D Bridge