From 5a2094acc011d720912b3643d6e0cb72734c4bf9 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Fri, 13 Jun 2025 11:57:09 -0300 Subject: [PATCH 1/7] feat(matter): Adds Matter Events callback plus example --- .../examples/MatterEvents/MatterEvents.ino | 246 ++++++++++++++++++ .../Matter/examples/MatterEvents/ci.json | 7 + libraries/Matter/src/Matter.cpp | 31 ++- libraries/Matter/src/Matter.h | 127 +++++++++ 4 files changed, 398 insertions(+), 13 deletions(-) create mode 100644 libraries/Matter/examples/MatterEvents/MatterEvents.ino create mode 100644 libraries/Matter/examples/MatterEvents/ci.json diff --git a/libraries/Matter/examples/MatterEvents/MatterEvents.ino b/libraries/Matter/examples/MatterEvents/MatterEvents.ino new file mode 100644 index 00000000000..0378b4e0939 --- /dev/null +++ b/libraries/Matter/examples/MatterEvents/MatterEvents.ino @@ -0,0 +1,246 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Matter Manager +#include +#include + +// 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 + +// List of Matter Endpoints for this Node +// On/Off Light Endpoint +MatterOnOffLight OnOffLight; + +// This function is called when a Matter event occurs +void onMatterEvent(ArduinoMatter::matterEvent_t eventType, const chip::DeviceLayer::ChipDeviceEvent *eventInfo) { + // Print the event type to Serial + Serial.print("===> Got a Matter Event: "); + switch (eventType) { + case ArduinoMatter::MATTER_WIFI_CONNECTIVITY_CHANGE: + Serial.println("WiFi Connectivity Change"); + break; + case ArduinoMatter::MATTER_THREAD_CONNECTIVITY_CHANGE: + Serial.println("Thread Connectivity Change"); + break; + case ArduinoMatter::MATTER_INTERNET_CONNECTIVITY_CHANGE: { + bool newIPAddress = false; + Serial.print("Internet Connectivity Change :: "); + if (eventInfo->InternetConnectivityChange.IPv4 != chip::DeviceLayer::ConnectivityChange::kConnectivity_NoChange) { + Serial.print("IPv4 Connectivity: "); + switch (eventInfo->InternetConnectivityChange.IPv4) { + case chip::DeviceLayer::ConnectivityChange::kConnectivity_Established: { + newIPAddress = true; + break; + } + case chip::DeviceLayer::ConnectivityChange::kConnectivity_Lost: + Serial.println("Lost"); + break; + default: + Serial.println("Unknown"); + break; + } + } + if (eventInfo->InternetConnectivityChange.IPv6 != chip::DeviceLayer::ConnectivityChange::kConnectivity_NoChange) { + Serial.print("IPv6 Connectivity: "); + switch (eventInfo->InternetConnectivityChange.IPv6) { + case chip::DeviceLayer::ConnectivityChange::kConnectivity_Established: { + newIPAddress = true; + break; + } + case chip::DeviceLayer::ConnectivityChange::kConnectivity_Lost: + Serial.println("Lost"); + break; + default: + Serial.println("Unknown"); + break; + } + } + // Print the IP address if it was established + if (newIPAddress) { + Serial.print("Established - IP Address: "); + char ipAddressStr[chip::Transport::PeerAddress::kMaxToStringSize]; + eventInfo->InternetConnectivityChange.ipAddress.ToString(ipAddressStr); + Serial.println(ipAddressStr); + } + break; + } + case ArduinoMatter::MATTER_SERVICE_CONNECTIVITY_CHANGE: + Serial.println("Service Connectivity Change"); + break; + case ArduinoMatter::MATTER_SERVICE_PROVISIONING_CHANGE: + Serial.println("Service Provisioning Change"); + break; + case ArduinoMatter::MATTER_TIME_SYNC_CHANGE: + Serial.println("Time Sync Change"); + break; + case ArduinoMatter::MATTER_CHIPOBLE_CONNECTION_ESTABLISHED: + Serial.println("CHIPoBLE Connection Established"); + break; + case ArduinoMatter::MATTER_CHIPOBLE_CONNECTION_CLOSED: + Serial.println("CHIPoBLE Connection Closed"); + break; + case ArduinoMatter::MATTER_CLOSE_ALL_BLE_CONNECTIONS: + Serial.println("Close All BLE Connections"); + break; + case ArduinoMatter::MATTER_WIFI_DEVICE_AVAILABLE: + Serial.println("WiFi Device Available"); + break; + case ArduinoMatter::MATTER_OPERATIONAL_NETWORK_STARTED: + Serial.println("Operational Network Started"); + break; + case ArduinoMatter::MATTER_THREAD_STATE_CHANGE: + Serial.println("Thread State Change"); + break; + case ArduinoMatter::MATTER_THREAD_INTERFACE_STATE_CHANGE: + Serial.println("Thread Interface State Change"); + break; + case ArduinoMatter::MATTER_CHIPOBLE_ADVERTISING_CHANGE: + Serial.println("CHIPoBLE Advertising Change"); + break; + case ArduinoMatter::MATTER_INTERFACE_IP_ADDRESS_CHANGED: + switch (eventInfo->InterfaceIpAddressChanged.Type) { + case chip::DeviceLayer::InterfaceIpChangeType::kIpV4_Assigned: + Serial.println("IPv4 Address Assigned"); + break; + case chip::DeviceLayer::InterfaceIpChangeType::kIpV4_Lost: + Serial.println("IPv4 Address Lost"); + break; + case chip::DeviceLayer::InterfaceIpChangeType::kIpV6_Assigned: + Serial.println("IPv6 Address Assigned"); + break; + case chip::DeviceLayer::InterfaceIpChangeType::kIpV6_Lost: + Serial.println("IPv6 Address Lost"); + break; + } + break; + case ArduinoMatter::MATTER_COMMISSIONING_COMPLETE: + Serial.println("Commissioning Complete"); + break; + case ArduinoMatter::MATTER_FAIL_SAFE_TIMER_EXPIRED: + Serial.println("Fail Safe Timer Expired"); + break; + case ArduinoMatter::MATTER_OPERATIONAL_NETWORK_ENABLED: + Serial.println("Operational Network Enabled"); + break; + case ArduinoMatter::MATTER_DNSSD_INITIALIZED: + Serial.println("DNS-SD Initialized"); + break; + case ArduinoMatter::MATTER_DNSSD_RESTART_NEEDED: + Serial.println("DNS-SD Restart Needed"); + break; + case ArduinoMatter::MATTER_BINDINGS_CHANGED_VIA_CLUSTER: + Serial.println("Bindings Changed Via Cluster"); + break; + case ArduinoMatter::MATTER_OTA_STATE_CHANGED: + Serial.println("OTA State Changed"); + break; + case ArduinoMatter::MATTER_SERVER_READY: + Serial.println("Server Ready"); + break; + case ArduinoMatter::MATTER_BLE_DEINITIALIZED: + Serial.println("BLE Deinitialized"); + break; + case ArduinoMatter::MATTER_COMMISSIONING_SESSION_STARTED: + Serial.println("Commissioning Session Started"); + break; + case ArduinoMatter::MATTER_COMMISSIONING_SESSION_STOPPED: + Serial.println("Commissioning Session Stopped"); + break; + case ArduinoMatter::MATTER_COMMISSIONING_WINDOW_OPEN: + Serial.println("Commissioning Window Opened"); + break; + case ArduinoMatter::MATTER_COMMISSIONING_WINDOW_CLOSED: + Serial.println("Commissioning Window Closed"); + break; + case ArduinoMatter::MATTER_FABRIC_WILL_BE_REMOVED: + Serial.println("Fabric Will Be Removed"); + break; + case ArduinoMatter::MATTER_FABRIC_REMOVED: + Serial.println("Fabric Removed"); + break; + case ArduinoMatter::MATTER_FABRIC_COMMITTED: + Serial.println("Fabric Committed"); + break; + case ArduinoMatter::MATTER_FABRIC_UPDATED: + Serial.println("Fabric Updated"); + break; + case ArduinoMatter::MATTER_ESP32_SPECIFIC_EVENT: + Serial.println("Sending ESP32 Platform Specific Events"); + break; + case ArduinoMatter::MATTER_ESP32_PUBLIC_SPECIFIC_EVENT: + Serial.println("Next Event Has Populated EventInfo"); + break; + default: + // If the event type is not recognized, print "Unknown" and the event ID + Serial.println("Unknown, EventID = 0x" + String(eventType, HEX)); + break; + } +} + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); // Wait for Serial to initialize + } + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + // Manually connect to WiFi + WiFi.enableIPv6(true); // Enable IPv6 if needed + 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(); + + // Set the Matter Event Callback + Matter.onEvent(onMatterEvent); + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); + Serial.println("Starting Matter Commission Test..."); + +} + +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 60 seconds. <===="); + delay(60000); + Matter.decommission(); + Serial.println("Matter Node is decommissioned. Commsssioning widget shall start over."); +} diff --git a/libraries/Matter/examples/MatterEvents/ci.json b/libraries/Matter/examples/MatterEvents/ci.json new file mode 100644 index 00000000000..556a8a9ee6b --- /dev/null +++ b/libraries/Matter/examples/MatterEvents/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=huge_app", + "requires": [ + "CONFIG_SOC_WIFI_SUPPORTED=y", + "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y" + ] +} diff --git a/libraries/Matter/src/Matter.cpp b/libraries/Matter/src/Matter.cpp index af7c4c8657e..a684390c0b5 100644 --- a/libraries/Matter/src/Matter.cpp +++ b/libraries/Matter/src/Matter.cpp @@ -29,6 +29,7 @@ constexpr auto k_timeout_seconds = 300; static bool _matter_has_started = false; static node::config_t node_config; static node_t *deviceNode = NULL; +ArduinoMatter::matterEventCB ArduinoMatter::_matterEventCB = NULL; // 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 @@ -89,21 +90,21 @@ static esp_err_t app_identification_cb(identification::callback_type_t type, uin static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) { switch (event->Type) { case chip::DeviceLayer::DeviceEventType::kInterfaceIpAddressChanged: - log_i( + log_d( "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::kCommissioningComplete: log_d("Commissioning complete"); break; + case chip::DeviceLayer::DeviceEventType::kFailSafeTimerExpired: log_d("Commissioning failed, fail safe timer expired"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStarted: log_d("Commissioning session started"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStopped: log_d("Commissioning session stopped"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningWindowOpened: log_d("Commissioning window opened"); break; + case chip::DeviceLayer::DeviceEventType::kCommissioningWindowClosed: log_d("Commissioning window closed"); break; case chip::DeviceLayer::DeviceEventType::kFabricRemoved: { - log_i("Fabric removed successfully"); + log_d("Fabric removed successfully"); if (chip::Server::GetInstance().GetFabricTable().FabricCount() == 0) { - log_i("No fabric left, opening commissioning window"); + log_d("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()) { @@ -116,12 +117,16 @@ static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) { } 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; + case chip::DeviceLayer::DeviceEventType::kFabricWillBeRemoved: log_d("Fabric will be removed"); break; + case chip::DeviceLayer::DeviceEventType::kFabricUpdated: log_d("Fabric is updated"); break; + case chip::DeviceLayer::DeviceEventType::kFabricCommitted: log_d("Fabric is committed"); break; + case chip::DeviceLayer::DeviceEventType::kBLEDeinitialized: log_d("BLE deinitialized and memory reclaimed"); break; default: break; } + // Check if the user-defined callback is set + if (ArduinoMatter::_matterEventCB != NULL) { + ArduinoMatter::_matterEventCB(static_cast(event->Type), event); + } } void ArduinoMatter::_init() { diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h index e54ceb47e5e..ed2a3ba23a7 100644 --- a/libraries/Matter/src/Matter.h +++ b/libraries/Matter/src/Matter.h @@ -38,6 +38,133 @@ using namespace esp_matter; class ArduinoMatter { public: + // Matter Event types used when there is a user callback for Matter Events + enum matterEvent_t { + // Starting from 0x8000, these events are public and can be used by applications. + // Defined in CHIPDeviceEvent.h + + // WiFi Connectivity Change: Signals a change in connectivity of the device's WiFi station interface. + MATTER_WIFI_CONNECTIVITY_CHANGE = (uint16_t) chip::DeviceLayer::DeviceEventType::kWiFiConnectivityChange, + + // Thread Connectivity Change: Signals a change in connectivity of the device's Thread interface. + MATTER_THREAD_CONNECTIVITY_CHANGE = (uint16_t) chip::DeviceLayer::DeviceEventType::kThreadConnectivityChange, + + // Internet Connectivity Change: Signals a change in the device's ability to communicate via the Internet. + MATTER_INTERNET_CONNECTIVITY_CHANGE = (uint16_t) chip::DeviceLayer::DeviceEventType::kInternetConnectivityChange, + + // Service Connectivity Change: Signals a change in the device's ability to communicate with a chip-enabled service. + MATTER_SERVICE_CONNECTIVITY_CHANGE = (uint16_t) chip::DeviceLayer::DeviceEventType::kServiceConnectivityChange, + + // Service Provisioning Change: Signals a change to the device's service provisioning state. + MATTER_SERVICE_PROVISIONING_CHANGE = (uint16_t) chip::DeviceLayer::DeviceEventType::kServiceProvisioningChange, + + // Time Sync Change: Signals a change to the device's real time clock synchronization state. + MATTER_TIME_SYNC_CHANGE = (uint16_t) chip::DeviceLayer::DeviceEventType::kTimeSyncChange, + + // CHIPoBLE Connection Established: Signals that an external entity has established a new + // CHIPoBLE connection with the device. + MATTER_CHIPOBLE_CONNECTION_ESTABLISHED = (uint16_t) chip::DeviceLayer::DeviceEventType::kCHIPoBLEConnectionEstablished, + + // CHIPoBLE Connection Closed: Signals that an external entity has closed existing CHIPoBLE + // connection with the device. + MATTER_CHIPOBLE_CONNECTION_CLOSED = (uint16_t) chip::DeviceLayer::DeviceEventType::kCHIPoBLEConnectionClosed, + + // Request BLE connections to be closed. This is used in the supportsConcurrentConnection = False case. + MATTER_CLOSE_ALL_BLE_CONNECTIONS = (uint16_t) chip::DeviceLayer::DeviceEventType::kCloseAllBleConnections, + + // WiFi Device Available: When supportsConcurrentConnection = False, the ConnectNetwork + // command cannot start until the BLE device is closed and the Operation Network device (e.g. WiFi) has been started. + MATTER_WIFI_DEVICE_AVAILABLE = (uint16_t) chip::DeviceLayer::DeviceEventType::kWiFiDeviceAvailable, + + MATTER_OPERATIONAL_NETWORK_STARTED = (uint16_t) chip::DeviceLayer::DeviceEventType::kOperationalNetworkStarted, + + // Thread State Change: Signals that a state change has occurred in the Thread stack. + MATTER_THREAD_STATE_CHANGE = (uint16_t) chip::DeviceLayer::DeviceEventType::kThreadStateChange, + + // Thread Interface State Change: Signals that the state of the Thread network interface has changed. + MATTER_THREAD_INTERFACE_STATE_CHANGE = (uint16_t) chip::DeviceLayer::DeviceEventType::kThreadInterfaceStateChange, + + // CHIPoBLE Advertising Change: Signals that the state of CHIPoBLE advertising has changed. + MATTER_CHIPOBLE_ADVERTISING_CHANGE = (uint16_t) chip::DeviceLayer::DeviceEventType::kCHIPoBLEAdvertisingChange, + + // Interface IP Address Changed: IP address availability - either ipv4 or ipv6 + // addresses assigned to the underlying wifi/ethernet interface. + MATTER_INTERFACE_IP_ADDRESS_CHANGED = (uint16_t) chip::DeviceLayer::DeviceEventType::kInterfaceIpAddressChanged, + + // Commissioning Complete: Commissioning has completed by a call to the general + // commissioning cluster command. + MATTER_COMMISSIONING_COMPLETE = (uint16_t) chip::DeviceLayer::DeviceEventType::kCommissioningComplete, + + // Fail Safe Timer Expired: Signals that the fail-safe timer expired before + // the CommissioningComplete command was successfully invoked. + MATTER_FAIL_SAFE_TIMER_EXPIRED = (uint16_t) chip::DeviceLayer::DeviceEventType::kFailSafeTimerExpired, + + // Operational Network Enabled. + MATTER_OPERATIONAL_NETWORK_ENABLED = (uint16_t) chip::DeviceLayer::DeviceEventType::kOperationalNetworkEnabled, + + // DNS-SD Initialized: Signals that DNS-SD has been initialized and is ready to operate. + MATTER_DNSSD_INITIALIZED = (uint16_t) chip::DeviceLayer::DeviceEventType::kDnssdInitialized, + + // DNS-SD Restart Needed: Signals that DNS-SD backend was restarted and services must be published again. + MATTER_DNSSD_RESTART_NEEDED = (uint16_t) chip::DeviceLayer::DeviceEventType::kDnssdRestartNeeded, + + // Bindings Changed Via Cluster: Signals that bindings were updated. + MATTER_BINDINGS_CHANGED_VIA_CLUSTER = (uint16_t) chip::DeviceLayer::DeviceEventType::kBindingsChangedViaCluster, + + // OTA State Changed: Signals that the state of the OTA engine changed. + MATTER_OTA_STATE_CHANGED = (uint16_t) chip::DeviceLayer::DeviceEventType::kOtaStateChanged, + + // Server Ready: Server initialization has completed. Signals that all server components have been initialized + // and the node is ready to establish connections with other nodes. This event can be used to trigger on-boot actions + // that require sending messages to other nodes. + MATTER_SERVER_READY = (uint16_t) chip::DeviceLayer::DeviceEventType::kServerReady, + + // BLE Deinitialized: Signals that BLE stack is deinitialized and memory reclaimed + MATTER_BLE_DEINITIALIZED = (uint16_t) chip::DeviceLayer::DeviceEventType::kBLEDeinitialized, + + // Starting ESP32 Platform Specific Events from 0x9000 + MATTER_ESP32_SPECIFIC_EVENT, // value is previous + 1 + + // Commissioning Session Started: Signals that Commissioning session has started + MATTER_COMMISSIONING_SESSION_STARTED = (uint16_t) chip::DeviceLayer::DeviceEventType::kCommissioningSessionStarted, + + // Commissioning Session Stopped: Signals that Commissioning session has stopped + MATTER_COMMISSIONING_SESSION_STOPPED = (uint16_t) chip::DeviceLayer::DeviceEventType::kCommissioningSessionStopped, + + // Commissioning Window Opened: Signals that Commissioning window is now opend + MATTER_COMMISSIONING_WINDOW_OPEN = (uint16_t) chip::DeviceLayer::DeviceEventType::kCommissioningWindowOpened, + + // Commissioning Window Closed: Signals that Commissioning window is now closed + MATTER_COMMISSIONING_WINDOW_CLOSED = (uint16_t) chip::DeviceLayer::DeviceEventType::kCommissioningWindowClosed, + + // Fabric Will Be Removed: Signals that a fabric is about to be deleted. This allows actions to be taken that need the + // fabric to still be around before we delete it + MATTER_FABRIC_WILL_BE_REMOVED = (uint16_t) chip::DeviceLayer::DeviceEventType::kFabricWillBeRemoved, + + // Fabric Has Been Removed: Signals that a fabric is effectivelly deleted + MATTER_FABRIC_REMOVED = (uint16_t) chip::DeviceLayer::DeviceEventType::kFabricRemoved, + + // Fabric Has Been Committed: Signals that a fabric in Fabric Table is persisted to storage, by CommitPendingFabricData + MATTER_FABRIC_COMMITTED = (uint16_t) chip::DeviceLayer::DeviceEventType::kFabricCommitted, + + // Fabric Has Been Updated: Signals that operational credentials are changed, which may not be persistent. + // Can be used to affect what is needed for UpdateNOC prior to commit + MATTER_FABRIC_UPDATED = (uint16_t) chip::DeviceLayer::DeviceEventType::kFabricUpdated, + + // ESP32 Matter Events: These are custom ESP32 Matter events as defined in CHIPDevicePlatformEvent.h. + MATTER_ESP32_PUBLIC_SPECIFIC_EVENT = (uint16_t) chip::DeviceLayer::DeviceEventType::kRange_PublicPlatformSpecific, // ESPSystemEvent + }; + + // Matter Event Callback type + using matterEventCB = std::function; + // Matter Event Callback + static matterEventCB _matterEventCB; + // set the Matter Event Callback + static void onEvent(matterEventCB cb) { + _matterEventCB = cb; + } + + static inline String getManualPairingCode() { // return the pairing code for manual pairing return String("34970112332"); From 4b3f58f580d0000c4a90ccacea762963cb3467ca Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Fri, 13 Jun 2025 13:11:34 -0300 Subject: [PATCH 2/7] feat(matter): use C++ nullptr instead of NULL C macro --- libraries/Matter/src/Matter.cpp | 10 +++++----- libraries/Matter/src/MatterEndPoint.h | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/libraries/Matter/src/Matter.cpp b/libraries/Matter/src/Matter.cpp index a684390c0b5..aec6ea66d72 100644 --- a/libraries/Matter/src/Matter.cpp +++ b/libraries/Matter/src/Matter.cpp @@ -28,8 +28,8 @@ constexpr auto k_timeout_seconds = 300; static bool _matter_has_started = false; static node::config_t node_config; -static node_t *deviceNode = NULL; -ArduinoMatter::matterEventCB ArduinoMatter::_matterEventCB = NULL; +static node_t *deviceNode = nullptr; +ArduinoMatter::matterEventCB ArduinoMatter::_matterEventCB = nullptr; // 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 @@ -43,7 +43,7 @@ static esp_err_t app_attribute_update_cb( switch (type) { case PRE_UPDATE: // Callback before updating the value in the database log_v("Attribute update callback: PRE_UPDATE"); - if (ep != NULL) { + if (ep != nullptr) { err = ep->attributeChangeCB(endpoint_id, cluster_id, attribute_id, val) ? ESP_OK : ESP_FAIL; } break; @@ -79,7 +79,7 @@ static esp_err_t app_identification_cb(identification::callback_type_t type, uin identifyIsActive = false; log_v("Identification callback: STOP"); } - if (ep != NULL) { + if (ep != nullptr) { err = ep->endpointIdentifyCB(endpoint_id, identifyIsActive) ? ESP_OK : ESP_FAIL; } @@ -124,7 +124,7 @@ static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) { default: break; } // Check if the user-defined callback is set - if (ArduinoMatter::_matterEventCB != NULL) { + if (ArduinoMatter::_matterEventCB != nullptr) { ArduinoMatter::_matterEventCB(static_cast(event->Type), event); } } diff --git a/libraries/Matter/src/MatterEndPoint.h b/libraries/Matter/src/MatterEndPoint.h index 5baa4747d18..95d3d3c08df 100644 --- a/libraries/Matter/src/MatterEndPoint.h +++ b/libraries/Matter/src/MatterEndPoint.h @@ -41,22 +41,22 @@ class MatterEndPoint { esp_matter::attribute_t *getAttribute(uint32_t cluster_id, uint32_t attribute_id) { if (endpoint_id == 0) { log_e("Endpoint ID is not set"); - return NULL; + return nullptr; } endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id); - if (endpoint == NULL) { + if (endpoint == nullptr) { log_e("Endpoint [%d] not found", endpoint_id); - return NULL; + return nullptr; } cluster_t *cluster = cluster::get(endpoint, cluster_id); - if (cluster == NULL) { + if (cluster == nullptr) { log_e("Cluster [%d] not found", cluster_id); - return NULL; + return nullptr; } esp_matter::attribute_t *attribute = attribute::get(cluster, attribute_id); - if (attribute == NULL) { + if (attribute == nullptr) { log_e("Attribute [%d] not found", attribute_id); - return NULL; + return nullptr; } return attribute; } @@ -64,7 +64,7 @@ class MatterEndPoint { // get the value of an attribute from its cluster id and attribute it bool getAttributeVal(uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *attrVal) { esp_matter::attribute_t *attribute = getAttribute(cluster_id, attribute_id); - if (attribute == NULL) { + if (attribute == nullptr) { return false; } if (attribute::get_val(attribute, attrVal) == ESP_OK) { @@ -78,7 +78,7 @@ class MatterEndPoint { // set the value of an attribute from its cluster id and attribute it bool setAttributeVal(uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *attrVal) { esp_matter::attribute_t *attribute = getAttribute(cluster_id, attribute_id); - if (attribute == NULL) { + if (attribute == nullptr) { return false; } if (attribute::set_val(attribute, attrVal) == ESP_OK) { @@ -117,6 +117,6 @@ class MatterEndPoint { protected: uint16_t endpoint_id = 0; - EndPointIdentifyCB _onEndPointIdentifyCB = NULL; + EndPointIdentifyCB _onEndPointIdentifyCB = nullptr; }; #endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ From 0b24dd10b7a9f65f11b88dcfd8f77b4dc4a1de66 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 18 Jun 2025 15:47:15 -0300 Subject: [PATCH 3/7] feat(matter): change to global event type --- .../examples/MatterEvents/MatterEvents.ino | 70 +++++++++---------- libraries/Matter/src/Matter.cpp | 2 +- libraries/Matter/src/Matter.h | 8 +-- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/libraries/Matter/examples/MatterEvents/MatterEvents.ino b/libraries/Matter/examples/MatterEvents/MatterEvents.ino index 0378b4e0939..3598e027fa9 100644 --- a/libraries/Matter/examples/MatterEvents/MatterEvents.ino +++ b/libraries/Matter/examples/MatterEvents/MatterEvents.ino @@ -25,17 +25,17 @@ const char *password = "your-password"; // Change this to your WiFi password MatterOnOffLight OnOffLight; // This function is called when a Matter event occurs -void onMatterEvent(ArduinoMatter::matterEvent_t eventType, const chip::DeviceLayer::ChipDeviceEvent *eventInfo) { +void onMatterEvent(matterEvent_t eventType, const chip::DeviceLayer::ChipDeviceEvent *eventInfo) { // Print the event type to Serial Serial.print("===> Got a Matter Event: "); switch (eventType) { - case ArduinoMatter::MATTER_WIFI_CONNECTIVITY_CHANGE: + case MATTER_WIFI_CONNECTIVITY_CHANGE: Serial.println("WiFi Connectivity Change"); break; - case ArduinoMatter::MATTER_THREAD_CONNECTIVITY_CHANGE: + case MATTER_THREAD_CONNECTIVITY_CHANGE: Serial.println("Thread Connectivity Change"); break; - case ArduinoMatter::MATTER_INTERNET_CONNECTIVITY_CHANGE: { + case MATTER_INTERNET_CONNECTIVITY_CHANGE: { bool newIPAddress = false; Serial.print("Internet Connectivity Change :: "); if (eventInfo->InternetConnectivityChange.IPv4 != chip::DeviceLayer::ConnectivityChange::kConnectivity_NoChange) { @@ -77,40 +77,40 @@ void onMatterEvent(ArduinoMatter::matterEvent_t eventType, const chip::DeviceLay } break; } - case ArduinoMatter::MATTER_SERVICE_CONNECTIVITY_CHANGE: + case MATTER_SERVICE_CONNECTIVITY_CHANGE: Serial.println("Service Connectivity Change"); break; - case ArduinoMatter::MATTER_SERVICE_PROVISIONING_CHANGE: + case MATTER_SERVICE_PROVISIONING_CHANGE: Serial.println("Service Provisioning Change"); break; - case ArduinoMatter::MATTER_TIME_SYNC_CHANGE: + case MATTER_TIME_SYNC_CHANGE: Serial.println("Time Sync Change"); break; - case ArduinoMatter::MATTER_CHIPOBLE_CONNECTION_ESTABLISHED: + case MATTER_CHIPOBLE_CONNECTION_ESTABLISHED: Serial.println("CHIPoBLE Connection Established"); break; - case ArduinoMatter::MATTER_CHIPOBLE_CONNECTION_CLOSED: + case MATTER_CHIPOBLE_CONNECTION_CLOSED: Serial.println("CHIPoBLE Connection Closed"); break; - case ArduinoMatter::MATTER_CLOSE_ALL_BLE_CONNECTIONS: + case MATTER_CLOSE_ALL_BLE_CONNECTIONS: Serial.println("Close All BLE Connections"); break; - case ArduinoMatter::MATTER_WIFI_DEVICE_AVAILABLE: + case MATTER_WIFI_DEVICE_AVAILABLE: Serial.println("WiFi Device Available"); break; - case ArduinoMatter::MATTER_OPERATIONAL_NETWORK_STARTED: + case MATTER_OPERATIONAL_NETWORK_STARTED: Serial.println("Operational Network Started"); break; - case ArduinoMatter::MATTER_THREAD_STATE_CHANGE: + case MATTER_THREAD_STATE_CHANGE: Serial.println("Thread State Change"); break; - case ArduinoMatter::MATTER_THREAD_INTERFACE_STATE_CHANGE: + case MATTER_THREAD_INTERFACE_STATE_CHANGE: Serial.println("Thread Interface State Change"); break; - case ArduinoMatter::MATTER_CHIPOBLE_ADVERTISING_CHANGE: + case MATTER_CHIPOBLE_ADVERTISING_CHANGE: Serial.println("CHIPoBLE Advertising Change"); break; - case ArduinoMatter::MATTER_INTERFACE_IP_ADDRESS_CHANGED: + case MATTER_INTERFACE_IP_ADDRESS_CHANGED: switch (eventInfo->InterfaceIpAddressChanged.Type) { case chip::DeviceLayer::InterfaceIpChangeType::kIpV4_Assigned: Serial.println("IPv4 Address Assigned"); @@ -126,61 +126,61 @@ void onMatterEvent(ArduinoMatter::matterEvent_t eventType, const chip::DeviceLay break; } break; - case ArduinoMatter::MATTER_COMMISSIONING_COMPLETE: + case MATTER_COMMISSIONING_COMPLETE: Serial.println("Commissioning Complete"); break; - case ArduinoMatter::MATTER_FAIL_SAFE_TIMER_EXPIRED: + case MATTER_FAIL_SAFE_TIMER_EXPIRED: Serial.println("Fail Safe Timer Expired"); break; - case ArduinoMatter::MATTER_OPERATIONAL_NETWORK_ENABLED: + case MATTER_OPERATIONAL_NETWORK_ENABLED: Serial.println("Operational Network Enabled"); break; - case ArduinoMatter::MATTER_DNSSD_INITIALIZED: + case MATTER_DNSSD_INITIALIZED: Serial.println("DNS-SD Initialized"); break; - case ArduinoMatter::MATTER_DNSSD_RESTART_NEEDED: + case MATTER_DNSSD_RESTART_NEEDED: Serial.println("DNS-SD Restart Needed"); break; - case ArduinoMatter::MATTER_BINDINGS_CHANGED_VIA_CLUSTER: + case MATTER_BINDINGS_CHANGED_VIA_CLUSTER: Serial.println("Bindings Changed Via Cluster"); break; - case ArduinoMatter::MATTER_OTA_STATE_CHANGED: + case MATTER_OTA_STATE_CHANGED: Serial.println("OTA State Changed"); break; - case ArduinoMatter::MATTER_SERVER_READY: + case MATTER_SERVER_READY: Serial.println("Server Ready"); break; - case ArduinoMatter::MATTER_BLE_DEINITIALIZED: + case MATTER_BLE_DEINITIALIZED: Serial.println("BLE Deinitialized"); break; - case ArduinoMatter::MATTER_COMMISSIONING_SESSION_STARTED: + case MATTER_COMMISSIONING_SESSION_STARTED: Serial.println("Commissioning Session Started"); break; - case ArduinoMatter::MATTER_COMMISSIONING_SESSION_STOPPED: + case MATTER_COMMISSIONING_SESSION_STOPPED: Serial.println("Commissioning Session Stopped"); break; - case ArduinoMatter::MATTER_COMMISSIONING_WINDOW_OPEN: + case MATTER_COMMISSIONING_WINDOW_OPEN: Serial.println("Commissioning Window Opened"); break; - case ArduinoMatter::MATTER_COMMISSIONING_WINDOW_CLOSED: + case MATTER_COMMISSIONING_WINDOW_CLOSED: Serial.println("Commissioning Window Closed"); break; - case ArduinoMatter::MATTER_FABRIC_WILL_BE_REMOVED: + case MATTER_FABRIC_WILL_BE_REMOVED: Serial.println("Fabric Will Be Removed"); break; - case ArduinoMatter::MATTER_FABRIC_REMOVED: + case MATTER_FABRIC_REMOVED: Serial.println("Fabric Removed"); break; - case ArduinoMatter::MATTER_FABRIC_COMMITTED: + case MATTER_FABRIC_COMMITTED: Serial.println("Fabric Committed"); break; - case ArduinoMatter::MATTER_FABRIC_UPDATED: + case MATTER_FABRIC_UPDATED: Serial.println("Fabric Updated"); break; - case ArduinoMatter::MATTER_ESP32_SPECIFIC_EVENT: + case MATTER_ESP32_SPECIFIC_EVENT: Serial.println("Sending ESP32 Platform Specific Events"); break; - case ArduinoMatter::MATTER_ESP32_PUBLIC_SPECIFIC_EVENT: + case MATTER_ESP32_PUBLIC_SPECIFIC_EVENT: Serial.println("Next Event Has Populated EventInfo"); break; default: diff --git a/libraries/Matter/src/Matter.cpp b/libraries/Matter/src/Matter.cpp index aec6ea66d72..b16edfd85c1 100644 --- a/libraries/Matter/src/Matter.cpp +++ b/libraries/Matter/src/Matter.cpp @@ -125,7 +125,7 @@ static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) { } // Check if the user-defined callback is set if (ArduinoMatter::_matterEventCB != nullptr) { - ArduinoMatter::_matterEventCB(static_cast(event->Type), event); + ArduinoMatter::_matterEventCB(static_cast(event->Type), event); } } diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h index ed2a3ba23a7..3b075f7e72b 100644 --- a/libraries/Matter/src/Matter.h +++ b/libraries/Matter/src/Matter.h @@ -34,10 +34,6 @@ #include #include -using namespace esp_matter; - -class ArduinoMatter { -public: // Matter Event types used when there is a user callback for Matter Events enum matterEvent_t { // Starting from 0x8000, these events are public and can be used by applications. @@ -155,6 +151,10 @@ class ArduinoMatter { MATTER_ESP32_PUBLIC_SPECIFIC_EVENT = (uint16_t) chip::DeviceLayer::DeviceEventType::kRange_PublicPlatformSpecific, // ESPSystemEvent }; +using namespace esp_matter; + +class ArduinoMatter { +public: // Matter Event Callback type using matterEventCB = std::function; // Matter Event Callback From 60e9da025a9eaac58423355bd3c333cf0426258a Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Wed, 18 Jun 2025 15:48:51 -0300 Subject: [PATCH 4/7] fix(matter): commentary correction Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- libraries/Matter/src/Matter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h index 3b075f7e72b..5f5fe59c7aa 100644 --- a/libraries/Matter/src/Matter.h +++ b/libraries/Matter/src/Matter.h @@ -127,7 +127,7 @@ // Commissioning Session Stopped: Signals that Commissioning session has stopped MATTER_COMMISSIONING_SESSION_STOPPED = (uint16_t) chip::DeviceLayer::DeviceEventType::kCommissioningSessionStopped, - // Commissioning Window Opened: Signals that Commissioning window is now opend + // Commissioning Window Opened: Signals that Commissioning window is now opened MATTER_COMMISSIONING_WINDOW_OPEN = (uint16_t) chip::DeviceLayer::DeviceEventType::kCommissioningWindowOpened, // Commissioning Window Closed: Signals that Commissioning window is now closed From ca23972e80ef320b3cacf291778cc3e8c7dc4f02 Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Wed, 18 Jun 2025 15:49:33 -0300 Subject: [PATCH 5/7] fix(matter): fix commentarie Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- libraries/Matter/examples/MatterEvents/MatterEvents.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/Matter/examples/MatterEvents/MatterEvents.ino b/libraries/Matter/examples/MatterEvents/MatterEvents.ino index 3598e027fa9..b0459813fc0 100644 --- a/libraries/Matter/examples/MatterEvents/MatterEvents.ino +++ b/libraries/Matter/examples/MatterEvents/MatterEvents.ino @@ -242,5 +242,5 @@ void loop() { Serial.println("====> Decommissioning in 60 seconds. <===="); delay(60000); Matter.decommission(); - Serial.println("Matter Node is decommissioned. Commsssioning widget shall start over."); + Serial.println("Matter Node is decommissioned. Commissioning widget shall start over."); } From d8edf0a3819969ed126330bda8d1eee32e480c00 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 18 Jun 2025 16:07:58 -0300 Subject: [PATCH 6/7] feat(matter): add keywords for matter events --- libraries/Matter/keywords.txt | 39 +++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/libraries/Matter/keywords.txt b/libraries/Matter/keywords.txt index a63d9a65acb..68aaebb1d4d 100644 --- a/libraries/Matter/keywords.txt +++ b/libraries/Matter/keywords.txt @@ -36,6 +36,8 @@ EndPointSpeedCB KEYWORD1 EndPointOnOffCB KEYWORD1 EndPointBrightnessCB KEYWORD1 EndPointRGBColorCB KEYWORD1 +matterEvent_t KEYWORD1 +matterEventCB KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -108,6 +110,7 @@ onChangeMode KEYWORD2 onChangeLocalTemperature KEYWORD2 onChangeCoolingSetpoint KEYWORD2 onChangeHeatingSetpoint KEYWORD2 +onEvent KEYWORD2 ####################################### # Constants (LITERAL1) @@ -144,5 +147,37 @@ THERMOSTAT_MODE_OFF LITERAL1 THERMOSTAT_MODE_AUTO LITERAL1 THERMOSTAT_MODE_COOL LITERAL1 THERMOSTAT_MODE_HEAT LITERAL1 -THERMOSTAT_AUTO_MODE_DISABLED LITERAL1 -THERMOSTAT_AUTO_MODE_ENABLED LITERAL1 +MATTER_WIFI_CONNECTIVITY_CHANGE LITERAL1 +MATTER_THREAD_CONNECTIVITY_CHANGE LITERAL1 +MATTER_INTERNET_CONNECTIVITY_CHANGE LITERAL1 +MATTER_SERVICE_CONNECTIVITY_CHANGE LITERAL1 +MATTER_SERVICE_PROVISIONING_CHANGE LITERAL1 +MATTER_TIME_SYNC_CHANGE LITERAL1 +MATTER_CHIPOBLE_CONNECTION_ESTABLISHED LITERAL1 +MATTER_CHIPOBLE_CONNECTION_CLOSED LITERAL1 +MATTER_CLOSE_ALL_BLE_CONNECTIONS LITERAL1 +MATTER_WIFI_DEVICE_AVAILABLE LITERAL1 +MATTER_OPERATIONAL_NETWORK_STARTED LITERAL1 +MATTER_THREAD_STATE_CHANGE LITERAL1 +MATTER_THREAD_INTERFACE_STATE_CHANGE LITERAL1 +MATTER_CHIPOBLE_ADVERTISING_CHANGE LITERAL1 +MATTER_INTERFACE_IP_ADDRESS_CHANGED LITERAL1 +MATTER_COMMISSIONING_COMPLETE LITERAL1 +MATTER_FAIL_SAFE_TIMER_EXPIRED LITERAL1 +MATTER_OPERATIONAL_NETWORK_ENABLED LITERAL1 +MATTER_DNSSD_INITIALIZED LITERAL1 +MATTER_DNSSD_RESTART_NEEDED LITERAL1 +MATTER_BINDINGS_CHANGED_VIA_CLUSTER LITERAL1 +MATTER_OTA_STATE_CHANGED LITERAL1 +MATTER_SERVER_READY LITERAL1 +MATTER_BLE_DEINITIALIZED LITERAL1 +MATTER_ESP32_SPECIFIC_EVENT LITERAL1 +MATTER_COMMISSIONING_SESSION_STARTED LITERAL1 +MATTER_COMMISSIONING_SESSION_STOPPED LITERAL1 +MATTER_COMMISSIONING_WINDOW_OPEN LITERAL1 +MATTER_COMMISSIONING_WINDOW_CLOSED LITERAL1 +MATTER_FABRIC_WILL_BE_REMOVED LITERAL1 +MATTER_FABRIC_REMOVED LITERAL1 +MATTER_FABRIC_COMMITTED LITERAL1 +MATTER_FABRIC_UPDATED LITERAL1 +MATTER_ESP32_PUBLIC_SPECIFIC_EVENT LITERAL1 From 64cd198a2eb8b46efc7bdae3b279d26daaf5b228 Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Wed, 18 Jun 2025 17:15:28 -0300 Subject: [PATCH 7/7] fix(matter): typo commentary Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- libraries/Matter/src/Matter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h index 5f5fe59c7aa..dd4bdf5756c 100644 --- a/libraries/Matter/src/Matter.h +++ b/libraries/Matter/src/Matter.h @@ -137,7 +137,7 @@ // fabric to still be around before we delete it MATTER_FABRIC_WILL_BE_REMOVED = (uint16_t) chip::DeviceLayer::DeviceEventType::kFabricWillBeRemoved, - // Fabric Has Been Removed: Signals that a fabric is effectivelly deleted + // Fabric Has Been Removed: Signals that a fabric is effectively deleted MATTER_FABRIC_REMOVED = (uint16_t) chip::DeviceLayer::DeviceEventType::kFabricRemoved, // Fabric Has Been Committed: Signals that a fabric in Fabric Table is persisted to storage, by CommitPendingFabricData