From fa1731d091fa74aab4161693036d12b1e0f6b56f Mon Sep 17 00:00:00 2001 From: simon3panda <340443303@qq.com> Date: Tue, 17 Dec 2024 14:43:10 +0800 Subject: [PATCH 1/2] Add Linxura Smart Controller Zigbee mode integrate with SmartThings hub Linxura Zigbee mode include 4 buttons, each button support press, double press, held. --- .../zigbee-button/fingerprints.yml | 6 + .../src/zigbee-multi-button/init.lua | 6 +- .../src/zigbee-multi-button/linxura/init.lua | 183 ++++++++++++++++++ .../zigbee-multi-button/supported_values.lua | 3 +- 4 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 drivers/SmartThings/zigbee-button/src/zigbee-multi-button/linxura/init.lua diff --git a/drivers/SmartThings/zigbee-button/fingerprints.yml b/drivers/SmartThings/zigbee-button/fingerprints.yml index 2e7b3fbe57..2efe748b62 100644 --- a/drivers/SmartThings/zigbee-button/fingerprints.yml +++ b/drivers/SmartThings/zigbee-button/fingerprints.yml @@ -184,6 +184,12 @@ zigbeeManufacturer: manufacturer: Samsung Electronics model: SAMSUNG-ITM-Z-005 deviceProfileName: SLED-three-buttons + - id: "Linxura Smart Controller" + deviceLabel: Linxura Smart Controller + manufacturer: Linxura + model: Smart Controller + deviceProfileName: four-buttons + isJoinable: true # Wall Hero - id: "WALL HERO/ACL-401SCA4" deviceLabel: WallHero Remote Control (4-Inch) diff --git a/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/init.lua b/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/init.lua index f572fd79e4..99c2e3a9ec 100644 --- a/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/init.lua +++ b/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/init.lua @@ -41,7 +41,8 @@ local ZIGBEE_MULTI_BUTTON_FINGERPRINTS = { { mfr = "ROBB smarrt", model = "ROB_200-007-0" }, { mfr = "ROBB smarrt", model = "ROB_200-008-0" }, { mfr = "WALL HERO", model = "ACL-401SCA4" }, - { mfr = "Samsung Electronics", model = "SAMSUNG-ITM-Z-005" } + { mfr = "Samsung Electronics", model = "SAMSUNG-ITM-Z-005" }, + { mfr = "Linxura", model = "Smart Controller" } } local function can_handle_zigbee_multi_button(opts, driver, device, ...) @@ -88,7 +89,8 @@ local zigbee_multi_button = { require("zigbee-multi-button.shinasystems"), require("zigbee-multi-button.robb"), require("zigbee-multi-button.wallhero"), - require("zigbee-multi-button.SLED") + require("zigbee-multi-button.SLED"), + require("zigbee-multi-button.linxura") } } diff --git a/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/linxura/init.lua b/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/linxura/init.lua new file mode 100644 index 0000000000..83bddd8fb6 --- /dev/null +++ b/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/linxura/init.lua @@ -0,0 +1,183 @@ +-- 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 capabilities = require "st.capabilities" +local IASZone = (require "st.zigbee.zcl.clusters").IASZone +local constants = require "st.zigbee.constants" +local clusters = require "st.zigbee.zcl.clusters" +local Groups = clusters.Groups +local log = require "log" +local device_management = require "st.zigbee.device_management" +local zcl_commands = require "st.zigbee.zcl.global_commands" +local zcl_clusters = require "st.zigbee.zcl.clusters" +local supported_values = require "zigbee-multi-button.supported_values" + +local BUTTON1_HELD = 0x0001 +local BUTTON1_PUSHED = 0x0003 +local BUTTON1_DOUBLE = 0x0005 +local BUTTON2_HELD = 0x0007 +local BUTTON2_PUSHED = 0x0009 +local BUTTON2_DOUBLE = 0x000B +local BUTTON3_HELD = 0x000D +local BUTTON3_PUSHED = 0x000F +local BUTTON3_DOUBLE = 0x0011 +local BUTTON4_HELD = 0x00013 +local BUTTON4_PUSHED = 0x00015 +local BUTTON4_DOUBLE = 0x0017 + +local BUTTON1 = "button1" +local BUTTON2 = "button2" +local BUTTON3 = "button3" +local BUTTON4 = "button4" + + +local LINXURA_BUTTON_FINGERPRINTS = { + { mfr = "Linxura", model = "Smart Controller" } +} + +local is_linxura_button = function(opts, driver, device) + for _, fingerprint in ipairs(LINXURA_BUTTON_FINGERPRINTS) do + if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then + return true + end + end + return false +end + +local function present_value_attr_handler(driver, device, zb_rx) + +end + +local function ias_zone_status_change_handler1(driver, device, zb_rx) + local status = zb_rx.body.zcl_body.zone_status + log.info("ias_zone_status_change_handler1 The current value is: ") + local additional_fields = { + state_change = true + } + local event + local mod = status.value % 6 + if mod == 1 then + event = capabilities.button.button.pushed(additional_fields) + elseif mod == 3 then + event = capabilities.button.button.double(additional_fields) + elseif mod == 5 then + event = capabilities.button.button.held(additional_fields) + else + return false + end + + if status.value == BUTTON1_HELD or status.value == BUTTON1_PUSHED or status.value == BUTTON1_DOUBLE then + device:emit_component_event(device.profile.components[BUTTON1], event) + --device:emit_event(device.profile.components[BUTTON1],event) + device:emit_event(event) + elseif status.value == BUTTON2_HELD or status.value == BUTTON2_PUSHED or status.value == BUTTON2_DOUBLE then + device:emit_component_event(device.profile.components[BUTTON2], event) + device:emit_event(event) + elseif status.value == BUTTON3_HELD or status.value == BUTTON3_PUSHED or status.value == BUTTON3_DOUBLE then + device:emit_component_event(device.profile.components[BUTTON3], event) + device:emit_event(event) + elseif status.value == BUTTON4_HELD or status.value == BUTTON4_PUSHED or status.value == BUTTON4_DOUBLE then + device:emit_component_event(device.profile.components[BUTTON4], event) + device:emit_event(event) + end +end + +local function ias_zone_status_change_handler(driver, device, zb_rx) + local status = zb_rx.body.zcl_body.zone_status + log.info("ias_zone_status_change_handler The current value is: ") + local additional_fields = { + state_change = true + } + local event + local mod = status.value % 6 + if mod == 1 then + event = capabilities.button.button.pushed(additional_fields) + elseif mod == 3 then + event = capabilities.button.button.double(additional_fields) + elseif mod == 5 then + event = capabilities.button.button.held(additional_fields) + else + return false + end + + if status.value == BUTTON1_HELD or status.value == BUTTON1_PUSHED or status.value == BUTTON1_DOUBLE then + device:emit_component_event(device.profile.components[BUTTON1], event) + --device:emit_event(device.profile.components[BUTTON1],event) + device:emit_event(event) + elseif status.value == BUTTON2_HELD or status.value == BUTTON2_PUSHED or status.value == BUTTON2_DOUBLE then + device:emit_component_event(device.profile.components[BUTTON2], event) + device:emit_event(event) + elseif status.value == BUTTON3_HELD or status.value == BUTTON3_PUSHED or status.value == BUTTON3_DOUBLE then + device:emit_component_event(device.profile.components[BUTTON3], event) + device:emit_event(event) + elseif status.value == BUTTON4_HELD or status.value == BUTTON4_PUSHED or status.value == BUTTON4_DOUBLE then + device:emit_component_event(device.profile.components[BUTTON4], event) + device:emit_event(event) + end +end + +local function added_handler(self, device) + log.info("bbbb") + local config = supported_values.get_device_parameters(device) + for _, component in pairs(device.profile.components) do + if config ~= nil then + --if config.NUMBER_OF_BUTTONS == 4 then + if config.NUMBER_OF_BUTTONS == 4 then + device:emit_component_event(component, + capabilities.button.supportedButtonValues(config.SUPPORTED_BUTTON_VALUES, { visibility = { displayed = false } })) + device:emit_component_event(component, + capabilities.button.numberOfButtons({ value = config.NUMBER_OF_BUTTONS }, { visibility = { displayed = false } })) + end + end + end + --device:emit_event(capabilities.button.button.pushed({state_change = false})) +end + +local do_configure = function(self, device) + log.info("configure") + device:configure() + self:add_hub_to_zigbee_group(0x0001) +end + + +local linxura_device_handler = { + NAME = "Linxura Device Handler", + lifecycle_handlers = { + doConfigure = do_configure, + added = added_handler + }, + + zigbee_handlers = { + attr = { + [IASZone.ID] = { + [IASZone.attributes.ZoneStatus.ID] = present_value_attr_handler + } + }, + cluster = { + [IASZone.ID] = { + [IASZone.client.commands.ZoneStatusChangeNotification.ID] = ias_zone_status_change_handler + } + }, + global = { + [IASZone.ID] = { + [zcl_commands.ReportAttribute.ID] = ias_zone_status_change_handler1 + } + } + }, + + can_handle = is_linxura_button, + ias_zone_configuration_method = constants.IAS_ZONE_CONFIGURE_TYPE.AUTO_ENROLL_RESPONSE +} + +return linxura_device_handler \ No newline at end of file diff --git a/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/supported_values.lua b/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/supported_values.lua index fabaa7da6f..fc6fde8f72 100644 --- a/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/supported_values.lua +++ b/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/supported_values.lua @@ -111,7 +111,8 @@ local devices = { }, BUTTON_PUSH_HELD_DOUBLE_4 = { MATCHING_MATRIX = { - { mfr = "ShinaSystem", model = "MSM-300Z" } + { mfr = "ShinaSystem", model = "MSM-300Z" }, + { mfr = "Linxura", model = "Smart Controller" } }, SUPPORTED_BUTTON_VALUES = { "pushed", "held", "double" }, NUMBER_OF_BUTTONS = 4 From 2c3b4451e5b317357ddfbd39a9fcd6f339aaddb8 Mon Sep 17 00:00:00 2001 From: simon3panda <340443303@qq.com> Date: Mon, 13 Jan 2025 14:59:56 +0800 Subject: [PATCH 2/2] Update init.lua add configuration part for Linxura smart controller driver --- .../src/zigbee-multi-button/linxura/init.lua | 89 ++++--------------- 1 file changed, 19 insertions(+), 70 deletions(-) diff --git a/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/linxura/init.lua b/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/linxura/init.lua index 83bddd8fb6..2d1bd35ec2 100644 --- a/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/linxura/init.lua +++ b/drivers/SmartThings/zigbee-button/src/zigbee-multi-button/linxura/init.lua @@ -21,7 +21,6 @@ local log = require "log" local device_management = require "st.zigbee.device_management" local zcl_commands = require "st.zigbee.zcl.global_commands" local zcl_clusters = require "st.zigbee.zcl.clusters" -local supported_values = require "zigbee-multi-button.supported_values" local BUTTON1_HELD = 0x0001 local BUTTON1_PUSHED = 0x0003 @@ -46,6 +45,16 @@ local LINXURA_BUTTON_FINGERPRINTS = { { mfr = "Linxura", model = "Smart Controller" } } +local configuration = { + { + cluster = IASZone.ID, + attribute = IASZone.attributes.ZoneStatus.ID, + minimum_interval = 0, + maximum_interval = 3600, + data_type = IASZone.attributes.ZoneStatus.base_type, + reportable_change = 1 + } +} local is_linxura_button = function(opts, driver, device) for _, fingerprint in ipairs(LINXURA_BUTTON_FINGERPRINTS) do if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then @@ -55,13 +64,11 @@ local is_linxura_button = function(opts, driver, device) return false end -local function present_value_attr_handler(driver, device, zb_rx) +local function present_value_attr_handler(driver, device, zone_status, zb_rx) + log.info("present_value_attr_handler The current value is: ", zone_status.value) + local status = zone_status -end -local function ias_zone_status_change_handler1(driver, device, zb_rx) - local status = zb_rx.body.zcl_body.zone_status - log.info("ias_zone_status_change_handler1 The current value is: ") local additional_fields = { state_change = true } @@ -93,69 +100,22 @@ local function ias_zone_status_change_handler1(driver, device, zb_rx) end end -local function ias_zone_status_change_handler(driver, device, zb_rx) - local status = zb_rx.body.zcl_body.zone_status - log.info("ias_zone_status_change_handler The current value is: ") - local additional_fields = { - state_change = true - } - local event - local mod = status.value % 6 - if mod == 1 then - event = capabilities.button.button.pushed(additional_fields) - elseif mod == 3 then - event = capabilities.button.button.double(additional_fields) - elseif mod == 5 then - event = capabilities.button.button.held(additional_fields) - else - return false - end - if status.value == BUTTON1_HELD or status.value == BUTTON1_PUSHED or status.value == BUTTON1_DOUBLE then - device:emit_component_event(device.profile.components[BUTTON1], event) - --device:emit_event(device.profile.components[BUTTON1],event) - device:emit_event(event) - elseif status.value == BUTTON2_HELD or status.value == BUTTON2_PUSHED or status.value == BUTTON2_DOUBLE then - device:emit_component_event(device.profile.components[BUTTON2], event) - device:emit_event(event) - elseif status.value == BUTTON3_HELD or status.value == BUTTON3_PUSHED or status.value == BUTTON3_DOUBLE then - device:emit_component_event(device.profile.components[BUTTON3], event) - device:emit_event(event) - elseif status.value == BUTTON4_HELD or status.value == BUTTON4_PUSHED or status.value == BUTTON4_DOUBLE then - device:emit_component_event(device.profile.components[BUTTON4], event) - device:emit_event(event) - end -end +local function device_init(driver, device) + for _, attribute in ipairs(configuration) do + device:add_configured_attribute(attribute) -local function added_handler(self, device) - log.info("bbbb") - local config = supported_values.get_device_parameters(device) - for _, component in pairs(device.profile.components) do - if config ~= nil then - --if config.NUMBER_OF_BUTTONS == 4 then - if config.NUMBER_OF_BUTTONS == 4 then - device:emit_component_event(component, - capabilities.button.supportedButtonValues(config.SUPPORTED_BUTTON_VALUES, { visibility = { displayed = false } })) - device:emit_component_event(component, - capabilities.button.numberOfButtons({ value = config.NUMBER_OF_BUTTONS }, { visibility = { displayed = false } })) - end + + device:add_monitored_attribute(attribute) end end - --device:emit_event(capabilities.button.button.pushed({state_change = false})) -end -local do_configure = function(self, device) - log.info("configure") - device:configure() - self:add_hub_to_zigbee_group(0x0001) -end local linxura_device_handler = { NAME = "Linxura Device Handler", lifecycle_handlers = { - doConfigure = do_configure, - added = added_handler + init = device_init, }, zigbee_handlers = { @@ -164,20 +124,9 @@ local linxura_device_handler = { [IASZone.attributes.ZoneStatus.ID] = present_value_attr_handler } }, - cluster = { - [IASZone.ID] = { - [IASZone.client.commands.ZoneStatusChangeNotification.ID] = ias_zone_status_change_handler - } - }, - global = { - [IASZone.ID] = { - [zcl_commands.ReportAttribute.ID] = ias_zone_status_change_handler1 - } - } }, can_handle = is_linxura_button, - ias_zone_configuration_method = constants.IAS_ZONE_CONFIGURE_TYPE.AUTO_ENROLL_RESPONSE } return linxura_device_handler \ No newline at end of file