From 1229e54afe1a2defc0bf9627d2ad14a7e817cff5 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Tue, 15 Oct 2024 21:37:08 -0300 Subject: [PATCH 01/24] feat(matter): initial commit with arduino matter lib --- .../MatterCommissionTest.ino | 67 ++++++++ .../examples/MatterCommissionTest/ci.json | 7 + .../MatterComposedLights.ino | 98 +++++++++++ .../examples/MatterComposedLights/ci.json | 7 + .../MatterOnOffLight/MatterOnOffLight.ino | 105 ++++++++++++ .../Matter/examples/MatterOnOffLight/ci.json | 7 + libraries/Matter/keywords.txt | 35 ++++ libraries/Matter/library.properties | 9 + libraries/Matter/src/Matter.cpp | 159 ++++++++++++++++++ libraries/Matter/src/Matter.h | 39 +++++ libraries/Matter/src/MatterEndPoint.h | 23 +++ libraries/Matter/src/MatterOnOffLight.cpp | 108 ++++++++++++ libraries/Matter/src/MatterOnOffLight.h | 34 ++++ 13 files changed, 698 insertions(+) create mode 100644 libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino create mode 100644 libraries/Matter/examples/MatterCommissionTest/ci.json create mode 100644 libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino create mode 100644 libraries/Matter/examples/MatterComposedLights/ci.json create mode 100644 libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino create mode 100644 libraries/Matter/examples/MatterOnOffLight/ci.json create mode 100644 libraries/Matter/keywords.txt create mode 100644 libraries/Matter/library.properties create mode 100644 libraries/Matter/src/Matter.cpp create mode 100644 libraries/Matter/src/Matter.h create mode 100644 libraries/Matter/src/MatterEndPoint.h create mode 100644 libraries/Matter/src/MatterOnOffLight.cpp create mode 100644 libraries/Matter/src/MatterOnOffLight.h diff --git a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino new file mode 100644 index 00000000000..4769565edf3 --- /dev/null +++ b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino @@ -0,0 +1,67 @@ +#include +#include + +// Matter Manager +#include + +// List of Matter Endpoints for this Node +// On/Off Light Endpoint +#include +MatterOnOffLight OnOffLight; + +// WiFi is manually set and stated +const char *ssid = "your-ssid"; // Change this to your WiFi SSID +const char *password = "your-password"; // Change this to your WiFi password + +void setup() { + 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 Matter Node + Matter.begin(); + // Initialize Matter EndPoint + OnOffLight.begin(); + // Matter start + Matter.start(); +} + +void loop() { + // Check Matter Commissioning state + 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 Light Commissioning. + while (!Matter.isDeviceCommissioned()) { + delay(5000); + Serial.println("Matter Fabric not commissioned yet. Waiting for commissioning."); + } + } + Serial.println("Matter Node is commissioned and connected to Wi-Fi."); + Serial.println("====> Decommissioning in 30 seconds. <===="); + delay(30000); + Matter.decommission(); + Serial.println("Matter Node is decommissioned. Commsssioning widget shall start over."); +} \ No newline at end of file diff --git a/libraries/Matter/examples/MatterCommissionTest/ci.json b/libraries/Matter/examples/MatterCommissionTest/ci.json new file mode 100644 index 00000000000..498b7b100d3 --- /dev/null +++ b/libraries/Matter/examples/MatterCommissionTest/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] +} + \ No newline at end of file diff --git a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino new file mode 100644 index 00000000000..a052f4b6392 --- /dev/null +++ b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino @@ -0,0 +1,98 @@ +#include +#include + +// Matter Manager +#include + +// List of Matter Endpoints for this Node +// There will be 3 On/Off Light Endpoints in the same Node +#include +MatterOnOffLight OnOffLight1; +MatterOnOffLight OnOffLight2; +MatterOnOffLight OnOffLight3; + +// Matter Protocol Endpoint Callback for each Light Accessory +bool setLightOnOff1(bool state) { + Serial.printf("CB-Light1 changed state to: %s\r\n", state ? "ON" : "OFF"); + return true; +} + +bool setLightOnOff2(bool state) { + Serial.printf("CB-Light2 changed state to: %s\r\n", state ? "ON" : "OFF"); + return true; +} + +bool setLightOnOff3(bool state) { + Serial.printf("CB-Light3 changed state to: %s\r\n", state ? "ON" : "OFF"); + return true; +} + +// WiFi is manually set and stated +const char *ssid = "your-ssid"; // Change this to your WiFi SSID +const char *password = "your-password"; // Change this to your WiFi password + +void setup() { + 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 Matter Node + Matter.begin(); + + // Initialize all 3 Matter EndPoints + OnOffLight1.begin(); + OnOffLight2.begin(); + OnOffLight3.begin(); + OnOffLight1.onChangeOnOff(setLightOnOff1); + OnOffLight2.onChangeOnOff(setLightOnOff2); + OnOffLight3.onChangeOnOff(setLightOnOff3); + + // Matter start - Last step, after all EndPoints are initialized + Matter.start(); +} + +void loop() { + // Check Matter Light Commissioning state + 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 Light 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."); + } + + //displays the Light state every 3 seconds + Serial.println("======================"); + Serial.printf("Matter Light #1 is %s\r\n", OnOffLight1.getOnOff() ? "ON" : "OFF"); + Serial.printf("Matter Light #2 is %s\r\n", OnOffLight2.getOnOff() ? "ON" : "OFF"); + Serial.printf("Matter Light #3 is %s\r\n", OnOffLight3.getOnOff() ? "ON" : "OFF"); + delay(3000); +} \ No newline at end of file diff --git a/libraries/Matter/examples/MatterComposedLights/ci.json b/libraries/Matter/examples/MatterComposedLights/ci.json new file mode 100644 index 00000000000..498b7b100d3 --- /dev/null +++ b/libraries/Matter/examples/MatterComposedLights/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] +} + \ No newline at end of file diff --git a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino new file mode 100644 index 00000000000..57d7a6aa04f --- /dev/null +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino @@ -0,0 +1,105 @@ +#include +#include + +// Matter Manager +#include + +// List of Matter Endpoints for this Node +// On/Off Light Endpoint +#include +MatterOnOffLight OnOffLight; + +// set your board LED pin here +#ifdef LED_BUILTIN +const uint8_t ledPin = LED_BUILTIN; +#else +const uint8_t ledPin = 2; // Set your pin here if your board has not defined LED_BUILTIN +#warning "Do not forget to set the LED pin" +#endif + +// Matter Protocol Endpoint Callback +bool setLightOnOff(bool state) { + Serial.printf("User Callback :: New Light State = %s\r\n", state ? "ON" : "OFF"); + if (state) { + digitalWrite(ledPin, HIGH); + } else { + digitalWrite(ledPin, LOW); + } + // This callback must return the success state to Matter core + return true; +} + +// WiFi is manually set and stated +const char *ssid = "your-ssid"; // Change this to your WiFi SSID +const char *password = "your-password"; // Change this to your WiFi password + +void setup() { + 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 Matter Node + Matter.begin(); + + // Initialize Matter EndPoint + OnOffLight.begin(true); + OnOffLight.onChangeOnOff(setLightOnOff); + + // Matter start - Last step, after all EndPoints are initialized + Matter.start(); +} + +uint32_t lastMillis = millis(); +const uint32_t toggle_interval = 15000; // light will toggle every 15 seconds +void loop() { + // Check Matter Light Commissioning state + 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 Light 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."); + } + } + // Initialize the LED (light) GPIO and Matter End Point + pinMode(ledPin, OUTPUT); + Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); + setLightOnOff(OnOffLight.getOnOff()); // configure the Light based on initial state + Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); + delay(10000); + } + + //displays the Light state every 3 seconds + Serial.printf("Matter Light is %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); + delay(3000); + if (millis() - lastMillis > toggle_interval) { + Serial.println("Toggling Light!"); + lastMillis = millis(); + OnOffLight.toggle(); // Matter Controller also can see the change + } +} \ No newline at end of file diff --git a/libraries/Matter/examples/MatterOnOffLight/ci.json b/libraries/Matter/examples/MatterOnOffLight/ci.json new file mode 100644 index 00000000000..498b7b100d3 --- /dev/null +++ b/libraries/Matter/examples/MatterOnOffLight/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y" + ] +} + \ No newline at end of file diff --git a/libraries/Matter/keywords.txt b/libraries/Matter/keywords.txt new file mode 100644 index 00000000000..7ff3e90f3b4 --- /dev/null +++ b/libraries/Matter/keywords.txt @@ -0,0 +1,35 @@ +####################################### +# Syntax Coloring Map For OpenThread +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Matter KEYWORD1 +MatterOnOffLight KEYWORD1 +MatterEndPoint KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +end KEYWORD2 +start KEYWORD2 +getManualPairingCode KEYWORD2 +getOnboardingQRCodeUrl KEYWORD2 +isDeviceCommissioned KEYWORD2 +isWiFiConnected KEYWORD2 +isThreadConnected KEYWORD2 +isDeviceConnected KEYWORD2 +decommission KEYWORD2 +attributeChangeCB KEYWORD2 +setOnOff KEYWORD2 +getOnOff KEYWORD2 +toggle KEYWORD2 +onChangeOnOff KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/libraries/Matter/library.properties b/libraries/Matter/library.properties new file mode 100644 index 00000000000..e08c750fb59 --- /dev/null +++ b/libraries/Matter/library.properties @@ -0,0 +1,9 @@ +name=Matter +version=3.1.0 +author=Rodrigo Garcia | GitHub @SuGlider +maintainer=Rodrigo Garcia +sentence=Library for supporting Matter environment on ESP32. +paragraph=This library implements Matter accessories using WiFi network. +category=Communication +url=https://github.com/espressif/arduino-esp32/ +architectures=esp32 diff --git a/libraries/Matter/src/Matter.cpp b/libraries/Matter/src/Matter.cpp new file mode 100644 index 00000000000..04d6f8e6c2c --- /dev/null +++ b/libraries/Matter/src/Matter.cpp @@ -0,0 +1,159 @@ +#include +#if DEVICE_HAS_MATTER + +#include +#include +#include "MatterEndPoint.h" + +using namespace esp_matter; +using namespace esp_matter::attribute; +using namespace esp_matter::endpoint; +using namespace chip::app::Clusters; + +constexpr auto k_timeout_seconds = 300; + +static bool _matter_has_started = false; +static node::config_t node_config; +static node_t *deviceNode = NULL; + +typedef void *app_driver_handle_t; +esp_err_t matter_light_attribute_update( + app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val +); + +// This callback is called for every attribute update. The callback implementation shall +// handle the desired attributes and return an appropriate error code. If the attribute +// is not of your interest, please do not return an error code and strictly return ESP_OK. +static esp_err_t app_attribute_update_cb( + attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, + uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data) +{ + esp_err_t err = ESP_OK; + if (type == PRE_UPDATE) { /** Callback before updating the value in the database */ + MatterEndPoint *ep = (MatterEndPoint *) priv_data; // end point pointer + if (ep != NULL) { + err = ep->attributeChangeCB(endpoint_id, cluster_id, attribute_id, val) ? ESP_OK : ESP_FAIL; + } + } + if (type == POST_UPDATE) { /** Callback after updating the value in the database */ + } + if (type == READ) { /** Callback for reading the attribute value. This is used when the `ATTRIBUTE_FLAG_OVERRIDE` is set. */ + } + if (type == WRITE) { /** Callback for writing the attribute value. This is used when the `ATTRIBUTE_FLAG_OVERRIDE` is set. */ + } + return err; +} + +// This callback is invoked when clients interact with the Identify Cluster. +// In the callback implementation, an endpoint can identify itself. (e.g., by flashing an LED or light). +static esp_err_t app_identification_cb(identification::callback_type_t type, uint16_t endpoint_id, uint8_t effect_id, uint8_t effect_variant, void *priv_data) { + log_i("Identification callback: type: %u, effect: %u, variant: %u", type, effect_id, effect_variant); + return ESP_OK; +} + + +// This callback is invoked for all Matter events. The application can handle the events as required. +static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) { + switch (event->Type) { + case chip::DeviceLayer::DeviceEventType::kInterfaceIpAddressChanged: + log_i( + "Interface %s Address changed", event->InterfaceIpAddressChanged.Type == chip::DeviceLayer::InterfaceIpChangeType::kIpV4_Assigned ? "IPv4" : "IPV6" + ); + break; + case chip::DeviceLayer::DeviceEventType::kCommissioningComplete: log_i("Commissioning complete"); break; + case chip::DeviceLayer::DeviceEventType::kFailSafeTimerExpired: log_i("Commissioning failed, fail safe timer expired"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStarted: log_i("Commissioning session started"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStopped: log_i("Commissioning session stopped"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningWindowOpened: log_i("Commissioning window opened"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningWindowClosed: log_i("Commissioning window closed"); break; + case chip::DeviceLayer::DeviceEventType::kFabricRemoved: + { + log_i("Fabric removed successfully"); + if (chip::Server::GetInstance().GetFabricTable().FabricCount() == 0) { + log_i("No fabric left, opening commissioning window"); + chip::CommissioningWindowManager &commissionMgr = chip::Server::GetInstance().GetCommissioningWindowManager(); + constexpr auto kTimeoutSeconds = chip::System::Clock::Seconds16(k_timeout_seconds); + if (!commissionMgr.IsCommissioningWindowOpen()) { + // After removing last fabric, it does not remove the Wi-Fi credentials and still has IP connectivity so, only advertising on DNS-SD. + CHIP_ERROR err = commissionMgr.OpenBasicCommissioningWindow(kTimeoutSeconds, chip::CommissioningWindowAdvertisement::kDnssdOnly); + if (err != CHIP_NO_ERROR) { + log_e("Failed to open commissioning window, err:%" CHIP_ERROR_FORMAT, err.Format()); + } + } + } + break; + } + case chip::DeviceLayer::DeviceEventType::kFabricWillBeRemoved: log_i("Fabric will be removed"); break; + case chip::DeviceLayer::DeviceEventType::kFabricUpdated: log_i("Fabric is updated"); break; + case chip::DeviceLayer::DeviceEventType::kFabricCommitted: log_i("Fabric is committed"); break; + case chip::DeviceLayer::DeviceEventType::kBLEDeinitialized: log_i("BLE deinitialized and memory reclaimed"); break; + default: break; + } +} + +void ArduinoMatter::begin() { + if (_matter_has_started) { + log_w("Matter has already started."); + return; + } + + // Create a Matter node and add the mandatory Root Node device type on endpoint 0 + // node handle can be used to add/modify other endpoints. + deviceNode = node::create(&node_config, app_attribute_update_cb, app_identification_cb); + if (deviceNode == nullptr) { + log_e("Failed to create Matter node"); + abort(); + } + + _matter_has_started = true; +} + +void ArduinoMatter::start() { + if (!_matter_has_started) { + log_w("No Matter Node has been created. Execute Matter.begin() first."); + return; + } + + /* Matter start */ + esp_err_t err = esp_matter::start(app_event_cb); + if (err != ESP_OK) { + log_e("Failed to start Matter, err:%d", err); + _matter_has_started = false; + } +} + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD +bool ArduinoMatter::isThreadConnected() { + return false; // Thread Network TBD +} +#endif + +bool ArduinoMatter::isDeviceCommissioned() { + return chip::Server::GetInstance().GetFabricTable().FabricCount() > 0; +} + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION +bool ArduinoMatter::isWiFiConnected() { + return chip::DeviceLayer::ConnectivityMgr().IsWiFiStationConnected(); +} +#endif + +bool ArduinoMatter::isDeviceConnected() { + bool retCode = false; +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + retCode |= ArduinoMatter::isThreadConnected(); +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION + retCode |= ArduinoMatter::isWiFiConnected(); +#endif + return retCode; +} + +void ArduinoMatter::decommission() { + esp_matter::factory_reset(); +} + +// Global Matter Object +ArduinoMatter Matter; + +#endif /* DEVICE_HAS_MATTER */ \ No newline at end of file diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h new file mode 100644 index 00000000000..daa181be0b9 --- /dev/null +++ b/libraries/Matter/src/Matter.h @@ -0,0 +1,39 @@ +#pragma once +#include +#include +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION || CHIP_DEVICE_CONFIG_ENABLE_THREAD +#define DEVICE_HAS_MATTER 1 +#else +#define DEVICE_HAS_MATTER 0 +#endif + +#if DEVICE_HAS_MATTER + +using namespace esp_matter; + +class ArduinoMatter { + public: + static void begin(); + static inline String getManualPairingCode() { + // return the pairing code for manual pairing + return String("34970112332"); + } + static inline String getOnboardingQRCodeUrl() { + // return the URL for the QR code for onboarding + return String("https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT:Y.K9042C00KA0648G00"); + } + static void start(); + static bool isDeviceCommissioned(); +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION + static bool isWiFiConnected(); +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + static bool isThreadConnected(); +#endif + static bool isDeviceConnected(); + static void decommission(); +}; + +extern ArduinoMatter Matter; + +#endif /* DEVICE_HAS_MATTER */ \ No newline at end of file diff --git a/libraries/Matter/src/MatterEndPoint.h b/libraries/Matter/src/MatterEndPoint.h new file mode 100644 index 00000000000..f80afa65fe4 --- /dev/null +++ b/libraries/Matter/src/MatterEndPoint.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#if DEVICE_HAS_MATTER + +#include + +// Matter Endpoint Base Class. Controls the endpoint ID and allows the child class to overwrite attribute change call +class MatterEndPoint { + public: + uint16_t getEndPointId() { + return endpoint_id; + } + void setEndPointId(uint16_t ep) { + endpoint_id = ep; + } + + virtual bool attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) = 0; + + protected: + uint16_t endpoint_id = 0; +}; +#endif /* DEVICE_HAS_MATTER */ \ No newline at end of file diff --git a/libraries/Matter/src/MatterOnOffLight.cpp b/libraries/Matter/src/MatterOnOffLight.cpp new file mode 100644 index 00000000000..f311d798ba3 --- /dev/null +++ b/libraries/Matter/src/MatterOnOffLight.cpp @@ -0,0 +1,108 @@ +#include +#if DEVICE_HAS_MATTER + +#include +#include +#include + +using namespace esp_matter; +using namespace esp_matter::endpoint; +using namespace chip::app::Clusters; + +bool MatterOnOffLight::attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) { + bool ret = true; + if (!started) { + log_w("Matter On-Off Light device has not begun."); + return false; + } + + if (endpoint_id == getEndPointId()) { + if (cluster_id == OnOff::Id) { + if (attribute_id == OnOff::Attributes::OnOff::Id) { + if (_onChangeCB != NULL) { + ret = _onChangeCB(val->val.b); + log_d("OnOffLight state changed to %d", val->val.b); + if (ret == true) { + state = val->val.b; + } + } + } + } + } + return ret; +} + +MatterOnOffLight::MatterOnOffLight() { +} + +MatterOnOffLight::~MatterOnOffLight() { + end(); +} + +bool MatterOnOffLight::begin(bool initialState) { + + on_off_light::config_t light_config; + light_config.on_off.on_off = initialState; + state = initialState; + light_config.on_off.lighting.start_up_on_off = nullptr; + + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = on_off_light::create(node::get(), &light_config, ENDPOINT_FLAG_NONE, (void *) this); + if (endpoint == nullptr) { + log_e("Failed to create on-off light endpoint"); + abort(); + } + + setEndPointId(endpoint::get_id(endpoint)); + log_i("On-Off Light created with endpoint_id %d", getEndPointId()); + started = true; + return true; +} + +void MatterOnOffLight::end() { + started = false; +} + +bool MatterOnOffLight::setOnOff(bool newState) { + if (!started) { + log_w("Matter On-Off Light device has not begun."); + return false; + } + + // avoid processing the a "no-change" + if (state == newState) { + return true; + } + + state = newState; + + endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id); + cluster_t *cluster = cluster::get(endpoint, OnOff::Id); + attribute_t *attribute = attribute::get(cluster, OnOff::Attributes::OnOff::Id); + + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + + if (val.val.b != state) { + val.val.b = state; + attribute::update(endpoint_id, OnOff::Id, OnOff::Attributes::OnOff::Id, &val); + } + return true; +} + +bool MatterOnOffLight::getOnOff() { + return state; +} + +bool MatterOnOffLight::toggle() { + return setOnOff(!state); +} + +MatterOnOffLight::operator bool() { + return getOnOff(); +} + +void MatterOnOffLight::operator=(bool newState) { + setOnOff(newState); +} +#endif /* DEVICE_HAS_MATTER */ \ No newline at end of file diff --git a/libraries/Matter/src/MatterOnOffLight.h b/libraries/Matter/src/MatterOnOffLight.h new file mode 100644 index 00000000000..47176e8bb3d --- /dev/null +++ b/libraries/Matter/src/MatterOnOffLight.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#if DEVICE_HAS_MATTER + +#include + +class MatterOnOffLight : public MatterEndPoint { + public: + MatterOnOffLight(); + ~MatterOnOffLight(); + virtual bool begin(bool initialState = false); // default initial state is off + void end(); // this will just stop proessing Light Matter events + + bool setOnOff(bool newState); // returns true if successful + bool getOnOff(); // returns current light state + bool toggle(); // returns true if successful + + operator bool(); // returns current light state + void operator=(bool state); // turns light on or off + // 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); + // User Callback for whenever the Light state is changed by the Matter Controller + using EndPointCB = std::function; + void onChangeOnOff(EndPointCB onChangeCB) { + _onChangeCB = onChangeCB; + } + + protected: + bool started = false; + bool state = false; // default initial state is off, but it can be changed by begin(bool) + EndPointCB _onChangeCB = NULL; +}; +#endif /* DEVICE_HAS_MATTER */ \ No newline at end of file From a9a6fc21840905e8263aae0b24e41f209e7ed1d1 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Tue, 15 Oct 2024 21:50:04 -0300 Subject: [PATCH 02/24] feat(matter): add matter library to cmakelists.txt --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a06f815c9d8..ed3d4d7e44a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,6 +93,7 @@ set(ARDUINO_ALL_LIBRARIES HTTPUpdate Insights LittleFS + Matter NetBIOS Network OpenThread @@ -164,6 +165,10 @@ set(ARDUINO_LIBRARY_OpenThread_SRCS libraries/OpenThread/src/OThreadCLI.cpp libraries/OpenThread/src/OThreadCLI_Util.cpp) +set(ARDUINO_LIBRARY_Matter_SRCS + libraries/Matter/src/MatterOnOffLight.cpp + libraries/Matter/src/Matter.cpp) + set(ARDUINO_LIBRARY_PPP_SRCS libraries/PPP/src/PPP.cpp libraries/PPP/src/ppp.c) From 713a1d6a863d4746db89d657ea86cf332558063d Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Tue, 15 Oct 2024 22:05:55 -0300 Subject: [PATCH 03/24] fix(matter): add correct guard for ci --- libraries/Matter/src/Matter.cpp | 8 ++++---- libraries/Matter/src/Matter.h | 12 ++++-------- libraries/Matter/src/MatterEndPoint.h | 6 +++--- libraries/Matter/src/MatterOnOffLight.cpp | 8 ++++---- libraries/Matter/src/MatterOnOffLight.h | 6 +++--- 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/libraries/Matter/src/Matter.cpp b/libraries/Matter/src/Matter.cpp index 04d6f8e6c2c..7f1d936e815 100644 --- a/libraries/Matter/src/Matter.cpp +++ b/libraries/Matter/src/Matter.cpp @@ -1,7 +1,7 @@ -#include -#if DEVICE_HAS_MATTER +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL -#include +#include #include #include "MatterEndPoint.h" @@ -156,4 +156,4 @@ void ArduinoMatter::decommission() { // Global Matter Object ArduinoMatter Matter; -#endif /* DEVICE_HAS_MATTER */ \ No newline at end of file +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h index daa181be0b9..537cebeb699 100644 --- a/libraries/Matter/src/Matter.h +++ b/libraries/Matter/src/Matter.h @@ -1,13 +1,9 @@ #pragma once +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + #include #include -#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION || CHIP_DEVICE_CONFIG_ENABLE_THREAD -#define DEVICE_HAS_MATTER 1 -#else -#define DEVICE_HAS_MATTER 0 -#endif - -#if DEVICE_HAS_MATTER using namespace esp_matter; @@ -36,4 +32,4 @@ class ArduinoMatter { extern ArduinoMatter Matter; -#endif /* DEVICE_HAS_MATTER */ \ No newline at end of file +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file diff --git a/libraries/Matter/src/MatterEndPoint.h b/libraries/Matter/src/MatterEndPoint.h index f80afa65fe4..5db30c52985 100644 --- a/libraries/Matter/src/MatterEndPoint.h +++ b/libraries/Matter/src/MatterEndPoint.h @@ -1,8 +1,8 @@ #pragma once +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL #include -#if DEVICE_HAS_MATTER - #include // Matter Endpoint Base Class. Controls the endpoint ID and allows the child class to overwrite attribute change call @@ -20,4 +20,4 @@ class MatterEndPoint { protected: uint16_t endpoint_id = 0; }; -#endif /* DEVICE_HAS_MATTER */ \ No newline at end of file +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file diff --git a/libraries/Matter/src/MatterOnOffLight.cpp b/libraries/Matter/src/MatterOnOffLight.cpp index f311d798ba3..017eaa6cae1 100644 --- a/libraries/Matter/src/MatterOnOffLight.cpp +++ b/libraries/Matter/src/MatterOnOffLight.cpp @@ -1,7 +1,7 @@ -#include -#if DEVICE_HAS_MATTER +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL -#include +#include #include #include @@ -105,4 +105,4 @@ MatterOnOffLight::operator bool() { void MatterOnOffLight::operator=(bool newState) { setOnOff(newState); } -#endif /* DEVICE_HAS_MATTER */ \ No newline at end of file +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file diff --git a/libraries/Matter/src/MatterOnOffLight.h b/libraries/Matter/src/MatterOnOffLight.h index 47176e8bb3d..718580c0f30 100644 --- a/libraries/Matter/src/MatterOnOffLight.h +++ b/libraries/Matter/src/MatterOnOffLight.h @@ -1,8 +1,8 @@ #pragma once +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL #include -#if DEVICE_HAS_MATTER - #include class MatterOnOffLight : public MatterEndPoint { @@ -31,4 +31,4 @@ class MatterOnOffLight : public MatterEndPoint { bool state = false; // default initial state is off, but it can be changed by begin(bool) EndPointCB _onChangeCB = NULL; }; -#endif /* DEVICE_HAS_MATTER */ \ No newline at end of file +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file From 3a185e9a227dacca6658e0e07c26b74a72365a82 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Tue, 15 Oct 2024 22:22:17 -0300 Subject: [PATCH 04/24] fix(matter): using correct ci requirements in ci.json --- libraries/Matter/examples/MatterCommissionTest/ci.json | 3 ++- libraries/Matter/examples/MatterComposedLights/ci.json | 3 ++- libraries/Matter/examples/MatterOnOffLight/ci.json | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/Matter/examples/MatterCommissionTest/ci.json b/libraries/Matter/examples/MatterCommissionTest/ci.json index 498b7b100d3..18715894b22 100644 --- a/libraries/Matter/examples/MatterCommissionTest/ci.json +++ b/libraries/Matter/examples/MatterCommissionTest/ci.json @@ -1,7 +1,8 @@ { "fqbn_append": "PartitionScheme=huge_app", "requires": [ - "CONFIG_SOC_WIFI_SUPPORTED=y" + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" ] } \ No newline at end of file diff --git a/libraries/Matter/examples/MatterComposedLights/ci.json b/libraries/Matter/examples/MatterComposedLights/ci.json index 498b7b100d3..18715894b22 100644 --- a/libraries/Matter/examples/MatterComposedLights/ci.json +++ b/libraries/Matter/examples/MatterComposedLights/ci.json @@ -1,7 +1,8 @@ { "fqbn_append": "PartitionScheme=huge_app", "requires": [ - "CONFIG_SOC_WIFI_SUPPORTED=y" + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" ] } \ No newline at end of file diff --git a/libraries/Matter/examples/MatterOnOffLight/ci.json b/libraries/Matter/examples/MatterOnOffLight/ci.json index 498b7b100d3..18715894b22 100644 --- a/libraries/Matter/examples/MatterOnOffLight/ci.json +++ b/libraries/Matter/examples/MatterOnOffLight/ci.json @@ -1,7 +1,8 @@ { "fqbn_append": "PartitionScheme=huge_app", "requires": [ - "CONFIG_SOC_WIFI_SUPPORTED=y" + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" ] } \ No newline at end of file From 260d6197e76a0bbea0bddb83679534f8269c2d6f Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Tue, 15 Oct 2024 22:32:12 -0300 Subject: [PATCH 05/24] fix(matter): using correct ci requirements in header files --- libraries/Matter/src/Matter.h | 6 +----- libraries/Matter/src/MatterEndPoint.h | 6 +----- libraries/Matter/src/MatterOnOffLight.h | 5 +---- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h index 537cebeb699..cd1c012d155 100644 --- a/libraries/Matter/src/Matter.h +++ b/libraries/Matter/src/Matter.h @@ -1,6 +1,4 @@ #pragma once -#include -#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL #include #include @@ -30,6 +28,4 @@ class ArduinoMatter { static void decommission(); }; -extern ArduinoMatter Matter; - -#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file +extern ArduinoMatter Matter; \ No newline at end of file diff --git a/libraries/Matter/src/MatterEndPoint.h b/libraries/Matter/src/MatterEndPoint.h index 5db30c52985..fe992909f27 100644 --- a/libraries/Matter/src/MatterEndPoint.h +++ b/libraries/Matter/src/MatterEndPoint.h @@ -1,7 +1,4 @@ #pragma once -#include -#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL - #include #include @@ -19,5 +16,4 @@ class MatterEndPoint { protected: uint16_t endpoint_id = 0; -}; -#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file +}; \ No newline at end of file diff --git a/libraries/Matter/src/MatterOnOffLight.h b/libraries/Matter/src/MatterOnOffLight.h index 718580c0f30..dd3f6552dae 100644 --- a/libraries/Matter/src/MatterOnOffLight.h +++ b/libraries/Matter/src/MatterOnOffLight.h @@ -1,6 +1,4 @@ #pragma once -#include -#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL #include #include @@ -30,5 +28,4 @@ class MatterOnOffLight : public MatterEndPoint { bool started = false; bool state = false; // default initial state is off, but it can be changed by begin(bool) EndPointCB _onChangeCB = NULL; -}; -#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file +}; \ No newline at end of file From b495cc319c42ba0aedd5b0b214ba9a7fb8740217 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Tue, 15 Oct 2024 22:43:50 -0300 Subject: [PATCH 06/24] fix(matter): using correct ci requirements header and examples --- .../MatterCommissionTest/MatterCommissionTest.ino | 9 ++++++++- .../MatterComposedLights/MatterComposedLights.ino | 9 ++++++++- .../examples/MatterOnOffLight/MatterOnOffLight.ino | 9 ++++++++- libraries/Matter/src/Matter.h | 6 +++++- libraries/Matter/src/MatterEndPoint.h | 6 +++++- libraries/Matter/src/MatterOnOffLight.h | 5 ++++- 6 files changed, 38 insertions(+), 6 deletions(-) diff --git a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino index 4769565edf3..9f050ed55d9 100644 --- a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino +++ b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino @@ -1,3 +1,5 @@ +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL #include #include @@ -64,4 +66,9 @@ void loop() { delay(30000); Matter.decommission(); Serial.println("Matter Node is decommissioned. Commsssioning widget shall start over."); -} \ No newline at end of file +} + +#else +void setup() {} +void loop() {} +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file diff --git a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino index a052f4b6392..aaaccd97ff3 100644 --- a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino +++ b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino @@ -1,3 +1,5 @@ +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL #include #include @@ -95,4 +97,9 @@ void loop() { Serial.printf("Matter Light #2 is %s\r\n", OnOffLight2.getOnOff() ? "ON" : "OFF"); Serial.printf("Matter Light #3 is %s\r\n", OnOffLight3.getOnOff() ? "ON" : "OFF"); delay(3000); -} \ No newline at end of file +} + +#else +void setup() {} +void loop() {} +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file diff --git a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino index 57d7a6aa04f..d9c9164345a 100644 --- a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino @@ -1,3 +1,5 @@ +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL #include #include @@ -102,4 +104,9 @@ void loop() { lastMillis = millis(); OnOffLight.toggle(); // Matter Controller also can see the change } -} \ No newline at end of file +} + +#else +void setup() {} +void loop() {} +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h index cd1c012d155..537cebeb699 100644 --- a/libraries/Matter/src/Matter.h +++ b/libraries/Matter/src/Matter.h @@ -1,4 +1,6 @@ #pragma once +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL #include #include @@ -28,4 +30,6 @@ class ArduinoMatter { static void decommission(); }; -extern ArduinoMatter Matter; \ No newline at end of file +extern ArduinoMatter Matter; + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file diff --git a/libraries/Matter/src/MatterEndPoint.h b/libraries/Matter/src/MatterEndPoint.h index fe992909f27..5db30c52985 100644 --- a/libraries/Matter/src/MatterEndPoint.h +++ b/libraries/Matter/src/MatterEndPoint.h @@ -1,4 +1,7 @@ #pragma once +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + #include #include @@ -16,4 +19,5 @@ class MatterEndPoint { protected: uint16_t endpoint_id = 0; -}; \ No newline at end of file +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file diff --git a/libraries/Matter/src/MatterOnOffLight.h b/libraries/Matter/src/MatterOnOffLight.h index dd3f6552dae..718580c0f30 100644 --- a/libraries/Matter/src/MatterOnOffLight.h +++ b/libraries/Matter/src/MatterOnOffLight.h @@ -1,4 +1,6 @@ #pragma once +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL #include #include @@ -28,4 +30,5 @@ class MatterOnOffLight : public MatterEndPoint { bool started = false; bool state = false; // default initial state is off, but it can be changed by begin(bool) EndPointCB _onChangeCB = NULL; -}; \ No newline at end of file +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file From d3b83d957f02fbef63375f557bb8929f2daafb44 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 16 Oct 2024 03:39:29 -0300 Subject: [PATCH 07/24] fix(typo): typo and commentaries --- .../examples/MatterCommissionTest/MatterCommissionTest.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino index 9f050ed55d9..77cd8c39652 100644 --- a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino +++ b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino @@ -11,7 +11,8 @@ #include MatterOnOffLight OnOffLight; -// WiFi is manually set and stated +// 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 From 2fbbca89f04862f8b25b9ed6f3539c8448b2ae47 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 16 Oct 2024 03:39:43 -0300 Subject: [PATCH 08/24] fix(typo): typo and commentaries --- .../examples/MatterComposedLights/MatterComposedLights.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino index aaaccd97ff3..74d1cada425 100644 --- a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino +++ b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino @@ -29,7 +29,8 @@ bool setLightOnOff3(bool state) { return true; } -// WiFi is manually set and stated +// 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 From d733d1950937bda4b1e2fb844b648893da4c3966 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 16 Oct 2024 03:39:52 -0300 Subject: [PATCH 09/24] fix(typo): typo and commentaries --- .../Matter/examples/MatterOnOffLight/MatterOnOffLight.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino index d9c9164345a..9babf5285d4 100644 --- a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino @@ -31,7 +31,8 @@ bool setLightOnOff(bool state) { return true; } -// WiFi is manually set and stated +// 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 From d3f870326579df5533d12c9ad8895a4dc5fad4c3 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 16 Oct 2024 03:40:31 -0300 Subject: [PATCH 10/24] fix(commentary): longer explanation --- .../examples/MatterCommissionTest/MatterCommissionTest.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino index 77cd8c39652..dd2ba08c6de 100644 --- a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino +++ b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino @@ -43,7 +43,8 @@ void setup() { Matter.begin(); // Initialize Matter EndPoint OnOffLight.begin(); - // Matter start + // Matter start - Last step, after all EndPoints are initialized + Matter.start(); } From 695df2411278f42f72b4b0a6e7d327a01f4a03ff Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 16 Oct 2024 09:58:33 -0300 Subject: [PATCH 11/24] feat(matter): api simplification with begin --- .../MatterCommissionTest/MatterCommissionTest.ino | 10 ++++------ .../MatterComposedLights/MatterComposedLights.ino | 7 ++----- .../examples/MatterOnOffLight/MatterOnOffLight.ino | 7 ++----- libraries/Matter/src/Matter.cpp | 9 ++++----- libraries/Matter/src/Matter.h | 8 ++++++-- libraries/Matter/src/MatterOnOffLight.cpp | 4 ++-- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino index dd2ba08c6de..0baca6eb472 100644 --- a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino +++ b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino @@ -39,13 +39,11 @@ void setup() { Serial.println(WiFi.localIP()); delay(500); - // Initialize Matter Node - Matter.begin(); - // Initialize Matter EndPoint + // Initialize at least one Matter EndPoint OnOffLight.begin(); - // Matter start - Last step, after all EndPoints are initialized - - Matter.start(); + + // Matter begining - Last step, after all EndPoints are initialized + Matter.begin(); } void loop() { diff --git a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino index 74d1cada425..3dd9273d89c 100644 --- a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino +++ b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino @@ -57,9 +57,6 @@ void setup() { Serial.println(WiFi.localIP()); delay(500); - // Initialize Matter Node - Matter.begin(); - // Initialize all 3 Matter EndPoints OnOffLight1.begin(); OnOffLight2.begin(); @@ -68,8 +65,8 @@ void setup() { OnOffLight2.onChangeOnOff(setLightOnOff2); OnOffLight3.onChangeOnOff(setLightOnOff3); - // Matter start - Last step, after all EndPoints are initialized - Matter.start(); + // Matter begining - Last step, after all EndPoints are initialized + Matter.begin(); } void loop() { diff --git a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino index 9babf5285d4..973b269ffcd 100644 --- a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino @@ -59,15 +59,12 @@ void setup() { Serial.println(WiFi.localIP()); delay(500); - // Initialize Matter Node - Matter.begin(); - // Initialize Matter EndPoint OnOffLight.begin(true); OnOffLight.onChangeOnOff(setLightOnOff); - // Matter start - Last step, after all EndPoints are initialized - Matter.start(); + // Matter begining - Last step, after all EndPoints are initialized + Matter.begin(); } uint32_t lastMillis = millis(); diff --git a/libraries/Matter/src/Matter.cpp b/libraries/Matter/src/Matter.cpp index 7f1d936e815..ac716b16934 100644 --- a/libraries/Matter/src/Matter.cpp +++ b/libraries/Matter/src/Matter.cpp @@ -91,9 +91,8 @@ static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) { } } -void ArduinoMatter::begin() { +void ArduinoMatter::_init() { if (_matter_has_started) { - log_w("Matter has already started."); return; } @@ -102,15 +101,15 @@ void ArduinoMatter::begin() { deviceNode = node::create(&node_config, app_attribute_update_cb, app_identification_cb); if (deviceNode == nullptr) { log_e("Failed to create Matter node"); - abort(); + return; } _matter_has_started = true; } -void ArduinoMatter::start() { +void ArduinoMatter::begin() { if (!_matter_has_started) { - log_w("No Matter Node has been created. Execute Matter.begin() first."); + log_w("No Matter endpoint has been created. Please create an endpoint first."); return; } diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h index 537cebeb699..289051d569a 100644 --- a/libraries/Matter/src/Matter.h +++ b/libraries/Matter/src/Matter.h @@ -9,7 +9,6 @@ using namespace esp_matter; class ArduinoMatter { public: - static void begin(); static inline String getManualPairingCode() { // return the pairing code for manual pairing return String("34970112332"); @@ -18,7 +17,7 @@ class ArduinoMatter { // return the URL for the QR code for onboarding return String("https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT:Y.K9042C00KA0648G00"); } - static void start(); + static void begin(); static bool isDeviceCommissioned(); #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION static bool isWiFiConnected(); @@ -28,6 +27,11 @@ class ArduinoMatter { #endif static bool isDeviceConnected(); static void decommission(); + + // list of Matter EndPoints Friend Classes + friend class MatterOnOffLight; + protected: + static void _init(); }; extern ArduinoMatter Matter; diff --git a/libraries/Matter/src/MatterOnOffLight.cpp b/libraries/Matter/src/MatterOnOffLight.cpp index 017eaa6cae1..c6715740969 100644 --- a/libraries/Matter/src/MatterOnOffLight.cpp +++ b/libraries/Matter/src/MatterOnOffLight.cpp @@ -40,7 +40,7 @@ MatterOnOffLight::~MatterOnOffLight() { } bool MatterOnOffLight::begin(bool initialState) { - + ArduinoMatter::_init(); on_off_light::config_t light_config; light_config.on_off.on_off = initialState; state = initialState; @@ -50,7 +50,7 @@ bool MatterOnOffLight::begin(bool initialState) { endpoint_t *endpoint = on_off_light::create(node::get(), &light_config, ENDPOINT_FLAG_NONE, (void *) this); if (endpoint == nullptr) { log_e("Failed to create on-off light endpoint"); - abort(); + return false; } setEndPointId(endpoint::get_id(endpoint)); From 5960abede4c31e3ba2da79adf27dadafa2b468ab Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 16 Oct 2024 16:12:41 -0300 Subject: [PATCH 12/24] feat(matter): testing flashmode=qio in CI --- libraries/Matter/examples/MatterCommissionTest/ci.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/Matter/examples/MatterCommissionTest/ci.json b/libraries/Matter/examples/MatterCommissionTest/ci.json index 18715894b22..01df8c5f811 100644 --- a/libraries/Matter/examples/MatterCommissionTest/ci.json +++ b/libraries/Matter/examples/MatterCommissionTest/ci.json @@ -1,8 +1,8 @@ { - "fqbn_append": "PartitionScheme=huge_app", + "fqbn_append": "PartitionScheme=huge_app,FlashMode=qio", "requires": [ "CONFIG_SOC_WIFI_SUPPORTED=y", "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" ] } - \ No newline at end of file + From 9e74283a90cdc528e2e82efee091737c1be75bc7 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 16 Oct 2024 16:13:40 -0300 Subject: [PATCH 13/24] feat(matter): testing flashmode=qio in CI --- .../MatterCommissionTest/MatterCommissionTest.ino | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino index 0baca6eb472..119f4de41ed 100644 --- a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino +++ b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino @@ -1,5 +1,5 @@ -#include -#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL +//#include +//#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL #include #include @@ -68,7 +68,7 @@ void loop() { Serial.println("Matter Node is decommissioned. Commsssioning widget shall start over."); } -#else -void setup() {} -void loop() {} -#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file +//#else +//void setup() {} +//void loop() {} +//#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ From 96672e65c5572a04acc194c556315b09c1cd236d Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 16 Oct 2024 16:20:51 -0300 Subject: [PATCH 14/24] fix(matter): changes CI FQBN --- libraries/Matter/examples/MatterCommissionTest/ci.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/Matter/examples/MatterCommissionTest/ci.json b/libraries/Matter/examples/MatterCommissionTest/ci.json index 01df8c5f811..97fbecaa79a 100644 --- a/libraries/Matter/examples/MatterCommissionTest/ci.json +++ b/libraries/Matter/examples/MatterCommissionTest/ci.json @@ -1,5 +1,9 @@ { - "fqbn_append": "PartitionScheme=huge_app,FlashMode=qio", + "fqbn": { + "esp32s3": [ + "espressif:esp32:esp32s3:PartitionScheme=huge_app,FlashMode=qio" + ] + }, "requires": [ "CONFIG_SOC_WIFI_SUPPORTED=y", "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" From 1797133651fef841141c13030b82668c676338fe Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 16 Oct 2024 16:29:33 -0300 Subject: [PATCH 15/24] fix(matte): include all fqbn in ci.json using qio --- .../Matter/examples/MatterCommissionTest/ci.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libraries/Matter/examples/MatterCommissionTest/ci.json b/libraries/Matter/examples/MatterCommissionTest/ci.json index 97fbecaa79a..4f1dbbf92be 100644 --- a/libraries/Matter/examples/MatterCommissionTest/ci.json +++ b/libraries/Matter/examples/MatterCommissionTest/ci.json @@ -2,6 +2,18 @@ "fqbn": { "esp32s3": [ "espressif:esp32:esp32s3:PartitionScheme=huge_app,FlashMode=qio" + ], + "esp32s2": [ + "espressif:esp32:esp32s2:PartitionScheme=huge_app,FlashMode=qio" + ], + "esp32": [ + "espressif:esp32:esp32:PartitionScheme=huge_app,FlashMode=qio" + ], + "esp32c3": [ + "espressif:esp32:esp32c3:PartitionScheme=huge_app,FlashMode=qio" + ], + "esp32c6": [ + "espressif:esp32:esp32c6:PartitionScheme=huge_app,FlashMode=qio" ] }, "requires": [ From bb43fbf11a4e100c1bc3e2b27eb8d2bac1518808 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Thu, 17 Oct 2024 03:39:10 -0300 Subject: [PATCH 16/24] fix(matter): revert ci and guard changes --- .../MatterCommissionTest.ino | 13 ++-------- .../examples/MatterCommissionTest/ci.json | 26 ++++--------------- .../MatterComposedLights.ino | 13 ++-------- .../examples/MatterComposedLights/ci.json | 3 +-- .../MatterOnOffLight/MatterOnOffLight.ino | 13 ++-------- .../Matter/examples/MatterOnOffLight/ci.json | 3 +-- 6 files changed, 13 insertions(+), 58 deletions(-) diff --git a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino index 119f4de41ed..c293b02c460 100644 --- a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino +++ b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino @@ -1,10 +1,6 @@ -//#include -//#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL -#include -#include - // Matter Manager #include +#include // List of Matter Endpoints for this Node // On/Off Light Endpoint @@ -66,9 +62,4 @@ void loop() { delay(30000); Matter.decommission(); Serial.println("Matter Node is decommissioned. Commsssioning widget shall start over."); -} - -//#else -//void setup() {} -//void loop() {} -//#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ +} \ No newline at end of file diff --git a/libraries/Matter/examples/MatterCommissionTest/ci.json b/libraries/Matter/examples/MatterCommissionTest/ci.json index 4f1dbbf92be..6d8bd16ac1d 100644 --- a/libraries/Matter/examples/MatterCommissionTest/ci.json +++ b/libraries/Matter/examples/MatterCommissionTest/ci.json @@ -1,24 +1,8 @@ { - "fqbn": { - "esp32s3": [ - "espressif:esp32:esp32s3:PartitionScheme=huge_app,FlashMode=qio" - ], - "esp32s2": [ - "espressif:esp32:esp32s2:PartitionScheme=huge_app,FlashMode=qio" - ], - "esp32": [ - "espressif:esp32:esp32:PartitionScheme=huge_app,FlashMode=qio" - ], - "esp32c3": [ - "espressif:esp32:esp32c3:PartitionScheme=huge_app,FlashMode=qio" - ], - "esp32c6": [ - "espressif:esp32:esp32c6:PartitionScheme=huge_app,FlashMode=qio" - ] - }, - "requires": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" - ] + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" + ] } diff --git a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino index 3dd9273d89c..8e726001483 100644 --- a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino +++ b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino @@ -1,10 +1,6 @@ -#include -#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL -#include -#include - // Matter Manager #include +#include // List of Matter Endpoints for this Node // There will be 3 On/Off Light Endpoints in the same Node @@ -95,9 +91,4 @@ void loop() { Serial.printf("Matter Light #2 is %s\r\n", OnOffLight2.getOnOff() ? "ON" : "OFF"); Serial.printf("Matter Light #3 is %s\r\n", OnOffLight3.getOnOff() ? "ON" : "OFF"); delay(3000); -} - -#else -void setup() {} -void loop() {} -#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file +} \ No newline at end of file diff --git a/libraries/Matter/examples/MatterComposedLights/ci.json b/libraries/Matter/examples/MatterComposedLights/ci.json index 18715894b22..3f9bfdcaa4c 100644 --- a/libraries/Matter/examples/MatterComposedLights/ci.json +++ b/libraries/Matter/examples/MatterComposedLights/ci.json @@ -4,5 +4,4 @@ "CONFIG_SOC_WIFI_SUPPORTED=y", "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" ] -} - \ No newline at end of file +} \ No newline at end of file diff --git a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino index 973b269ffcd..aca4fd9dc9d 100644 --- a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino @@ -1,10 +1,6 @@ -#include -#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL -#include -#include - // Matter Manager #include +#include // List of Matter Endpoints for this Node // On/Off Light Endpoint @@ -102,9 +98,4 @@ void loop() { lastMillis = millis(); OnOffLight.toggle(); // Matter Controller also can see the change } -} - -#else -void setup() {} -void loop() {} -#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file +} \ No newline at end of file diff --git a/libraries/Matter/examples/MatterOnOffLight/ci.json b/libraries/Matter/examples/MatterOnOffLight/ci.json index 18715894b22..f31414ace23 100644 --- a/libraries/Matter/examples/MatterOnOffLight/ci.json +++ b/libraries/Matter/examples/MatterOnOffLight/ci.json @@ -4,5 +4,4 @@ "CONFIG_SOC_WIFI_SUPPORTED=y", "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" ] -} - \ No newline at end of file +} \ No newline at end of file From 9380713a5fd5fd0cf6b3967fc71c0770d6651d75 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Thu, 17 Oct 2024 03:50:00 -0300 Subject: [PATCH 17/24] fix(matter): typo and commentaties --- libraries/Matter/src/MatterOnOffLight.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/Matter/src/MatterOnOffLight.h b/libraries/Matter/src/MatterOnOffLight.h index 718580c0f30..8fac52be62e 100644 --- a/libraries/Matter/src/MatterOnOffLight.h +++ b/libraries/Matter/src/MatterOnOffLight.h @@ -10,7 +10,7 @@ class MatterOnOffLight : public MatterEndPoint { MatterOnOffLight(); ~MatterOnOffLight(); virtual bool begin(bool initialState = false); // default initial state is off - void end(); // this will just stop proessing Light Matter events + void end(); // this will just stop processing Light Matter events bool setOnOff(bool newState); // returns true if successful bool getOnOff(); // returns current light state From cb1759b68d9b55760866676921dbd5d5ea60474b Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Thu, 17 Oct 2024 04:00:48 -0300 Subject: [PATCH 18/24] feat(matter): adds a light toggle switch button --- .../MatterOnOffLight/MatterOnOffLight.ino | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino index aca4fd9dc9d..ff977dd7791 100644 --- a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino @@ -15,6 +15,9 @@ const uint8_t ledPin = 2; // Set your pin here if your board has not defined LE #warning "Do not forget to set the LED pin" #endif +// set your board USER BUTTON pin here +const uint8_t buttonPin = 0; // Set your pin here. Using BOOT Button. C6/C3 use GPIO9. + // Matter Protocol Endpoint Callback bool setLightOnOff(bool state) { Serial.printf("User Callback :: New Light State = %s\r\n", state ? "ON" : "OFF"); @@ -64,7 +67,7 @@ void setup() { } uint32_t lastMillis = millis(); -const uint32_t toggle_interval = 15000; // light will toggle every 15 seconds +const uint32_t debouceTime = 70; // button debounce time void loop() { // Check Matter Light Commissioning state if (!Matter.isDeviceCommissioned()) { @@ -82,6 +85,8 @@ void loop() { Serial.println("Matter Node not commissioned yet. Waiting for commissioning."); } } + // Initializa the USER BUTTON (Boot button) GPIO that will act as a toggle switch + pinMode(buttonPin, INPUT_PULLUP); // Initialize the LED (light) GPIO and Matter End Point pinMode(ledPin, OUTPUT); Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); @@ -90,11 +95,9 @@ void loop() { delay(10000); } - //displays the Light state every 3 seconds - Serial.printf("Matter Light is %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); - delay(3000); - if (millis() - lastMillis > toggle_interval) { - Serial.println("Toggling Light!"); + // Onboard User Button is used as a Light toggle switch + if (digitalRead(buttonPin) == 0 && millis() - lastMillis > debouceTime) { + Serial.println("User button pressed. Toggling Light!"); lastMillis = millis(); OnOffLight.toggle(); // Matter Controller also can see the change } From 78656193a67f6942d1ce13f447547184f8898f06 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Fri, 18 Oct 2024 07:03:58 -0300 Subject: [PATCH 19/24] feat(matter): improved the button control --- .../MatterOnOffLight/MatterOnOffLight.ino | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino index ff977dd7791..fd4357a22b3 100644 --- a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino @@ -66,8 +66,12 @@ void setup() { Matter.begin(); } -uint32_t lastMillis = millis(); -const uint32_t debouceTime = 70; // button debounce time +// 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 light + void loop() { // Check Matter Light Commissioning state if (!Matter.isDeviceCommissioned()) { @@ -92,13 +96,29 @@ void loop() { Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); setLightOnOff(OnOffLight.getOnOff()); // configure the Light based on initial state Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); - delay(10000); } - // Onboard User Button is used as a Light toggle switch - if (digitalRead(buttonPin) == 0 && millis() - lastMillis > debouceTime) { - Serial.println("User button pressed. Toggling Light!"); - lastMillis = millis(); + // A button is also used to control the light + // 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 Light toggle switch 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 + // Toggle button is released - toggle the light + Serial.println("User button released. Toggling Light!"); OnOffLight.toggle(); // Matter Controller also can see the change + + // Factory reset is triggered if the button is pressed longer than 10 seconds + if (time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + OnOffLight.setOnOff(false); // turn the light off + Matter.decommission(); + } } -} \ No newline at end of file +} From a980226b4d646dae92cd15435acb129558746c40 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Fri, 18 Oct 2024 10:18:09 -0300 Subject: [PATCH 20/24] feat(matter): using switch instead of if() for attibute change --- libraries/Matter/src/Matter.cpp | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/libraries/Matter/src/Matter.cpp b/libraries/Matter/src/Matter.cpp index ac716b16934..f4ac805dafa 100644 --- a/libraries/Matter/src/Matter.cpp +++ b/libraries/Matter/src/Matter.cpp @@ -29,17 +29,25 @@ static esp_err_t app_attribute_update_cb( uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data) { esp_err_t err = ESP_OK; - if (type == PRE_UPDATE) { /** Callback before updating the value in the database */ - MatterEndPoint *ep = (MatterEndPoint *) priv_data; // end point pointer - if (ep != NULL) { - err = ep->attributeChangeCB(endpoint_id, cluster_id, attribute_id, val) ? ESP_OK : ESP_FAIL; - } - } - if (type == POST_UPDATE) { /** Callback after updating the value in the database */ - } - if (type == READ) { /** Callback for reading the attribute value. This is used when the `ATTRIBUTE_FLAG_OVERRIDE` is set. */ - } - if (type == WRITE) { /** Callback for writing the attribute value. This is used when the `ATTRIBUTE_FLAG_OVERRIDE` is set. */ + switch(type) { + case PRE_UPDATE: // Callback before updating the value in the database + log_i("Attribute update callback: PRE_UPDATE"); + MatterEndPoint *ep = (MatterEndPoint *) priv_data; // endpoint pointer to base class + if (ep != NULL) { + err = ep->attributeChangeCB(endpoint_id, cluster_id, attribute_id, val) ? ESP_OK : ESP_FAIL; + } + break; + case POST_UPDATE: // Callback after updating the value in the database + log_i("Attribute update callback: POST_UPDATE"); + break; + case READ: // Callback for reading the attribute value. This is used when the `ATTRIBUTE_FLAG_OVERRIDE` is set. + log_i("Attribute update callback: READ"); + break; + case WRITE: // Callback for writing the attribute value. This is used when the `ATTRIBUTE_FLAG_OVERRIDE` is set. + log_i("Attribute update callback: WRITE"); + break; + default: + log_i("Attribute update callback: Unknown type %d", type); } return err; } From 8d6575a0b1e0328601b386a9644262eb1ab2dbc7 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Fri, 18 Oct 2024 12:01:37 -0300 Subject: [PATCH 21/24] fix(matter): switch/case scope --- libraries/Matter/src/Matter.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libraries/Matter/src/Matter.cpp b/libraries/Matter/src/Matter.cpp index f4ac805dafa..90da3b9380e 100644 --- a/libraries/Matter/src/Matter.cpp +++ b/libraries/Matter/src/Matter.cpp @@ -29,13 +29,14 @@ static esp_err_t app_attribute_update_cb( uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data) { esp_err_t err = ESP_OK; + MatterEndPoint *ep = (MatterEndPoint *) priv_data; // endpoint pointer to base class + if (ep == NULL) { + return err; + } switch(type) { case PRE_UPDATE: // Callback before updating the value in the database log_i("Attribute update callback: PRE_UPDATE"); - MatterEndPoint *ep = (MatterEndPoint *) priv_data; // endpoint pointer to base class - if (ep != NULL) { - err = ep->attributeChangeCB(endpoint_id, cluster_id, attribute_id, val) ? ESP_OK : ESP_FAIL; - } + err = ep->attributeChangeCB(endpoint_id, cluster_id, attribute_id, val) ? ESP_OK : ESP_FAIL; break; case POST_UPDATE: // Callback after updating the value in the database log_i("Attribute update callback: POST_UPDATE"); @@ -163,4 +164,4 @@ void ArduinoMatter::decommission() { // Global Matter Object ArduinoMatter Matter; -#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ From 966ae0d7bb83c22fef6431a44b56a6f41b44e86d Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Fri, 18 Oct 2024 12:52:33 -0300 Subject: [PATCH 22/24] fix(matter): problems found after pressing reset --- .../Matter/examples/MatterOnOffLight/MatterOnOffLight.ino | 5 +++-- libraries/Matter/src/Matter.cpp | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino index fd4357a22b3..abfcdad802f 100644 --- a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino @@ -36,6 +36,9 @@ const char *ssid = "your-ssid"; // Change this to your WiFi SSID const char *password = "your-password"; // Change this to your WiFi password void setup() { + // Initializa the USER BUTTON (Boot button) GPIO that will act as a toggle switch + pinMode(buttonPin, INPUT_PULLUP); + Serial.begin(115200); while (!Serial) { delay(100); @@ -89,8 +92,6 @@ void loop() { Serial.println("Matter Node not commissioned yet. Waiting for commissioning."); } } - // Initializa the USER BUTTON (Boot button) GPIO that will act as a toggle switch - pinMode(buttonPin, INPUT_PULLUP); // Initialize the LED (light) GPIO and Matter End Point pinMode(ledPin, OUTPUT); Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); diff --git a/libraries/Matter/src/Matter.cpp b/libraries/Matter/src/Matter.cpp index 90da3b9380e..e51074adc1a 100644 --- a/libraries/Matter/src/Matter.cpp +++ b/libraries/Matter/src/Matter.cpp @@ -30,13 +30,12 @@ static esp_err_t app_attribute_update_cb( { esp_err_t err = ESP_OK; MatterEndPoint *ep = (MatterEndPoint *) priv_data; // endpoint pointer to base class - if (ep == NULL) { - return err; - } switch(type) { case PRE_UPDATE: // Callback before updating the value in the database log_i("Attribute update callback: PRE_UPDATE"); - err = ep->attributeChangeCB(endpoint_id, cluster_id, attribute_id, val) ? ESP_OK : ESP_FAIL; + if (ep != NULL) { + err = ep->attributeChangeCB(endpoint_id, cluster_id, attribute_id, val) ? ESP_OK : ESP_FAIL; + } break; case POST_UPDATE: // Callback after updating the value in the database log_i("Attribute update callback: POST_UPDATE"); From 9ecb6f369b5945f10fed3cb3dd084691911fdd55 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Fri, 18 Oct 2024 13:51:21 -0300 Subject: [PATCH 23/24] feat(matter): improve example using preferences --- .../MatterOnOffLight/MatterOnOffLight.ino | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino index abfcdad802f..cd02c5eee53 100644 --- a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino @@ -1,12 +1,16 @@ // Matter Manager #include #include +#include // List of Matter Endpoints for this Node // On/Off Light Endpoint #include MatterOnOffLight OnOffLight; +// it will keep last OnOff state stored, using Preferences +Preferences lastStatePref; + // set your board LED pin here #ifdef LED_BUILTIN const uint8_t ledPin = LED_BUILTIN; @@ -26,19 +30,23 @@ bool setLightOnOff(bool state) { } else { digitalWrite(ledPin, LOW); } + // store last OnOff state for when the Light is restarted / power goes off + lastStatePref.putBool("lastOnOffState", state); // This callback must return the success state to Matter core return true; } // 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 +const char *ssid = "Apartment B15"; // Change this to your WiFi SSID +const char *password = "flat-pony-body"; // Change this to your WiFi password void setup() { // Initializa the USER BUTTON (Boot button) GPIO that will act as a toggle switch pinMode(buttonPin, INPUT_PULLUP); - + // Initialize the LED (light) GPIO and Matter End Point + pinMode(ledPin, OUTPUT); + Serial.begin(115200); while (!Serial) { delay(100); @@ -62,13 +70,20 @@ void setup() { delay(500); // Initialize Matter EndPoint - OnOffLight.begin(true); + lastStatePref.begin("matterLight", false); + bool lastOnOffState = lastStatePref.getBool("lastOnOffState", true); + OnOffLight.begin(lastOnOffState); OnOffLight.onChangeOnOff(setLightOnOff); // Matter begining - 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."); + Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); + setLightOnOff(OnOffLight.getOnOff()); // configure the Light based on initial state + } } - // Button control uint32_t button_time_stamp = 0; // debouncing control bool button_state = false; // false = released | true = pressed @@ -76,7 +91,7 @@ const uint32_t debouceTime = 250; // button debouncing time (ms) const uint32_t decommissioningTimeout = 10000; // keep the button pressed for 10s to decommission the light void loop() { - // Check Matter Light Commissioning state + // Check Matter Light Commissioning state, which may change during execution of loop() if (!Matter.isDeviceCommissioned()) { Serial.println(""); Serial.println("Matter Node is not commissioned yet."); @@ -92,8 +107,6 @@ void loop() { Serial.println("Matter Node not commissioned yet. Waiting for commissioning."); } } - // Initialize the LED (light) GPIO and Matter End Point - pinMode(ledPin, OUTPUT); Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); setLightOnOff(OnOffLight.getOnOff()); // configure the Light based on initial state Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); @@ -122,4 +135,4 @@ void loop() { Matter.decommission(); } } -} +} \ No newline at end of file From a6d1d200d836b373b5e9e026c626506b8c8266a1 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 21 Oct 2024 09:34:22 -0300 Subject: [PATCH 24/24] fix(pre-commit): Fix and apply pre-commit hooks --- .pre-commit-config.yaml | 1 + cores/esp32/esp32-hal-tinyusb.c | 15 +- .../MatterCommissionTest.ino | 130 +++---- .../examples/MatterCommissionTest/ci.json | 15 +- .../MatterComposedLights.ino | 188 +++++----- .../examples/MatterComposedLights/ci.json | 14 +- .../MatterOnOffLight/MatterOnOffLight.ino | 276 +++++++-------- .../Matter/examples/MatterOnOffLight/ci.json | 14 +- libraries/Matter/src/Matter.cpp | 329 +++++++++--------- libraries/Matter/src/Matter.h | 79 ++--- libraries/Matter/src/MatterEndPoint.h | 46 +-- libraries/Matter/src/MatterOnOffLight.cpp | 215 ++++++------ libraries/Matter/src/MatterOnOffLight.h | 68 ++-- libraries/USB/src/USBHID.cpp | 4 +- 14 files changed, 696 insertions(+), 698 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0aff5b6f07b..6a949631bd9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,6 +26,7 @@ repos: - id: trailing-whitespace args: [--markdown-linebreak-ext=md] - id: pretty-format-json + stages: [manual] args: [--autofix] types_or: [json] exclude: | diff --git a/cores/esp32/esp32-hal-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c index c69fca08fc7..16cd5d831d2 100644 --- a/cores/esp32/esp32-hal-tinyusb.c +++ b/cores/esp32/esp32-hal-tinyusb.c @@ -287,15 +287,14 @@ enum { VENDOR_REQUEST_MICROSOFT = 2 }; -static uint8_t const tinyusb_bos_descriptor[] = { - // total length, number of device caps - TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2), +static uint8_t const tinyusb_bos_descriptor[] = {// total length, number of device caps + TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2), - // Vendor Code, iLandingPage - TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1), + // Vendor Code, iLandingPage + TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1), - // Microsoft OS 2.0 descriptor - TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT) + // Microsoft OS 2.0 descriptor + TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT) }; /* @@ -831,7 +830,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) { periph_ll_enable_clk_clear_rst(PERIPH_USB_MODULE); } #endif - + tinyusb_config_t tusb_cfg = { .external_phy = false // In the most cases you need to use a `false` value }; diff --git a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino index c293b02c460..a9afb0c4484 100644 --- a/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino +++ b/libraries/Matter/examples/MatterCommissionTest/MatterCommissionTest.ino @@ -1,65 +1,65 @@ -// Matter Manager -#include -#include - -// List of Matter Endpoints for this Node -// On/Off Light Endpoint -#include -MatterOnOffLight OnOffLight; - -// 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() { - 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 at least one Matter EndPoint - OnOffLight.begin(); - - // Matter begining - Last step, after all EndPoints are initialized - Matter.begin(); -} - -void loop() { - // Check Matter Commissioning state - 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 Light Commissioning. - while (!Matter.isDeviceCommissioned()) { - delay(5000); - Serial.println("Matter Fabric not commissioned yet. Waiting for commissioning."); - } - } - Serial.println("Matter Node is commissioned and connected to Wi-Fi."); - Serial.println("====> Decommissioning in 30 seconds. <===="); - delay(30000); - Matter.decommission(); - Serial.println("Matter Node is decommissioned. Commsssioning widget shall start over."); -} \ No newline at end of file +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// On/Off Light Endpoint +#include +MatterOnOffLight OnOffLight; + +// 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() { + 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 at least one Matter EndPoint + OnOffLight.begin(); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); +} + +void loop() { + // Check Matter Commissioning state + 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 Light Commissioning. + while (!Matter.isDeviceCommissioned()) { + delay(5000); + Serial.println("Matter Fabric not commissioned yet. Waiting for commissioning."); + } + } + Serial.println("Matter Node is commissioned and connected to Wi-Fi."); + Serial.println("====> Decommissioning in 30 seconds. <===="); + delay(30000); + Matter.decommission(); + Serial.println("Matter Node is decommissioned. Commsssioning widget shall start over."); +} diff --git a/libraries/Matter/examples/MatterCommissionTest/ci.json b/libraries/Matter/examples/MatterCommissionTest/ci.json index 6d8bd16ac1d..556a8a9ee6b 100644 --- a/libraries/Matter/examples/MatterCommissionTest/ci.json +++ b/libraries/Matter/examples/MatterCommissionTest/ci.json @@ -1,8 +1,7 @@ -{ - "fqbn_append": "PartitionScheme=huge_app", - "requires": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" - ] -} - +{ + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" + ] +} diff --git a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino index 8e726001483..63f154d4492 100644 --- a/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino +++ b/libraries/Matter/examples/MatterComposedLights/MatterComposedLights.ino @@ -1,94 +1,94 @@ -// Matter Manager -#include -#include - -// List of Matter Endpoints for this Node -// There will be 3 On/Off Light Endpoints in the same Node -#include -MatterOnOffLight OnOffLight1; -MatterOnOffLight OnOffLight2; -MatterOnOffLight OnOffLight3; - -// Matter Protocol Endpoint Callback for each Light Accessory -bool setLightOnOff1(bool state) { - Serial.printf("CB-Light1 changed state to: %s\r\n", state ? "ON" : "OFF"); - return true; -} - -bool setLightOnOff2(bool state) { - Serial.printf("CB-Light2 changed state to: %s\r\n", state ? "ON" : "OFF"); - return true; -} - -bool setLightOnOff3(bool state) { - Serial.printf("CB-Light3 changed state to: %s\r\n", state ? "ON" : "OFF"); - return true; -} - -// 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() { - 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 all 3 Matter EndPoints - OnOffLight1.begin(); - OnOffLight2.begin(); - OnOffLight3.begin(); - OnOffLight1.onChangeOnOff(setLightOnOff1); - OnOffLight2.onChangeOnOff(setLightOnOff2); - OnOffLight3.onChangeOnOff(setLightOnOff3); - - // Matter begining - Last step, after all EndPoints are initialized - Matter.begin(); -} - -void loop() { - // Check Matter Light Commissioning state - 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 Light 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."); - } - - //displays the Light state every 3 seconds - Serial.println("======================"); - Serial.printf("Matter Light #1 is %s\r\n", OnOffLight1.getOnOff() ? "ON" : "OFF"); - Serial.printf("Matter Light #2 is %s\r\n", OnOffLight2.getOnOff() ? "ON" : "OFF"); - Serial.printf("Matter Light #3 is %s\r\n", OnOffLight3.getOnOff() ? "ON" : "OFF"); - delay(3000); -} \ No newline at end of file +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// There will be 3 On/Off Light Endpoints in the same Node +#include +MatterOnOffLight OnOffLight1; +MatterOnOffLight OnOffLight2; +MatterOnOffLight OnOffLight3; + +// Matter Protocol Endpoint Callback for each Light Accessory +bool setLightOnOff1(bool state) { + Serial.printf("CB-Light1 changed state to: %s\r\n", state ? "ON" : "OFF"); + return true; +} + +bool setLightOnOff2(bool state) { + Serial.printf("CB-Light2 changed state to: %s\r\n", state ? "ON" : "OFF"); + return true; +} + +bool setLightOnOff3(bool state) { + Serial.printf("CB-Light3 changed state to: %s\r\n", state ? "ON" : "OFF"); + return true; +} + +// 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() { + 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 all 3 Matter EndPoints + OnOffLight1.begin(); + OnOffLight2.begin(); + OnOffLight3.begin(); + OnOffLight1.onChangeOnOff(setLightOnOff1); + OnOffLight2.onChangeOnOff(setLightOnOff2); + OnOffLight3.onChangeOnOff(setLightOnOff3); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); +} + +void loop() { + // Check Matter Light Commissioning state + 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 Light 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."); + } + + //displays the Light state every 3 seconds + Serial.println("======================"); + Serial.printf("Matter Light #1 is %s\r\n", OnOffLight1.getOnOff() ? "ON" : "OFF"); + Serial.printf("Matter Light #2 is %s\r\n", OnOffLight2.getOnOff() ? "ON" : "OFF"); + Serial.printf("Matter Light #3 is %s\r\n", OnOffLight3.getOnOff() ? "ON" : "OFF"); + delay(3000); +} diff --git a/libraries/Matter/examples/MatterComposedLights/ci.json b/libraries/Matter/examples/MatterComposedLights/ci.json index 3f9bfdcaa4c..556a8a9ee6b 100644 --- a/libraries/Matter/examples/MatterComposedLights/ci.json +++ b/libraries/Matter/examples/MatterComposedLights/ci.json @@ -1,7 +1,7 @@ -{ - "fqbn_append": "PartitionScheme=huge_app", - "requires": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" - ] -} \ No newline at end of file +{ + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" + ] +} diff --git a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino index cd02c5eee53..64981b23a66 100644 --- a/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino +++ b/libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino @@ -1,138 +1,138 @@ -// Matter Manager -#include -#include -#include - -// List of Matter Endpoints for this Node -// On/Off Light Endpoint -#include -MatterOnOffLight OnOffLight; - -// it will keep last OnOff state stored, using Preferences -Preferences lastStatePref; - -// set your board LED pin here -#ifdef LED_BUILTIN -const uint8_t ledPin = LED_BUILTIN; -#else -const uint8_t ledPin = 2; // Set your pin here if your board has not defined LED_BUILTIN -#warning "Do not forget to set the LED pin" -#endif - -// set your board USER BUTTON pin here -const uint8_t buttonPin = 0; // Set your pin here. Using BOOT Button. C6/C3 use GPIO9. - -// Matter Protocol Endpoint Callback -bool setLightOnOff(bool state) { - Serial.printf("User Callback :: New Light State = %s\r\n", state ? "ON" : "OFF"); - if (state) { - digitalWrite(ledPin, HIGH); - } else { - digitalWrite(ledPin, LOW); - } - // store last OnOff state for when the Light is restarted / power goes off - lastStatePref.putBool("lastOnOffState", state); - // This callback must return the success state to Matter core - return true; -} - -// WiFi is manually set and started - -const char *ssid = "Apartment B15"; // Change this to your WiFi SSID -const char *password = "flat-pony-body"; // Change this to your WiFi password - -void setup() { - // Initializa the USER BUTTON (Boot button) GPIO that will act as a toggle switch - pinMode(buttonPin, INPUT_PULLUP); - // Initialize the LED (light) GPIO and Matter End Point - pinMode(ledPin, OUTPUT); - - 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 Matter EndPoint - lastStatePref.begin("matterLight", false); - bool lastOnOffState = lastStatePref.getBool("lastOnOffState", true); - OnOffLight.begin(lastOnOffState); - OnOffLight.onChangeOnOff(setLightOnOff); - - // Matter begining - 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."); - Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); - setLightOnOff(OnOffLight.getOnOff()); // configure the Light based on initial state - } -} -// 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 light - -void loop() { - // Check Matter Light 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 Light 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.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); - setLightOnOff(OnOffLight.getOnOff()); // configure the Light based on initial state - Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); - } - - // A button is also used to control the light - // 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 Light toggle switch 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 - // Toggle button is released - toggle the light - Serial.println("User button released. Toggling Light!"); - OnOffLight.toggle(); // Matter Controller also can see the change - - // Factory reset is triggered if the button is pressed longer than 10 seconds - if (time_diff > decommissioningTimeout) { - Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); - OnOffLight.setOnOff(false); // turn the light off - Matter.decommission(); - } - } -} \ No newline at end of file +// Matter Manager +#include +#include +#include + +// List of Matter Endpoints for this Node +// On/Off Light Endpoint +#include +MatterOnOffLight OnOffLight; + +// it will keep last OnOff state stored, using Preferences +Preferences lastStatePref; + +// set your board LED pin here +#ifdef LED_BUILTIN +const uint8_t ledPin = LED_BUILTIN; +#else +const uint8_t ledPin = 2; // Set your pin here if your board has not defined LED_BUILTIN +#warning "Do not forget to set the LED pin" +#endif + +// set your board USER BUTTON pin here +const uint8_t buttonPin = 0; // Set your pin here. Using BOOT Button. C6/C3 use GPIO9. + +// Matter Protocol Endpoint Callback +bool setLightOnOff(bool state) { + Serial.printf("User Callback :: New Light State = %s\r\n", state ? "ON" : "OFF"); + if (state) { + digitalWrite(ledPin, HIGH); + } else { + digitalWrite(ledPin, LOW); + } + // store last OnOff state for when the Light is restarted / power goes off + lastStatePref.putBool("lastOnOffState", state); + // This callback must return the success state to Matter core + return true; +} + +// WiFi is manually set and started + +const char *ssid = "Apartment B15"; // Change this to your WiFi SSID +const char *password = "flat-pony-body"; // 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); + // Initialize the LED (light) GPIO and Matter End Point + pinMode(ledPin, OUTPUT); + + 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 Matter EndPoint + lastStatePref.begin("matterLight", false); + bool lastOnOffState = lastStatePref.getBool("lastOnOffState", true); + OnOffLight.begin(lastOnOffState); + OnOffLight.onChangeOnOff(setLightOnOff); + + // 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."); + Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); + setLightOnOff(OnOffLight.getOnOff()); // configure the Light based on initial state + } +} +// 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 light + +void loop() { + // Check Matter Light 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 Light 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.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF"); + setLightOnOff(OnOffLight.getOnOff()); // configure the Light based on initial state + Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use."); + } + + // A button is also used to control the light + // 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 Light toggle switch 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 + // Toggle button is released - toggle the light + Serial.println("User button released. Toggling Light!"); + OnOffLight.toggle(); // Matter Controller also can see the change + + // Factory reset is triggered if the button is pressed longer than 10 seconds + if (time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + OnOffLight.setOnOff(false); // turn the light off + Matter.decommission(); + } + } +} diff --git a/libraries/Matter/examples/MatterOnOffLight/ci.json b/libraries/Matter/examples/MatterOnOffLight/ci.json index f31414ace23..556a8a9ee6b 100644 --- a/libraries/Matter/examples/MatterOnOffLight/ci.json +++ b/libraries/Matter/examples/MatterOnOffLight/ci.json @@ -1,7 +1,7 @@ -{ - "fqbn_append": "PartitionScheme=huge_app", - "requires": [ - "CONFIG_SOC_WIFI_SUPPORTED=y", - "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" - ] -} \ No newline at end of file +{ + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" + ] +} diff --git a/libraries/Matter/src/Matter.cpp b/libraries/Matter/src/Matter.cpp index e51074adc1a..49504babac0 100644 --- a/libraries/Matter/src/Matter.cpp +++ b/libraries/Matter/src/Matter.cpp @@ -1,166 +1,163 @@ -#include -#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL - -#include -#include -#include "MatterEndPoint.h" - -using namespace esp_matter; -using namespace esp_matter::attribute; -using namespace esp_matter::endpoint; -using namespace chip::app::Clusters; - -constexpr auto k_timeout_seconds = 300; - -static bool _matter_has_started = false; -static node::config_t node_config; -static node_t *deviceNode = NULL; - -typedef void *app_driver_handle_t; -esp_err_t matter_light_attribute_update( - app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val -); - -// This callback is called for every attribute update. The callback implementation shall -// handle the desired attributes and return an appropriate error code. If the attribute -// is not of your interest, please do not return an error code and strictly return ESP_OK. -static esp_err_t app_attribute_update_cb( - attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, - uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data) -{ - esp_err_t err = ESP_OK; - MatterEndPoint *ep = (MatterEndPoint *) priv_data; // endpoint pointer to base class - switch(type) { - case PRE_UPDATE: // Callback before updating the value in the database - log_i("Attribute update callback: PRE_UPDATE"); - if (ep != NULL) { - err = ep->attributeChangeCB(endpoint_id, cluster_id, attribute_id, val) ? ESP_OK : ESP_FAIL; - } - break; - case POST_UPDATE: // Callback after updating the value in the database - log_i("Attribute update callback: POST_UPDATE"); - break; - case READ: // Callback for reading the attribute value. This is used when the `ATTRIBUTE_FLAG_OVERRIDE` is set. - log_i("Attribute update callback: READ"); - break; - case WRITE: // Callback for writing the attribute value. This is used when the `ATTRIBUTE_FLAG_OVERRIDE` is set. - log_i("Attribute update callback: WRITE"); - break; - default: - log_i("Attribute update callback: Unknown type %d", type); - } - return err; -} - -// This callback is invoked when clients interact with the Identify Cluster. -// In the callback implementation, an endpoint can identify itself. (e.g., by flashing an LED or light). -static esp_err_t app_identification_cb(identification::callback_type_t type, uint16_t endpoint_id, uint8_t effect_id, uint8_t effect_variant, void *priv_data) { - log_i("Identification callback: type: %u, effect: %u, variant: %u", type, effect_id, effect_variant); - return ESP_OK; -} - - -// This callback is invoked for all Matter events. The application can handle the events as required. -static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) { - switch (event->Type) { - case chip::DeviceLayer::DeviceEventType::kInterfaceIpAddressChanged: - log_i( - "Interface %s Address changed", event->InterfaceIpAddressChanged.Type == chip::DeviceLayer::InterfaceIpChangeType::kIpV4_Assigned ? "IPv4" : "IPV6" - ); - break; - case chip::DeviceLayer::DeviceEventType::kCommissioningComplete: log_i("Commissioning complete"); break; - case chip::DeviceLayer::DeviceEventType::kFailSafeTimerExpired: log_i("Commissioning failed, fail safe timer expired"); break; - case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStarted: log_i("Commissioning session started"); break; - case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStopped: log_i("Commissioning session stopped"); break; - case chip::DeviceLayer::DeviceEventType::kCommissioningWindowOpened: log_i("Commissioning window opened"); break; - case chip::DeviceLayer::DeviceEventType::kCommissioningWindowClosed: log_i("Commissioning window closed"); break; - case chip::DeviceLayer::DeviceEventType::kFabricRemoved: - { - log_i("Fabric removed successfully"); - if (chip::Server::GetInstance().GetFabricTable().FabricCount() == 0) { - log_i("No fabric left, opening commissioning window"); - chip::CommissioningWindowManager &commissionMgr = chip::Server::GetInstance().GetCommissioningWindowManager(); - constexpr auto kTimeoutSeconds = chip::System::Clock::Seconds16(k_timeout_seconds); - if (!commissionMgr.IsCommissioningWindowOpen()) { - // After removing last fabric, it does not remove the Wi-Fi credentials and still has IP connectivity so, only advertising on DNS-SD. - CHIP_ERROR err = commissionMgr.OpenBasicCommissioningWindow(kTimeoutSeconds, chip::CommissioningWindowAdvertisement::kDnssdOnly); - if (err != CHIP_NO_ERROR) { - log_e("Failed to open commissioning window, err:%" CHIP_ERROR_FORMAT, err.Format()); - } - } - } - break; - } - case chip::DeviceLayer::DeviceEventType::kFabricWillBeRemoved: log_i("Fabric will be removed"); break; - case chip::DeviceLayer::DeviceEventType::kFabricUpdated: log_i("Fabric is updated"); break; - case chip::DeviceLayer::DeviceEventType::kFabricCommitted: log_i("Fabric is committed"); break; - case chip::DeviceLayer::DeviceEventType::kBLEDeinitialized: log_i("BLE deinitialized and memory reclaimed"); break; - default: break; - } -} - -void ArduinoMatter::_init() { - if (_matter_has_started) { - return; - } - - // Create a Matter node and add the mandatory Root Node device type on endpoint 0 - // node handle can be used to add/modify other endpoints. - deviceNode = node::create(&node_config, app_attribute_update_cb, app_identification_cb); - if (deviceNode == nullptr) { - log_e("Failed to create Matter node"); - return; - } - - _matter_has_started = true; -} - -void ArduinoMatter::begin() { - if (!_matter_has_started) { - log_w("No Matter endpoint has been created. Please create an endpoint first."); - return; - } - - /* Matter start */ - esp_err_t err = esp_matter::start(app_event_cb); - if (err != ESP_OK) { - log_e("Failed to start Matter, err:%d", err); - _matter_has_started = false; - } -} - -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD -bool ArduinoMatter::isThreadConnected() { - return false; // Thread Network TBD -} -#endif - -bool ArduinoMatter::isDeviceCommissioned() { - return chip::Server::GetInstance().GetFabricTable().FabricCount() > 0; -} - -#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION -bool ArduinoMatter::isWiFiConnected() { - return chip::DeviceLayer::ConnectivityMgr().IsWiFiStationConnected(); -} -#endif - -bool ArduinoMatter::isDeviceConnected() { - bool retCode = false; -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD - retCode |= ArduinoMatter::isThreadConnected(); -#endif -#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION - retCode |= ArduinoMatter::isWiFiConnected(); -#endif - return retCode; -} - -void ArduinoMatter::decommission() { - esp_matter::factory_reset(); -} - -// Global Matter Object -ArduinoMatter Matter; - -#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include +#include "MatterEndPoint.h" + +using namespace esp_matter; +using namespace esp_matter::attribute; +using namespace esp_matter::endpoint; +using namespace chip::app::Clusters; + +constexpr auto k_timeout_seconds = 300; + +static bool _matter_has_started = false; +static node::config_t node_config; +static node_t *deviceNode = NULL; + +typedef void *app_driver_handle_t; +esp_err_t matter_light_attribute_update( + app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val +); + +// This callback is called for every attribute update. The callback implementation shall +// handle the desired attributes and return an appropriate error code. If the attribute +// is not of your interest, please do not return an error code and strictly return ESP_OK. +static esp_err_t app_attribute_update_cb( + attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data +) { + esp_err_t err = ESP_OK; + MatterEndPoint *ep = (MatterEndPoint *)priv_data; // endpoint pointer to base class + switch (type) { + case PRE_UPDATE: // Callback before updating the value in the database + log_i("Attribute update callback: PRE_UPDATE"); + if (ep != NULL) { + err = ep->attributeChangeCB(endpoint_id, cluster_id, attribute_id, val) ? ESP_OK : ESP_FAIL; + } + break; + case POST_UPDATE: // Callback after updating the value in the database + log_i("Attribute update callback: POST_UPDATE"); + break; + case READ: // Callback for reading the attribute value. This is used when the `ATTRIBUTE_FLAG_OVERRIDE` is set. + log_i("Attribute update callback: READ"); + break; + case WRITE: // Callback for writing the attribute value. This is used when the `ATTRIBUTE_FLAG_OVERRIDE` is set. + log_i("Attribute update callback: WRITE"); + break; + default: log_i("Attribute update callback: Unknown type %d", type); + } + return err; +} + +// This callback is invoked when clients interact with the Identify Cluster. +// In the callback implementation, an endpoint can identify itself. (e.g., by flashing an LED or light). +static esp_err_t app_identification_cb(identification::callback_type_t type, uint16_t endpoint_id, uint8_t effect_id, uint8_t effect_variant, void *priv_data) { + log_i("Identification callback: type: %u, effect: %u, variant: %u", type, effect_id, effect_variant); + return ESP_OK; +} + +// This callback is invoked for all Matter events. The application can handle the events as required. +static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) { + switch (event->Type) { + case chip::DeviceLayer::DeviceEventType::kInterfaceIpAddressChanged: + log_i( + "Interface %s Address changed", event->InterfaceIpAddressChanged.Type == chip::DeviceLayer::InterfaceIpChangeType::kIpV4_Assigned ? "IPv4" : "IPV6" + ); + break; + case chip::DeviceLayer::DeviceEventType::kCommissioningComplete: log_i("Commissioning complete"); break; + case chip::DeviceLayer::DeviceEventType::kFailSafeTimerExpired: log_i("Commissioning failed, fail safe timer expired"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStarted: log_i("Commissioning session started"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStopped: log_i("Commissioning session stopped"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningWindowOpened: log_i("Commissioning window opened"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningWindowClosed: log_i("Commissioning window closed"); break; + case chip::DeviceLayer::DeviceEventType::kFabricRemoved: + { + log_i("Fabric removed successfully"); + if (chip::Server::GetInstance().GetFabricTable().FabricCount() == 0) { + log_i("No fabric left, opening commissioning window"); + chip::CommissioningWindowManager &commissionMgr = chip::Server::GetInstance().GetCommissioningWindowManager(); + constexpr auto kTimeoutSeconds = chip::System::Clock::Seconds16(k_timeout_seconds); + if (!commissionMgr.IsCommissioningWindowOpen()) { + // After removing last fabric, it does not remove the Wi-Fi credentials and still has IP connectivity so, only advertising on DNS-SD. + CHIP_ERROR err = commissionMgr.OpenBasicCommissioningWindow(kTimeoutSeconds, chip::CommissioningWindowAdvertisement::kDnssdOnly); + if (err != CHIP_NO_ERROR) { + log_e("Failed to open commissioning window, err:%" CHIP_ERROR_FORMAT, err.Format()); + } + } + } + break; + } + case chip::DeviceLayer::DeviceEventType::kFabricWillBeRemoved: log_i("Fabric will be removed"); break; + case chip::DeviceLayer::DeviceEventType::kFabricUpdated: log_i("Fabric is updated"); break; + case chip::DeviceLayer::DeviceEventType::kFabricCommitted: log_i("Fabric is committed"); break; + case chip::DeviceLayer::DeviceEventType::kBLEDeinitialized: log_i("BLE deinitialized and memory reclaimed"); break; + default: break; + } +} + +void ArduinoMatter::_init() { + if (_matter_has_started) { + return; + } + + // Create a Matter node and add the mandatory Root Node device type on endpoint 0 + // node handle can be used to add/modify other endpoints. + deviceNode = node::create(&node_config, app_attribute_update_cb, app_identification_cb); + if (deviceNode == nullptr) { + log_e("Failed to create Matter node"); + return; + } + + _matter_has_started = true; +} + +void ArduinoMatter::begin() { + if (!_matter_has_started) { + log_w("No Matter endpoint has been created. Please create an endpoint first."); + return; + } + + /* Matter start */ + esp_err_t err = esp_matter::start(app_event_cb); + if (err != ESP_OK) { + log_e("Failed to start Matter, err:%d", err); + _matter_has_started = false; + } +} + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD +bool ArduinoMatter::isThreadConnected() { + return false; // Thread Network TBD +} +#endif + +bool ArduinoMatter::isDeviceCommissioned() { + return chip::Server::GetInstance().GetFabricTable().FabricCount() > 0; +} + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION +bool ArduinoMatter::isWiFiConnected() { + return chip::DeviceLayer::ConnectivityMgr().IsWiFiStationConnected(); +} +#endif + +bool ArduinoMatter::isDeviceConnected() { + bool retCode = false; +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + retCode |= ArduinoMatter::isThreadConnected(); +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION + retCode |= ArduinoMatter::isWiFiConnected(); +#endif + return retCode; +} + +void ArduinoMatter::decommission() { + esp_matter::factory_reset(); +} + +// Global Matter Object +ArduinoMatter Matter; + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h index 289051d569a..a1ce0f2f644 100644 --- a/libraries/Matter/src/Matter.h +++ b/libraries/Matter/src/Matter.h @@ -1,39 +1,40 @@ -#pragma once -#include -#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL - -#include -#include - -using namespace esp_matter; - -class ArduinoMatter { - public: - static inline String getManualPairingCode() { - // return the pairing code for manual pairing - return String("34970112332"); - } - static inline String getOnboardingQRCodeUrl() { - // return the URL for the QR code for onboarding - return String("https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT:Y.K9042C00KA0648G00"); - } - static void begin(); - static bool isDeviceCommissioned(); -#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION - static bool isWiFiConnected(); -#endif -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD - static bool isThreadConnected(); -#endif - static bool isDeviceConnected(); - static void decommission(); - - // list of Matter EndPoints Friend Classes - friend class MatterOnOffLight; - protected: - static void _init(); -}; - -extern ArduinoMatter Matter; - -#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file +#pragma once +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +using namespace esp_matter; + +class ArduinoMatter { +public: + static inline String getManualPairingCode() { + // return the pairing code for manual pairing + return String("34970112332"); + } + static inline String getOnboardingQRCodeUrl() { + // return the URL for the QR code for onboarding + return String("https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT:Y.K9042C00KA0648G00"); + } + static void begin(); + static bool isDeviceCommissioned(); +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION + static bool isWiFiConnected(); +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + static bool isThreadConnected(); +#endif + static bool isDeviceConnected(); + static void decommission(); + + // list of Matter EndPoints Friend Classes + friend class MatterOnOffLight; + +protected: + static void _init(); +}; + +extern ArduinoMatter Matter; + +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndPoint.h b/libraries/Matter/src/MatterEndPoint.h index 5db30c52985..2be5bf5bb5d 100644 --- a/libraries/Matter/src/MatterEndPoint.h +++ b/libraries/Matter/src/MatterEndPoint.h @@ -1,23 +1,23 @@ -#pragma once -#include -#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL - -#include -#include - -// Matter Endpoint Base Class. Controls the endpoint ID and allows the child class to overwrite attribute change call -class MatterEndPoint { - public: - uint16_t getEndPointId() { - return endpoint_id; - } - void setEndPointId(uint16_t ep) { - endpoint_id = ep; - } - - virtual bool attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) = 0; - - protected: - uint16_t endpoint_id = 0; -}; -#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file +#pragma once +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +// Matter Endpoint Base Class. Controls the endpoint ID and allows the child class to overwrite attribute change call +class MatterEndPoint { +public: + uint16_t getEndPointId() { + return endpoint_id; + } + void setEndPointId(uint16_t ep) { + endpoint_id = ep; + } + + virtual bool attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) = 0; + +protected: + uint16_t endpoint_id = 0; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterOnOffLight.cpp b/libraries/Matter/src/MatterOnOffLight.cpp index c6715740969..7e8926ffdef 100644 --- a/libraries/Matter/src/MatterOnOffLight.cpp +++ b/libraries/Matter/src/MatterOnOffLight.cpp @@ -1,108 +1,107 @@ -#include -#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL - -#include -#include -#include - -using namespace esp_matter; -using namespace esp_matter::endpoint; -using namespace chip::app::Clusters; - -bool MatterOnOffLight::attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) { - bool ret = true; - if (!started) { - log_w("Matter On-Off Light device has not begun."); - return false; - } - - if (endpoint_id == getEndPointId()) { - if (cluster_id == OnOff::Id) { - if (attribute_id == OnOff::Attributes::OnOff::Id) { - if (_onChangeCB != NULL) { - ret = _onChangeCB(val->val.b); - log_d("OnOffLight state changed to %d", val->val.b); - if (ret == true) { - state = val->val.b; - } - } - } - } - } - return ret; -} - -MatterOnOffLight::MatterOnOffLight() { -} - -MatterOnOffLight::~MatterOnOffLight() { - end(); -} - -bool MatterOnOffLight::begin(bool initialState) { - ArduinoMatter::_init(); - on_off_light::config_t light_config; - light_config.on_off.on_off = initialState; - state = initialState; - light_config.on_off.lighting.start_up_on_off = nullptr; - - // endpoint handles can be used to add/modify clusters. - endpoint_t *endpoint = on_off_light::create(node::get(), &light_config, ENDPOINT_FLAG_NONE, (void *) this); - if (endpoint == nullptr) { - log_e("Failed to create on-off light endpoint"); - return false; - } - - setEndPointId(endpoint::get_id(endpoint)); - log_i("On-Off Light created with endpoint_id %d", getEndPointId()); - started = true; - return true; -} - -void MatterOnOffLight::end() { - started = false; -} - -bool MatterOnOffLight::setOnOff(bool newState) { - if (!started) { - log_w("Matter On-Off Light device has not begun."); - return false; - } - - // avoid processing the a "no-change" - if (state == newState) { - return true; - } - - state = newState; - - endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id); - cluster_t *cluster = cluster::get(endpoint, OnOff::Id); - attribute_t *attribute = attribute::get(cluster, OnOff::Attributes::OnOff::Id); - - esp_matter_attr_val_t val = esp_matter_invalid(NULL); - attribute::get_val(attribute, &val); - - if (val.val.b != state) { - val.val.b = state; - attribute::update(endpoint_id, OnOff::Id, OnOff::Attributes::OnOff::Id, &val); - } - return true; -} - -bool MatterOnOffLight::getOnOff() { - return state; -} - -bool MatterOnOffLight::toggle() { - return setOnOff(!state); -} - -MatterOnOffLight::operator bool() { - return getOnOff(); -} - -void MatterOnOffLight::operator=(bool newState) { - setOnOff(newState); -} -#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include +#include + +using namespace esp_matter; +using namespace esp_matter::endpoint; +using namespace chip::app::Clusters; + +bool MatterOnOffLight::attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) { + bool ret = true; + if (!started) { + log_w("Matter On-Off Light device has not begun."); + return false; + } + + if (endpoint_id == getEndPointId()) { + if (cluster_id == OnOff::Id) { + if (attribute_id == OnOff::Attributes::OnOff::Id) { + if (_onChangeCB != NULL) { + ret = _onChangeCB(val->val.b); + log_d("OnOffLight state changed to %d", val->val.b); + if (ret == true) { + state = val->val.b; + } + } + } + } + } + return ret; +} + +MatterOnOffLight::MatterOnOffLight() {} + +MatterOnOffLight::~MatterOnOffLight() { + end(); +} + +bool MatterOnOffLight::begin(bool initialState) { + ArduinoMatter::_init(); + on_off_light::config_t light_config; + light_config.on_off.on_off = initialState; + state = initialState; + light_config.on_off.lighting.start_up_on_off = nullptr; + + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = on_off_light::create(node::get(), &light_config, ENDPOINT_FLAG_NONE, (void *)this); + if (endpoint == nullptr) { + log_e("Failed to create on-off light endpoint"); + return false; + } + + setEndPointId(endpoint::get_id(endpoint)); + log_i("On-Off Light created with endpoint_id %d", getEndPointId()); + started = true; + return true; +} + +void MatterOnOffLight::end() { + started = false; +} + +bool MatterOnOffLight::setOnOff(bool newState) { + if (!started) { + log_w("Matter On-Off Light device has not begun."); + return false; + } + + // avoid processing the a "no-change" + if (state == newState) { + return true; + } + + state = newState; + + endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id); + cluster_t *cluster = cluster::get(endpoint, OnOff::Id); + attribute_t *attribute = attribute::get(cluster, OnOff::Attributes::OnOff::Id); + + esp_matter_attr_val_t val = esp_matter_invalid(NULL); + attribute::get_val(attribute, &val); + + if (val.val.b != state) { + val.val.b = state; + attribute::update(endpoint_id, OnOff::Id, OnOff::Attributes::OnOff::Id, &val); + } + return true; +} + +bool MatterOnOffLight::getOnOff() { + return state; +} + +bool MatterOnOffLight::toggle() { + return setOnOff(!state); +} + +MatterOnOffLight::operator bool() { + return getOnOff(); +} + +void MatterOnOffLight::operator=(bool newState) { + setOnOff(newState); +} +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterOnOffLight.h b/libraries/Matter/src/MatterOnOffLight.h index 8fac52be62e..39220652e21 100644 --- a/libraries/Matter/src/MatterOnOffLight.h +++ b/libraries/Matter/src/MatterOnOffLight.h @@ -1,34 +1,34 @@ -#pragma once -#include -#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL - -#include -#include - -class MatterOnOffLight : public MatterEndPoint { - public: - MatterOnOffLight(); - ~MatterOnOffLight(); - virtual bool begin(bool initialState = false); // default initial state is off - void end(); // this will just stop processing Light Matter events - - bool setOnOff(bool newState); // returns true if successful - bool getOnOff(); // returns current light state - bool toggle(); // returns true if successful - - operator bool(); // returns current light state - void operator=(bool state); // turns light on or off - // 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); - // User Callback for whenever the Light state is changed by the Matter Controller - using EndPointCB = std::function; - void onChangeOnOff(EndPointCB onChangeCB) { - _onChangeCB = onChangeCB; - } - - protected: - bool started = false; - bool state = false; // default initial state is off, but it can be changed by begin(bool) - EndPointCB _onChangeCB = NULL; -}; -#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ \ No newline at end of file +#pragma once +#include +#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL + +#include +#include + +class MatterOnOffLight : public MatterEndPoint { +public: + MatterOnOffLight(); + ~MatterOnOffLight(); + virtual bool begin(bool initialState = false); // default initial state is off + void end(); // this will just stop processing Light Matter events + + bool setOnOff(bool newState); // returns true if successful + bool getOnOff(); // returns current light state + bool toggle(); // returns true if successful + + operator bool(); // returns current light state + void operator=(bool state); // turns light on or off + // 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); + // User Callback for whenever the Light state is changed by the Matter Controller + using EndPointCB = std::function; + void onChangeOnOff(EndPointCB onChangeCB) { + _onChangeCB = onChangeCB; + } + +protected: + bool started = false; + bool state = false; // default initial state is off, but it can be changed by begin(bool) + EndPointCB _onChangeCB = NULL; +}; +#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/USB/src/USBHID.cpp b/libraries/USB/src/USBHID.cpp index 4bc555b8e30..1d5d86fb3a3 100644 --- a/libraries/USB/src/USBHID.cpp +++ b/libraries/USB/src/USBHID.cpp @@ -206,7 +206,9 @@ extern "C" uint16_t tusb_hid_load_descriptor(uint8_t *dst, uint8_t *itf) { uint8_t descriptor[TUD_HID_INOUT_DESC_LEN] = { // HID Input & Output descriptor // Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval - TUD_HID_INOUT_DESCRIPTOR(*itf, str_index, tinyusb_interface_protocol, tinyusb_hid_device_descriptor_len, ep_out, (uint8_t)(0x80 | ep_in), CFG_TUD_ENDOINT_SIZE, 1) + TUD_HID_INOUT_DESCRIPTOR( + *itf, str_index, tinyusb_interface_protocol, tinyusb_hid_device_descriptor_len, ep_out, (uint8_t)(0x80 | ep_in), CFG_TUD_ENDOINT_SIZE, 1 + ) }; *itf += 1; memcpy(dst, descriptor, TUD_HID_INOUT_DESC_LEN);