diff --git a/drivers/SmartThings/zigbee-switch/src/test/test_switch_power.lua b/drivers/SmartThings/zigbee-switch/src/test/test_switch_power.lua index 2a26c95e3c..70e5a426b8 100644 --- a/drivers/SmartThings/zigbee-switch/src/test/test_switch_power.lua +++ b/drivers/SmartThings/zigbee-switch/src/test/test_switch_power.lua @@ -2,6 +2,7 @@ -- Licensed under the Apache License, Version 2.0 local test = require "integration_test" +local capabilities = require "st.capabilities" local t_utils = require "integration_test.utils" local clusters = require "st.zigbee.zcl.clusters" local zigbee_test_utils = require "integration_test.zigbee_test_utils" @@ -53,14 +54,30 @@ local mock_vimar_device = test.mock_device.build_test_zigbee_device( } ) +local mock_climax_device = test.mock_device.build_test_zigbee_device( + { profile = t_utils.get_profile_definition("switch-power-smartplug.yml"), + fingerprinted_endpoint_id = 0x01, + zigbee_endpoints = { + [1] = { + id = 1, + manufacturer = "ClimaxTechnology", + model = "PSM_00.00.00.35TC", + server_clusters = {0x0006, 0x0B04, 0x0702} + } + } + } +) + zigbee_test_utils.prepare_zigbee_env_info() local function test_init() mock_device:set_field("_configuration_version", 1, {persist = true}) + mock_climax_device:set_field("_configuration_version", 1, {persist = true}) test.mock_device.add_test_device(mock_device) test.mock_device.add_test_device(mock_aurora_relay_device) test.mock_device.add_test_device(mock_vimar_device) + test.mock_device.add_test_device(mock_climax_device) end test.set_test_init_function(test_init) @@ -316,5 +333,182 @@ test.register_coroutine_test( } ) +test.register_message_test( + "Climax ActivePower should apply multiplier and divisor", + { + { + channel = "zigbee", + direction = "receive", + message = { + mock_climax_device.id, + ElectricalMeasurement.attributes.ACPowerMultiplier:build_test_attr_report(mock_climax_device, 3) + } + }, + { + channel = "zigbee", + direction = "receive", + message = { + mock_climax_device.id, + ElectricalMeasurement.attributes.ACPowerDivisor:build_test_attr_report(mock_climax_device, 10) + } + }, + { + channel = "zigbee", + direction = "receive", + message = { + mock_climax_device.id, + ElectricalMeasurement.attributes.ActivePower:build_test_attr_report(mock_climax_device, 20) + } + }, + { + channel = "capability", + direction = "send", + message = mock_climax_device:generate_test_message( + "main", + capabilities.powerMeter.power({ value = 6.0, unit = "W" }) + ) + } + }, + { + min_api_version = 14, + max_api_version = 14 + } +) + +test.register_message_test( + "Climax ActivePower should apply multiplier and divisor with native registration", + { + { + channel = "zigbee", + direction = "receive", + message = { + mock_climax_device.id, + ElectricalMeasurement.attributes.ACPowerMultiplier:build_test_attr_report(mock_climax_device, 3) + } + }, + { + channel = "zigbee", + direction = "receive", + message = { + mock_climax_device.id, + ElectricalMeasurement.attributes.ACPowerDivisor:build_test_attr_report(mock_climax_device, 10) + } + }, + { + channel = "zigbee", + direction = "receive", + message = { + mock_climax_device.id, + ElectricalMeasurement.attributes.ActivePower:build_test_attr_report(mock_climax_device, 20) + } + }, + { + channel = "capability", + direction = "send", + message = mock_climax_device:generate_test_message( + "main", + capabilities.powerMeter.power({ value = 6.0, unit = "W" }) + ) + }, + { + channel = "devices", + direction = "send", + message = { + "register_native_capability_attr_handler", + { + device_uuid = mock_climax_device.id, + capability_id = "powerMeter", + capability_attr_id = "power" + } + } + } + }, + { + min_api_version = 15 + } +) + +test.register_message_test( + "Climax InstantaneousDemand should convert kilowatts to watts", + { + { + channel = "zigbee", + direction = "receive", + message = { + mock_climax_device.id, + SimpleMetering.attributes.Multiplier:build_test_attr_report(mock_climax_device, 1) + } + }, + { + channel = "zigbee", + direction = "receive", + message = { + mock_climax_device.id, + SimpleMetering.attributes.Divisor:build_test_attr_report(mock_climax_device, 1000) + } + }, + { + channel = "zigbee", + direction = "receive", + message = { + mock_climax_device.id, + SimpleMetering.attributes.InstantaneousDemand:build_test_attr_report(mock_climax_device, 800) + } + }, + { + channel = "capability", + direction = "send", + message = mock_climax_device:generate_test_message( + "main", + capabilities.powerMeter.power({ value = 800.0, unit = "W" }) + ) + } + }, + { + min_api_version = 14 + } +) + +test.register_message_test( + "Climax InstantaneousDemand should apply multiplier", + { + { + channel = "zigbee", + direction = "receive", + message = { + mock_climax_device.id, + SimpleMetering.attributes.Multiplier:build_test_attr_report(mock_climax_device, 2) + } + }, + { + channel = "zigbee", + direction = "receive", + message = { + mock_climax_device.id, + SimpleMetering.attributes.Divisor:build_test_attr_report(mock_climax_device, 1000) + } + }, + { + channel = "zigbee", + direction = "receive", + message = { + mock_climax_device.id, + SimpleMetering.attributes.InstantaneousDemand:build_test_attr_report(mock_climax_device, 800) + } + }, + { + channel = "capability", + direction = "send", + message = mock_climax_device:generate_test_message( + "main", + capabilities.powerMeter.power({ value = 1600.0, unit = "W" }) + ) + } + }, + { + min_api_version = 14 + } +) + test.run_registered_tests() diff --git a/drivers/SmartThings/zigbee-switch/src/zigbee-switch-power/climax-power-meter/can_handle.lua b/drivers/SmartThings/zigbee-switch/src/zigbee-switch-power/climax-power-meter/can_handle.lua new file mode 100644 index 0000000000..bda6e91b8c --- /dev/null +++ b/drivers/SmartThings/zigbee-switch/src/zigbee-switch-power/climax-power-meter/can_handle.lua @@ -0,0 +1,9 @@ +-- Copyright 2026 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +return function(opts, driver, device) + if device:get_manufacturer() == "ClimaxTechnology" and device:get_model() == "PSM_00.00.00.35TC" then + return true, require("zigbee-switch-power.climax-power-meter") + end + return false +end diff --git a/drivers/SmartThings/zigbee-switch/src/zigbee-switch-power/climax-power-meter/init.lua b/drivers/SmartThings/zigbee-switch/src/zigbee-switch-power/climax-power-meter/init.lua new file mode 100644 index 0000000000..665cfcc239 --- /dev/null +++ b/drivers/SmartThings/zigbee-switch/src/zigbee-switch-power/climax-power-meter/init.lua @@ -0,0 +1,25 @@ +-- Copyright 2026 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local clusters = require "st.zigbee.zcl.clusters" +local power_meter_defaults = require "st.zigbee.defaults.powerMeter_defaults" + +local ElectricalMeasurement = clusters.ElectricalMeasurement +local SimpleMetering = clusters.SimpleMetering + +local climax_power_meter = { + NAME = "Climax Power Meter", + zigbee_handlers = { + attr = { + [ElectricalMeasurement.ID] = { + [ElectricalMeasurement.attributes.ActivePower.ID] = power_meter_defaults.active_power_meter_handler + }, + [SimpleMetering.ID] = { + [SimpleMetering.attributes.InstantaneousDemand.ID] = power_meter_defaults.instantaneous_demand_handler + } + } + }, + can_handle = require("zigbee-switch-power.climax-power-meter.can_handle") +} + +return climax_power_meter diff --git a/drivers/SmartThings/zigbee-switch/src/zigbee-switch-power/sub_drivers.lua b/drivers/SmartThings/zigbee-switch/src/zigbee-switch-power/sub_drivers.lua index 0c1ba5eeef..4953f1722d 100644 --- a/drivers/SmartThings/zigbee-switch/src/zigbee-switch-power/sub_drivers.lua +++ b/drivers/SmartThings/zigbee-switch/src/zigbee-switch-power/sub_drivers.lua @@ -5,6 +5,7 @@ local lazy_load = require "lazy_load_subdriver" return { lazy_load("zigbee-switch-power.aurora-relay"), + lazy_load("zigbee-switch-power.climax-power-meter"), lazy_load("zigbee-switch-power.vimar"), lazy_load("zigbee-switch-power.ledvance-metering-plug") }