From fe5f13a9f0cfb08543cc63061684349d08264adb Mon Sep 17 00:00:00 2001 From: Cooper Towns Date: Mon, 22 Jan 2024 17:09:17 -0600 Subject: [PATCH 1/8] Matter Switch: fix Nanoleaf NL71K1 fingerprint --- drivers/SmartThings/matter-switch/fingerprints.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/SmartThings/matter-switch/fingerprints.yml b/drivers/SmartThings/matter-switch/fingerprints.yml index 96ee824e7a..255ce24572 100644 --- a/drivers/SmartThings/matter-switch/fingerprints.yml +++ b/drivers/SmartThings/matter-switch/fingerprints.yml @@ -59,10 +59,10 @@ matterManufacturer: vendorId: 0x115a productId: 0x44 deviceProfileName: light-color-level-2700K-6500K - - id: "4442/1809" + - id: "Nanoleaf NL71K1" deviceLabel: Smart Holiday String Lights vendorId: 0x115A - productId: 0x771 + productId: 0x711 deviceProfileName: light-color-level-2700K-6500K #SONOFF - id: "SONOFF MINIR4M" From 90259222d9dee613735c0385ad398680e711113f Mon Sep 17 00:00:00 2001 From: Steven Green Date: Wed, 15 Nov 2023 17:08:55 -0800 Subject: [PATCH 2/8] BUG2-521 Rework yoolax window shade driver Consolidates the timer logic used to check up on changing window shades into the sub-driver. Also uses a default response success from the device to indicate that the shade is moving. A subsequent poll should change the status to a stationary one if no updates are received within 30s. --- ...est_zigbee_window_shade_battery_yoolax.lua | 178 +++++++++++------- .../src/yoolax/init.lua | 88 ++++++++- 2 files changed, 188 insertions(+), 78 deletions(-) diff --git a/drivers/SmartThings/zigbee-window-treatment/src/test/test_zigbee_window_shade_battery_yoolax.lua b/drivers/SmartThings/zigbee-window-treatment/src/test/test_zigbee_window_shade_battery_yoolax.lua index d413813a60..98d8ccb44f 100644 --- a/drivers/SmartThings/zigbee-window-treatment/src/test/test_zigbee_window_shade_battery_yoolax.lua +++ b/drivers/SmartThings/zigbee-window-treatment/src/test/test_zigbee_window_shade_battery_yoolax.lua @@ -19,6 +19,13 @@ local clusters = require "st.zigbee.zcl.clusters" local capabilities = require "st.capabilities" local t_utils = require "integration_test.utils" +local messages = require "st.zigbee.messages" +local default_response = require "st.zigbee.zcl.global_commands.default_response" +local zb_const = require "st.zigbee.constants" +local Status = require "st.zigbee.generated.types.ZclStatus" +local data_types = require "st.zigbee.data_types" +local zcl_messages = require "st.zigbee.zcl" + local WindowCovering = clusters.WindowCovering local mock_device = test.mock_device.build_test_zigbee_device( @@ -35,6 +42,29 @@ local mock_device = test.mock_device.build_test_zigbee_device( } ) +local function build_default_response_msg(cluster, command, status) + local addr_header = messages.AddressHeader( + mock_device:get_short_address(), + mock_device.fingerprinted_endpoint_id, + zb_const.HUB.ADDR, + zb_const.HUB.ENDPOINT, + zb_const.HA_PROFILE_ID, + cluster + ) + local default_response_body = default_response.DefaultResponse(command, status) + local zcl_header = zcl_messages.ZclHeader({ + cmd = data_types.ZCLCommandId(default_response_body.ID) + }) + local message_body = zcl_messages.ZclMessageBody({ + zcl_header = zcl_header, + zcl_body = default_response_body + }) + return messages.ZigbeeMessageRx({ + address_header = addr_header, + body = message_body + }) +end + zigbee_test_utils.prepare_zigbee_env_info() local function test_init() test.mock_device.add_test_device(mock_device) @@ -44,9 +74,8 @@ end test.set_test_init_function(test_init) test.register_coroutine_test( - "State transition from opening to partially open", + "Initial level report", function() - test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") test.socket.zigbee:__queue_receive( { mock_device.id, @@ -54,20 +83,10 @@ test.register_coroutine_test( } ) test.socket.capability:__expect_send( - { - mock_device.id, - { - capability_id = "windowShadeLevel", component_id = "main", - attribute_id = "shadeLevel", state = { value = 99 } - } - } - ) - test.socket.capability:__expect_send( - mock_device:generate_test_message("main", capabilities.windowShade.windowShade.opening()) + mock_device:generate_test_message("main", capabilities.windowShade.windowShade.partially_open()) ) - test.mock_time.advance_time(2) test.socket.capability:__expect_send( - mock_device:generate_test_message("main", capabilities.windowShade.windowShade.partially_open()) + mock_device:generate_test_message("main", capabilities.windowShadeLevel.shadeLevel(99)) ) test.wait_for_events() end @@ -76,7 +95,7 @@ test.register_coroutine_test( test.register_coroutine_test( "State transition from opening to closing", function() - test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + test.timer.__create_and_queue_test_time_advance_timer(2, "oneshot") test.socket.zigbee:__queue_receive( { mock_device.id, @@ -84,38 +103,23 @@ test.register_coroutine_test( } ) test.socket.capability:__expect_send( - { - mock_device.id, - { - capability_id = "windowShadeLevel", component_id = "main", - attribute_id = "shadeLevel", state = { value = 90 } - } - } + mock_device:generate_test_message("main", capabilities.windowShade.windowShade.partially_open()) ) test.socket.capability:__expect_send( - mock_device:generate_test_message("main", capabilities.windowShade.windowShade.opening()) + mock_device:generate_test_message("main", capabilities.windowShadeLevel.shadeLevel(90)) ) - test.mock_time.advance_time(2) - test.socket.capability:__expect_send( - mock_device:generate_test_message("main", capabilities.windowShade.windowShade.partially_open()) - ) - test.wait_for_events() - test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") test.socket.zigbee:__queue_receive({ mock_device.id, WindowCovering.attributes.CurrentPositionLiftPercentage:build_test_attr_report(mock_device, 15) }) - test.socket.capability:__expect_send({ - mock_device.id, - { - capability_id = "windowShadeLevel", component_id = "main", - attribute_id = "shadeLevel", state = { value = 85 } - } - }) test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.windowShade.windowShade.closing()) ) - test.mock_time.advance_time(3) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.windowShadeLevel.shadeLevel(85)) + ) + test.wait_for_events() + test.mock_time.advance_time(2) test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.windowShade.windowShade.partially_open()) ) @@ -196,10 +200,9 @@ test.register_coroutine_test( ) test.register_coroutine_test( - "an attribute read should not be sent after 30s if there is a response", + "an attribute read should not be sent after 30s if there is a matching response", function () test.timer.__create_and_queue_test_time_advance_timer(30, "oneshot") --Only one timer in the driver - test.timer.__create_and_queue_test_time_advance_timer(2, "oneshot") --delay timer for defaults parially open delay test.socket.capability:__queue_receive( { mock_device.id, @@ -214,36 +217,25 @@ test.register_coroutine_test( test.socket.zigbee:__queue_receive({ mock_device.id, - WindowCovering.attributes.CurrentPositionLiftPercentage:build_test_attr_report(mock_device, 15) - }) - test.socket.capability:__expect_send({ - mock_device.id, - { - capability_id = "windowShadeLevel", component_id = "main", - attribute_id = "shadeLevel", state = { value = 85 } - } + WindowCovering.attributes.CurrentPositionLiftPercentage:build_test_attr_report(mock_device, 0) }) test.socket.capability:__expect_send( - mock_device:generate_test_message("main", capabilities.windowShade.windowShade.opening()) + mock_device:generate_test_message("main", capabilities.windowShade.windowShade.open()) ) - test.wait_for_events() - - test.mock_time.advance_time(20) test.socket.capability:__expect_send( - mock_device:generate_test_message("main", capabilities.windowShade.windowShade.partially_open()) + mock_device:generate_test_message("main", capabilities.windowShadeLevel.shadeLevel(100)) ) test.wait_for_events() - test.mock_time.advance_time(11) + test.mock_time.advance_time(30) test.wait_for_events() end ) test.register_coroutine_test( - "an attribute read should not be sent after 30s if there is a response another timing", + "an attribute read should be sent after 30s if there is a non-matching response", function () test.timer.__create_and_queue_test_time_advance_timer(30, "oneshot") --Only one timer in the driver - test.timer.__create_and_queue_test_time_advance_timer(2, "oneshot") --delay timer for defaults parially open delay test.socket.capability:__queue_receive( { mock_device.id, @@ -255,32 +247,82 @@ test.register_coroutine_test( WindowCovering.server.commands.GoToLiftPercentage(mock_device, 0) }) test.wait_for_events() - - test.mock_time.advance_time(1) test.socket.zigbee:__queue_receive({ mock_device.id, WindowCovering.attributes.CurrentPositionLiftPercentage:build_test_attr_report(mock_device, 15) }) - test.socket.capability:__expect_send({ + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.windowShade.windowShade.partially_open()) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.windowShadeLevel.shadeLevel(85))) + test.wait_for_events() + + test.mock_time.advance_time(30) + test.socket.zigbee:__expect_send({ mock_device.id, + zigbee_test_utils.build_bind_request(mock_device, + zigbee_test_utils.mock_hub_eui, + clusters.WindowCovering.ID) + }) + test.socket.zigbee:__expect_send({ + mock_device.id, + clusters.WindowCovering.attributes.CurrentPositionLiftPercentage:configure_reporting(mock_device, + 0, + 600, + 1) + }) + test.socket.zigbee:__expect_send({ + mock_device.id, + clusters.WindowCovering.attributes.CurrentPositionLiftPercentage:read(mock_device) + }) + test.wait_for_events() + end +) + +test.register_coroutine_test( + "Command success should result in opening/closing event", + function() + test.socket.zigbee:__queue_receive({ + mock_device.id, + WindowCovering.attributes.CurrentPositionLiftPercentage:build_test_attr_report(mock_device, 0) + }) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.windowShade.windowShade.open()) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.windowShadeLevel.shadeLevel(100)) + ) + test.wait_for_events() + test.socket.capability:__queue_receive( { - capability_id = "windowShadeLevel", component_id = "main", - attribute_id = "shadeLevel", state = { value = 85 } + mock_device.id, + { capability = "windowShade", component = "main", command = "close", args = {} } } + ) + test.socket.zigbee:__expect_send({ + mock_device.id, + WindowCovering.server.commands.GoToLiftPercentage(mock_device, 100) + }) + test.wait_for_events() + test.socket.zigbee:__queue_receive({ + mock_device.id, + build_default_response_msg(WindowCovering.ID, WindowCovering.server.commands.GoToLiftPercentage.ID, Status.SUCCESS) }) test.socket.capability:__expect_send( - mock_device:generate_test_message("main", capabilities.windowShade.windowShade.opening()) + mock_device:generate_test_message("main", capabilities.windowShade.windowShade.closing()) ) test.wait_for_events() - - test.mock_time.advance_time(1) + test.socket.zigbee:__queue_receive({ + mock_device.id, + WindowCovering.attributes.CurrentPositionLiftPercentage:build_test_attr_report(mock_device, 100) + }) test.socket.capability:__expect_send( - mock_device:generate_test_message("main", capabilities.windowShade.windowShade.partially_open()) + mock_device:generate_test_message("main", capabilities.windowShade.windowShade.closed()) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.windowShadeLevel.shadeLevel(0)) ) - test.wait_for_events() - - test.mock_time.advance_time(28) - test.wait_for_events() end ) diff --git a/drivers/SmartThings/zigbee-window-treatment/src/yoolax/init.lua b/drivers/SmartThings/zigbee-window-treatment/src/yoolax/init.lua index 827b984151..d98924f54a 100644 --- a/drivers/SmartThings/zigbee-window-treatment/src/yoolax/init.lua +++ b/drivers/SmartThings/zigbee-window-treatment/src/yoolax/init.lua @@ -14,12 +14,14 @@ local capabilities = require "st.capabilities" local zcl_clusters = require "st.zigbee.zcl.clusters" +local zcl_global_commands = require "st.zigbee.zcl.global_commands" +local Status = require "st.zigbee.generated.types.ZclStatus" local WindowCovering = zcl_clusters.WindowCovering -local windowShadeDefaults = require "st.zigbee.defaults.windowShade_defaults" local device_management = require "st.zigbee.device_management" local LEVEL_UPDATE_TIMEOUT = "__level_update_timeout" +local MOST_RECENT_SETLEVEL = "__most_recent_setlevel" local YOOLAX_WINDOW_SHADE_FINGERPRINTS = { { mfr = "Yookee", model = "D10110" }, -- Yookee Window Treatment @@ -35,10 +37,34 @@ local function is_yoolax_window_shade(opts, driver, device) return false end +local function default_response_handler(driver, device, zb_message) + local is_success = zb_message.body.zcl_body.status.value + local command = zb_message.body.zcl_body.cmd.value + + if is_success == Status.SUCCESS and command == WindowCovering.server.commands.GoToLiftPercentage.ID then + local current_level = device:get_latest_state("main", capabilities.windowShadeLevel.ID, capabilities.windowShadeLevel.shadeLevel.NAME) + if current_level then current_level = 100 - current_level end -- convert to the zigbee value + local most_recent_setlevel = device:get_field(MOST_RECENT_SETLEVEL) + if current_level and most_recent_setlevel and current_level ~= most_recent_setlevel then + if current_level > most_recent_setlevel then + device:emit_event(capabilities.windowShade.windowShade.opening()) + else + device:emit_event(capabilities.windowShade.windowShade.closing()) + end + end + end +end + local function set_shade_level(driver, device, value, command) local level = 100 - value device:send_to_component(command.component, WindowCovering.server.commands.GoToLiftPercentage(device, level)) - local timer = device.thread:call_with_delay(30, function () + device:set_field(MOST_RECENT_SETLEVEL, level) -- set the value to the zigbee protocol value + + local timer = device:get_field(LEVEL_UPDATE_TIMEOUT) + if timer then + device.thread.cancel_timer(timer) + end + timer = device.thread:call_with_delay(30, function () -- for some reason the device isn't updating us about its state so we'll send another bind request device:send(device_management.build_bind_request(device, WindowCovering.ID, driver.environment_info.hub_zigbee_eui)) device:send(WindowCovering.attributes.CurrentPositionLiftPercentage:configure_reporting(device, 0, 600, 1)) @@ -63,12 +89,49 @@ local function set_window_shade_level(level) end local function current_position_attr_handler(driver, device, value, zb_rx) - local timer = device:get_field(LEVEL_UPDATE_TIMEOUT) - if timer then - device.thread:cancel_timer(timer) - device:set_field(LEVEL_UPDATE_TIMEOUT, nil) + local current_level = device:get_latest_state("main", capabilities.windowShadeLevel.ID, capabilities.windowShadeLevel.shadeLevel.NAME) + if current_level then current_level = 100 - current_level end -- convert to the zigbee value + + if value.value == 0 then + device:emit_event(capabilities.windowShade.windowShade.open()) + elseif value.value == 100 then + device:emit_event(capabilities.windowShade.windowShade.closed()) + elseif current_level == nil then + -- our first level change to a non-open/closed value + device:emit_event(capabilities.windowShade.windowShade.partially_open()) + end + + local most_recent_setlevel = device:get_field(MOST_RECENT_SETLEVEL) + if most_recent_setlevel and value.value == most_recent_setlevel then + -- this is a report matching our most recent set level command, assume we've stopped + device:set_field(MOST_RECENT_SETLEVEL, nil) + if value.value ~= 0 and value.value ~= 100 then + device:emit_event(capabilities.windowShade.windowShade.partially_open()) + end + local timer = device:get_field(LEVEL_UPDATE_TIMEOUT) + if timer then + device.thread:cancel_timer(timer) + device:set_field(LEVEL_UPDATE_TIMEOUT, nil) + end + elseif most_recent_setlevel == nil then + -- this is a spontaneous level change + if current_level and current_level ~= value.value then + if current_level > value.value then + device:emit_event(capabilities.windowShade.windowShade.opening()) + else + device:emit_event(capabilities.windowShade.windowShade.closing()) + end + device.thread:call_with_delay(2, function() + -- if we don't have a changed level value within the next 2s, assume we've stopped moving + local current_level_now = device:get_latest_state("main", capabilities.windowShadeLevel.ID, capabilities.windowShadeLevel.shadeLevel.NAME) + if current_level_now then current_level_now = 100 - current_level_now end -- convert to the zigbee value + if current_level_now == value.value and current_level_now ~= 0 and current_level_now ~= 100 then + device:emit_event(capabilities.windowShade.windowShade.partially_open()) + end + end) + end end - windowShadeDefaults.default_current_lift_percentage_handler(driver, device, {value = 100 - value.value}, zb_rx) + device:emit_event(capabilities.windowShadeLevel.shadeLevel(100 - value.value)) end local yoolax_window_shade = { @@ -76,8 +139,8 @@ local yoolax_window_shade = { capability_handlers = { [capabilities.windowShade.ID] = { [capabilities.windowShadeLevel.commands.setShadeLevel.NAME] = window_shade_level_cmd, - [capabilities.windowShade.commands.open.NAME] = set_window_shade_level(100), - [capabilities.windowShade.commands.close.NAME] = set_window_shade_level(0), + [capabilities.windowShade.commands.open.NAME] = set_window_shade_level(100), -- a report of 0 = open + [capabilities.windowShade.commands.close.NAME] = set_window_shade_level(0), -- a report of 100 = closed }, [capabilities.windowShadePreset.ID] = { [capabilities.windowShadePreset.commands.presetPosition.NAME] = window_shade_preset_cmd @@ -88,7 +151,12 @@ local yoolax_window_shade = { [WindowCovering.ID] = { [WindowCovering.attributes.CurrentPositionLiftPercentage.ID] = current_position_attr_handler } - } + }, + global = { + [WindowCovering.ID] = { + [zcl_global_commands.DEFAULT_RESPONSE_ID] = default_response_handler + } + }, }, can_handle = is_yoolax_window_shade } From 352d768add335b330d79fc44d59fa857ff44eddd Mon Sep 17 00:00:00 2001 From: Steven Green Date: Wed, 3 Jan 2024 12:20:59 -0800 Subject: [PATCH 3/8] CHAD-12259 zigbee motion: high battery usage Users reported higher battery consumption with edge drivers and a disparity was noted between DTH and driver cluster configurations. A forthcoming change in the lua libraries will change the defaults, but this change should significantly improve the situation for most users in the meantime with a simple refresh. Changes the IAS Zone reporting configuration to use the device defaults and changes temperature reporting to a max interval of 10 minutes with a 1 degree celsius reporting threshold. add change for zigbee contact as well --- .../src/battery-overrides/init.lua | 27 --- .../src/contact-temperature-sensor/init.lua | 1 + .../SmartThings/zigbee-contact/src/init.lua | 1 - .../multi-sensor/centralite-multi/init.lua | 3 + .../zigbee-contact/src/multi-sensor/init.lua | 8 +- .../multi-sensor/smartthings-multi/init.lua | 3 + .../src/test/test_centralite_multi_sensor.lua | 8 - .../src/test/test_samjin_multi_sensor.lua | 8 - .../test/test_smartthings_multi_sensor.lua | 8 - .../src/centralite/init.lua | 5 + .../zigbee-motion-sensor/src/init.lua | 26 +++ .../zigbee-motion-sensor/src/iris/init.lua | 10 +- .../zigbee-motion-sensor/src/samjin/init.lua | 9 + .../src/smartthings/init.lua | 4 + .../test_all_capabilities_zigbee_motion.lua | 24 +++ .../src/test/test_aurora_motion.lua | 12 ++ .../src/test/test_samjin_sensor.lua | 18 +- .../src/test/test_sengled_motion.lua | 2 + .../src/test/test_zigbee_motion_iris.lua | 174 ++++++++++-------- 19 files changed, 213 insertions(+), 138 deletions(-) delete mode 100644 drivers/SmartThings/zigbee-contact/src/battery-overrides/init.lua diff --git a/drivers/SmartThings/zigbee-contact/src/battery-overrides/init.lua b/drivers/SmartThings/zigbee-contact/src/battery-overrides/init.lua deleted file mode 100644 index ce43b96d2a..0000000000 --- a/drivers/SmartThings/zigbee-contact/src/battery-overrides/init.lua +++ /dev/null @@ -1,27 +0,0 @@ --- Copyright 2022 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 battery_defaults = require "st.zigbee.defaults.battery_defaults" - -local battery_range_2_1v_handler = { - NAME = "Cell battery 2.1v", - lifecycle_handlers = { - init = battery_defaults.build_linear_voltage_init(2.1, 3.0) - }, - can_handle = function(opts, driver, device, ...) - return device:get_manufacturer() == "Visonic" - end -} - -return battery_range_2_1v_handler diff --git a/drivers/SmartThings/zigbee-contact/src/contact-temperature-sensor/init.lua b/drivers/SmartThings/zigbee-contact/src/contact-temperature-sensor/init.lua index 8eaf2e4d38..87ee88c5f3 100644 --- a/drivers/SmartThings/zigbee-contact/src/contact-temperature-sensor/init.lua +++ b/drivers/SmartThings/zigbee-contact/src/contact-temperature-sensor/init.lua @@ -22,6 +22,7 @@ local CONTACT_TEMPERATURE_SENSOR_FINGERPRINTS = { { mfr = "CentraLite", model = "3323-G" }, { mfr = "CentraLite", model = "Contact Sensor-A" }, { mfr = "Visonic", model = "MCT-340 E" }, + { mfr = "Visonic", model = "MCT-340 SMA" }, { mfr = "Ecolink", model = "4655BC0-R" }, { mfr = "Ecolink", model = "DWZB1-ECO" }, { mfr = "iMagic by GreatStar", model = "1116-S" }, diff --git a/drivers/SmartThings/zigbee-contact/src/init.lua b/drivers/SmartThings/zigbee-contact/src/init.lua index 53a2665e1f..7a1dc6b237 100644 --- a/drivers/SmartThings/zigbee-contact/src/init.lua +++ b/drivers/SmartThings/zigbee-contact/src/init.lua @@ -45,7 +45,6 @@ local zigbee_contact_driver_template = { }, sub_drivers = { require("aqara"), - require("battery-overrides"), require("aurora-contact-sensor"), require("contact-temperature-sensor"), require("multi-sensor"), diff --git a/drivers/SmartThings/zigbee-contact/src/multi-sensor/centralite-multi/init.lua b/drivers/SmartThings/zigbee-contact/src/multi-sensor/centralite-multi/init.lua index c398cd7831..1e75aa6b0d 100644 --- a/drivers/SmartThings/zigbee-contact/src/multi-sensor/centralite-multi/init.lua +++ b/drivers/SmartThings/zigbee-contact/src/multi-sensor/centralite-multi/init.lua @@ -16,6 +16,7 @@ local battery_defaults = require "st.zigbee.defaults.battery_defaults" local multi_utils = require "multi-sensor/multi_utils" local capabilities = require "st.capabilities" local data_types = require "st.zigbee.data_types" +local zcl_clusters = require "st.zigbee.zcl.clusters" local TARGET_DEV_MAJOR = 1 local TARGET_DEV_MINOR = 15 @@ -24,6 +25,8 @@ local TARGET_DEV_BUILD = 7 local CENTRALITE_MFG = 0x104E local init_handler = function(self, device) + device:remove_configured_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) + device:remove_monitored_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) local firmware_full_version = device.data.firmwareFullVersion or "0000" local dev_major = tonumber(firmware_full_version:sub(1,1), 16) local dev_minor = tonumber(firmware_full_version:sub(2,2), 16) diff --git a/drivers/SmartThings/zigbee-contact/src/multi-sensor/init.lua b/drivers/SmartThings/zigbee-contact/src/multi-sensor/init.lua index 33629b4b7c..a440156c11 100644 --- a/drivers/SmartThings/zigbee-contact/src/multi-sensor/init.lua +++ b/drivers/SmartThings/zigbee-contact/src/multi-sensor/init.lua @@ -64,6 +64,11 @@ local function zone_status_handler(driver, device, zone_status, zb_rx) end end +local function do_init(driver, device) + device:remove_configured_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) + device:remove_monitored_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) +end + local function added_handler(self, device) device:emit_event(capabilities.accelerationSensor.acceleration.inactive()) device:refresh() @@ -72,7 +77,8 @@ end local multi_sensor = { NAME = "Zigbee Multi Sensor", lifecycle_handlers = { - added = added_handler + added = added_handler, + init = do_init }, zigbee_handlers = { global = { diff --git a/drivers/SmartThings/zigbee-contact/src/multi-sensor/smartthings-multi/init.lua b/drivers/SmartThings/zigbee-contact/src/multi-sensor/smartthings-multi/init.lua index a0150bdcd0..69d0b7f3f4 100644 --- a/drivers/SmartThings/zigbee-contact/src/multi-sensor/smartthings-multi/init.lua +++ b/drivers/SmartThings/zigbee-contact/src/multi-sensor/smartthings-multi/init.lua @@ -17,6 +17,7 @@ local zcl_commands = require "st.zigbee.zcl.global_commands" local multi_utils = require "multi-sensor/multi_utils" local capabilities = require "st.capabilities" local data_types = require "st.zigbee.data_types" +local zcl_clusters = require "st.zigbee.zcl.clusters" local SMARTTHINGS_MFG = 0x110A @@ -55,6 +56,8 @@ end local function init_handler(driver, device) battery_defaults.enable_battery_voltage_table(device, battery_table) + device:remove_configured_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) + device:remove_monitored_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) end local function do_configure(self, device) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_centralite_multi_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_centralite_multi_sensor.lua index 10a3e3284d..2b93291472 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_centralite_multi_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_centralite_multi_sensor.lua @@ -242,14 +242,6 @@ test.register_coroutine_test( mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) }) - test.socket.zigbee:__expect_send({ - mock_device.id, - zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, IASZone.ID) - }) - test.socket.zigbee:__expect_send({ - mock_device.id, - IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 30, 300, 1) - }) test.socket.zigbee:__expect_send({ mock_device.id, IASCIEAddress:write(mock_device, zigbee_test_utils.mock_hub_eui) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_samjin_multi_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_samjin_multi_sensor.lua index 95f33f5c60..a1b72c1344 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_samjin_multi_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_samjin_multi_sensor.lua @@ -149,14 +149,6 @@ test.register_coroutine_test( mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) }) - test.socket.zigbee:__expect_send({ - mock_device.id, - zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, IASZone.ID) - }) - test.socket.zigbee:__expect_send({ - mock_device.id, - IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 30, 300, 1) - }) test.socket.zigbee:__expect_send({ mock_device.id, IASCIEAddress:write(mock_device, zigbee_test_utils.mock_hub_eui) diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_smartthings_multi_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_smartthings_multi_sensor.lua index 9a54704a1c..0953858c0d 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_smartthings_multi_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_smartthings_multi_sensor.lua @@ -296,14 +296,6 @@ test.register_coroutine_test( mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) }) - test.socket.zigbee:__expect_send({ - mock_device.id, - zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, IASZone.ID) - }) - test.socket.zigbee:__expect_send({ - mock_device.id, - IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 30, 300, 1) - }) test.socket.zigbee:__expect_send({ mock_device.id, IASCIEAddress:write(mock_device, zigbee_test_utils.mock_hub_eui) diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/centralite/init.lua b/drivers/SmartThings/zigbee-motion-sensor/src/centralite/init.lua index b76fc4091b..6a40360224 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/centralite/init.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/centralite/init.lua @@ -13,12 +13,17 @@ -- limitations under the License. local battery_defaults = require "st.zigbee.defaults.battery_defaults" +local zcl_clusters = require "st.zigbee.zcl.clusters" local TARGET_DEV_MAJOR = 1 local TARGET_DEV_MINOR = 15 local TARGET_DEV_BUILD = 7 local init_handler = function(self, device) + -- TODO: the IAS Zone changes should be replaced after supporting functions are included in the lua libs + device:remove_monitored_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) + device:remove_configured_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) + local firmware_full_version = device.data.firmwareFullVersion or "0000" local dev_major = tonumber(firmware_full_version:sub(1,1), 16) local dev_minor = tonumber(firmware_full_version:sub(2,2), 16) diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/init.lua b/drivers/SmartThings/zigbee-motion-sensor/src/init.lua index d299296fca..88e06eae68 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/init.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/init.lua @@ -16,6 +16,27 @@ local capabilities = require "st.capabilities" local ZigbeeDriver = require "st.zigbee" local defaults = require "st.zigbee.defaults" local constants = require "st.zigbee.constants" +local zcl_clusters = require "st.zigbee.zcl.clusters" + +local HAS_RECONFIGURED = "_has_reconfigured" + +-- TODO: Remove when available in lua libs +-- This is a temporary method to lower battery consumption in several devices. +-- Disparities were noted between DTH implementations and driver defaults. -sg +local do_refresh = function(driver, device, command) + device:refresh() + + if device:get_field(HAS_RECONFIGURED) == nil then + if device:supports_capability_by_id(capabilities.temperatureMeasurement.ID) and device:supports_server_cluster(zcl_clusters.TemperatureMeasurement.ID) then + device:send(zcl_clusters.TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(device, 30, 600, 100)) + end + + if device:supports_capability_by_id(capabilities.motionSensor.ID) and device:supports_server_cluster(zcl_clusters.IASZone.ID) then + device:send(zcl_clusters.IASZone.attributes.ZoneStatus:configure_reporting(device, 0xFFFF, 0x0000, 0)) -- reset to default + end + device:set_field(HAS_RECONFIGURED, true) + end +end local zigbee_motion_driver = { supported_capabilities = { @@ -26,6 +47,11 @@ local zigbee_motion_driver = { capabilities.presenceSensor, capabilities.contactSensor }, + capability_handlers = { + [capabilities.refresh.ID] = { + [capabilities.refresh.commands.refresh.NAME] = do_refresh, + } + }, sub_drivers = { require("aqara"), require("aurora"), diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/iris/init.lua b/drivers/SmartThings/zigbee-motion-sensor/src/iris/init.lua index 6ac08a9169..5a553b4325 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/iris/init.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/iris/init.lua @@ -12,12 +12,20 @@ -- See the License for the specific language governing permissions and -- limitations under the License. +local zcl_clusters = require "st.zigbee.zcl.clusters" local battery_defaults = require "st.zigbee.defaults.battery_defaults" local ZIGBEE_IRIS_MOTION_SENSOR_FINGERPRINTS = { { mfr = "iMagic by GreatStar", model = "1117-S" } } +-- TODO: the IAS Zone changes should be replaced after supporting functions are included in the lua libs +local do_init = function(driver, device) + battery_defaults.build_linear_voltage_init(2.4, 2.7)(driver, device) + device:remove_monitored_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) + device:remove_configured_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) +end + local is_zigbee_iris_motion_sensor = function(opts, driver, device) for _, fingerprint in ipairs(ZIGBEE_IRIS_MOTION_SENSOR_FINGERPRINTS) do if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then @@ -30,7 +38,7 @@ end local iris_motion_handler = { NAME = "Iris Motion Handler", lifecycle_handlers = { - init = battery_defaults.build_linear_voltage_init(2.4, 2.7) + init = do_init }, can_handle = is_zigbee_iris_motion_sensor } diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/samjin/init.lua b/drivers/SmartThings/zigbee-motion-sensor/src/samjin/init.lua index 349a783749..66fe8b4491 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/samjin/init.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/samjin/init.lua @@ -20,6 +20,12 @@ local capabilities = require "st.capabilities" local utils = require "st.utils" +-- TODO: the IAS Zone changes should be replaced after supporting functions are included in the lua libs +local do_init = function(driver, device) + device:remove_monitored_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) + device:remove_configured_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) +end + local function samjin_battery_percentage_handler(driver, device, raw_value, zb_rx) local raw_percentage = raw_value.value - (200 - raw_value.value) / 2 local percentage = utils.clamp_value(utils.round(raw_percentage / 2), 0, 100) @@ -28,6 +34,9 @@ end local samjin_driver = { NAME = "Samjin Sensor", + lifecycle_handlers = { + init = do_init + }, zigbee_handlers = { attr = { [PowerConfiguration.ID] = { diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/smartthings/init.lua b/drivers/SmartThings/zigbee-motion-sensor/src/smartthings/init.lua index c297cab8e9..586378edc5 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/smartthings/init.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/smartthings/init.lua @@ -12,6 +12,7 @@ -- See the License for the specific language governing permissions and -- limitations under the License. +local zcl_clusters = require "st.zigbee.zcl.clusters" local battery_defaults = require "st.zigbee.defaults.battery_defaults" local battery_table = { @@ -33,6 +34,9 @@ local battery_table = { local function init_handler(driver, device) battery_defaults.enable_battery_voltage_table(device, battery_table) + -- TODO: the IAS Zone changes should be replaced after supporting functions are included in the lua libs + device:remove_monitored_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) + device:remove_configured_attribute(zcl_clusters.IASZone.ID, zcl_clusters.IASZone.attributes.ZoneStatus.ID) end local smartthings_motion = { diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_all_capabilities_zigbee_motion.lua b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_all_capabilities_zigbee_motion.lua index efab5273e8..4f348b727f 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_all_capabilities_zigbee_motion.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_all_capabilities_zigbee_motion.lua @@ -196,6 +196,10 @@ test.register_coroutine_test( mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 0x10) }) + test.socket.zigbee:__expect_send({ + mock_device.id, + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) + }) test.socket.zigbee:__expect_send({ mock_device.id, zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, TemperatureMeasurement.ID) @@ -228,6 +232,10 @@ test.register_coroutine_test( mock_device.id, IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 30, 300, 0) }) + test.socket.zigbee:__expect_send({ + mock_device.id, + IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 0xFFFF, 0x0000, 0) + }) test.socket.zigbee:__expect_send({ mock_device.id, zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, IASZone.ID) @@ -285,6 +293,22 @@ test.register_message_test( IASZone.attributes.ZoneStatus:read(mock_device) } }, + { + channel = "zigbee", + direction = "send", + message = { + mock_device.id, + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) + } + }, + { + channel = "zigbee", + direction = "send", + message = { + mock_device.id, + IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 0xFFFF, 0x0000, 0) + } + }, }, { inner_block_ordering = "relaxed" diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_aurora_motion.lua b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_aurora_motion.lua index be74d835fa..c77d9d623d 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_aurora_motion.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_aurora_motion.lua @@ -136,6 +136,10 @@ test.register_coroutine_test( mock_device.id, zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, IASZone.ID) }) + test.socket.zigbee:__expect_send({ + mock_device.id, + IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 0xFFFF, 0x0000, 0) + }) mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end @@ -170,6 +174,14 @@ test.register_message_test( IASZone.attributes.ZoneStatus:read(mock_device) } }, + { + channel = "zigbee", + direction = "send", + message = { + mock_device.id, + IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 0xFFFF, 0x0000, 0) + } + }, }, { inner_block_ordering = "relaxed" diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_samjin_sensor.lua b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_samjin_sensor.lua index a83b42aa6f..637b2346f8 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_samjin_sensor.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_samjin_sensor.lua @@ -72,6 +72,10 @@ test.register_coroutine_test( mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) }) + test.socket.zigbee:__expect_send({ + mock_device.id, + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) + }) test.socket.zigbee:__expect_send({ mock_device.id, zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, TemperatureMeasurement.ID) @@ -88,14 +92,18 @@ test.register_coroutine_test( mock_device.id, IASZone.attributes.ZoneStatus:read(mock_device) }) + -- test.socket.zigbee:__expect_send({ + -- mock_device.id, + -- IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 30, 300, 0) + -- }) test.socket.zigbee:__expect_send({ mock_device.id, - IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 30, 300, 0) - }) - test.socket.zigbee:__expect_send({ - mock_device.id, - zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, IASZone.ID) + IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 0xFFFF, 0x0000, 0) }) + -- test.socket.zigbee:__expect_send({ + -- mock_device.id, + -- zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, IASZone.ID) + -- }) mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) end ) diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_sengled_motion.lua b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_sengled_motion.lua index 0b5a0d4027..1b9676c9b6 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_sengled_motion.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_sengled_motion.lua @@ -52,6 +52,7 @@ test.register_coroutine_test( test.socket.capability:__queue_receive({ mock_device.id, { capability = "refresh", component = "main", command = "refresh", args = {} } }) test.socket.zigbee:__expect_send({ mock_device.id, IASZone.attributes.ZoneStatus:read(mock_device) }) test.socket.zigbee:__expect_send({ mock_device.id, PowerConfiguration.attributes.BatteryVoltage:read(mock_device) }) + test.socket.zigbee:__expect_send({ mock_device.id, IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 0xFFFF, 0x0000, 0) }) end ) @@ -79,6 +80,7 @@ test.register_coroutine_test( IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 30, 3600, 1) } ) + test.socket.zigbee:__expect_send({ mock_device.id, IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 0xFFFF, 0x0000, 0) }) test.socket.zigbee:__expect_send( { mock_device.id, diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_zigbee_motion_iris.lua b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_zigbee_motion_iris.lua index 11d3786c22..922bc663c9 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_zigbee_motion_iris.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_zigbee_motion_iris.lua @@ -24,17 +24,17 @@ local zigbee_test_utils = require "integration_test.zigbee_test_utils" local t_utils = require "integration_test.utils" local mock_device = test.mock_device.build_test_zigbee_device( - { - profile = t_utils.get_profile_definition("motion-humidity-temp-battery.yml"), - zigbee_endpoints = { - [1] = { - id = 1, - manufacturer = "iMagic by GreatStar", - model = "1117-S", - server_clusters = {0x0001, 0x0402, 0x0405, 0x0500} - } + { + profile = t_utils.get_profile_definition("motion-humidity-temp-battery.yml"), + zigbee_endpoints = { + [1] = { + id = 1, + manufacturer = "iMagic by GreatStar", + model = "1117-S", + server_clusters = {0x0001, 0x0402, 0x0405, 0x0500} } } + } ) zigbee_test_utils.prepare_zigbee_env_info() @@ -46,81 +46,97 @@ test.set_test_init_function(test_init) test.register_coroutine_test( - "Battery Voltage test cases", - function() - -- Manufacturer name: - --[batteryVoltage] = batteryPercentage - local battery_test_map = { - ["iMagic by GreatStar"] = { - [28] = 100, - [27] = 100, - [26] = 67, - [25] = 33, - [24] = 0, - [23] = 0 - } + "Battery Voltage test cases", + function() + -- Manufacturer name: + --[batteryVoltage] = batteryPercentage + local battery_test_map = { + ["iMagic by GreatStar"] = { + [28] = 100, + [27] = 100, + [26] = 67, + [25] = 33, + [24] = 0, + [23] = 0 } + } - for voltage, batt_perc in pairs(battery_test_map[mock_device:get_manufacturer()]) do - test.socket.zigbee:__queue_receive({ mock_device.id, PowerConfiguration.attributes.BatteryVoltage:build_test_attr_report(mock_device, voltage) }) - test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.battery.battery(batt_perc)) ) - test.wait_for_events() - end + for voltage, batt_perc in pairs(battery_test_map[mock_device:get_manufacturer()]) do + test.socket.zigbee:__queue_receive({ mock_device.id, PowerConfiguration.attributes.BatteryVoltage:build_test_attr_report(mock_device, voltage) }) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.battery.battery(batt_perc)) ) + test.wait_for_events() end - ) + end +) test.register_message_test( - "Refresh should read all necessary attributes", - { - { - channel = "device_lifecycle", - direction = "receive", - message = {mock_device.id, "added"} - }, - { - channel = "capability", - direction = "receive", - message = { - mock_device.id, - { capability = "refresh", component = "main", command = "refresh", args = {} } - } - }, - { - channel = "zigbee", - direction = "send", - message = { - mock_device.id, - PowerConfiguration.attributes.BatteryVoltage:read(mock_device) - } - }, - { - channel = "zigbee", - direction = "send", - message = { - mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:read(mock_device) - } - }, - { - channel = "zigbee", - direction = "send", - message = { - mock_device.id, - RelativeHumidity.attributes.MeasuredValue:read(mock_device) - } - }, - { - channel = "zigbee", - direction = "send", - message = { - mock_device.id, - IASZone.attributes.ZoneStatus:read(mock_device) - } - }, - }, - { - inner_block_ordering = "relaxed" - } + "Refresh should read all necessary attributes", + { + { + channel = "device_lifecycle", + direction = "receive", + message = {mock_device.id, "added"} + }, + { + channel = "capability", + direction = "receive", + message = { + mock_device.id, + { capability = "refresh", component = "main", command = "refresh", args = {} } + } + }, + { + channel = "zigbee", + direction = "send", + message = { + mock_device.id, + PowerConfiguration.attributes.BatteryVoltage:read(mock_device) + } + }, + { + channel = "zigbee", + direction = "send", + message = { + mock_device.id, + TemperatureMeasurement.attributes.MeasuredValue:read(mock_device) + } + }, + { + channel = "zigbee", + direction = "send", + message = { + mock_device.id, + RelativeHumidity.attributes.MeasuredValue:read(mock_device) + } + }, + { + channel = "zigbee", + direction = "send", + message = { + mock_device.id, + IASZone.attributes.ZoneStatus:read(mock_device) + } + }, + { + channel = "zigbee", + direction = "send", + message = { + mock_device.id, + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) + } + }, + { + channel = "zigbee", + direction = "send", + message = { + mock_device.id, + IASZone.attributes.ZoneStatus:configure_reporting(mock_device, 0xFFFF, 0x0000, 0) + } + }, + }, + { + inner_block_ordering = "relaxed" + } ) test.run_registered_tests() From e2bd207bd27e759f1f7dfbb1232167deaca5ca15 Mon Sep 17 00:00:00 2001 From: lisongjun12 <104352186+lisongjun12@users.noreply.github.com> Date: Wed, 31 Jan 2024 23:54:50 +0800 Subject: [PATCH 4/8] M5 wwts (#1158) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adding SONOFF matter device:MINIR4M * Adding SONOFF matter device:M5-1C、M5-2C、M5-3C --------- Co-authored-by: lelandblue <79465613+lelandblue@users.noreply.github.com> --- .../SmartThings/matter-switch/fingerprints.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/SmartThings/matter-switch/fingerprints.yml b/drivers/SmartThings/matter-switch/fingerprints.yml index 323daa4e90..518f716326 100644 --- a/drivers/SmartThings/matter-switch/fingerprints.yml +++ b/drivers/SmartThings/matter-switch/fingerprints.yml @@ -70,6 +70,22 @@ matterManufacturer: vendorId: 0x1321 productId: 0x0002 deviceProfileName: plug-binary + - id: "SONOFF M5-1C" + deviceLabel: SONOFF SwitchMan Smart Wall Switch + vendorId: 0x1321 + productId: 0x000B + deviceProfileName: switch-binary + - id: "SONOFF M5-2C" + deviceLabel: SONOFF SwitchMan Smart Wall Switch + vendorId: 0x1321 + productId: 0x000C + deviceProfileName: switch-binary + - id: "SONOFF M5-3C" + deviceLabel: SONOFF SwitchMan Smart Wall Switch + vendorId: 0x1321 + productId: 0x000D + deviceProfileName: switch-binary + #Yeelight - id: "Yeelight Smart Lamp" deviceLabel: Yeelight Smart Lamp From 632e96c71954390c7ea169355c7cabf12a79a03b Mon Sep 17 00:00:00 2001 From: Abdul Samad Date: Wed, 31 Jan 2024 15:57:47 -0800 Subject: [PATCH 5/8] Fix the battery check in matter-thermostat, look for feature map --- drivers/SmartThings/matter-thermostat/src/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/SmartThings/matter-thermostat/src/init.lua b/drivers/SmartThings/matter-thermostat/src/init.lua index d221caeae8..eeba65e635 100644 --- a/drivers/SmartThings/matter-thermostat/src/init.lua +++ b/drivers/SmartThings/matter-thermostat/src/init.lua @@ -118,7 +118,7 @@ local function do_configure(driver, device) local thermo_eps = device:get_endpoints(clusters.Thermostat.ID) local fan_eps = device:get_endpoints(clusters.FanControl.ID) local humidity_eps = device:get_endpoints(clusters.RelativeHumidityMeasurement.ID) - local battery_eps = device:get_endpoints(clusters.PowerSource.ID) + local battery_eps = device:get_endpoints(clusters.PowerSource.ID, {feature_bitmap = clusters.PowerSource.types.PowerSourceFeature.BATTERY}) local profile_name = "thermostat" --Note: we have not encountered thermostats with multiple endpoints that support the Thermostat cluster if #thermo_eps == 1 then From a58f397ed0759dbbe1ac4347201f53ae0c64eb94 Mon Sep 17 00:00:00 2001 From: Cooper Towns Date: Wed, 31 Jan 2024 18:14:23 -0600 Subject: [PATCH 6/8] Matter Button: specifically check for battery in power source --- drivers/SmartThings/matter-button/src/init.lua | 2 +- .../SmartThings/matter-button/src/test/test_matter_button.lua | 2 +- .../matter-button/src/test/test_matter_button_parent_child.lua | 2 +- .../matter-button/src/test/test_matter_multi_button.lua | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/SmartThings/matter-button/src/init.lua b/drivers/SmartThings/matter-button/src/init.lua index d78812807d..88379c765c 100644 --- a/drivers/SmartThings/matter-button/src/init.lua +++ b/drivers/SmartThings/matter-button/src/init.lua @@ -174,7 +174,7 @@ local function device_added(driver, device) local battery_support = false if device.manufacturer_info.vendor_id ~= HUE_MANUFACTURER_ID and - #device:get_endpoints(clusters.PowerSource.ID) > 0 then + #device:get_endpoints(clusters.PowerSource.ID, {feature_bitmap = clusters.PowerSource.types.PowerSourceFeature.BATTERY}) > 0 then battery_support = true end diff --git a/drivers/SmartThings/matter-button/src/test/test_matter_button.lua b/drivers/SmartThings/matter-button/src/test/test_matter_button.lua index 2eb5b26489..c18daeab98 100644 --- a/drivers/SmartThings/matter-button/src/test/test_matter_button.lua +++ b/drivers/SmartThings/matter-button/src/test/test_matter_button.lua @@ -19,7 +19,7 @@ local mock_device = test.mock_device.build_test_matter_device( feature_map = clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH, cluster_type = "SERVER" }, - {cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER"} + {cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER", feature_map = clusters.PowerSource.types.PowerSourceFeature.BATTERY} }, }, }, diff --git a/drivers/SmartThings/matter-button/src/test/test_matter_button_parent_child.lua b/drivers/SmartThings/matter-button/src/test/test_matter_button_parent_child.lua index 31f9ba902f..83a8195090 100644 --- a/drivers/SmartThings/matter-button/src/test/test_matter_button_parent_child.lua +++ b/drivers/SmartThings/matter-button/src/test/test_matter_button_parent_child.lua @@ -22,7 +22,7 @@ local mock_device = test.mock_device.build_test_matter_device( feature_map = clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH, cluster_type = "SERVER" }, - {cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER"} + {cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER", feature_map = clusters.PowerSource.types.PowerSourceFeature.BATTERY} }, }, { diff --git a/drivers/SmartThings/matter-button/src/test/test_matter_multi_button.lua b/drivers/SmartThings/matter-button/src/test/test_matter_multi_button.lua index 96100108bd..42d97c109d 100644 --- a/drivers/SmartThings/matter-button/src/test/test_matter_multi_button.lua +++ b/drivers/SmartThings/matter-button/src/test/test_matter_multi_button.lua @@ -25,7 +25,7 @@ local mock_device = test.mock_device.build_test_matter_device( feature_map = clusters.Switch.types.SwitchFeature.MOMENTARY_SWITCH, cluster_type = "SERVER" }, - {cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER"} + {cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER", feature_map = clusters.PowerSource.types.PowerSourceFeature.BATTERY} }, }, { From 38a14ebe6ffaf6bd9c734212ad318e8c7e3391bb Mon Sep 17 00:00:00 2001 From: Cooper Towns Date: Thu, 1 Feb 2024 16:43:30 -0600 Subject: [PATCH 7/8] Fix unit tests for matter-thermostat battery check --- .../src/test/test_matter_thermo_featuremap.lua | 4 ++-- .../src/test/test_matter_thermo_setpoint_limits.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_featuremap.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_featuremap.lua index 3e408a16f4..a004c70c04 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_featuremap.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_featuremap.lua @@ -37,7 +37,7 @@ local mock_device = test.mock_device.build_test_matter_device({ endpoint_id = 1, clusters = { {cluster_id = clusters.FanControl.ID, cluster_type = "SERVER"}, - {cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER"}, + {cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER", feature_map = clusters.PowerSource.types.PowerSourceFeature.BATTERY}, { cluster_id = clusters.Thermostat.ID, cluster_revision=5, @@ -70,7 +70,7 @@ local mock_device_simple = test.mock_device.build_test_matter_device({ { endpoint_id = 1, clusters = { - {cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER"}, + {cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER", feature_map = clusters.PowerSource.types.PowerSourceFeature.BATTERY}, { cluster_id = clusters.Thermostat.ID, cluster_revision=5, diff --git a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_setpoint_limits.lua b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_setpoint_limits.lua index f5f04b574a..a28296f1ec 100644 --- a/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_setpoint_limits.lua +++ b/drivers/SmartThings/matter-thermostat/src/test/test_matter_thermo_setpoint_limits.lua @@ -42,7 +42,7 @@ local mock_device = test.mock_device.build_test_matter_device({ cluster_type="SERVER", feature_map=35, -- Heat, Cool, and Auto features. }, - {cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER"}, + {cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER", feature_map = clusters.PowerSource.types.PowerSourceFeature.BATTERY}, } } } From fcc57bda0a9ac60c629c3f2a1df5977b86f182cb Mon Sep 17 00:00:00 2001 From: cy248740603 <30711596+cy248740603@users.noreply.github.com> Date: Tue, 6 Feb 2024 23:11:09 +0800 Subject: [PATCH 8/8] Add Smartvill Switch drivers (#1191) * Add Smartvill Switch drivers * Modify the code according to the specifications. * Correct an oversight * use 2 spaces for our tab width * Change to multi_switch_no_master * Add a comment --- .../zigbee-switch/fingerprints.yml | 31 +++++++++++++++++++ .../src/multi-switch-no-master/init.lua | 5 +++ 2 files changed, 36 insertions(+) diff --git a/drivers/SmartThings/zigbee-switch/fingerprints.yml b/drivers/SmartThings/zigbee-switch/fingerprints.yml index e229e2e603..e1d212be01 100644 --- a/drivers/SmartThings/zigbee-switch/fingerprints.yml +++ b/drivers/SmartThings/zigbee-switch/fingerprints.yml @@ -1,4 +1,35 @@ zigbeeManufacturer: + #SMARTvill + - id: "SMARTvill/SLA06" + deviceLabel: "SMARTvill Switch 1" + manufacturer: SMARTvill + model: SLA06 + deviceProfileName: basic-switch + - id: "SMARTvill/SLA05" + deviceLabel: "SMARTvill Switch 1" + manufacturer: SMARTvill + model: SLA05 + deviceProfileName: basic-switch + - id: "SMARTvill/SLA04" + deviceLabel: "SMARTvill Switch 1" + manufacturer: SMARTvill + model: SLA04 + deviceProfileName: basic-switch + - id: "SMARTvill/SLA03" + deviceLabel: "SMARTvill Switch 1" + manufacturer: SMARTvill + model: SLA03 + deviceProfileName: basic-switch + - id: "SMARTvill/SLA02" + deviceLabel: "SMARTvill Switch 1" + manufacturer: SMARTvill + model: SLA02 + deviceProfileName: basic-switch + - id: "SMARTvill/SLA01" + deviceLabel: SMARTvill Switch 1 + manufacturer: SMARTvill + model: SLA01 + deviceProfileName: basic-switch #HANSSEM SMART SWITCH - id: "Winners/LSS1-101" deviceLabel: HS Switch 1(1 way) diff --git a/drivers/SmartThings/zigbee-switch/src/multi-switch-no-master/init.lua b/drivers/SmartThings/zigbee-switch/src/multi-switch-no-master/init.lua index d4d69f3ece..d53b27f18b 100644 --- a/drivers/SmartThings/zigbee-switch/src/multi-switch-no-master/init.lua +++ b/drivers/SmartThings/zigbee-switch/src/multi-switch-no-master/init.lua @@ -36,6 +36,11 @@ local MULTI_SWITCH_NO_MASTER_FINGERPRINTS = { { mfr = "eWeLink", model = "ZB-SW02", children = 1 }, { mfr = "eWeLink", model = "ZB-SW03", children = 2 }, { mfr = "eWeLink", model = "ZB-SW04", children = 3 }, + { mfr = "SMARTvill", model = "SLA02", children = 1 }, + { mfr = "SMARTvill", model = "SLA03", children = 2 }, + { mfr = "SMARTvill", model = "SLA04", children = 3 }, + { mfr = "SMARTvill", model = "SLA05", children = 4 }, + { mfr = "SMARTvill", model = "SLA06", children = 5 }, { mfr = "ShinaSystem", model = "SBM300Z2", children = 1 }, { mfr = "ShinaSystem", model = "SBM300Z3", children = 2 }, { mfr = "ShinaSystem", model = "SBM300Z4", children = 3 },