feat(matter): initial commit with arduino matter lib (#10467)
* feat(matter): initial commit with arduino matter lib * feat(matter): add matter library to cmakelists.txt * fix(matter): add correct guard for ci * fix(matter): using correct ci requirements in ci.json * fix(matter): using correct ci requirements in header files * fix(matter): using correct ci requirements header and examples * fix(typo): typo and commentaries * fix(typo): typo and commentaries * fix(typo): typo and commentaries * fix(commentary): longer explanation * feat(matter): api simplification with begin * feat(matter): testing flashmode=qio in CI * feat(matter): testing flashmode=qio in CI * fix(matter): changes CI FQBN * fix(matte): include all fqbn in ci.json using qio * fix(matter): revert ci and guard changes * fix(matter): typo and commentaties * feat(matter): adds a light toggle switch button * feat(matter): improved the button control * feat(matter): using switch instead of if() for attibute change * fix(matter): switch/case scope * fix(matter): problems found after pressing reset * feat(matter): improve example using preferences * fix(pre-commit): Fix and apply pre-commit hooks --------- Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
This commit is contained in:
parent
f668557b54
commit
c40444ab33
15 changed files with 735 additions and 0 deletions
|
|
@ -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: |
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ set(ARDUINO_ALL_LIBRARIES
|
|||
HTTPUpdate
|
||||
Insights
|
||||
LittleFS
|
||||
Matter
|
||||
NetBIOS
|
||||
Network
|
||||
OpenThread
|
||||
|
|
@ -165,6 +166,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)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// On/Off Light Endpoint
|
||||
#include <MatterOnOffLight.h>
|
||||
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.");
|
||||
}
|
||||
7
libraries/Matter/examples/MatterCommissionTest/ci.json
Normal file
7
libraries/Matter/examples/MatterCommissionTest/ci.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=huge_app",
|
||||
"requires": [
|
||||
"CONFIG_SOC_WIFI_SUPPORTED=y",
|
||||
"CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// There will be 3 On/Off Light Endpoints in the same Node
|
||||
#include <MatterOnOffLight.h>
|
||||
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);
|
||||
}
|
||||
7
libraries/Matter/examples/MatterComposedLights/ci.json
Normal file
7
libraries/Matter/examples/MatterComposedLights/ci.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=huge_app",
|
||||
"requires": [
|
||||
"CONFIG_SOC_WIFI_SUPPORTED=y",
|
||||
"CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y"
|
||||
]
|
||||
}
|
||||
138
libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino
Normal file
138
libraries/Matter/examples/MatterOnOffLight/MatterOnOffLight.ino
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#include <WiFi.h>
|
||||
#include <Preferences.h>
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// On/Off Light Endpoint
|
||||
#include <MatterOnOffLight.h>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
7
libraries/Matter/examples/MatterOnOffLight/ci.json
Normal file
7
libraries/Matter/examples/MatterOnOffLight/ci.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=huge_app",
|
||||
"requires": [
|
||||
"CONFIG_SOC_WIFI_SUPPORTED=y",
|
||||
"CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y"
|
||||
]
|
||||
}
|
||||
35
libraries/Matter/keywords.txt
Normal file
35
libraries/Matter/keywords.txt
Normal file
|
|
@ -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)
|
||||
#######################################
|
||||
9
libraries/Matter/library.properties
Normal file
9
libraries/Matter/library.properties
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
name=Matter
|
||||
version=3.1.0
|
||||
author=Rodrigo Garcia | GitHub @SuGlider
|
||||
maintainer=Rodrigo Garcia <Rodrigo.Garcia@espressif.com>
|
||||
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
|
||||
163
libraries/Matter/src/Matter.cpp
Normal file
163
libraries/Matter/src/Matter.cpp
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
#include <sdkconfig.h>
|
||||
#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
|
||||
|
||||
#include <Matter.h>
|
||||
#include <app/server/Server.h>
|
||||
#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 */
|
||||
40
libraries/Matter/src/Matter.h
Normal file
40
libraries/Matter/src/Matter.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
#include <sdkconfig.h>
|
||||
#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <esp_matter.h>
|
||||
|
||||
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 */
|
||||
23
libraries/Matter/src/MatterEndPoint.h
Normal file
23
libraries/Matter/src/MatterEndPoint.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
#include <sdkconfig.h>
|
||||
#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
|
||||
|
||||
#include <Matter.h>
|
||||
#include <functional>
|
||||
|
||||
// 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 */
|
||||
107
libraries/Matter/src/MatterOnOffLight.cpp
Normal file
107
libraries/Matter/src/MatterOnOffLight.cpp
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
#include <sdkconfig.h>
|
||||
#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
|
||||
|
||||
#include <Matter.h>
|
||||
#include <app/server/Server.h>
|
||||
#include <MatterOnOffLight.h>
|
||||
|
||||
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 */
|
||||
34
libraries/Matter/src/MatterOnOffLight.h
Normal file
34
libraries/Matter/src/MatterOnOffLight.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
#include <sdkconfig.h>
|
||||
#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
|
||||
|
||||
#include <Matter.h>
|
||||
#include <MatterEndPoint.h>
|
||||
|
||||
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<bool(bool)>;
|
||||
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 */
|
||||
Loading…
Reference in a new issue