Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(matter) adds Identification callback to all matter endpoints #10734

Merged
merged 11 commits into from
Dec 16, 2024
128 changes: 128 additions & 0 deletions libraries/Matter/examples/MatterOnIdentify/MatterOnIdentify.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*
* This example is the smallest code that will create a Matter Device which can be
* commissioned and controlled from a Matter Environment APP.
* It controls a GPIO that could be attached to a LED for visualization.
* Additionally the ESP32 will send debug messages indicating the Matter activity.
* Turning DEBUG Level ON may be useful to following Matter Accessory and Controller messages.
*
* This example is a simple Matter On/Off Light that can be controlled by a Matter Controller.
* It demonstrates how to use On Identify callback when the Identify Cluster is called.
* The Matter user APP can be used to request the device to identify itself by blinking the LED.
*/

// Matter Manager
#include <Matter.h>
#include <WiFi.h>

// List of Matter Endpoints for this Node
// Single On/Off Light Endpoint - at least one per node
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

// Light GPIO that can be controlled by Matter APP
#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
#endif

// set your board USER BUTTON pin here - decommissioning button
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.

// Button control - decommision the Matter Node
uint32_t button_time_stamp = 0; // debouncing control
bool button_state = false; // false = released | true = pressed
const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission

// Matter Protocol Endpoint (On/OFF Light) Callback
bool onOffLightCallback(bool state) {
digitalWrite(ledPin, state ? HIGH : LOW);
// This callback must return the success state to Matter core
return true;
}

bool onIdentifyLightCallback(bool identifyIsActive, uint8_t counter) {
log_i("Identify Cluster is %s, counter: %d", identifyIsActive ? "Active" : "Inactive", counter);
if (identifyIsActive) {
// Start Blinking the light
OnOffLight.toggle();
} else {
// Stop Blinking and restore the light to the its last state
OnOffLight.updateAccessory();
}
return true;
}

void setup() {
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
pinMode(buttonPin, INPUT_PULLUP);
// Initialize the LED GPIO
pinMode(ledPin, OUTPUT);

// Manually connect to WiFi
WiFi.begin(ssid, password);
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}

// Initialize at least one Matter EndPoint
OnOffLight.begin();

// On Identify Callback - Blink the LED
OnOffLight.onIdentify(onIdentifyLightCallback);

// Associate a callback to the Matter Controller
OnOffLight.onChange(onOffLightCallback);

// Matter beginning - Last step, after all EndPoints are initialized
Matter.begin();

if (!Matter.isDeviceCommissioned()) {
log_i("Matter Node is not commissioned yet.");
log_i("Initiate the device discovery in your Matter environment.");
log_i("Commission it to your Matter hub with the manual pairing code or QR code");
log_i("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str());
log_i("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str());
}
}

void loop() {
// 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.
}

if (digitalRead(buttonPin) == HIGH && button_state) {
button_state = false; // released
}

// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
uint32_t time_diff = millis() - button_time_stamp;
if (button_state && time_diff > decommissioningTimeout) {
Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again.");
Matter.decommission();
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
}

delay(500);
}
7 changes: 7 additions & 0 deletions libraries/Matter/examples/MatterOnIdentify/ci.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"fqbn_append": "PartitionScheme=huge_app",
"requires": [
"CONFIG_SOC_WIFI_SUPPORTED=y",
"CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y"
]
}
26 changes: 24 additions & 2 deletions libraries/Matter/src/Matter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using namespace esp_matter;
using namespace esp_matter::attribute;
using namespace esp_matter::endpoint;
using namespace esp_matter::identification;
using namespace chip::app::Clusters;

constexpr auto k_timeout_seconds = 300;
Expand Down Expand Up @@ -67,8 +68,29 @@ static esp_err_t app_attribute_update_cb(
// 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;
log_d("Identification callback to endpoint %d: type: %u, effect: %u, variant: %u", endpoint_id, type, effect_id, effect_variant);
esp_err_t err = ESP_OK;
MatterEndPoint *ep = (MatterEndPoint *)priv_data; // endpoint pointer to base class
// Identify the endpoint sending a counter to the application
static uint8_t counter = 0;
bool identifyIsActive = false;

if (type == identification::callback_type_t::START) {
log_v("Identification callback: START");
counter = 0;
identifyIsActive = true;
} else if (type == identification::callback_type_t::EFFECT) {
log_v("Identification callback: EFFECT");
counter++;
} else if (type == identification::callback_type_t::STOP) {
identifyIsActive = false;
log_v("Identification callback: STOP");
}
if (ep != NULL) {
err = ep->endpointIdentifyCB(endpoint_id, identifyIsActive, counter) ? ESP_OK : ESP_FAIL;
}

return err;
}

// This callback is invoked for all Matter events. The application can handle the events as required.
Expand Down
15 changes: 15 additions & 0 deletions libraries/Matter/src/MatterEndPoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,22 @@ class MatterEndPoint {
// this function is called by Matter internal event processor. It could be overwritten by the application, if necessary.
virtual bool attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) = 0;

// This callback is invoked when clients interact with the Identify Cluster of an specific endpoint.
bool endpointIdentifyCB(uint16_t endpoint_id, bool identifyIsEnabled, uint8_t identifyCounter) {
if (_onEndPointIdentifyCB) {
return _onEndPointIdentifyCB(identifyIsEnabled, identifyCounter);
}
return true;
}
// User callaback for the Identify Cluster functionality
using EndPointIdentifyCB = std::function<bool(bool, uint8_t)>;
void onIdentify(EndPointIdentifyCB onEndPointIdentifyCB) {
_onEndPointIdentifyCB = onEndPointIdentifyCB;
}


protected:
uint16_t endpoint_id = 0;
EndPointIdentifyCB _onEndPointIdentifyCB = NULL;
};
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */
2 changes: 2 additions & 0 deletions libraries/Matter/src/MatterEndpoints/MatterDimmableLight.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ class MatterDimmableLight : public MatterEndPoint {

operator bool(); // returns current on/off 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 On/Off state is changed by the Matter Controller
using EndPointOnOffCB = std::function<bool(bool)>;
void onChangeOnOff(EndPointOnOffCB onChangeCB) {
Expand Down
2 changes: 2 additions & 0 deletions libraries/Matter/src/MatterEndpoints/MatterOnOffLight.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ class MatterOnOffLight : public MatterEndPoint {

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 onChange(EndPointCB onChangeCB) {
Expand Down
2 changes: 2 additions & 0 deletions libraries/Matter/src/MatterEndpoints/MatterOnOffPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ class MatterOnOffPlugin : public MatterEndPoint {

operator bool(); // returns current plugin state
void operator=(bool state); // turns plugin 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 Plugin state is changed by the Matter Controller
using EndPointCB = std::function<bool(bool)>;
void onChange(EndPointCB onChangeCB) {
Expand Down
Loading