From dca8a90ee37727eab0f5e84081af5c1738fe1f1e Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Thu, 28 Nov 2024 22:14:19 -0300 Subject: [PATCH 1/3] feat(matter): adds new matter generic switch endpoint --- CMakeLists.txt | 1 + .../MatterSmartButon/MatterSmartButon.ino | 116 ++++++++++++++++++ .../Matter/examples/MatterSmartButon/ci.json | 7 ++ libraries/Matter/keywords.txt | 3 +- libraries/Matter/src/Matter.h | 2 + .../MatterEndpoints/MatterGenericSwitch.cpp | 101 +++++++++++++++ .../src/MatterEndpoints/MatterGenericSwitch.h | 39 ++++++ 7 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 libraries/Matter/examples/MatterSmartButon/MatterSmartButon.ino create mode 100644 libraries/Matter/examples/MatterSmartButon/ci.json create mode 100644 libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp create mode 100644 libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ab001c2d09..b9090c18511 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -168,6 +168,7 @@ set(ARDUINO_LIBRARY_OpenThread_SRCS libraries/OpenThread/src/OThreadCLI_Util.cpp) set(ARDUINO_LIBRARY_Matter_SRCS + libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp libraries/Matter/src/MatterEndpoints/MatterOnOffLight.cpp libraries/Matter/src/MatterEndpoints/MatterDimmableLight.cpp libraries/Matter/src/MatterEndpoints/MatterColorTemperatureLight.cpp diff --git a/libraries/Matter/examples/MatterSmartButon/MatterSmartButon.ino b/libraries/Matter/examples/MatterSmartButon/MatterSmartButon.ino new file mode 100644 index 00000000000..0bd612bcbdf --- /dev/null +++ b/libraries/Matter/examples/MatterSmartButon/MatterSmartButon.ino @@ -0,0 +1,116 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +// Matter Manager +#include +#include +#include + +// List of Matter Endpoints for this Node +// Generic Switch Endpoint - works as a smart button with a single click +MatterGenericSwitch SmartButton; + +// set your board USER BUTTON pin here +const uint8_t buttonPin = 0; // Set your pin here. Using BOOT Button. C6/C3 use GPIO9. + +// WiFi is manually set and started +const char *ssid = "your-ssid"; // Change this to your WiFi SSID +const char *password = "your-password"; // Change this to your WiFi password + +void setup() { + // Initialize the USER BUTTON (Boot button) GPIO that will act as a toggle switch + pinMode(buttonPin, INPUT_PULLUP); + + Serial.begin(115200); + while (!Serial) { + delay(100); + } + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + // enable IPv6 + WiFi.enableIPv6(true); + // Manually connect to WiFi + WiFi.begin(ssid, password); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("\r\nWiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + delay(500); + + // Initialize the Matter EndPoint + SmartButton.begin(); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); + // This may be a restart of a already commissioned Matter accessory + if (Matter.isDeviceCommissioned()) { + Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); + } +} +// Button control +uint32_t button_time_stamp = 0; // debouncing control +bool button_state = false; // false = released | true = pressed +const uint32_t debouceTime = 250; // button debouncing time (ms) +const uint32_t decommissioningTimeout = 10000; // keep the button pressed for 10s to decommission the Matter Fabric + +void loop() { + // Check Matter Accessory Commissioning state, which may change during execution of loop() + if (!Matter.isDeviceCommissioned()) { + Serial.println(""); + Serial.println("Matter Node is not commissioned yet."); + Serial.println("Initiate the device discovery in your Matter environment."); + Serial.println("Commission it to your Matter hub with the manual pairing code or QR code"); + Serial.printf("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str()); + Serial.printf("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str()); + // waits for Matter Generic Switch Commissioning. + uint32_t timeCount = 0; + while (!Matter.isDeviceCommissioned()) { + delay(100); + if ((timeCount++ % 50) == 0) { // 50*100ms = 5 sec + Serial.println("Matter Node not commissioned yet. Waiting for commissioning."); + } + } + Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); + } + + // A builtin button is used to trigger a command to the Matter Controller + // Check if the button has been pressed + if (digitalRead(buttonPin) == LOW && !button_state) { + // deals with button debouncing + button_time_stamp = millis(); // record the time while the button is pressed. + button_state = true; // pressed. + } + + // Onboard User Button is used as a smart button or to decommission it + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > debouceTime && digitalRead(buttonPin) == HIGH) { + button_state = false; // released + // builtin button is released - send a click event to the Matter Controller + Serial.println("User button released. Sending Click to the Matter Controller!"); + // Matter Controller will receive an event and, if programmed, it will trigger an action + SmartButton.click(); + + // Factory reset is triggered if the button is pressed longer than 10 seconds + if (time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Generic Switch Matter Accessory. It shall be commissioned again."); + Matter.decommission(); + } + } +} diff --git a/libraries/Matter/examples/MatterSmartButon/ci.json b/libraries/Matter/examples/MatterSmartButon/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterSmartButon/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" + ] +} diff --git a/libraries/Matter/keywords.txt b/libraries/Matter/keywords.txt index 39a74e76583..524dd645d59 100644 --- a/libraries/Matter/keywords.txt +++ b/libraries/Matter/keywords.txt @@ -8,6 +8,7 @@ Matter KEYWORD1 ArduinoMatter KEYWORD1 +MatterGenericSwitch KEYWORD1 MatterOnOffLight KEYWORD1 MatterDimmableLight KEYWORD1 MatterColorTemperatureLight KEYWORD1 @@ -45,7 +46,7 @@ onChangeOnOff KEYWORD2 onChangeBrightness KEYWORD2 onChangeColorTemperature KEYWORD2 onChangeColorHSV KEYWORD2 - +click KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h index 4d269474187..c27ebf7e7da 100644 --- a/libraries/Matter/src/Matter.h +++ b/libraries/Matter/src/Matter.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ class ArduinoMatter { static void decommission(); // list of Matter EndPoints Friend Classes + friend class MatterGenericSwitch; friend class MatterOnOffLight; friend class MatterDimmableLight; friend class MatterColorTemperatureLight; diff --git a/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp b/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp new file mode 100644 index 00000000000..cc1786477fc --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp @@ -0,0 +1,101 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include +#include + +using namespace esp_matter; +using namespace esp_matter::endpoint; +using namespace esp_matter::cluster; +using namespace chip::app::Clusters; + +MatterGenericSwitch::MatterGenericSwitch() { +} + +MatterGenericSwitch::~MatterGenericSwitch() { + end(); +} + +bool MatterGenericSwitch::attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) { + if (!started) { + log_e("Matter Generic Switch device has not begun."); + return false; + } + + log_d("Generic Switch Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); + return true; +} + +bool MatterGenericSwitch::begin() { + ArduinoMatter::_init(); + generic_switch::config_t switch_config; + + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = generic_switch::create(node::get(), &switch_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create Generic swtich endpoint"); + return false; + } + // Add group cluster to the switch endpoint + cluster::groups::config_t groups_config; + cluster::groups::create(endpoint, &groups_config, CLUSTER_FLAG_SERVER | CLUSTER_FLAG_CLIENT); + + cluster_t* aCluster = cluster::get(endpoint,Descriptor::Id); + esp_matter::cluster::descriptor::feature::taglist::add(aCluster); + + cluster::fixed_label::config_t fl_config; + cluster::fixed_label::create(endpoint, &fl_config, CLUSTER_FLAG_SERVER); + + cluster::user_label::config_t ul_config; + cluster::user_label::create(endpoint, &ul_config, CLUSTER_FLAG_SERVER); + + aCluster = cluster::get(endpoint, Switch::Id); + switch_cluster::feature::momentary_switch::add(aCluster); + switch_cluster::event::create_initial_press(aCluster); + + switch_cluster::feature::momentary_switch::add(aCluster); + + switch_cluster::attribute::create_current_position(aCluster, 0); + switch_cluster::attribute::create_number_of_positions(aCluster, 2); + + setEndPointId(endpoint::get_id(endpoint)); + log_i("Generic Switch created with endpoint_id %d", getEndPointId()); + started = true; + return true; +} + +void MatterGenericSwitch::end() { + started = false; +} + +void MatterGenericSwitch::click() { + if (!started) { + log_e("Matter Generic Switch device has not begun."); + return; + } + + int switch_endpoint_id = getEndPointId(); + uint8_t newPosition = 1; + // Press moves Position from 0 (off) to 1 (on) + chip::DeviceLayer::SystemLayer().ScheduleLambda([switch_endpoint_id, newPosition]() { + // InitialPress event takes newPosition as event data + switch_cluster::event::send_initial_press(switch_endpoint_id, newPosition); + }); +} + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.h b/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.h new file mode 100644 index 00000000000..4f90b249d79 --- /dev/null +++ b/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.h @@ -0,0 +1,39 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#pragma once +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +// Matter Generic Switch Endpoint that works as a single click smart button +class MatterGenericSwitch : public MatterEndPoint { +public: + MatterGenericSwitch(); + ~MatterGenericSwitch(); + virtual bool begin(); + void end(); // this will just stop processing Matter events + + // send a simple click event to the Matter Controller + void click(); + + // this function is called by Matter internal event processor. It could be overwritten by the application, if necessary. + bool attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val); + +protected: + bool started = false; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ From 111400a93bccaa135b9cdf97a4cbfd34b7b686e8 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Sun, 1 Dec 2024 18:48:06 -0300 Subject: [PATCH 2/3] fix(matter): no need of arduino preferences here --- libraries/Matter/examples/MatterSmartButon/MatterSmartButon.ino | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/Matter/examples/MatterSmartButon/MatterSmartButon.ino b/libraries/Matter/examples/MatterSmartButon/MatterSmartButon.ino index 0bd612bcbdf..1d71f2123a6 100644 --- a/libraries/Matter/examples/MatterSmartButon/MatterSmartButon.ino +++ b/libraries/Matter/examples/MatterSmartButon/MatterSmartButon.ino @@ -15,7 +15,6 @@ // Matter Manager #include #include -#include // List of Matter Endpoints for this Node // Generic Switch Endpoint - works as a smart button with a single click From b2776e315bfbcfd6bcc546e573e0a3868bf364c8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 06:04:57 +0000 Subject: [PATCH 3/3] ci(pre-commit): Apply automatic fixes --- libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp | 5 ++--- libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp b/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp index cc1786477fc..f5c6c9d750f 100644 --- a/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp +++ b/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.cpp @@ -24,8 +24,7 @@ using namespace esp_matter::endpoint; using namespace esp_matter::cluster; using namespace chip::app::Clusters; -MatterGenericSwitch::MatterGenericSwitch() { -} +MatterGenericSwitch::MatterGenericSwitch() {} MatterGenericSwitch::~MatterGenericSwitch() { end(); @@ -55,7 +54,7 @@ bool MatterGenericSwitch::begin() { cluster::groups::config_t groups_config; cluster::groups::create(endpoint, &groups_config, CLUSTER_FLAG_SERVER | CLUSTER_FLAG_CLIENT); - cluster_t* aCluster = cluster::get(endpoint,Descriptor::Id); + cluster_t *aCluster = cluster::get(endpoint, Descriptor::Id); esp_matter::cluster::descriptor::feature::taglist::add(aCluster); cluster::fixed_label::config_t fl_config; diff --git a/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.h b/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.h index 4f90b249d79..14118462932 100644 --- a/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.h +++ b/libraries/Matter/src/MatterEndpoints/MatterGenericSwitch.h @@ -25,7 +25,7 @@ class MatterGenericSwitch : public MatterEndPoint { MatterGenericSwitch(); ~MatterGenericSwitch(); virtual bool begin(); - void end(); // this will just stop processing Matter events + void end(); // this will just stop processing Matter events // send a simple click event to the Matter Controller void click();