From c8278e832869a75a4f5f5e4f4e84b024ab03e0f9 Mon Sep 17 00:00:00 2001 From: jack Date: Mon, 26 Jan 2026 17:55:35 +0800 Subject: [PATCH 01/16] ledvance zigbee meter plug driver pull --- .../zigbee-switch/fingerprints.yml | 16 ++--- .../simple-metering-config/fingerprints.lua | 10 +++ .../src/simple-metering-config/init.lua | 68 +++++++++++++++++++ 3 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua create mode 100644 drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua diff --git a/drivers/SmartThings/zigbee-switch/fingerprints.yml b/drivers/SmartThings/zigbee-switch/fingerprints.yml index 3d598372fa..abe73221d6 100644 --- a/drivers/SmartThings/zigbee-switch/fingerprints.yml +++ b/drivers/SmartThings/zigbee-switch/fingerprints.yml @@ -1715,6 +1715,11 @@ zigbeeManufacturer: manufacturer: LEDVANCE model: RT TW deviceProfileName: color-temp-bulb + - id: "LEDVANCE/PLUG COMPACT EU EM T" + deviceLabel: SMART+ ZIGBEE COMPACT OUTDOOR PLUG EU + manufacturer: LEDVANCE + model: PLUG COMPACT EU EM T + deviceProfileName: switch-power-energy - id: "OSRAM/LIGHTIFY Edge-lit flushmount" deviceLabel: SYLVANIA Light manufacturer: OSRAM @@ -2400,22 +2405,11 @@ zigbeeManufacturer: manufacturer: NodOn model: SIN-4-1-21 deviceProfileName: switch-power-energy - #Yanmi - id: "JNL/Y-K003-001" deviceLabel: Yanmi Switch (3 Way) 1 manufacturer: JNL model: Y-K003-001 deviceProfileName: basic-switch - - id: "JNL/Y-K001-001" - deviceLabel: Yanmi Switch (1 Way) - manufacturer: JNL - model: Y-K001-001 - deviceProfileName: basic-switch - - id: "JNL/Y-K002-001" - deviceLabel: Yanmi Switch (2 Way) 1 - manufacturer: JNL - model: Y-K002-001 - deviceProfileName: basic-switch zigbeeGeneric: - id: "genericSwitch" deviceLabel: Zigbee Switch diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua new file mode 100644 index 0000000000..f05e7c7d63 --- /dev/null +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua @@ -0,0 +1,10 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +-- 定义支持该子驱动程序的设备指纹 +-- 这里可以指定特定的制造商和型号 +return { + ["Generic"] = { + ["SimpleMeteringDevice"] = true + } +} \ No newline at end of file diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua new file mode 100644 index 0000000000..fc3aca3367 --- /dev/null +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua @@ -0,0 +1,68 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local capabilities = require "st.capabilities" +local zigbee_constants = require "st.zigbee.constants" +local SimpleMetering = require "st.zigbee.cluster".clusters.SimpleMetering +local zigbee_handlers = require "st.zigbee.handlers" + +-- 设置 Simple Metering 集群的 multipliers 和 divisors 属性 +local function device_init(driver, device) + -- 在设备初始化时设置 multipliers 和 divisors + device:configure() + + -- 设置 Multiplier 为 1 + local write_multiplier_cmd = SimpleMetering.server.commands.WriteAttributes(device) + if write_multiplier_cmd then + device:send_to_component( + write_multiplier_cmd({ + {id = SimpleMetering.attributes.Multiplier.ID, value = 1, DataType = 0x22} -- 0x22 is 24-bit integer + }), + "main" + ) + end + + -- 设置 Divisor 为 100 + local write_divisor_cmd = SimpleMetering.server.commands.WriteAttributes(device) + if write_divisor_cmd then + device:send_to_component( + write_divisor_cmd({ + {id = SimpleMetering.attributes.Divisor.ID, value = 100, DataType = 0x23} -- 0x23 is 32-bit integer + }), + "main" + ) + end +end + +-- 处理能量计量事件 +local function energy_meter_handler(driver, device, value, zb_rx) + local raw_value = value.value + local divisor = device:get_field(SimpleMetering.attributes.Divisor.ID) or 100 + local multiplier = device:get_field(SimpleMetering.attributes.Multiplier.ID) or 1 + + local calculated_value = (raw_value * multiplier) / divisor + device:emit_event_for_endpoint( + zb_rx.address_header.src_endpoint.value, + capabilities.energyMeter.energy({value = calculated_value, unit = "kWh"}) + ) +end + +-- 定义子驱动程序模板 +local simple_metering_config_subdriver = { + supported_capabilities = { + capabilities.energyMeter, + capabilities.powerMeter + }, + lifecycle_handlers = { + init = device_init + }, + zigbee_handlers = { + cluster = { + [SimpleMetering.ID] = { + [SimpleMetering.attributes.CurrentSummationDelivered.ID] = energy_meter_handler + } + } + } +} + +return simple_metering_config_subdriver \ No newline at end of file From 316276dd2789563a4a0bbb60301f5e2c2e0d1c8e Mon Sep 17 00:00:00 2001 From: jack Date: Mon, 26 Jan 2026 18:04:08 +0800 Subject: [PATCH 02/16] add the handle file --- .../src/simple-metering-config/can_handle.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua new file mode 100644 index 0000000000..7ad2a4e0a3 --- /dev/null +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua @@ -0,0 +1,14 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local can_handle_simple_metering_config = function(opts, driver, device) + -- 检查设备是否支持 Simple Metering 集群 (0x0702) + for _, cluster in ipairs(device.server_clusters) do + if cluster == 0x0702 then + return true + end + end + return false +end + +return can_handle_simple_metering_config \ No newline at end of file From c01a9d081d9cfaa17dc2ab9a81b385b1b78e7d6a Mon Sep 17 00:00:00 2001 From: jack Date: Fri, 30 Jan 2026 14:04:53 +0800 Subject: [PATCH 03/16] add driver fingerprints --- drivers/SmartThings/zigbee-switch/config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/SmartThings/zigbee-switch/config.yml b/drivers/SmartThings/zigbee-switch/config.yml index 32ad44a36e..242e9e6631 100644 --- a/drivers/SmartThings/zigbee-switch/config.yml +++ b/drivers/SmartThings/zigbee-switch/config.yml @@ -4,3 +4,10 @@ permissions: zigbee: {} description: "SmartThings driver for Zigbee switch devices" vendorSupportInformation: "https://support.smartthings.com" + +fingerprints: + - manufacturer: "LEDVANCE" + model: "PLUG COMPACT EU EM T" + deviceProfileName: "switch-power-energy" + id: "LEDVANCE/PLUG COMPACT EU EM T" + deviceLabel: "SMART+ ZIGBEE COMPACT OUTDOOR PLUG EU" From 5e5a3876a6ba8fda08a07875dc8809ea1ccefc96 Mon Sep 17 00:00:00 2001 From: jack Date: Fri, 30 Jan 2026 15:13:48 +0800 Subject: [PATCH 04/16] modify the ledvance zigbee meter plug device Label --- drivers/SmartThings/zigbee-switch/fingerprints.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/SmartThings/zigbee-switch/fingerprints.yml b/drivers/SmartThings/zigbee-switch/fingerprints.yml index abe73221d6..3c8180e4c0 100644 --- a/drivers/SmartThings/zigbee-switch/fingerprints.yml +++ b/drivers/SmartThings/zigbee-switch/fingerprints.yml @@ -1716,7 +1716,7 @@ zigbeeManufacturer: model: RT TW deviceProfileName: color-temp-bulb - id: "LEDVANCE/PLUG COMPACT EU EM T" - deviceLabel: SMART+ ZIGBEE COMPACT OUTDOOR PLUG EU + deviceLabel: SMART ZIGBEE COMPACT OUTDOOR PLUG EU manufacturer: LEDVANCE model: PLUG COMPACT EU EM T deviceProfileName: switch-power-energy From 98aafe1eb50aafd2626ad11dd488c23c12fd3071 Mon Sep 17 00:00:00 2001 From: jack Date: Fri, 30 Jan 2026 16:00:40 +0800 Subject: [PATCH 05/16] add driver for PLUG EU EM T --- drivers/SmartThings/zigbee-switch/config.yml | 7 ++++++- drivers/SmartThings/zigbee-switch/fingerprints.yml | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/SmartThings/zigbee-switch/config.yml b/drivers/SmartThings/zigbee-switch/config.yml index 242e9e6631..8737165704 100644 --- a/drivers/SmartThings/zigbee-switch/config.yml +++ b/drivers/SmartThings/zigbee-switch/config.yml @@ -10,4 +10,9 @@ fingerprints: model: "PLUG COMPACT EU EM T" deviceProfileName: "switch-power-energy" id: "LEDVANCE/PLUG COMPACT EU EM T" - deviceLabel: "SMART+ ZIGBEE COMPACT OUTDOOR PLUG EU" + deviceLabel: "SMART ZIGBEE COMPACT OUTDOOR PLUG EU" + - manufacturer: "LEDVANCE" + model: "PLUG EU EM T" + deviceProfileName: "switch-power-energy" + id: "LEDVANCE/PLUG COMPACT EU EM T" + deviceLabel: "SMART ZIGBEE PLUG EU" \ No newline at end of file diff --git a/drivers/SmartThings/zigbee-switch/fingerprints.yml b/drivers/SmartThings/zigbee-switch/fingerprints.yml index 3c8180e4c0..08aee5ad85 100644 --- a/drivers/SmartThings/zigbee-switch/fingerprints.yml +++ b/drivers/SmartThings/zigbee-switch/fingerprints.yml @@ -1719,6 +1719,11 @@ zigbeeManufacturer: deviceLabel: SMART ZIGBEE COMPACT OUTDOOR PLUG EU manufacturer: LEDVANCE model: PLUG COMPACT EU EM T + deviceProfileName: switch-power-energy + - id: "LEDVANCE/PLUG EU EM T" + deviceLabel: SMART ZIGBEE PLUG EU + manufacturer: LEDVANCE + model: PLUG EU EM T deviceProfileName: switch-power-energy - id: "OSRAM/LIGHTIFY Edge-lit flushmount" deviceLabel: SYLVANIA Light From 6a7628385dc7da7d7d4b5a4a8b25b4b765159414 Mon Sep 17 00:00:00 2001 From: jack Date: Fri, 30 Jan 2026 16:08:23 +0800 Subject: [PATCH 06/16] delete the PLUG EU EM T driver --- drivers/SmartThings/zigbee-switch/config.yml | 7 +------ drivers/SmartThings/zigbee-switch/fingerprints.yml | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/SmartThings/zigbee-switch/config.yml b/drivers/SmartThings/zigbee-switch/config.yml index 8737165704..9fd141694f 100644 --- a/drivers/SmartThings/zigbee-switch/config.yml +++ b/drivers/SmartThings/zigbee-switch/config.yml @@ -10,9 +10,4 @@ fingerprints: model: "PLUG COMPACT EU EM T" deviceProfileName: "switch-power-energy" id: "LEDVANCE/PLUG COMPACT EU EM T" - deviceLabel: "SMART ZIGBEE COMPACT OUTDOOR PLUG EU" - - manufacturer: "LEDVANCE" - model: "PLUG EU EM T" - deviceProfileName: "switch-power-energy" - id: "LEDVANCE/PLUG COMPACT EU EM T" - deviceLabel: "SMART ZIGBEE PLUG EU" \ No newline at end of file + deviceLabel: "SMART ZIGBEE COMPACT OUTDOOR PLUG EU" \ No newline at end of file diff --git a/drivers/SmartThings/zigbee-switch/fingerprints.yml b/drivers/SmartThings/zigbee-switch/fingerprints.yml index 08aee5ad85..30d951445f 100644 --- a/drivers/SmartThings/zigbee-switch/fingerprints.yml +++ b/drivers/SmartThings/zigbee-switch/fingerprints.yml @@ -1719,12 +1719,7 @@ zigbeeManufacturer: deviceLabel: SMART ZIGBEE COMPACT OUTDOOR PLUG EU manufacturer: LEDVANCE model: PLUG COMPACT EU EM T - deviceProfileName: switch-power-energy - - id: "LEDVANCE/PLUG EU EM T" - deviceLabel: SMART ZIGBEE PLUG EU - manufacturer: LEDVANCE - model: PLUG EU EM T - deviceProfileName: switch-power-energy + deviceProfileName: switch-power-energy - id: "OSRAM/LIGHTIFY Edge-lit flushmount" deviceLabel: SYLVANIA Light manufacturer: OSRAM From 14de7bafc0796d4d070450661a0a544a67c26866 Mon Sep 17 00:00:00 2001 From: jack Date: Tue, 10 Feb 2026 16:52:17 +0800 Subject: [PATCH 07/16] Update the PLUG COMPACT EU EM T device driver --- drivers/SmartThings/zigbee-switch/config.yml | 7 --- .../zigbee-switch/fingerprints.yml | 11 ++++ .../src/simple-metering-config/can_handle.lua | 8 +-- .../simple-metering-config/fingerprints.lua | 10 ++-- .../src/simple-metering-config/init.lua | 50 +++++-------------- 5 files changed, 31 insertions(+), 55 deletions(-) diff --git a/drivers/SmartThings/zigbee-switch/config.yml b/drivers/SmartThings/zigbee-switch/config.yml index 9fd141694f..32ad44a36e 100644 --- a/drivers/SmartThings/zigbee-switch/config.yml +++ b/drivers/SmartThings/zigbee-switch/config.yml @@ -4,10 +4,3 @@ permissions: zigbee: {} description: "SmartThings driver for Zigbee switch devices" vendorSupportInformation: "https://support.smartthings.com" - -fingerprints: - - manufacturer: "LEDVANCE" - model: "PLUG COMPACT EU EM T" - deviceProfileName: "switch-power-energy" - id: "LEDVANCE/PLUG COMPACT EU EM T" - deviceLabel: "SMART ZIGBEE COMPACT OUTDOOR PLUG EU" \ No newline at end of file diff --git a/drivers/SmartThings/zigbee-switch/fingerprints.yml b/drivers/SmartThings/zigbee-switch/fingerprints.yml index 30d951445f..a55c45d371 100644 --- a/drivers/SmartThings/zigbee-switch/fingerprints.yml +++ b/drivers/SmartThings/zigbee-switch/fingerprints.yml @@ -2405,11 +2405,22 @@ zigbeeManufacturer: manufacturer: NodOn model: SIN-4-1-21 deviceProfileName: switch-power-energy + #Yanmi - id: "JNL/Y-K003-001" deviceLabel: Yanmi Switch (3 Way) 1 manufacturer: JNL model: Y-K003-001 deviceProfileName: basic-switch + - id: "JNL/Y-K001-001" + deviceLabel: Yanmi Switch (1 Way) + manufacturer: JNL + model: Y-K001-001 + deviceProfileName: basic-switch + - id: "JNL/Y-K002-001" + deviceLabel: Yanmi Switch (2 Way) 1 + manufacturer: JNL + model: Y-K002-001 + deviceProfileName: basic-switch zigbeeGeneric: - id: "genericSwitch" deviceLabel: Zigbee Switch diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua index 7ad2a4e0a3..6a7ee71b17 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua @@ -2,13 +2,7 @@ -- Licensed under the Apache License, Version 2.0 local can_handle_simple_metering_config = function(opts, driver, device) - -- 检查设备是否支持 Simple Metering 集群 (0x0702) - for _, cluster in ipairs(device.server_clusters) do - if cluster == 0x0702 then - return true - end - end - return false + return device.fingerprinted == true end return can_handle_simple_metering_config \ No newline at end of file diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua index f05e7c7d63..64f6414810 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua @@ -1,10 +1,12 @@ -- Copyright 2025 SmartThings, Inc. -- Licensed under the Apache License, Version 2.0 --- 定义支持该子驱动程序的设备指纹 --- 这里可以指定特定的制造商和型号 return { - ["Generic"] = { - ["SimpleMeteringDevice"] = true + ["LEDVANCE"] = { + ["PLUG COMPACT EU EM T"] = { + deviceProfileName = "switch-power-energy", + --id = "LEDVANCE/PLUG COMPACT EU EM T", + --deviceLabel = "SMART ZIGBEE COMPACT OUTDOOR PLUG EU" + } } } \ No newline at end of file diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua index fc3aca3367..1c21e3f83c 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua @@ -4,58 +4,34 @@ local capabilities = require "st.capabilities" local zigbee_constants = require "st.zigbee.constants" local SimpleMetering = require "st.zigbee.cluster".clusters.SimpleMetering -local zigbee_handlers = require "st.zigbee.handlers" --- 设置 Simple Metering 集群的 multipliers 和 divisors 属性 -local function device_init(driver, device) - -- 在设备初始化时设置 multipliers 和 divisors - device:configure() - - -- 设置 Multiplier 为 1 - local write_multiplier_cmd = SimpleMetering.server.commands.WriteAttributes(device) - if write_multiplier_cmd then - device:send_to_component( - write_multiplier_cmd({ - {id = SimpleMetering.attributes.Multiplier.ID, value = 1, DataType = 0x22} -- 0x22 is 24-bit integer - }), - "main" - ) +local function energy_meter_handler(driver, device, value, zb_rx) + local raw_value = value.value + + if type(raw_value) ~= "number" or raw_value < 0 then + return end - - -- 设置 Divisor 为 100 - local write_divisor_cmd = SimpleMetering.server.commands.WriteAttributes(device) - if write_divisor_cmd then - device:send_to_component( - write_divisor_cmd({ - {id = SimpleMetering.attributes.Divisor.ID, value = 100, DataType = 0x23} -- 0x23 is 32-bit integer - }), - "main" - ) + + local divisor = device:get_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY) or 100 + local multiplier = device:get_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY) or 1 + + if divisor == 0 then + return end -end --- 处理能量计量事件 -local function energy_meter_handler(driver, device, value, zb_rx) - local raw_value = value.value - local divisor = device:get_field(SimpleMetering.attributes.Divisor.ID) or 100 - local multiplier = device:get_field(SimpleMetering.attributes.Multiplier.ID) or 1 - local calculated_value = (raw_value * multiplier) / divisor + device:emit_event_for_endpoint( zb_rx.address_header.src_endpoint.value, - capabilities.energyMeter.energy({value = calculated_value, unit = "kWh"}) + capabilities.energyMeter.energy({ value = calculated_value, unit = "kWh" }) ) end --- 定义子驱动程序模板 local simple_metering_config_subdriver = { supported_capabilities = { capabilities.energyMeter, capabilities.powerMeter }, - lifecycle_handlers = { - init = device_init - }, zigbee_handlers = { cluster = { [SimpleMetering.ID] = { From 99ce6eac9501cdfb7bd30cf9814e176131ec8d52 Mon Sep 17 00:00:00 2001 From: jack Date: Tue, 3 Mar 2026 13:40:08 +0800 Subject: [PATCH 08/16] set the multiplier and divisor fields in the initial handler --- .../src/simple-metering-config/init.lua | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua index 1c21e3f83c..d88d4c8cb2 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua @@ -4,6 +4,7 @@ local capabilities = require "st.capabilities" local zigbee_constants = require "st.zigbee.constants" local SimpleMetering = require "st.zigbee.cluster".clusters.SimpleMetering +local configurations = require "configurations" local function energy_meter_handler(driver, device, value, zb_rx) local raw_value = value.value @@ -27,18 +28,45 @@ local function energy_meter_handler(driver, device, value, zb_rx) ) end +local function device_init(driver, device) + device:set_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY, 1, {persist = true}) + device:set_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY, 100, {persist = true}) +end + +local function read_metering_attributes(driver, device) + device:send(SimpleMetering.attributes.Multiplier:read(device)) + device:send(SimpleMetering.attributes.Divisor:read(device)) +end + +local function handle_multiplier_response(driver, device, value, zb_rx) + device:set_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY, value.value, {persist = true}) +end + +local function handle_divisor_response(driver, device, value, zb_rx) + device:set_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY, value.value, {persist = true}) +end + local simple_metering_config_subdriver = { + NAME = "Simple Metering Config", supported_capabilities = { capabilities.energyMeter, capabilities.powerMeter }, zigbee_handlers = { - cluster = { + attr = { [SimpleMetering.ID] = { - [SimpleMetering.attributes.CurrentSummationDelivered.ID] = energy_meter_handler + [SimpleMetering.attributes.CurrentSummationDelivered.ID] = energy_meter_handler, + [SimpleMetering.attributes.Multiplier.ID] = handle_multiplier_response, + [SimpleMetering.attributes.Divisor.ID] = handle_divisor_response } } - } + }, + lifecycle_handlers = { + init = configurations.power_reconfig_wrapper(device_init), + added = read_metering_attributes, + doConfigure = read_metering_attributes + }, + can_handle = require("simple-metering-config.can_handle") } return simple_metering_config_subdriver \ No newline at end of file From 22bc75b2045ebeb86ff4f5fdac6440d40514a3a0 Mon Sep 17 00:00:00 2001 From: jack Date: Wed, 4 Mar 2026 11:34:59 +0800 Subject: [PATCH 09/16] disable the rely on the defaults to read the multiplier/divisor and Add driver registration processing --- .../SmartThings/zigbee-switch/src/init.lua | 1 + .../src/simple-metering-config/can_handle.lua | 15 +++++++---- .../simple-metering-config/fingerprints.lua | 8 +----- .../src/simple-metering-config/init.lua | 25 ++++++------------- 4 files changed, 19 insertions(+), 30 deletions(-) diff --git a/drivers/SmartThings/zigbee-switch/src/init.lua b/drivers/SmartThings/zigbee-switch/src/init.lua index 1b694d2a5e..0c3b5d2277 100644 --- a/drivers/SmartThings/zigbee-switch/src/init.lua +++ b/drivers/SmartThings/zigbee-switch/src/init.lua @@ -79,6 +79,7 @@ local zigbee_switch_driver_template = { lazy_load_if_possible("sinope"), lazy_load_if_possible("sinope-dimmer"), lazy_load_if_possible("zigbee-dimmer-power-energy"), + lazy_load_if_possible("simple-metering-config"), lazy_load_if_possible("zigbee-metering-plug-power-consumption-report"), lazy_load_if_possible("jasco"), lazy_load_if_possible("multi-switch-no-master"), diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua index 6a7ee71b17..f7bffb3583 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua @@ -1,8 +1,13 @@ -- Copyright 2025 SmartThings, Inc. -- Licensed under the Apache License, Version 2.0 -local can_handle_simple_metering_config = function(opts, driver, device) - return device.fingerprinted == true -end - -return can_handle_simple_metering_config \ No newline at end of file +return function(opts, driver, device, ...) + local FINGERPRINTS = require("simple-metering-config.fingerprints") + for _, fingerprint in ipairs(FINGERPRINTS) do + if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then + local subdriver = require("simple-metering-config") + return true, subdriver + end + end + return false +end \ No newline at end of file diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua index 64f6414810..9768066449 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua @@ -2,11 +2,5 @@ -- Licensed under the Apache License, Version 2.0 return { - ["LEDVANCE"] = { - ["PLUG COMPACT EU EM T"] = { - deviceProfileName = "switch-power-energy", - --id = "LEDVANCE/PLUG COMPACT EU EM T", - --deviceLabel = "SMART ZIGBEE COMPACT OUTDOOR PLUG EU" - } - } + { mfr = "LEDVANCE", model = "PLUG COMPACT EU EM T" } } \ No newline at end of file diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua index d88d4c8cb2..0d49678852 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua @@ -33,19 +33,6 @@ local function device_init(driver, device) device:set_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY, 100, {persist = true}) end -local function read_metering_attributes(driver, device) - device:send(SimpleMetering.attributes.Multiplier:read(device)) - device:send(SimpleMetering.attributes.Divisor:read(device)) -end - -local function handle_multiplier_response(driver, device, value, zb_rx) - device:set_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY, value.value, {persist = true}) -end - -local function handle_divisor_response(driver, device, value, zb_rx) - device:set_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY, value.value, {persist = true}) -end - local simple_metering_config_subdriver = { NAME = "Simple Metering Config", supported_capabilities = { @@ -56,15 +43,17 @@ local simple_metering_config_subdriver = { attr = { [SimpleMetering.ID] = { [SimpleMetering.attributes.CurrentSummationDelivered.ID] = energy_meter_handler, - [SimpleMetering.attributes.Multiplier.ID] = handle_multiplier_response, - [SimpleMetering.attributes.Divisor.ID] = handle_divisor_response + [SimpleMetering.attributes.Multiplier.ID] = function(driver, device, value, zb_rx) + device:set_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY, value.value, {persist = true}) + end, + [SimpleMetering.attributes.Divisor.ID] = function(driver, device, value, zb_rx) + device:set_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY, value.value, {persist = true}) + end } } }, lifecycle_handlers = { - init = configurations.power_reconfig_wrapper(device_init), - added = read_metering_attributes, - doConfigure = read_metering_attributes + init = configurations.power_reconfig_wrapper(device_init) }, can_handle = require("simple-metering-config.can_handle") } From b81fa6bfc80b71edc6715725c3c6d2a63a85ca58 Mon Sep 17 00:00:00 2001 From: jack Date: Wed, 4 Mar 2026 18:42:13 +0800 Subject: [PATCH 10/16] fixing the init.lua multiplier/divisor handle ,fixing the commit conflict --- .../SmartThings/zigbee-switch/src/init.lua | 35 +---------------- .../src/simple-metering-config/can_handle.lua | 2 +- .../src/simple-metering-config/init.lua | 38 +----------------- .../zigbee-switch/src/sub_drivers.lua | 39 +++++++++++++++++++ 4 files changed, 42 insertions(+), 72 deletions(-) create mode 100644 drivers/SmartThings/zigbee-switch/src/sub_drivers.lua diff --git a/drivers/SmartThings/zigbee-switch/src/init.lua b/drivers/SmartThings/zigbee-switch/src/init.lua index 0c3b5d2277..aa245f5910 100644 --- a/drivers/SmartThings/zigbee-switch/src/init.lua +++ b/drivers/SmartThings/zigbee-switch/src/init.lua @@ -54,8 +54,6 @@ local device_init = function(driver, device) end end -local lazy_load_if_possible = require "lazy_load_subdriver" - local zigbee_switch_driver_template = { supported_capabilities = { capabilities.switch, @@ -69,38 +67,7 @@ local zigbee_switch_driver_template = { capabilities.relativeHumidityMeasurement, capabilities.temperatureMeasurement, }, - sub_drivers = { - lazy_load_if_possible("non_zigbee_devices"), - lazy_load_if_possible("hanssem"), - lazy_load_if_possible("aqara"), - lazy_load_if_possible("aqara-light"), - lazy_load_if_possible("ezex"), - lazy_load_if_possible("rexense"), - lazy_load_if_possible("sinope"), - lazy_load_if_possible("sinope-dimmer"), - lazy_load_if_possible("zigbee-dimmer-power-energy"), - lazy_load_if_possible("simple-metering-config"), - lazy_load_if_possible("zigbee-metering-plug-power-consumption-report"), - lazy_load_if_possible("jasco"), - lazy_load_if_possible("multi-switch-no-master"), - lazy_load_if_possible("zigbee-dual-metering-switch"), - lazy_load_if_possible("rgb-bulb"), - lazy_load_if_possible("zigbee-dimming-light"), - lazy_load_if_possible("white-color-temp-bulb"), - lazy_load_if_possible("rgbw-bulb"), - (version.api < 16) and lazy_load_if_possible("zll-dimmer-bulb") or nil, - lazy_load_if_possible("ikea-xy-color-bulb"), - lazy_load_if_possible("zll-polling"), - lazy_load_if_possible("zigbee-switch-power"), - lazy_load_if_possible("ge-link-bulb"), - lazy_load_if_possible("bad_on_off_data_type"), - lazy_load_if_possible("robb"), - lazy_load_if_possible("wallhero"), - lazy_load_if_possible("inovelli"), -- Combined driver for both VZM31-SN and VZM32-SN - lazy_load_if_possible("laisiao"), - lazy_load_if_possible("tuya-multi"), - lazy_load_if_possible("frient") - }, + sub_drivers = require("sub_drivers"), zigbee_handlers = { global = { [SIMPLE_METERING_ID] = { diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua index f7bffb3583..64ff6e1fc5 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua @@ -1,7 +1,7 @@ -- Copyright 2025 SmartThings, Inc. -- Licensed under the Apache License, Version 2.0 -return function(opts, driver, device, ...) +return function(opts, driver, device) local FINGERPRINTS = require("simple-metering-config.fingerprints") for _, fingerprint in ipairs(FINGERPRINTS) do if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua index 0d49678852..659e50c3d9 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua @@ -3,31 +3,8 @@ local capabilities = require "st.capabilities" local zigbee_constants = require "st.zigbee.constants" -local SimpleMetering = require "st.zigbee.cluster".clusters.SimpleMetering local configurations = require "configurations" -local function energy_meter_handler(driver, device, value, zb_rx) - local raw_value = value.value - - if type(raw_value) ~= "number" or raw_value < 0 then - return - end - - local divisor = device:get_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY) or 100 - local multiplier = device:get_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY) or 1 - - if divisor == 0 then - return - end - - local calculated_value = (raw_value * multiplier) / divisor - - device:emit_event_for_endpoint( - zb_rx.address_header.src_endpoint.value, - capabilities.energyMeter.energy({ value = calculated_value, unit = "kWh" }) - ) -end - local function device_init(driver, device) device:set_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY, 1, {persist = true}) device:set_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY, 100, {persist = true}) @@ -39,23 +16,10 @@ local simple_metering_config_subdriver = { capabilities.energyMeter, capabilities.powerMeter }, - zigbee_handlers = { - attr = { - [SimpleMetering.ID] = { - [SimpleMetering.attributes.CurrentSummationDelivered.ID] = energy_meter_handler, - [SimpleMetering.attributes.Multiplier.ID] = function(driver, device, value, zb_rx) - device:set_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY, value.value, {persist = true}) - end, - [SimpleMetering.attributes.Divisor.ID] = function(driver, device, value, zb_rx) - device:set_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY, value.value, {persist = true}) - end - } - } - }, lifecycle_handlers = { init = configurations.power_reconfig_wrapper(device_init) }, can_handle = require("simple-metering-config.can_handle") } -return simple_metering_config_subdriver \ No newline at end of file +return simple_metering_config_subdriver diff --git a/drivers/SmartThings/zigbee-switch/src/sub_drivers.lua b/drivers/SmartThings/zigbee-switch/src/sub_drivers.lua new file mode 100644 index 0000000000..b20e534fb4 --- /dev/null +++ b/drivers/SmartThings/zigbee-switch/src/sub_drivers.lua @@ -0,0 +1,39 @@ +-- Copyright 2026 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 +local version = require "version" + +local lazy_load_if_possible = require "lazy_load_subdriver" + +return { + lazy_load_if_possible("non_zigbee_devices"), + lazy_load_if_possible("hanssem"), + lazy_load_if_possible("aqara"), + lazy_load_if_possible("aqara-light"), + lazy_load_if_possible("ezex"), + lazy_load_if_possible("rexense"), + lazy_load_if_possible("sinope"), + lazy_load_if_possible("sinope-dimmer"), + lazy_load_if_possible("zigbee-dimmer-power-energy"), + lazy_load_if_possible("zigbee-metering-plug-power-consumption-report"), + lazy_load_if_possible("simple-metering-config"), + lazy_load_if_possible("jasco"), + lazy_load_if_possible("multi-switch-no-master"), + lazy_load_if_possible("zigbee-dual-metering-switch"), + lazy_load_if_possible("rgb-bulb"), + lazy_load_if_possible("zigbee-dimming-light"), + lazy_load_if_possible("white-color-temp-bulb"), + lazy_load_if_possible("rgbw-bulb"), + (version.api < 16) and lazy_load_if_possible("zll-dimmer-bulb") or nil, + lazy_load_if_possible("ikea-xy-color-bulb"), + lazy_load_if_possible("zll-polling"), + lazy_load_if_possible("zigbee-switch-power"), + lazy_load_if_possible("ge-link-bulb"), + lazy_load_if_possible("bad_on_off_data_type"), + lazy_load_if_possible("robb"), + lazy_load_if_possible("wallhero"), + lazy_load_if_possible("inovelli"), -- Combined driver for both VZM31-SN and VZM32-SN + lazy_load_if_possible("laisiao"), + lazy_load_if_possible("tuya-multi"), + lazy_load_if_possible("frient"), + lazy_load_if_possible("frient-IO") +} From 328797c61b17ecf67336be185f8b56e7161901c4 Mon Sep 17 00:00:00 2001 From: jack Date: Wed, 4 Mar 2026 19:25:18 +0800 Subject: [PATCH 11/16] update sub driver init.lua files --- check_lua_syntax.ps1 | 81 +++++++++++ .../src/simple-metering-config/can_handle.lua | 2 +- .../src/simple-metering-config/init.lua | 48 +++++- test_can_handle.md | 137 ++++++++++++++++++ 4 files changed, 265 insertions(+), 3 deletions(-) create mode 100644 check_lua_syntax.ps1 create mode 100644 test_can_handle.md diff --git a/check_lua_syntax.ps1 b/check_lua_syntax.ps1 new file mode 100644 index 0000000000..62b1a8fa5a --- /dev/null +++ b/check_lua_syntax.ps1 @@ -0,0 +1,81 @@ +# Lua Syntax Checker for simple-metering-config +$files = @( + "drivers\SmartThings\zigbee-switch\src\simple-metering-config\init.lua", + "drivers\SmartThings\zigbee-switch\src\simple-metering-config\can_handle.lua", + "drivers\SmartThings\zigbee-switch\src\simple-metering-config\fingerprints.lua" +) + +Write-Host "Checking Lua syntax for simple-metering-config files..." -ForegroundColor Cyan +Write-Host "" + +$allOk = $true + +foreach ($file in $files) { + Write-Host "Checking: $file" -ForegroundColor Yellow + + if (-not (Test-Path $file)) { + Write-Host " ERROR: File not found!" -ForegroundColor Red + $allOk = $false + continue + } + + $content = Get-Content $file -Raw -ErrorAction Stop + + # Basic syntax checks + $errors = @() + + # Check for balanced parentheses + $openParens = ([regex]::Matches($content, '\(')).Count + $closeParens = ([regex]::Matches($content, '\)')).Count + if ($openParens -ne $closeParens) { + $errors += "Unbalanced parentheses (open: $openParens, close: $closeParens)" + } + + # Check for balanced braces + $openBraces = ([regex]::Matches($content, '\{')).Count + $closeBraces = ([regex]::Matches($content, '\}')).Count + if ($openBraces -ne $closeBraces) { + $errors += "Unbalanced braces (open: $openBraces, close: $closeBraces)" + } + + # Check for balanced brackets + $openBrackets = ([regex]::Matches($content, '\[')).Count + $closeBrackets = ([regex]::Matches($content, '\]')).Count + if ($openBrackets -ne $closeBrackets) { + $errors += "Unbalanced brackets (open: $openBrackets, close: $closeBrackets)" + } + + # Check for proper 'end' statements + $functions = ([regex]::Matches($content, '\bfunction\b')).Count + $ends = ([regex]::Matches($content, '\bend\b')).Count + if ($functions -ne $ends) { + $errors += "Unbalanced function/end (functions: $functions, ends: $ends)" + } + + # Check for proper 'local' usage (warning only) + $globals = ([regex]::Matches($content, '^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*=')).Count + if ($globals -gt 0) { + Write-Host " WARNING: Found $globals potential global variable assignments" -ForegroundColor Yellow + } + + if ($errors.Count -eq 0) { + Write-Host " OK: Syntax looks good" -ForegroundColor Green + } else { + Write-Host " ERRORS FOUND:" -ForegroundColor Red + foreach ($error in $errors) { + Write-Host " - $error" -ForegroundColor Red + } + $allOk = $false + } + + Write-Host "" +} + +Write-Host "Summary:" -ForegroundColor Cyan +if ($allOk) { + Write-Host " All files passed syntax check!" -ForegroundColor Green + exit 0 +} else { + Write-Host " Some files have syntax errors!" -ForegroundColor Red + exit 1 +} diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua index 64ff6e1fc5..f7bffb3583 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua @@ -1,7 +1,7 @@ -- Copyright 2025 SmartThings, Inc. -- Licensed under the Apache License, Version 2.0 -return function(opts, driver, device) +return function(opts, driver, device, ...) local FINGERPRINTS = require("simple-metering-config.fingerprints") for _, fingerprint in ipairs(FINGERPRINTS) do if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua index 659e50c3d9..1dd009c181 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua @@ -3,23 +3,67 @@ local capabilities = require "st.capabilities" local zigbee_constants = require "st.zigbee.constants" +local SimpleMetering = require "st.zigbee.cluster".clusters.SimpleMetering local configurations = require "configurations" +local function energy_meter_handler(driver, device, value, zb_rx) + local raw_value = value.value + + if type(raw_value) ~= "number" or raw_value < 0 then + return + end + + local divisor = device:get_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY) or 100 + local multiplier = device:get_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY) or 1 + + if divisor == 0 then + return + end + + local calculated_value = (raw_value * multiplier) / divisor + + device:emit_event_for_endpoint( + zb_rx.address_header.src_endpoint.value, + capabilities.energyMeter.energy({ value = calculated_value, unit = "kWh" }) + ) +end + local function device_init(driver, device) device:set_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY, 1, {persist = true}) device:set_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY, 100, {persist = true}) end +local function do_configure(driver, device) + device:configure() + device:refresh() +end + local simple_metering_config_subdriver = { NAME = "Simple Metering Config", supported_capabilities = { capabilities.energyMeter, capabilities.powerMeter }, + zigbee_handlers = { + attr = { + [SimpleMetering.ID] = { + [SimpleMetering.attributes.CurrentSummationDelivered.ID] = energy_meter_handler, + [SimpleMetering.attributes.Multiplier.ID] = function(driver, device, value, zb_rx) + device:set_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY, value.value, {persist = true}) + end, + [SimpleMetering.attributes.Divisor.ID] = function(driver, device, value, zb_rx) + device:set_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY, value.value, {persist = true}) + end + } + } + }, lifecycle_handlers = { - init = configurations.power_reconfig_wrapper(device_init) + init = function(driver, device) + configurations.power_reconfig_wrapper(device_init)(driver, device) + end, + doConfigure = do_configure }, can_handle = require("simple-metering-config.can_handle") } -return simple_metering_config_subdriver +return simple_metering_config_subdriver \ No newline at end of file diff --git a/test_can_handle.md b/test_can_handle.md new file mode 100644 index 0000000000..58ab2e7e4e --- /dev/null +++ b/test_can_handle.md @@ -0,0 +1,137 @@ +# 测试 can_handle.lua 功能验证 + +## 测试场景 + +### 场景 1: 匹配的设备 (LEDVANCE/PLUG COMPACT EU EM T) +**输入**: +- device:get_manufacturer() = "LEDVANCE" +- device:get_model() = "PLUG COMPACT EU EM T" + +**预期输出**: +- 返回:`true, subdriver` +- 结果:✅ can_handle 返回 true,加载子驱动 + +### 场景 2: 不匹配的设备 +**输入**: +- device:get_manufacturer() = "Other Manufacturer" +- device:get_model() = "Other Model" + +**预期输出**: +- 返回:`false` +- 结果:✅ can_handle 返回 false,不使用此子驱动 + +## 代码逻辑验证 + +### fingerprints.lua +```lua +return { + { mfr = "LEDVANCE", model = "PLUG COMPACT EU EM T" } +} +``` +✅ **格式正确** - 使用数组格式,与其他子驱动一致 + +### can_handle.lua +```lua +return function(opts, driver, device, ...) + local FINGERPRINTS = require("simple-metering-config.fingerprints") + for _, fingerprint in ipairs(FINGERPRINTS) do + if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then + local subdriver = require("simple-metering-config") + return true, subdriver + end + end + return false +end +``` +✅ **逻辑正确** - 遍历 fingerprints,匹配 manufacturer 和 model +✅ **返回值正确** - 匹配时返回 `true, subdriver`,不匹配时返回 `false` + +## 与其他子驱动对比 + +| 子驱动 | fingerprints 格式 | can_handle 逻辑 | 状态 | +|--------|------------------|----------------|------| +| wallhero | 数组格式 | `ipairs` 遍历 | ✅ | +| hanssem | 数组格式 | `ipairs` 遍历 | ✅ | +| multi-switch-no-master | 数组格式 | `ipairs` 遍历 | ✅ | +| zigbee-switch-power | 数组格式 | `ipairs` 遍历 | ✅ | +| **simple-metering-config** | **数组格式** | **`ipairs` 遍历** | ✅ **已修复** | + +## 修复内容总结 + +### 修复前 ❌ +**fingerprints.lua**: +```lua +return { + ["LEDVANCE"] = { + ["PLUG COMPACT EU EM T"] = { + deviceProfileName = "switch-power-energy", + } + } +} +``` +- ❌ 使用嵌套表格式(与其他子驱动不一致) +- ❌ can_handle 使用 `pairs` 遍历嵌套表 + +**can_handle.lua**: +```lua +local fingerprints = require("simple-metering-config.fingerprints") +for mfr, models in pairs(fingerprints) do + for model, fingerprint in pairs(models) do + if device:get_manufacturer() == mfr and device:get_model() == model then + return true -- 缺少 subdriver + end + end +end +``` + +### 修复后 ✅ +**fingerprints.lua**: +```lua +return { + { mfr = "LEDVANCE", model = "PLUG COMPACT EU EM T" } +} +``` +- ✅ 使用数组格式(与其他子驱动一致) +- ✅ 简化结构,只包含必要信息 + +**can_handle.lua**: +```lua +local FINGERPRINTS = require("simple-metering-config.fingerprints") +for _, fingerprint in ipairs(FINGERPRINTS) do + if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then + local subdriver = require("simple-metering-config") + return true, subdriver + end +end +return false +``` +- ✅ 使用 `ipairs` 遍历(与其他子驱动一致) +- ✅ 返回 `true, subdriver`(与其他子驱动一致) + +## 验证结果 + +### ✅ 语法检查 +- fingerprints.lua: ✅ 语法正确 +- can_handle.lua: ✅ 语法正确 + +### ✅ 格式一致性 +- 与 wallhero 一致: ✅ +- 与 hanssem 一致: ✅ +- 与 multi-switch-no-master 一致: ✅ +- 与 zigbee-switch-power 一致: ✅ + +### ✅ 功能完整性 +- 正确匹配设备: ✅ +- 正确返回 subdriver: ✅ +- 正确返回 false: ✅ + +## 结论 + +✅ **can_handle.lua 现在完全正确并起作用** + +**修复的问题**: +1. ✅ fingerprints 格式改为数组格式(与其他子驱动一致) +2. ✅ can_handle 使用 `ipairs` 遍历(与其他子驱动一致) +3. ✅ 返回值包含 subdriver(与其他子驱动一致) + +**可以提交给 SmartThings**! From 5004c958768d9d533c8659fb7a8a393005cb17fe Mon Sep 17 00:00:00 2001 From: jack Date: Thu, 5 Mar 2026 17:32:12 +0800 Subject: [PATCH 12/16] Remove unnecessary files --- .gitignore | 2 + check_lua_syntax.ps1 | 81 ------------------------- test_can_handle.md | 137 ------------------------------------------- 3 files changed, 2 insertions(+), 218 deletions(-) delete mode 100644 check_lua_syntax.ps1 delete mode 100644 test_can_handle.md diff --git a/.gitignore b/.gitignore index 72da442d81..9aeae9c9c9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ tools/coverage_output_html/ tools/__pycache__/ .DS_Store .venv/ +/test_can_handle.md +/check_lua_syntax.ps1 diff --git a/check_lua_syntax.ps1 b/check_lua_syntax.ps1 deleted file mode 100644 index 62b1a8fa5a..0000000000 --- a/check_lua_syntax.ps1 +++ /dev/null @@ -1,81 +0,0 @@ -# Lua Syntax Checker for simple-metering-config -$files = @( - "drivers\SmartThings\zigbee-switch\src\simple-metering-config\init.lua", - "drivers\SmartThings\zigbee-switch\src\simple-metering-config\can_handle.lua", - "drivers\SmartThings\zigbee-switch\src\simple-metering-config\fingerprints.lua" -) - -Write-Host "Checking Lua syntax for simple-metering-config files..." -ForegroundColor Cyan -Write-Host "" - -$allOk = $true - -foreach ($file in $files) { - Write-Host "Checking: $file" -ForegroundColor Yellow - - if (-not (Test-Path $file)) { - Write-Host " ERROR: File not found!" -ForegroundColor Red - $allOk = $false - continue - } - - $content = Get-Content $file -Raw -ErrorAction Stop - - # Basic syntax checks - $errors = @() - - # Check for balanced parentheses - $openParens = ([regex]::Matches($content, '\(')).Count - $closeParens = ([regex]::Matches($content, '\)')).Count - if ($openParens -ne $closeParens) { - $errors += "Unbalanced parentheses (open: $openParens, close: $closeParens)" - } - - # Check for balanced braces - $openBraces = ([regex]::Matches($content, '\{')).Count - $closeBraces = ([regex]::Matches($content, '\}')).Count - if ($openBraces -ne $closeBraces) { - $errors += "Unbalanced braces (open: $openBraces, close: $closeBraces)" - } - - # Check for balanced brackets - $openBrackets = ([regex]::Matches($content, '\[')).Count - $closeBrackets = ([regex]::Matches($content, '\]')).Count - if ($openBrackets -ne $closeBrackets) { - $errors += "Unbalanced brackets (open: $openBrackets, close: $closeBrackets)" - } - - # Check for proper 'end' statements - $functions = ([regex]::Matches($content, '\bfunction\b')).Count - $ends = ([regex]::Matches($content, '\bend\b')).Count - if ($functions -ne $ends) { - $errors += "Unbalanced function/end (functions: $functions, ends: $ends)" - } - - # Check for proper 'local' usage (warning only) - $globals = ([regex]::Matches($content, '^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*=')).Count - if ($globals -gt 0) { - Write-Host " WARNING: Found $globals potential global variable assignments" -ForegroundColor Yellow - } - - if ($errors.Count -eq 0) { - Write-Host " OK: Syntax looks good" -ForegroundColor Green - } else { - Write-Host " ERRORS FOUND:" -ForegroundColor Red - foreach ($error in $errors) { - Write-Host " - $error" -ForegroundColor Red - } - $allOk = $false - } - - Write-Host "" -} - -Write-Host "Summary:" -ForegroundColor Cyan -if ($allOk) { - Write-Host " All files passed syntax check!" -ForegroundColor Green - exit 0 -} else { - Write-Host " Some files have syntax errors!" -ForegroundColor Red - exit 1 -} diff --git a/test_can_handle.md b/test_can_handle.md deleted file mode 100644 index 58ab2e7e4e..0000000000 --- a/test_can_handle.md +++ /dev/null @@ -1,137 +0,0 @@ -# 测试 can_handle.lua 功能验证 - -## 测试场景 - -### 场景 1: 匹配的设备 (LEDVANCE/PLUG COMPACT EU EM T) -**输入**: -- device:get_manufacturer() = "LEDVANCE" -- device:get_model() = "PLUG COMPACT EU EM T" - -**预期输出**: -- 返回:`true, subdriver` -- 结果:✅ can_handle 返回 true,加载子驱动 - -### 场景 2: 不匹配的设备 -**输入**: -- device:get_manufacturer() = "Other Manufacturer" -- device:get_model() = "Other Model" - -**预期输出**: -- 返回:`false` -- 结果:✅ can_handle 返回 false,不使用此子驱动 - -## 代码逻辑验证 - -### fingerprints.lua -```lua -return { - { mfr = "LEDVANCE", model = "PLUG COMPACT EU EM T" } -} -``` -✅ **格式正确** - 使用数组格式,与其他子驱动一致 - -### can_handle.lua -```lua -return function(opts, driver, device, ...) - local FINGERPRINTS = require("simple-metering-config.fingerprints") - for _, fingerprint in ipairs(FINGERPRINTS) do - if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then - local subdriver = require("simple-metering-config") - return true, subdriver - end - end - return false -end -``` -✅ **逻辑正确** - 遍历 fingerprints,匹配 manufacturer 和 model -✅ **返回值正确** - 匹配时返回 `true, subdriver`,不匹配时返回 `false` - -## 与其他子驱动对比 - -| 子驱动 | fingerprints 格式 | can_handle 逻辑 | 状态 | -|--------|------------------|----------------|------| -| wallhero | 数组格式 | `ipairs` 遍历 | ✅ | -| hanssem | 数组格式 | `ipairs` 遍历 | ✅ | -| multi-switch-no-master | 数组格式 | `ipairs` 遍历 | ✅ | -| zigbee-switch-power | 数组格式 | `ipairs` 遍历 | ✅ | -| **simple-metering-config** | **数组格式** | **`ipairs` 遍历** | ✅ **已修复** | - -## 修复内容总结 - -### 修复前 ❌ -**fingerprints.lua**: -```lua -return { - ["LEDVANCE"] = { - ["PLUG COMPACT EU EM T"] = { - deviceProfileName = "switch-power-energy", - } - } -} -``` -- ❌ 使用嵌套表格式(与其他子驱动不一致) -- ❌ can_handle 使用 `pairs` 遍历嵌套表 - -**can_handle.lua**: -```lua -local fingerprints = require("simple-metering-config.fingerprints") -for mfr, models in pairs(fingerprints) do - for model, fingerprint in pairs(models) do - if device:get_manufacturer() == mfr and device:get_model() == model then - return true -- 缺少 subdriver - end - end -end -``` - -### 修复后 ✅ -**fingerprints.lua**: -```lua -return { - { mfr = "LEDVANCE", model = "PLUG COMPACT EU EM T" } -} -``` -- ✅ 使用数组格式(与其他子驱动一致) -- ✅ 简化结构,只包含必要信息 - -**can_handle.lua**: -```lua -local FINGERPRINTS = require("simple-metering-config.fingerprints") -for _, fingerprint in ipairs(FINGERPRINTS) do - if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then - local subdriver = require("simple-metering-config") - return true, subdriver - end -end -return false -``` -- ✅ 使用 `ipairs` 遍历(与其他子驱动一致) -- ✅ 返回 `true, subdriver`(与其他子驱动一致) - -## 验证结果 - -### ✅ 语法检查 -- fingerprints.lua: ✅ 语法正确 -- can_handle.lua: ✅ 语法正确 - -### ✅ 格式一致性 -- 与 wallhero 一致: ✅ -- 与 hanssem 一致: ✅ -- 与 multi-switch-no-master 一致: ✅ -- 与 zigbee-switch-power 一致: ✅ - -### ✅ 功能完整性 -- 正确匹配设备: ✅ -- 正确返回 subdriver: ✅ -- 正确返回 false: ✅ - -## 结论 - -✅ **can_handle.lua 现在完全正确并起作用** - -**修复的问题**: -1. ✅ fingerprints 格式改为数组格式(与其他子驱动一致) -2. ✅ can_handle 使用 `ipairs` 遍历(与其他子驱动一致) -3. ✅ 返回值包含 subdriver(与其他子驱动一致) - -**可以提交给 SmartThings**! From 3a46f9d64fa4eed79bc33d39bcfc6e0e2d82c66c Mon Sep 17 00:00:00 2001 From: jack Date: Fri, 6 Mar 2026 09:42:21 +0800 Subject: [PATCH 13/16] Remove redundant code --- .../src/simple-metering-config/init.lua | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua index 1dd009c181..37afe96fae 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua @@ -1,10 +1,9 @@ --- Copyright 2025 SmartThings, Inc. +-- Copyright 2026 SmartThings, Inc. -- Licensed under the Apache License, Version 2.0 local capabilities = require "st.capabilities" local zigbee_constants = require "st.zigbee.constants" local SimpleMetering = require "st.zigbee.cluster".clusters.SimpleMetering -local configurations = require "configurations" local function energy_meter_handler(driver, device, value, zb_rx) local raw_value = value.value @@ -28,11 +27,6 @@ local function energy_meter_handler(driver, device, value, zb_rx) ) end -local function device_init(driver, device) - device:set_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY, 1, {persist = true}) - device:set_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY, 100, {persist = true}) -end - local function do_configure(driver, device) device:configure() device:refresh() @@ -47,20 +41,11 @@ local simple_metering_config_subdriver = { zigbee_handlers = { attr = { [SimpleMetering.ID] = { - [SimpleMetering.attributes.CurrentSummationDelivered.ID] = energy_meter_handler, - [SimpleMetering.attributes.Multiplier.ID] = function(driver, device, value, zb_rx) - device:set_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY, value.value, {persist = true}) - end, - [SimpleMetering.attributes.Divisor.ID] = function(driver, device, value, zb_rx) - device:set_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY, value.value, {persist = true}) - end + [SimpleMetering.attributes.CurrentSummationDelivered.ID] = energy_meter_handler } } }, lifecycle_handlers = { - init = function(driver, device) - configurations.power_reconfig_wrapper(device_init)(driver, device) - end, doConfigure = do_configure }, can_handle = require("simple-metering-config.can_handle") From 28e778305add17c66b33551333dafab1177af10c Mon Sep 17 00:00:00 2001 From: jack Date: Wed, 11 Mar 2026 13:28:45 +0800 Subject: [PATCH 14/16] 1.add the test unit 2. add sub driver register 3.fixing the energy_meter_handler issue --- .../src/simple-metering-config/can_handle.lua | 2 +- .../simple-metering-config/fingerprints.lua | 2 +- .../src/simple-metering-config/init.lua | 9 +-- .../test/test_simple_metering_config.lua | 71 +++++++++++++++++++ .../zigbee-switch/src/sub_drivers.lua | 1 + 5 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 drivers/SmartThings/zigbee-switch/src/simple-metering-config/test/test_simple_metering_config.lua diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua index f7bffb3583..85f3725f2f 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/can_handle.lua @@ -1,4 +1,4 @@ --- Copyright 2025 SmartThings, Inc. +-- Copyright 2026 SmartThings, Inc. -- Licensed under the Apache License, Version 2.0 return function(opts, driver, device, ...) diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua index 9768066449..8c4730e1df 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/fingerprints.lua @@ -1,4 +1,4 @@ --- Copyright 2025 SmartThings, Inc. +-- Copyright 2026 SmartThings, Inc. -- Licensed under the Apache License, Version 2.0 return { diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua index 37afe96fae..2861e4bbc6 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua @@ -27,9 +27,10 @@ local function energy_meter_handler(driver, device, value, zb_rx) ) end -local function do_configure(driver, device) - device:configure() - device:refresh() +local function device_init(driver, device) + -- Set default multiplier and divisor values as suggested by SmartThings + device:set_field(zigbee_constants.SIMPLE_METERING_MULTIPLIER_KEY, 1, {persist = true}) + device:set_field(zigbee_constants.SIMPLE_METERING_DIVISOR_KEY, 100, {persist = true}) end local simple_metering_config_subdriver = { @@ -46,7 +47,7 @@ local simple_metering_config_subdriver = { } }, lifecycle_handlers = { - doConfigure = do_configure + init = device_init }, can_handle = require("simple-metering-config.can_handle") } diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/test/test_simple_metering_config.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/test/test_simple_metering_config.lua new file mode 100644 index 0000000000..bb3cde38c4 --- /dev/null +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/test/test_simple_metering_config.lua @@ -0,0 +1,71 @@ +-- Copyright 2026 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local test = require "integration_test" +local zigbee_test_utils = require "integration_test.zigbee_test_utils" +local clusters = require "st.zigbee.zcl.clusters" +local SimpleMetering = clusters.SimpleMetering +local capabilities = require "st.capabilities" +local t_utils = require "integration_test.utils" + +local mock_device = test.mock_device.build_test_zigbee_device( + { + profile = t_utils.get_profile_definition("switch-power-energy.yml"), + zigbee_endpoints = { + [1] = { + id = 1, + manufacturer = "LEDVANCE", + model = "PLUG COMPACT EU EM T", + server_clusters = { 0x0006, 0x0702 } + } + } + } +) + +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_message_test( + "Energy meter report should be handled with default multiplier and divisor", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device.id, SimpleMetering.attributes.CurrentSummationDelivered:build_test_attr_report(mock_device, 1000) } + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message("main", capabilities.energyMeter.energy({ value = 10, unit = "kWh" })) + } + } +) + +test.register_message_test( + "Energy meter report with zero value should be ignored", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device.id, SimpleMetering.attributes.CurrentSummationDelivered:build_test_attr_report(mock_device, 0) } + } + } +) + +test.register_message_test( + "Energy meter report with negative value should be ignored", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device.id, SimpleMetering.attributes.CurrentSummationDelivered:build_test_attr_report(mock_device, -100) } + } + } +) + +test.run_registered_tests() diff --git a/drivers/SmartThings/zigbee-switch/src/sub_drivers.lua b/drivers/SmartThings/zigbee-switch/src/sub_drivers.lua index 5dcf24ca74..71b7007c68 100644 --- a/drivers/SmartThings/zigbee-switch/src/sub_drivers.lua +++ b/drivers/SmartThings/zigbee-switch/src/sub_drivers.lua @@ -14,6 +14,7 @@ return { lazy_load_if_possible("sinope"), lazy_load_if_possible("sinope-dimmer"), lazy_load_if_possible("zigbee-dimmer-power-energy"), + lazy_load_if_possible("simple-metering-config"), lazy_load_if_possible("zigbee-metering-plug-power-consumption-report"), lazy_load_if_possible("jasco"), lazy_load_if_possible("multi-switch-no-master"), From 875c75fcd53f9111a9d06c5c17e8df9d648fc79b Mon Sep 17 00:00:00 2001 From: jack Date: Wed, 11 Mar 2026 13:36:07 +0800 Subject: [PATCH 15/16] revert the gitgnore file to the default --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9aeae9c9c9..0c358e0f68 100644 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,4 @@ tools/coverage_output_html/ tools/__pycache__/ .DS_Store .venv/ -/test_can_handle.md -/check_lua_syntax.ps1 + From d02ef905dafb8f525b76dbe7b2cc0cb9a1b8d0ca Mon Sep 17 00:00:00 2001 From: jack Date: Mon, 16 Mar 2026 09:39:48 +0800 Subject: [PATCH 16/16] 1.fixing the energy meter value redundant processing 2.change the location of the test file --- .../src/simple-metering-config/init.lua | 2 +- .../test/test_simple_metering_config.lua | 16 +++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) rename drivers/SmartThings/zigbee-switch/src/{simple-metering-config => }/test/test_simple_metering_config.lua (82%) diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua index 2861e4bbc6..f5059ffeac 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua +++ b/drivers/SmartThings/zigbee-switch/src/simple-metering-config/init.lua @@ -8,7 +8,7 @@ local SimpleMetering = require "st.zigbee.cluster".clusters.SimpleMetering local function energy_meter_handler(driver, device, value, zb_rx) local raw_value = value.value - if type(raw_value) ~= "number" or raw_value < 0 then + if type(raw_value) ~= "number" then return end diff --git a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/test/test_simple_metering_config.lua b/drivers/SmartThings/zigbee-switch/src/test/test_simple_metering_config.lua similarity index 82% rename from drivers/SmartThings/zigbee-switch/src/simple-metering-config/test/test_simple_metering_config.lua rename to drivers/SmartThings/zigbee-switch/src/test/test_simple_metering_config.lua index bb3cde38c4..f44114783a 100644 --- a/drivers/SmartThings/zigbee-switch/src/simple-metering-config/test/test_simple_metering_config.lua +++ b/drivers/SmartThings/zigbee-switch/src/test/test_simple_metering_config.lua @@ -47,23 +47,17 @@ test.register_message_test( ) test.register_message_test( - "Energy meter report with zero value should be ignored", + "Energy meter report with zero value should emit zero event", { { channel = "zigbee", direction = "receive", message = { mock_device.id, SimpleMetering.attributes.CurrentSummationDelivered:build_test_attr_report(mock_device, 0) } - } - } -) - -test.register_message_test( - "Energy meter report with negative value should be ignored", - { + }, { - channel = "zigbee", - direction = "receive", - message = { mock_device.id, SimpleMetering.attributes.CurrentSummationDelivered:build_test_attr_report(mock_device, -100) } + channel = "capability", + direction = "send", + message = mock_device:generate_test_message("main", capabilities.energyMeter.energy({ value = 0, unit = "kWh" })) } } )