From 7a4d85656f8f92ea8ca3fd77cb399041e43a0ae5 Mon Sep 17 00:00:00 2001 From: zhongpei-ge Date: Tue, 11 Feb 2025 16:56:39 +0800 Subject: [PATCH 1/6] add support for generic zigbee sensor --- drivers/SmartThings/zigbee-sensor/config.yml | 6 + .../zigbee-sensor/fingerprints.yml | 8 + .../profiles/generic-contact-sensor.yml | 14 + .../profiles/generic-motion-sensor.yml | 14 + .../zigbee-sensor/profiles/generic-sensor.yml | 8 + .../profiles/generic-waterleak-sensor.yml | 14 + .../SmartThings/zigbee-sensor/src/init.lua | 157 +++++++ .../src/test/test_zigbee_sensor.lua | 429 ++++++++++++++++++ 8 files changed, 650 insertions(+) create mode 100644 drivers/SmartThings/zigbee-sensor/config.yml create mode 100644 drivers/SmartThings/zigbee-sensor/fingerprints.yml create mode 100644 drivers/SmartThings/zigbee-sensor/profiles/generic-contact-sensor.yml create mode 100644 drivers/SmartThings/zigbee-sensor/profiles/generic-motion-sensor.yml create mode 100644 drivers/SmartThings/zigbee-sensor/profiles/generic-sensor.yml create mode 100644 drivers/SmartThings/zigbee-sensor/profiles/generic-waterleak-sensor.yml create mode 100644 drivers/SmartThings/zigbee-sensor/src/init.lua create mode 100644 drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua diff --git a/drivers/SmartThings/zigbee-sensor/config.yml b/drivers/SmartThings/zigbee-sensor/config.yml new file mode 100644 index 0000000000..7bfe5e3e7c --- /dev/null +++ b/drivers/SmartThings/zigbee-sensor/config.yml @@ -0,0 +1,6 @@ +name: 'Zigbee Sensor' +packageKey: 'zigbee-sensor' +permissions: + zigbee: {} +description: "SmartThings driver for Zigbee sensor devices" +vendorSupportInformation: "https://support.smartthings.com" diff --git a/drivers/SmartThings/zigbee-sensor/fingerprints.yml b/drivers/SmartThings/zigbee-sensor/fingerprints.yml new file mode 100644 index 0000000000..e2c067ad44 --- /dev/null +++ b/drivers/SmartThings/zigbee-sensor/fingerprints.yml @@ -0,0 +1,8 @@ +zigbeeGeneric: + - id: "generic-sensor" + deviceLabel: "Zigbee Generic Sensor" + clusters: + server: + - 0x0500 + deviceProfileName: generic-sensor + diff --git a/drivers/SmartThings/zigbee-sensor/profiles/generic-contact-sensor.yml b/drivers/SmartThings/zigbee-sensor/profiles/generic-contact-sensor.yml new file mode 100644 index 0000000000..a58cbc5214 --- /dev/null +++ b/drivers/SmartThings/zigbee-sensor/profiles/generic-contact-sensor.yml @@ -0,0 +1,14 @@ +name: generic-contact-sensor +components: +- id: main + capabilities: + - id: batteryLevel + version: 1 + - id: contactSensor + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: ContactSensor diff --git a/drivers/SmartThings/zigbee-sensor/profiles/generic-motion-sensor.yml b/drivers/SmartThings/zigbee-sensor/profiles/generic-motion-sensor.yml new file mode 100644 index 0000000000..0fb385103e --- /dev/null +++ b/drivers/SmartThings/zigbee-sensor/profiles/generic-motion-sensor.yml @@ -0,0 +1,14 @@ +name: generic-motion-sensor +components: +- id: main + capabilities: + - id: batteryLevel + version: 1 + - id: motionSensor + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: MotionSensor diff --git a/drivers/SmartThings/zigbee-sensor/profiles/generic-sensor.yml b/drivers/SmartThings/zigbee-sensor/profiles/generic-sensor.yml new file mode 100644 index 0000000000..882e61bcf8 --- /dev/null +++ b/drivers/SmartThings/zigbee-sensor/profiles/generic-sensor.yml @@ -0,0 +1,8 @@ +name: generic-sensor +components: +- id: main + capabilities: + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 \ No newline at end of file diff --git a/drivers/SmartThings/zigbee-sensor/profiles/generic-waterleak-sensor.yml b/drivers/SmartThings/zigbee-sensor/profiles/generic-waterleak-sensor.yml new file mode 100644 index 0000000000..dbc0524bf7 --- /dev/null +++ b/drivers/SmartThings/zigbee-sensor/profiles/generic-waterleak-sensor.yml @@ -0,0 +1,14 @@ +name: generic-waterleak-sensor +components: +- id: main + capabilities: + - id: batteryLevel + version: 1 + - id: waterSensor + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: LeakSensor diff --git a/drivers/SmartThings/zigbee-sensor/src/init.lua b/drivers/SmartThings/zigbee-sensor/src/init.lua new file mode 100644 index 0000000000..142aa14612 --- /dev/null +++ b/drivers/SmartThings/zigbee-sensor/src/init.lua @@ -0,0 +1,157 @@ +-- Copyright 2025 SmartThings +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +local ZigbeeDriver = require "st.zigbee" +local defaults = require "st.zigbee.defaults" +local clusters = require "st.zigbee.zcl.clusters" +local IASZone = clusters.IASZone +local capabilities = require "st.capabilities" +local ZONETYPE = "ZoneType" +local constants = require "st.zigbee.constants" +local PowerConfiguration = clusters.PowerConfiguration +local device_management = require "st.zigbee.device_management" + +local CONTACT_SWITCH = 0x0015 +local MOTION_SENSOR = 0x000D +local WATER_SENSOR = 0x002A + +local ZIGBEE_GENERIC_SENSOR_PROFILE = "generic-sensor" +local ZIGBEE_GENERIC_CONTACT_SENSOR_PROFILE = "generic-contact-sensor" +local ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE = "generic-motion-sensor" +local ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE = "generic-waterleak-sensor" + +-- ask device to upload its zone type +local ias_device_added = function(driver, device) + device:send(IASZone.attributes.ZoneType:read(device)) +end + +-- ask device to upload its zone status, then the status of capabilities can be synchronized +local ias_info_changed = function(driver, device) + device:send(IASZone.attributes.ZoneStatus:read(device)) +end + +-- update profile with different zone type +local function update_profile(device, zone_type) + local profile = ZIGBEE_GENERIC_SENSOR_PROFILE + if zone_type == CONTACT_SWITCH then + profile = ZIGBEE_GENERIC_CONTACT_SENSOR_PROFILE + elseif zone_type == MOTION_SENSOR then + profile = ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE + elseif zone_type == WATER_SENSOR then + profile = ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE + end + + device:try_update_metadata({profile = profile}) +end + +-- read zone type and update profile +local ias_zone_type_attr_handler = function (driver, device, attr_val) + device:set_field(ZONETYPE, attr_val.value) + update_profile(device, attr_val.value) +end + +-- since we don't have button devices using IASZone, the driver here is remaining to be updated +local generate_event_from_zone_status = function(driver, device, zone_status, zb_rx) + local type = device:get_field(ZONETYPE) + local event + if type == CONTACT_SWITCH then + if zone_status:is_alarm1_set() then + event = capabilities.contactSensor.contact.open() + else + event = capabilities.contactSensor.contact.closed() + end + elseif type == MOTION_SENSOR then + if zone_status:is_alarm1_set() then + event = capabilities.motionSensor.motion.active() + else + event = capabilities.motionSensor.motion.inactive() + end + elseif type == WATER_SENSOR then + if zone_status:is_alarm1_set() then + event = capabilities.waterSensor.water.wet() + else + event = capabilities.waterSensor.water.dry() + end + end + if event ~= nil then + device:emit_event_for_endpoint( + zb_rx.address_header.src_endpoint.value, + event) + if device:get_component_id_for_endpoint(zb_rx.address_header.src_endpoint.value) ~= "main" then + device:emit_event(event) + end + end +end + +local ias_zone_status_attr_handler = function(driver, device, zone_status, zb_rx) + generate_event_from_zone_status(driver, device, zone_status, zb_rx) +end + +local ias_zone_status_change_handler = function(driver, device, zb_rx) + generate_event_from_zone_status(driver, device, zb_rx.body.zcl_body.zone_status, zb_rx) +end + +local battery_level_handler = function(driver, device, value, zb_rx) + local voltage = value.value + if voltage <= 25 then + device:emit_event(capabilities.batteryLevel.battery.critical()) + elseif voltage < 28 then + device:emit_event(capabilities.batteryLevel.battery.warning()) + else + device:emit_event(capabilities.batteryLevel.battery.normal()) + end +end + +local configure_handler = function(self, device) + device:send(device_management.build_bind_request(device, PowerConfiguration.ID, self.environment_info.hub_zigbee_eui)) + device:send(PowerConfiguration.attributes.BatteryVoltage:configure_reporting(device, 30, 21600, 1)) + device:send(PowerConfiguration.attributes.BatteryVoltage:read(device)) +end + +local zigbee_generic_sensor_template = { + supported_capabilities = { + capabilities.batteryLevel, + capabilities.firmwareUpdate, + capabilities.refresh + -- capabilities.motionSensor, + -- capabilities.contactSensor, + -- capabilities.waterSensor + }, + zigbee_handlers = { + attr = { + [IASZone.ID] = { + [IASZone.attributes.ZoneType.ID] = ias_zone_type_attr_handler, + [IASZone.attributes.ZoneStatus.ID] = ias_zone_status_attr_handler + }, + [PowerConfiguration.ID] = { + [PowerConfiguration.attributes.BatteryVoltage.ID] = battery_level_handler + } + }, + cluster = { + [IASZone.ID] = { + [IASZone.client.commands.ZoneStatusChangeNotification.ID] = ias_zone_status_change_handler + } + } + }, + lifecycle_handlers = { + added = ias_device_added, + doConfigure = configure_handler, + infoChanged = ias_info_changed + }, + ias_zone_configuration_method = constants.IAS_ZONE_CONFIGURE_TYPE.AUTO_ENROLL_RESPONSE +} + +defaults.register_for_default_handlers(zigbee_generic_sensor_template, zigbee_generic_sensor_template.supported_capabilities) +local zigbee_sensor = ZigbeeDriver("zigbee-sensor", zigbee_generic_sensor_template) +zigbee_sensor:run() diff --git a/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua b/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua new file mode 100644 index 0000000000..d4a2846dd6 --- /dev/null +++ b/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua @@ -0,0 +1,429 @@ +-- Copyright 2025 SmartThings +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +local test = require "integration_test" +local zigbee_test_utils = require "integration_test.zigbee_test_utils" +local clusters = require "st.zigbee.zcl.clusters" +local IASZone = clusters.IASZone +local capabilities = require "st.capabilities" +local IasEnrollResponseCode = require "st.zigbee.generated.zcl_clusters.IASZone.types.EnrollResponseCode" +local t_utils = require "integration_test.utils" + +local ZoneStatusAttribute = IASZone.attributes.ZoneStatus + +local ZONETYPE = "ZoneType" +local Contact_Switch = 21 -- 0x0015 +local Motion_Sensor = 13 -- 0x000d +local Water_Sensor = 42 -- 0x002a +local ZIGBEE_GENERIC_CONTACT_SENSOR_PROFILE = "generic-contact-sensor" +local ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE = "generic-motion-sensor" +local ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE = "generic-waterleak-sensor" + +local log = require "log" + + + +local mock_device_contact_sensor = test.mock_device.build_test_zigbee_device( + { + profile = t_utils.get_profile_definition(ZIGBEE_GENERIC_CONTACT_SENSOR_PROFILE .. ".yml"), + zigbee_endpoints = { + [1] = { + id = 1, + server_clusters = { 0x0500 } + } + } + } +) + +local mock_device_motion_sensor = test.mock_device.build_test_zigbee_device( + { + profile = t_utils.get_profile_definition(ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE .. ".yml"), + zigbee_endpoints = { + [1] = { + id = 1, + server_clusters = { 0x0500 } + } + } + } +) + +local mock_device_waterleak_sensor = test.mock_device.build_test_zigbee_device( + { + profile = t_utils.get_profile_definition(ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE .. ".yml"), + zigbee_endpoints = { + [1] = { + id = 1, + server_clusters = { 0x0500 } + } + } + } +) + +zigbee_test_utils.prepare_zigbee_env_info() +local function test_init() + mock_device_contact_sensor:set_field(ZONETYPE, Contact_Switch, { persist = true }) + mock_device_motion_sensor:set_field(ZONETYPE, Motion_Sensor, { persist = true }) + mock_device_waterleak_sensor:set_field(ZONETYPE, Water_Sensor, { persist = true }) + test.mock_device.add_test_device(mock_device_contact_sensor) + test.mock_device.add_test_device(mock_device_motion_sensor) + test.mock_device.add_test_device(mock_device_waterleak_sensor) + zigbee_test_utils.init_noop_health_check_timer() +end + +test.set_test_init_function(test_init) + +test.register_message_test( + "Reported contact should be handled: open", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_contact_sensor.id, ZoneStatusAttribute:build_test_attr_report(mock_device_contact_sensor, 0x0001) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_contact_sensor:generate_test_message("main", capabilities.contactSensor.contact.open()) + } + } +) + +test.register_message_test( + "Reported contact should be handled: closed", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_contact_sensor.id, ZoneStatusAttribute:build_test_attr_report(mock_device_contact_sensor, 0x0000) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_contact_sensor:generate_test_message("main", capabilities.contactSensor.contact.closed()) + } + } +) + +test.register_message_test( + "ZoneStatusChangeNotification from contact sensor should be handled: open", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_contact_sensor.id, IASZone.client.commands.ZoneStatusChangeNotification.build_test_rx(mock_device_contact_sensor, + 0x0001, + 0x00) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_contact_sensor:generate_test_message("main", capabilities.contactSensor.contact.open()) + } + } +) + +test.register_message_test( + "ZoneStatusChangeNotification from contact sensor should be handled: closed", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_contact_sensor.id, IASZone.client.commands.ZoneStatusChangeNotification.build_test_rx(mock_device_contact_sensor, + 0x0000, + 0x00) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_contact_sensor:generate_test_message("main", capabilities.contactSensor.contact.closed()) + } + } +) + +test.register_message_test( + "Reported motion should be handled: active", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_motion_sensor.id, ZoneStatusAttribute:build_test_attr_report(mock_device_motion_sensor, 0x0001) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_motion_sensor:generate_test_message("main", capabilities.motionSensor.motion.active()) + } + } +) + +test.register_message_test( + "Reported motion should be handled: inactive", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_motion_sensor.id, ZoneStatusAttribute:build_test_attr_report(mock_device_motion_sensor, 0x0000) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_motion_sensor:generate_test_message("main", capabilities.motionSensor.motion.inactive()) + } + } +) + +test.register_message_test( + "ZoneStatusChangeNotification from motion sensor should be handled: active", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_motion_sensor.id, IASZone.client.commands.ZoneStatusChangeNotification.build_test_rx(mock_device_motion_sensor, 0x0001, 0x00) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_motion_sensor:generate_test_message("main", capabilities.motionSensor.motion.active()) + } + } +) + +test.register_message_test( + "ZoneStatusChangeNotification from motion sensor should be handled: inactive", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_motion_sensor.id, IASZone.client.commands.ZoneStatusChangeNotification.build_test_rx(mock_device_motion_sensor, 0x0000, 0x00) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_motion_sensor:generate_test_message("main", capabilities.motionSensor.motion.inactive()) + } + } +) + +test.register_message_test( + "Reported water should be handled: wet", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_waterleak_sensor.id, ZoneStatusAttribute:build_test_attr_report(mock_device_waterleak_sensor, 0x0001) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_waterleak_sensor:generate_test_message("main", capabilities.waterSensor.water.wet()) + } + } +) + +test.register_message_test( + "Reported water should be handled: dry", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_waterleak_sensor.id, ZoneStatusAttribute:build_test_attr_report(mock_device_waterleak_sensor, 0x0000) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_waterleak_sensor:generate_test_message("main", capabilities.waterSensor.water.dry()) + } + } +) + +test.register_message_test( + "ZoneStatusChangeNotification from waterleak sensor should be handled: wet", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_waterleak_sensor.id, IASZone.client.commands.ZoneStatusChangeNotification.build_test_rx(mock_device_waterleak_sensor, 0x0001, 0x00) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_waterleak_sensor:generate_test_message("main", capabilities.waterSensor.water.wet()) + } + } +) + +test.register_message_test( + "ZoneStatusChangeNotification from waterleak sensor should be handled: dry", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_waterleak_sensor.id, IASZone.client.commands.ZoneStatusChangeNotification.build_test_rx(mock_device_waterleak_sensor, 0x0000, 0x00) } + }, + { + channel = "capability", + direction = "send", + message = mock_device_waterleak_sensor:generate_test_message("main", capabilities.waterSensor.water.dry()) + } + } +) + +test.register_coroutine_test( + "Health check should check all relevant attributes(contact)", + function() + test.socket.device_lifecycle:__queue_receive({ mock_device_contact_sensor.id, "added" }) + test.socket.zigbee:__expect_send({ + mock_device_contact_sensor.id, + IASZone.attributes.ZoneType:read(mock_device_contact_sensor) + }) + test.wait_for_events() + + -- test.mock_time.advance_time(50000) + -- test.socket.zigbee:__set_channel_ordering("relaxed") + -- test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_contact_sensor) }) + -- test.wait_for_events() + end, + { + test_init = function() + test.mock_device.add_test_device(mock_device_contact_sensor) + test.timer.__create_and_queue_test_time_advance_timer(30, "interval", "health_check") + end + } +) + +test.register_coroutine_test( + "Health check should check all relevant attributes(motion)", + function() + test.socket.device_lifecycle:__queue_receive({ mock_device_motion_sensor.id, "added" }) + test.socket.zigbee:__expect_send({ + mock_device_motion_sensor.id, + IASZone.attributes.ZoneType:read(mock_device_motion_sensor) + }) + test.wait_for_events() + + -- test.mock_time.advance_time(50000) + -- test.socket.zigbee:__set_channel_ordering("relaxed") + -- test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_motion_sensor) }) + -- test.wait_for_events() + end, + { + test_init = function() + test.mock_device.add_test_device(mock_device_motion_sensor) + test.timer.__create_and_queue_test_time_advance_timer(30, "interval", "health_check") + end + } +) + +test.register_coroutine_test( + "Health check should check all relevant attributes(waterleak)", + function() + test.socket.device_lifecycle:__queue_receive({ mock_device_waterleak_sensor.id, "added" }) + test.socket.zigbee:__expect_send({ + mock_device_waterleak_sensor.id, + IASZone.attributes.ZoneType:read(mock_device_waterleak_sensor) + }) + test.wait_for_events() + + -- test.mock_time.advance_time(50000) + -- test.socket.zigbee:__set_channel_ordering("relaxed") + -- test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_waterleak_sensor) }) + -- test.wait_for_events() + end, + { + test_init = function() + test.mock_device.add_test_device(mock_device_waterleak_sensor) + test.timer.__create_and_queue_test_time_advance_timer(30, "interval", "health_check") + end + } +) + +test.register_coroutine_test( + "Refresh necessary attributes(contact)", + function() + test.wait_for_events() + + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.capability:__queue_receive({ mock_device_contact_sensor.id, { capability = "refresh", component = "main", command = "refresh", args = {} } }) + test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_contact_sensor) }) + end +) + +test.register_coroutine_test( + "Refresh necessary attributes(motion)", + function() + test.wait_for_events() + + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.capability:__queue_receive({ mock_device_motion_sensor.id, { capability = "refresh", component = "main", command = "refresh", args = {} } }) + test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_motion_sensor) }) + end +) + +test.register_coroutine_test( + "Refresh necessary attributes(waterleak)", + function() + test.wait_for_events() + + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.capability:__queue_receive({ mock_device_waterleak_sensor.id, { capability = "refresh", component = "main", command = "refresh", args = {} } }) + test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_waterleak_sensor) }) + end +) + +test.register_coroutine_test( + "Configure should configure all necessary attributes(contact)", + function() + test.socket.device_lifecycle:__queue_receive({ mock_device_contact_sensor.id, "added" }) + test.socket.zigbee:__expect_send({ + mock_device_contact_sensor.id, + IASZone.attributes.ZoneType:read(mock_device_contact_sensor) + }) + test.wait_for_events() + + test.socket.zigbee:__set_channel_ordering("relaxed") + mock_device_contact_sensor:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + end +) + +test.register_coroutine_test( + "Configure should configure all necessary attributes(motion)", + function() + test.socket.device_lifecycle:__queue_receive({ mock_device_motion_sensor.id, "added" }) + test.socket.zigbee:__expect_send({ + mock_device_motion_sensor.id, + IASZone.attributes.ZoneType:read(mock_device_motion_sensor) + }) + test.wait_for_events() + + test.socket.zigbee:__set_channel_ordering("relaxed") + mock_device_contact_sensor:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + end +) + +test.register_coroutine_test( + "Configure should configure all necessary attributes(waterleak)", + function() + test.socket.device_lifecycle:__queue_receive({ mock_device_waterleak_sensor.id, "added" }) + test.socket.zigbee:__expect_send({ + mock_device_waterleak_sensor.id, + IASZone.attributes.ZoneType:read(mock_device_waterleak_sensor) + }) + test.wait_for_events() + + test.socket.zigbee:__set_channel_ordering("relaxed") + mock_device_waterleak_sensor:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + end +) + +test.run_registered_tests() \ No newline at end of file From 6b7d791edd546d204fe276aec25cdb0fdcc418b9 Mon Sep 17 00:00:00 2001 From: frank-huang Date: Wed, 19 Feb 2025 18:53:52 +0800 Subject: [PATCH 2/6] Replace batteryLevel with battery Signed-off-by: frank-huang --- .../profiles/generic-contact-sensor.yml | 4 +- .../profiles/generic-motion-sensor.yml | 4 +- .../zigbee-sensor/profiles/generic-sensor.yml | 2 + .../profiles/generic-waterleak-sensor.yml | 4 +- .../SmartThings/zigbee-sensor/src/init.lua | 52 +++++++------------ 5 files changed, 27 insertions(+), 39 deletions(-) diff --git a/drivers/SmartThings/zigbee-sensor/profiles/generic-contact-sensor.yml b/drivers/SmartThings/zigbee-sensor/profiles/generic-contact-sensor.yml index a58cbc5214..8d07bcc70e 100644 --- a/drivers/SmartThings/zigbee-sensor/profiles/generic-contact-sensor.yml +++ b/drivers/SmartThings/zigbee-sensor/profiles/generic-contact-sensor.yml @@ -2,10 +2,10 @@ name: generic-contact-sensor components: - id: main capabilities: - - id: batteryLevel - version: 1 - id: contactSensor version: 1 + - id: battery + version: 1 - id: firmwareUpdate version: 1 - id: refresh diff --git a/drivers/SmartThings/zigbee-sensor/profiles/generic-motion-sensor.yml b/drivers/SmartThings/zigbee-sensor/profiles/generic-motion-sensor.yml index 0fb385103e..c126485be9 100644 --- a/drivers/SmartThings/zigbee-sensor/profiles/generic-motion-sensor.yml +++ b/drivers/SmartThings/zigbee-sensor/profiles/generic-motion-sensor.yml @@ -2,10 +2,10 @@ name: generic-motion-sensor components: - id: main capabilities: - - id: batteryLevel - version: 1 - id: motionSensor version: 1 + - id: battery + version: 1 - id: firmwareUpdate version: 1 - id: refresh diff --git a/drivers/SmartThings/zigbee-sensor/profiles/generic-sensor.yml b/drivers/SmartThings/zigbee-sensor/profiles/generic-sensor.yml index 882e61bcf8..c91fdca717 100644 --- a/drivers/SmartThings/zigbee-sensor/profiles/generic-sensor.yml +++ b/drivers/SmartThings/zigbee-sensor/profiles/generic-sensor.yml @@ -2,6 +2,8 @@ name: generic-sensor components: - id: main capabilities: + - id: battery + version: 1 - id: firmwareUpdate version: 1 - id: refresh diff --git a/drivers/SmartThings/zigbee-sensor/profiles/generic-waterleak-sensor.yml b/drivers/SmartThings/zigbee-sensor/profiles/generic-waterleak-sensor.yml index dbc0524bf7..45b0ed2a9d 100644 --- a/drivers/SmartThings/zigbee-sensor/profiles/generic-waterleak-sensor.yml +++ b/drivers/SmartThings/zigbee-sensor/profiles/generic-waterleak-sensor.yml @@ -2,10 +2,10 @@ name: generic-waterleak-sensor components: - id: main capabilities: - - id: batteryLevel - version: 1 - id: waterSensor version: 1 + - id: battery + version: 1 - id: firmwareUpdate version: 1 - id: refresh diff --git a/drivers/SmartThings/zigbee-sensor/src/init.lua b/drivers/SmartThings/zigbee-sensor/src/init.lua index 142aa14612..815970f25c 100644 --- a/drivers/SmartThings/zigbee-sensor/src/init.lua +++ b/drivers/SmartThings/zigbee-sensor/src/init.lua @@ -20,7 +20,11 @@ local capabilities = require "st.capabilities" local ZONETYPE = "ZoneType" local constants = require "st.zigbee.constants" local PowerConfiguration = clusters.PowerConfiguration -local device_management = require "st.zigbee.device_management" +local battery_defaults = require "st.zigbee.defaults.battery_defaults" +local utils = require "st.utils" +local battery_config = utils.deep_copy(battery_defaults.default_percentage_configuration) +battery_config.reportable_change = 0x10 +battery_config.data_type = clusters.PowerConfiguration.attributes.BatteryVoltage.base_type local CONTACT_SWITCH = 0x0015 local MOTION_SENSOR = 0x000D @@ -31,16 +35,18 @@ local ZIGBEE_GENERIC_CONTACT_SENSOR_PROFILE = "generic-contact-sensor" local ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE = "generic-motion-sensor" local ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE = "generic-waterleak-sensor" +local device_init = function(self, device) + device:add_configured_attribute(battery_config) + device:add_monitored_attribute(battery_config) +end + -- ask device to upload its zone type local ias_device_added = function(driver, device) device:send(IASZone.attributes.ZoneType:read(device)) -end - --- ask device to upload its zone status, then the status of capabilities can be synchronized -local ias_info_changed = function(driver, device) device:send(IASZone.attributes.ZoneStatus:read(device)) end + -- update profile with different zone type local function update_profile(device, zone_type) local profile = ZIGBEE_GENERIC_SENSOR_PROFILE @@ -68,12 +74,16 @@ local generate_event_from_zone_status = function(driver, device, zone_status, zb if type == CONTACT_SWITCH then if zone_status:is_alarm1_set() then event = capabilities.contactSensor.contact.open() + elseif zone_status:is_alarm2_set() then + event = capabilities.contactSensor.contact.open() else event = capabilities.contactSensor.contact.closed() end elseif type == MOTION_SENSOR then if zone_status:is_alarm1_set() then event = capabilities.motionSensor.motion.active() + elseif zone_status:is_alarm2_set() then + event = capabilities.motionSensor.motion.active() else event = capabilities.motionSensor.motion.inactive() end @@ -102,40 +112,17 @@ local ias_zone_status_change_handler = function(driver, device, zb_rx) generate_event_from_zone_status(driver, device, zb_rx.body.zcl_body.zone_status, zb_rx) end -local battery_level_handler = function(driver, device, value, zb_rx) - local voltage = value.value - if voltage <= 25 then - device:emit_event(capabilities.batteryLevel.battery.critical()) - elseif voltage < 28 then - device:emit_event(capabilities.batteryLevel.battery.warning()) - else - device:emit_event(capabilities.batteryLevel.battery.normal()) - end -end - -local configure_handler = function(self, device) - device:send(device_management.build_bind_request(device, PowerConfiguration.ID, self.environment_info.hub_zigbee_eui)) - device:send(PowerConfiguration.attributes.BatteryVoltage:configure_reporting(device, 30, 21600, 1)) - device:send(PowerConfiguration.attributes.BatteryVoltage:read(device)) -end - local zigbee_generic_sensor_template = { supported_capabilities = { - capabilities.batteryLevel, + capabilities.battery, capabilities.firmwareUpdate, capabilities.refresh - -- capabilities.motionSensor, - -- capabilities.contactSensor, - -- capabilities.waterSensor }, zigbee_handlers = { attr = { [IASZone.ID] = { [IASZone.attributes.ZoneType.ID] = ias_zone_type_attr_handler, [IASZone.attributes.ZoneStatus.ID] = ias_zone_status_attr_handler - }, - [PowerConfiguration.ID] = { - [PowerConfiguration.attributes.BatteryVoltage.ID] = battery_level_handler } }, cluster = { @@ -145,13 +132,12 @@ local zigbee_generic_sensor_template = { } }, lifecycle_handlers = { - added = ias_device_added, - doConfigure = configure_handler, - infoChanged = ias_info_changed + init = device_init, + added = ias_device_added }, ias_zone_configuration_method = constants.IAS_ZONE_CONFIGURE_TYPE.AUTO_ENROLL_RESPONSE } defaults.register_for_default_handlers(zigbee_generic_sensor_template, zigbee_generic_sensor_template.supported_capabilities) local zigbee_sensor = ZigbeeDriver("zigbee-sensor", zigbee_generic_sensor_template) -zigbee_sensor:run() +zigbee_sensor:run() \ No newline at end of file From fa1311cc8922e2418150ec69a2d6cb85813cdfd9 Mon Sep 17 00:00:00 2001 From: frank-huang Date: Fri, 21 Feb 2025 15:54:01 +0800 Subject: [PATCH 3/6] Add test cases for added, receiving zonetype and profile changing Signed-off-by: frank-huang --- .../src/test/test_zigbee_sensor.lua | 90 +++++++++++++++---- 1 file changed, 74 insertions(+), 16 deletions(-) diff --git a/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua b/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua index d4a2846dd6..9b6b457ea9 100644 --- a/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua +++ b/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua @@ -17,22 +17,31 @@ local zigbee_test_utils = require "integration_test.zigbee_test_utils" local clusters = require "st.zigbee.zcl.clusters" local IASZone = clusters.IASZone local capabilities = require "st.capabilities" -local IasEnrollResponseCode = require "st.zigbee.generated.zcl_clusters.IASZone.types.EnrollResponseCode" local t_utils = require "integration_test.utils" local ZoneStatusAttribute = IASZone.attributes.ZoneStatus +local ZoneTypeAttribute = IASZone.attributes.ZoneType local ZONETYPE = "ZoneType" local Contact_Switch = 21 -- 0x0015 local Motion_Sensor = 13 -- 0x000d local Water_Sensor = 42 -- 0x002a +local ZIGBEE_GENERIC_SENSOR_PROFILE = "generic-sensor" local ZIGBEE_GENERIC_CONTACT_SENSOR_PROFILE = "generic-contact-sensor" local ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE = "generic-motion-sensor" local ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE = "generic-waterleak-sensor" -local log = require "log" - - +local mock_device_generic_sensor = test.mock_device.build_test_zigbee_device( + { + profile = t_utils.get_profile_definition(ZIGBEE_GENERIC_SENSOR_PROFILE .. ".yml"), + zigbee_endpoints = { + [1] = { + id = 1, + server_clusters = { 0x0500 } + } + } + } +) local mock_device_contact_sensor = test.mock_device.build_test_zigbee_device( { @@ -78,11 +87,48 @@ local function test_init() test.mock_device.add_test_device(mock_device_contact_sensor) test.mock_device.add_test_device(mock_device_motion_sensor) test.mock_device.add_test_device(mock_device_waterleak_sensor) + test.mock_device.add_test_device(mock_device_generic_sensor) zigbee_test_utils.init_noop_health_check_timer() end test.set_test_init_function(test_init) +test.register_message_test( + "Profile should change to Contact Sensor", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_generic_sensor.id, ZoneTypeAttribute:build_test_attr_report(mock_device_generic_sensor, 0x0015) } + }, + mock_device_generic_sensor:expect_metadata_update({profile = ZIGBEE_GENERIC_CONTACT_SENSOR_PROFILE}) + } +) + +test.register_message_test( + "Profile should change to Motion Sensor", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_generic_sensor.id, ZoneTypeAttribute:build_test_attr_report(mock_device_generic_sensor, 0x000d) } + }, + mock_device_generic_sensor:expect_metadata_update({profile = ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE}) + } +) + +test.register_message_test( + "Profile should change to Waterleak Sensor", + { + { + channel = "zigbee", + direction = "receive", + message = { mock_device_generic_sensor.id, ZoneTypeAttribute:build_test_attr_report(mock_device_generic_sensor, 0x002a) } + }, + mock_device_generic_sensor:expect_metadata_update({profile = ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE}) + } +) + test.register_message_test( "Reported contact should be handled: open", { @@ -285,13 +331,13 @@ test.register_coroutine_test( test.socket.device_lifecycle:__queue_receive({ mock_device_contact_sensor.id, "added" }) test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, - IASZone.attributes.ZoneType:read(mock_device_contact_sensor) + ZoneTypeAttribute:read(mock_device_contact_sensor) }) test.wait_for_events() -- test.mock_time.advance_time(50000) -- test.socket.zigbee:__set_channel_ordering("relaxed") - -- test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_contact_sensor) }) + -- test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, ZoneStatusAttribute:read(mock_device_contact_sensor) }) -- test.wait_for_events() end, { @@ -308,13 +354,13 @@ test.register_coroutine_test( test.socket.device_lifecycle:__queue_receive({ mock_device_motion_sensor.id, "added" }) test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, - IASZone.attributes.ZoneType:read(mock_device_motion_sensor) + ZoneTypeAttribute:read(mock_device_motion_sensor) }) test.wait_for_events() -- test.mock_time.advance_time(50000) -- test.socket.zigbee:__set_channel_ordering("relaxed") - -- test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_motion_sensor) }) + -- test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, ZoneStatusAttribute:read(mock_device_motion_sensor) }) -- test.wait_for_events() end, { @@ -331,13 +377,13 @@ test.register_coroutine_test( test.socket.device_lifecycle:__queue_receive({ mock_device_waterleak_sensor.id, "added" }) test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, - IASZone.attributes.ZoneType:read(mock_device_waterleak_sensor) + ZoneTypeAttribute:read(mock_device_waterleak_sensor) }) test.wait_for_events() -- test.mock_time.advance_time(50000) -- test.socket.zigbee:__set_channel_ordering("relaxed") - -- test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_waterleak_sensor) }) + -- test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, ZoneStatusAttribute:read(mock_device_waterleak_sensor) }) -- test.wait_for_events() end, { @@ -355,7 +401,7 @@ test.register_coroutine_test( test.socket.zigbee:__set_channel_ordering("relaxed") test.socket.capability:__queue_receive({ mock_device_contact_sensor.id, { capability = "refresh", component = "main", command = "refresh", args = {} } }) - test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_contact_sensor) }) + test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, ZoneStatusAttribute:read(mock_device_contact_sensor) }) end ) @@ -366,7 +412,7 @@ test.register_coroutine_test( test.socket.zigbee:__set_channel_ordering("relaxed") test.socket.capability:__queue_receive({ mock_device_motion_sensor.id, { capability = "refresh", component = "main", command = "refresh", args = {} } }) - test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_motion_sensor) }) + test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, ZoneStatusAttribute:read(mock_device_motion_sensor) }) end ) @@ -377,7 +423,7 @@ test.register_coroutine_test( test.socket.zigbee:__set_channel_ordering("relaxed") test.socket.capability:__queue_receive({ mock_device_waterleak_sensor.id, { capability = "refresh", component = "main", command = "refresh", args = {} } }) - test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_waterleak_sensor) }) + test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, ZoneStatusAttribute:read(mock_device_waterleak_sensor) }) end ) @@ -387,7 +433,11 @@ test.register_coroutine_test( test.socket.device_lifecycle:__queue_receive({ mock_device_contact_sensor.id, "added" }) test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, - IASZone.attributes.ZoneType:read(mock_device_contact_sensor) + ZoneTypeAttribute:read(mock_device_contact_sensor) + }) + test.socket.zigbee:__expect_send({ + mock_device_contact_sensor.id, + ZoneStatusAttribute:read(mock_device_contact_sensor) }) test.wait_for_events() @@ -402,7 +452,11 @@ test.register_coroutine_test( test.socket.device_lifecycle:__queue_receive({ mock_device_motion_sensor.id, "added" }) test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, - IASZone.attributes.ZoneType:read(mock_device_motion_sensor) + ZoneTypeAttribute:read(mock_device_motion_sensor) + }) + test.socket.zigbee:__expect_send({ + mock_device_contact_sensor.id, + ZoneStatusAttribute:read(mock_device_contact_sensor) }) test.wait_for_events() @@ -417,7 +471,11 @@ test.register_coroutine_test( test.socket.device_lifecycle:__queue_receive({ mock_device_waterleak_sensor.id, "added" }) test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, - IASZone.attributes.ZoneType:read(mock_device_waterleak_sensor) + ZoneTypeAttribute:read(mock_device_waterleak_sensor) + }) + test.socket.zigbee:__expect_send({ + mock_device_contact_sensor.id, + ZoneStatusAttribute:read(mock_device_contact_sensor) }) test.wait_for_events() From fb68377ffde82c615c0e15eaa58b70a6857b467e Mon Sep 17 00:00:00 2001 From: zhongpei-ge Date: Fri, 21 Feb 2025 19:37:18 +0800 Subject: [PATCH 4/6] improve code and add TC --- .../SmartThings/zigbee-sensor/src/init.lua | 9 +- .../src/test/test_zigbee_sensor.lua | 107 ++++++++++++------ 2 files changed, 72 insertions(+), 44 deletions(-) diff --git a/drivers/SmartThings/zigbee-sensor/src/init.lua b/drivers/SmartThings/zigbee-sensor/src/init.lua index 815970f25c..cff6553935 100644 --- a/drivers/SmartThings/zigbee-sensor/src/init.lua +++ b/drivers/SmartThings/zigbee-sensor/src/init.lua @@ -19,7 +19,6 @@ local IASZone = clusters.IASZone local capabilities = require "st.capabilities" local ZONETYPE = "ZoneType" local constants = require "st.zigbee.constants" -local PowerConfiguration = clusters.PowerConfiguration local battery_defaults = require "st.zigbee.defaults.battery_defaults" local utils = require "st.utils" local battery_config = utils.deep_copy(battery_defaults.default_percentage_configuration) @@ -72,17 +71,13 @@ local generate_event_from_zone_status = function(driver, device, zone_status, zb local type = device:get_field(ZONETYPE) local event if type == CONTACT_SWITCH then - if zone_status:is_alarm1_set() then - event = capabilities.contactSensor.contact.open() - elseif zone_status:is_alarm2_set() then + if zone_status:is_alarm1_set() or zone_status:is_alarm2_set() then event = capabilities.contactSensor.contact.open() else event = capabilities.contactSensor.contact.closed() end elseif type == MOTION_SENSOR then - if zone_status:is_alarm1_set() then - event = capabilities.motionSensor.motion.active() - elseif zone_status:is_alarm2_set() then + if zone_status:is_alarm1_set() or zone_status:is_alarm2_set() then event = capabilities.motionSensor.motion.active() else event = capabilities.motionSensor.motion.inactive() diff --git a/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua b/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua index 9b6b457ea9..4e099ac2d0 100644 --- a/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua +++ b/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua @@ -18,6 +18,7 @@ local clusters = require "st.zigbee.zcl.clusters" local IASZone = clusters.IASZone local capabilities = require "st.capabilities" local t_utils = require "integration_test.utils" +local PowerConfiguration = clusters.PowerConfiguration local ZoneStatusAttribute = IASZone.attributes.ZoneStatus local ZoneTypeAttribute = IASZone.attributes.ZoneType @@ -93,39 +94,76 @@ end test.set_test_init_function(test_init) -test.register_message_test( +test.register_coroutine_test( "Profile should change to Contact Sensor", + function () + test.socket.zigbee:__queue_receive({mock_device_generic_sensor.id, ZoneTypeAttribute:build_test_attr_report(mock_device_generic_sensor, 0x0015)}) + mock_device_generic_sensor:expect_metadata_update({profile = ZIGBEE_GENERIC_CONTACT_SENSOR_PROFILE}) + end +) + +test.register_coroutine_test( + "Profile should change to Motion Sensor", + + function () + test.socket.zigbee:__queue_receive({mock_device_generic_sensor.id, ZoneTypeAttribute:build_test_attr_report(mock_device_generic_sensor, 0x000d)}) + mock_device_generic_sensor:expect_metadata_update({profile = ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE}) + end +) + +test.register_coroutine_test( + "Profile should change to Waterleak Sensor", + function () + test.socket.zigbee:__queue_receive({mock_device_generic_sensor.id, ZoneTypeAttribute:build_test_attr_report(mock_device_generic_sensor, 0x002a)}) + mock_device_generic_sensor:expect_metadata_update({profile = ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE}) + end +) + +test.register_message_test( + "Battery percentage report should be handled (contact sensor)", { { channel = "zigbee", direction = "receive", - message = { mock_device_generic_sensor.id, ZoneTypeAttribute:build_test_attr_report(mock_device_generic_sensor, 0x0015) } + message = { mock_device_contact_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:build_test_attr_report(mock_device_contact_sensor, 55) } }, - mock_device_generic_sensor:expect_metadata_update({profile = ZIGBEE_GENERIC_CONTACT_SENSOR_PROFILE}) + { + channel = "capability", + direction = "send", + message = mock_device_contact_sensor:generate_test_message("main", capabilities.battery.battery(28)) + } } ) test.register_message_test( - "Profile should change to Motion Sensor", + "Battery percentage report should be handled (motion sensor)", { { channel = "zigbee", direction = "receive", - message = { mock_device_generic_sensor.id, ZoneTypeAttribute:build_test_attr_report(mock_device_generic_sensor, 0x000d) } + message = { mock_device_motion_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:build_test_attr_report(mock_device_motion_sensor, 55) } }, - mock_device_generic_sensor:expect_metadata_update({profile = ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE}) + { + channel = "capability", + direction = "send", + message = mock_device_motion_sensor:generate_test_message("main", capabilities.battery.battery(28)) + } } ) test.register_message_test( - "Profile should change to Waterleak Sensor", + "Battery percentage report should be handled (water leak sensor)", { { channel = "zigbee", direction = "receive", - message = { mock_device_generic_sensor.id, ZoneTypeAttribute:build_test_attr_report(mock_device_generic_sensor, 0x002a) } + message = { mock_device_waterleak_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:build_test_attr_report(mock_device_waterleak_sensor, 55) } }, - mock_device_generic_sensor:expect_metadata_update({profile = ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE}) + { + channel = "capability", + direction = "send", + message = mock_device_waterleak_sensor:generate_test_message("main", capabilities.battery.battery(28)) + } } ) @@ -333,12 +371,11 @@ test.register_coroutine_test( mock_device_contact_sensor.id, ZoneTypeAttribute:read(mock_device_contact_sensor) }) + test.socket.zigbee:__expect_send({ + mock_device_contact_sensor.id, + ZoneStatusAttribute:read(mock_device_contact_sensor) + }) test.wait_for_events() - - -- test.mock_time.advance_time(50000) - -- test.socket.zigbee:__set_channel_ordering("relaxed") - -- test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, ZoneStatusAttribute:read(mock_device_contact_sensor) }) - -- test.wait_for_events() end, { test_init = function() @@ -356,12 +393,11 @@ test.register_coroutine_test( mock_device_motion_sensor.id, ZoneTypeAttribute:read(mock_device_motion_sensor) }) + test.socket.zigbee:__expect_send({ + mock_device_motion_sensor.id, + ZoneStatusAttribute:read(mock_device_motion_sensor) + }) test.wait_for_events() - - -- test.mock_time.advance_time(50000) - -- test.socket.zigbee:__set_channel_ordering("relaxed") - -- test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, ZoneStatusAttribute:read(mock_device_motion_sensor) }) - -- test.wait_for_events() end, { test_init = function() @@ -379,12 +415,11 @@ test.register_coroutine_test( mock_device_waterleak_sensor.id, ZoneTypeAttribute:read(mock_device_waterleak_sensor) }) + test.socket.zigbee:__expect_send({ + mock_device_waterleak_sensor.id, + ZoneStatusAttribute:read(mock_device_waterleak_sensor) + }) test.wait_for_events() - - -- test.mock_time.advance_time(50000) - -- test.socket.zigbee:__set_channel_ordering("relaxed") - -- test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, ZoneStatusAttribute:read(mock_device_waterleak_sensor) }) - -- test.wait_for_events() end, { test_init = function() @@ -401,7 +436,14 @@ test.register_coroutine_test( test.socket.zigbee:__set_channel_ordering("relaxed") test.socket.capability:__queue_receive({ mock_device_contact_sensor.id, { capability = "refresh", component = "main", command = "refresh", args = {} } }) + test.socket.zigbee:__expect_send( + { + mock_device_contact_sensor.id, + PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_contact_sensor) + } + ) test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, ZoneStatusAttribute:read(mock_device_contact_sensor) }) + end ) @@ -440,9 +482,6 @@ test.register_coroutine_test( ZoneStatusAttribute:read(mock_device_contact_sensor) }) test.wait_for_events() - - test.socket.zigbee:__set_channel_ordering("relaxed") - mock_device_contact_sensor:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end ) @@ -455,13 +494,10 @@ test.register_coroutine_test( ZoneTypeAttribute:read(mock_device_motion_sensor) }) test.socket.zigbee:__expect_send({ - mock_device_contact_sensor.id, - ZoneStatusAttribute:read(mock_device_contact_sensor) + mock_device_motion_sensor.id, + ZoneStatusAttribute:read(mock_device_motion_sensor) }) test.wait_for_events() - - test.socket.zigbee:__set_channel_ordering("relaxed") - mock_device_contact_sensor:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end ) @@ -474,13 +510,10 @@ test.register_coroutine_test( ZoneTypeAttribute:read(mock_device_waterleak_sensor) }) test.socket.zigbee:__expect_send({ - mock_device_contact_sensor.id, - ZoneStatusAttribute:read(mock_device_contact_sensor) + mock_device_waterleak_sensor.id, + ZoneStatusAttribute:read(mock_device_waterleak_sensor) }) test.wait_for_events() - - test.socket.zigbee:__set_channel_ordering("relaxed") - mock_device_waterleak_sensor:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end ) From f4cc05a7b5f142ac1011070d25190a71c43a1455 Mon Sep 17 00:00:00 2001 From: frank-huang Date: Mon, 24 Feb 2025 15:43:31 +0800 Subject: [PATCH 5/6] add configurations and related test cases Signed-off-by: frank-huang --- .../SmartThings/zigbee-sensor/src/init.lua | 29 ++- .../src/test/test_zigbee_sensor.lua | 212 +++++++++++++++++- 2 files changed, 229 insertions(+), 12 deletions(-) diff --git a/drivers/SmartThings/zigbee-sensor/src/init.lua b/drivers/SmartThings/zigbee-sensor/src/init.lua index cff6553935..33fa25ecfe 100644 --- a/drivers/SmartThings/zigbee-sensor/src/init.lua +++ b/drivers/SmartThings/zigbee-sensor/src/init.lua @@ -19,11 +19,24 @@ local IASZone = clusters.IASZone local capabilities = require "st.capabilities" local ZONETYPE = "ZoneType" local constants = require "st.zigbee.constants" -local battery_defaults = require "st.zigbee.defaults.battery_defaults" -local utils = require "st.utils" -local battery_config = utils.deep_copy(battery_defaults.default_percentage_configuration) -battery_config.reportable_change = 0x10 -battery_config.data_type = clusters.PowerConfiguration.attributes.BatteryVoltage.base_type + +local configurations = { + { + cluster = clusters.IASZone.ID, + attribute = clusters.IASZone.attributes.ZoneStatus.ID, + minimum_interval = 30, + maximum_interval = 300, + data_type = clusters.IASZone.attributes.ZoneStatus.base_type + }, + { + cluster = clusters.PowerConfiguration.ID, + attribute = clusters.PowerConfiguration.attributes.BatteryPercentageRemaining.ID, + minimum_interval = 30, + maximum_interval = 21600, + data_type = clusters.PowerConfiguration.attributes.BatteryVoltage.base_type, + reportable_change = 16 + } +} local CONTACT_SWITCH = 0x0015 local MOTION_SENSOR = 0x000D @@ -35,8 +48,10 @@ local ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE = "generic-motion-sensor" local ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE = "generic-waterleak-sensor" local device_init = function(self, device) - device:add_configured_attribute(battery_config) - device:add_monitored_attribute(battery_config) + for _, attribute in ipairs(configurations) do + device:add_configured_attribute(attribute) + device:add_monitored_attribute(attribute) + end end -- ask device to upload its zone type diff --git a/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua b/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua index 4e099ac2d0..5d83643648 100644 --- a/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua +++ b/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua @@ -22,6 +22,7 @@ local PowerConfiguration = clusters.PowerConfiguration local ZoneStatusAttribute = IASZone.attributes.ZoneStatus local ZoneTypeAttribute = IASZone.attributes.ZoneType +local IasEnrollResponseCode = require "st.zigbee.generated.zcl_clusters.IASZone.types.EnrollResponseCode" local ZONETYPE = "ZoneType" local Contact_Switch = 21 -- 0x0015 @@ -38,7 +39,7 @@ local mock_device_generic_sensor = test.mock_device.build_test_zigbee_device( zigbee_endpoints = { [1] = { id = 1, - server_clusters = { 0x0500 } + server_clusters = { 0x0500, 0x0001 } } } } @@ -50,7 +51,7 @@ local mock_device_contact_sensor = test.mock_device.build_test_zigbee_device( zigbee_endpoints = { [1] = { id = 1, - server_clusters = { 0x0500 } + server_clusters = { 0x0500, 0x0001 } } } } @@ -62,7 +63,7 @@ local mock_device_motion_sensor = test.mock_device.build_test_zigbee_device( zigbee_endpoints = { [1] = { id = 1, - server_clusters = { 0x0500 } + server_clusters = { 0x0500, 0x0001 } } } } @@ -74,7 +75,7 @@ local mock_device_waterleak_sensor = test.mock_device.build_test_zigbee_device( zigbee_endpoints = { [1] = { id = 1, - server_clusters = { 0x0500 } + server_clusters = { 0x0500, 0x0001 } } } } @@ -376,6 +377,12 @@ test.register_coroutine_test( ZoneStatusAttribute:read(mock_device_contact_sensor) }) test.wait_for_events() + + test.mock_time.advance_time(50000) + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_contact_sensor) }) + test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_contact_sensor) }) + test.wait_for_events() end, { test_init = function() @@ -398,6 +405,12 @@ test.register_coroutine_test( ZoneStatusAttribute:read(mock_device_motion_sensor) }) test.wait_for_events() + + test.mock_time.advance_time(50000) + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_motion_sensor) }) + test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_motion_sensor) }) + test.wait_for_events() end, { test_init = function() @@ -420,6 +433,12 @@ test.register_coroutine_test( ZoneStatusAttribute:read(mock_device_waterleak_sensor) }) test.wait_for_events() + + test.mock_time.advance_time(50000) + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_waterleak_sensor) }) + test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_waterleak_sensor) }) + test.wait_for_events() end, { test_init = function() @@ -441,7 +460,7 @@ test.register_coroutine_test( mock_device_contact_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_contact_sensor) } - ) + ) test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, ZoneStatusAttribute:read(mock_device_contact_sensor) }) end @@ -454,6 +473,12 @@ test.register_coroutine_test( test.socket.zigbee:__set_channel_ordering("relaxed") test.socket.capability:__queue_receive({ mock_device_motion_sensor.id, { capability = "refresh", component = "main", command = "refresh", args = {} } }) + test.socket.zigbee:__expect_send( + { + mock_device_motion_sensor.id, + PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_motion_sensor) + } + ) test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, ZoneStatusAttribute:read(mock_device_motion_sensor) }) end ) @@ -465,6 +490,12 @@ test.register_coroutine_test( test.socket.zigbee:__set_channel_ordering("relaxed") test.socket.capability:__queue_receive({ mock_device_waterleak_sensor.id, { capability = "refresh", component = "main", command = "refresh", args = {} } }) + test.socket.zigbee:__expect_send( + { + mock_device_waterleak_sensor.id, + PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_waterleak_sensor) + } + ) test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, ZoneStatusAttribute:read(mock_device_waterleak_sensor) }) end ) @@ -482,6 +513,63 @@ test.register_coroutine_test( ZoneStatusAttribute:read(mock_device_contact_sensor) }) test.wait_for_events() + + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.device_lifecycle:__queue_receive({ mock_device_contact_sensor.id, "doConfigure" }) + + test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_contact_sensor) }) + test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_contact_sensor) }) + test.socket.zigbee:__expect_send( + { + mock_device_contact_sensor.id, + zigbee_test_utils.build_bind_request(mock_device_contact_sensor, + zigbee_test_utils.mock_hub_eui, + PowerConfiguration.ID) + } + ) + test.socket.zigbee:__expect_send( + { + mock_device_contact_sensor.id, + PowerConfiguration.attributes.BatteryPercentageRemaining:configure_reporting(mock_device_contact_sensor, + 30, + 21600, + 16) + } + ) + + test.socket.zigbee:__expect_send( + { + mock_device_contact_sensor.id, + IASZone.attributes.IASCIEAddress:write(mock_device_contact_sensor, + zigbee_test_utils.mock_hub_eui) + } + ) + test.socket.zigbee:__expect_send( + { + mock_device_contact_sensor.id, + IASZone.server.commands.ZoneEnrollResponse(mock_device_contact_sensor, + IasEnrollResponseCode.SUCCESS, + 0x00) + } + ) + test.socket.zigbee:__expect_send( + { + mock_device_contact_sensor.id, + IASZone.attributes.ZoneStatus:configure_reporting(mock_device_contact_sensor, + 30, + 300, + 0) + } + ) + test.socket.zigbee:__expect_send( + { + mock_device_contact_sensor.id, + zigbee_test_utils.build_bind_request(mock_device_contact_sensor, + zigbee_test_utils.mock_hub_eui, + IASZone.ID) + } + ) + mock_device_contact_sensor:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end ) @@ -498,6 +586,63 @@ test.register_coroutine_test( ZoneStatusAttribute:read(mock_device_motion_sensor) }) test.wait_for_events() + + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.device_lifecycle:__queue_receive({ mock_device_motion_sensor.id, "doConfigure" }) + + test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_motion_sensor) }) + test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_motion_sensor) }) + test.socket.zigbee:__expect_send( + { + mock_device_motion_sensor.id, + zigbee_test_utils.build_bind_request(mock_device_motion_sensor, + zigbee_test_utils.mock_hub_eui, + PowerConfiguration.ID) + } + ) + test.socket.zigbee:__expect_send( + { + mock_device_motion_sensor.id, + PowerConfiguration.attributes.BatteryPercentageRemaining:configure_reporting(mock_device_motion_sensor, + 30, + 21600, + 16) + } + ) + + test.socket.zigbee:__expect_send( + { + mock_device_motion_sensor.id, + IASZone.attributes.IASCIEAddress:write(mock_device_motion_sensor, + zigbee_test_utils.mock_hub_eui) + } + ) + test.socket.zigbee:__expect_send( + { + mock_device_motion_sensor.id, + IASZone.server.commands.ZoneEnrollResponse(mock_device_motion_sensor, + IasEnrollResponseCode.SUCCESS, + 0x00) + } + ) + test.socket.zigbee:__expect_send( + { + mock_device_motion_sensor.id, + IASZone.attributes.ZoneStatus:configure_reporting(mock_device_motion_sensor, + 30, + 300, + 0) + } + ) + test.socket.zigbee:__expect_send( + { + mock_device_motion_sensor.id, + zigbee_test_utils.build_bind_request(mock_device_motion_sensor, + zigbee_test_utils.mock_hub_eui, + IASZone.ID) + } + ) + mock_device_motion_sensor:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end ) @@ -514,6 +659,63 @@ test.register_coroutine_test( ZoneStatusAttribute:read(mock_device_waterleak_sensor) }) test.wait_for_events() + + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.device_lifecycle:__queue_receive({ mock_device_waterleak_sensor.id, "doConfigure" }) + + test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_waterleak_sensor) }) + test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_waterleak_sensor) }) + test.socket.zigbee:__expect_send( + { + mock_device_waterleak_sensor.id, + zigbee_test_utils.build_bind_request(mock_device_waterleak_sensor, + zigbee_test_utils.mock_hub_eui, + PowerConfiguration.ID) + } + ) + test.socket.zigbee:__expect_send( + { + mock_device_waterleak_sensor.id, + PowerConfiguration.attributes.BatteryPercentageRemaining:configure_reporting(mock_device_waterleak_sensor, + 30, + 21600, + 16) + } + ) + + test.socket.zigbee:__expect_send( + { + mock_device_waterleak_sensor.id, + IASZone.attributes.IASCIEAddress:write(mock_device_waterleak_sensor, + zigbee_test_utils.mock_hub_eui) + } + ) + test.socket.zigbee:__expect_send( + { + mock_device_waterleak_sensor.id, + IASZone.server.commands.ZoneEnrollResponse(mock_device_waterleak_sensor, + IasEnrollResponseCode.SUCCESS, + 0x00) + } + ) + test.socket.zigbee:__expect_send( + { + mock_device_waterleak_sensor.id, + IASZone.attributes.ZoneStatus:configure_reporting(mock_device_waterleak_sensor, + 30, + 300, + 0) + } + ) + test.socket.zigbee:__expect_send( + { + mock_device_waterleak_sensor.id, + zigbee_test_utils.build_bind_request(mock_device_waterleak_sensor, + zigbee_test_utils.mock_hub_eui, + IASZone.ID) + } + ) + mock_device_waterleak_sensor:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end ) From 6113590a2b86511ecee03f47ad7ced906a8c2e0b Mon Sep 17 00:00:00 2001 From: frank-huang Date: Fri, 28 Feb 2025 20:53:54 +0800 Subject: [PATCH 6/6] Modify test case for changed drivers Signed-off-by: frank-huang --- .../SmartThings/zigbee-sensor/src/init.lua | 4 +- .../src/test/test_zigbee_sensor.lua | 141 ++---------------- 2 files changed, 15 insertions(+), 130 deletions(-) diff --git a/drivers/SmartThings/zigbee-sensor/src/init.lua b/drivers/SmartThings/zigbee-sensor/src/init.lua index eaa9162f1a..c95cffac3b 100644 --- a/drivers/SmartThings/zigbee-sensor/src/init.lua +++ b/drivers/SmartThings/zigbee-sensor/src/init.lua @@ -40,7 +40,7 @@ local device_init = function(self, device) end -- ask device to upload its zone type -local ias_device_added = function(self, device) +local device_added = function(self, device) device:send(IASZone.attributes.ZoneType:read(device)) end @@ -135,7 +135,7 @@ local zigbee_generic_sensor_template = { }, lifecycle_handlers = { init = device_init, - added = ias_device_added, + added = device_added, doConfigure = do_configure, infoChanged = info_changed }, diff --git a/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua b/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua index 5d83643648..45c6196db9 100644 --- a/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua +++ b/drivers/SmartThings/zigbee-sensor/src/test/test_zigbee_sensor.lua @@ -19,6 +19,8 @@ local IASZone = clusters.IASZone local capabilities = require "st.capabilities" local t_utils = require "integration_test.utils" local PowerConfiguration = clusters.PowerConfiguration +local dkjson = require 'dkjson' +local utils = require "st.utils" local ZoneStatusAttribute = IASZone.attributes.ZoneStatus local ZoneTypeAttribute = IASZone.attributes.ZoneType @@ -400,16 +402,11 @@ test.register_coroutine_test( mock_device_motion_sensor.id, ZoneTypeAttribute:read(mock_device_motion_sensor) }) - test.socket.zigbee:__expect_send({ - mock_device_motion_sensor.id, - ZoneStatusAttribute:read(mock_device_motion_sensor) - }) test.wait_for_events() test.mock_time.advance_time(50000) test.socket.zigbee:__set_channel_ordering("relaxed") test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_motion_sensor) }) - test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_motion_sensor) }) test.wait_for_events() end, { @@ -428,16 +425,16 @@ test.register_coroutine_test( mock_device_waterleak_sensor.id, ZoneTypeAttribute:read(mock_device_waterleak_sensor) }) - test.socket.zigbee:__expect_send({ - mock_device_waterleak_sensor.id, - ZoneStatusAttribute:read(mock_device_waterleak_sensor) - }) + -- test.socket.zigbee:__expect_send({ + -- mock_device_waterleak_sensor.id, + -- ZoneStatusAttribute:read(mock_device_waterleak_sensor) + -- }) test.wait_for_events() test.mock_time.advance_time(50000) test.socket.zigbee:__set_channel_ordering("relaxed") test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_waterleak_sensor) }) - test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_waterleak_sensor) }) + -- test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_waterleak_sensor) }) test.wait_for_events() end, { @@ -508,50 +505,13 @@ test.register_coroutine_test( mock_device_contact_sensor.id, ZoneTypeAttribute:read(mock_device_contact_sensor) }) - test.socket.zigbee:__expect_send({ - mock_device_contact_sensor.id, - ZoneStatusAttribute:read(mock_device_contact_sensor) - }) + local device_info_copy = utils.deep_copy(mock_device_contact_sensor.raw_st_data) + device_info_copy.profile.id = "generic-contact-sensor" + local device_info_json = dkjson.encode(device_info_copy) test.wait_for_events() test.socket.zigbee:__set_channel_ordering("relaxed") test.socket.device_lifecycle:__queue_receive({ mock_device_contact_sensor.id, "doConfigure" }) - - test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_contact_sensor) }) - test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_contact_sensor) }) - test.socket.zigbee:__expect_send( - { - mock_device_contact_sensor.id, - zigbee_test_utils.build_bind_request(mock_device_contact_sensor, - zigbee_test_utils.mock_hub_eui, - PowerConfiguration.ID) - } - ) - test.socket.zigbee:__expect_send( - { - mock_device_contact_sensor.id, - PowerConfiguration.attributes.BatteryPercentageRemaining:configure_reporting(mock_device_contact_sensor, - 30, - 21600, - 16) - } - ) - - test.socket.zigbee:__expect_send( - { - mock_device_contact_sensor.id, - IASZone.attributes.IASCIEAddress:write(mock_device_contact_sensor, - zigbee_test_utils.mock_hub_eui) - } - ) - test.socket.zigbee:__expect_send( - { - mock_device_contact_sensor.id, - IASZone.server.commands.ZoneEnrollResponse(mock_device_contact_sensor, - IasEnrollResponseCode.SUCCESS, - 0x00) - } - ) test.socket.zigbee:__expect_send( { mock_device_contact_sensor.id, @@ -569,6 +529,9 @@ test.register_coroutine_test( IASZone.ID) } ) + test.socket.device_lifecycle:__queue_receive({ mock_device_contact_sensor.id, "infoChanged", device_info_json }) + test.socket.zigbee:__expect_send({ mock_device_contact_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_contact_sensor) }) + mock_device_contact_sensor:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end ) @@ -581,50 +544,11 @@ test.register_coroutine_test( mock_device_motion_sensor.id, ZoneTypeAttribute:read(mock_device_motion_sensor) }) - test.socket.zigbee:__expect_send({ - mock_device_motion_sensor.id, - ZoneStatusAttribute:read(mock_device_motion_sensor) - }) test.wait_for_events() test.socket.zigbee:__set_channel_ordering("relaxed") test.socket.device_lifecycle:__queue_receive({ mock_device_motion_sensor.id, "doConfigure" }) - test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_motion_sensor) }) - test.socket.zigbee:__expect_send({ mock_device_motion_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_motion_sensor) }) - test.socket.zigbee:__expect_send( - { - mock_device_motion_sensor.id, - zigbee_test_utils.build_bind_request(mock_device_motion_sensor, - zigbee_test_utils.mock_hub_eui, - PowerConfiguration.ID) - } - ) - test.socket.zigbee:__expect_send( - { - mock_device_motion_sensor.id, - PowerConfiguration.attributes.BatteryPercentageRemaining:configure_reporting(mock_device_motion_sensor, - 30, - 21600, - 16) - } - ) - - test.socket.zigbee:__expect_send( - { - mock_device_motion_sensor.id, - IASZone.attributes.IASCIEAddress:write(mock_device_motion_sensor, - zigbee_test_utils.mock_hub_eui) - } - ) - test.socket.zigbee:__expect_send( - { - mock_device_motion_sensor.id, - IASZone.server.commands.ZoneEnrollResponse(mock_device_motion_sensor, - IasEnrollResponseCode.SUCCESS, - 0x00) - } - ) test.socket.zigbee:__expect_send( { mock_device_motion_sensor.id, @@ -654,50 +578,11 @@ test.register_coroutine_test( mock_device_waterleak_sensor.id, ZoneTypeAttribute:read(mock_device_waterleak_sensor) }) - test.socket.zigbee:__expect_send({ - mock_device_waterleak_sensor.id, - ZoneStatusAttribute:read(mock_device_waterleak_sensor) - }) test.wait_for_events() test.socket.zigbee:__set_channel_ordering("relaxed") test.socket.device_lifecycle:__queue_receive({ mock_device_waterleak_sensor.id, "doConfigure" }) - test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device_waterleak_sensor) }) - test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_waterleak_sensor) }) - test.socket.zigbee:__expect_send( - { - mock_device_waterleak_sensor.id, - zigbee_test_utils.build_bind_request(mock_device_waterleak_sensor, - zigbee_test_utils.mock_hub_eui, - PowerConfiguration.ID) - } - ) - test.socket.zigbee:__expect_send( - { - mock_device_waterleak_sensor.id, - PowerConfiguration.attributes.BatteryPercentageRemaining:configure_reporting(mock_device_waterleak_sensor, - 30, - 21600, - 16) - } - ) - - test.socket.zigbee:__expect_send( - { - mock_device_waterleak_sensor.id, - IASZone.attributes.IASCIEAddress:write(mock_device_waterleak_sensor, - zigbee_test_utils.mock_hub_eui) - } - ) - test.socket.zigbee:__expect_send( - { - mock_device_waterleak_sensor.id, - IASZone.server.commands.ZoneEnrollResponse(mock_device_waterleak_sensor, - IasEnrollResponseCode.SUCCESS, - 0x00) - } - ) test.socket.zigbee:__expect_send( { mock_device_waterleak_sensor.id,