Merge branch 'master' into release/v3.3.x

This commit is contained in:
Me No Dev 2025-06-21 15:46:46 +03:00 committed by GitHub
commit bf55924b67
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 484 additions and 67 deletions

View file

@ -32,10 +32,11 @@
#include "driver/gpio.h"
#include "hal/gpio_hal.h"
#include "esp_rom_gpio.h"
#include "esp_private/gpio.h"
#include "driver/rtc_io.h"
#include "driver/lp_io.h"
#include "soc/uart_periph.h"
#include "soc/uart_pins.h"
#include "esp_private/uart_share_hw_ctrl.h"
static int s_uart_debug_nr = 0; // UART number for debug output
@ -1399,39 +1400,9 @@ unsigned long uartDetectBaudrate(uart_t *uart) {
}
/*
These functions are for testing purpose only and can be used in Arduino Sketches
Those are used in the UART examples
*/
/*
This is intended to make an internal loopback connection using IOMUX
The function uart_internal_loopback() shall be used right after Arduino Serial.begin(...)
This code "replaces" the physical wiring for connecting TX <--> RX in a loopback
*/
// gets the right TX or RX SIGNAL, based on the UART number from gpio_sig_map.h
#ifdef CONFIG_IDF_TARGET_ESP32P4
#define UART_TX_SIGNAL(uartNumber) \
(uartNumber == UART_NUM_0 \
? UART0_TXD_PAD_OUT_IDX \
: (uartNumber == UART_NUM_1 \
? UART1_TXD_PAD_OUT_IDX \
: (uartNumber == UART_NUM_2 ? UART2_TXD_PAD_OUT_IDX : (uartNumber == UART_NUM_3 ? UART3_TXD_PAD_OUT_IDX : UART4_TXD_PAD_OUT_IDX))))
#define UART_RX_SIGNAL(uartNumber) \
(uartNumber == UART_NUM_0 \
? UART0_RXD_PAD_IN_IDX \
: (uartNumber == UART_NUM_1 \
? UART1_RXD_PAD_IN_IDX \
: (uartNumber == UART_NUM_2 ? UART2_RXD_PAD_IN_IDX : (uartNumber == UART_NUM_3 ? UART3_RXD_PAD_IN_IDX : UART4_RXD_PAD_IN_IDX))))
#else
#if SOC_UART_HP_NUM > 2
#define UART_TX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0TXD_OUT_IDX : (uartNumber == UART_NUM_1 ? U1TXD_OUT_IDX : U2TXD_OUT_IDX))
#define UART_RX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0RXD_IN_IDX : (uartNumber == UART_NUM_1 ? U1RXD_IN_IDX : U2RXD_IN_IDX))
#else
#define UART_TX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0TXD_OUT_IDX : U1TXD_OUT_IDX)
#define UART_RX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0RXD_IN_IDX : U1RXD_IN_IDX)
#endif
#endif // ifdef CONFIG_IDF_TARGET_ESP32P4
* These functions are for testing purposes only and can be used in Arduino Sketches.
* They are utilized in the UART examples and CI.
*/
/*
This function internally binds defined UARTs TX signal with defined RX pin of any UART (same or different).
@ -1443,7 +1414,12 @@ void uart_internal_loopback(uint8_t uartNum, int8_t rxPin) {
log_e("UART%d is not supported for loopback or RX pin %d is invalid.", uartNum, rxPin);
return;
}
esp_rom_gpio_connect_out_signal(rxPin, UART_TX_SIGNAL(uartNum), false, false);
// forces rxPin to use GPIO Matrix and setup the pin to receive UART TX Signal - IDF 5.4.1 Change with uart_release_pin()
gpio_func_sel((gpio_num_t)rxPin, PIN_FUNC_GPIO);
gpio_pullup_en((gpio_num_t)rxPin);
gpio_input_enable((gpio_num_t)rxPin);
esp_rom_gpio_connect_in_signal(rxPin, uart_periph_signal[uartNum].pins[SOC_UART_RX_PIN_IDX].signal, false);
esp_rom_gpio_connect_out_signal(rxPin, uart_periph_signal[uartNum].pins[SOC_UART_TX_PIN_IDX].signal, false, false);
}
/*

View file

@ -111,16 +111,22 @@ void DNSServer::_handleUDP(AsyncUDPPacket &pkt) {
// will reply with IP only to "*" or if domain matches without www. subdomain
if (dnsHeader.OPCode == DNS_OPCODE_QUERY && requestIncludesOnlyOneQuestion(dnsHeader)
&& (_domainName.isEmpty() || getDomainNameWithoutWwwPrefix(static_cast<const unsigned char *>(dnsQuestion.QName), dnsQuestion.QNameLength) == _domainName)) {
replyWithIP(pkt, dnsHeader, dnsQuestion);
// Qtype = A (1) or ANY (255): send an A record otherwise an empty response
if (ntohs(dnsQuestion.QType) == 1 || ntohs(dnsQuestion.QType) == 255) {
replyWithIP(pkt, dnsHeader, dnsQuestion);
} else {
replyWithNoAnsw(pkt, dnsHeader, dnsQuestion);
}
return;
}
// otherwise reply with custom code
replyWithCustomCode(pkt, dnsHeader);
}
bool DNSServer::requestIncludesOnlyOneQuestion(DNSHeader &dnsHeader) {
return ntohs(dnsHeader.QDCount) == 1 && dnsHeader.ANCount == 0 && dnsHeader.NSCount == 0 && dnsHeader.ARCount == 0;
dnsHeader.ARCount = 0; // We assume that if ARCount !=0 there is a EDNS OPT packet, just ignore
return ntohs(dnsHeader.QDCount) == 1 && dnsHeader.ANCount == 0 && dnsHeader.NSCount == 0;
}
String DNSServer::getDomainNameWithoutWwwPrefix(const unsigned char *start, size_t len) {
@ -139,7 +145,6 @@ String DNSServer::getDomainNameWithoutWwwPrefix(const unsigned char *start, size
void DNSServer::replyWithIP(AsyncUDPPacket &req, DNSHeader &dnsHeader, DNSQuestion &dnsQuestion) {
AsyncUDPMessage rpl;
// Change the type of message to a response and set the number of answers equal to
// the number of questions in the header
dnsHeader.QR = DNS_QR_RESPONSE;
@ -187,3 +192,76 @@ void DNSServer::replyWithCustomCode(AsyncUDPPacket &req, DNSHeader &dnsHeader) {
rpl.write(reinterpret_cast<const uint8_t *>(&dnsHeader), sizeof(DNSHeader));
_udp.sendTo(rpl, req.remoteIP(), req.remotePort());
}
void DNSServer::replyWithNoAnsw(AsyncUDPPacket &req, DNSHeader &dnsHeader, DNSQuestion &dnsQuestion) {
dnsHeader.QR = DNS_QR_RESPONSE;
dnsHeader.ANCount = 0;
dnsHeader.NSCount = htons(1);
AsyncUDPMessage rpl;
rpl.write(reinterpret_cast<const uint8_t *>(&dnsHeader), sizeof(DNSHeader));
// Write the question
rpl.write(dnsQuestion.QName, dnsQuestion.QNameLength);
rpl.write((uint8_t *)&dnsQuestion.QType, 2);
rpl.write((uint8_t *)&dnsQuestion.QClass, 2);
// An empty answer contains an authority section with a SOA,
// We take the name of the query as the root of the zone for which the SOA is generated
// and use a value of DNS_MINIMAL_TTL seconds in order to minimize negative caching
// Write the authority section:
// The SOA RR's ownername is set equal to the query name, and we use made up names for
// the MNAME and RNAME - it doesn't really matter from a protocol perspective - as for
// a no such QTYPE answer only the timing fields are used.
// a protocol perspective - it
// Use DNS name compression : instead of repeating the name in this RNAME occurrence,
// set the two MSB of the byte corresponding normally to the length to 1. The following
// 14 bits must be used to specify the offset of the domain name in the message
// (<255 here so the first byte has the 6 LSB at 0)
rpl.write((uint8_t)0xC0);
rpl.write((uint8_t)DNS_OFFSET_DOMAIN_NAME);
// DNS type A : host address, DNS class IN for INternet, returning an IPv4 address
uint16_t answerType = htons(DNS_TYPE_SOA), answerClass = htons(DNS_CLASS_IN);
uint32_t Serial = htonl(DNS_SOA_SERIAL); // Date type serial based on the date this piece of code was written
uint32_t Refresh = htonl(DNS_SOA_REFRESH); // These timers don't matter, we don't serve zone transfers
uint32_t Retry = htonl(DNS_SOA_RETRY);
uint32_t Expire = htonl(DNS_SOA_EXPIRE);
uint32_t MinTTL = htonl(DNS_MINIMAL_TTL); // See RFC2308 section 5
char MLabel[] = DNS_SOA_MNAME_LABEL;
char RLabel[] = DNS_SOA_RNAME_LABEL;
char PostFixLabel[] = DNS_SOA_POSTFIX_LABEL;
// 4 accounts for len fields and for both rname
// and lname and their postfix labels and there are 5 32 bit fields
uint16_t RdataLength = htons((uint16_t)(strlen(MLabel) + strlen(RLabel) + 2 * strlen(PostFixLabel) + 4 + 5 * sizeof(Serial)));
rpl.write((unsigned char *)&answerType, 2);
rpl.write((unsigned char *)&answerClass, 2);
rpl.write((unsigned char *)&MinTTL, 4); // DNS Time To Live
rpl.write((unsigned char *)&RdataLength, 2);
rpl.write((uint8_t)strlen(MLabel));
rpl.write((unsigned char *)&MLabel, strlen(MLabel));
rpl.write((unsigned char *)&PostFixLabel, strlen(PostFixLabel));
rpl.write((uint8_t)0);
// rpl.write((uint8_t)0xC0);
// rpl.write((uint8_t)DNS_OFFSET_DOMAIN_NAME);
rpl.write((uint8_t)strlen(RLabel));
rpl.write((unsigned char *)&RLabel, strlen(RLabel));
rpl.write((unsigned char *)&PostFixLabel, strlen(PostFixLabel));
rpl.write((uint8_t)0);
rpl.write((unsigned char *)&Serial, 4);
rpl.write((unsigned char *)&Refresh, 4);
rpl.write((unsigned char *)&Retry, 4);
rpl.write((unsigned char *)&Expire, 4);
rpl.write((unsigned char *)&MinTTL, 4);
_udp.sendTo(rpl, req.remoteIP(), req.remotePort());
}

View file

@ -9,6 +9,26 @@
#define DNS_OFFSET_DOMAIN_NAME DNS_HEADER_SIZE // Offset in bytes to reach the domain name labels in the DNS message
#define DNS_DEFAULT_PORT 53
#define DNS_SOA_MNAME_LABEL "ns"
#define DNS_SOA_RNAME_LABEL "esp32"
// The POSTFIX_LABEL will be concatenated to the RName and MName Label label
// do not use a multilabel name here. "local" is a good choice as it is reserved for
// local use by IANA
// The postfix label is defined as an array of characters that follows the
// definition of RFC1035 3.1
// for instance, a postfix of example.com would be defined as:
// #define DNS_SOA_POSTFIX_LABEL {'\7', 'e', 'x', 'a', 'm', 'p', 'l', 'e', '\3', 'c', 'o', 'm', '\0'}
#define DNS_SOA_POSTFIX_LABEL \
{ '\5', 'l', 'o', 'c', 'a', 'l', '\0' }
// From the following values only the MINIMAL_TTL has relevance
// in the context of client-server protocol interactions.
// The other values are arbitrary chosen as they are only relevant for
// in a zone-transfer scenario.
#define DNS_SOA_SERIAL 2025052900 // Arbitrary serial (format: YYYYMMDDnn)
#define DNS_SOA_REFRESH 100000 // Arbitrary (seconds)
#define DNS_SOA_RETRY 10000 // Arbitrary (seconds)
#define DNS_SOA_EXPIRE 1000000 // Arbitrary (seconds)
#define DNS_MINIMAL_TTL 5 // Time to live for negative answers RFC2308
enum class DNSReplyCode : uint16_t {
NoError = 0,
FormError = 1,
@ -179,5 +199,7 @@ private:
inline bool requestIncludesOnlyOneQuestion(DNSHeader &dnsHeader);
void replyWithIP(AsyncUDPPacket &req, DNSHeader &dnsHeader, DNSQuestion &dnsQuestion);
inline void replyWithCustomCode(AsyncUDPPacket &req, DNSHeader &dnsHeader);
inline void replyWithNoAnsw(AsyncUDPPacket &req, DNSHeader &dnsHeader, DNSQuestion &dnsQuestion);
void _handleUDP(AsyncUDPPacket &pkt);
};

View file

@ -0,0 +1,168 @@
// 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 <Matter.h>
#include <WiFi.h>
// 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(matterEvent_t eventType, const chip::DeviceLayer::ChipDeviceEvent *eventInfo) {
// Print the event type to Serial
Serial.print("===> Got a Matter Event: ");
switch (eventType) {
case MATTER_WIFI_CONNECTIVITY_CHANGE: Serial.println("WiFi Connectivity Change"); break;
case MATTER_THREAD_CONNECTIVITY_CHANGE: Serial.println("Thread Connectivity Change"); break;
case 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 MATTER_SERVICE_CONNECTIVITY_CHANGE: Serial.println("Service Connectivity Change"); break;
case MATTER_SERVICE_PROVISIONING_CHANGE: Serial.println("Service Provisioning Change"); break;
case MATTER_TIME_SYNC_CHANGE: Serial.println("Time Sync Change"); break;
case MATTER_CHIPOBLE_CONNECTION_ESTABLISHED: Serial.println("CHIPoBLE Connection Established"); break;
case MATTER_CHIPOBLE_CONNECTION_CLOSED: Serial.println("CHIPoBLE Connection Closed"); break;
case MATTER_CLOSE_ALL_BLE_CONNECTIONS: Serial.println("Close All BLE Connections"); break;
case MATTER_WIFI_DEVICE_AVAILABLE: Serial.println("WiFi Device Available"); break;
case MATTER_OPERATIONAL_NETWORK_STARTED: Serial.println("Operational Network Started"); break;
case MATTER_THREAD_STATE_CHANGE: Serial.println("Thread State Change"); break;
case MATTER_THREAD_INTERFACE_STATE_CHANGE: Serial.println("Thread Interface State Change"); break;
case MATTER_CHIPOBLE_ADVERTISING_CHANGE: Serial.println("CHIPoBLE Advertising Change"); break;
case 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 MATTER_COMMISSIONING_COMPLETE: Serial.println("Commissioning Complete"); break;
case MATTER_FAIL_SAFE_TIMER_EXPIRED: Serial.println("Fail Safe Timer Expired"); break;
case MATTER_OPERATIONAL_NETWORK_ENABLED: Serial.println("Operational Network Enabled"); break;
case MATTER_DNSSD_INITIALIZED: Serial.println("DNS-SD Initialized"); break;
case MATTER_DNSSD_RESTART_NEEDED: Serial.println("DNS-SD Restart Needed"); break;
case MATTER_BINDINGS_CHANGED_VIA_CLUSTER: Serial.println("Bindings Changed Via Cluster"); break;
case MATTER_OTA_STATE_CHANGED: Serial.println("OTA State Changed"); break;
case MATTER_SERVER_READY: Serial.println("Server Ready"); break;
case MATTER_BLE_DEINITIALIZED: Serial.println("BLE Deinitialized"); break;
case MATTER_COMMISSIONING_SESSION_STARTED: Serial.println("Commissioning Session Started"); break;
case MATTER_COMMISSIONING_SESSION_STOPPED: Serial.println("Commissioning Session Stopped"); break;
case MATTER_COMMISSIONING_WINDOW_OPEN: Serial.println("Commissioning Window Opened"); break;
case MATTER_COMMISSIONING_WINDOW_CLOSED: Serial.println("Commissioning Window Closed"); break;
case MATTER_FABRIC_WILL_BE_REMOVED: Serial.println("Fabric Will Be Removed"); break;
case MATTER_FABRIC_REMOVED: Serial.println("Fabric Removed"); break;
case MATTER_FABRIC_COMMITTED: Serial.println("Fabric Committed"); break;
case MATTER_FABRIC_UPDATED: Serial.println("Fabric Updated"); break;
case MATTER_ESP32_SPECIFIC_EVENT: Serial.println("Sending ESP32 Platform Specific Events"); break;
case 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. Commissioning widget shall start over.");
}

View file

@ -0,0 +1,7 @@
{
"fqbn_append": "PartitionScheme=huge_app",
"requires": [
"CONFIG_SOC_WIFI_SUPPORTED=y",
"CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y"
]
}

View file

@ -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

View file

@ -28,7 +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;
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
@ -42,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;
@ -78,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;
}
@ -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 != nullptr) {
ArduinoMatter::_matterEventCB(static_cast<matterEvent_t>(event->Type), event);
}
}
void ArduinoMatter::_init() {

View file

@ -34,10 +34,136 @@
#include <MatterEndpoints/MatterOnOffPlugin.h>
#include <MatterEndpoints/MatterThermostat.h>
// 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 opened
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 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
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
};
using namespace esp_matter;
class ArduinoMatter {
public:
// Matter Event Callback type
using matterEventCB = std::function<void(matterEvent_t, const chip::DeviceLayer::ChipDeviceEvent *)>;
// 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");

View file

@ -41,22 +41,22 @@ public:
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 @@ public:
// 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 @@ public:
// 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 @@ public:
protected:
uint16_t endpoint_id = 0;
EndPointIdentifyCB _onEndPointIdentifyCB = NULL;
EndPointIdentifyCB _onEndPointIdentifyCB = nullptr;
};
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */