From 5998b3fcbafced68ef9454b0026b3a685b16c009 Mon Sep 17 00:00:00 2001 From: Abdul Samad Date: Mon, 8 Jun 2026 15:53:13 -0500 Subject: [PATCH 1/3] Isolate the eve-energy subdriver to private cluster usage --- .../src/sub_drivers/eve_energy/can_handle.lua | 9 +- .../src/test/test_eve_energy.lua | 97 +++++++++++++++++++ 2 files changed, 102 insertions(+), 4 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/eve_energy/can_handle.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/eve_energy/can_handle.lua index 369b93b8de..02bc9e06d2 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/eve_energy/can_handle.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/eve_energy/can_handle.lua @@ -6,11 +6,12 @@ local fields = require "switch_utils.fields" local switch_utils = require "switch_utils.utils" return function(opts, driver, device) - local EVE_MANUFACTURER_ID = 0x130A - -- this sub driver does NOT support child devices, and ONLY supports Eve devices - -- that do NOT support the Electrical Sensor device type + local EVE_PRIVATE_CLUSTER_ID = 0x130AFC01 + -- this sub driver loads for devices that: + -- 1. Contain the Eve Private Cluster (0x130AFC01) + -- 2. Do NOT have the Standard Electrical Sensor device type if device.network_type == device_lib.NETWORK_TYPE_MATTER and - device.manufacturer_info.vendor_id == EVE_MANUFACTURER_ID and + #device:get_endpoints(EVE_PRIVATE_CLUSTER_ID) > 0 and #switch_utils.get_endpoints_by_device_type(device, fields.DEVICE_TYPE_ID.ELECTRICAL_SENSOR) == 0 then return true, require("sub_drivers.eve_energy") end 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 1be1e16980..89d3ba448a 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_eve_energy.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_eve_energy.lua @@ -15,6 +15,28 @@ local PRIVATE_ATTR_ID_WATT = 0x130A000A local PRIVATE_ATTR_ID_WATT_ACCUMULATED = 0x130A000B local PRIVATE_ATTR_ID_ACCUMULATED_CONTROL_POINT = 0x130A000E +-- Helper function to add get_endpoints method to mock devices for can_handle testing +local function add_get_endpoints_to_mock(device) + device.get_endpoints = function(self, cluster_id, opts) + opts = opts or {} + local eps = {} + for _, ep in ipairs(self.endpoints) do + for _, cluster in ipairs(ep.clusters or {}) do + if cluster.cluster_id == cluster_id then + -- Check feature_bitmap if specified + if opts.feature_bitmap == nil or + (cluster.feature_map and (cluster.feature_map & opts.feature_bitmap) == opts.feature_bitmap) then + table.insert(eps, ep.endpoint_id) + break + end + end + end + end + return eps + end + return device +end + local mock_device = test.mock_device.build_test_matter_device({ profile = t_utils.get_profile_definition("power-energy-powerConsumption.yml"), manufacturer_info = { @@ -53,6 +75,7 @@ local mock_device = test.mock_device.build_test_matter_device({ } } }) +add_get_endpoints_to_mock(mock_device) local mock_eve_device_using_electrical_sensor = test.mock_device.build_test_matter_device({ profile = t_utils.get_profile_definition("plug-energy-powerConsumption.yml"), @@ -112,6 +135,42 @@ local mock_eve_device_using_electrical_sensor = test.mock_device.build_test_matt } } }) +add_get_endpoints_to_mock(mock_eve_device_using_electrical_sensor) + +-- Mock device without Eve Private Cluster (should not match eve_energy sub-driver) +local mock_device_without_private_cluster = test.mock_device.build_test_matter_device({ + profile = t_utils.get_profile_definition("plug-binary.yml"), + manufacturer_info = { + vendor_id = 0x130A, + product_id = 0x0051, + }, + endpoints = { + { + endpoint_id = 0, + clusters = { + { cluster_id = clusters.Basic.ID, cluster_type = "SERVER" }, + }, + device_types = { + { device_type_id = 0x0016, device_type_revision = 1 } -- RootNode + } + }, + { + endpoint_id = 1, + clusters = { + { + cluster_id = clusters.OnOff.ID, + cluster_type = "SERVER", + cluster_revision = 1, + feature_map = 0, --u32 bitmap + } + }, + device_types = { + { device_type_id = 0x010A, device_type_revision = 1 } -- On/Off Plug + } + } + } +}) +add_get_endpoints_to_mock(mock_device_without_private_cluster) local function test_init() local cluster_subscribe_list = { @@ -129,6 +188,44 @@ local function test_init() end test.set_test_init_function(test_init) +-- Test can_handle logic +test.register_coroutine_test( + "Eve Energy sub-driver can_handle should return true for devices with Eve Private Cluster and no Electrical Sensor", + function() + local eve_energy_can_handle = require("sub_drivers.eve_energy.can_handle") + local result, sub_driver = eve_energy_can_handle(nil, nil, mock_device) + assert(result == true, "can_handle should return true for Eve device with private cluster and no electrical sensor") + assert(sub_driver ~= nil, "sub_driver should be returned") + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "Eve Energy sub-driver can_handle should return false for devices with Electrical Sensor device type", + function() + local eve_energy_can_handle = require("sub_drivers.eve_energy.can_handle") + local result = eve_energy_can_handle(nil, nil, mock_eve_device_using_electrical_sensor) + assert(result == false, "can_handle should return false for Eve device with electrical sensor") + end, + { + min_api_version = 17 + } +) + +test.register_coroutine_test( + "Eve Energy sub-driver can_handle should return false for devices without Eve Private Cluster", + function() + local eve_energy_can_handle = require("sub_drivers.eve_energy.can_handle") + local result = eve_energy_can_handle(nil, nil, mock_device_without_private_cluster) + assert(result == false, "can_handle should return false for device without Eve Private Cluster") + end, + { + min_api_version = 17 + } +) + test.register_message_test( "On command should send the appropriate commands", { From 5d2a4d2c430262e1c301360b95d242d22a5e4eaf Mon Sep 17 00:00:00 2001 From: Abdul Samad Date: Tue, 9 Jun 2026 10:23:55 -0500 Subject: [PATCH 2/3] Remove redundant test, check cluster differently in can_handle --- .../src/sub_drivers/eve_energy/can_handle.lua | 13 ++++++- .../src/test/test_eve_energy.lua | 38 ------------------- 2 files changed, 12 insertions(+), 39 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/eve_energy/can_handle.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/eve_energy/can_handle.lua index 02bc9e06d2..b5b536a44e 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/eve_energy/can_handle.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/eve_energy/can_handle.lua @@ -5,13 +5,24 @@ local device_lib = require "st.device" local fields = require "switch_utils.fields" local switch_utils = require "switch_utils.utils" +local function has_cluster(device, cluster_id) + for _, ep in ipairs(device.endpoints) do + for _, cluster in ipairs(ep.clusters or {}) do + if cluster.cluster_id == cluster_id then + return true + end + end + end + return false +end + return function(opts, driver, device) local EVE_PRIVATE_CLUSTER_ID = 0x130AFC01 -- this sub driver loads for devices that: -- 1. Contain the Eve Private Cluster (0x130AFC01) -- 2. Do NOT have the Standard Electrical Sensor device type if device.network_type == device_lib.NETWORK_TYPE_MATTER and - #device:get_endpoints(EVE_PRIVATE_CLUSTER_ID) > 0 and + has_cluster(device, EVE_PRIVATE_CLUSTER_ID) and #switch_utils.get_endpoints_by_device_type(device, fields.DEVICE_TYPE_ID.ELECTRICAL_SENSOR) == 0 then return true, require("sub_drivers.eve_energy") end 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 89d3ba448a..48a2eaa2df 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_eve_energy.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_eve_energy.lua @@ -15,28 +15,6 @@ local PRIVATE_ATTR_ID_WATT = 0x130A000A local PRIVATE_ATTR_ID_WATT_ACCUMULATED = 0x130A000B local PRIVATE_ATTR_ID_ACCUMULATED_CONTROL_POINT = 0x130A000E --- Helper function to add get_endpoints method to mock devices for can_handle testing -local function add_get_endpoints_to_mock(device) - device.get_endpoints = function(self, cluster_id, opts) - opts = opts or {} - local eps = {} - for _, ep in ipairs(self.endpoints) do - for _, cluster in ipairs(ep.clusters or {}) do - if cluster.cluster_id == cluster_id then - -- Check feature_bitmap if specified - if opts.feature_bitmap == nil or - (cluster.feature_map and (cluster.feature_map & opts.feature_bitmap) == opts.feature_bitmap) then - table.insert(eps, ep.endpoint_id) - break - end - end - end - end - return eps - end - return device -end - local mock_device = test.mock_device.build_test_matter_device({ profile = t_utils.get_profile_definition("power-energy-powerConsumption.yml"), manufacturer_info = { @@ -75,7 +53,6 @@ local mock_device = test.mock_device.build_test_matter_device({ } } }) -add_get_endpoints_to_mock(mock_device) local mock_eve_device_using_electrical_sensor = test.mock_device.build_test_matter_device({ profile = t_utils.get_profile_definition("plug-energy-powerConsumption.yml"), @@ -135,7 +112,6 @@ local mock_eve_device_using_electrical_sensor = test.mock_device.build_test_matt } } }) -add_get_endpoints_to_mock(mock_eve_device_using_electrical_sensor) -- Mock device without Eve Private Cluster (should not match eve_energy sub-driver) local mock_device_without_private_cluster = test.mock_device.build_test_matter_device({ @@ -170,7 +146,6 @@ local mock_device_without_private_cluster = test.mock_device.build_test_matter_d } } }) -add_get_endpoints_to_mock(mock_device_without_private_cluster) local function test_init() local cluster_subscribe_list = { @@ -188,7 +163,6 @@ local function test_init() end test.set_test_init_function(test_init) --- Test can_handle logic test.register_coroutine_test( "Eve Energy sub-driver can_handle should return true for devices with Eve Private Cluster and no Electrical Sensor", function() @@ -202,18 +176,6 @@ test.register_coroutine_test( } ) -test.register_coroutine_test( - "Eve Energy sub-driver can_handle should return false for devices with Electrical Sensor device type", - function() - local eve_energy_can_handle = require("sub_drivers.eve_energy.can_handle") - local result = eve_energy_can_handle(nil, nil, mock_eve_device_using_electrical_sensor) - assert(result == false, "can_handle should return false for Eve device with electrical sensor") - end, - { - min_api_version = 17 - } -) - test.register_coroutine_test( "Eve Energy sub-driver can_handle should return false for devices without Eve Private Cluster", function() From d141a472e31185025671b66a12fe148283b88d6c Mon Sep 17 00:00:00 2001 From: Abdul Samad Date: Tue, 9 Jun 2026 11:43:36 -0500 Subject: [PATCH 3/3] Revert 5d2a4d2, except the redundant test removal --- .../src/sub_drivers/eve_energy/can_handle.lua | 13 +--------- .../src/test/test_eve_energy.lua | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/SmartThings/matter-switch/src/sub_drivers/eve_energy/can_handle.lua b/drivers/SmartThings/matter-switch/src/sub_drivers/eve_energy/can_handle.lua index b5b536a44e..02bc9e06d2 100644 --- a/drivers/SmartThings/matter-switch/src/sub_drivers/eve_energy/can_handle.lua +++ b/drivers/SmartThings/matter-switch/src/sub_drivers/eve_energy/can_handle.lua @@ -5,24 +5,13 @@ local device_lib = require "st.device" local fields = require "switch_utils.fields" local switch_utils = require "switch_utils.utils" -local function has_cluster(device, cluster_id) - for _, ep in ipairs(device.endpoints) do - for _, cluster in ipairs(ep.clusters or {}) do - if cluster.cluster_id == cluster_id then - return true - end - end - end - return false -end - return function(opts, driver, device) local EVE_PRIVATE_CLUSTER_ID = 0x130AFC01 -- this sub driver loads for devices that: -- 1. Contain the Eve Private Cluster (0x130AFC01) -- 2. Do NOT have the Standard Electrical Sensor device type if device.network_type == device_lib.NETWORK_TYPE_MATTER and - has_cluster(device, EVE_PRIVATE_CLUSTER_ID) and + #device:get_endpoints(EVE_PRIVATE_CLUSTER_ID) > 0 and #switch_utils.get_endpoints_by_device_type(device, fields.DEVICE_TYPE_ID.ELECTRICAL_SENSOR) == 0 then return true, require("sub_drivers.eve_energy") end 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 48a2eaa2df..e90f5a70da 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_eve_energy.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_eve_energy.lua @@ -15,6 +15,28 @@ local PRIVATE_ATTR_ID_WATT = 0x130A000A local PRIVATE_ATTR_ID_WATT_ACCUMULATED = 0x130A000B local PRIVATE_ATTR_ID_ACCUMULATED_CONTROL_POINT = 0x130A000E +-- Helper function to add get_endpoints method to mock devices +local function add_get_endpoints_to_mock(device) + device.get_endpoints = function(self, cluster_id, opts) + opts = opts or {} + local eps = {} + for _, ep in ipairs(self.endpoints) do + for _, cluster in ipairs(ep.clusters or {}) do + if cluster.cluster_id == cluster_id then + -- Check feature_bitmap if specified + if opts.feature_bitmap == nil or + (cluster.feature_map and (cluster.feature_map & opts.feature_bitmap) == opts.feature_bitmap) then + table.insert(eps, ep.endpoint_id) + break + end + end + end + end + return eps + end + return device +end + local mock_device = test.mock_device.build_test_matter_device({ profile = t_utils.get_profile_definition("power-energy-powerConsumption.yml"), manufacturer_info = { @@ -53,6 +75,7 @@ local mock_device = test.mock_device.build_test_matter_device({ } } }) +add_get_endpoints_to_mock(mock_device) local mock_eve_device_using_electrical_sensor = test.mock_device.build_test_matter_device({ profile = t_utils.get_profile_definition("plug-energy-powerConsumption.yml"), @@ -112,6 +135,7 @@ local mock_eve_device_using_electrical_sensor = test.mock_device.build_test_matt } } }) +add_get_endpoints_to_mock(mock_eve_device_using_electrical_sensor) -- Mock device without Eve Private Cluster (should not match eve_energy sub-driver) local mock_device_without_private_cluster = test.mock_device.build_test_matter_device({ @@ -146,6 +170,7 @@ local mock_device_without_private_cluster = test.mock_device.build_test_matter_d } } }) +add_get_endpoints_to_mock(mock_device_without_private_cluster) local function test_init() local cluster_subscribe_list = {