8000 Merge pull request #10734 from SuGlider/matter_identify_callback · bsideup/arduino-esp32@6bf6df2 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6bf6df2

Browse files
authored
Merge pull request espressif#10734 from SuGlider/matter_identify_callback
feat(matter) adds Identification callback to all matter endpoints
2 parents 6a6edcb + 71e57ea commit 6bf6df2

17 files changed

+288
-25
lines changed
Lines changed: 164 additions & 0 deletions
152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/*
16+
* This example is the smallest code that will create a Matter Device which can be
17+
* commissioned and controlled from a Matter Environment APP.
18+
* It controls a GPIO that could be attached to a LED for visualization.
19+
* Additionally the ESP32 will send debug messages indicating the Matter activity.
20+
* Turning DEBUG Level ON may be useful to following Matter Accessory and Controller messages.
21+
*
22+
* This example is a simple Matter On/Off Light that can be controlled by a Matter Controller.
23+
* It demonstrates how to use On Identify callback when the Identify Cluster is called.
24+
* The Matter user APP can be used to request the device to identify itself by blinking the LED.
25+
*/
26+
27+
// Matter Manager
28+
#include <Matter.h>
29+
#include <WiFi.h>
30+
31+
// List of Matter Endpoints for this Node
32+
// Single On/Off Light Endpoint - at least one per node
33+
MatterOnOffLight OnOffLight;
34+
35+
// WiFi is manually set and started
36+
const char *ssid = "your-ssid"; // Change this to your WiFi SSID
37+
const char *password = "your-password"; // Change this to your WiFi password
38+
39+
// Light GPIO that can be controlled by Matter APP
40+
#ifdef LED_BUILTIN
41+
const uint8_t ledPin = LED_BUILTIN;
42+
#else
43+
const uint8_t ledPin = 2; // Set your pin here if your board has not defined LED_BUILTIN
44+
#endif
45+
46+
// set your board USER BUTTON pin here - decommissioning button
47+
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
48+
49+
// Button control - decommision the Matter Node
50+
uint32_t button_time_stamp = 0; // debouncing control
51+
bool button_state = false; // false = released | true = pressed
52+
const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission
53+
54+
// Identify Flag and blink time - Blink the LED
55+
const uint8_t identifyLedPin = ledPin; // uses the same LED as the Light - change if needed
56+
volatile bool identifyFlag = false; // Flag to start the Blink when in Identify state
57+
bool identifyBlink = false; // Blink state when in Identify state
58+
59+
// Matter Protocol Endpoint (On/OFF Light) Callback
60+
bool onOffLightCallback(bool state) {
61+
digitalWrite(ledPin, state ? HIGH : LOW);
62+
// This callback must return the success state to Matter core
63+
return true;
64+
}
65+
66+
// Identification shall be done by Blink in Red or just the GPIO when no LED_BUILTIN is not defined
67+
bool onIdentifyLightCallback(bool identifyIsActive) {
68+
Serial.printf("Identify Cluster is %s\r\n", identifyIsActive ? "Active" : "Inactive");
69+
if (identifyIsActive) {
70+
// Start Blinking the light in loop()
71+
identifyFlag = true;
72+
identifyBlink = !OnOffLight; // Start with the inverted light state
73+
} else {
74+
// Stop Blinking and restore the light to the its last state
75+
identifyFlag = false;
76+
// force returning to the original state by toggling the light twice
77+
OnOffLight.toggle();
78+
OnOffLight.toggle();
79+
}
80+
return true;
81+
}
82+
83+
void setup() {
84+
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
85+
pinMode(buttonPin, INPUT_PULLUP);
86+
// Initialize the LED GPIO
87+
pinMode(ledPin, OUTPUT);
88+
89+
Serial.begin(115200);
90+
91+
// Manually connect to WiFi
92+
WiFi.begin(ssid, password);
93+
// Wait for connection
94+
while (WiFi.status() != WL_CONNECTED) {
95+
delay(500);
96+
Serial.print(".");
97+
}
98+
Serial.println();
99+
100+
// Initialize at least one Matter EndPoint
101+
OnOffLight.begin();
102+
103+
// On Identify Callback - Blink the LED
104+
OnOffLight.onIdentify(onIdentifyLightCallback);
105+
106+
// Associate a callback to the Matter Controller
107+
OnOffLight.onChange(onOffLightCallback);
108+
109+
// Matter beginning - Last step, after all EndPoints are initialized
110+
Matter.begin();
111+
112+
// Check Matter Accessory Commissioning state, which may change during execution of loop()
113+
if (!Matter.isDeviceCommissioned()) {
114+
Serial.println("");
115+
Serial.println("Matter Node is not commissioned yet.");
116+
Serial.println("Initiate the device discovery in your Matter environment.");
117+
Serial.println("Commission it to your Matter hub with the manual pairing code or QR code");
118+
Serial.printf("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str());
119+
Serial.printf("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str());
120+
// waits for Matter Occupancy Sensor Commissioning.
121+
uint32_t timeCount = 0;
122+
while (!Matter.isDeviceCommissioned()) {
123+
delay(100);
124+
if ((timeCount++ % 50) == 0) { // 50*100ms = 5 sec
125+
Serial.println("Matter Node not commissioned yet. Waiting for commissioning.");
126+
}
127+
}
128+
Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use.");
129+
}
130+
}
131+
132+
void loop() {
133+
// check if the Light is in identify state and blink it every 500ms (delay loop time)
134+
if (identifyFlag) {
135+
#ifdef LED_BUILTIN
136+
uint8_t brightness = 32 * identifyBlink;
137+
rgbLedWrite(identifyLedPin, brightness, 0, 0);
138+
#else
139+
digitalWrite(identifyLedPin, identifyBlink ? HIGH : LOW);
140+
#endif
141+
identifyBlink = !identifyBlink;
142+
}
143+
144+
// Check if the button has been pressed
145+
if (digitalRead(buttonPin) == LOW && !button_state) {
146+
// deals with button debouncing
147+
button_time_stamp = millis(); // record the time while the button is pressed.
148+
button_state = true; // pressed.
149+
}
150+
151+
if (digitalRead(buttonPin) == HIGH && button_state) {
+
button_state = false; // released
153+
}
154+
155+
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
156+
uint32_t time_diff = millis() - button_time_stamp;
157+
if (button_state && time_diff > decommissioningTimeout) {
158+
Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again.");
159+
Matter.decommission();
160+
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
161+
}
162+
163+
delay(500); // works as a debounce for the button and also for the LED blink
164+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"fqbn_append": "PartitionScheme=huge_app",
3+
"requires": [
4+
"CONFIG_SOC_WIFI_SUPPORTED=y",
5+
"CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y"
6+
]
7+
}

libraries/Matter/src/Matter.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using namespace esp_matter;
2222
using namespace esp_matter::attribute;
2323
using namespace esp_matter::endpoint;
24+
using namespace esp_matter::identification;
2425
using namespace chip::app::Clusters;
2526

2627
constexpr auto k_timeout_seconds = 300;
@@ -29,11 +30,6 @@ static bool _matter_has_started = false;
2930
static node::config_t node_config;
3031
static node_t *deviceNode = NULL;
3132

32-
typedef void *app_driver_handle_t;
33-
esp_err_t matter_light_attribute_update(
34-
app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val
35-
);
36-
3733
// This callback is called for every attribute update. The callback implementation shall
3834
// handle the desired attributes and return an appropriate error code. If the attribute
3935
// is not of your interest, please do not return an error code and strictly return ESP_OK.
@@ -67,8 +63,26 @@ static esp_err_t app_attribute_update_cb(
6763
// This callback is invoked when clients interact with the Identify Cluster.
6864
// In the callback implementation, an endpoint can identify itself. (e.g., by flashing an LED or light).
6965
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) {
70-
log_i("Identification callback: type: %u, effect: %u, variant: %u", type, effect_id, effect_variant);
71-
return ESP_OK;
66+
log_d("Identification callback to endpoint %d: type: %u, effect: %u, variant: %u", endpoint_id, type, effect_id, effect_variant);
67+
esp_err_t err = ESP_OK;
68+
MatterEndPoint *ep = (MatterEndPoint *)priv_data; // endpoint pointer to base class
69+
// Identify the endpoint sending a counter to the application
70+
bool identifyIsActive = false;
71+
72+
if (type == identification::callback_type_t::START) {
73+
log_v("Identification callback: START");
74+
identifyIsActive = true;
75+
} else if (type == identification::callback_type_t::EFFECT) {
76+
log_v("Identification callback: EFFECT");
77+
} else if (type == identification::callback_type_t::STOP) {
78+
identifyIsActive = false;
79+
log_v("Identification callback: STOP");
80+
}
81+
if (ep != NULL) {
82+
err = ep->endpointIdentifyCB(endpoint_id, identifyIsActive) ? ESP_OK : ESP_FAIL;
83+
}
84+
85+
return err;
7286
}
7387

7488
// This callback is invoked for all Matter events. The application can handle the events as required.

libraries/Matter/src/MatterEndPoint.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,21 @@ class MatterEndPoint {
102102
// this function is called by Matter internal event processor. It could be overwritten by the application, if necessary.
103103
virtual bool attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) = 0;
104104

105+
// This callback is invoked when clients interact with the Identify Cluster of an specific endpoint.
106+
bool endpointIdentifyCB(uint16_t endpoint_id, bool identifyIsEnabled) {
107+
if (_onEndPointIdentifyCB) {
108+
return _onEndPointIdentifyCB(identifyIsEnabled);
109+
}
110+
return true;
111+
}
112+
// User callaback for the Identify Cluster functionality
113+
using EndPointIdentifyCB = std::function<bool(bool)>;
114+
void onIdentify(EndPointIdentifyCB onEndPointIdentifyCB) {
115+
_onEndPointIdentifyCB = onEndPointIdentifyCB;
116+
}
117+
105118
protected:
106119
uint16_t endpoint_id = 0;
120+
EndPointIdentifyCB _onEndPointIdentifyCB = NULL;
107121
};
108122
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */

libraries/Matter/src/MatterEndpoints/MatterColorLight.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,13 @@ MatterColorLight::~MatterColorLight() {
162162

163163
bool MatterColorLight::begin(bool initialState, espHsvColor_t _colorHSV) {
164164
ArduinoMatter::_init();
165-
rgb_color_light::config_t light_config;
166165

166+
if (getEndPointId() != 0) {
167+
log_e("Matter RGB Color Light with Endpoint Id %d device has already been created.", getEndPointId());
168+
return false;
169+
}
170+
171+
rgb_color_light::config_t light_config;
167172
light_config.on_off.on_off = initialState;
168173
light_config.on_off.lighting.start_up_on_off = nullptr;
169174
onOffState = initialState;

libraries/Matter/src/MatterEndpoints/MatterColorTemperatureLight.cpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ using namespace chip::app::Clusters;
2626
bool MatterColorTemperatureLight::attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) {
2727
bool ret = true;
2828
if (!started) {
29-
log_e("Matter CW_WW Light device has not begun.");
29+
log_e("Matter Temperature Light device has not begun.");
3030
return false;
3131
}
3232

33-
log_d("CW_WW Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32);
33+
log_d("Temperature Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32);
3434

3535
if (endpoint_id == getEndPointId()) {
3636
switch (cluster_id) {
3737
case OnOff::Id:
3838
if (attribute_id == OnOff::Attributes::OnOff::Id) {
39-
log_d("CW_WW Light On/Off State changed to %d", val->val.b);
39+
log_d("Temperature Light On/Off State changed to %d", val->val.b);
4040
if (_onChangeOnOffCB != NULL) {
4141
ret &= _onChangeOnOffCB(val->val.b);
4242
}
@@ -50,7 +50,7 @@ bool MatterColorTemperatureLight::attributeChangeCB(uint16_t endpoint_id, uint32
5050
break;
5151
case LevelControl::Id:
5252
if (attribute_id == LevelControl::Attributes::CurrentLevel::Id) {
53-
log_d("CW_WW Light Brightness changed to %d", val->val.u8);
53+
log_d("Temperature Light Brightness changed to %d", val->val.u8);
5454
if (_onChangeBrightnessCB != NULL) {
5555
ret &= _onChangeBrightnessCB(val->val.u8);
5656
}
@@ -64,7 +64,7 @@ bool MatterColorTemperatureLight::attributeChangeCB(uint16_t endpoint_id, uint32
6464
break;
6565
case ColorControl::Id:
6666
if (attribute_id == ColorControl::Attributes::ColorTemperatureMireds::Id) {
67-
log_d("CW_WW Light Temperature changed to %d", val->val.u16);
67+
log_d("Temperature Light Temperature changed to %d", val->val.u16);
6868
if (_onChangeTemperatureCB != NULL) {
6969
ret &= _onChangeTemperatureCB(val->val.u16);
7070
}
@@ -89,8 +89,13 @@ MatterColorTemperatureLight::~MatterColorTemperatureLight() {
8989

9090
bool MatterColorTemperatureLight::begin(bool initialState, uint8_t brightness, uint16_t ColorTemperature) {
9191
ArduinoMatter::_init();
92-
color_temperature_light::config_t light_config;
9392

93+
if (getEndPointId() != 0) {
94+
log_e("Matter Temperature Light with Endpoint Id %d device has already been created.", getEndPointId());
95+
return false;
96+
}
97+
98+
color_temperature_light::config_t light_config;
9499
light_config.on_off.on_off = initialState;
95100
light_config.on_off.lighting.start_up_on_off = nullptr;
96101
onOffState = initialState;
@@ -108,12 +113,12 @@ bool MatterColorTemperatureLight::begin(bool initialState, uint8_t brightness, u
108113
// endpoint handles can be used to add/modify clusters.
109114
endpoint_t *endpoint = color_temperature_light::create(node::get(), &light_config, ENDPOINT_FLAG_NONE, (void *)this);
110115
if (endpoint == nullptr) {
111-
log_e("Failed to create CW_WW light endpoint");
116+
log_e("Failed to create Temperature Light endpoint");
112117
return false;
113118
}
114119

115120
setEndPointId(endpoint::get_id(endpoint));
116-
log_i("CW_WW Light created with endpoint_id %d", getEndPointId());
121+
log_i("Temperature Light created with endpoint_id %d", getEndPointId());
117122

118123
/* Mark deferred persistence for some attributes that might be changed rapidly */
119124
cluster_t *level_control_cluster = cluster::get(endpoint, LevelControl::Id);
@@ -134,7 +139,7 @@ void MatterColorTemperatureLight::end() {
134139

135140
bool MatterColorTemperatureLight::setOnOff(bool newState) {
136141
if (!started) {
137-
log_e("Matter CW_WW Light device has not begun.");
142+
log_e("Matter Temperature Light device has not begun.");
138143
return false;
139144
}
140145

@@ -175,7 +180,7 @@ bool MatterColorTemperatureLight::toggle() {
175180

176181
bool MatterColorTemperatureLight::setBrightness(uint8_t newBrightness) {
177182
if (!started) {
178-
log_w("Matter CW_WW Light device has not begun.");
183+
log_w("Matter Temperature Light device has not begun.");
179184
return false;
180185
}
181186

@@ -206,7 +211,7 @@ uint8_t MatterColorTemperatureLight::getBrightness() {
206211

207212
bool MatterColorTemperatureLight::setColorTemperature(uint16_t newTemperature) {
208213
if (!started) {
209-
log_w("Matter CW_WW Light device has not begun.");
214+
log_w("Matter Temperature Light device has not begun.");
210215
return false;
211216
}
212217

libraries/Matter/src/MatterEndpoints/MatterContactSensor.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ MatterContactSensor::~MatterContactSensor() {
4343
bool MatterContactSensor::begin(bool _contactState) {
4444
ArduinoMatter::_init();
4545

46+
if (getEndPointId() != 0) {
47+
log_e("Matter Contact Sensor with Endpoint Id %d device has already been created.", getEndPointId());
48+
return false;
49+
}
50+
4651
contact_sensor::config_t contact_sensor_config;
4752
contact_sensor_config.boolean_state.state_value = _contactState;
4853

libraries/Matter/src/MatterEndpoints/MatterDimmableLight.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,12 @@ MatterDimmableLight::~MatterDimmableLight() {
7575

7676
bool MatterDimmableLight::begin(bool initialState, uint8_t brightness) {
7777
ArduinoMatter::_init();
78-
dimmable_light::config_t light_config;
78+
if (getEndPointId() != 0) {
79+
log_e("Matter Dimmable Light with Endpoint Id %d device has already been created.", getEndPointId());
80+
return false;
81+
}
7982

83+
dimmable_light::config_t light_config;
8084
light_config.on_off.on_off = initialState;
8185
light_config.on_off.lighting.start_up_on_off = nullptr;
8286
onOffState = initialState;

libraries/Matter/src/MatterEndpoints/MatterEnhancedColorLight.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,13 @@ MatterEnhancedColorLight::~MatterEnhancedColorLight() {
178178

179179
bool MatterEnhancedColorLight::begin(bool initialState, espHsvColor_t _colorHSV, uint8_t brightness, uint16_t ColorTemperature) {
180180
ArduinoMatter::_init();
181-
enhanced_color_light::config_t light_config;
182181

182+
if (getEndPointId() != 0) {
183+
log_e("Matter Enhanced ColorLight with Endpoint Id %d device has already been created.", getEndPointId());
184+
return false;
185+
}
186+
187+
enhanced_color_light::config_t light_config;
183188
light_config.on_off.on_off = initialState;
184189
light_config.on_off.lighting.start_up_on_off = nullptr;
185190
onOffState = initialState;

0 commit comments

Comments
 (0)
0