diff --git a/drivers/SmartThings/zigbee-button/fingerprints.yml b/drivers/SmartThings/zigbee-button/fingerprints.yml index 7acc77387f..61285448f7 100644 --- a/drivers/SmartThings/zigbee-button/fingerprints.yml +++ b/drivers/SmartThings/zigbee-button/fingerprints.yml @@ -8,12 +8,22 @@ zigbeeManufacturer: deviceLabel: Aqara Wireless Mini Switch T1 manufacturer: LUMI model: lumi.remote.b1acn02 - deviceProfileName: one-button-battery + deviceProfileName: one-button-batteryLevel - id: "LUMI/lumi.remote.acn003" deviceLabel: Aqara Wireless Remote Switch E1 (Single Rocker) manufacturer: LUMI model: lumi.remote.acn003 - deviceProfileName: one-button-battery + deviceProfileName: one-button-batteryLevel + - id: "LUMI/lumi.remote.b186acn03" + deviceLabel: Aqara Wireless Remote Switch T1 (Single Rocker) + manufacturer: LUMI + model: lumi.remote.b186acn03 + deviceProfileName: one-button-batteryLevel + - 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..38ad8b57db --- /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: RemoteController + - 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/one-button-batteryLevel.yml b/drivers/SmartThings/zigbee-button/profiles/one-button-batteryLevel.yml new file mode 100644 index 0000000000..005e41256f --- /dev/null +++ b/drivers/SmartThings/zigbee-button/profiles/one-button-batteryLevel.yml @@ -0,0 +1,14 @@ +name: one-button-batteryLevel +components: + - id: main + capabilities: + - id: button + version: 1 + - id: batteryLevel + version: 1 + - id: firmwareUpdate + 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..1d7b6d090c 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("one-button-batteryLevel.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()