From 1a29cb63d8076cb714305170a6244015e6a67f70 Mon Sep 17 00:00:00 2001 From: seojune Date: Mon, 13 Oct 2025 08:48:13 +0900 Subject: [PATCH 1/3] add Aqara Wireless Remote Switch T1(Single/Double) --- .../zigbee-button/fingerprints.yml | 10 ++ .../profiles/aqara-double-buttons.yml | 30 ++++ .../profiles/aqara-single-button.yml | 12 ++ .../zigbee-button/src/aqara/init.lua | 160 +++++++++++------- .../src/test/test_aqara_button.lua | 156 ++++++++++------- 5 files changed, 251 insertions(+), 117 deletions(-) create mode 100644 drivers/SmartThings/zigbee-button/profiles/aqara-double-buttons.yml create mode 100644 drivers/SmartThings/zigbee-button/profiles/aqara-single-button.yml diff --git a/drivers/SmartThings/zigbee-button/fingerprints.yml b/drivers/SmartThings/zigbee-button/fingerprints.yml index 7acc77387f..83db2a9062 100644 --- a/drivers/SmartThings/zigbee-button/fingerprints.yml +++ b/drivers/SmartThings/zigbee-button/fingerprints.yml @@ -14,6 +14,16 @@ zigbeeManufacturer: manufacturer: LUMI model: lumi.remote.acn003 deviceProfileName: one-button-battery + - id: "LUMI/lumi.remote.b186acn03" + deviceLabel: Aqara Wireless Remote Switch T1 (Single Rocker) + manufacturer: LUMI + model: lumi.remote.b186acn03 + deviceProfileName: aqara-single-button + - id: "LUMI/lumi.remote.b286acn03" + deviceLabel: Aqara Wireless Remote Switch T1 (Double Rocker) + manufacturer: LUMI + model: lumi.remote.b286acn03 + deviceProfileName: aqara-double-buttons - id: "HEIMAN/SOS-EM" deviceLabel: HEIMAN Button manufacturer: HEIMAN diff --git a/drivers/SmartThings/zigbee-button/profiles/aqara-double-buttons.yml b/drivers/SmartThings/zigbee-button/profiles/aqara-double-buttons.yml new file mode 100644 index 0000000000..09bcd2b1f4 --- /dev/null +++ b/drivers/SmartThings/zigbee-button/profiles/aqara-double-buttons.yml @@ -0,0 +1,30 @@ +name: aqara-double-buttons +components: + - id: main + capabilities: + - id: button + version: 1 + - id: batteryLevel + version: 1 + - id: refresh + version: 1 + categories: + - name: Button + - id: button1 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: button2 + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController + - id: all + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController diff --git a/drivers/SmartThings/zigbee-button/profiles/aqara-single-button.yml b/drivers/SmartThings/zigbee-button/profiles/aqara-single-button.yml new file mode 100644 index 0000000000..9570b1fdd8 --- /dev/null +++ b/drivers/SmartThings/zigbee-button/profiles/aqara-single-button.yml @@ -0,0 +1,12 @@ +name: aqara-single-button +components: + - id: main + capabilities: + - id: button + version: 1 + - id: batteryLevel + version: 1 + - id: refresh + version: 1 + categories: + - name: Button diff --git a/drivers/SmartThings/zigbee-button/src/aqara/init.lua b/drivers/SmartThings/zigbee-button/src/aqara/init.lua index 174d775324..b405b506cd 100644 --- a/drivers/SmartThings/zigbee-button/src/aqara/init.lua +++ b/drivers/SmartThings/zigbee-button/src/aqara/init.lua @@ -29,74 +29,113 @@ local MFG_CODE = 0x115F local MULTISTATE_INPUT_CLUSTER_ID = 0x0012 local PRESENT_ATTRIBUTE_ID = 0x0055 +local COMP_LIST = { "button1", "button2", "all" } local FINGERPRINTS = { - { mfr = "LUMI", model = "lumi.remote.b1acn02" }, - { mfr = "LUMI", model = "lumi.remote.acn003" } + ["lumi.remote.b1acn02"] = { mfr = "LUMI", btn_cnt = 1 }, + ["lumi.remote.acn003"] = { mfr = "LUMI", btn_cnt = 1 }, + ["lumi.remote.b186acn03"] = { mfr = "LUMI", btn_cnt = 1 }, + ["lumi.remote.b286acn03"] = { mfr = "LUMI", btn_cnt = 3 } } local configuration = { - { - cluster = MULTISTATE_INPUT_CLUSTER_ID, - attribute = PRESENT_ATTRIBUTE_ID, - minimum_interval = 3, - maximum_interval = 7200, - data_type = data_types.Uint16, - reportable_change = 1 - }, - { - cluster = PowerConfiguration.ID, - attribute = PowerConfiguration.attributes.BatteryVoltage.ID, - minimum_interval = 30, - maximum_interval = 3600, - data_type = PowerConfiguration.attributes.BatteryVoltage.base_type, - reportable_change = 1 - } + { + cluster = MULTISTATE_INPUT_CLUSTER_ID, + attribute = PRESENT_ATTRIBUTE_ID, + minimum_interval = 3, + maximum_interval = 7200, + data_type = data_types.Uint16, + reportable_change = 1 + }, + { + cluster = PowerConfiguration.ID, + attribute = PowerConfiguration.attributes.BatteryVoltage.ID, + minimum_interval = 30, + maximum_interval = 3600, + data_type = PowerConfiguration.attributes.BatteryVoltage.base_type, + reportable_change = 1 + } } local function present_value_attr_handler(driver, device, value, zb_rx) - if value.value == 1 then - device:emit_event(capabilities.button.button.pushed({state_change = true})) - elseif value.value == 2 then - device:emit_event(capabilities.button.button.double({state_change = true})) - elseif value.value == 0 then - device:emit_event(capabilities.button.button.held({state_change = true})) - end + local end_point = zb_rx.address_header.src_endpoint.value + local btn_evt_cnt = FINGERPRINTS[device:get_model()].btn_cnt or 1 + local evt = capabilities.button.button.held({ state_change = true }) + if value.value == 1 then + evt = capabilities.button.button.pushed({ state_change = true }) + elseif value.value == 2 then + evt = capabilities.button.button.double({ state_change = true }) + end + device:emit_event(evt) + if btn_evt_cnt > 1 then + device:emit_component_event(device.profile.components[COMP_LIST[end_point]], evt) + 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 is_aqara_products = function(opts, driver, device) - for _, fingerprint in ipairs(FINGERPRINTS) do - if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then - return true - end - end - return false + local isAqaraProducts = false + if FINGERPRINTS[device:get_model()] and FINGERPRINTS[device:get_model()].mfr == device:get_manufacturer() then + isAqaraProducts = true + end + return isAqaraProducts end local function device_init(driver, device) - battery_defaults.build_linear_voltage_init(2.6, 3.0)(driver, device) - if configuration ~= nil then - for _, attribute in ipairs(configuration) do - device:add_configured_attribute(attribute) - end + battery_defaults.build_linear_voltage_init(2.6, 3.0)(driver, device) + if configuration ~= nil then + for _, attribute in ipairs(configuration) do + device:add_configured_attribute(attribute) end + end end local function added_handler(self, device) - 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.battery.battery(100)) + local btn_evt_cnt = FINGERPRINTS[device:get_model()].btn_cnt 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("CR2032")) + device:emit_event(capabilities.batteryLevel.quantity(1)) + + if btn_evt_cnt > 1 then + for i = 1, btn_evt_cnt do + device:emit_component_event(device.profile.components[COMP_LIST[i]], + capabilities.button.supportedButtonValues({ "pushed", "held", "double" }, + { visibility = { displayed = false } })) + device:emit_component_event(device.profile.components[COMP_LIST[i]], + capabilities.button.numberOfButtons({ value = 1 })) + device:emit_component_event(device.profile.components[COMP_LIST[i]], + capabilities.button.button.pushed({ state_change = false })) + button_utils.emit_event_if_latest_state_missing(device, COMP_LIST[i], capabilities.button, + capabilities.button.button.NAME, capabilities.button.button.pushed({ state_change = false })) + end + end end local function do_configure(driver, device) + local ATTR_ID = PRIVATE_ATTRIBUTE_ID_T1 + local cmd_value = 1 + device:configure() - if device:get_model() == "lumi.remote.b1acn02" then - device:send(cluster_base.write_manufacturer_specific_attribute(device, - PRIVATE_CLUSTER_ID, PRIVATE_ATTRIBUTE_ID_T1, MFG_CODE, data_types.Uint8, 1)) - elseif device:get_model() == "lumi.remote.acn003" then - device:send(cluster_base.write_manufacturer_specific_attribute(device, - PRIVATE_CLUSTER_ID, PRIVATE_ATTRIBUTE_ID_E1, MFG_CODE, data_types.Uint8, 2)) + if device:get_model() == "lumi.remote.acn003" then + ATTR_ID = PRIVATE_ATTRIBUTE_ID_E1 + cmd_value = 2 end + device:send(cluster_base.write_manufacturer_specific_attribute(device, + PRIVATE_CLUSTER_ID, ATTR_ID, MFG_CODE, data_types.Uint8, cmd_value)) -- when the wireless switch T1 accesses the network, the gateway sends -- private attribute 0009 to make the device no longer distinguish -- between the standard gateway and the aqara gateway. @@ -105,20 +144,23 @@ local function do_configure(driver, device) end local aqara_wireless_switch_handler = { - NAME = "Aqara Wireless Switch Handler", - lifecycle_handlers = { - init = device_init, - added = added_handler, - doConfigure = do_configure - }, - zigbee_handlers = { - attr = { - [MULTISTATE_INPUT_CLUSTER_ID] = { - [PRESENT_ATTRIBUTE_ID] = present_value_attr_handler - } + NAME = "Aqara Wireless Switch Handler", + lifecycle_handlers = { + init = device_init, + added = added_handler, + doConfigure = do_configure + }, + zigbee_handlers = { + attr = { + [MULTISTATE_INPUT_CLUSTER_ID] = { + [PRESENT_ATTRIBUTE_ID] = present_value_attr_handler + }, + [PowerConfiguration.ID] = { + [PowerConfiguration.attributes.BatteryVoltage.ID] = battery_level_handler } - }, - can_handle = is_aqara_products + } + }, + can_handle = is_aqara_products } return aqara_wireless_switch_handler 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 b53a966761..31dc55fb20 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_aqara_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_aqara_button.lua @@ -29,9 +29,10 @@ local PRIVATE_CLUSTER_ID = 0xFCC0 local PRIVATE_ATTRIBUTE_ID_T1 = 0x0009 local PRIVATE_ATTRIBUTE_ID_E1 = 0x0125 +local COMP_LIST = { "button1", "button2", "all" } local mock_device_e1 = test.mock_device.build_test_zigbee_device( { - profile = t_utils.get_profile_definition("one-button-battery.yml"), + profile = t_utils.get_profile_definition("aqara-single-button.yml"), zigbee_endpoints = { [1] = { id = 1, @@ -43,14 +44,14 @@ local mock_device_e1 = test.mock_device.build_test_zigbee_device( } ) -local mock_device_t1 = test.mock_device.build_test_zigbee_device( +local mock_device_t1_double_rocker = test.mock_device.build_test_zigbee_device( { - profile = t_utils.get_profile_definition("one-button-battery.yml"), + profile = t_utils.get_profile_definition("aqara-double-buttons.yml"), zigbee_endpoints = { [1] = { id = 1, manufacturer = "LUMI", - model = "lumi.remote.b1acn02", + model = "lumi.remote.b286acn03", server_clusters = { 0x0001, 0x0012 } } } @@ -60,41 +61,36 @@ local mock_device_t1 = test.mock_device.build_test_zigbee_device( zigbee_test_utils.prepare_zigbee_env_info() local function test_init() test.mock_device.add_test_device(mock_device_e1) - test.mock_device.add_test_device(mock_device_t1)end + test.mock_device.add_test_device(mock_device_t1_double_rocker) +end test.set_test_init_function(test_init) test.register_coroutine_test( - "Handle added lifecycle -- e1", + "Handle added lifecycle - T1 double rocker", function() - -- The initial button pushed event should be send during the device's first time onboarding - test.socket.device_lifecycle:__queue_receive({ mock_device_e1.id, "added" }) - test.socket.capability:__expect_send(mock_device_e1:generate_test_message("main", capabilities.button.supportedButtonValues({"pushed","held","double"}, {visibility = { displayed = false }}))) - test.socket.capability:__expect_send(mock_device_e1:generate_test_message("main", capabilities.button.numberOfButtons({value = 1}))) - test.socket.capability:__expect_send(mock_device_e1:generate_test_message("main", capabilities.button.button.pushed({state_change = false}))) - test.socket.capability:__expect_send(mock_device_e1:generate_test_message("main", capabilities.battery.battery(100))) - -- Avoid sending the initial button pushed event after driver switch-over, as the switch-over event itself re-triggers the added lifecycle. - test.socket.device_lifecycle:__queue_receive({ mock_device_e1.id, "added" }) - test.socket.capability:__expect_send(mock_device_e1:generate_test_message("main", capabilities.button.supportedButtonValues({"pushed","held","double"}, {visibility = { displayed = false }}))) - test.socket.capability:__expect_send(mock_device_e1:generate_test_message("main", capabilities.button.numberOfButtons({value = 1}))) - test.socket.capability:__expect_send(mock_device_e1:generate_test_message("main", capabilities.battery.battery(100))) + test.socket.device_lifecycle:__queue_receive({ mock_device_t1_double_rocker.id, "added" }) + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message("main", + capabilities.button.supportedButtonValues({ "pushed", "held", "double" }, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message("main", + capabilities.button.numberOfButtons({ value = 1 }))) + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message("main", + capabilities.button.button.pushed({ state_change = false }))) + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message("main", + capabilities.batteryLevel.battery.normal())) + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message("main", + capabilities.batteryLevel.type("CR2032"))) + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message("main", + capabilities.batteryLevel.quantity(1))) + for i = 1, 3 do + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message(COMP_LIST[i], + capabilities.button.supportedButtonValues({ "pushed", "held", "double" }, { visibility = { displayed = false } }))) + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message(COMP_LIST[i], + capabilities.button.numberOfButtons({ value = 1 }))) + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message(COMP_LIST[i], + capabilities.button.button.pushed({ state_change = false }))) end -) -test.register_coroutine_test( - "Handle added lifecycle -- t1", - function() - -- The initial button pushed event should be send during the device's first time onboarding - test.socket.device_lifecycle:__queue_receive({ mock_device_t1.id, "added" }) - test.socket.capability:__expect_send(mock_device_t1:generate_test_message("main", capabilities.button.supportedButtonValues({"pushed","held","double"}, {visibility = { displayed = false }}))) - test.socket.capability:__expect_send(mock_device_t1:generate_test_message("main", capabilities.button.numberOfButtons({value = 1}))) - test.socket.capability:__expect_send(mock_device_t1:generate_test_message("main", capabilities.button.button.pushed({state_change = false}))) - test.socket.capability:__expect_send(mock_device_t1:generate_test_message("main", capabilities.battery.battery(100))) - -- Avoid sending the initial button pushed event after driver switch-over, as the switch-over event itself re-triggers the added lifecycle. - test.socket.device_lifecycle:__queue_receive({ mock_device_t1.id, "added" }) - test.socket.capability:__expect_send(mock_device_t1:generate_test_message("main", capabilities.button.supportedButtonValues({"pushed","held","double"}, {visibility = { displayed = false }}))) - test.socket.capability:__expect_send(mock_device_t1:generate_test_message("main", capabilities.button.numberOfButtons({value = 1}))) - test.socket.capability:__expect_send(mock_device_t1:generate_test_message("main", capabilities.battery.battery(100))) end ) @@ -116,10 +112,12 @@ test.register_coroutine_test( }) test.socket.zigbee:__expect_send({ mock_device_e1.id, - zigbee_test_utils.build_attr_config(mock_device_e1, MULTISTATE_INPUT_CLUSTER_ID, PRESENT_ATTRIBUTE_ID, 0x0003, 0x1C20, data_types.Uint16, 0x0001) + zigbee_test_utils.build_attr_config(mock_device_e1, MULTISTATE_INPUT_CLUSTER_ID, PRESENT_ATTRIBUTE_ID, 0x0003, + 0x1C20, data_types.Uint16, 0x0001) }) test.socket.zigbee:__expect_send({ mock_device_e1.id, - cluster_base.write_manufacturer_specific_attribute(mock_device_e1, PRIVATE_CLUSTER_ID, PRIVATE_ATTRIBUTE_ID_E1, MFG_CODE, + cluster_base.write_manufacturer_specific_attribute(mock_device_e1, PRIVATE_CLUSTER_ID, PRIVATE_ATTRIBUTE_ID_E1, + MFG_CODE, data_types.Uint8, 2) }) mock_device_e1:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end @@ -129,27 +127,31 @@ test.register_coroutine_test( test.register_coroutine_test( "Handle doConfigure lifecycle -- t1", function() - test.socket.device_lifecycle:__queue_receive({ mock_device_t1.id, "doConfigure" }) + test.socket.device_lifecycle:__queue_receive({ mock_device_t1_double_rocker.id, "doConfigure" }) test.socket.zigbee:__expect_send({ - mock_device_t1.id, - zigbee_test_utils.build_bind_request(mock_device_t1, zigbee_test_utils.mock_hub_eui, PowerConfiguration.ID) + mock_device_t1_double_rocker.id, + zigbee_test_utils.build_bind_request(mock_device_t1_double_rocker, zigbee_test_utils.mock_hub_eui, + PowerConfiguration.ID) }) test.socket.zigbee:__expect_send({ - mock_device_t1.id, - PowerConfiguration.attributes.BatteryVoltage:configure_reporting(mock_device_t1, 30, 3600, 1) + mock_device_t1_double_rocker.id, + PowerConfiguration.attributes.BatteryVoltage:configure_reporting(mock_device_t1_double_rocker, 30, 3600, 1) }) test.socket.zigbee:__expect_send({ - mock_device_t1.id, - zigbee_test_utils.build_bind_request(mock_device_t1, zigbee_test_utils.mock_hub_eui, MULTISTATE_INPUT_CLUSTER_ID) + mock_device_t1_double_rocker.id, + zigbee_test_utils.build_bind_request(mock_device_t1_double_rocker, zigbee_test_utils.mock_hub_eui, + MULTISTATE_INPUT_CLUSTER_ID) }) test.socket.zigbee:__expect_send({ - mock_device_t1.id, - zigbee_test_utils.build_attr_config(mock_device_t1, MULTISTATE_INPUT_CLUSTER_ID, PRESENT_ATTRIBUTE_ID, 0x0003, 0x1C20, data_types.Uint16, 0x0001) + mock_device_t1_double_rocker.id, + zigbee_test_utils.build_attr_config(mock_device_t1_double_rocker, MULTISTATE_INPUT_CLUSTER_ID, PRESENT_ATTRIBUTE_ID, + 0x0003, 0x1C20, data_types.Uint16, 0x0001) }) - test.socket.zigbee:__expect_send({ mock_device_t1.id, - cluster_base.write_manufacturer_specific_attribute(mock_device_t1, PRIVATE_CLUSTER_ID, PRIVATE_ATTRIBUTE_ID_T1, MFG_CODE, + test.socket.zigbee:__expect_send({ mock_device_t1_double_rocker.id, + cluster_base.write_manufacturer_specific_attribute(mock_device_t1_double_rocker, PRIVATE_CLUSTER_ID, + PRIVATE_ATTRIBUTE_ID_T1, MFG_CODE, data_types.Uint8, 1) }) - mock_device_t1:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + mock_device_t1_double_rocker:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end ) @@ -160,10 +162,13 @@ test.register_coroutine_test( { PRESENT_ATTRIBUTE_ID, data_types.Uint16.ID, 0x0001 } } test.socket.zigbee:__queue_receive({ - mock_device_e1.id, - zigbee_test_utils.build_attribute_report(mock_device_e1, MULTISTATE_INPUT_CLUSTER_ID, attr_report_data, MFG_CODE) + mock_device_t1_double_rocker.id, + zigbee_test_utils.build_attribute_report(mock_device_t1_double_rocker, MULTISTATE_INPUT_CLUSTER_ID, + attr_report_data, MFG_CODE) }) - test.socket.capability:__expect_send(mock_device_e1:generate_test_message("main", + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message("main", + capabilities.button.button.pushed({ state_change = true }))) + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message("button1", capabilities.button.button.pushed({state_change = true}))) end ) @@ -175,10 +180,13 @@ test.register_coroutine_test( { PRESENT_ATTRIBUTE_ID, data_types.Uint16.ID, 0x0002 } } test.socket.zigbee:__queue_receive({ - mock_device_e1.id, - zigbee_test_utils.build_attribute_report(mock_device_e1, MULTISTATE_INPUT_CLUSTER_ID, attr_report_data, MFG_CODE) + mock_device_t1_double_rocker.id, + zigbee_test_utils.build_attribute_report(mock_device_t1_double_rocker, MULTISTATE_INPUT_CLUSTER_ID, + attr_report_data, MFG_CODE) }) - test.socket.capability:__expect_send(mock_device_e1:generate_test_message("main", + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message("main", + capabilities.button.button.double({ state_change = true }))) + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message("button1", capabilities.button.button.double({state_change = true}))) end ) @@ -190,16 +198,19 @@ test.register_coroutine_test( { PRESENT_ATTRIBUTE_ID, data_types.Uint16.ID, 0x0000 } } test.socket.zigbee:__queue_receive({ - mock_device_e1.id, - zigbee_test_utils.build_attribute_report(mock_device_e1, MULTISTATE_INPUT_CLUSTER_ID, attr_report_data, MFG_CODE) + mock_device_t1_double_rocker.id, + zigbee_test_utils.build_attribute_report(mock_device_t1_double_rocker, MULTISTATE_INPUT_CLUSTER_ID, + attr_report_data, MFG_CODE) }) - test.socket.capability:__expect_send(mock_device_e1:generate_test_message("main", + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message("main", capabilities.button.button.held({state_change = true}))) + test.socket.capability:__expect_send(mock_device_t1_double_rocker:generate_test_message("button1", + capabilities.button.button.held({ state_change = true }))) end ) test.register_message_test( - "Battery voltage report should be handled", + "Battery Level - Normal", { { channel = "zigbee", @@ -209,9 +220,38 @@ test.register_message_test( { channel = "capability", direction = "send", - message = mock_device_e1:generate_test_message("main", capabilities.battery.battery(100)) + message = mock_device_e1:generate_test_message("main", capabilities.batteryLevel.battery("normal")) + } + } +) +test.register_message_test( + "Battery Level - Warning", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_e1.id, PowerConfiguration.attributes.BatteryVoltage:build_test_attr_report(mock_device_e1, 27) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_e1:generate_test_message("main", capabilities.batteryLevel.battery("warning")) + } + } +) +test.register_message_test( + "Battery Level - Critical", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_e1.id, PowerConfiguration.attributes.BatteryVoltage:build_test_attr_report(mock_device_e1, 20) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_e1:generate_test_message("main", capabilities.batteryLevel.battery("critical")) } } ) - test.run_registered_tests() From e7dc7d5792bac7fa146e550927fe7cb6663c50b8 Mon Sep 17 00:00:00 2001 From: seojune Date: Mon, 13 Oct 2025 10:34:42 +0900 Subject: [PATCH 2/3] change the categories of the main component from 'Button' to 'RemoteController' in the 'aqara-double-buttons' profile --- .../SmartThings/zigbee-button/profiles/aqara-double-buttons.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/SmartThings/zigbee-button/profiles/aqara-double-buttons.yml b/drivers/SmartThings/zigbee-button/profiles/aqara-double-buttons.yml index 09bcd2b1f4..38ad8b57db 100644 --- a/drivers/SmartThings/zigbee-button/profiles/aqara-double-buttons.yml +++ b/drivers/SmartThings/zigbee-button/profiles/aqara-double-buttons.yml @@ -9,7 +9,7 @@ components: - id: refresh version: 1 categories: - - name: Button + - name: RemoteController - id: button1 capabilities: - id: button From d1841bf71c7cd0aa3c2edc8259d9c921978d743f Mon Sep 17 00:00:00 2001 From: seojune Date: Fri, 24 Oct 2025 11:03:56 +0900 Subject: [PATCH 3/3] Added the firmwareUpdate capability to aqara-single-button.yml and renamed the file to one-button-batteryLevel.yml. --- drivers/SmartThings/zigbee-button/fingerprints.yml | 2 +- .../{aqara-single-button.yml => one-button-batteryLevel.yml} | 4 +++- .../SmartThings/zigbee-button/src/test/test_aqara_button.lua | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) rename drivers/SmartThings/zigbee-button/profiles/{aqara-single-button.yml => one-button-batteryLevel.yml} (72%) diff --git a/drivers/SmartThings/zigbee-button/fingerprints.yml b/drivers/SmartThings/zigbee-button/fingerprints.yml index 83db2a9062..592f91dd4d 100644 --- a/drivers/SmartThings/zigbee-button/fingerprints.yml +++ b/drivers/SmartThings/zigbee-button/fingerprints.yml @@ -18,7 +18,7 @@ zigbeeManufacturer: deviceLabel: Aqara Wireless Remote Switch T1 (Single Rocker) manufacturer: LUMI model: lumi.remote.b186acn03 - deviceProfileName: aqara-single-button + deviceProfileName: one-button-batteryLevel - id: "LUMI/lumi.remote.b286acn03" deviceLabel: Aqara Wireless Remote Switch T1 (Double Rocker) manufacturer: LUMI diff --git a/drivers/SmartThings/zigbee-button/profiles/aqara-single-button.yml b/drivers/SmartThings/zigbee-button/profiles/one-button-batteryLevel.yml similarity index 72% rename from drivers/SmartThings/zigbee-button/profiles/aqara-single-button.yml rename to drivers/SmartThings/zigbee-button/profiles/one-button-batteryLevel.yml index 9570b1fdd8..005e41256f 100644 --- a/drivers/SmartThings/zigbee-button/profiles/aqara-single-button.yml +++ b/drivers/SmartThings/zigbee-button/profiles/one-button-batteryLevel.yml @@ -1,4 +1,4 @@ -name: aqara-single-button +name: one-button-batteryLevel components: - id: main capabilities: @@ -6,6 +6,8 @@ components: version: 1 - id: batteryLevel version: 1 + - id: firmwareUpdate + version: 1 - id: refresh version: 1 categories: 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 31dc55fb20..1d7b6d090c 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_aqara_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_aqara_button.lua @@ -32,7 +32,7 @@ local PRIVATE_ATTRIBUTE_ID_E1 = 0x0125 local COMP_LIST = { "button1", "button2", "all" } local mock_device_e1 = test.mock_device.build_test_zigbee_device( { - profile = t_utils.get_profile_definition("aqara-single-button.yml"), + profile = t_utils.get_profile_definition("one-button-batteryLevel.yml"), zigbee_endpoints = { [1] = { id = 1,