3.3.7
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
// 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
#include <Preferences.h>
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Color Light Endpoint
|
||||
MatterColorLight ColorLight;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// it will keep last OnOff & HSV Color state stored, using Preferences
|
||||
Preferences matterPref;
|
||||
const char *onOffPrefKey = "OnOff";
|
||||
const char *hsvColorPrefKey = "HSV";
|
||||
|
||||
// set your board RGB LED pin here
|
||||
#ifdef RGB_BUILTIN
|
||||
const uint8_t ledPin = RGB_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 RGB LED pin"
|
||||
#endif
|
||||
|
||||
// set your board USER BUTTON pin here
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||
|
||||
// Set the RGB LED Light based on the current state of the Color Light
|
||||
bool setLightState(bool state, espHsvColor_t colorHSV) {
|
||||
|
||||
if (state) {
|
||||
#ifdef RGB_BUILTIN
|
||||
espRgbColor_t rgbColor = espHsvColorToRgbColor(colorHSV);
|
||||
// set the RGB LED
|
||||
rgbLedWrite(ledPin, rgbColor.r, rgbColor.g, rgbColor.b);
|
||||
#else
|
||||
// No Color RGB LED, just use the HSV value (brightness) to control the LED
|
||||
analogWrite(ledPin, colorHSV.v);
|
||||
#endif
|
||||
} else {
|
||||
#ifndef RGB_BUILTIN
|
||||
// after analogWrite(), it is necessary to set the GPIO to digital mode first
|
||||
pinMode(ledPin, OUTPUT);
|
||||
#endif
|
||||
digitalWrite(ledPin, LOW);
|
||||
}
|
||||
// store last HSV Color and OnOff state for when the Light is restarted / power goes off
|
||||
matterPref.putBool(onOffPrefKey, state);
|
||||
matterPref.putUInt(hsvColorPrefKey, colorHSV.h << 16 | colorHSV.s << 8 | colorHSV.v);
|
||||
// This callback must return the success state to Matter core
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// Initialize Matter EndPoint
|
||||
matterPref.begin("MatterPrefs", false);
|
||||
// default OnOff state is ON if not stored before
|
||||
bool lastOnOffState = matterPref.getBool(onOffPrefKey, true);
|
||||
// default HSV color is blue HSV(169, 254, 254)
|
||||
uint32_t prefHsvColor = matterPref.getUInt(hsvColorPrefKey, 169 << 16 | 254 << 8 | 254);
|
||||
espHsvColor_t lastHsvColor = {uint8_t(prefHsvColor >> 16), uint8_t(prefHsvColor >> 8), uint8_t(prefHsvColor)};
|
||||
ColorLight.begin(lastOnOffState, lastHsvColor);
|
||||
// set the callback function to handle the Light state change
|
||||
ColorLight.onChange(setLightState);
|
||||
|
||||
// lambda functions are used to set the attribute change callbacks
|
||||
ColorLight.onChangeOnOff([](bool state) {
|
||||
Serial.printf("Light OnOff changed to %s\r\n", state ? "ON" : "OFF");
|
||||
return true;
|
||||
});
|
||||
ColorLight.onChangeColorHSV([](HsvColor_t hsvColor) {
|
||||
Serial.printf("Light HSV Color changed to (%d,%d,%d)\r\n", hsvColor.h, hsvColor.s, hsvColor.v);
|
||||
return true;
|
||||
});
|
||||
|
||||
// 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 the network. Ready for use.");
|
||||
Serial.printf(
|
||||
"Initial state: %s | RGB Color: (%d,%d,%d) \r\n", ColorLight ? "ON" : "OFF", ColorLight.getColorRGB().r, ColorLight.getColorRGB().g,
|
||||
ColorLight.getColorRGB().b
|
||||
);
|
||||
// configure the Light based on initial on-off state and its color
|
||||
ColorLight.updateAccessory();
|
||||
}
|
||||
}
|
||||
|
||||
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 | RGB Color: (%d,%d,%d) \r\n", ColorLight ? "ON" : "OFF", ColorLight.getColorRGB().r, ColorLight.getColorRGB().g,
|
||||
ColorLight.getColorRGB().b
|
||||
);
|
||||
// configure the Light based on initial on-off state and its color
|
||||
ColorLight.updateAccessory();
|
||||
Serial.println("Matter Node is commissioned and connected to the network. 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 (digitalRead(buttonPin) == HIGH && button_state && time_diff > debouceTime) {
|
||||
// Toggle button is released - toggle the light
|
||||
Serial.println("User button released. Toggling Light!");
|
||||
ColorLight.toggle(); // Matter Controller also can see the change
|
||||
button_state = false; // released
|
||||
}
|
||||
|
||||
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||
if (button_state && time_diff > decommissioningTimeout) {
|
||||
Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again.");
|
||||
ColorLight = false; // turn the light off
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
# Matter Color Light Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible color light device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device control via smart home ecosystems, and manual control using a physical button.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | RGB LED | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a color light device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- RGB color control with HSV color model
|
||||
- State persistence using `Preferences` library
|
||||
- Button control for toggling light and factory reset
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- RGB LED connected to GPIO pins (or using built-in RGB LED)
|
||||
- User button for manual control (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **RGB LED**: Uses `RGB_BUILTIN` if defined, otherwise pin 2
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Preferences`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **LED pin configuration** (if not using built-in RGB LED):
|
||||
``` cpp
|
||||
const uint8_t ledPin = 2; // Set your RGB LED pin here
|
||||
```
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for the Light On/Off manual control. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = 0; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterColorLight.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Initial state: ON | RGB Color: (0,0,255)
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Short press of the button**: Toggle light on/off
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a color light in your Home app
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The light will appear in your Alexa app
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterColorLight example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, LED), configures Wi-Fi (if needed), sets up the Matter endpoint, restores the last known state from `Preferences`, and registers callbacks for state changes.
|
||||
2. **`loop()`**: Checks the Matter commissioning state, handles button input for toggling the light and factory reset, and allows the Matter stack to process events.
|
||||
3. **Callbacks**:
|
||||
- `setLightState()`: Controls the physical RGB LED.
|
||||
- `onChangeOnOff()`: Handles on/off state changes.
|
||||
- `onChangeColorHSV()`: Handles color changes.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **RGB LED not responding**: Verify pin configurations and connections
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Color Light Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_color_light.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,81 @@
|
||||
// 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// On/Off Light Endpoint
|
||||
MatterOnOffLight OnOffLight;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// 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 the network.");
|
||||
Serial.println("====> Decommissioning in 30 seconds. <====");
|
||||
delay(30000);
|
||||
Matter.decommission();
|
||||
Serial.println("Matter Node is decommissioned. Commissioning widget shall start over.");
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
# Matter Commission Test Example
|
||||
|
||||
This example demonstrates how to test Matter commissioning functionality using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device connection to smart home ecosystems, and automatic decommissioning after a 30-second delay for continuous testing cycles.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for an on/off light device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Automatic decommissioning after 30 seconds for continuous testing
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
- Simple test tool for validating Matter commissioning workflows
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterCommissionTest.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Fabric not commissioned yet. Waiting for commissioning.
|
||||
Matter Fabric not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network.
|
||||
====> Decommissioning in 30 seconds. <====
|
||||
Matter Node is decommissioned. Commissioning widget shall start over.
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
...
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Test Cycle
|
||||
|
||||
The device operates in a continuous test cycle:
|
||||
|
||||
1. **Commissioning Phase**: The device waits for Matter commissioning. It displays the manual pairing code and QR code URL in the Serial Monitor.
|
||||
2. **Commissioned Phase**: Once commissioned, the device is connected to the Matter network and ready for use.
|
||||
3. **Automatic Decommissioning**: After 30 seconds, the device automatically decommissions itself.
|
||||
4. **Repeat**: The cycle repeats, allowing you to test the commissioning process multiple times.
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device during each test cycle.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as an on/off light in your Home app
|
||||
7. After 30 seconds, the device will automatically decommission and the cycle will repeat
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The light will appear in your Alexa app
|
||||
6. After 30 seconds, the device will automatically decommission and the cycle will repeat
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. After 30 seconds, the device will automatically decommission and the cycle will repeat
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterCommissionTest example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Configures Wi-Fi (if needed), initializes the Matter On/Off Light endpoint, and starts the Matter stack.
|
||||
2. **`loop()`**: Checks the Matter commissioning state, displays pairing information when not commissioned, waits for commissioning, and then automatically decommissions after 30 seconds to repeat the cycle.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Failed to commission**: Try waiting for the next cycle after decommissioning. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
- **Device keeps decommissioning**: This is expected behavior - the device automatically decommissions after 30 seconds to allow continuous testing
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,146 @@
|
||||
// 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// There will be 3 On/Off Light Endpoints in the same Node
|
||||
MatterOnOffLight Light1;
|
||||
MatterDimmableLight Light2;
|
||||
MatterColorLight Light3;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// set your board USER BUTTON pin here - USED to decommission the Matter Node
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// Button control
|
||||
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 Callback for each Light Accessory
|
||||
bool setLightOnOff1(bool state) {
|
||||
Serial.printf("Light1 changed state to: %s\r\n", state ? "ON" : "OFF");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setLightOnOff2(bool state) {
|
||||
Serial.printf("Light2 changed state to: %s\r\n", state ? "ON" : "OFF");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setLightOnOff3(bool state) {
|
||||
Serial.printf("Light3 changed state to: %s\r\n", state ? "ON" : "OFF");
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
Serial.println("WiFi connected");
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
delay(500);
|
||||
#endif
|
||||
|
||||
// Initialize all 3 Matter EndPoints
|
||||
Light1.begin();
|
||||
Light2.begin();
|
||||
Light3.begin();
|
||||
Light1.onChangeOnOff(setLightOnOff1);
|
||||
Light2.onChangeOnOff(setLightOnOff2);
|
||||
Light3.onChangeOnOff(setLightOnOff3);
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint32_t timeCounter = 0;
|
||||
|
||||
// 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 the network. Ready for use.");
|
||||
}
|
||||
|
||||
//displays the Light state every 5 seconds
|
||||
if (!(timeCounter++ % 10)) { // delaying for 500ms x 10 = 5s
|
||||
Serial.println("======================");
|
||||
Serial.printf("Matter Light #1 is %s\r\n", Light1.getOnOff() ? "ON" : "OFF");
|
||||
Serial.printf("Matter Light #2 is %s\r\n", Light2.getOnOff() ? "ON" : "OFF");
|
||||
Serial.printf("Matter Light #3 is %s\r\n", Light3.getOnOff() ? "ON" : "OFF");
|
||||
}
|
||||
|
||||
// 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 Composed 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);
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
# Matter Composed Lights Example
|
||||
|
||||
This example demonstrates how to create a Matter node with multiple light endpoints using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, a single Matter node containing three different light types (On/Off Light, Dimmable Light, and Color Light), and factory reset using a physical button.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a composed device with multiple light endpoints
|
||||
- Three light endpoints in a single Matter node:
|
||||
- Light #1: Simple On/Off Light
|
||||
- Light #2: Dimmable Light (on/off with brightness control)
|
||||
- Light #3: Color Light (RGB color control)
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Button control for factory reset (decommission)
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
- Periodic state display of all three lights
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- User button for factory reset (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **Button**: Uses `BOOT_PIN` by default for factory reset (long press >5 seconds)
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterComposedLights.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
======================
|
||||
Matter Light #1 is OFF
|
||||
Matter Light #2 is OFF
|
||||
Matter Light #3 is OFF
|
||||
======================
|
||||
Light1 changed state to: ON
|
||||
Light2 changed state to: ON
|
||||
Light3 changed state to: ON
|
||||
======================
|
||||
Matter Light #1 is ON
|
||||
Matter Light #2 is ON
|
||||
Matter Light #3 is ON
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides factory reset functionality:
|
||||
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device. After commissioning, you will see three separate light devices in your smart home app:
|
||||
|
||||
- **Light #1**: Simple on/off light
|
||||
- **Light #2**: Dimmable light with brightness control
|
||||
- **Light #3**: Color light with RGB color control
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as three separate lights in your Home app
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The three lights will appear in your Alexa app
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The three lights will appear in your Google Home app
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterComposedLights example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button), configures Wi-Fi (if needed), sets up three Matter endpoints (OnOffLight, DimmableLight, ColorLight), and registers callbacks for state changes.
|
||||
2. **`loop()`**: Checks the Matter commissioning state, displays the state of all three lights every 5 seconds, handles button input for factory reset, and allows the Matter stack to process events.
|
||||
3. **Callbacks**:
|
||||
- `setLightOnOff1()`: Handles on/off state changes for Light #1.
|
||||
- `setLightOnOff2()`: Handles on/off state changes for Light #2.
|
||||
- `setLightOnOff3()`: Handles on/off state changes for Light #3.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Only one or two lights appear**: Some smart home platforms may group or display lights differently. Check your app's device list
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter On/Off Light Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_on_off_light.html)
|
||||
- [Matter Dimmable Light Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_dimmable_light.html)
|
||||
- [Matter Color Light Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_color_light.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,161 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* This example is an example code that will create a Matter Device which can be
|
||||
* commissioned and controlled from a Matter Environment APP.
|
||||
* 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.
|
||||
*
|
||||
* The example will create a Matter Contact Sensor Device.
|
||||
* The Contact Sensor state can be toggled by pressing the onboard button.
|
||||
* The Contact Sensor state will be indicated by the onboard LED.
|
||||
* The Contact Sensor state will be simulated to change every 20 seconds.
|
||||
*
|
||||
* The onboard button can be kept pressed for 5 seconds to decommission the Matter Node.
|
||||
* The example will also show the manual commissioning code and QR code to be used in the Matter environment.
|
||||
*
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Matter Contact Sensor Endpoint
|
||||
MatterContactSensor ContactSensor;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// LED will be used to indicate the Contact Sensor state
|
||||
// set your board RGB LED pin here
|
||||
#ifdef RGB_BUILTIN
|
||||
const uint8_t ledPin = RGB_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 RGB LED pin"
|
||||
#endif
|
||||
|
||||
// set your board USER BUTTON pin here - decommissioning and Manual Contact Sensor toggle button
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||
// The button will also be used to manually toggle the Contact Sensor state
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
// Initialize the LED (light) GPIO and Matter End Point
|
||||
pinMode(ledPin, OUTPUT);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// set initial contact sensor state as false (default)
|
||||
ContactSensor.begin();
|
||||
digitalWrite(ledPin, LOW); // LED OFF
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
|
||||
// Check Matter Accessory 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 Contact Sensor 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 the network. Ready for use.");
|
||||
}
|
||||
}
|
||||
|
||||
bool simulatedHWContactSensor() {
|
||||
// Simulated Contact Sensor
|
||||
static bool contactState = false;
|
||||
static uint32_t lastTime = 0;
|
||||
|
||||
// Simulate a Contact Sensor state change every 20 seconds
|
||||
if (millis() - lastTime > 20000) {
|
||||
contactState = !contactState;
|
||||
lastTime = millis();
|
||||
}
|
||||
return contactState;
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
uint32_t time_diff = millis() - button_time_stamp;
|
||||
if (button_state && time_diff > debouceTime && digitalRead(buttonPin) == HIGH) {
|
||||
button_state = false; // released
|
||||
// button is released - toggle Contact State (Open/Closed)
|
||||
ContactSensor.setContact(!ContactSensor.getContact()); // same as ContactSensor = !ContactSensor;
|
||||
Serial.printf("User button released. Setting the Contact Sensor to %s.\r\n", ContactSensor ? "Closed" : "Open");
|
||||
// LED will indicate the Contact Sensor state
|
||||
if (ContactSensor) {
|
||||
digitalWrite(ledPin, HIGH); // LED ON
|
||||
} else {
|
||||
digitalWrite(ledPin, LOW); // LED OFF
|
||||
}
|
||||
}
|
||||
|
||||
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||
if (button_state && time_diff > decommissioningTimeout) {
|
||||
Serial.println("Decommissioning Contact Sensor Matter Accessory. It shall be commissioned again.");
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||
}
|
||||
|
||||
// Simulated Contact Sensor
|
||||
ContactSensor.setContact(simulatedHWContactSensor());
|
||||
|
||||
delay(50);
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
# Matter Contact Sensor Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible contact sensor device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device control via smart home ecosystems, manual control using a physical button, and automatic simulation of contact state changes.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | LED | Status |
|
||||
| --- | ---- | ------ | ----------------- | --- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a contact sensor device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Contact state indication using LED (ON = Closed, OFF = Open)
|
||||
- Automatic simulation of contact state changes every 20 seconds
|
||||
- Button control for toggling contact state and factory reset
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- LED connected to GPIO pins (or using built-in LED) to indicate contact state
|
||||
- User button for manual control (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **LED**: Uses `RGB_BUILTIN` if defined, otherwise pin 2
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **LED pin configuration** (if not using built-in LED):
|
||||
```cpp
|
||||
const uint8_t ledPin = 2; // Set your LED pin here
|
||||
```
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for the Contact Sensor state toggle and factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterContactSensor.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
User button released. Setting the Contact Sensor to Closed.
|
||||
User button released. Setting the Contact Sensor to Open.
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Short press of the button**: Toggle contact sensor state (Open/Closed)
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Automatic Simulation
|
||||
|
||||
The contact sensor state automatically toggles every 20 seconds to simulate a real contact sensor (such as a door or window sensor). The LED will reflect the current state:
|
||||
- **LED ON**: Contact sensor is Closed
|
||||
- **LED OFF**: Contact sensor is Open
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a contact sensor in your Home app
|
||||
7. You can monitor the contact state (Open/Closed) and receive notifications when the state changes
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The contact sensor will appear in your Alexa app
|
||||
6. You can monitor the contact state and set up routines based on state changes
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The contact sensor will appear in your Google Home app
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterContactSensor example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, LED), configures Wi-Fi (if needed), sets up the Matter Contact Sensor endpoint with initial state (Open), and waits for Matter commissioning.
|
||||
2. **`loop()`**: Handles button input for toggling contact state and factory reset, and automatically simulates contact state changes every 20 seconds.
|
||||
3. **`simulatedHWContactSensor()`**: Simulates a hardware contact sensor by toggling the contact state every 20 seconds.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **LED not responding**: Verify pin configurations and connections
|
||||
- **Contact sensor state not updating**: Check Serial Monitor output to verify state changes are being processed
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Contact Sensor Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_contact_sensor.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,182 @@
|
||||
// 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
#include <Preferences.h>
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Dimmable Light Endpoint
|
||||
MatterDimmableLight DimmableLight;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// it will keep last OnOff & Brightness state stored, using Preferences
|
||||
Preferences matterPref;
|
||||
const char *onOffPrefKey = "OnOff";
|
||||
const char *brightnessPrefKey = "Brightness";
|
||||
|
||||
// set your board RGB LED pin here
|
||||
#ifdef RGB_BUILTIN
|
||||
const uint8_t ledPin = RGB_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 RGB LED pin"
|
||||
#endif
|
||||
|
||||
// set your board USER BUTTON pin here
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||
|
||||
// Set the RGB LED Light based on the current state of the Dimmable Light
|
||||
bool setLightState(bool state, uint8_t brightness) {
|
||||
if (state) {
|
||||
#ifdef RGB_BUILTIN
|
||||
rgbLedWrite(ledPin, brightness, brightness, brightness);
|
||||
#else
|
||||
analogWrite(ledPin, brightness);
|
||||
#endif
|
||||
} else {
|
||||
#ifndef RGB_BUILTIN
|
||||
// after analogWrite(), it is necessary to set the GPIO to digital mode first
|
||||
pinMode(ledPin, OUTPUT);
|
||||
#endif
|
||||
digitalWrite(ledPin, LOW);
|
||||
}
|
||||
// store last Brightness and OnOff state for when the Light is restarted / power goes off
|
||||
matterPref.putUChar(brightnessPrefKey, brightness);
|
||||
matterPref.putBool(onOffPrefKey, state);
|
||||
// This callback must return the success state to Matter core
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// Initialize Matter EndPoint
|
||||
matterPref.begin("MatterPrefs", false);
|
||||
// default OnOff state is ON if not stored before
|
||||
bool lastOnOffState = matterPref.getBool(onOffPrefKey, true);
|
||||
// default brightness ~= 6% (15/255)
|
||||
uint8_t lastBrightness = matterPref.getUChar(brightnessPrefKey, 15);
|
||||
DimmableLight.begin(lastOnOffState, lastBrightness);
|
||||
// set the callback function to handle the Light state change
|
||||
DimmableLight.onChange(setLightState);
|
||||
|
||||
// lambda functions are used to set the attribute change callbacks
|
||||
DimmableLight.onChangeOnOff([](bool state) {
|
||||
Serial.printf("Light OnOff changed to %s\r\n", state ? "ON" : "OFF");
|
||||
return true;
|
||||
});
|
||||
DimmableLight.onChangeBrightness([](uint8_t level) {
|
||||
Serial.printf("Light Brightness changed to %d\r\n", level);
|
||||
return true;
|
||||
});
|
||||
|
||||
// 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 the network. Ready for use.");
|
||||
Serial.printf("Initial state: %s | brightness: %d\r\n", DimmableLight ? "ON" : "OFF", DimmableLight.getBrightness());
|
||||
// configure the Light based on initial on-off state and brightness
|
||||
DimmableLight.updateAccessory();
|
||||
}
|
||||
}
|
||||
|
||||
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 | brightness: %d\r\n", DimmableLight ? "ON" : "OFF", DimmableLight.getBrightness());
|
||||
// configure the Light based on initial on-off state and brightness
|
||||
DimmableLight.updateAccessory();
|
||||
Serial.println("Matter Node is commissioned and connected to the network. 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 (digitalRead(buttonPin) == HIGH && button_state && time_diff > debouceTime) {
|
||||
// Toggle button is released - toggle the light
|
||||
Serial.println("User button released. Toggling Light!");
|
||||
DimmableLight.toggle(); // Matter Controller also can see the change
|
||||
button_state = false; // released
|
||||
}
|
||||
|
||||
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||
if (button_state && time_diff > decommissioningTimeout) {
|
||||
Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again.");
|
||||
DimmableLight = false; // turn the light off
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
# Matter Dimmable Light Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible dimmable light device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device control via smart home ecosystems, and manual control using a physical button.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | LED | Status |
|
||||
| --- | ---- | ------ | ----------------- | --- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a dimmable light device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Brightness control (0-255 levels)
|
||||
- State persistence using `Preferences` library
|
||||
- Button control for toggling light and factory reset
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- LED connected to GPIO pins (or using built-in LED/RGB LED)
|
||||
- User button for manual control (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **LED**: Uses `RGB_BUILTIN` if defined, otherwise pin 2 (supports both RGB LED and regular LED with PWM brightness control)
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Preferences`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **LED pin configuration** (if not using built-in LED):
|
||||
```cpp
|
||||
const uint8_t ledPin = 2; // Set your LED pin here
|
||||
```
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for the Light On/Off manual control. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterDimmableLight.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Initial state: ON | brightness: 15
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
Light OnOff changed to ON
|
||||
Light Brightness changed to 128
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Short press of the button**: Toggle light on/off
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a dimmable light in your Home app
|
||||
7. You can control both the on/off state and brightness level (0-100%)
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The dimmable light will appear in your Alexa app
|
||||
6. You can control brightness using voice commands like "Alexa, set light to 50 percent"
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can control brightness using voice commands or the slider in the app
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterDimmableLight example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, LED), configures Wi-Fi (if needed), sets up the Matter endpoint, restores the last known state (on/off and brightness) from `Preferences`, and registers callbacks for state changes.
|
||||
2. **`loop()`**: Checks the Matter commissioning state, handles button input for toggling the light and factory reset, and allows the Matter stack to process events.
|
||||
3. **Callbacks**:
|
||||
- `setLightState()`: Controls the physical LED with brightness level (supports both RGB LED and regular LED with PWM).
|
||||
- `onChangeOnOff()`: Handles on/off state changes.
|
||||
- `onChangeBrightness()`: Handles brightness level changes (0-255).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **LED not responding or brightness not working**: Verify pin configurations and connections. For non-RGB LEDs, ensure the pin supports PWM (analogWrite)
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Dimmable Light Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_dimmable_light.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,186 @@
|
||||
// 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
#include <Preferences.h>
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Dimmable Plugin Endpoint
|
||||
MatterDimmablePlugin DimmablePlugin;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// it will keep last OnOff & Level state stored, using Preferences
|
||||
Preferences matterPref;
|
||||
const char *onOffPrefKey = "OnOff";
|
||||
const char *levelPrefKey = "Level";
|
||||
|
||||
// set your board RGB LED pin here
|
||||
#ifdef RGB_BUILTIN
|
||||
const uint8_t pluginPin = RGB_BUILTIN; // Using built-in RGB LED for visualization
|
||||
#else
|
||||
const uint8_t pluginPin = 2; // Set your pin here if your board has not defined RGB_BUILTIN
|
||||
#warning "Do not forget to set the RGB LED pin"
|
||||
#endif
|
||||
|
||||
// set your board USER BUTTON pin here
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// Button control
|
||||
uint32_t button_time_stamp = 0; // debouncing control
|
||||
bool button_state = false; // false = released | true = pressed
|
||||
const uint32_t debounceTime = 250; // button debouncing time (ms)
|
||||
const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||
|
||||
// Set the RGB LED Plugin output based on the current state and level
|
||||
bool setPluginState(bool state, uint8_t level) {
|
||||
Serial.printf("User Callback :: New Plugin State = %s, Level = %d\r\n", state ? "ON" : "OFF", level);
|
||||
if (state) {
|
||||
// Plugin is ON - set RGB LED level (0-255 maps to 0-100% power)
|
||||
#ifdef RGB_BUILTIN
|
||||
rgbLedWrite(pluginPin, level, level, level);
|
||||
#else
|
||||
analogWrite(pluginPin, level);
|
||||
#endif
|
||||
} else {
|
||||
// Plugin is OFF - turn off output
|
||||
#ifndef RGB_BUILTIN
|
||||
// After analogWrite(), it is necessary to set the GPIO to digital mode first
|
||||
pinMode(pluginPin, OUTPUT);
|
||||
#endif
|
||||
digitalWrite(pluginPin, LOW);
|
||||
}
|
||||
// store last Level and OnOff state for when the Plugin is restarted / power goes off
|
||||
matterPref.putUChar(levelPrefKey, level);
|
||||
matterPref.putBool(onOffPrefKey, state);
|
||||
// This callback must return the success state to Matter core
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) GPIO that will act as a toggle switch
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
// Initialize the RGB LED (plugin) GPIO
|
||||
pinMode(pluginPin, OUTPUT);
|
||||
digitalWrite(pluginPin, LOW); // Start with plugin off
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// Initialize Matter EndPoint
|
||||
matterPref.begin("MatterPrefs", false);
|
||||
// default OnOff state is OFF if not stored before
|
||||
bool lastOnOffState = matterPref.getBool(onOffPrefKey, false);
|
||||
// default level ~= 25% (64/255)
|
||||
uint8_t lastLevel = matterPref.getUChar(levelPrefKey, 64);
|
||||
DimmablePlugin.begin(lastOnOffState, lastLevel);
|
||||
// set the callback function to handle the Plugin state change
|
||||
DimmablePlugin.onChange(setPluginState);
|
||||
|
||||
// lambda functions are used to set the attribute change callbacks
|
||||
DimmablePlugin.onChangeOnOff([](bool state) {
|
||||
Serial.printf("Plugin OnOff changed to %s\r\n", state ? "ON" : "OFF");
|
||||
return true;
|
||||
});
|
||||
DimmablePlugin.onChangeLevel([](uint8_t level) {
|
||||
Serial.printf("Plugin Level changed to %d\r\n", level);
|
||||
return true;
|
||||
});
|
||||
|
||||
// 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 the network. Ready for use.");
|
||||
Serial.printf("Initial state: %s | level: %d\r\n", DimmablePlugin ? "ON" : "OFF", DimmablePlugin.getLevel());
|
||||
// configure the Plugin based on initial on-off state and level
|
||||
DimmablePlugin.updateAccessory();
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Check Matter Plugin 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 Plugin 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 | level: %d\r\n", DimmablePlugin ? "ON" : "OFF", DimmablePlugin.getLevel());
|
||||
// configure the Plugin based on initial on-off state and level
|
||||
DimmablePlugin.updateAccessory();
|
||||
Serial.println("Matter Node is commissioned and connected to the network. Ready for use.");
|
||||
}
|
||||
|
||||
// A button is also used to control the plugin
|
||||
// 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 Plugin toggle switch or to decommission it
|
||||
uint32_t time_diff = millis() - button_time_stamp;
|
||||
if (digitalRead(buttonPin) == HIGH && button_state && time_diff > debounceTime) {
|
||||
// Toggle button is released - toggle the plugin
|
||||
Serial.println("User button released. Toggling Plugin!");
|
||||
DimmablePlugin.toggle(); // Matter Controller also can see the change
|
||||
button_state = false; // released
|
||||
}
|
||||
|
||||
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||
if (button_state && time_diff > decommissioningTimeout) {
|
||||
Serial.println("Decommissioning the Plugin Matter Accessory. It shall be commissioned again.");
|
||||
DimmablePlugin = false; // turn the plugin off
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissioning again, reboot takes a second or so
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
# Matter Dimmable Plugin Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible dimmable plugin unit (power outlet with level control) device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device control via smart home ecosystems, and state persistence for dimmable power control applications.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Relay/Dimmer | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------------ | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a dimmable plugin unit (power outlet with level control) device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- On/off control and power level control (0-255 levels)
|
||||
- State persistence using `Preferences` library
|
||||
- Button control for toggling plugin and factory reset
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- Power relay/dimmer module or RGB LED for visualization (for testing, uses built-in RGB LED if available)
|
||||
- User button for manual control (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **RGB LED/Relay/Dimmer Pin**: Uses `RGB_BUILTIN` if defined (for testing with RGB LED visualization), otherwise pin 2. For production use, connect this to a PWM-capable pin for dimmer control or relay control pin.
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Preferences`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **Power relay/dimmer pin configuration** (if not using built-in LED):
|
||||
For production use, change this to a PWM-capable GPIO pin connected to your dimmer control module:
|
||||
```cpp
|
||||
const uint8_t pluginPin = 2; // Set your PWM-capable pin here for dimmer control
|
||||
```
|
||||
|
||||
**Note**: The example uses `RGB_BUILTIN` if available on your board (e.g., ESP32-S3, ESP32-C3) to visually demonstrate the level control. The RGB LED brightness will change based on the power level (0-255). For boards without RGB LED, it falls back to a regular pin with PWM support.
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for the Plugin On/Off manual control. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterDimmablePlugin.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Initial state: OFF | level: 64
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
Plugin OnOff changed to ON
|
||||
Plugin Level changed to 128
|
||||
User Callback :: New Plugin State = ON, Level = 128
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Short press of the button**: Toggle plugin on/off
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### State Persistence
|
||||
|
||||
The device saves the last known on/off state and power level using the `Preferences` library. After a power cycle or restart:
|
||||
|
||||
- The device will restore to the last saved state (ON or OFF) and power level
|
||||
- Default state is OFF with level 64 (25%) if no previous state was saved
|
||||
- The Matter controller will be notified of the restored state
|
||||
- The relay/dimmer will reflect the restored state and level
|
||||
|
||||
### Power Relay/Dimmer Integration
|
||||
|
||||
For production use with a power relay or dimmer module:
|
||||
|
||||
1. **For Dimmer Control (PWM-based)**:
|
||||
- Connect the dimmer module to your ESP32:
|
||||
- Dimmer VCC → ESP32 3.3 V or 5 V (check dimmer module specifications)
|
||||
- Dimmer GND → ESP32 GND
|
||||
- Dimmer PWM/Control → ESP32 GPIO pin with PWM support (configured as `pluginPin`)
|
||||
- Update the pin configuration in the sketch:
|
||||
```cpp
|
||||
const uint8_t pluginPin = 2; // Your PWM-capable pin for dimmer control
|
||||
```
|
||||
- The level (0-255) will control the dimmer output power (0% to 100%)
|
||||
|
||||
2. **For Relay Control (On/Off only)**:
|
||||
- Connect the relay module to your ESP32:
|
||||
- Relay VCC → ESP32 3.3 V or 5 V (check relay module specifications)
|
||||
- Relay GND → ESP32 GND
|
||||
- Relay IN → ESP32 GPIO pin (configured as `pluginPin`)
|
||||
- Update the pin configuration in the sketch:
|
||||
```cpp
|
||||
const uint8_t pluginPin = 2; // Your relay control pin
|
||||
```
|
||||
- Note: When using a relay, the level control will still work but the relay will only switch on/off based on the state
|
||||
|
||||
3. **Test the relay/dimmer** by controlling it via Matter app - the device should respond to both on/off and level changes
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a dimmable outlet/switch in your Home app
|
||||
7. You can control both the on/off state and power level (0-100%)
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The dimmable plugin will appear in your Alexa app
|
||||
6. You can control power level using voice commands like "Alexa, set outlet to 50 percent"
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can control power level using voice commands or the slider in the app
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterDimmablePlugin example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, relay/dimmer pin), configures Wi-Fi (if needed), initializes `Preferences` library, sets up the Matter plugin endpoint with the last saved state (defaults to OFF with level 64 if not previously saved), registers callback functions, and starts the Matter stack.
|
||||
|
||||
2. **`loop()`**: Checks the Matter commissioning state, handles button input for toggling the plugin and factory reset, and allows the Matter stack to process events.
|
||||
|
||||
3. **Callbacks**:
|
||||
- `setPluginState()`: Controls the physical relay/dimmer based on the on/off state and power level, saves the state to `Preferences` for persistence, and prints the state change to Serial Monitor.
|
||||
- `onChangeOnOff()`: Handles on/off state changes.
|
||||
- `onChangeLevel()`: Handles power level changes (0-255).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Relay/Dimmer not responding**: Verify pin configurations and connections. For dimmer modules, ensure the pin supports PWM (analogWrite). For relay modules, ensure proper power supply and wiring
|
||||
- **Level control not working**: For dimmer control, verify the pin supports PWM. Check that `analogWrite()` or `rgbLedWrite()` (for RGB LED) is working correctly on your board. On boards with RGB LED, the brightness will change based on the level value (0-255)
|
||||
- **State not persisting**: Check that the `Preferences` library is properly initialized and that flash memory is not corrupted
|
||||
- **Relay not switching**: For relay modules, verify the control signal voltage levels match your relay module requirements (some relays need 5 V, others work with 3.3 V)
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Dimmable Plugin Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_dimmable_plugin.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,215 @@
|
||||
// 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
#include <Preferences.h>
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Color Light Endpoint
|
||||
MatterEnhancedColorLight EnhancedColorLight;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// It will use HSV color to control all Matter Attribute Changes
|
||||
HsvColor_t currentHSVColor = {0, 0, 0};
|
||||
|
||||
// it will keep last OnOff & HSV Color state stored, using Preferences
|
||||
Preferences matterPref;
|
||||
const char *onOffPrefKey = "OnOff";
|
||||
const char *hsvColorPrefKey = "HSV";
|
||||
|
||||
// set your board RGB LED pin here
|
||||
#ifdef RGB_BUILTIN
|
||||
const uint8_t ledPin = RGB_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 RGB LED pin"
|
||||
#endif
|
||||
|
||||
// set your board USER BUTTON pin here
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||
|
||||
// Set the RGB LED Light based on the current state of the Enhanced Color Light
|
||||
bool setLightState(bool state, espHsvColor_t colorHSV, uint8_t brighteness, uint16_t temperature_Mireds) {
|
||||
|
||||
if (state) {
|
||||
#ifdef RGB_BUILTIN
|
||||
// currentHSVColor keeps final color result
|
||||
espRgbColor_t rgbColor = espHsvColorToRgbColor(currentHSVColor);
|
||||
// set the RGB LED
|
||||
rgbLedWrite(ledPin, rgbColor.r, rgbColor.g, rgbColor.b);
|
||||
#else
|
||||
// No Color RGB LED, just use the HSV value (brightness) to control the LED
|
||||
analogWrite(ledPin, colorHSV.v);
|
||||
#endif
|
||||
} else {
|
||||
#ifndef RGB_BUILTIN
|
||||
// after analogWrite(), it is necessary to set the GPIO to digital mode first
|
||||
pinMode(ledPin, OUTPUT);
|
||||
#endif
|
||||
digitalWrite(ledPin, LOW);
|
||||
}
|
||||
// store last HSV Color and OnOff state for when the Light is restarted / power goes off
|
||||
matterPref.putBool(onOffPrefKey, state);
|
||||
matterPref.putUInt(hsvColorPrefKey, currentHSVColor.h << 16 | currentHSVColor.s << 8 | currentHSVColor.v);
|
||||
// This callback must return the success state to Matter core
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// Initialize Matter EndPoint
|
||||
matterPref.begin("MatterPrefs", false);
|
||||
// default OnOff state is ON if not stored before
|
||||
bool lastOnOffState = matterPref.getBool(onOffPrefKey, true);
|
||||
// default HSV color is (21, 216, 25) - Warm White Color at 10% intensity
|
||||
uint32_t prefHsvColor = matterPref.getUInt(hsvColorPrefKey, 21 << 16 | 216 << 8 | 25);
|
||||
currentHSVColor = {uint8_t(prefHsvColor >> 16), uint8_t(prefHsvColor >> 8), uint8_t(prefHsvColor)};
|
||||
EnhancedColorLight.begin(lastOnOffState, currentHSVColor);
|
||||
// set the callback function to handle the Light state change
|
||||
EnhancedColorLight.onChange(setLightState);
|
||||
|
||||
// lambda functions are used to set the attribute change callbacks
|
||||
EnhancedColorLight.onChangeOnOff([](bool state) {
|
||||
Serial.printf("Light OnOff changed to %s\r\n", state ? "ON" : "OFF");
|
||||
return true;
|
||||
});
|
||||
EnhancedColorLight.onChangeColorTemperature([](uint16_t colorTemperature) {
|
||||
Serial.printf("Light Color Temperature changed to %d\r\n", colorTemperature);
|
||||
// get correspondent Hue and Saturation of the color temperature
|
||||
HsvColor_t hsvTemperature = espRgbColorToHsvColor(espCTToRgbColor(colorTemperature));
|
||||
// keep previous the brightness and just change the Hue and Saturation
|
||||
currentHSVColor.h = hsvTemperature.h;
|
||||
currentHSVColor.s = hsvTemperature.s;
|
||||
return true;
|
||||
});
|
||||
EnhancedColorLight.onChangeBrightness([](uint8_t brightness) {
|
||||
Serial.printf("Light brightness changed to %d\r\n", brightness);
|
||||
// change current brightness (HSV value)
|
||||
currentHSVColor.v = brightness;
|
||||
return true;
|
||||
});
|
||||
EnhancedColorLight.onChangeColorHSV([](HsvColor_t hsvColor) {
|
||||
Serial.printf("Light HSV Color changed to (%d,%d,%d)\r\n", hsvColor.h, hsvColor.s, hsvColor.v);
|
||||
// keep the current brightness and just change Hue and Saturation
|
||||
currentHSVColor.h = hsvColor.h;
|
||||
currentHSVColor.s = hsvColor.s;
|
||||
return true;
|
||||
});
|
||||
|
||||
// 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 the network. Ready for use.");
|
||||
Serial.printf(
|
||||
"Initial state: %s | RGB Color: (%d,%d,%d) \r\n", EnhancedColorLight ? "ON" : "OFF", EnhancedColorLight.getColorRGB().r,
|
||||
EnhancedColorLight.getColorRGB().g, EnhancedColorLight.getColorRGB().b
|
||||
);
|
||||
// configure the Light based on initial on-off state and its color
|
||||
EnhancedColorLight.updateAccessory();
|
||||
}
|
||||
}
|
||||
|
||||
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 | RGB Color: (%d,%d,%d) \r\n", EnhancedColorLight ? "ON" : "OFF", EnhancedColorLight.getColorRGB().r,
|
||||
EnhancedColorLight.getColorRGB().g, EnhancedColorLight.getColorRGB().b
|
||||
);
|
||||
// configure the Light based on initial on-off state and its color
|
||||
EnhancedColorLight.updateAccessory();
|
||||
Serial.println("Matter Node is commissioned and connected to the network. 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!");
|
||||
EnhancedColorLight.toggle(); // Matter Controller also can see the change
|
||||
}
|
||||
|
||||
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||
if (button_state && time_diff > decommissioningTimeout) {
|
||||
Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again.");
|
||||
EnhancedColorLight = false; // turn the light off
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
# Matter Enhanced Color Light Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible enhanced color light device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device control via smart home ecosystems, and manual control using a physical button. The enhanced color light provides additional features including color temperature control and brightness adjustment.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | RGB LED | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for an enhanced color light device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- RGB color control with HSV color model
|
||||
- Color temperature control (warm to cool white)
|
||||
- Brightness control (0-255 levels)
|
||||
- State persistence using `Preferences` library
|
||||
- Button control for toggling light and factory reset
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- RGB LED connected to GPIO pins (or using built-in RGB LED)
|
||||
- User button for manual control (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **RGB LED**: Uses `RGB_BUILTIN` if defined, otherwise pin 2
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Preferences`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **LED pin configuration** (if not using built-in RGB LED):
|
||||
```cpp
|
||||
const uint8_t ledPin = 2; // Set your RGB LED pin here
|
||||
```
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for the Light On/Off manual control. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterEnhancedColorLight.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Initial state: ON | RGB Color: (255,255,255)
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
Light OnOff changed to ON
|
||||
Light Color Temperature changed to 370
|
||||
Light brightness changed to 128
|
||||
Light HSV Color changed to (120,255,255)
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Short press of the button**: Toggle light on/off
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as an enhanced color light in your Home app
|
||||
7. You can control RGB color, color temperature (warm/cool white), and brightness
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The enhanced color light will appear in your Alexa app
|
||||
6. You can control color, color temperature, and brightness using voice commands or the app
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can control color, color temperature, and brightness using voice commands or the app controls
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterEnhancedColorLight example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, LED), configures Wi-Fi (if needed), sets up the Matter endpoint, restores the last known state (on/off and HSV color) from `Preferences`, and registers callbacks for state changes.
|
||||
2. **`loop()`**: Checks the Matter commissioning state, handles button input for toggling the light and factory reset, and allows the Matter stack to process events.
|
||||
3. **Callbacks**:
|
||||
- `setLightState()`: Controls the physical RGB LED with state, HSV color, brightness, and color temperature parameters.
|
||||
- `onChangeOnOff()`: Handles on/off state changes.
|
||||
- `onChangeColorHSV()`: Handles HSV color changes (Hue and Saturation).
|
||||
- `onChangeBrightness()`: Handles brightness level changes (0-255, maps to HSV Value).
|
||||
- `onChangeColorTemperature()`: Handles color temperature changes (warm to cool white).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **RGB LED not responding**: Verify pin configurations and connections
|
||||
- **Color temperature not working**: Verify that the color temperature callback is properly handling HSV conversion
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Enhanced Color Light Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_enhanced_color_light.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,177 @@
|
||||
// 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// 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.");
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
# Matter Events Example
|
||||
|
||||
This example demonstrates how to monitor and handle Matter events using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter event handling, commissioning, and automatic decommissioning. It provides a comprehensive view of all Matter events that occur during device operation, making it useful for debugging and understanding the Matter protocol behavior.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation with comprehensive event monitoring
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Event callback handler that displays all Matter events to Serial Monitor
|
||||
- Monitors connectivity changes (Wi-Fi, Thread, Internet, IPv4/IPv6)
|
||||
- Tracks commissioning lifecycle events
|
||||
- Monitors fabric management events
|
||||
- Tracks BLE/CHIPoBLE events
|
||||
- Automatic decommissioning after 60 seconds for continuous testing
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterEvents.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning and displays Matter events:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Starting Matter Commission Test...
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
===> Got a Matter Event: CHIPoBLE Advertising Change
|
||||
===> Got a Matter Event: Commissioning Window Opened
|
||||
===> Got a Matter Event: Commissioning Session Started
|
||||
===> Got a Matter Event: Commissioning Complete
|
||||
===> Got a Matter Event: Operational Network Started
|
||||
===> Got a Matter Event: Operational Network Enabled
|
||||
===> Got a Matter Event: Internet Connectivity Change :: IPv4 Connectivity: Established - IP Address: 192.168.1.100
|
||||
===> Got a Matter Event: IPv4 Address Assigned
|
||||
===> Got a Matter Event: Server Ready
|
||||
===> Got a Matter Event: DNS-SD Initialized
|
||||
Matter Fabric not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to Wi-Fi.
|
||||
====> Decommissioning in 60 seconds. <====
|
||||
===> Got a Matter Event: Fabric Will Be Removed
|
||||
===> Got a Matter Event: Fabric Removed
|
||||
===> Got a Matter Event: Commissioning Window Opened
|
||||
Matter Node is decommissioned. Commissioning widget shall start over.
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Event Monitoring
|
||||
|
||||
The example continuously monitors and displays Matter events to the Serial Monitor. This includes:
|
||||
|
||||
- **Connectivity Events**: Wi-Fi, Thread, Internet connectivity changes, IP address assignments
|
||||
- **Commissioning Events**: Commissioning session start/stop, commissioning window open/close, commissioning complete
|
||||
- **Fabric Events**: Fabric committed, updated, removed
|
||||
- **BLE Events**: CHIPoBLE connection established/closed, advertising changes
|
||||
- **Network Events**: Operational network started/enabled, interface IP address changes
|
||||
- **Service Events**: Service connectivity changes, provisioning changes, DNS-SD events
|
||||
- **System Events**: Server ready, OTA state changes, time sync changes, fail-safe timer expiration
|
||||
|
||||
### Test Cycle
|
||||
|
||||
The device operates in a continuous test cycle:
|
||||
|
||||
1. **Commissioning Phase**: The device waits for Matter commissioning and displays all related events.
|
||||
2. **Commissioned Phase**: Once commissioned, the device is connected to the Matter network and ready for use. All network and service events are displayed.
|
||||
3. **Automatic Decommissioning**: After 60 seconds, the device automatically decommissions itself.
|
||||
4. **Repeat**: The cycle repeats, allowing you to test the commissioning process multiple times and observe all events.
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device during each test cycle. Monitor the Serial Monitor to see all events that occur during the commissioning process.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. Monitor the Serial Monitor to see all Matter events during commissioning
|
||||
7. The device will appear as an on/off light in your Home app
|
||||
8. After 60 seconds, the device will automatically decommission and the cycle will repeat
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. Monitor the Serial Monitor to see all Matter events during commissioning
|
||||
6. The light will appear in your Alexa app
|
||||
7. After 60 seconds, the device will automatically decommission and the cycle will repeat
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. Monitor the Serial Monitor to see all Matter events during commissioning
|
||||
7. After 60 seconds, the device will automatically decommission and the cycle will repeat
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterEvents example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes Serial communication, configures Wi-Fi (if needed), sets up the Matter On/Off Light endpoint, registers the Matter event callback handler, and starts the Matter stack.
|
||||
2. **`loop()`**: Checks the Matter commissioning state, displays pairing information when not commissioned, waits for commissioning, and then automatically decommissions after 60 seconds to repeat the cycle.
|
||||
3. **`onMatterEvent()`**: Comprehensive event callback handler that processes and displays all Matter events, including connectivity changes, commissioning events, fabric management, BLE events, and system events.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **No events displayed**: Verify that the event callback is properly registered using `Matter.onEvent()`
|
||||
- **Failed to commission**: Try waiting for the next cycle after decommissioning. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
- **Device keeps decommissioning**: This is expected behavior - the device automatically decommissions after 60 seconds to allow continuous testing and event monitoring
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,211 @@
|
||||
// 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Fan Endpoint - On/Off control + Speed Percent Control + Fan Modes
|
||||
MatterFan Fan;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// set your board USER BUTTON pin here - used for toggling On/Off and decommission the Matter Node
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||
|
||||
// set your board Analog Pin here - used for changing the Fan speed
|
||||
const uint8_t analogPin = A0; // Analog Pin depends on each board
|
||||
|
||||
// set your board PWM Pin here - used for controlling the Fan speed (DC motor example)
|
||||
// for this example, it will use the builtin board RGB LED to simulate the Fan DC motor using its brightness
|
||||
#ifdef RGB_BUILTIN
|
||||
const uint8_t dcMotorPin = RGB_BUILTIN;
|
||||
#else
|
||||
const uint8_t dcMotorPin = 2; // Set your pin here if your board has not defined LED_BUILTIN
|
||||
#warning "Do not forget to set the RGB LED pin"
|
||||
#endif
|
||||
|
||||
void fanDCMotorDrive(bool fanState, uint8_t speedPercent) {
|
||||
// drive the Fan DC motor
|
||||
if (fanState == false) {
|
||||
// turn off the Fan
|
||||
#ifndef RGB_BUILTIN
|
||||
// after analogWrite(), it is necessary to set the GPIO to digital mode first
|
||||
pinMode(dcMotorPin, OUTPUT);
|
||||
#endif
|
||||
digitalWrite(dcMotorPin, LOW);
|
||||
} else {
|
||||
// set the Fan speed
|
||||
uint8_t fanDCMotorPWM = map(speedPercent, 0, 100, 0, 255);
|
||||
#ifdef RGB_BUILTIN
|
||||
rgbLedWrite(dcMotorPin, fanDCMotorPWM, fanDCMotorPWM, fanDCMotorPWM);
|
||||
#else
|
||||
analogWrite(dcMotorPin, fanDCMotorPWM);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) GPIO that will toggle the Fan (On/Off) and decommission the Matter Node
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
// Initialize the Analog Pin A0 used to read input voltage and to set the Fan speed accordingly
|
||||
pinMode(analogPin, INPUT);
|
||||
analogReadResolution(10); // 10 bits resolution reading 0..1023
|
||||
// Initialize the PWM output pin for a Fan DC motor
|
||||
pinMode(dcMotorPin, OUTPUT);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// On Boot or Reset, Fan is set at 0% speed, OFF, changing between OFF, ON, SMART and HIGH
|
||||
Fan.begin(0, MatterFan::FAN_MODE_OFF, MatterFan::FAN_MODE_SEQ_OFF_HIGH);
|
||||
|
||||
// callback functions would control Fan motor
|
||||
// the Matter Controller will send new data whenever the User APP or Automation request
|
||||
|
||||
// single feature callbacks take place before the generic (all features) callback
|
||||
// This callback will be executed whenever the speed percent matter attribute is updated
|
||||
Fan.onChangeSpeedPercent([](uint8_t speedPercent) {
|
||||
// setting speed to Zero, while the Fan is ON, shall turn the Fan OFF
|
||||
if (speedPercent == MatterFan::OFF_SPEED && Fan.getMode() != MatterFan::FAN_MODE_OFF) {
|
||||
// ATTR_SET do not update the attribute, just SET it to avoid infinite loop
|
||||
return Fan.setOnOff(false, Fan.ATTR_SET);
|
||||
}
|
||||
// changing the speed to higher than Zero, while the Fan is OFF, shall turn the Fan ON
|
||||
if (speedPercent > MatterFan::OFF_SPEED && Fan.getMode() == MatterFan::FAN_MODE_OFF) {
|
||||
// ATTR_SET do not update the attribute, just SET it to avoid infinite loop
|
||||
return Fan.setOnOff(true, Fan.ATTR_SET);
|
||||
}
|
||||
// for other case, just return true
|
||||
return true;
|
||||
});
|
||||
|
||||
// This callback will be executed whenever the fan mode matter attribute is updated
|
||||
// This will take action when user APP starts the Fan by changing the mode
|
||||
Fan.onChangeMode([](MatterFan::FanMode_t fanMode) {
|
||||
// when the Fan is turned ON using Mode Selection, while it is OFF, shall start it by setting the speed to 50%
|
||||
if (Fan.getSpeedPercent() == MatterFan::OFF_SPEED && fanMode != MatterFan::FAN_MODE_OFF) {
|
||||
Serial.printf("Fan set to %s mode -- speed percentage will go to 50%%\r\n", Fan.getFanModeString(fanMode));
|
||||
// ATTR_SET do not update the attribute, just SET it to avoid infinite loop
|
||||
return Fan.setSpeedPercent(50, Fan.ATTR_SET);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// Generic callback will be executed as soon as a single feature callback is done
|
||||
// In this example, it will just print status messages
|
||||
Fan.onChange([](MatterFan::FanMode_t fanMode, uint8_t speedPercent) {
|
||||
// just report state
|
||||
Serial.printf("Fan State: Mode %s | %d%% speed.\r\n", Fan.getFanModeString(fanMode), speedPercent);
|
||||
// drive the Fan DC motor
|
||||
fanDCMotorDrive(fanMode != MatterFan::FAN_MODE_OFF, speedPercent);
|
||||
// returns success
|
||||
return true;
|
||||
});
|
||||
|
||||
// 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 the network. Ready for use.");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Check Matter Accessory 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 Generic Switch 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 the network. Ready for use.");
|
||||
}
|
||||
|
||||
// A builtin button is used to trigger and send a command to the Matter Controller
|
||||
// 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 smart button 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
|
||||
// button is released - toggle Fan On/Off
|
||||
Fan.toggle();
|
||||
Serial.printf("User button released. Setting the Fan %s.\r\n", Fan > 0 ? "ON" : "OFF");
|
||||
}
|
||||
|
||||
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||
if (button_state && time_diff > decommissioningTimeout) {
|
||||
Serial.println("Decommissioning Fan Matter Accessory. It shall be commissioned again.");
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||
}
|
||||
|
||||
// checks Analog pin and adjust the speed only if it has changed
|
||||
static int lastRead = 0;
|
||||
// analog values (0..1023) / 103 => mapped into 10 steps (0..9)
|
||||
int anaVal = analogRead(analogPin) / 103;
|
||||
if (lastRead != anaVal) {
|
||||
// speed percent moves in steps of 10. Range is 10..100
|
||||
if (Fan.setSpeedPercent((anaVal + 1) * 10)) {
|
||||
lastRead = anaVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
# Matter Fan Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible fan device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device control via smart home ecosystems, manual control using a physical button, and analog input for speed control.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | PWM Pin | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a fan device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- On/Off control
|
||||
- Speed control (0-100% in steps of 10%)
|
||||
- Fan modes (OFF, ON, SMART, HIGH)
|
||||
- Analog input for manual speed adjustment
|
||||
- PWM output for DC motor control (simulated with RGB LED brightness)
|
||||
- Button control for toggling fan and factory reset
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- PWM-capable pin for DC motor control (uses RGB_BUILTIN or pin 2 by default)
|
||||
- Analog input pin (A0) for speed control via potentiometer or similar
|
||||
- User button for manual control (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **DC Motor PWM Pin**: Uses `RGB_BUILTIN` if defined, otherwise pin 2 (for controlling fan speed)
|
||||
- **Analog Input Pin**: A0 (for reading speed control input, 0-1023 mapped to 10-100% speed)
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **DC Motor PWM pin configuration** (if not using built-in RGB LED):
|
||||
```cpp
|
||||
const uint8_t dcMotorPin = 2; // Set your PWM pin here
|
||||
```
|
||||
|
||||
3. **Analog input pin configuration** (optional):
|
||||
By default, analog pin A0 is used for speed control. You can change this if needed.
|
||||
```cpp
|
||||
const uint8_t analogPin = A0; // Set your analog pin here
|
||||
```
|
||||
|
||||
4. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for the Fan On/Off manual control and factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterFan.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
Fan State: Mode OFF | 0% speed.
|
||||
User button released. Setting the Fan ON.
|
||||
Fan State: Mode ON | 50% speed.
|
||||
Fan set to SMART mode -- speed percentage will go to 50%
|
||||
Fan State: Mode SMART | 50% speed.
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Short press of the button**: Toggle fan on/off
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Analog Speed Control
|
||||
|
||||
The analog input pin (A0) allows manual speed adjustment:
|
||||
|
||||
- Connect a potentiometer or similar analog input to pin A0
|
||||
- Analog values (0-1023) are mapped to speed percentages (10-100%) in steps of 10%
|
||||
- The speed automatically updates when the analog input changes
|
||||
- Speed changes are synchronized with the Matter controller
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a fan in your Home app
|
||||
7. You can control on/off, speed (0-100%), and fan modes (OFF, ON, SMART, HIGH)
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The fan will appear in your Alexa app
|
||||
6. You can control speed and modes using voice commands like "Alexa, set fan to 50 percent" or "Alexa, set fan to high"
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can control speed and modes using voice commands or the app controls
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterFan example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, analog input, PWM output), configures Wi-Fi (if needed), sets up the Matter Fan endpoint with initial state (OFF, 0% speed), and registers callbacks for state changes.
|
||||
2. **`loop()`**: Checks the Matter commissioning state, handles button input for toggling the fan and factory reset, reads analog input to adjust fan speed, and allows the Matter stack to process events.
|
||||
3. **Callbacks**:
|
||||
- `onChangeSpeedPercent()`: Handles speed percentage changes (0% to 100%). Automatically turns fan on/off based on speed.
|
||||
- `onChangeMode()`: Handles fan mode changes (OFF, ON, SMART, HIGH). Automatically sets speed to 50% when switching from OFF to another mode.
|
||||
- `onChange()`: Generic callback that controls the DC motor via PWM and reports the current state.
|
||||
- `fanDCMotorDrive()`: Drives the DC motor (or simulates it with RGB LED brightness) based on fan state and speed.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Fan speed not responding**: Verify PWM pin configuration and connections. For DC motor control, ensure the pin supports PWM output
|
||||
- **Analog input not working**: Verify analog pin configuration and that the input voltage is within the ESP32's ADC range (0-3.3V typically)
|
||||
- **Speed changes not synchronized**: The analog input is read continuously, and speed updates only when the value changes by a step (0-9 steps mapped to 10-100%)
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Fan Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_fan.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,139 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* This example is an example code that will create a Matter Device which can be
|
||||
* commissioned and controlled from a Matter Environment APP.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Matter Humidity Sensor Endpoint
|
||||
MatterHumiditySensor SimulatedHumiditySensor;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#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
|
||||
|
||||
// Simulate a humidity sensor - add your preferred humidity sensor library code here
|
||||
float getSimulatedHumidity() {
|
||||
// The Endpoint implementation keeps an uint16_t as internal value information,
|
||||
// which stores data in 1/100th of humidity percent
|
||||
static float simulatedHumidityHWSensor = 10.0;
|
||||
|
||||
// it will increase from 10% to 30% in 0.5% steps to simulate a humidity sensor
|
||||
simulatedHumidityHWSensor = simulatedHumidityHWSensor + 0.5;
|
||||
if (simulatedHumidityHWSensor > 30) {
|
||||
simulatedHumidityHWSensor = 10;
|
||||
}
|
||||
|
||||
return simulatedHumidityHWSensor;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// set initial humidity sensor measurement
|
||||
// Simulated Sensor - it shall initially print 95% and then move to the 10% to 30% humidity range
|
||||
SimulatedHumiditySensor.begin(95.00);
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
|
||||
// Check Matter Accessory 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 Humidity Sensor 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 the network. Ready for use.");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint32_t timeCounter = 0;
|
||||
|
||||
// Print the current humidity value every 5s
|
||||
if (!(timeCounter++ % 10)) { // delaying for 500ms x 10 = 5s
|
||||
// Print the current humidity value
|
||||
Serial.printf("Current Humidity is %.02f%%\r\n", SimulatedHumiditySensor.getHumidity());
|
||||
// Update Humidity from the (Simulated) Hardware Sensor
|
||||
// Matter APP shall display the updated humidity percent
|
||||
SimulatedHumiditySensor.setHumidity(getSimulatedHumidity());
|
||||
}
|
||||
|
||||
// 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 Humidity Sensor Matter Accessory. It shall be commissioned again.");
|
||||
Matter.decommission();
|
||||
}
|
||||
|
||||
delay(500);
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
# Matter Humidity Sensor Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible humidity sensor device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, sensor data reporting to smart home ecosystems, and automatic simulation of humidity readings.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a humidity sensor device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Humidity measurement reporting (0-100%)
|
||||
- Automatic simulation of humidity readings (10% to 30% range)
|
||||
- Periodic sensor updates every 5 seconds
|
||||
- Button control for factory reset (decommission)
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- User button for factory reset (uses BOOT button by default)
|
||||
- Optional: Connect a real humidity sensor (DHT11, DHT22, SHT31, etc.) and replace the simulation function
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
3. **Real sensor integration** (optional):
|
||||
To use a real humidity sensor, replace the `getSimulatedHumidity()` function with your sensor reading code. The function should return a float value representing humidity percentage (0-100%).
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterHumiditySensor.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
Current Humidity is 95.00%
|
||||
Current Humidity is 10.50%
|
||||
Current Humidity is 11.00%
|
||||
Current Humidity is 11.50%
|
||||
...
|
||||
Current Humidity is 30.00%
|
||||
Current Humidity is 10.00%
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides factory reset functionality:
|
||||
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Sensor Simulation
|
||||
|
||||
The example includes a simulated humidity sensor that:
|
||||
|
||||
- Starts at 95% humidity (initial value)
|
||||
- Cycles through 10% to 30% humidity range
|
||||
- Increases in 0.5% steps
|
||||
- Updates every 5 seconds
|
||||
- Resets to 10% when reaching 30%
|
||||
|
||||
To use a real humidity sensor, replace the `getSimulatedHumidity()` function with your sensor library code. For example, with a DHT22:
|
||||
|
||||
```cpp
|
||||
#include <DHT.h>
|
||||
DHT dht(DHT_PIN, DHT22);
|
||||
|
||||
float getSimulatedHumidity() {
|
||||
return dht.readHumidity();
|
||||
}
|
||||
```
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a humidity sensor in your Home app
|
||||
7. You can monitor the humidity readings and set up automations based on humidity levels
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The humidity sensor will appear in your Alexa app
|
||||
6. You can monitor humidity readings and create routines based on humidity levels
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can monitor humidity readings and create automations based on humidity levels
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterHumiditySensor example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button), configures Wi-Fi (if needed), sets up the Matter Humidity Sensor endpoint with initial value (95%), and waits for Matter commissioning.
|
||||
2. **`loop()`**: Displays the current humidity value every 5 seconds, updates the sensor reading from the simulated hardware sensor, handles button input for factory reset, and allows the Matter stack to process events.
|
||||
3. **`getSimulatedHumidity()`**: Simulates a hardware humidity sensor by cycling through values from 10% to 30% in 0.5% steps. Replace this function with your actual sensor reading code.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Humidity readings not updating**: Check that the sensor simulation function is being called correctly. For real sensors, verify sensor wiring and library initialization
|
||||
<!-- vale Microsoft.Percentages = NO -->
|
||||
- **Humidity values out of range**: Ensure humidity values are between 0-100%. The Matter protocol stores values as 1/100th of a percent internally
|
||||
<!-- vale Microsoft.Percentages = YES -->
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Humidity Sensor Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_humidity_sensor.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
This example creates 6 on-off light endpoints that share the same onChangeOnOff() callback code.
|
||||
It uses Lambda Function with an extra Lambda Capture information that links the Endpoint to its individual information.
|
||||
After the Matter example is commissioned, the expected Serial output shall be similar to this:
|
||||
|
||||
Matter App Control: 'Room 1' (OnOffLight[0], Endpoint 1, GPIO 2) changed to: OFF
|
||||
Matter App Control: 'Room 1' (OnOffLight[0], Endpoint 1, GPIO 2) changed to: ON
|
||||
Matter App Control: 'Room 5' (OnOffLight[4], Endpoint 5, GPIO 10) changed to: ON
|
||||
Matter App Control: 'Room 2' (OnOffLight[1], Endpoint 2, GPIO 4) changed to: ON
|
||||
Matter App Control: 'Room 4' (OnOffLight[3], Endpoint 4, GPIO 8) changed to: ON
|
||||
Matter App Control: 'Room 6' (OnOffLight[5], Endpoint 6, GPIO 12) changed to: ON
|
||||
Matter App Control: 'Room 3' (OnOffLight[2], Endpoint 3, GPIO 6) changed to: ON
|
||||
Matter App Control: 'Room 5' (OnOffLight[4], Endpoint 5, GPIO 10) changed to: OFF
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#include <Preferences.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
// 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
|
||||
#endif
|
||||
|
||||
//number of On-Off Lights:
|
||||
const uint8_t MAX_LIGHT_NUMBER = 6;
|
||||
|
||||
// array of OnOffLight endpoints
|
||||
MatterOnOffLight OnOffLight[MAX_LIGHT_NUMBER];
|
||||
|
||||
// all pins, one for each on-off light
|
||||
uint8_t lightPins[MAX_LIGHT_NUMBER] = {2, 4, 6, 8, 10, 12}; // must replace it by the real pin for the target SoC and application
|
||||
|
||||
// friendly OnOffLights names used for printing a message in the callback
|
||||
const char *lightName[MAX_LIGHT_NUMBER] = {
|
||||
"Room 1", "Room 2", "Room 3", "Room 4", "Room 5", "Room 6",
|
||||
};
|
||||
|
||||
// simple setup() function
|
||||
void setup() {
|
||||
Serial.begin(115200); // callback will just print a message in the console
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// setup all the OnOff Light endpoint and their lambda callback functions
|
||||
for (uint8_t i = 0; i < MAX_LIGHT_NUMBER; i++) {
|
||||
pinMode(lightPins[i], OUTPUT); // set the GPIO function
|
||||
OnOffLight[i].begin(false); // off
|
||||
|
||||
// inline lambda function using capture array index -> it will just print a message in the console
|
||||
OnOffLight[i].onChangeOnOff([i](bool state) -> bool {
|
||||
// Display message with the specific light name and details
|
||||
Serial.printf(
|
||||
"Matter App Control: '%s' (OnOffLight[%d], Endpoint %d, GPIO %d) changed to: %s\r\n", lightName[i], i, OnOffLight[i].getEndPointId(), lightPins[i],
|
||||
state ? "ON" : "OFF"
|
||||
);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
// last step, starting Matter Stack
|
||||
Matter.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Check Matter Plugin 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 Plugin 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.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Matter.isDeviceConnected()) {
|
||||
Serial.println("Matter Node is commissioned and connected to the network. Ready for use.");
|
||||
} else {
|
||||
Serial.println("Matter Node is commissioned. Waiting for the network connection.");
|
||||
}
|
||||
// wait 3 seconds for the network connection
|
||||
delay(3000);
|
||||
}
|
||||
|
||||
delay(100);
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
# Matter Lambda Single Callback Many Endpoints Example
|
||||
|
||||
This example demonstrates how to create multiple Matter endpoints in a single node using a shared lambda function callback with capture in an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, multiple endpoint management, and efficient callback handling using C++ lambda functions with capture variables.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | GPIO Pins | Status |
|
||||
| --- | ---- | ------ | ----------------- | --------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation with multiple endpoints in a single node
|
||||
- Six on/off light endpoints sharing a single callback function
|
||||
- Lambda function with capture variable for efficient endpoint identification
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Each endpoint has a unique GPIO pin and friendly name
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- Optional: Six LEDs connected to GPIO pins (2, 4, 6, 8, 10, 12) for visual feedback
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
By default, the example uses six GPIO pins for the on/off lights:
|
||||
- **Light 1 (Room 1)**: GPIO 2
|
||||
- **Light 2 (Room 2)**: GPIO 4
|
||||
- **Light 3 (Room 3)**: GPIO 6
|
||||
- **Light 4 (Room 4)**: GPIO 8
|
||||
- **Light 5 (Room 5)**: GPIO 10
|
||||
- **Light 6 (Room 6)**: GPIO 12
|
||||
|
||||
You can modify the `lightPins` array to match your hardware configuration:
|
||||
|
||||
```cpp
|
||||
uint8_t lightPins[MAX_LIGHT_NUMBER] = {2, 4, 6, 8, 10, 12};
|
||||
```
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Preferences`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **GPIO pin configuration** (optional):
|
||||
Modify the `lightPins` array to match your hardware:
|
||||
```cpp
|
||||
uint8_t lightPins[MAX_LIGHT_NUMBER] = {2, 4, 6, 8, 10, 12};
|
||||
```
|
||||
|
||||
3. **Light names** (optional):
|
||||
Modify the `lightName` array to customize the friendly names:
|
||||
```cpp
|
||||
const char *lightName[MAX_LIGHT_NUMBER] = {
|
||||
"Room 1", "Room 2", "Room 3", "Room 4", "Room 5", "Room 6",
|
||||
};
|
||||
```
|
||||
|
||||
4. **Number of endpoints** (optional):
|
||||
Change `MAX_LIGHT_NUMBER` to create more or fewer endpoints:
|
||||
```cpp
|
||||
const uint8_t MAX_LIGHT_NUMBER = 6;
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterLambdaSingleCallbackManyEPs.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
Matter App Control: 'Room 1' (OnOffLight[0], Endpoint 1, GPIO 2) changed to: OFF
|
||||
Matter App Control: 'Room 1' (OnOffLight[0], Endpoint 1, GPIO 2) changed to: ON
|
||||
Matter App Control: 'Room 5' (OnOffLight[4], Endpoint 5, GPIO 10) changed to: ON
|
||||
Matter App Control: 'Room 2' (OnOffLight[1], Endpoint 2, GPIO 4) changed to: ON
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Lambda Function with Capture
|
||||
|
||||
This example demonstrates how to use C++ lambda functions with capture variables to efficiently handle multiple endpoints with a single callback function. The lambda capture `[i]` allows the callback to identify which endpoint triggered the event:
|
||||
|
||||
```cpp
|
||||
OnOffLight[i].onChangeOnOff([i](bool state) -> bool {
|
||||
Serial.printf(
|
||||
"Matter App Control: '%s' (OnOffLight[%d], Endpoint %d, GPIO %d) changed to: %s\r\n",
|
||||
lightName[i], i, OnOffLight[i].getEndPointId(), lightPins[i], state ? "ON" : "OFF"
|
||||
);
|
||||
return true;
|
||||
});
|
||||
```
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device. After commissioning, you will see six separate on/off light devices in your smart home app, each representing a different room.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as six separate on/off lights in your Home app (Room 1 through Room 6)
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The six lights will appear in your Alexa app
|
||||
6. You can control each room independently
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The six lights will appear in your Google Home app
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterLambdaSingleCallbackManyEPs example consists of the following main components:
|
||||
|
||||
1. **Arrays and Configuration**:
|
||||
- `OnOffLight[MAX_LIGHT_NUMBER]`: Array of Matter on/off light endpoints
|
||||
- `lightPins[]`: Array of GPIO pins for each light
|
||||
- `lightName[]`: Array of friendly names for each light
|
||||
|
||||
2. **`setup()`**: Configures Wi-Fi (if needed), initializes all GPIO pins, initializes all Matter endpoints, registers lambda callbacks with capture variables for each endpoint, and starts the Matter stack.
|
||||
|
||||
3. **`loop()`**: Checks the Matter commissioning state and connection status, displays appropriate messages, and allows the Matter stack to process events.
|
||||
|
||||
4. **Lambda Callback**:
|
||||
- Uses capture variable `[i]` to identify which endpoint triggered the callback
|
||||
- Displays detailed information including friendly name, array index, endpoint ID, GPIO pin, and state
|
||||
- Demonstrates efficient callback handling for multiple endpoints
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Only some endpoints appear**: Some smart home platforms may group or display endpoints differently. Check your app's device list
|
||||
- **GPIO pins not responding**: Verify pin configurations match your hardware. Ensure pins are not used by other peripherals
|
||||
- **Failed to commission**: Try erasing the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
- **Compilation errors with lambda functions**: Ensure you're using a C++11 compatible compiler (ESP32 Arduino Core 2.0+ supports this)
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,125 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Single On/Off Light Endpoint - at least one per node
|
||||
MatterOnOffLight OnOffLight;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// 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);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
Serial.println();
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print('.');
|
||||
delay(500);
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// Initialize at least one Matter EndPoint
|
||||
OnOffLight.begin();
|
||||
|
||||
// Associate a callback to the Matter Controller
|
||||
OnOffLight.onChange(onOffLightCallback);
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
|
||||
if (!Matter.isDeviceCommissioned()) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
# Matter Minimum Example
|
||||
|
||||
This example demonstrates the smallest code required to create a Matter-compatible device using an ESP32 SoC microcontroller.\
|
||||
The application showcases the minimal implementation for Matter commissioning and device control via smart home ecosystems. This is an ideal starting point for understanding Matter basics and building more complex devices.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | LED | Status |
|
||||
| --- | ---- | ------ | ----------------- | --- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Optional | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Optional | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Optional | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Optional | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Optional | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Optional | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Optional | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Minimal Matter protocol implementation for an on/off light device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Simple on/off control via Matter app
|
||||
- Button control for factory reset (decommission)
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
- Minimal code footprint - ideal for learning Matter basics
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- Optional: LED connected to GPIO pin (or using built-in LED) for visual feedback
|
||||
- Optional: User button for factory reset (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **LED**: Uses `LED_BUILTIN` if defined, otherwise pin 2
|
||||
- **Button**: Uses `BOOT_PIN` by default (only for factory reset)
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **LED pin configuration** (if not using built-in LED):
|
||||
```cpp
|
||||
const uint8_t ledPin = 2; // Set your LED pin here
|
||||
```
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterMinimum.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
```
|
||||
|
||||
After commissioning, the device will be ready for control via Matter apps. No additional status messages are printed in this minimal example.
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides factory reset functionality:
|
||||
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
Note: This minimal example does not include button toggle functionality. To add manual toggle control, you can extend the code with additional button handling logic.
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as an on/off light in your Home app
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The light will appear in your Alexa app
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterMinimum example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, LED), configures Wi-Fi (if needed), initializes the Matter on/off light endpoint, registers the callback function, and starts the Matter stack. Displays commissioning information if not yet commissioned.
|
||||
|
||||
2. **`loop()`**: Handles button input for factory reset (long press >5 seconds) and allows the Matter stack to process events. This minimal example does not include commissioning state checking in the loop - it only checks once in setup.
|
||||
|
||||
3. **`onOffLightCallback()`**: Simple callback function that controls the LED based on the on/off state received from the Matter controller. This is the minimal callback implementation.
|
||||
|
||||
## Extending the Example
|
||||
|
||||
This minimal example can be extended with additional features:
|
||||
|
||||
- **State persistence**: Add `Preferences` library to save the last known state
|
||||
- **Button toggle**: Add button press detection to toggle the light manually
|
||||
- **Commissioning status check**: Add periodic checking of commissioning state in the loop
|
||||
- **Multiple endpoints**: Add more Matter endpoints to the same node
|
||||
- **Enhanced callbacks**: Add more detailed callback functions for better control
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **LED not responding**: Verify pin configurations and connections. The LED will only respond to Matter app commands after commissioning
|
||||
- **Failed to commission**: Try erasing the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
- **LED not turning on/off**: Ensure the device is commissioned and you're controlling it via a Matter app. The minimal example only responds to Matter controller commands, not local button presses
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,137 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* This example is an example code that will create a Matter Device which can be
|
||||
* commissioned and controlled from a Matter Environment APP.
|
||||
* 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.
|
||||
*
|
||||
* The example will create a Matter Occupancy Sensor Device.
|
||||
* The Occupancy Sensor will be simulated to change its state every 2 minutes.
|
||||
*
|
||||
* The onboard button can be kept pressed for 5 seconds to decommission the Matter Node.
|
||||
* The example will also show the manual commissioning code and QR code to be used in the Matter environment.
|
||||
*
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Matter Occupancy Sensor Endpoint
|
||||
MatterOccupancySensor OccupancySensor;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// set your board USER BUTTON pin here - decommissioning only
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// Button control
|
||||
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
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// set initial occupancy sensor state as false and connected to a PIR sensor type (default)
|
||||
OccupancySensor.begin();
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
|
||||
// Check Matter Accessory 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 Occupancy Sensor 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 the network. Ready for use.");
|
||||
}
|
||||
}
|
||||
|
||||
bool simulatedHWOccupancySensor() {
|
||||
// Simulated Occupancy Sensor
|
||||
static bool occupancyState = false;
|
||||
static uint32_t lastTime = millis();
|
||||
const uint32_t occupancyTimeout = 120000; // 2 minutes to toggle the state
|
||||
|
||||
// Simulate a Occupancy Sensor state change every 2 minutes
|
||||
if (millis() - lastTime > occupancyTimeout) {
|
||||
occupancyState = !occupancyState;
|
||||
lastTime = millis();
|
||||
}
|
||||
return occupancyState;
|
||||
}
|
||||
|
||||
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 (button_state && digitalRead(buttonPin) == HIGH) {
|
||||
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 Occupancy Sensor Matter Accessory. It shall be commissioned again.");
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||
}
|
||||
|
||||
// Check Simulated Occupancy Sensor and set Matter Attribute
|
||||
OccupancySensor.setOccupancy(simulatedHWOccupancySensor());
|
||||
|
||||
delay(50);
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
# Matter Occupancy Sensor Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible occupancy sensor device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, sensor data reporting to smart home ecosystems, and automatic simulation of occupancy state changes.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for an occupancy sensor device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Occupancy state reporting (Occupied/Unoccupied)
|
||||
- Automatic simulation of occupancy state changes every 2 minutes
|
||||
- Button control for factory reset (decommission)
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- User button for factory reset (uses BOOT button by default)
|
||||
- Optional: PIR (Passive Infrared) motion sensor (e.g., HC-SR501, AM312) for real occupancy detection
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
- **PIR Sensor** (optional): Connect to any available GPIO pin (e.g., GPIO 4) when using a real sensor
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
3. **PIR sensor pin configuration** (optional, if using a real PIR sensor):
|
||||
```cpp
|
||||
const uint8_t pirPin = 4; // Set your PIR sensor pin here
|
||||
```
|
||||
See the "PIR Sensor Integration Example" section below for complete integration instructions.
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterOccupancySensor.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
```
|
||||
|
||||
After commissioning, the occupancy sensor will automatically toggle between occupied and unoccupied states every 2 minutes, and the Matter controller will receive these state updates.
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides factory reset functionality:
|
||||
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Sensor Simulation
|
||||
|
||||
The example includes a simulated occupancy sensor that:
|
||||
|
||||
- Starts in the unoccupied state (false)
|
||||
- Toggles between occupied (true) and unoccupied (false) every 2 minutes
|
||||
- Updates the Matter attribute automatically
|
||||
|
||||
To use a real occupancy sensor, replace the `simulatedHWOccupancySensor()` function with your sensor library code.
|
||||
|
||||
### PIR Sensor Integration Example
|
||||
|
||||
Here's a complete example for integrating a simple PIR (Passive Infrared) motion sensor:
|
||||
|
||||
#### Hardware Connections
|
||||
|
||||
Connect the PIR sensor to your ESP32:
|
||||
- **PIR VCC** → ESP32 3.3 V or 5 V (check your PIR sensor specifications)
|
||||
- **PIR GND** → ESP32 GND
|
||||
- **PIR OUT** → ESP32 GPIO pin (e.g., GPIO 4)
|
||||
|
||||
Common PIR sensors (HC-SR501, AM312, etc.) typically have three pins: VCC, GND, and OUT (digital output).
|
||||
|
||||
#### Code Modifications
|
||||
|
||||
1. **Add PIR pin definition** at the top of the sketch (after the button pin definition):
|
||||
|
||||
```cpp
|
||||
// PIR sensor pin
|
||||
const uint8_t pirPin = 4; // Change this to your PIR sensor pin
|
||||
```
|
||||
|
||||
2. **Initialize PIR pin in setup()** (after button initialization):
|
||||
|
||||
```cpp
|
||||
void setup() {
|
||||
// ... existing code ...
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
|
||||
// Initialize PIR sensor pin
|
||||
pinMode(pirPin, INPUT);
|
||||
|
||||
// ... rest of setup code ...
|
||||
}
|
||||
```
|
||||
|
||||
3. **Replace the simulated function** with the real PIR reading function:
|
||||
|
||||
```cpp
|
||||
bool simulatedHWOccupancySensor() {
|
||||
// Read PIR sensor digital input
|
||||
// HIGH = motion detected (occupied), LOW = no motion (unoccupied)
|
||||
return digitalRead(pirPin) == HIGH;
|
||||
}
|
||||
```
|
||||
|
||||
#### Complete Modified Function Example
|
||||
|
||||
Here's the complete modified function with debouncing for more reliable readings:
|
||||
|
||||
```cpp
|
||||
bool simulatedHWOccupancySensor() {
|
||||
// Read PIR sensor with debouncing
|
||||
static bool lastState = false;
|
||||
static uint32_t lastChangeTime = 0;
|
||||
const uint32_t debounceTime = 100; // 100ms debounce
|
||||
|
||||
bool currentState = digitalRead(pirPin) == HIGH;
|
||||
|
||||
// Only update if state has changed and debounce time has passed
|
||||
if (currentState != lastState) {
|
||||
if (millis() - lastChangeTime > debounceTime) {
|
||||
lastState = currentState;
|
||||
lastChangeTime = millis();
|
||||
Serial.printf("Occupancy state changed: %s\r\n", currentState ? "OCCUPIED" : "UNOCCUPIED");
|
||||
}
|
||||
}
|
||||
|
||||
return lastState;
|
||||
}
|
||||
```
|
||||
|
||||
#### Testing the PIR Sensor
|
||||
|
||||
After making these changes:
|
||||
1. Upload the modified sketch to your ESP32
|
||||
2. Open the Serial Monitor at 115200 baud
|
||||
3. Move in front of the PIR sensor - you should see "OCCUPIED" messages
|
||||
4. Stay still for a few seconds - you should see "UNOCCUPIED" messages
|
||||
5. The Matter controller will automatically receive these occupancy state updates
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as an occupancy sensor in your Home app
|
||||
7. You can monitor the occupancy state and set up automations based on occupancy (e.g., turn on lights when occupied)
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The occupancy sensor will appear in your Alexa app
|
||||
6. You can monitor occupancy readings and create routines based on occupancy state changes
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can monitor occupancy readings and create automations based on occupancy state changes
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterOccupancySensor example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button), configures Wi-Fi (if needed), sets up the Matter Occupancy Sensor endpoint with initial state (unoccupied), and waits for Matter commissioning.
|
||||
|
||||
2. **`loop()`**: Handles button input for factory reset, continuously checks the simulated occupancy sensor and updates the Matter attribute, and allows the Matter stack to process events.
|
||||
|
||||
3. **`simulatedHWOccupancySensor()`**: Simulates a hardware occupancy sensor by toggling the occupancy state every 2 minutes. Replace this function with your actual sensor reading code.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Occupancy readings not updating**: Check that the sensor simulation function is being called correctly. For real sensors, verify sensor wiring and library initialization
|
||||
- **State not changing**: The simulated sensor toggles every 2 minutes (120000 ms). If you're using a real sensor, ensure it's properly connected and reading correctly
|
||||
- **PIR sensor not detecting motion**:
|
||||
- Verify PIR sensor wiring (VCC, GND, OUT connections)
|
||||
- Check if PIR sensor requires 5 V or 3.3 V power (some PIR sensors need 5 V)
|
||||
- Allow 30-60 seconds for PIR sensor to stabilize after power-on
|
||||
- Adjust PIR sensor sensitivity and time delay potentiometers (if available on your sensor)
|
||||
- Ensure the PIR sensor has a clear view of the detection area
|
||||
- Test the PIR sensor directly by reading the GPIO pin value in Serial Monitor
|
||||
- **PIR sensor false triggers**: Add debouncing to the sensor reading function (see the "Complete Modified Function Example" above)
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Occupancy Sensor Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_occupancy_sensor.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* This example is an example code that will create a Matter Device which can be
|
||||
* commissioned and controlled from a Matter Environment APP.
|
||||
* 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.
|
||||
*
|
||||
* The example will create a Matter Occupancy Sensor Device.
|
||||
* The Occupancy Sensor will be simulated to toggle occupancy every 2 minutes.
|
||||
* When occupancy is detected, the sensor holds the "occupied" state for the HoldTime duration
|
||||
* (default: 30 seconds, configurable via Matter Controller). After HoldTime expires,
|
||||
* the sensor automatically switches to "unoccupied" state.
|
||||
*
|
||||
* The HoldTime attribute allows you to adjust how long the active status is retained
|
||||
* after the person leaves. The HoldTime can be changed by a Matter Controller, and the
|
||||
* onHoldTimeChange() callback is used to update the simulated sensor functionality.
|
||||
*
|
||||
* The HoldTime value is persisted to Preferences (NVS) and restored on reboot, so the
|
||||
* last configured HoldTime value is maintained across device restarts.
|
||||
*
|
||||
* The onboard button can be kept pressed for 5 seconds to decommission the Matter Node.
|
||||
* The example will also show the manual commissioning code and QR code to be used in the Matter environment.
|
||||
*
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#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
|
||||
#endif
|
||||
#include <Preferences.h>
|
||||
|
||||
// HoldTime configuration constants
|
||||
const uint16_t HOLD_TIME_MIN = 0; // Minimum HoldTime in seconds
|
||||
const uint16_t HOLD_TIME_MAX = 3600; // Maximum HoldTime in seconds (1 hour)
|
||||
const uint16_t HOLD_TIME_DEFAULT = 30; // Default HoldTime in seconds
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Matter Occupancy Sensor Endpoint
|
||||
MatterOccupancySensor OccupancySensor;
|
||||
|
||||
// Preferences to store HoldTime value across reboots
|
||||
Preferences matterPref;
|
||||
const char *holdTimePrefKey = "HoldTime";
|
||||
|
||||
// set your board USER BUTTON pin here - decommissioning only
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// Button control
|
||||
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
|
||||
|
||||
// Simulated Occupancy Sensor with HoldTime support
|
||||
// When occupancy is detected, it holds the "occupied" state for HoldTime seconds
|
||||
// After HoldTime expires, it automatically switches to "unoccupied"
|
||||
//
|
||||
// Behavior for different HoldTime vs detectionInterval relationships:
|
||||
// - holdTime_ms < detectionInterval: State switches to unoccupied after HoldTime, then waits for next detection
|
||||
// - holdTime_ms == detectionInterval: If detections keep coming, timer resets (continuous occupancy)
|
||||
// - holdTime_ms > detectionInterval: If detections keep coming, timer resets (continuous occupancy)
|
||||
// If detections stop, HoldTime expires after the last detection
|
||||
bool simulatedHWOccupancySensor() {
|
||||
static bool occupancyState = false;
|
||||
static uint32_t lastDetectionTime = 0;
|
||||
static uint32_t lastDetectionEvent = millis();
|
||||
const uint32_t detectionInterval = 120000; // Simulate detection every 2 minutes
|
||||
|
||||
// Get current HoldTime from the sensor (can be changed by Matter Controller)
|
||||
uint32_t holdTime_ms = OccupancySensor.getHoldTime() * 1000; // Convert seconds to milliseconds
|
||||
|
||||
// Check HoldTime expiration FIRST (before processing new detections)
|
||||
// This ensures HoldTime can expire even if a detection occurs in the same iteration
|
||||
if (occupancyState && (millis() - lastDetectionTime > holdTime_ms)) {
|
||||
occupancyState = false;
|
||||
// Reset detection interval counter so next detection can happen immediately
|
||||
// This makes the simulation more responsive after the room becomes unoccupied
|
||||
lastDetectionEvent = millis();
|
||||
Serial.println("HoldTime expired. Switching to unoccupied state.");
|
||||
}
|
||||
|
||||
// Simulate periodic occupancy detection (e.g., motion detected)
|
||||
// Check this AFTER HoldTime expiration so new detections can immediately re-trigger occupancy
|
||||
if (millis() - lastDetectionEvent > detectionInterval) {
|
||||
// New detection event occurred
|
||||
lastDetectionEvent = millis();
|
||||
|
||||
if (!occupancyState) {
|
||||
// Transition from unoccupied to occupied - start hold timer
|
||||
occupancyState = true;
|
||||
lastDetectionTime = millis();
|
||||
Serial.printf("Occupancy detected! Holding state for %u seconds (HoldTime)\n", OccupancySensor.getHoldTime());
|
||||
} else {
|
||||
// Already occupied - new detection extends the hold period by resetting the timer
|
||||
// This simulates continuous occupancy (person still present)
|
||||
lastDetectionTime = millis();
|
||||
Serial.printf("Occupancy still detected. Resetting hold timer to %u seconds (HoldTime)\n", OccupancySensor.getHoldTime());
|
||||
}
|
||||
}
|
||||
|
||||
return occupancyState;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// Initialize Preferences and read stored HoldTime value
|
||||
matterPref.begin("MatterPrefs", false);
|
||||
uint16_t storedHoldTime = matterPref.getUShort(holdTimePrefKey, HOLD_TIME_DEFAULT);
|
||||
|
||||
// Validate stored value is within limits
|
||||
if (storedHoldTime < HOLD_TIME_MIN || storedHoldTime > HOLD_TIME_MAX) {
|
||||
uint16_t invalidValue = storedHoldTime;
|
||||
storedHoldTime = HOLD_TIME_DEFAULT;
|
||||
Serial.printf("Invalid stored HoldTime (%u), using default: %u seconds\n", invalidValue, HOLD_TIME_DEFAULT);
|
||||
} else if (storedHoldTime != HOLD_TIME_DEFAULT) {
|
||||
Serial.printf("Restored HoldTime from Preferences: %u seconds\n", storedHoldTime);
|
||||
}
|
||||
|
||||
// Register callback for HoldTime changes from Matter Controller
|
||||
OccupancySensor.onHoldTimeChange([](uint16_t holdTime_seconds) -> bool {
|
||||
Serial.printf("HoldTime changed to %u seconds by Matter Controller\n", holdTime_seconds);
|
||||
// Store the new HoldTime value to Preferences for persistence across reboots
|
||||
matterPref.putUShort(holdTimePrefKey, holdTime_seconds);
|
||||
// The callback can return false to reject the change, or true to accept it
|
||||
// In this case, we always accept the change and update the simulator
|
||||
return true;
|
||||
});
|
||||
|
||||
// set initial occupancy sensor state as false and connected to a PIR sensor type (default)
|
||||
OccupancySensor.begin();
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
|
||||
// Set HoldTimeLimits after Matter.begin() (optional, but recommended for validation)
|
||||
if (!OccupancySensor.setHoldTimeLimits(HOLD_TIME_MIN, HOLD_TIME_MAX, HOLD_TIME_DEFAULT)) {
|
||||
Serial.println("Warning: Failed to set HoldTimeLimits");
|
||||
} else {
|
||||
Serial.printf("HoldTimeLimits set: Min=%u, Max=%u, Default=%u seconds\n", HOLD_TIME_MIN, HOLD_TIME_MAX, HOLD_TIME_DEFAULT);
|
||||
}
|
||||
|
||||
// Set initial HoldTime (use stored value if valid, otherwise use default)
|
||||
// This must be done after Matter.begin() because setHoldTime() requires the Matter event loop
|
||||
if (!OccupancySensor.setHoldTime(storedHoldTime)) {
|
||||
Serial.printf("Warning: Failed to set HoldTime to %u seconds\n", storedHoldTime);
|
||||
} else {
|
||||
Serial.printf("HoldTime set to: %u seconds\n", storedHoldTime);
|
||||
}
|
||||
|
||||
Serial.printf("Initial HoldTime: %u seconds\n", OccupancySensor.getHoldTime());
|
||||
|
||||
// Check Matter Accessory 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 Occupancy Sensor 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 the network. Ready for use.");
|
||||
}
|
||||
}
|
||||
|
||||
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 (button_state && digitalRead(buttonPin) == HIGH) {
|
||||
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 Occupancy Sensor Matter Accessory. It shall be commissioned again.");
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||
}
|
||||
|
||||
// Check Simulated Occupancy Sensor and set Matter Attribute
|
||||
OccupancySensor.setOccupancy(simulatedHWOccupancySensor());
|
||||
|
||||
delay(50);
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
# Matter Occupancy Sensor with HoldTime Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible occupancy sensor device with HoldTime functionality using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, sensor data reporting to smart home ecosystems, automatic simulation of occupancy state changes, and HoldTime configuration with persistence across reboots.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for an occupancy sensor device with HoldTime support
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Occupancy state reporting (Occupied/Unoccupied)
|
||||
- HoldTime attribute for configuring how long the sensor holds the "occupied" state
|
||||
- HoldTimeLimits (min, max, default) for validation and controller guidance
|
||||
- HoldTime persistence across reboots using Preferences (NVS)
|
||||
- Automatic simulation of occupancy state changes every 2 minutes with HoldTime expiration
|
||||
- HoldTime change callback for real-time updates from Matter controllers
|
||||
- Button control for factory reset (decommission)
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- User button for factory reset (uses BOOT button by default)
|
||||
- Optional: PIR (Passive Infrared) motion sensor (e.g., HC-SR501, AM312) for real occupancy detection
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
- **PIR Sensor** (optional): Connect to any available GPIO pin (e.g., GPIO 4) when using a real sensor
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **HoldTime configuration** (optional):
|
||||
The example uses default HoldTime limits. You can customize them:
|
||||
```cpp
|
||||
const uint16_t HOLD_TIME_MIN = 0; // Minimum HoldTime in seconds
|
||||
const uint16_t HOLD_TIME_MAX = 3600; // Maximum HoldTime in seconds (1 hour)
|
||||
const uint16_t HOLD_TIME_DEFAULT = 30; // Default HoldTime in seconds
|
||||
```
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
4. **PIR sensor pin configuration** (optional, if using a real PIR sensor):
|
||||
```cpp
|
||||
const uint8_t pirPin = 4; // Set your PIR sensor pin here
|
||||
```
|
||||
See the "PIR Sensor Integration Example" section below for complete integration instructions.
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterOccupancyWithHoldTime.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Restored HoldTime from Preferences: 30 seconds
|
||||
HoldTimeLimits set: Min=0, Max=3600, Default=30 seconds
|
||||
HoldTime set to: 30 seconds
|
||||
Initial HoldTime: 30 seconds
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
Occupancy detected! Holding state for 30 seconds (HoldTime)
|
||||
HoldTime expired. Switching to unoccupied state.
|
||||
```
|
||||
|
||||
After commissioning, the occupancy sensor will automatically simulate occupancy detections every 2 minutes. When occupancy is detected, the sensor holds the "occupied" state for the configured HoldTime duration (default: 30 seconds). After HoldTime expires, it automatically switches to "unoccupied" state. The Matter controller will receive these state updates and can also configure the HoldTime value.
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides factory reset functionality:
|
||||
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Sensor Simulation
|
||||
|
||||
The example includes a simulated occupancy sensor with HoldTime support that:
|
||||
|
||||
- Starts in the unoccupied state (false)
|
||||
- Simulates occupancy detection every 2 minutes
|
||||
- When occupancy is detected, holds the "occupied" state for the HoldTime duration
|
||||
- After HoldTime expires, automatically switches to "unoccupied" state
|
||||
- If new detections occur while occupied, the HoldTime timer resets (continuous occupancy)
|
||||
- Updates the Matter attribute automatically
|
||||
|
||||
**HoldTime Behavior:**
|
||||
- The HoldTime value determines how long the sensor maintains the "occupied" state after the last detection
|
||||
- HoldTime can be configured via Matter Controller (within the min/max limits)
|
||||
- HoldTime value is persisted to Preferences and restored on reboot
|
||||
- When HoldTime expires, the sensor transitions to "unoccupied" even if no new detection occurs
|
||||
|
||||
To use a real occupancy sensor, replace the `simulatedHWOccupancySensor()` function with your sensor library code. The HoldTime functionality will work the same way - the sensor will hold the occupied state for the configured HoldTime duration after motion is no longer detected.
|
||||
|
||||
### PIR Sensor Integration Example
|
||||
|
||||
Here's a complete example for integrating a simple PIR (Passive Infrared) motion sensor:
|
||||
|
||||
#### Hardware Connections
|
||||
|
||||
Connect the PIR sensor to your ESP32:
|
||||
- **PIR VCC** → ESP32 3.3 V or 5 V (check your PIR sensor specifications)
|
||||
- **PIR GND** → ESP32 GND
|
||||
- **PIR OUT** → ESP32 GPIO pin (e.g., GPIO 4)
|
||||
|
||||
Common PIR sensors (HC-SR501, AM312, etc.) typically have three pins: VCC, GND, and OUT (digital output).
|
||||
|
||||
#### Code Modifications
|
||||
|
||||
1. **Add PIR pin definition** at the top of the sketch (after the button pin definition):
|
||||
|
||||
```cpp
|
||||
// PIR sensor pin
|
||||
const uint8_t pirPin = 4; // Change this to your PIR sensor pin
|
||||
```
|
||||
|
||||
2. **Initialize PIR pin in setup()** (after button initialization):
|
||||
|
||||
```cpp
|
||||
void setup() {
|
||||
// ... existing code ...
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
|
||||
// Initialize PIR sensor pin
|
||||
pinMode(pirPin, INPUT);
|
||||
|
||||
// ... rest of setup code ...
|
||||
}
|
||||
```
|
||||
|
||||
3. **Replace the simulated function** with the real PIR reading function:
|
||||
|
||||
```cpp
|
||||
bool simulatedHWOccupancySensor() {
|
||||
// Read PIR sensor digital input
|
||||
// HIGH = motion detected (occupied), LOW = no motion (unoccupied)
|
||||
return digitalRead(pirPin) == HIGH;
|
||||
}
|
||||
```
|
||||
|
||||
#### Complete Modified Function Example
|
||||
|
||||
Here's the complete modified function with debouncing for more reliable readings:
|
||||
|
||||
```cpp
|
||||
bool simulatedHWOccupancySensor() {
|
||||
// Read PIR sensor with debouncing
|
||||
static bool lastState = false;
|
||||
static uint32_t lastChangeTime = 0;
|
||||
const uint32_t debounceTime = 100; // 100ms debounce
|
||||
|
||||
bool currentState = digitalRead(pirPin) == HIGH;
|
||||
|
||||
// Only update if state has changed and debounce time has passed
|
||||
if (currentState != lastState) {
|
||||
if (millis() - lastChangeTime > debounceTime) {
|
||||
lastState = currentState;
|
||||
lastChangeTime = millis();
|
||||
Serial.printf("Occupancy state changed: %s\r\n", currentState ? "OCCUPIED" : "UNOCCUPIED");
|
||||
}
|
||||
}
|
||||
|
||||
return lastState;
|
||||
}
|
||||
```
|
||||
|
||||
#### Testing the PIR Sensor
|
||||
|
||||
After making these changes:
|
||||
1. Upload the modified sketch to your ESP32
|
||||
2. Open the Serial Monitor at 115200 baud
|
||||
3. Move in front of the PIR sensor - you should see "OCCUPIED" messages
|
||||
4. Stay still for a few seconds - you should see "UNOCCUPIED" messages
|
||||
5. The Matter controller will automatically receive these occupancy state updates
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as an occupancy sensor in your Home app
|
||||
7. You can monitor the occupancy state and set up automations based on occupancy (e.g., turn on lights when occupied)
|
||||
8. You can configure the HoldTime value through the device settings (if supported by your Home app version)
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The occupancy sensor will appear in your Alexa app
|
||||
6. You can monitor occupancy readings and create routines based on occupancy state changes
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can monitor occupancy readings and create automations based on occupancy state changes
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterOccupancyWithHoldTime example consists of the following main components:
|
||||
|
||||
1. **`setup()`**:
|
||||
- Initializes hardware (button), configures Wi-Fi (if needed)
|
||||
- Initializes Preferences and restores stored HoldTime value
|
||||
- Registers HoldTime change callback for persistence
|
||||
- Sets up the Matter Occupancy Sensor endpoint with initial state (unoccupied)
|
||||
- Calls `Matter.begin()` to start the Matter stack
|
||||
- Sets HoldTimeLimits (min, max, default) after Matter.begin()
|
||||
- Sets initial HoldTime value (from Preferences or default)
|
||||
- Waits for Matter commissioning
|
||||
|
||||
2. **`loop()`**:
|
||||
- Handles button input for factory reset
|
||||
- Continuously checks the simulated occupancy sensor and updates the Matter attribute
|
||||
- Allows the Matter stack to process events
|
||||
|
||||
3. **`simulatedHWOccupancySensor()`**:
|
||||
- Simulates a hardware occupancy sensor with HoldTime support
|
||||
- Detects occupancy every 2 minutes
|
||||
- Holds the "occupied" state for HoldTime seconds after detection
|
||||
- Automatically transitions to "unoccupied" when HoldTime expires
|
||||
- Resets HoldTime timer on new detections while occupied (continuous occupancy)
|
||||
- Replace this function with your actual sensor reading code
|
||||
|
||||
4. **HoldTime Callback**:
|
||||
- `onHoldTimeChange()` callback persists HoldTime changes to Preferences
|
||||
- Ensures HoldTime value is maintained across device reboots
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Occupancy readings not updating**: Check that the sensor simulation function is being called correctly. For real sensors, verify sensor wiring and library initialization
|
||||
- **State not changing**: The simulated sensor detects occupancy every 2 minutes (120000 ms). The state will hold for HoldTime seconds after detection. If you're using a real sensor, ensure it's properly connected and reading correctly
|
||||
- **HoldTime not persisting**: Verify that Preferences is properly initialized and the callback is saving the value. Check Serial Monitor for "HoldTime changed" messages
|
||||
- **HoldTime not working**: Ensure `setHoldTimeLimits()` and `setHoldTime()` are called after `Matter.begin()`. Check Serial Monitor for error messages
|
||||
- **PIR sensor not detecting motion**:
|
||||
- Verify PIR sensor wiring (VCC, GND, OUT connections)
|
||||
- Check if PIR sensor requires 5 V or 3.3 V power (some PIR sensors need 5 V)
|
||||
- Allow 30-60 seconds for PIR sensor to stabilize after power-on
|
||||
- Adjust PIR sensor sensitivity and time delay potentiometers (if available on your sensor)
|
||||
- Ensure the PIR sensor has a clear view of the detection area
|
||||
- Test the PIR sensor directly by reading the GPIO pin value in Serial Monitor
|
||||
- **PIR sensor false triggers**: Add debouncing to the sensor reading function (see the "Complete Modified Function Example" above)
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Occupancy Sensor Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_occupancy_sensor.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,173 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Single On/Off Light Endpoint - at least one per node
|
||||
MatterOnOffLight OnOffLight;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// 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
|
||||
|
||||
// Identify Flag and blink time - Blink the LED
|
||||
const uint8_t identifyLedPin = ledPin; // uses the same LED as the Light - change if needed
|
||||
volatile bool identifyFlag = false; // Flag to start the Blink when in Identify state
|
||||
bool identifyBlink = false; // Blink state when in Identify state
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Identification shall be done by Blink in Red or just the GPIO when no LED_BUILTIN is not defined
|
||||
bool onIdentifyLightCallback(bool identifyIsActive) {
|
||||
Serial.printf("Identify Cluster is %s\r\n", identifyIsActive ? "Active" : "Inactive");
|
||||
if (identifyIsActive) {
|
||||
// Start Blinking the light in loop()
|
||||
identifyFlag = true;
|
||||
identifyBlink = !OnOffLight; // Start with the inverted light state
|
||||
} else {
|
||||
// Stop Blinking and restore the light to the its last state
|
||||
identifyFlag = false;
|
||||
// force returning to the original state by toggling the light twice
|
||||
OnOffLight.toggle();
|
||||
OnOffLight.toggle();
|
||||
}
|
||||
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);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// 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();
|
||||
|
||||
// Check Matter Accessory 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 Occupancy Sensor 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 the network. Ready for use.");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// check if the Light is in identify state and blink it every 500ms (delay loop time)
|
||||
if (identifyFlag) {
|
||||
#ifdef LED_BUILTIN
|
||||
uint8_t brightness = 32 * identifyBlink;
|
||||
rgbLedWrite(identifyLedPin, brightness, 0, 0);
|
||||
#else
|
||||
digitalWrite(identifyLedPin, identifyBlink ? HIGH : LOW);
|
||||
#endif
|
||||
identifyBlink = !identifyBlink;
|
||||
}
|
||||
|
||||
// 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); // works as a debounce for the button and also for the LED blink
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
# Matter On Identify Example
|
||||
|
||||
This example demonstrates how to implement the Matter Identify cluster callback for an on/off light device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device control via smart home ecosystems, and the Identify feature that makes the LED blink when the device is identified from a Matter app.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | LED | Status |
|
||||
| --- | ---- | ------ | ----------------- | --- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for an on/off light device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- On Identify callback implementation - LED blinks when device is identified
|
||||
- Visual identification feedback (red blinking for RGB LED, toggling for regular LED)
|
||||
- Button control for factory reset (decommission)
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- LED connected to GPIO pin (or using built-in LED) for visual feedback
|
||||
- Optional: RGB LED for red blinking identification (uses RGB_BUILTIN if available)
|
||||
- User button for factory reset (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **LED**: Uses `LED_BUILTIN` if defined, otherwise pin 2
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **LED pin configuration** (if not using built-in LED):
|
||||
```cpp
|
||||
const uint8_t ledPin = 2; // Set your LED pin here
|
||||
```
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterOnIdentify.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
```
|
||||
|
||||
When you trigger the Identify command from a Matter app, you should see:
|
||||
```
|
||||
Identify Cluster is Active
|
||||
Identify Cluster is Inactive
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides factory reset functionality:
|
||||
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Identify Feature
|
||||
|
||||
The Identify feature allows you to visually identify a specific device from your Matter app. When you trigger the Identify command:
|
||||
|
||||
1. **For RGB LED (RGB_BUILTIN)**: The LED will blink in red color
|
||||
2. **For regular LED**: The LED will toggle on/off
|
||||
|
||||
The blinking continues while the Identify cluster is active (typically 3-15 seconds depending on the app). When the Identify period ends, the LED automatically returns to its previous state (on or off).
|
||||
|
||||
### How to Trigger Identify
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Find your device in the device list
|
||||
3. Long press on the device
|
||||
4. Tap "Identify" or look for the identify option in device settings
|
||||
5. The LED will start blinking
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Navigate to your device
|
||||
3. Look for "Identify" or "Find Device" option in device settings
|
||||
4. The LED will start blinking
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Select your device
|
||||
3. Look for "Identify" or "Find Device" option
|
||||
4. The LED will start blinking
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as an on/off light in your Home app
|
||||
7. Use the Identify feature to visually locate the device
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The light will appear in your Alexa app
|
||||
6. Use the Identify feature to visually locate the device
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. Use the Identify feature to visually locate the device
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterOnIdentify example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, LED), configures Wi-Fi (if needed), initializes the Matter on/off light endpoint, registers the on/off callback and the Identify callback, and starts the Matter stack.
|
||||
|
||||
2. **`loop()`**: Handles the Identify blinking logic (if identify flag is active, blinks the LED every 500 ms), handles button input for factory reset, and allows the Matter stack to process events.
|
||||
|
||||
3. **Callbacks**:
|
||||
- `onOffLightCallback()`: Controls the physical LED based on on/off state from Matter controller.
|
||||
- `onIdentifyLightCallback()`: Handles the Identify cluster activation/deactivation. When active, sets the identify flag to start blinking. When inactive, stops blinking and restores the original light state.
|
||||
|
||||
4. **Identify Blinking Logic**:
|
||||
- For RGB LEDs: Blinks in red color (brightness 32) when identify is active
|
||||
- For regular LEDs: Toggles on/off when identify is active
|
||||
- Blinking rate: Every 500 ms (determined by the delay in loop)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **LED not responding**: Verify pin configurations and connections
|
||||
- **Identify feature not working**: Ensure the device is commissioned and you're using a Matter app that supports the Identify cluster. Some apps may not have a visible Identify button
|
||||
- **LED not blinking during identify**: Check Serial Monitor for "Identify Cluster is Active" message. If you don't see it, the Identify command may not be reaching the device
|
||||
- **LED state not restored after identify**: The code uses a double-toggle to restore state. If this doesn't work, ensure the light state is properly tracked
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter On/Off Light Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_on_off_light.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,157 @@
|
||||
// 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
#include <Preferences.h>
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// On/Off Light Endpoint
|
||||
MatterOnOffLight OnOffLight;
|
||||
|
||||
// it will keep last OnOff state stored, using Preferences
|
||||
Preferences matterPref;
|
||||
const char *onOffPrefKey = "OnOff";
|
||||
|
||||
// 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 = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||
|
||||
// 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
|
||||
matterPref.putBool(onOffPrefKey, state);
|
||||
// This callback must return the success state to Matter core
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// Initialize Matter EndPoint
|
||||
matterPref.begin("MatterPrefs", false);
|
||||
bool lastOnOffState = matterPref.getBool(onOffPrefKey, true);
|
||||
OnOffLight.begin(lastOnOffState);
|
||||
OnOffLight.onChange(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 the network. Ready for use.");
|
||||
Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF");
|
||||
OnOffLight.updateAccessory(); // configure the Light based on initial state
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
OnOffLight.updateAccessory(); // configure the Light based on initial state
|
||||
Serial.println("Matter Node is commissioned and connected to the network. 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
|
||||
}
|
||||
|
||||
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||
if (button_state && time_diff > decommissioningTimeout) {
|
||||
Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again.");
|
||||
OnOffLight.setOnOff(false); // turn the light off
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
# Matter On/Off Light Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible on/off light device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device control via smart home ecosystems, and manual control using a physical button with state persistence.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | LED | Status |
|
||||
| --- | ---- | ------ | ----------------- | --- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for an on/off light device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Simple on/off control
|
||||
- State persistence using `Preferences` library
|
||||
- Button control for toggling light and factory reset
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- LED connected to GPIO pin (or using built-in LED) for visual feedback
|
||||
- User button for manual control (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **LED**: Uses `LED_BUILTIN` if defined, otherwise pin 2
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Preferences`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **LED pin configuration** (if not using built-in LED):
|
||||
```cpp
|
||||
const uint8_t ledPin = 2; // Set your LED pin here
|
||||
```
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for the Light On/Off manual control and factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterOnOffLight.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Initial state: ON
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
User Callback :: New Light State = ON
|
||||
User Callback :: New Light State = OFF
|
||||
User button released. Toggling Light!
|
||||
User Callback :: New Light State = ON
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Short press of the button**: Toggle light on/off
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### State Persistence
|
||||
|
||||
The device saves the last known on/off state using the `Preferences` library. After a power cycle or restart:
|
||||
|
||||
- The device will restore to the last saved state (ON or OFF)
|
||||
- The Matter controller will be notified of the restored state
|
||||
- The LED will reflect the restored state
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as an on/off light in your Home app
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The light will appear in your Alexa app
|
||||
6. You can control it using voice commands like "Alexa, turn on the light" or "Alexa, turn off the light"
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can control it using voice commands or the app controls
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterOnOffLight example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, LED), configures Wi-Fi (if needed), initializes `Preferences` library, sets up the Matter endpoint with the last saved state (defaults to ON if not previously saved), registers the callback function, and starts the Matter stack.
|
||||
|
||||
2. **`loop()`**: Checks the Matter commissioning state, handles button input for toggling the light and factory reset, and allows the Matter stack to process events.
|
||||
|
||||
3. **Callbacks**:
|
||||
- `setLightOnOff()`: Controls the physical LED based on the on/off state, saves the state to `Preferences` for persistence, and prints the state change to Serial Monitor.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **LED not responding**: Verify pin configurations and connections
|
||||
- **State not persisting**: Check that the `Preferences` library is properly initialized and that flash memory is not corrupted
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **Button not toggling light**: Ensure the button is properly connected and the debounce time is appropriate. Check Serial Monitor for "User button released" messages
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter On/Off Light Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_on_off_light.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,151 @@
|
||||
// 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
#include <Preferences.h>
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// On/Off Plugin Endpoint
|
||||
MatterOnOffPlugin OnOffPlugin;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// it will keep last OnOff state stored, using Preferences
|
||||
Preferences matterPref;
|
||||
const char *onOffPrefKey = "OnOff";
|
||||
|
||||
// set your board Power Relay pin here - this example uses the built-in LED for easy visualization
|
||||
#ifdef LED_BUILTIN
|
||||
const uint8_t onoffPin = LED_BUILTIN;
|
||||
#else
|
||||
const uint8_t onoffPin = 2; // Set your pin here - usually a power relay
|
||||
#warning "Do not forget to set the Power Relay pin"
|
||||
#endif
|
||||
|
||||
// board USER BUTTON pin necessary for Decommissioning
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// Button control
|
||||
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 Callback
|
||||
bool setPluginOnOff(bool state) {
|
||||
Serial.printf("User Callback :: New Plugin State = %s\r\n", state ? "ON" : "OFF");
|
||||
if (state) {
|
||||
digitalWrite(onoffPin, HIGH);
|
||||
} else {
|
||||
digitalWrite(onoffPin, LOW);
|
||||
}
|
||||
// store last OnOff state for when the Plugin is restarted / power goes off
|
||||
matterPref.putBool(onOffPrefKey, state);
|
||||
// This callback must return the success state to Matter core
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
// Initialize the Power Relay (plugin) GPIO
|
||||
pinMode(onoffPin, OUTPUT);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
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);
|
||||
#endif
|
||||
|
||||
// Initialize Matter EndPoint
|
||||
matterPref.begin("MatterPrefs", false);
|
||||
bool lastOnOffState = matterPref.getBool(onOffPrefKey, false);
|
||||
OnOffPlugin.begin(lastOnOffState);
|
||||
OnOffPlugin.onChange(setPluginOnOff);
|
||||
|
||||
// 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 the network. Ready for use.");
|
||||
Serial.printf("Initial state: %s\r\n", OnOffPlugin.getOnOff() ? "ON" : "OFF");
|
||||
OnOffPlugin.updateAccessory(); // configure the Plugin based on initial state
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Check Matter Plugin 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 Plugin 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", OnOffPlugin.getOnOff() ? "ON" : "OFF");
|
||||
OnOffPlugin.updateAccessory(); // configure the Plugin based on initial state
|
||||
Serial.println("Matter Node is commissioned and connected to the network. Ready for use.");
|
||||
}
|
||||
|
||||
// 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 to decommission the Matter Node
|
||||
if (button_state && digitalRead(buttonPin) == HIGH) {
|
||||
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 Plugin Matter Accessory. It shall be commissioned again.");
|
||||
OnOffPlugin.setOnOff(false); // turn the plugin off
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
# Matter On/Off Plugin Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible on/off plugin unit (power relay) device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device control via smart home ecosystems, and state persistence for power control applications.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Relay/LED | Status |
|
||||
| --- | ---- | ------ | ----------------- | --------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for an on/off plugin unit (power relay) device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Simple on/off control for power management
|
||||
- State persistence using `Preferences` library
|
||||
- Button control for factory reset (decommission)
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- Power relay module or LED for visualization (for testing, uses built-in LED)
|
||||
- User button for factory reset (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **Power Relay/Plugin Pin**: Uses `LED_BUILTIN` if defined (for testing), otherwise pin 2. For production use, connect this to your relay control pin.
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Preferences`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **Power relay pin configuration** (if not using built-in LED):
|
||||
For production use, change this to the GPIO pin connected to your relay control module:
|
||||
```cpp
|
||||
const uint8_t onoffPin = 2; // Set your relay control pin here
|
||||
```
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterOnOffPlugin.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Initial state: OFF
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
User Callback :: New Plugin State = ON
|
||||
User Callback :: New Plugin State = OFF
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides factory reset functionality:
|
||||
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
Note: This example does not include button toggle functionality. The plugin is controlled exclusively via Matter app commands.
|
||||
|
||||
### State Persistence
|
||||
|
||||
The device saves the last known on/off state using the `Preferences` library. After a power cycle or restart:
|
||||
|
||||
- The device will restore to the last saved state (ON or OFF)
|
||||
- Default state is OFF if no previous state was saved
|
||||
- The Matter controller will be notified of the restored state
|
||||
- The relay/LED will reflect the restored state
|
||||
|
||||
### Power Relay Integration
|
||||
|
||||
For production use with a power relay module:
|
||||
|
||||
1. **Connect the relay module** to your ESP32:
|
||||
- Relay VCC → ESP32 3.3 V or 5 V (check relay module specifications)
|
||||
- Relay GND → ESP32 GND
|
||||
- Relay IN → ESP32 GPIO pin (configured as `onoffPin`)
|
||||
|
||||
2. **Update the pin configuration** in the sketch:
|
||||
```cpp
|
||||
const uint8_t onoffPin = 2; // Your relay control pin
|
||||
```
|
||||
|
||||
3. **Test the relay** by controlling it via Matter app - the relay should turn on/off accordingly
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as an on/off switch/outlet in your Home app
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The plugin will appear in your Alexa app
|
||||
6. You can control it using voice commands like "Alexa, turn on the plugin" or "Alexa, turn off the plugin"
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can control it using voice commands or the app controls
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterOnOffPlugin example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, relay/LED pin), configures Wi-Fi (if needed), initializes `Preferences` library, sets up the Matter plugin endpoint with the last saved state (defaults to OFF if not previously saved), registers the callback function, and starts the Matter stack.
|
||||
|
||||
2. **`loop()`**: Checks the Matter commissioning state, handles button input for factory reset, and allows the Matter stack to process events.
|
||||
|
||||
3. **Callbacks**:
|
||||
- `setPluginOnOff()`: Controls the physical relay/LED based on the on/off state, saves the state to `Preferences` for persistence, and prints the state change to Serial Monitor.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Relay/LED not responding**: Verify pin configurations and connections. For relay modules, ensure proper power supply and wiring
|
||||
- **State not persisting**: Check that the `Preferences` library is properly initialized and that flash memory is not corrupted
|
||||
- **Relay not switching**: For relay modules, verify the control signal voltage levels match your relay module requirements (some relays need 5 V, others work with 3.3 V)
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter On/Off Plugin Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_on_off_plugin.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,140 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* This example is an example code that will create a Matter Device which can be
|
||||
* commissioned and controlled from a Matter Environment APP.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Matter Pressure Sensor Endpoint
|
||||
MatterPressureSensor SimulatedPressureSensor;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#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
|
||||
|
||||
// Simulate a pressure sensor - add your preferred pressure sensor library code here
|
||||
float getSimulatedPressure() {
|
||||
// The Endpoint implementation keeps an uint16_t as internal value information,
|
||||
// which stores data in hPa (pressure measurement unit)
|
||||
static float simulatedPressureHWSensor = 950;
|
||||
|
||||
// it will increase from 950 to 1100 hPa in steps of 10 hPa to simulate a pressure sensor
|
||||
simulatedPressureHWSensor = simulatedPressureHWSensor + 10;
|
||||
if (simulatedPressureHWSensor > 1100) {
|
||||
simulatedPressureHWSensor = 950;
|
||||
}
|
||||
|
||||
return simulatedPressureHWSensor;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// set initial pressure sensor measurement
|
||||
// Simulated Sensor - it shall initially print 900hPa and then move to the 950 to 1100 hPa as pressure range
|
||||
SimulatedPressureSensor.begin(900.00);
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
|
||||
// Check Matter Accessory 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 Pressure Sensor 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 the network. Ready for use.");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint32_t timeCounter = 0;
|
||||
|
||||
// Print the current pressure value every 5s
|
||||
if (!(timeCounter++ % 10)) { // delaying for 500ms x 10 = 5s
|
||||
// Print the current pressure value
|
||||
Serial.printf("Current Pressure is %.02fhPa\r\n", SimulatedPressureSensor.getPressure());
|
||||
// Update Pressure from the (Simulated) Hardware Sensor
|
||||
// Matter APP shall display the updated pressure percent
|
||||
SimulatedPressureSensor.setPressure(getSimulatedPressure());
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Factory reset is triggered if the button is pressed longer than 5 seconds
|
||||
Serial.println("Decommissioning Pressure Sensor Matter Accessory. It shall be commissioned again.");
|
||||
Matter.decommission();
|
||||
}
|
||||
|
||||
delay(500);
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
# Matter Pressure Sensor Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible pressure sensor device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, sensor data reporting to smart home ecosystems, and automatic simulation of pressure readings.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a pressure sensor device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Pressure measurement reporting in hectopascals (hPa)
|
||||
- Automatic simulation of pressure readings (950-1100 hPa range)
|
||||
- Periodic sensor updates every 5 seconds
|
||||
- Button control for factory reset (decommission)
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- User button for factory reset (uses BOOT button by default)
|
||||
- Optional: Connect a real pressure sensor (BMP280, BME280, BMP388, etc.) and replace the simulation function
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
3. **Real sensor integration** (optional):
|
||||
To use a real pressure sensor, replace the `getSimulatedPressure()` function with your sensor reading code. The function should return a float value representing pressure in hectopascals (hPa).
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterPressureSensor.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
Current Pressure is 900.00hPa
|
||||
Current Pressure is 950.00hPa
|
||||
Current Pressure is 960.00hPa
|
||||
...
|
||||
Current Pressure is 1100.00hPa
|
||||
Current Pressure is 950.00hPa
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides factory reset functionality:
|
||||
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Sensor Simulation
|
||||
|
||||
The example includes a simulated pressure sensor that:
|
||||
|
||||
- Starts at 900 hPa (initial value)
|
||||
- Cycles through 950 to 1100 hPa range
|
||||
- Increases in 10 hPa steps
|
||||
- Updates every 5 seconds
|
||||
- Resets to 950 hPa when reaching 1100 hPa
|
||||
|
||||
To use a real pressure sensor, replace the `getSimulatedPressure()` function with your sensor library code. For example, with a BMP280:
|
||||
|
||||
```cpp
|
||||
#include <Adafruit_BMP280.h>
|
||||
Adafruit_BMP280 bmp;
|
||||
|
||||
float getSimulatedPressure() {
|
||||
return bmp.readPressure() / 100.0; // Convert Pa to hPa
|
||||
}
|
||||
```
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a pressure sensor in your Home app
|
||||
7. You can monitor the pressure readings and set up automations based on pressure levels (e.g., weather monitoring)
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The pressure sensor will appear in your Alexa app
|
||||
6. You can monitor pressure readings and create routines based on pressure changes
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can monitor pressure readings and create automations based on pressure changes
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterPressureSensor example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button), configures Wi-Fi (if needed), sets up the Matter Pressure Sensor endpoint with initial value (900 hPa), and waits for Matter commissioning.
|
||||
|
||||
2. **`loop()`**: Displays the current pressure value every 5 seconds, updates the sensor reading from the simulated hardware sensor, handles button input for factory reset, and allows the Matter stack to process events.
|
||||
|
||||
3. **`getSimulatedPressure()`**: Simulates a hardware pressure sensor by cycling through values from 950 to 1100 hPa in 10 hPa steps. Replace this function with your actual sensor reading code.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Pressure readings not updating**: Check that the sensor simulation function is being called correctly. For real sensors, verify sensor wiring and library initialization
|
||||
- **Pressure values out of range**: Ensure pressure values are in hectopascals (hPa). The Matter protocol stores values as uint16_t internally. Typical atmospheric pressure ranges from 950-1050 hPa at sea level
|
||||
- **State not changing**: The simulated sensor increases by 10 hPa every 5 seconds. If you're using a real sensor, ensure it's properly connected and reading correctly
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Pressure Sensor Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_pressure_sensor.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,161 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* This example is an example code that will create a Matter Device which can be
|
||||
* commissioned and controlled from a Matter Environment APP.
|
||||
* 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.
|
||||
*
|
||||
* The example will create a Matter Rain Sensor Device.
|
||||
* The Rain Sensor state can be toggled by pressing the onboard button.
|
||||
* The Rain Sensor state will be indicated by the onboard LED.
|
||||
* The Rain Sensor state will be simulated to change every 20 seconds.
|
||||
*
|
||||
* The onboard button can be kept pressed for 5 seconds to decommission the Matter Node.
|
||||
* The example will also show the manual commissioning code and QR code to be used in the Matter environment.
|
||||
*
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Matter Rain Sensor Endpoint
|
||||
MatterRainSensor RainSensor;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// LED will be used to indicate the Rain Sensor state
|
||||
// set your board RGB LED pin here
|
||||
#ifdef RGB_BUILTIN
|
||||
const uint8_t ledPin = RGB_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 RGB LED pin"
|
||||
#endif
|
||||
|
||||
// set your board USER BUTTON pin here - decommissioning and Manual Rain Sensor toggle button
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||
// The button will also be used to manually toggle the Rain Sensor state
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
// Initialize the LED (light) GPIO and Matter End Point
|
||||
pinMode(ledPin, OUTPUT);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// set initial rain sensor state as false (default)
|
||||
RainSensor.begin();
|
||||
digitalWrite(ledPin, LOW); // LED OFF
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
|
||||
// Check Matter Accessory 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 Rain Sensor 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 the network. Ready for use.");
|
||||
}
|
||||
}
|
||||
|
||||
bool simulatedHWRainSensor() {
|
||||
// Simulated Rain Sensor
|
||||
static bool rainState = false;
|
||||
static uint32_t lastTime = 0;
|
||||
|
||||
// Simulate a Rain Sensor state change every 20 seconds
|
||||
if (millis() - lastTime > 20000) {
|
||||
rainState = !rainState;
|
||||
lastTime = millis();
|
||||
}
|
||||
return rainState;
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
uint32_t time_diff = millis() - button_time_stamp;
|
||||
if (button_state && time_diff > debouceTime && digitalRead(buttonPin) == HIGH) {
|
||||
button_state = false; // released
|
||||
// button is released - toggle Rain State (Not Detected/Detected)
|
||||
RainSensor.setRain(!RainSensor.getRain()); // same as RainSensor = !RainSensor;
|
||||
Serial.printf("User button released. Setting the Rain Sensor to %s.\r\n", RainSensor ? "Detected" : "Not Detected");
|
||||
// LED will indicate the Rain Sensor state
|
||||
if (RainSensor) {
|
||||
digitalWrite(ledPin, HIGH); // LED ON
|
||||
} else {
|
||||
digitalWrite(ledPin, LOW); // LED OFF
|
||||
}
|
||||
}
|
||||
|
||||
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||
if (button_state && time_diff > decommissioningTimeout) {
|
||||
Serial.println("Decommissioning Rain Sensor Matter Accessory. It shall be commissioned again.");
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||
}
|
||||
|
||||
// Simulated Rain Sensor
|
||||
RainSensor.setRain(simulatedHWRainSensor());
|
||||
|
||||
delay(50);
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
# Matter Rain Sensor Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible rain sensor device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device control via smart home ecosystems, manual control using a physical button, and automatic simulation of rain detection state changes.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | LED | Status |
|
||||
| --- | ---- | ------ | ----------------- | --- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a rain sensor device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Rain detection state indication using LED (ON = Detected, OFF = Not Detected)
|
||||
- Automatic simulation of rain detection state changes every 20 seconds
|
||||
- Button control for toggling rain detection state and factory reset
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- LED connected to GPIO pins (or using built-in LED) to indicate rain detection state
|
||||
- User button for manual control (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **LED**: Uses `RGB_BUILTIN` if defined, otherwise pin 2
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **LED pin configuration** (if not using built-in LED):
|
||||
```cpp
|
||||
const uint8_t ledPin = 2; // Set your LED pin here
|
||||
```
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for the Rain Sensor state toggle and factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterRainSensor.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
User button released. Setting the Rain Sensor to Detected.
|
||||
User button released. Setting the Rain Sensor to Not Detected.
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Short press of the button**: Toggle rain sensor state (Not Detected/Detected)
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Automatic Simulation
|
||||
|
||||
The rain sensor state automatically toggles every 20 seconds to simulate a real rain sensor. The LED will reflect the current state:
|
||||
- **LED ON**: Rain is Detected
|
||||
- **LED OFF**: Rain is Not Detected
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
Check for Matter Rain Sensor endpoint support within the Matter Controller developer webpage.
|
||||
This endpoint is part of the latest Matter supported device list and it may not be fully supported by your Matter environment.
|
||||
You can also try the Home Assistant Matter feature in order to test it.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a rain sensor in your Home app
|
||||
7. You can monitor the rain detection state (Detected/Not Detected) and receive notifications when the state changes
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The rain sensor will appear in your Alexa app
|
||||
6. You can monitor the rain detection state and set up routines based on state changes
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The rain sensor will appear in your Google Home app
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterRainSensor example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, LED), configures Wi-Fi (if needed), sets up the Matter Rain Sensor endpoint with initial state (Not Detected), and waits for Matter commissioning.
|
||||
2. **`loop()`**: Handles button input for toggling rain detection state and factory reset, and automatically simulates rain detection state changes every 20 seconds.
|
||||
3. **`simulatedHWRainSensor()`**: Simulates a hardware rain sensor by toggling the rain detection state every 20 seconds.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **LED not responding**: Verify pin configurations and connections
|
||||
- **Rain sensor state not updating**: Check Serial Monitor output to verify state changes are being processed
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Rain Sensor Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_rain_sensor.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,92 @@
|
||||
// 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 Simple Blinds Example
|
||||
// This is a minimal example that only controls Lift percentage using a single onGoToLiftPercentage() callback
|
||||
|
||||
#include <Matter.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Window Covering Endpoint
|
||||
MatterWindowCovering WindowBlinds;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// Simple callback - handles window Lift change request
|
||||
bool onBlindsLift(uint8_t liftPercent) {
|
||||
// This example only uses lift
|
||||
Serial.printf("Window Covering change request: Lift=%d%%\r\n", liftPercent);
|
||||
|
||||
// Returning true will store the new Lift value into the Matter Cluster
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
Serial.println("\n============================");
|
||||
Serial.println("Matter Simple Blinds Example");
|
||||
Serial.println("============================\n");
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println("");
|
||||
Serial.println("WiFi connected");
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
#endif
|
||||
|
||||
// Initialize Window Covering endpoint
|
||||
// Using ROLLERSHADE type (lift only, no tilt)
|
||||
WindowBlinds.begin(100, 0, MatterWindowCovering::ROLLERSHADE);
|
||||
|
||||
// Set up the onGoToLiftPercentage callback - this handles all window covering changes requested by the Matter Controller
|
||||
WindowBlinds.onGoToLiftPercentage(onBlindsLift);
|
||||
|
||||
// Start Matter
|
||||
Matter.begin();
|
||||
Serial.println("Matter started");
|
||||
Serial.println();
|
||||
|
||||
// Print commissioning information
|
||||
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());
|
||||
Serial.println("========================================");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
delay(100);
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
# Matter Simple Blinds Example
|
||||
|
||||
This is a minimal example demonstrating how to create a Matter-compatible window covering device with lift control only. This example uses a single `onGoToLiftPercentage()` callback to handle all window covering lift changes, making it ideal for simple implementations.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a window covering device
|
||||
- **Lift control only** (0-100%) - simplified implementation
|
||||
- **Single `onGoToLiftPercentage()` callback** - handles all window covering lift changes when `TargetPositionLiftPercent100ths` changes
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- Window covering motor/actuator (optional for testing - example simulates movement)
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi Credentials** (for ESP32 and ESP32-S2 only):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid";
|
||||
const char *password = "your-password";
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterSimpleBlinds.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
```
|
||||
============================
|
||||
Matter Simple Blinds Example
|
||||
============================
|
||||
|
||||
Connecting to your-ssid
|
||||
WiFi connected
|
||||
IP address: 192.168.1.100
|
||||
Matter started
|
||||
|
||||
========================================
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT:Y.K9042C00KA0648G00
|
||||
========================================
|
||||
```
|
||||
|
||||
When a command is received from the Matter controller:
|
||||
```
|
||||
Window Covering change request: Lift=50%
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
1. **Commissioning**: Use the QR code or manual pairing code to commission the device to your Matter hub (Apple Home, Google Home, or Amazon Alexa).
|
||||
|
||||
2. **Control**: Once commissioned, you can control the window covering lift percentage (0-100%) from your smart home app. The `onGoToLiftPercentage()` callback will be triggered whenever the target lift percentage changes.
|
||||
|
||||
## Code Structure
|
||||
|
||||
- **`onBlindsLift()`**: Callback function that handles window covering lift changes. This is registered with `WindowBlinds.onGoToLiftPercentage()` and is triggered when `TargetPositionLiftPercent100ths` changes. The callback receives the target lift percentage (0-100%).
|
||||
- **`setup()`**: Initializes Wi-Fi (if needed), Window Covering endpoint with `ROLLERSHADE` type, registers the callback, and starts Matter.
|
||||
- **`loop()`**: Empty - all control is handled via Matter callbacks.
|
||||
|
||||
## Customization
|
||||
|
||||
### Adding Motor Control
|
||||
|
||||
In the `onBlindsLift()` callback, replace the simulation code with actual motor control:
|
||||
|
||||
```cpp
|
||||
bool onBlindsLift(uint8_t liftPercent) {
|
||||
Serial.printf("Moving window covering to %d%%\r\n", liftPercent);
|
||||
|
||||
// Here you would control your actual motor/actuator
|
||||
// For example:
|
||||
// - Calculate target position based on liftPercent and installed limits (if configured)
|
||||
// - Move motor to target position
|
||||
// - When movement is complete, update current position:
|
||||
// WindowBlinds.setLiftPercentage(finalLiftPercent);
|
||||
// WindowBlinds.setOperationalState(MatterWindowCovering::LIFT, MatterWindowCovering::STALL);
|
||||
|
||||
// For this minimal example, we just return true to accept the command
|
||||
return true; // Indicate command was accepted
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
1. **Device not discoverable**: Ensure Wi-Fi is connected (for ESP32/ESP32-S2) or BLE is enabled (for other chips).
|
||||
|
||||
2. **Lift percentage not updating**: Check that `onGoToLiftPercentage()` callback is properly registered and that `setLiftPercentage()` is called when movement is complete to update the `CurrentPosition` attribute.
|
||||
|
||||
3. **Commands not working**: Ensure the callback returns `true` to accept the command. If it returns `false`, the command will be rejected.
|
||||
|
||||
4. **Motor not responding**: Replace the simulation code in `onBlindsLift()` with your actual motor control implementation. Remember to update `CurrentPosition` and set `OperationalState` to `STALL` when movement is complete.
|
||||
|
||||
## Notes
|
||||
|
||||
- This example uses `ROLLERSHADE` window covering type (lift only, no tilt).
|
||||
- The example accepts commands but doesn't actually move a motor. In a real implementation, you should:
|
||||
1. Move the motor to the target position in the callback
|
||||
2. Update `CurrentPositionLiftPercent100ths` using `setLiftPercentage()` when movement is complete
|
||||
3. Set `OperationalState` to `STALL` using `setOperationalState(MatterWindowCovering::LIFT, MatterWindowCovering::STALL)` to indicate the device has reached the target position
|
||||
- **Important**: `onGoToLiftPercentage()` is called when `TargetPositionLiftPercent100ths` changes. This happens when commands are executed or when a Matter controller writes directly to the target position attribute.
|
||||
- Commands modify `TargetPosition`, not `CurrentPosition`. The application is responsible for updating `CurrentPosition` when the physical device actually moves.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,122 @@
|
||||
// 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Generic Switch Endpoint - works as a smart button with a single click
|
||||
MatterGenericSwitch SmartButton;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// set your board USER BUTTON pin here
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) GPIO that will act as a smart button or to decommission the Matter Node
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// Initialize the Matter EndPoint
|
||||
SmartButton.begin();
|
||||
|
||||
// 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 the network. Ready for use.");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Check Matter Accessory 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 Generic Switch 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 the network. Ready for use.");
|
||||
}
|
||||
|
||||
// A builtin button is used to trigger a command to the Matter Controller
|
||||
// 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 smart button 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
|
||||
// builtin button is released - send a click event to the Matter Controller
|
||||
Serial.println("User button released. Sending Click to the Matter Controller!");
|
||||
// Matter Controller will receive an event and, if programmed, it will trigger an action
|
||||
SmartButton.click();
|
||||
}
|
||||
|
||||
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||
if (button_state && time_diff > decommissioningTimeout) {
|
||||
Serial.println("Decommissioning the Generic Switch Matter Accessory. It shall be commissioned again.");
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
# Matter Smart Button Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible smart button (generic switch) device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, sending button click events to smart home ecosystems, and triggering automations based on button presses.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a smart button (generic switch) device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Button click event reporting to Matter controller
|
||||
- Button control for triggering events and factory reset
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
- Automation trigger support - button presses can trigger actions in smart home apps
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- User button for triggering events (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for triggering click events and factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterSmartButton.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
User button released. Sending Click to the Matter Controller!
|
||||
User button released. Sending Click to the Matter Controller!
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides the following functionality:
|
||||
|
||||
- **Short press and release**: Sends a click event to the Matter controller (triggers automations)
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Button Click Events
|
||||
|
||||
When you press and release the button:
|
||||
|
||||
1. The button press is detected and debounced
|
||||
2. A click event is sent to the Matter controller via the Generic Switch cluster
|
||||
3. The Matter controller receives the event and can trigger programmed automations
|
||||
4. The event is logged to Serial Monitor for debugging
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device. After commissioning, you can set up automations that trigger when the button is pressed.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a switch/button in your Home app
|
||||
7. Set up automations: Go to Automation tab > Create Automation > When an accessory is controlled > Select the smart button > Choose the action (e.g., turn on lights, activate scene)
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The smart button will appear in your Alexa app
|
||||
6. Create routines: Tap More > Routines > Create Routine > When this happens > Select the smart button > Add action (e.g., turn on lights, control other devices)
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. Create automations: Tap Automations > Create Automation > When button is pressed > Choose action
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterSmartButton example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button), configures Wi-Fi (if needed), initializes the Matter Generic Switch endpoint, and starts the Matter stack.
|
||||
|
||||
2. **`loop()`**: Checks the Matter commissioning state, handles button input for sending click events and factory reset, and allows the Matter stack to process events.
|
||||
|
||||
3. **Button Event Handling**:
|
||||
- Detects button press and release with debouncing (250 ms)
|
||||
- Sends click event to Matter controller using `SmartButton.click()` when button is released
|
||||
- Handles long press (>5 seconds) for factory reset
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Button clicks not registering**: Check Serial Monitor for "User button released" messages. Verify button wiring and that debounce time is appropriate
|
||||
- **Automations not triggering**: Ensure the device is commissioned and that automations are properly configured in your Matter app. The button sends events, but automations must be set up in the app
|
||||
- **Button not responding**: Verify button pin configuration and connections. Check that the button is properly connected with pull-up resistor (INPUT_PULLUP mode)
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
- **Multiple clicks registered for single press**: Increase the debounce time in the code if needed
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Generic Switch Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_generic_switch.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,119 @@
|
||||
// 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 Status Example
|
||||
// This example demonstrates how to check enabled Matter features and connectivity status
|
||||
// It implements a basic on/off light and reports capability and connection status
|
||||
|
||||
#include <Matter.h>
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE // ESP32 and ESP32-S2 do not support BLE commissioning
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#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
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// On/Off Light Endpoint
|
||||
MatterOnOffLight OnOffLight;
|
||||
|
||||
// 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
|
||||
|
||||
// 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);
|
||||
}
|
||||
// This callback must return the success state to Matter core
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize the LED (light) GPIO
|
||||
pinMode(ledPin, OUTPUT);
|
||||
digitalWrite(ledPin, LOW); // Start with light OFF
|
||||
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
Serial.println("\n========================================");
|
||||
Serial.println("Matter Status Example");
|
||||
Serial.println("========================================\n");
|
||||
|
||||
// Report enabled features
|
||||
Serial.println("=== Enabled Features ===");
|
||||
Serial.printf("WiFi Station Enabled: %s\r\n", Matter.isWiFiStationEnabled() ? "YES" : "NO");
|
||||
Serial.printf("WiFi Access Point Enabled: %s\r\n", Matter.isWiFiAccessPointEnabled() ? "YES" : "NO");
|
||||
Serial.printf("Thread Enabled: %s\r\n", Matter.isThreadEnabled() ? "YES" : "NO");
|
||||
Serial.printf("BLE Commissioning Enabled: %s\r\n", Matter.isBLECommissioningEnabled() ? "YES" : "NO");
|
||||
Serial.println();
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
if (Matter.isWiFiStationEnabled()) {
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println("");
|
||||
Serial.println("WiFi connected");
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize On/Off Light endpoint
|
||||
OnOffLight.begin(false); // Start with light OFF
|
||||
OnOffLight.onChange(setLightOnOff);
|
||||
|
||||
// Start Matter
|
||||
Matter.begin();
|
||||
Serial.println("Matter started");
|
||||
Serial.println();
|
||||
|
||||
// Print commissioning information
|
||||
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());
|
||||
Serial.println("========================================\n");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Report connection status every 10 seconds
|
||||
Serial.println("=== Connection Status ===");
|
||||
Serial.printf("WiFi Connected: %s\r\n", Matter.isWiFiConnected() ? "YES" : "NO");
|
||||
Serial.printf("Thread Connected: %s\r\n", Matter.isThreadConnected() ? "YES" : "NO");
|
||||
Serial.printf("Device Connected: %s\r\n", Matter.isDeviceConnected() ? "YES" : "NO");
|
||||
Serial.printf("Device Commissioned: %s\r\n", Matter.isDeviceCommissioned() ? "YES" : "NO");
|
||||
Serial.println();
|
||||
delay(10000);
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
# Matter Status Example
|
||||
|
||||
This example demonstrates how to check enabled Matter features and connectivity status using the Matter library's capability query functions. It implements a basic on/off light device and periodically reports the status of enabled features and network connections.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | LED | Status |
|
||||
| --- | ---- | ------ | ----------------- | --- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for an on/off light device
|
||||
- **Capability reporting**: Checks and reports enabled Matter features at startup
|
||||
- `isWiFiStationEnabled()`: Checks if Wi-Fi Station mode is supported and enabled
|
||||
- `isWiFiAccessPointEnabled()`: Checks if Wi-Fi AP mode is supported and enabled
|
||||
- `isThreadEnabled()`: Checks if Thread network is supported and enabled
|
||||
- `isBLECommissioningEnabled()`: Checks if BLE commissioning is supported and enabled
|
||||
- **Connection status monitoring**: Reports connection status every 10 seconds
|
||||
- `isWiFiConnected()`: Checks Wi-Fi connection status (if Wi-Fi Station is enabled)
|
||||
- `isThreadConnected()`: Checks Thread connection status (if Thread is enabled)
|
||||
- `isDeviceConnected()`: Checks overall device connectivity (Wi-Fi or Thread)
|
||||
- `isDeviceCommissioned()`: Checks if the device is commissioned to a Matter fabric
|
||||
- Simple on/off light control
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- LED connected to GPIO pin (or using built-in LED) for visual feedback
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **LED**: Uses `LED_BUILTIN` if defined, otherwise pin 2
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi Credentials** (for ESP32 and ESP32-S2 only):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid";
|
||||
const char *password = "your-password";
|
||||
```
|
||||
|
||||
2. **LED pin configuration** (if not using built-in LED):
|
||||
```cpp
|
||||
const uint8_t ledPin = 2; // Set your LED pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterStatus.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. You should see output similar to the following:
|
||||
|
||||
```
|
||||
========================================
|
||||
Matter Status Example
|
||||
========================================
|
||||
|
||||
=== Enabled Features ===
|
||||
WiFi Station Enabled: YES
|
||||
WiFi Access Point Enabled: NO
|
||||
Thread Enabled: NO
|
||||
BLE Commissioning Enabled: NO
|
||||
|
||||
Connecting to your-ssid
|
||||
.......
|
||||
WiFi connected
|
||||
IP address: 192.168.1.100
|
||||
Matter started
|
||||
|
||||
========================================
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT:Y.K9042C00KA0648G00
|
||||
========================================
|
||||
|
||||
=== Connection Status ===
|
||||
WiFi Connected: YES
|
||||
Thread Connected: NO
|
||||
Device Connected: YES
|
||||
Device Commissioned: NO
|
||||
|
||||
=== Connection Status ===
|
||||
WiFi Connected: YES
|
||||
Thread Connected: NO
|
||||
Device Connected: YES
|
||||
Device Commissioned: NO
|
||||
|
||||
... (reports every 10 seconds)
|
||||
|
||||
User Callback :: New Light State = ON
|
||||
=== Connection Status ===
|
||||
WiFi Connected: YES
|
||||
Thread Connected: NO
|
||||
Device Connected: YES
|
||||
Device Commissioned: YES
|
||||
|
||||
... (reports every 10 seconds)
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Capability Queries
|
||||
|
||||
The example demonstrates the use of capability query functions that check both hardware support (SoC capabilities) and Matter configuration:
|
||||
|
||||
- **`Matter.isWiFiStationEnabled()`**: Returns `true` if the device supports Wi-Fi Station mode and it's enabled in Matter configuration
|
||||
- **`Matter.isWiFiAccessPointEnabled()`**: Returns `true` if the device supports Wi-Fi AP mode and it's enabled in Matter configuration
|
||||
- **`Matter.isThreadEnabled()`**: Returns `true` if the device supports Thread networking and it's enabled in Matter configuration
|
||||
- **`Matter.isBLECommissioningEnabled()`**: Returns `true` if the device supports BLE and BLE commissioning is enabled
|
||||
|
||||
These functions are useful for:
|
||||
- Determining which features are available on the current device
|
||||
- Adapting application behavior based on available capabilities
|
||||
- Debugging configuration issues
|
||||
|
||||
### Connection Status Monitoring
|
||||
|
||||
The example periodically reports connection status every 10 seconds:
|
||||
|
||||
- **`Matter.isWiFiConnected()`**: Returns `true` if Wi-Fi Station is connected. If Wi-Fi Station is not enabled, always returns `false`.
|
||||
- **`Matter.isThreadConnected()`**: Returns `true` if Thread is attached to a network. If Thread is not enabled, always returns `false`.
|
||||
- **`Matter.isDeviceConnected()`**: Returns `true` if the device is connected via Wi-Fi or Thread (overall connectivity status)
|
||||
- **`Matter.isDeviceCommissioned()`**: Returns `true` if the device has been commissioned to a Matter fabric
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device. Once commissioned, you can control the light from your smart home app.
|
||||
|
||||
## Code Structure
|
||||
|
||||
- **`setup()`**:
|
||||
- Initializes hardware (LED)
|
||||
- Reports enabled features using capability query functions
|
||||
- Connects to Wi-Fi (if needed and enabled)
|
||||
- Initializes On/Off Light endpoint
|
||||
- Starts Matter stack
|
||||
- Prints commissioning information
|
||||
|
||||
- **`loop()`**:
|
||||
- Reports connection status every 10 seconds
|
||||
- All light control is handled via Matter callbacks
|
||||
|
||||
- **Callbacks**:
|
||||
- `setLightOnOff()`: Controls the physical LED based on the on/off state and prints the state change to Serial Monitor
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
1. **Device not discoverable**: Ensure Wi-Fi is connected (for ESP32/ESP32-S2) or BLE is enabled (for other chips).
|
||||
|
||||
2. **Capability queries return unexpected values**: These functions check both hardware support and Matter configuration. Verify that the features are enabled in your Matter build configuration.
|
||||
|
||||
3. **Connection status not updating**: The status is reported every 10 seconds. Check Serial Monitor output to see the periodic reports.
|
||||
|
||||
4. **LED not responding**: Verify pin configurations and connections.
|
||||
|
||||
5. **Failed to commission**: Try factory resetting the device by calling `Matter.decommission()`. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter On/Off Light Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_on_off_light.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
// Copyright 2025 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*
|
||||
* This example demonstrates the Temperature Number mode of the Matter Temperature Controlled Cabinet Device.
|
||||
*
|
||||
* This example will create a Matter Device which can be commissioned and controlled from a Matter Environment APP.
|
||||
* 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.
|
||||
*
|
||||
* The example will create a Matter Temperature Controlled Cabinet Device using temperature_number feature.
|
||||
* The Temperature Controlled Cabinet can be controlled via Matter controllers to set
|
||||
* temperature setpoint with min/max limits and optional step control.
|
||||
*
|
||||
* This mode is mutually exclusive with temperature_level mode.
|
||||
* See MatterTemperatureControlledCabinetLevels example for temperature level control.
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Matter Temperature Controlled Cabinet Endpoint
|
||||
MatterTemperatureControlledCabinet TemperatureCabinet;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#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 - decommission 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
|
||||
|
||||
// Temperature control state
|
||||
struct TemperatureControlState {
|
||||
bool initialized;
|
||||
bool increasing;
|
||||
double currentSetpoint;
|
||||
double initialSetpoint;
|
||||
bool setpointReachedIncreasing;
|
||||
bool setpointReachedDecreasing;
|
||||
};
|
||||
|
||||
static TemperatureControlState tempState = {
|
||||
.initialized = false,
|
||||
.increasing = true,
|
||||
.currentSetpoint = 0.0,
|
||||
.initialSetpoint = 0.0,
|
||||
.setpointReachedIncreasing = false,
|
||||
.setpointReachedDecreasing = false
|
||||
};
|
||||
|
||||
// Initialize temperature control state
|
||||
void initTemperatureControl() {
|
||||
if (!tempState.initialized) {
|
||||
tempState.currentSetpoint = TemperatureCabinet.getTemperatureSetpoint();
|
||||
tempState.initialSetpoint = tempState.currentSetpoint;
|
||||
tempState.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check and log when initial setpoint is reached/overpassed
|
||||
void checkSetpointReached(double newSetpoint, bool isIncreasing, bool directionChanged) {
|
||||
if (directionChanged) {
|
||||
// Reset flags when direction changes
|
||||
tempState.setpointReachedIncreasing = false;
|
||||
tempState.setpointReachedDecreasing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isIncreasing && !tempState.setpointReachedIncreasing && newSetpoint >= tempState.initialSetpoint) {
|
||||
Serial.printf("*** Temperature setpoint %.02f°C reached/overpassed while increasing ***\r\n", tempState.initialSetpoint);
|
||||
tempState.setpointReachedIncreasing = true;
|
||||
} else if (!isIncreasing && !tempState.setpointReachedDecreasing && newSetpoint <= tempState.initialSetpoint) {
|
||||
Serial.printf("*** Temperature setpoint %.02f°C reached/overpassed while decreasing ***\r\n", tempState.initialSetpoint);
|
||||
tempState.setpointReachedDecreasing = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Update temperature setpoint with cycling logic
|
||||
void updateTemperatureSetpoint() {
|
||||
double minTemp = TemperatureCabinet.getMinTemperature();
|
||||
double maxTemp = TemperatureCabinet.getMaxTemperature();
|
||||
double step = TemperatureCabinet.getStep();
|
||||
|
||||
// Calculate next setpoint based on direction and step
|
||||
bool directionChanged = false;
|
||||
|
||||
if (tempState.increasing) {
|
||||
tempState.currentSetpoint += step;
|
||||
if (tempState.currentSetpoint >= maxTemp) {
|
||||
tempState.currentSetpoint = maxTemp;
|
||||
tempState.increasing = false; // Reverse direction
|
||||
directionChanged = true;
|
||||
}
|
||||
} else {
|
||||
tempState.currentSetpoint -= step;
|
||||
if (tempState.currentSetpoint <= minTemp) {
|
||||
tempState.currentSetpoint = minTemp;
|
||||
tempState.increasing = true; // Reverse direction
|
||||
directionChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if setpoint has been reached or overpassed
|
||||
checkSetpointReached(tempState.currentSetpoint, tempState.increasing, directionChanged);
|
||||
|
||||
// Update the temperature setpoint
|
||||
if (TemperatureCabinet.setTemperatureSetpoint(tempState.currentSetpoint)) {
|
||||
Serial.printf("Temperature setpoint updated to: %.02f°C (Range: %.02f°C to %.02f°C)\r\n", tempState.currentSetpoint, minTemp, maxTemp);
|
||||
} else {
|
||||
Serial.printf("Failed to update temperature setpoint to: %.02f°C\r\n", tempState.currentSetpoint);
|
||||
}
|
||||
}
|
||||
|
||||
// Print current temperature status
|
||||
void printTemperatureStatus() {
|
||||
Serial.printf(
|
||||
"Current Temperature Setpoint: %.02f°C (Range: %.02f°C to %.02f°C)\r\n", TemperatureCabinet.getTemperatureSetpoint(),
|
||||
TemperatureCabinet.getMinTemperature(), TemperatureCabinet.getMaxTemperature()
|
||||
);
|
||||
}
|
||||
|
||||
// Handle button press for decommissioning
|
||||
void handleButtonPress() {
|
||||
// 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 Temperature Controlled Cabinet Matter Accessory. It shall be commissioned again.");
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissioning again, reboot takes a second or so
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// Initialize Temperature Controlled Cabinet with:
|
||||
// - Initial setpoint: 4.0°C (typical refrigerator temperature)
|
||||
// - Min temperature: -10.0°C
|
||||
// - Max temperature: 10.0°C
|
||||
// - Step: 0.5°C (optional, for temperature_step feature)
|
||||
TemperatureCabinet.begin(4.0, -10.0, 10.0, 0.5);
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
|
||||
// Check Matter Accessory 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 Temperature Controlled Cabinet 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 the network. Ready for use.");
|
||||
}
|
||||
|
||||
// Print initial configuration
|
||||
Serial.println("\nTemperature Controlled Cabinet Configuration:");
|
||||
Serial.printf(" Setpoint: %.02f°C\n", TemperatureCabinet.getTemperatureSetpoint());
|
||||
Serial.printf(" Min Temperature: %.02f°C\n", TemperatureCabinet.getMinTemperature());
|
||||
Serial.printf(" Max Temperature: %.02f°C\n", TemperatureCabinet.getMaxTemperature());
|
||||
Serial.printf(" Step: %.02f°C\n", TemperatureCabinet.getStep());
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint32_t timeCounter = 0;
|
||||
static uint32_t lastUpdateTime = 0;
|
||||
|
||||
// Initialize temperature control state on first run
|
||||
initTemperatureControl();
|
||||
|
||||
// Update temperature setpoint dynamically every 1 second
|
||||
uint32_t currentTime = millis();
|
||||
if (currentTime - lastUpdateTime >= 1000) { // 1 second interval
|
||||
lastUpdateTime = currentTime;
|
||||
updateTemperatureSetpoint();
|
||||
}
|
||||
|
||||
// Print the current temperature setpoint every 5s
|
||||
if (!(timeCounter++ % 10)) { // delaying for 500ms x 10 = 5s
|
||||
printTemperatureStatus();
|
||||
}
|
||||
|
||||
// Handle button press for decommissioning
|
||||
handleButtonPress();
|
||||
|
||||
delay(500);
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
# Matter Temperature Controlled Cabinet Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible temperature controlled cabinet device using an ESP32 SoC microcontroller with the **temperature_number** feature mode. This mode provides precise temperature setpoint control with min/max limits and optional step control.
|
||||
|
||||
**Important:** The `temperature_number` and `temperature_level` features are **mutually exclusive**. Only one can be enabled at a time. See `MatterTemperatureControlledCabinetLevels` example for temperature level control mode.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a temperature controlled cabinet device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Temperature setpoint control with min/max limits
|
||||
- Temperature step control (always enabled, can be set via begin() or setStep())
|
||||
- Temperature setpoint validation against min/max limits
|
||||
- Button control for factory reset (decommission)
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Use Case
|
||||
|
||||
Use this mode when you need precise temperature control with specific setpoint values (e.g., 4.0°C for a refrigerator, -18.0°C for a freezer). For preset-based temperature control using levels, see the `MatterTemperatureControlledCabinetLevels` example.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- User button for factory reset (uses BOOT button by default)
|
||||
- Optional: Connect temperature control hardware (relays, heaters, coolers, etc.) to implement actual temperature control
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
3. **Temperature range configuration** (optional):
|
||||
Adjust the initial temperature setpoint, min, max, and step values in the `begin()` call:
|
||||
```cpp
|
||||
TemperatureCabinet.begin(4.0, -10.0, 10.0, 0.5);
|
||||
// Parameters: setpoint, min_temp, max_temp, step (all in Celsius)
|
||||
// Note: Step can also be set later using setStep() even if not provided here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterTemperatureControlledCabinet.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
|
||||
Temperature Controlled Cabinet Configuration:
|
||||
Setpoint: 4.00°C
|
||||
Min Temperature: -10.00°C
|
||||
Max Temperature: 10.00°C
|
||||
Step: 0.50°C
|
||||
Temperature setpoint updated to: 4.50°C (Range: -10.00°C to 10.00°C)
|
||||
*** Temperature setpoint 4.00°C reached/overpassed while increasing ***
|
||||
Temperature setpoint updated to: 5.00°C (Range: -10.00°C to 10.00°C)
|
||||
Temperature setpoint updated to: 5.50°C (Range: -10.00°C to 10.00°C)
|
||||
...
|
||||
Current Temperature Setpoint: 6.00°C (Range: -10.00°C to 10.00°C)
|
||||
...
|
||||
*** Temperature setpoint 4.00°C reached/overpassed while decreasing ***
|
||||
Temperature setpoint updated to: 3.50°C (Range: -10.00°C to 10.00°C)
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a temperature controlled cabinet in your Home app
|
||||
7. You can adjust the temperature setpoint within the min/max range
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The temperature controlled cabinet will appear in your Alexa app
|
||||
6. You can control the temperature setpoint and set up routines
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The temperature controlled cabinet will appear in your Google Home app
|
||||
7. You can control the temperature setpoint
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterTemperatureControlledCabinet example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button), configures Wi-Fi (if needed), sets up the Matter Temperature Controlled Cabinet endpoint with initial temperature configuration, and waits for Matter commissioning.
|
||||
|
||||
2. **`loop()`**:
|
||||
- **Dynamic Temperature Updates**: Automatically changes the temperature setpoint every 1 second, cycling between the minimum and maximum temperature limits using the configured step value. This demonstrates the temperature control functionality and allows Matter controllers to observe real-time changes.
|
||||
- **Setpoint Reached Detection**: Monitors when the initial setpoint is reached or overpassed in each direction and prints a notification message once per direction.
|
||||
- Periodically prints the current temperature setpoint (every 5 seconds)
|
||||
- Handles button input for factory reset
|
||||
|
||||
3. **Helper Functions**:
|
||||
- `initTemperatureControl()`: Initializes the temperature control state from the current setpoint
|
||||
- `checkSetpointReached()`: Checks and logs when the initial setpoint is reached/overpassed
|
||||
- `updateTemperatureSetpoint()`: Updates the temperature setpoint with cycling logic and boundary detection
|
||||
- `printTemperatureStatus()`: Prints the current temperature status
|
||||
- `handleButtonPress()`: Handles button press detection and factory reset functionality
|
||||
|
||||
## API Usage
|
||||
|
||||
The example demonstrates the following API methods:
|
||||
|
||||
- `begin(tempSetpoint, minTemperature, maxTemperature, step)` - Initialize the cabinet with temperature settings
|
||||
- `getTemperatureSetpoint()` - Get current temperature setpoint
|
||||
- `setTemperatureSetpoint(temperature)` - Set temperature setpoint (validated against min/max)
|
||||
- `getMinTemperature()` / `getMaxTemperature()` - Get temperature limits
|
||||
- `setMinTemperature(temperature)` / `setMaxTemperature(temperature)` - Set temperature limits
|
||||
- `getStep()` / `setStep(step)` - Get/set temperature step value
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Temperature setpoint not updating**: Check Serial Monitor output to verify setpoint changes are being processed
|
||||
- **Setpoint out of range error**: Ensure the setpoint is within the min/max temperature range
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Temperature Controlled Cabinet Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_temperature_controlled_cabinet.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
+279
@@ -0,0 +1,279 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* This example demonstrates the Temperature Level mode of the Matter Temperature Controlled Cabinet Device.
|
||||
*
|
||||
* This example will create a Matter Device which can be commissioned and controlled from a Matter Environment APP.
|
||||
* 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.
|
||||
*
|
||||
* The example will create a Matter Temperature Controlled Cabinet Device using temperature_level feature.
|
||||
* The Temperature Controlled Cabinet can be controlled via Matter controllers to set
|
||||
* temperature levels from a predefined array of supported levels.
|
||||
*
|
||||
* This mode is mutually exclusive with temperature_number mode.
|
||||
* See MatterTemperatureControlledCabinet example for temperature setpoint control.
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Matter Temperature Controlled Cabinet Endpoint
|
||||
MatterTemperatureControlledCabinet TemperatureCabinet;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#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 - decommission 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
|
||||
|
||||
// Temperature levels array - these represent different temperature presets
|
||||
// Example: 0 = Off, 1 = Low, 2 = Medium, 3 = High, 4 = Maximum
|
||||
// The actual temperature values are application-specific
|
||||
uint8_t supportedLevels[] = {0, 1, 2, 3, 4};
|
||||
const uint16_t levelCount = sizeof(supportedLevels) / sizeof(supportedLevels[0]);
|
||||
const uint8_t initialLevel = 2; // Start with level 2 (Medium)
|
||||
|
||||
// Temperature level control state
|
||||
struct LevelControlState {
|
||||
bool initialized;
|
||||
bool increasing;
|
||||
uint16_t currentLevelIndex;
|
||||
uint8_t initialLevel;
|
||||
bool levelReachedIncreasing;
|
||||
bool levelReachedDecreasing;
|
||||
};
|
||||
|
||||
static LevelControlState levelState = {
|
||||
.initialized = false, .increasing = true, .currentLevelIndex = 0, .initialLevel = 0, .levelReachedIncreasing = false, .levelReachedDecreasing = false
|
||||
};
|
||||
|
||||
// Initialize level control state
|
||||
void initLevelControl() {
|
||||
if (!levelState.initialized) {
|
||||
uint8_t currentLevel = TemperatureCabinet.getSelectedTemperatureLevel();
|
||||
levelState.initialLevel = currentLevel;
|
||||
// Find the index of current level in supportedLevels array
|
||||
for (uint16_t i = 0; i < levelCount; i++) {
|
||||
if (supportedLevels[i] == currentLevel) {
|
||||
levelState.currentLevelIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
levelState.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check and log when initial level is reached/overpassed
|
||||
void checkLevelReached(uint8_t newLevel, bool isIncreasing, bool directionChanged) {
|
||||
if (directionChanged) {
|
||||
// Reset flags when direction changes
|
||||
levelState.levelReachedIncreasing = false;
|
||||
levelState.levelReachedDecreasing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isIncreasing && !levelState.levelReachedIncreasing && newLevel >= levelState.initialLevel) {
|
||||
Serial.printf("*** Temperature level %u reached/overpassed while increasing ***\r\n", levelState.initialLevel);
|
||||
levelState.levelReachedIncreasing = true;
|
||||
} else if (!isIncreasing && !levelState.levelReachedDecreasing && newLevel <= levelState.initialLevel) {
|
||||
Serial.printf("*** Temperature level %u reached/overpassed while decreasing ***\r\n", levelState.initialLevel);
|
||||
levelState.levelReachedDecreasing = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Update temperature level with cycling logic
|
||||
void updateTemperatureLevel() {
|
||||
// Cycle through supported levels in both directions
|
||||
bool directionChanged = false;
|
||||
|
||||
if (levelState.increasing) {
|
||||
levelState.currentLevelIndex++;
|
||||
if (levelState.currentLevelIndex >= levelCount) {
|
||||
levelState.currentLevelIndex = levelCount - 1;
|
||||
levelState.increasing = false; // Reverse direction
|
||||
directionChanged = true;
|
||||
}
|
||||
} else {
|
||||
if (levelState.currentLevelIndex == 0) {
|
||||
levelState.currentLevelIndex = 0;
|
||||
levelState.increasing = true; // Reverse direction
|
||||
directionChanged = true;
|
||||
} else {
|
||||
levelState.currentLevelIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t newLevel = supportedLevels[levelState.currentLevelIndex];
|
||||
|
||||
// Check if initial level has been reached or overpassed
|
||||
checkLevelReached(newLevel, levelState.increasing, directionChanged);
|
||||
|
||||
// Update the temperature level
|
||||
if (TemperatureCabinet.setSelectedTemperatureLevel(newLevel)) {
|
||||
Serial.printf("Temperature level updated to: %u (Supported Levels: ", newLevel);
|
||||
for (uint16_t i = 0; i < levelCount; i++) {
|
||||
Serial.printf("%u", supportedLevels[i]);
|
||||
if (i < levelCount - 1) {
|
||||
Serial.print(", ");
|
||||
}
|
||||
}
|
||||
Serial.println(")");
|
||||
} else {
|
||||
Serial.printf("Failed to update temperature level to: %u\r\n", newLevel);
|
||||
}
|
||||
}
|
||||
|
||||
// Print current level status
|
||||
void printLevelStatus() {
|
||||
uint8_t currentLevel = TemperatureCabinet.getSelectedTemperatureLevel();
|
||||
Serial.printf("Current Temperature Level: %u (Supported Levels: ", currentLevel);
|
||||
for (uint16_t i = 0; i < levelCount; i++) {
|
||||
Serial.printf("%u", supportedLevels[i]);
|
||||
if (i < levelCount - 1) {
|
||||
Serial.print(", ");
|
||||
}
|
||||
}
|
||||
Serial.println(")");
|
||||
}
|
||||
|
||||
// Handle button press for decommissioning
|
||||
void handleButtonPress() {
|
||||
// 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 Temperature Controlled Cabinet Matter Accessory. It shall be commissioned again.");
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissioning again, reboot takes a second or so
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// Initialize Temperature Controlled Cabinet with temperature_level feature:
|
||||
// - supportedLevels: Array of temperature level values (0-255)
|
||||
// - levelCount: Number of levels in the array
|
||||
// - initialLevel: Initial selected temperature level
|
||||
//
|
||||
// Note: This mode is mutually exclusive with temperature_number mode.
|
||||
// See MatterTemperatureControlledCabinet example for temperature setpoint control.
|
||||
if (!TemperatureCabinet.begin(supportedLevels, levelCount, initialLevel)) {
|
||||
Serial.println("Failed to initialize Temperature Controlled Cabinet!");
|
||||
while (1) {
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
|
||||
// Check Matter Accessory 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 Temperature Controlled Cabinet 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 the network. Ready for use.");
|
||||
}
|
||||
|
||||
// Print initial configuration
|
||||
Serial.println("\nTemperature Controlled Cabinet Configuration (Temperature Level Mode):");
|
||||
Serial.printf(" Selected Level: %u\n", TemperatureCabinet.getSelectedTemperatureLevel());
|
||||
Serial.printf(" Supported Levels Count: %u\n", TemperatureCabinet.getSupportedTemperatureLevelsCount());
|
||||
Serial.print(" Supported Levels: ");
|
||||
for (uint16_t i = 0; i < levelCount; i++) {
|
||||
Serial.printf("%u", supportedLevels[i]);
|
||||
if (i < levelCount - 1) {
|
||||
Serial.print(", ");
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint32_t timeCounter = 0;
|
||||
static uint32_t lastUpdateTime = 0;
|
||||
|
||||
// Initialize level control state on first run
|
||||
initLevelControl();
|
||||
|
||||
// Update temperature level dynamically every 1 second
|
||||
uint32_t currentTime = millis();
|
||||
if (currentTime - lastUpdateTime >= 1000) { // 1 second interval
|
||||
lastUpdateTime = currentTime;
|
||||
updateTemperatureLevel();
|
||||
}
|
||||
|
||||
// Print the current temperature level every 5s
|
||||
if (!(timeCounter++ % 10)) { // delaying for 500ms x 10 = 5s
|
||||
printLevelStatus();
|
||||
}
|
||||
|
||||
// Handle button press for decommissioning
|
||||
handleButtonPress();
|
||||
|
||||
delay(500);
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
# Matter Temperature Controlled Cabinet Example (Temperature Level Mode)
|
||||
|
||||
This example demonstrates how to create a Matter-compatible temperature controlled cabinet device using the **temperature_level** feature mode. This mode provides temperature control using predefined levels (e.g., Off, Low, Medium, High, Maximum) rather than precise temperature setpoint values.
|
||||
|
||||
**Important:** The `temperature_number` and `temperature_level` features are **mutually exclusive**. Only one can be enabled at a time. See `MatterTemperatureControlledCabinet` example for temperature setpoint control mode.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a temperature controlled cabinet device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Temperature level control with array of supported levels
|
||||
- Up to 16 predefined temperature levels
|
||||
- Button control for factory reset (decommission)
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Use Case
|
||||
|
||||
Use this mode when you need simple preset-based temperature control (e.g., 0=Off, 1=Low, 2=Medium, 3=High, 4=Maximum) rather than precise temperature values. This is ideal for devices where users select from predefined temperature presets rather than setting exact temperatures.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- User button for factory reset (uses BOOT button by default)
|
||||
- Optional: Connect temperature control hardware (relays, heaters, coolers, etc.) to implement actual temperature control
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
3. **Temperature levels configuration** (optional):
|
||||
Adjust the supported levels array and initial level in the sketch:
|
||||
```cpp
|
||||
uint8_t supportedLevels[] = {0, 1, 2, 3, 4}; // Define your levels
|
||||
const uint16_t levelCount = sizeof(supportedLevels) / sizeof(supportedLevels[0]);
|
||||
const uint8_t initialLevel = 2; // Initial selected level
|
||||
TemperatureCabinet.begin(supportedLevels, levelCount, initialLevel);
|
||||
// Note: The array is copied internally, so it doesn't need to remain valid after begin() returns
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterTemperatureControlledCabinetLevels.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
|
||||
Temperature Controlled Cabinet Configuration (Temperature Level Mode):
|
||||
Selected Level: 2
|
||||
Supported Levels Count: 5
|
||||
Supported Levels: 0, 1, 2, 3, 4
|
||||
Temperature level updated to: 3 (Supported Levels: 0, 1, 2, 3, 4)
|
||||
*** Temperature level 2 reached/overpassed while increasing ***
|
||||
Temperature level updated to: 4 (Supported Levels: 0, 1, 2, 3, 4)
|
||||
Temperature level updated to: 3 (Supported Levels: 0, 1, 2, 3, 4)
|
||||
Temperature level updated to: 2 (Supported Levels: 0, 1, 2, 3, 4)
|
||||
*** Temperature level 2 reached/overpassed while decreasing ***
|
||||
Temperature level updated to: 1 (Supported Levels: 0, 1, 2, 3, 4)
|
||||
...
|
||||
Current Temperature Level: 2 (Supported Levels: 0, 1, 2, 3, 4)
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a temperature controlled cabinet in your Home app
|
||||
7. You can select from the available temperature levels
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The temperature controlled cabinet will appear in your Alexa app
|
||||
6. You can select temperature levels and set up routines
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The temperature controlled cabinet will appear in your Google Home app
|
||||
7. You can select from available temperature levels
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterTemperatureControlledCabinetLevels example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button), configures Wi-Fi (if needed), sets up the Matter Temperature Controlled Cabinet endpoint with temperature level configuration, and waits for Matter commissioning.
|
||||
|
||||
2. **`loop()`**:
|
||||
- **Dynamic Level Updates**: Automatically cycles through all supported temperature levels every 1 second in both directions (increasing and decreasing). This demonstrates the temperature level control functionality and allows Matter controllers to observe real-time changes.
|
||||
- **Level Reached Detection**: Monitors when the initial level is reached or overpassed in each direction and prints a notification message once per direction.
|
||||
- Periodically prints the current temperature level (every 5 seconds)
|
||||
- Handles button input for factory reset
|
||||
|
||||
3. **Helper Functions**:
|
||||
- `initLevelControl()`: Initializes the level control state from the current selected level
|
||||
- `checkLevelReached()`: Checks and logs when the initial level is reached/overpassed
|
||||
- `updateTemperatureLevel()`: Updates the temperature level with cycling logic and boundary detection
|
||||
- `printLevelStatus()`: Prints the current level status
|
||||
- `handleButtonPress()`: Handles button press detection and factory reset functionality
|
||||
|
||||
## API Usage
|
||||
|
||||
The example demonstrates the following API methods:
|
||||
|
||||
- `begin(supportedLevels, levelCount, selectedLevel)` - Initialize the cabinet with temperature levels
|
||||
- `getSelectedTemperatureLevel()` - Get current selected temperature level
|
||||
- `setSelectedTemperatureLevel(level)` - Set selected temperature level
|
||||
- `getSupportedTemperatureLevelsCount()` - Get count of supported levels
|
||||
- `setSupportedTemperatureLevels(levels, count)` - Set supported temperature levels array
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Temperature level not updating**: Check Serial Monitor output to verify level changes are being processed
|
||||
- **Invalid level error**: Ensure the selected level is in the supported levels array
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
- **Wrong mode error**: Remember that temperature_number and temperature_level modes are mutually exclusive. Make sure you're using the correct example and API methods for temperature level mode
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Temperature Controlled Cabinet Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_temperature_controlled_cabinet.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,205 @@
|
||||
// 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
#include <Preferences.h>
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Color Temperature CW/WW Light Endpoint
|
||||
MatterColorTemperatureLight CW_WW_Light;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// it will keep last OnOff & Brightness state stored, using Preferences
|
||||
Preferences matterPref;
|
||||
const char *onOffPrefKey = "OnOff";
|
||||
const char *brightnessPrefKey = "Brightness";
|
||||
const char *temperaturePrefKey = "Temperature";
|
||||
|
||||
// set your board RGB LED pin here
|
||||
#ifdef RGB_BUILTIN
|
||||
const uint8_t ledPin = RGB_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 RGB LED pin"
|
||||
#endif
|
||||
|
||||
// set your board USER BUTTON pin here
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||
|
||||
// Set the RGB LED Light based on the current state of the Color Temperature Light
|
||||
bool setLightState(bool state, uint8_t brightness, uint16_t temperature_Mireds) {
|
||||
|
||||
if (state) {
|
||||
#ifdef RGB_BUILTIN
|
||||
espRgbColor_t rgb_ct = espCTToRgbColor(temperature_Mireds);
|
||||
// simple intensity correction
|
||||
float brightnessPercent = (float)brightness / MatterColorTemperatureLight::MAX_BRIGHTNESS;
|
||||
rgb_ct.r = brightnessPercent * rgb_ct.r;
|
||||
rgb_ct.g = brightnessPercent * rgb_ct.g;
|
||||
rgb_ct.b = brightnessPercent * rgb_ct.b;
|
||||
// set the RGB LED
|
||||
rgbLedWrite(ledPin, rgb_ct.r, rgb_ct.g, rgb_ct.b);
|
||||
#else
|
||||
// No Color RGB LED, just use the brightness to control the LED
|
||||
analogWrite(ledPin, brightness);
|
||||
#endif
|
||||
} else {
|
||||
#ifndef RGB_BUILTIN
|
||||
// after analogWrite(), it is necessary to set the GPIO to digital mode first
|
||||
pinMode(ledPin, OUTPUT);
|
||||
#endif
|
||||
digitalWrite(ledPin, LOW);
|
||||
}
|
||||
// store last Brightness and OnOff state for when the Light is restarted / power goes off
|
||||
matterPref.putUChar(brightnessPrefKey, brightness);
|
||||
matterPref.putBool(onOffPrefKey, state);
|
||||
matterPref.putUShort(temperaturePrefKey, temperature_Mireds);
|
||||
// This callback must return the success state to Matter core
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// Initialize Matter EndPoint
|
||||
matterPref.begin("MatterPrefs", false);
|
||||
// default OnOff state is ON if not stored before
|
||||
bool lastOnOffState = matterPref.getBool(onOffPrefKey, true);
|
||||
// default brightness ~= 6% (15/255)
|
||||
uint8_t lastBrightness = matterPref.getUChar(brightnessPrefKey, 15);
|
||||
// default temperature ~= 454 Mireds (Warm White)
|
||||
uint16_t lastTemperature = matterPref.getUShort(temperaturePrefKey, WARM_WHITE_COLOR_TEMPERATURE.ctMireds);
|
||||
CW_WW_Light.begin(lastOnOffState, lastBrightness, lastTemperature);
|
||||
// set the callback function to handle the Light state change
|
||||
CW_WW_Light.onChange(setLightState);
|
||||
|
||||
// lambda functions are used to set the attribute change callbacks
|
||||
CW_WW_Light.onChangeOnOff([](bool state) {
|
||||
Serial.printf("Light OnOff changed to %s\r\n", state ? "ON" : "OFF");
|
||||
return true;
|
||||
});
|
||||
CW_WW_Light.onChangeBrightness([](uint8_t level) {
|
||||
Serial.printf("Light Brightness changed to %d\r\n", level);
|
||||
return true;
|
||||
});
|
||||
CW_WW_Light.onChangeColorTemperature([](uint16_t temperature) {
|
||||
Serial.printf("Light Color Temperature changed to %d\r\n", temperature);
|
||||
return true;
|
||||
});
|
||||
|
||||
// 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 the network. Ready for use.");
|
||||
Serial.printf(
|
||||
"Initial state: %s | brightness: %d | Color Temperature: %d mireds \r\n", CW_WW_Light ? "ON" : "OFF", CW_WW_Light.getBrightness(),
|
||||
CW_WW_Light.getColorTemperature()
|
||||
);
|
||||
// configure the Light based on initial on-off state and brightness
|
||||
CW_WW_Light.updateAccessory();
|
||||
}
|
||||
}
|
||||
|
||||
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 | brightness: %d | Color Temperature: %d mireds \r\n", CW_WW_Light ? "ON" : "OFF", CW_WW_Light.getBrightness(),
|
||||
CW_WW_Light.getColorTemperature()
|
||||
);
|
||||
// configure the Light based on initial on-off state and brightness
|
||||
CW_WW_Light.updateAccessory();
|
||||
Serial.println("Matter Node is commissioned and connected to the network. 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!");
|
||||
CW_WW_Light.toggle(); // Matter Controller also can see the change
|
||||
}
|
||||
|
||||
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||
if (button_state && time_diff > decommissioningTimeout) {
|
||||
Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again.");
|
||||
CW_WW_Light = false; // turn the light off
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
# Matter Color Temperature Light Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible color temperature light device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device control via smart home ecosystems, and manual control using a physical button. The color temperature light provides warm white to cool white control with adjustable brightness.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | RGB LED | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a color temperature light device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Color temperature control (warm white to cool white, 100-500 mireds)
|
||||
- Brightness level control (0-255)
|
||||
- State persistence using `Preferences` library
|
||||
- Button control for toggling light and factory reset
|
||||
- RGB LED support with color temperature to RGB conversion
|
||||
- Regular LED support with PWM brightness control
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- RGB LED connected to GPIO pins (or using built-in RGB LED), or regular LED for PWM brightness control
|
||||
- User button for manual control (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **RGB LED**: Uses `RGB_BUILTIN` if defined, otherwise pin 2
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Preferences`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **LED pin configuration** (if not using built-in RGB LED):
|
||||
```cpp
|
||||
const uint8_t ledPin = 2; // Set your RGB LED pin here
|
||||
```
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for the Light On/Off manual control. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterTemperatureLight.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Initial state: ON | brightness: 15 | Color Temperature: 454 mireds
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
Light OnOff changed to ON
|
||||
Light Brightness changed to 128
|
||||
Light Color Temperature changed to 370
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Short press of the button**: Toggle light on/off
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Color Temperature Control
|
||||
|
||||
The light supports color temperature adjustment from warm white to cool white:
|
||||
|
||||
- **Warm White**: Higher mired values (400-500 mireds) - warmer, more yellow light
|
||||
- **Cool White**: Lower mired values (100-200 mireds) - cooler, more blue light
|
||||
- **Default**: 454 mireds (Warm White)
|
||||
|
||||
The color temperature is stored in `Preferences` and restored after power cycles.
|
||||
|
||||
### Brightness Control
|
||||
|
||||
The light supports brightness adjustment from 0 to 255:
|
||||
|
||||
- **0**: Light is off
|
||||
- **1-254**: Various brightness levels
|
||||
- **255**: Maximum brightness
|
||||
- **Default**: 15 (~6% brightness)
|
||||
|
||||
The brightness level is stored in `Preferences` and restored after power cycles.
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a color temperature light in your Home app
|
||||
7. You can adjust the color temperature (warm/cool) and brightness from the Home app
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The light will appear in your Alexa app
|
||||
6. You can control color temperature and brightness using voice commands or the app
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can adjust color temperature and brightness from the Google Home app
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterTemperatureLight example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, LED), configures Wi-Fi (if needed), sets up the Matter Color Temperature Light endpoint, restores the last known state from `Preferences` (on/off, brightness, color temperature), and registers callbacks for state changes.
|
||||
|
||||
2. **`loop()`**: Checks the Matter commissioning state, handles button input for toggling the light and factory reset, and allows the Matter stack to process events.
|
||||
|
||||
3. **Callbacks**:
|
||||
- `setLightState()`: Controls the physical LED. For RGB LEDs, converts color temperature (mireds) to RGB color and applies brightness. For regular LEDs, uses PWM brightness control.
|
||||
- `onChangeOnOff()`: Handles on/off state changes and logs to Serial Monitor.
|
||||
- `onChangeBrightness()`: Handles brightness changes and logs to Serial Monitor.
|
||||
- `onChangeColorTemperature()`: Handles color temperature changes and logs to Serial Monitor.
|
||||
|
||||
4. **State Persistence**: Uses `Preferences` library to store and restore:
|
||||
- On/off state (default: ON if not previously stored)
|
||||
- Brightness level (default: 15 if not previously stored)
|
||||
- Color temperature in mireds (default: 454 mireds - Warm White if not previously stored)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **RGB LED not responding**: Verify pin configurations and connections. For RGB LEDs, ensure the board defines `RGB_BUILTIN` or set the pin manually
|
||||
- **LED not showing color temperature correctly**: RGB LED conversion uses `espCTToRgbColor()` function. For regular LEDs, only brightness is controlled via PWM
|
||||
- **Color temperature not changing**: Verify that color temperature is within valid range (100-500 mireds). Check Serial Monitor for callback messages
|
||||
- **Brightness not responding**: Ensure LED pin supports PWM output. Check Serial Monitor for brightness change messages
|
||||
- **State not persisting**: Verify `Preferences` library is working correctly. Check that flash memory is not full
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Color Temperature Light Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_color_temperature_light.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,140 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* This example is an example code that will create a Matter Device which can be
|
||||
* commissioned and controlled from a Matter Environment APP.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Matter Temperature Sensor Endpoint
|
||||
MatterTemperatureSensor SimulatedTemperatureSensor;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#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
|
||||
|
||||
// Simulate a temperature sensor - add your preferred temperature sensor library code here
|
||||
float getSimulatedTemperature() {
|
||||
// The Endpoint implementation keeps an int16_t as internal value information,
|
||||
// which stores data in 1/100th Celsius.
|
||||
static float simulatedTempHWSensor = -10.0;
|
||||
|
||||
// it will increase from -10C to 10C in 0.5C steps to simulate a temperature sensor
|
||||
simulatedTempHWSensor = simulatedTempHWSensor + 0.5;
|
||||
if (simulatedTempHWSensor > 10) {
|
||||
simulatedTempHWSensor = -10;
|
||||
}
|
||||
|
||||
return simulatedTempHWSensor;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// set initial temperature sensor measurement
|
||||
// Simulated Sensor - it shall initially print -25C and then move to the -10C to 10C range
|
||||
SimulatedTemperatureSensor.begin(-25.00);
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
|
||||
// Check Matter Accessory 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 Temperature Sensor 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 the network. Ready for use.");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint32_t timeCounter = 0;
|
||||
|
||||
// Print the current temperature value every 5s
|
||||
if (!(timeCounter++ % 10)) { // delaying for 500ms x 10 = 5s
|
||||
// Print the current temperature value
|
||||
Serial.printf("Current Temperature is %.02fC\r\n", SimulatedTemperatureSensor.getTemperature());
|
||||
// Update Temperature from the (Simulated) Hardware Sensor
|
||||
// Matter APP shall display the updated temperature percent
|
||||
SimulatedTemperatureSensor.setTemperature(getSimulatedTemperature());
|
||||
}
|
||||
|
||||
// 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 Temperature Sensor 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);
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
# Matter Temperature Sensor Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible temperature sensor device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, sensor data reporting to smart home ecosystems, and automatic simulation of temperature readings.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a temperature sensor device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Temperature measurement reporting in Celsius
|
||||
- Automatic simulation of temperature readings (-10°C to 10°C range)
|
||||
- Periodic sensor updates every 5 seconds
|
||||
- Button control for factory reset (decommission)
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- User button for factory reset (uses BOOT button by default)
|
||||
- Optional: Connect a real temperature sensor (DS18B20, DHT22, BMP280, BME280, etc.) and replace the simulation function
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
3. **Real sensor integration** (optional):
|
||||
To use a real temperature sensor, replace the `getSimulatedTemperature()` function with your sensor reading code. The function should return a float value representing temperature in Celsius.
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterTemperatureSensor.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
Current Temperature is -25.00C
|
||||
Current Temperature is -10.00C
|
||||
Current Temperature is -9.50C
|
||||
...
|
||||
Current Temperature is 10.00C
|
||||
Current Temperature is -10.00C
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides factory reset functionality:
|
||||
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Sensor Simulation
|
||||
|
||||
The example includes a simulated temperature sensor that:
|
||||
|
||||
- Starts at -25°C (initial value)
|
||||
- Cycles through -10°C to 10°C range
|
||||
- Increases in 0.5°C steps
|
||||
- Updates every 5 seconds
|
||||
- Resets to -10°C when reaching 10°C
|
||||
|
||||
To use a real temperature sensor, replace the `getSimulatedTemperature()` function with your sensor library code. For example, with a DS18B20:
|
||||
|
||||
```cpp
|
||||
#include <OneWire.h>
|
||||
#include <DallasTemperature.h>
|
||||
|
||||
OneWire oneWire(4); // GPIO pin connected to DS18B20
|
||||
DallasTemperature sensors(&oneWire);
|
||||
|
||||
float getSimulatedTemperature() {
|
||||
sensors.requestTemperatures();
|
||||
return sensors.getTempCByIndex(0);
|
||||
}
|
||||
```
|
||||
|
||||
Or with a DHT22:
|
||||
|
||||
```cpp
|
||||
#include <DHT.h>
|
||||
DHT dht(DHT_PIN, DHT22);
|
||||
|
||||
float getSimulatedTemperature() {
|
||||
return dht.readTemperature();
|
||||
}
|
||||
```
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a temperature sensor in your Home app
|
||||
7. You can monitor the temperature readings and set up automations based on temperature levels (e.g., turn on AC when temperature exceeds threshold)
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The temperature sensor will appear in your Alexa app
|
||||
6. You can monitor temperature readings and create routines based on temperature changes
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can monitor temperature readings and create automations based on temperature changes
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterTemperatureSensor example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button), configures Wi-Fi (if needed), sets up the Matter Temperature Sensor endpoint with initial value (-25°C), and waits for Matter commissioning.
|
||||
|
||||
2. **`loop()`**: Displays the current temperature value every 5 seconds, updates the sensor reading from the simulated hardware sensor, handles button input for factory reset, and allows the Matter stack to process events.
|
||||
|
||||
3. **`getSimulatedTemperature()`**: Simulates a hardware temperature sensor by cycling through values from -10°C to 10°C in 0.5°C steps. Replace this function with your actual sensor reading code.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Temperature readings not updating**: Check that the sensor simulation function is being called correctly. For real sensors, verify sensor wiring and library initialization
|
||||
- **Temperature values out of range**: Ensure temperature values are in Celsius. The Matter protocol stores values as int16_t internally (1/100th of a degree Celsius), so -273.15°C (absolute zero) to 327.67°C is the valid range
|
||||
- **State not changing**: The simulated sensor increases by 0.5°C every 5 seconds. If you're using a real sensor, ensure it's properly connected and reading correctly
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Temperature Sensor Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_temperature_sensor.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,252 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
This example is an example code that will create a Matter Device which can be
|
||||
commissioned and controlled from a Matter Environment APP.
|
||||
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.
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Matter Thermostat Endpoint
|
||||
MatterThermostat SimulatedThermostat;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#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
|
||||
|
||||
// Simulate a system that will activate heating/cooling in addition to a temperature sensor - add your preferred code here
|
||||
float getSimulatedTemperature(bool isHeating, bool isCooling) {
|
||||
// read sensor temperature and apply heating/cooling
|
||||
float simulatedTempHWSensor = SimulatedThermostat.getLocalTemperature();
|
||||
|
||||
if (isHeating) {
|
||||
// it will increase to simulate a heating system
|
||||
simulatedTempHWSensor = simulatedTempHWSensor + 0.5;
|
||||
}
|
||||
if (isCooling) {
|
||||
// it will decrease to simulate a colling system
|
||||
simulatedTempHWSensor = simulatedTempHWSensor - 0.5;
|
||||
}
|
||||
// otherwise, it will keep the temperature stable
|
||||
return simulatedTempHWSensor;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// Simulated Thermostat in COOLING and HEATING mode with Auto Mode to keep the temperature between setpoints
|
||||
// Auto Mode can only be used when the control sequence of operation is Cooling & Heating
|
||||
SimulatedThermostat.begin(MatterThermostat::THERMOSTAT_SEQ_OP_COOLING_HEATING, MatterThermostat::THERMOSTAT_AUTO_MODE_ENABLED);
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
|
||||
// Check Matter Accessory 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 Thermostat 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 the network. Ready for use.");
|
||||
|
||||
// after commissioning, set initial thermostat parameters
|
||||
// start the thermostat in AUTO mode
|
||||
SimulatedThermostat.setMode(MatterThermostat::THERMOSTAT_MODE_AUTO);
|
||||
// cooling setpoint must be lower than heating setpoint by at least 2.5C (deadband), in auto mode
|
||||
SimulatedThermostat.setCoolingHeatingSetpoints(20.0, 23.00); // the target cooler and heating setpoint
|
||||
// set the local temperature sensor in Celsius
|
||||
SimulatedThermostat.setLocalTemperature(12.50);
|
||||
|
||||
Serial.println();
|
||||
Serial.printf(
|
||||
"Initial Setpoints are %.01fC to %.01fC with a minimum 2.5C difference\r\n", SimulatedThermostat.getHeatingSetpoint(),
|
||||
SimulatedThermostat.getCoolingSetpoint()
|
||||
);
|
||||
Serial.printf("Auto mode is ON. Initial Temperature of %.01fC \r\n", SimulatedThermostat.getLocalTemperature());
|
||||
Serial.println("Local Temperature Sensor will be simulated every 10 seconds and changed by a simulated heater and cooler to move in between setpoints.");
|
||||
}
|
||||
}
|
||||
|
||||
// This will simulate the thermostat control system (heating and cooling)
|
||||
// User can set a local temperature using the Serial input (type a number and press Enter)
|
||||
// New temperature can be an positive or negative temperature in Celsius, between -50C and 50C
|
||||
// Initial local temperature is 10C as defined in getSimulatedTemperature() function
|
||||
void readSerialForNewTemperature() {
|
||||
static String newTemperatureStr;
|
||||
|
||||
while (Serial.available()) {
|
||||
char c = Serial.read();
|
||||
if (c == '\n' || c == '\r') {
|
||||
if (newTemperatureStr.length() > 0) {
|
||||
// convert the string to a float value
|
||||
float newTemperature = newTemperatureStr.toFloat();
|
||||
// check if the new temperature is valid
|
||||
if (newTemperature >= -50.0 && newTemperature <= 50.0) {
|
||||
// set the new temperature
|
||||
SimulatedThermostat.setLocalTemperature(newTemperature);
|
||||
Serial.printf("New Temperature is %.01fC\r\n", newTemperature);
|
||||
} else {
|
||||
Serial.println("Invalid Temperature value. Please type a number between -50 and 50");
|
||||
}
|
||||
newTemperatureStr = "";
|
||||
}
|
||||
} else {
|
||||
if (c == '+' || c == '-' || (c >= '0' && c <= '9') || c == '.') {
|
||||
newTemperatureStr += c;
|
||||
} else {
|
||||
Serial.println("Invalid character. Please type a number between -50 and 50");
|
||||
newTemperatureStr = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop will simulate the thermostat control system
|
||||
// User can set a local temperature using the Serial input (type a number and press Enter)
|
||||
// User can change the thermostat mode using the Matter APP (smartphone)
|
||||
// The loop will simulate a heating and cooling system and the associated local temperature change
|
||||
void loop() {
|
||||
static uint32_t timeCounter = 0;
|
||||
|
||||
// Simulate the heating and cooling systems
|
||||
static bool isHeating = false;
|
||||
static bool isCooling = false;
|
||||
|
||||
// check if a new temperature is typed in the Serial Monitor
|
||||
readSerialForNewTemperature();
|
||||
|
||||
// simulate thermostat with heating/cooling system and the associated local temperature change, every 10s
|
||||
if (!(timeCounter++ % 20)) { // delaying for 500ms x 20 = 10s
|
||||
float localTemperature = getSimulatedTemperature(isHeating, isCooling);
|
||||
// Print the current thermostat local temperature value
|
||||
Serial.printf("Current Local Temperature is %.01fC\r\n", localTemperature);
|
||||
SimulatedThermostat.setLocalTemperature(localTemperature); // publish the new temperature value
|
||||
|
||||
// Simulate the thermostat control system - User has 4 modes: OFF, HEAT, COOL, AUTO
|
||||
switch (SimulatedThermostat.getMode()) {
|
||||
case MatterThermostat::THERMOSTAT_MODE_OFF:
|
||||
// turn off the heating and cooling systems
|
||||
isHeating = false;
|
||||
isCooling = false;
|
||||
break;
|
||||
case MatterThermostat::THERMOSTAT_MODE_AUTO:
|
||||
// User APP has set the thermostat to AUTO mode -- keeping the tempeature between both setpoints
|
||||
// check if the heating system should be turned on or off
|
||||
if (localTemperature < SimulatedThermostat.getHeatingSetpoint() + SimulatedThermostat.getDeadBand()) {
|
||||
// turn on the heating system and turn off the cooling system
|
||||
isHeating = true;
|
||||
isCooling = false;
|
||||
}
|
||||
if (localTemperature > SimulatedThermostat.getCoolingSetpoint() - SimulatedThermostat.getDeadBand()) {
|
||||
// turn off the heating system and turn on the cooling system
|
||||
isHeating = false;
|
||||
isCooling = true;
|
||||
}
|
||||
break;
|
||||
case MatterThermostat::THERMOSTAT_MODE_HEAT:
|
||||
// Simulate the heating system - User has turned the heating system ON
|
||||
isHeating = true;
|
||||
isCooling = false; // keep the cooling system off as it is in heating mode
|
||||
// when the heating system is in HEATING mode, it will be turned off as soon as the local temperature is above the setpoint
|
||||
if (localTemperature > SimulatedThermostat.getHeatingSetpoint()) {
|
||||
// turn off the heating system
|
||||
isHeating = false;
|
||||
}
|
||||
break;
|
||||
case MatterThermostat::THERMOSTAT_MODE_COOL:
|
||||
// Simulate the cooling system - User has turned the cooling system ON
|
||||
if (SimulatedThermostat.getMode() == MatterThermostat::THERMOSTAT_MODE_COOL) {
|
||||
isCooling = true;
|
||||
isHeating = false; // keep the heating system off as it is in cooling mode
|
||||
// when the cooling system is in COOLING mode, it will be turned off as soon as the local temperature is bellow the setpoint
|
||||
if (localTemperature < SimulatedThermostat.getCoolingSetpoint()) {
|
||||
// turn off the cooling system
|
||||
isCooling = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: log_e("Invalid Thermostat Mode %d", SimulatedThermostat.getMode());
|
||||
}
|
||||
// Reporting Heating and Cooling status
|
||||
Serial.printf(
|
||||
"\tThermostat Mode: %s >>> Heater is %s -- Cooler is %s\r\n", MatterThermostat::getThermostatModeString(SimulatedThermostat.getMode()),
|
||||
isHeating ? "ON" : "OFF", isCooling ? "ON" : "OFF"
|
||||
);
|
||||
}
|
||||
// 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 Thermostat 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);
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
# Matter Thermostat Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible thermostat device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, thermostat control via smart home ecosystems, temperature setpoint management, and simulated heating/cooling systems with automatic temperature regulation.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a thermostat device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Multiple thermostat modes: OFF, HEAT, COOL, AUTO
|
||||
- Heating and cooling setpoint control
|
||||
- Automatic temperature regulation in AUTO mode
|
||||
- Simulated heating/cooling systems with temperature changes
|
||||
- Serial input for manual temperature setting
|
||||
- Button control for factory reset (decommission)
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- User button for factory reset (uses BOOT button by default)
|
||||
- Optional: Connect a real temperature sensor and replace the simulation function
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
3. **Real sensor integration** (optional):
|
||||
To use a real temperature sensor, replace the `getSimulatedTemperature()` function with your sensor reading code. The function should return a float value representing temperature in Celsius.
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterThermostat.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
|
||||
Initial Setpoints are 23.0C to 20.0C with a minimum 2.5C difference
|
||||
Auto mode is ON. Initial Temperature of 12.5C
|
||||
Local Temperature Sensor will be simulated every 10 seconds and changed by a simulated heater and cooler to move in between setpoints.
|
||||
Current Local Temperature is 12.5C
|
||||
Thermostat Mode: AUTO >>> Heater is ON -- Cooler is OFF
|
||||
Current Local Temperature is 13.0C
|
||||
Thermostat Mode: AUTO >>> Heater is ON -- Cooler is OFF
|
||||
...
|
||||
Current Local Temperature is 20.0C
|
||||
Thermostat Mode: AUTO >>> Heater is OFF -- Cooler is OFF
|
||||
Current Local Temperature is 23.0C
|
||||
Thermostat Mode: AUTO >>> Heater is OFF -- Cooler is ON
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides factory reset functionality:
|
||||
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Serial Input
|
||||
|
||||
You can manually set the temperature by typing a value in the Serial Monitor:
|
||||
|
||||
1. Open Serial Monitor at 115200 baud
|
||||
2. Type a temperature value between -50°C and 50°C
|
||||
3. Press Enter
|
||||
4. The thermostat will update the local temperature reading
|
||||
|
||||
Example:
|
||||
```
|
||||
15.5
|
||||
New Temperature is 15.5C
|
||||
```
|
||||
|
||||
### Thermostat Modes
|
||||
|
||||
The thermostat supports four operating modes:
|
||||
|
||||
- **OFF**: Heating and cooling systems are turned off
|
||||
- **HEAT**: Only heating system is active. Turns off when temperature exceeds heating setpoint
|
||||
- **COOL**: Only cooling system is active. Turns off when temperature falls below cooling setpoint
|
||||
- **AUTO**: Automatically switches between heating and cooling to maintain temperature between setpoints
|
||||
|
||||
### Setpoints
|
||||
|
||||
- **Heating Setpoint**: Target temperature for heating (default: 23.0°C)
|
||||
- **Cooling Setpoint**: Target temperature for cooling (default: 20.0°C)
|
||||
- **Deadband**: Minimum difference between heating and cooling setpoints (2.5°C required in AUTO mode)
|
||||
|
||||
### Temperature Simulation
|
||||
|
||||
The example includes a simulated heating/cooling system:
|
||||
|
||||
- **Heating**: Temperature increases by 0.5°C every 10 seconds when heating is active
|
||||
- **Cooling**: Temperature decreases by 0.5°C every 10 seconds when cooling is active
|
||||
- **No heating/cooling**: Temperature remains stable
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a thermostat in your Home app
|
||||
7. You can control the mode (OFF, HEAT, COOL, AUTO) and adjust heating/cooling setpoints
|
||||
8. Monitor the current temperature and set up automations based on temperature
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The thermostat will appear in your Alexa app
|
||||
6. You can control the mode and setpoints using voice commands or the app
|
||||
7. Create routines based on temperature changes
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can control the mode and setpoints using voice commands or the app
|
||||
7. Create automations based on temperature
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterThermostat example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button), configures Wi-Fi (if needed), sets up the Matter Thermostat endpoint with cooling/heating sequence of operation and AUTO mode enabled, sets initial setpoints (heating: 23.0°C, cooling: 20.0°C) and initial temperature (12.5°C), and waits for Matter commissioning.
|
||||
|
||||
2. **`loop()`**: Reads serial input for manual temperature setting, simulates heating/cooling systems and temperature changes every 10 seconds, controls heating/cooling based on thermostat mode and setpoints, handles button input for factory reset, and allows the Matter stack to process events.
|
||||
|
||||
3. **`getSimulatedTemperature()`**: Simulates temperature changes based on heating/cooling state. Temperature increases when heating is active, decreases when cooling is active. Replace this function with your actual sensor reading code.
|
||||
|
||||
4. **`readSerialForNewTemperature()`**: Reads temperature values from Serial Monitor input, validates the range (-50°C to 50°C), and updates the thermostat's local temperature.
|
||||
|
||||
5. **Thermostat Control Logic**:
|
||||
- **OFF mode**: Both heating and cooling are disabled
|
||||
- **AUTO mode**: Automatically switches between heating and cooling to maintain temperature between setpoints
|
||||
- **HEAT mode**: Activates heating until temperature exceeds heating setpoint
|
||||
- **COOL mode**: Activates cooling until temperature falls below cooling setpoint
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Temperature not updating**: Check that the simulation function is being called correctly. For real sensors, verify sensor wiring and library initialization
|
||||
- **Heating/cooling not responding**: Verify that the thermostat mode is set correctly and that setpoints are properly configured
|
||||
- **Setpoints not working**: Ensure cooling setpoint is at least 2.5°C lower than heating setpoint in AUTO mode
|
||||
- **Serial input not working**: Make sure Serial Monitor is set to 115200 baud and "No line ending" or "Newline" is selected
|
||||
- **Invalid temperature values**: Temperature must be between -50°C and 50°C. The Matter protocol stores values as int16_t internally (1/100th of a degree Celsius)
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Thermostat Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_thermostat.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,161 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* This example is an example code that will create a Matter Device which can be
|
||||
* commissioned and controlled from a Matter Environment APP.
|
||||
* 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.
|
||||
*
|
||||
* The example will create a Matter Water Freeze Detector Device.
|
||||
* The Water Freeze Detector state can be toggled by pressing the onboard button.
|
||||
* The Water Freeze Detector state will be indicated by the onboard LED.
|
||||
* The Water Freeze Detector state will be simulated to change every 20 seconds.
|
||||
*
|
||||
* The onboard button can be kept pressed for 5 seconds to decommission the Matter Node.
|
||||
* The example will also show the manual commissioning code and QR code to be used in the Matter environment.
|
||||
*
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Matter Water Freeze Detector Endpoint
|
||||
MatterWaterFreezeDetector WaterFreezeDetector;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// LED will be used to indicate the Water Freeze Detector state
|
||||
// set your board RGB LED pin here
|
||||
#ifdef RGB_BUILTIN
|
||||
const uint8_t ledPin = RGB_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 RGB LED pin"
|
||||
#endif
|
||||
|
||||
// set your board USER BUTTON pin here - decommissioning and Manual Water Freeze Detector toggle button
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// 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 = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||
// The button will also be used to manually toggle the Water Freeze Detector state
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
// Initialize the LED (light) GPIO and Matter End Point
|
||||
pinMode(ledPin, OUTPUT);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// set initial water freeze detector state as false (default)
|
||||
WaterFreezeDetector.begin();
|
||||
digitalWrite(ledPin, LOW); // LED OFF
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
|
||||
// Check Matter Accessory 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 Water Freeze Detector 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 the network. Ready for use.");
|
||||
}
|
||||
}
|
||||
|
||||
bool simulatedHWWaterFreezeDetector() {
|
||||
// Simulated Water Freeze Detector
|
||||
static bool freezeState = false;
|
||||
static uint32_t lastTime = 0;
|
||||
|
||||
// Simulate a Water Freeze Detector state change every 20 seconds
|
||||
if (millis() - lastTime > 20000) {
|
||||
freezeState = !freezeState;
|
||||
lastTime = millis();
|
||||
}
|
||||
return freezeState;
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
uint32_t time_diff = millis() - button_time_stamp;
|
||||
if (button_state && time_diff > debouceTime && digitalRead(buttonPin) == HIGH) {
|
||||
button_state = false; // released
|
||||
// button is released - toggle Freeze State (Not Detected/Detected)
|
||||
WaterFreezeDetector.setFreeze(!WaterFreezeDetector.getFreeze()); // same as WaterFreezeDetector = !WaterFreezeDetector;
|
||||
Serial.printf("User button released. Setting the Water Freeze Detector to %s.\r\n", WaterFreezeDetector ? "Detected" : "Not Detected");
|
||||
// LED will indicate the Water Freeze Detector state
|
||||
if (WaterFreezeDetector) {
|
||||
digitalWrite(ledPin, HIGH); // LED ON
|
||||
} else {
|
||||
digitalWrite(ledPin, LOW); // LED OFF
|
||||
}
|
||||
}
|
||||
|
||||
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||
if (button_state && time_diff > decommissioningTimeout) {
|
||||
Serial.println("Decommissioning Water Freeze Detector Matter Accessory. It shall be commissioned again.");
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
|
||||
}
|
||||
|
||||
// Simulated Water Freeze Detector
|
||||
WaterFreezeDetector.setFreeze(simulatedHWWaterFreezeDetector());
|
||||
|
||||
delay(50);
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
# Matter Water Freeze Detector Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible water freeze detector device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device control via smart home ecosystems, manual control using a physical button, and automatic simulation of water freeze detection state changes.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | LED | Status |
|
||||
| --- | ---- | ------ | ----------------- | --- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a water freeze detector device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Water freeze detection state indication using LED (ON = Detected, OFF = Not Detected)
|
||||
- Automatic simulation of water freeze detection state changes every 20 seconds
|
||||
- Button control for toggling water freeze detection state and factory reset
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- LED connected to GPIO pins (or using built-in LED) to indicate water freeze detection state
|
||||
- User button for manual control (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **LED**: Uses `RGB_BUILTIN` if defined, otherwise pin 2
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **LED pin configuration** (if not using built-in LED):
|
||||
```cpp
|
||||
const uint8_t ledPin = 2; // Set your LED pin here
|
||||
```
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for the Water Freeze Detector state toggle and factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterWaterFreezeDetector.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
User button released. Setting the Water Freeze Detector to Detected.
|
||||
User button released. Setting the Water Freeze Detector to Not Detected.
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Short press of the button**: Toggle water freeze detector state (Not Detected/Detected)
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Automatic Simulation
|
||||
|
||||
The water freeze detector state automatically toggles every 20 seconds to simulate a real water freeze detector. The LED will reflect the current state:
|
||||
- **LED ON**: Water freeze is Detected
|
||||
- **LED OFF**: Water freeze is Not Detected
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
Check for Matter Water Freeze Detector endpoint support within the Matter Controller developer webpage.
|
||||
This endpoint is part of the latest Matter supported device list and it may not be fully supported by your Matter environment.
|
||||
You can also try the Home Assistant Matter feature in order to test it.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a water freeze detector in your Home app
|
||||
7. You can monitor the water freeze detection state (Detected/Not Detected) and receive notifications when the state changes
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The water freeze detector will appear in your Alexa app
|
||||
6. You can monitor the water freeze detection state and set up routines based on state changes
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The water freeze detector will appear in your Google Home app
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterWaterFreezeDetector example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, LED), configures Wi-Fi (if needed), sets up the Matter Water Freeze Detector endpoint with initial state (Not Detected), and waits for Matter commissioning.
|
||||
2. **`loop()`**: Handles button input for toggling water freeze detection state and factory reset, and automatically simulates water freeze detection state changes every 20 seconds.
|
||||
3. **`simulatedHWWaterFreezeDetector()`**: Simulates a hardware water freeze detector by toggling the water freeze detection state every 20 seconds.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **LED not responding**: Verify pin configurations and connections
|
||||
- **Water freeze detector state not updating**: Check Serial Monitor output to verify state changes are being processed
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Water Freeze Detector Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_water_freeze_detector.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,161 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* This example is an example code that will create a Matter Device which can be
|
||||
* commissioned and controlled from a Matter Environment APP.
|
||||
* 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.
|
||||
*
|
||||
* The example will create a Matter Water Leak Detector Device.
|
||||
* The Water Leak Detector state can be toggled by pressing the onboard button.
|
||||
* The Water Leak Detector state will be indicated by the onboard LED.
|
||||
* The Water Leak Detector state will be simulated to change every 20 seconds.
|
||||
*
|
||||
* The onboard button can be kept pressed for 5 seconds to decommission the Matter Node.
|
||||
* The example will also show the manual commissioning code and QR code to be used in the Matter environment.
|
||||
*
|
||||
*/
|
||||
|
||||
// Matter Manager
|
||||
#include <Matter.h>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Matter Water Leak Detector Endpoint
|
||||
MatterWaterLeakDetector WaterLeakDetector;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// LED will be used to indicate the Water Leak Detector state
|
||||
// set your board RGB LED pin here
|
||||
#ifdef RGB_BUILTIN
|
||||
const uint8_t ledPin = RGB_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 RGB LED pin"
|
||||
#endif
|
||||
|
||||
// set your board USER BUTTON pin here - decommissioning and Manual Water Leak Detector toggle button
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// Button control
|
||||
uint32_t button_time_stamp = 0; // debouncing control
|
||||
bool button_state = false; // false = released | true = pressed
|
||||
const uint32_t debounceTime = 250; // button debouncing time (ms)
|
||||
const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
|
||||
// The button will also be used to manually toggle the Water Leak Detector state
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
// Initialize the LED (light) GPIO and Matter End Point
|
||||
pinMode(ledPin, OUTPUT);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// Manually connect to WiFi
|
||||
WiFi.begin(ssid, password);
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
// set initial water leak detector state as false (default)
|
||||
WaterLeakDetector.begin();
|
||||
digitalWrite(ledPin, LOW); // LED OFF
|
||||
|
||||
// Matter beginning - Last step, after all EndPoints are initialized
|
||||
Matter.begin();
|
||||
|
||||
// Check Matter Accessory 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 Water Leak Detector 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 the network. Ready for use.");
|
||||
}
|
||||
}
|
||||
|
||||
bool simulatedHWWaterLeakDetector() {
|
||||
// Simulated Water Leak Detector
|
||||
static bool leakState = false;
|
||||
static uint32_t lastTime = 0;
|
||||
|
||||
// Simulate a Water Leak Detector state change every 20 seconds
|
||||
if (millis() - lastTime > 20000) {
|
||||
leakState = !leakState;
|
||||
lastTime = millis();
|
||||
}
|
||||
return leakState;
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
uint32_t time_diff = millis() - button_time_stamp;
|
||||
if (button_state && time_diff > debounceTime && digitalRead(buttonPin) == HIGH) {
|
||||
button_state = false; // released
|
||||
// button is released - toggle Leak State (Not Detected/Detected)
|
||||
WaterLeakDetector.setLeak(!WaterLeakDetector.getLeak()); // same as WaterLeakDetector = !WaterLeakDetector;
|
||||
Serial.printf("User button released. Setting the Water Leak Detector to %s.\r\n", WaterLeakDetector ? "Detected" : "Not Detected");
|
||||
// LED will indicate the Water Leak Detector state
|
||||
if (WaterLeakDetector) {
|
||||
digitalWrite(ledPin, HIGH); // LED ON
|
||||
} else {
|
||||
digitalWrite(ledPin, LOW); // LED OFF
|
||||
}
|
||||
}
|
||||
|
||||
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||
if (button_state && time_diff > decommissioningTimeout) {
|
||||
Serial.println("Decommissioning Water Leak Detector Matter Accessory. It shall be commissioned again.");
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissioning again, reboot takes a second or so
|
||||
}
|
||||
|
||||
// Simulated Water Leak Detector
|
||||
WaterLeakDetector.setLeak(simulatedHWWaterLeakDetector());
|
||||
|
||||
delay(50);
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
# Matter Water Leak Detector Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible water leak detector device using an ESP32 SoC microcontroller.\
|
||||
The application showcases Matter commissioning, device control via smart home ecosystems, manual control using a physical button, and automatic simulation of water leak detection state changes.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | LED | Status |
|
||||
| --- | ---- | ------ | ----------------- | --- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a water leak detector device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Water leak detection state indication using LED (ON = Detected, OFF = Not Detected)
|
||||
- Automatic simulation of water leak detection state changes every 20 seconds
|
||||
- Button control for toggling water leak detection state and factory reset
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- LED connected to GPIO pins (or using built-in LED) to indicate water leak detection state
|
||||
- User button for manual control (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **LED**: Uses `RGB_BUILTIN` if defined, otherwise pin 2
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **LED pin configuration** (if not using built-in LED):
|
||||
```cpp
|
||||
const uint8_t ledPin = 2; // Set your LED pin here
|
||||
```
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for the Water Leak Detector state toggle and factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterWaterLeakDetector.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
Wi-Fi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
User button released. Setting the Water Leak Detector to Detected.
|
||||
User button released. Setting the Water Leak Detector to Not Detected.
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Short press of the button**: Toggle water leak detector state (Not Detected/Detected)
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### Automatic Simulation
|
||||
|
||||
The water leak detector state automatically toggles every 20 seconds to simulate a real water leak detector. The LED will reflect the current state:
|
||||
- **LED ON**: Water leak is Detected
|
||||
- **LED OFF**: Water leak is Not Detected
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
Check for Matter Water Leak Detector endpoint support within the Matter Controller developer webpage.
|
||||
This endpoint is part of the latest Matter supported device list and it may not be fully supported by your Matter environment.
|
||||
You can also try the Home Assistant Matter feature in order to test it.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a water leak detector in your Home app
|
||||
7. You can monitor the water leak detection state (Detected/Not Detected) and receive notifications when the state changes
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The water leak detector will appear in your Alexa app
|
||||
6. You can monitor the water leak detection state and set up routines based on state changes
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The water leak detector will appear in your Google Home app
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterWaterLeakDetector example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, LED), configures Wi-Fi (if needed), sets up the Matter Water Leak Detector endpoint with initial state (Not Detected), and waits for Matter commissioning.
|
||||
2. **`loop()`**: Handles button input for toggling water leak detection state and factory reset, and automatically simulates water leak detection state changes every 20 seconds.
|
||||
3. **`simulatedHWWaterLeakDetector()`**: Simulates a hardware water leak detector by toggling the water leak detection state every 20 seconds.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **LED not responding**: Verify pin configurations and connections
|
||||
- **Water leak detector state not updating**: Check Serial Monitor output to verify state changes are being processed
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Water Leak Detector Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_water_leak_detector.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
@@ -0,0 +1,355 @@
|
||||
// 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>
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// if the device can be commissioned using BLE, WiFi is not used - save flash space
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
#include <Preferences.h>
|
||||
|
||||
// List of Matter Endpoints for this Node
|
||||
// Window Covering Endpoint
|
||||
MatterWindowCovering WindowBlinds;
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// it will keep last Lift & Tilt state stored, using Preferences
|
||||
Preferences matterPref;
|
||||
const char *liftPercentPrefKey = "LiftPercent";
|
||||
const char *tiltPercentPrefKey = "TiltPercent";
|
||||
|
||||
// set your board USER BUTTON pin here
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button.
|
||||
|
||||
// Button control
|
||||
uint32_t button_time_stamp = 0; // debouncing control
|
||||
bool button_state = false; // false = released | true = pressed
|
||||
const uint32_t debounceTime = 250; // button debouncing time (ms)
|
||||
const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission
|
||||
|
||||
// Window covering limits
|
||||
// Lift limits in centimeters (physical position)
|
||||
const uint16_t MAX_LIFT = 200; // Maximum lift position (fully open)
|
||||
const uint16_t MIN_LIFT = 0; // Minimum lift position (fully closed)
|
||||
|
||||
// Tilt limits (absolute values for conversion, not physical units)
|
||||
// Tilt is a rotation, not a linear measurement
|
||||
const uint16_t MAX_TILT = 90; // Maximum tilt absolute value
|
||||
const uint16_t MIN_TILT = 0; // Minimum tilt absolute value
|
||||
|
||||
// Current window covering state
|
||||
// These will be initialized in setup() based on installed limits and saved percentages
|
||||
uint16_t currentLift = 0; // Lift position in cm
|
||||
uint8_t currentLiftPercent = 100;
|
||||
uint8_t currentTiltPercent = 0; // Tilt rotation percentage (0-100%)
|
||||
|
||||
// Visualize window covering position using RGB LED
|
||||
// Lift percentage controls brightness (0% = off, 100% = full brightness)
|
||||
#ifdef RGB_BUILTIN
|
||||
const uint8_t ledPin = RGB_BUILTIN;
|
||||
#else
|
||||
const uint8_t ledPin = 2; // Set your pin here if your board has not defined RGB_BUILTIN
|
||||
#warning "Do not forget to set the RGB LED pin"
|
||||
#endif
|
||||
|
||||
void visualizeWindowBlinds(uint8_t liftPercent, uint8_t tiltPercent) {
|
||||
#ifdef RGB_BUILTIN
|
||||
// Use RGB LED to visualize lift position (brightness) and tilt (color shift)
|
||||
float brightness = (float)liftPercent / 100.0; // 0.0 to 1.0
|
||||
// Tilt affects color: 0% = red, 100% = blue
|
||||
uint8_t red = (uint8_t)(map(tiltPercent, 0, 100, 255, 0) * brightness);
|
||||
uint8_t blue = (uint8_t)(map(tiltPercent, 0, 100, 0, 255) * brightness);
|
||||
uint8_t green = 0;
|
||||
rgbLedWrite(ledPin, red, green, blue);
|
||||
#else
|
||||
// For non-RGB boards, just use brightness
|
||||
uint8_t brightnessValue = map(liftPercent, 0, 100, 0, 255);
|
||||
analogWrite(ledPin, brightnessValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Window Covering Callbacks
|
||||
bool fullOpen() {
|
||||
// This is where you would trigger your motor to go to full open state
|
||||
// For simulation, we update instantly
|
||||
uint16_t openLimit = WindowBlinds.getInstalledOpenLimitLift();
|
||||
currentLift = openLimit;
|
||||
currentLiftPercent = 100;
|
||||
Serial.printf("Opening window covering to full open (position: %d cm)\r\n", currentLift);
|
||||
|
||||
// Update CurrentPosition to reflect actual position (setLiftPercentage now only updates CurrentPosition)
|
||||
WindowBlinds.setLiftPercentage(currentLiftPercent);
|
||||
|
||||
// Set operational status to STALL when movement is complete
|
||||
WindowBlinds.setOperationalState(MatterWindowCovering::LIFT, MatterWindowCovering::STALL);
|
||||
|
||||
// Store state
|
||||
matterPref.putUChar(liftPercentPrefKey, currentLiftPercent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fullClose() {
|
||||
// This is where you would trigger your motor to go to full close state
|
||||
// For simulation, we update instantly
|
||||
uint16_t closedLimit = WindowBlinds.getInstalledClosedLimitLift();
|
||||
currentLift = closedLimit;
|
||||
currentLiftPercent = 0;
|
||||
Serial.printf("Closing window covering to full close (position: %d cm)\r\n", currentLift);
|
||||
|
||||
// Update CurrentPosition to reflect actual position (setLiftPercentage now only updates CurrentPosition)
|
||||
WindowBlinds.setLiftPercentage(currentLiftPercent);
|
||||
|
||||
// Set operational status to STALL when movement is complete
|
||||
WindowBlinds.setOperationalState(MatterWindowCovering::LIFT, MatterWindowCovering::STALL);
|
||||
|
||||
// Store state
|
||||
matterPref.putUChar(liftPercentPrefKey, currentLiftPercent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool goToLiftPercentage(uint8_t liftPercent) {
|
||||
// update Lift operational state
|
||||
if (liftPercent > currentLiftPercent) {
|
||||
// Set operational status to OPEN
|
||||
WindowBlinds.setOperationalState(MatterWindowCovering::LIFT, MatterWindowCovering::MOVING_UP_OR_OPEN);
|
||||
}
|
||||
if (liftPercent < currentLiftPercent) {
|
||||
// Set operational status to CLOSE
|
||||
WindowBlinds.setOperationalState(MatterWindowCovering::LIFT, MatterWindowCovering::MOVING_DOWN_OR_CLOSE);
|
||||
}
|
||||
|
||||
// This is where you would trigger your motor to go towards liftPercent
|
||||
// For simulation, we update instantly
|
||||
// Calculate absolute position based on installed limits
|
||||
uint16_t openLimit = WindowBlinds.getInstalledOpenLimitLift();
|
||||
uint16_t closedLimit = WindowBlinds.getInstalledClosedLimitLift();
|
||||
|
||||
// Linear interpolation: 0% = openLimit, 100% = closedLimit
|
||||
if (openLimit < closedLimit) {
|
||||
currentLift = openLimit + ((closedLimit - openLimit) * liftPercent) / 100;
|
||||
} else {
|
||||
currentLift = openLimit - ((openLimit - closedLimit) * liftPercent) / 100;
|
||||
}
|
||||
currentLiftPercent = liftPercent;
|
||||
Serial.printf("Moving lift to %d%% (position: %d cm)\r\n", currentLiftPercent, currentLift);
|
||||
|
||||
// Update CurrentPosition to reflect actual position (setLiftPercentage now only updates CurrentPosition)
|
||||
WindowBlinds.setLiftPercentage(currentLiftPercent);
|
||||
|
||||
// Set operational status to STALL when movement is complete
|
||||
WindowBlinds.setOperationalState(MatterWindowCovering::LIFT, MatterWindowCovering::STALL);
|
||||
|
||||
// Store state
|
||||
matterPref.putUChar(liftPercentPrefKey, currentLiftPercent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool goToTiltPercentage(uint8_t tiltPercent) {
|
||||
// update Tilt operational state
|
||||
if (tiltPercent < currentTiltPercent) {
|
||||
// Set operational status to OPEN
|
||||
WindowBlinds.setOperationalState(MatterWindowCovering::TILT, MatterWindowCovering::MOVING_UP_OR_OPEN);
|
||||
}
|
||||
if (tiltPercent > currentTiltPercent) {
|
||||
// Set operational status to CLOSE
|
||||
WindowBlinds.setOperationalState(MatterWindowCovering::TILT, MatterWindowCovering::MOVING_DOWN_OR_CLOSE);
|
||||
}
|
||||
|
||||
// This is where you would trigger your motor to rotate the shade to tiltPercent
|
||||
// For simulation, we update instantly
|
||||
currentTiltPercent = tiltPercent;
|
||||
Serial.printf("Rotating tilt to %d%%\r\n", currentTiltPercent);
|
||||
|
||||
// Update CurrentPosition to reflect actual position
|
||||
WindowBlinds.setTiltPercentage(currentTiltPercent);
|
||||
|
||||
// Set operational status to STALL when movement is complete
|
||||
WindowBlinds.setOperationalState(MatterWindowCovering::TILT, MatterWindowCovering::STALL);
|
||||
|
||||
// Store state
|
||||
matterPref.putUChar(tiltPercentPrefKey, currentTiltPercent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool stopMotor() {
|
||||
// Motor can be stopped while moving cover toward current target
|
||||
Serial.println("Stopping window covering motor");
|
||||
|
||||
// Update CurrentPosition to reflect actual position when stopped
|
||||
// (setLiftPercentage and setTiltPercentage now only update CurrentPosition)
|
||||
WindowBlinds.setLiftPercentage(currentLiftPercent);
|
||||
WindowBlinds.setTiltPercentage(currentTiltPercent);
|
||||
|
||||
// Set operational status to STALL for both lift and tilt
|
||||
WindowBlinds.setOperationalState(MatterWindowCovering::LIFT, MatterWindowCovering::STALL);
|
||||
WindowBlinds.setOperationalState(MatterWindowCovering::TILT, MatterWindowCovering::STALL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize the USER BUTTON (Boot button) GPIO
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
// Initialize the RGB LED GPIO
|
||||
pinMode(ledPin, OUTPUT);
|
||||
digitalWrite(ledPin, LOW);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
|
||||
#if !CONFIG_ENABLE_CHIPOBLE
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// Initialize Matter EndPoint
|
||||
matterPref.begin("MatterPrefs", false);
|
||||
// default lift percentage is 100% (fully open) if not stored before
|
||||
uint8_t lastLiftPercent = matterPref.getUChar(liftPercentPrefKey, 100);
|
||||
// default tilt percentage is 0% if not stored before
|
||||
uint8_t lastTiltPercent = matterPref.getUChar(tiltPercentPrefKey, 0);
|
||||
|
||||
// Initialize window covering with BLIND_LIFT_AND_TILT type
|
||||
WindowBlinds.begin(lastLiftPercent, lastTiltPercent, MatterWindowCovering::BLIND_LIFT_AND_TILT);
|
||||
|
||||
// Configure installed limits for lift and tilt
|
||||
WindowBlinds.setInstalledOpenLimitLift(MIN_LIFT);
|
||||
WindowBlinds.setInstalledClosedLimitLift(MAX_LIFT);
|
||||
WindowBlinds.setInstalledOpenLimitTilt(MIN_TILT);
|
||||
WindowBlinds.setInstalledClosedLimitTilt(MAX_TILT);
|
||||
|
||||
// Initialize current positions based on percentages and installed limits
|
||||
uint16_t openLimitLift = WindowBlinds.getInstalledOpenLimitLift();
|
||||
uint16_t closedLimitLift = WindowBlinds.getInstalledClosedLimitLift();
|
||||
currentLiftPercent = lastLiftPercent;
|
||||
if (openLimitLift < closedLimitLift) {
|
||||
currentLift = openLimitLift + ((closedLimitLift - openLimitLift) * lastLiftPercent) / 100;
|
||||
} else {
|
||||
currentLift = openLimitLift - ((openLimitLift - closedLimitLift) * lastLiftPercent) / 100;
|
||||
}
|
||||
|
||||
currentTiltPercent = lastTiltPercent;
|
||||
|
||||
Serial.printf(
|
||||
"Window Covering limits configured: Lift [%d-%d cm], Tilt [%d-%d]\r\n", WindowBlinds.getInstalledOpenLimitLift(),
|
||||
WindowBlinds.getInstalledClosedLimitLift(), WindowBlinds.getInstalledOpenLimitTilt(), WindowBlinds.getInstalledClosedLimitTilt()
|
||||
);
|
||||
Serial.printf("Initial positions: Lift=%d cm (%d%%), Tilt=%d%%\r\n", currentLift, currentLiftPercent, currentTiltPercent);
|
||||
|
||||
// Set callback functions
|
||||
WindowBlinds.onOpen(fullOpen);
|
||||
WindowBlinds.onClose(fullClose);
|
||||
WindowBlinds.onGoToLiftPercentage(goToLiftPercentage);
|
||||
WindowBlinds.onGoToTiltPercentage(goToTiltPercentage);
|
||||
WindowBlinds.onStop(stopMotor);
|
||||
|
||||
// Generic callback for Lift or Tilt change
|
||||
WindowBlinds.onChange([](uint8_t liftPercent, uint8_t tiltPercent) {
|
||||
Serial.printf("Window Covering changed: Lift=%d%%, Tilt=%d%%\r\n", liftPercent, tiltPercent);
|
||||
visualizeWindowBlinds(liftPercent, tiltPercent);
|
||||
return true;
|
||||
});
|
||||
|
||||
// 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 the network. Ready for use.");
|
||||
Serial.printf("Initial state: Lift=%d%%, Tilt=%d%%\r\n", WindowBlinds.getLiftPercentage(), WindowBlinds.getTiltPercentage());
|
||||
// Update visualization based on initial state
|
||||
visualizeWindowBlinds(WindowBlinds.getLiftPercentage(), WindowBlinds.getTiltPercentage());
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Check Matter Window Covering 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 Window Covering 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: Lift=%d%%, Tilt=%d%%\r\n", WindowBlinds.getLiftPercentage(), WindowBlinds.getTiltPercentage());
|
||||
// Update visualization based on initial state
|
||||
visualizeWindowBlinds(WindowBlinds.getLiftPercentage(), WindowBlinds.getTiltPercentage());
|
||||
Serial.println("Matter Node is commissioned and connected to the network. Ready for use.");
|
||||
}
|
||||
|
||||
// A button is also used to control the window covering
|
||||
// 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 to manually change lift percentage or to decommission
|
||||
uint32_t time_diff = millis() - button_time_stamp;
|
||||
if (digitalRead(buttonPin) == HIGH && button_state && time_diff > debounceTime) {
|
||||
// Button is released - cycle lift percentage by 20%
|
||||
button_state = false; // released
|
||||
uint8_t targetLiftPercent = currentLiftPercent;
|
||||
// go to the closest next 20% or move 20% more
|
||||
if ((targetLiftPercent % 20) != 0) {
|
||||
targetLiftPercent = ((targetLiftPercent / 20) + 1) * 20;
|
||||
} else {
|
||||
targetLiftPercent += 20;
|
||||
}
|
||||
if (targetLiftPercent > 100) {
|
||||
targetLiftPercent = 0;
|
||||
}
|
||||
Serial.printf("User button released. Setting lift to %d%%\r\n", targetLiftPercent);
|
||||
WindowBlinds.setTargetLiftPercent100ths(targetLiftPercent * 100);
|
||||
}
|
||||
|
||||
// Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
|
||||
if (button_state && time_diff > decommissioningTimeout) {
|
||||
Serial.println("Decommissioning the Window Covering Matter Accessory. It shall be commissioned again.");
|
||||
WindowBlinds.setLiftPercentage(0); // close the covering
|
||||
Matter.decommission();
|
||||
button_time_stamp = millis(); // avoid running decommissioning again, reboot takes a second or so
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
# Matter Window Covering Example
|
||||
|
||||
This example demonstrates how to create a Matter-compatible window covering device using an ESP32 SoC microcontroller. The application showcases Matter commissioning, device control via smart home ecosystems, and manual control using a physical button.
|
||||
|
||||
## Supported Targets
|
||||
|
||||
| SoC | Wi-Fi | Thread | BLE Commissioning | Status |
|
||||
| --- | ---- | ------ | ----------------- | ------ |
|
||||
| ESP32 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported |
|
||||
| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported |
|
||||
| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) |
|
||||
|
||||
### Note on Commissioning:
|
||||
|
||||
- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
|
||||
- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
|
||||
- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.
|
||||
|
||||
## Features
|
||||
|
||||
- Matter protocol implementation for a window covering device
|
||||
- Support for both Wi-Fi and Thread(*) connectivity
|
||||
- Lift position and percentage control (0-100%) - Lift represents the physical position (centimeters)
|
||||
- Tilt rotation and percentage control (0-100%) - Tilt represents rotation of the shade, not a linear measurement
|
||||
- Multiple window covering types support
|
||||
- State persistence using `Preferences` library
|
||||
- Button control for manual lift adjustment and factory reset
|
||||
- RGB LED visualization of lift (brightness) and tilt (color) positions
|
||||
- Installed limit configuration for lift (cm) and tilt (absolute values)
|
||||
- Matter commissioning via QR code or manual pairing code
|
||||
- Integration with Apple HomeKit, Amazon Alexa, and Google Home
|
||||
(*) It is necessary to compile the project using Arduino as IDF Component.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- ESP32 compatible development board (see supported targets table)
|
||||
- RGB LED for visualization (uses built-in RGB LED if available)
|
||||
- User button for manual control (uses BOOT button by default)
|
||||
|
||||
## Pin Configuration
|
||||
|
||||
- **RGB LED**: Uses `RGB_BUILTIN` if defined (for visualization), otherwise pin 2. The LED brightness represents lift position (0% = off, 100% = full brightness), and color represents tilt rotation (red = 0%, blue = 100%).
|
||||
- **Button**: Uses `BOOT_PIN` by default
|
||||
|
||||
## Software Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install the Arduino IDE (2.0 or newer recommended)
|
||||
2. Install ESP32 Arduino Core with Matter support
|
||||
3. ESP32 Arduino libraries:
|
||||
- `Matter`
|
||||
- `Preferences`
|
||||
- `Wi-Fi` (only for ESP32 and ESP32-S2)
|
||||
|
||||
### Configuration
|
||||
|
||||
Before uploading the sketch, configure the following:
|
||||
|
||||
1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):
|
||||
```cpp
|
||||
const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID
|
||||
const char *password = "your-password"; // Change to your Wi-Fi password
|
||||
```
|
||||
|
||||
2. **RGB LED pin configuration** (if not using built-in RGB LED):
|
||||
```cpp
|
||||
const uint8_t ledPin = 2; // Set your RGB LED pin here
|
||||
```
|
||||
|
||||
3. **Button pin configuration** (optional):
|
||||
By default, the `BOOT` button (GPIO 0) is used for manual lift control and factory reset. You can change this to a different pin if needed.
|
||||
```cpp
|
||||
const uint8_t buttonPin = BOOT_PIN; // Set your button pin here
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
|
||||
1. Open the `MatterWindowCovering.ino` sketch in the Arduino IDE.
|
||||
2. Select your ESP32 board from the **Tools > Board** menu.
|
||||
<!-- vale off -->
|
||||
3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu.
|
||||
<!-- vale on -->
|
||||
4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu.
|
||||
5. Connect your ESP32 board to your computer via USB.
|
||||
6. Click the **Upload** button to compile and flash the sketch.
|
||||
|
||||
## Expected Output
|
||||
|
||||
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following:
|
||||
|
||||
```
|
||||
Connecting to your-wifi-ssid
|
||||
.......
|
||||
WiFi connected
|
||||
IP address: 192.168.1.100
|
||||
|
||||
Matter Node is not commissioned yet.
|
||||
Initiate the device discovery in your Matter environment.
|
||||
Commission it to your Matter hub with the manual pairing code or QR code
|
||||
Manual pairing code: 34970112332
|
||||
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
|
||||
Matter Node not commissioned yet. Waiting for commissioning.
|
||||
...
|
||||
Initial state: Lift=100%, Tilt=0%
|
||||
Matter Node is commissioned and connected to the network. Ready for use.
|
||||
Window Covering changed: Lift=100%, Tilt=0%
|
||||
Moving lift to 50% (position: 100 cm)
|
||||
Window Covering changed: Lift=50%, Tilt=0%
|
||||
```
|
||||
|
||||
## Using the Device
|
||||
|
||||
### Manual Control
|
||||
|
||||
The user button (BOOT button by default) provides manual control:
|
||||
|
||||
- **Short press of the button**: Cycle lift percentage by 20% increments. If the current position is not a multiple of 20%, it will round up to the next multiple of 20%. Otherwise, it will add 20% (0% → 20% → 40% → ... → 100% → 0%)
|
||||
- **Long press (>5 seconds)**: Factory reset the device (decommission)
|
||||
|
||||
### State Persistence
|
||||
|
||||
The device saves the last known lift and tilt percentages using the `Preferences` library. After a power cycle or restart:
|
||||
|
||||
- The device will restore to the last saved lift and tilt percentages
|
||||
- Default state is 100% lift (fully open) and 0% tilt if no previous state was saved
|
||||
- The Matter controller will be notified of the restored state
|
||||
- The RGB LED will reflect the restored state
|
||||
|
||||
### RGB LED Visualization
|
||||
|
||||
The RGB LED provides visual feedback:
|
||||
|
||||
- **Brightness**: Represents lift position (0% = off, 100% = full brightness)
|
||||
- **Color**: Represents tilt position (red = 0% tilt, blue = 100% tilt)
|
||||
- For boards without RGB LED, only brightness is used
|
||||
|
||||
### Window Covering Integration
|
||||
|
||||
For production use with a motorized window covering:
|
||||
|
||||
1. **Motor Control**:
|
||||
- Connect your motor driver to your ESP32
|
||||
- Update the callback functions (`fullOpen()`, `fullClose()`, `goToLiftPercentage()`, `goToTiltPercentage()`, `stopMotor()`) to control your actual motor
|
||||
- The example currently simulates movement instantly - replace with actual motor control code
|
||||
|
||||
2. **Position Feedback**:
|
||||
- Use encoders or limit switches to provide position feedback
|
||||
- For lift: Update `currentLift` (cm) based on actual motor position
|
||||
- For tilt: Update `currentTiltPercent` (rotation percentage) based on actual motor rotation
|
||||
- **Important**: Call `setLiftPercentage()` and `setTiltPercentage()` in your `onGoToLiftPercentage()` or `onGoToTiltPercentage()` callbacks to update `CurrentPosition` attributes when the physical device actually moves. This will trigger the `onChange()` callback if registered.
|
||||
- Call `setOperationalState(LIFT, STALL)` or `setOperationalState(TILT, STALL)` when movement is complete to indicate the device has reached the target position
|
||||
- Configure installed limits using `setInstalledOpenLimitLift()`, `setInstalledClosedLimitLift()`, `setInstalledOpenLimitTilt()`, and `setInstalledClosedLimitTilt()` to define the physical range of your window covering
|
||||
|
||||
**Callback Flow:**
|
||||
- Matter command → `TargetPosition` changes → `onGoToLiftPercentage()`/`onGoToTiltPercentage()` called
|
||||
- Your callback moves the motor → When movement completes, call `setLiftPercentage()`/`setTiltPercentage()`
|
||||
- `setLiftPercentage()`/`setTiltPercentage()` update `CurrentPosition` → `onChange()` called (if registered)
|
||||
|
||||
3. **Window Covering Type**:
|
||||
- Pass the covering type to `begin()` to configure the appropriate type (e.g., `BLIND_LIFT_AND_TILT`, `ROLLERSHADE`, etc.)
|
||||
- Different types support different features (lift only, tilt only, or both)
|
||||
- The covering type must be specified during initialization to ensure the correct features are enabled
|
||||
|
||||
### Smart Home Integration
|
||||
|
||||
Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.
|
||||
|
||||
#### Apple Home
|
||||
|
||||
1. Open the Home app on your iOS device
|
||||
2. Tap the "+" button > Add Accessory
|
||||
3. Scan the QR code displayed in the Serial Monitor, or
|
||||
4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. The device will appear as a window covering/blind in your Home app
|
||||
7. You can control both lift and tilt positions using sliders
|
||||
|
||||
#### Amazon Alexa
|
||||
|
||||
1. Open the Alexa app
|
||||
2. Tap More > Add Device > Matter
|
||||
3. Select "Scan QR code" or "Enter code manually"
|
||||
4. Complete the setup process
|
||||
5. The window covering will appear in your Alexa app
|
||||
6. You can control positions using voice commands like "Alexa, set blinds to 50 percent"
|
||||
|
||||
#### Google Home
|
||||
|
||||
1. Open the Google Home app
|
||||
2. Tap "+" > Set up device > New device
|
||||
3. Choose "Matter device"
|
||||
4. Scan the QR code or enter the manual pairing code
|
||||
5. Follow the prompts to complete setup
|
||||
6. You can control positions using voice commands or sliders in the app
|
||||
|
||||
## Code Structure
|
||||
|
||||
The MatterWindowCovering example consists of the following main components:
|
||||
|
||||
1. **`setup()`**: Initializes hardware (button, RGB LED), configures Wi-Fi (if needed), initializes `Preferences` library, sets up the Matter window covering endpoint with the last saved state, registers callback functions, and starts the Matter stack.
|
||||
|
||||
2. **`loop()`**: Checks the Matter commissioning state, handles button input for manual lift control and factory reset, and allows the Matter stack to process events.
|
||||
|
||||
3. **Callbacks**:
|
||||
|
||||
**Target Position Callbacks** (called when `TargetPosition` attributes change):
|
||||
- `fullOpen()`: Registered with `onOpen()` - called when `UpOrOpen` command is received. Moves window covering to fully open (100% lift), calls `setLiftPercentage()` to update `CurrentPosition`, and sets operational state to `STALL`
|
||||
- `fullClose()`: Registered with `onClose()` - called when `DownOrClose` command is received. Moves window covering to fully closed (0% lift), calls `setLiftPercentage()` to update `CurrentPosition`, and sets operational state to `STALL`
|
||||
- `goToLiftPercentage()`: Registered with `onGoToLiftPercentage()` - called when `TargetPositionLiftPercent100ths` changes (from commands, `setTargetLiftPercent100ths()`, or direct attribute writes). Calculates absolute position (cm) based on installed limits, calls `setLiftPercentage()` to update `CurrentPosition`, and sets operational state to `STALL` when movement is complete
|
||||
- `goToTiltPercentage()`: Registered with `onGoToTiltPercentage()` - called when `TargetPositionTiltPercent100ths` changes. Calls `setTiltPercentage()` to update `CurrentPosition`, and sets operational state to `STALL` when movement is complete
|
||||
- `stopMotor()`: Registered with `onStop()` - called when `StopMotion` command is received. Stops any ongoing movement, calls `setLiftPercentage()` and `setTiltPercentage()` to update `CurrentPosition` for both, and sets operational state to `STALL` for both
|
||||
|
||||
**Current Position Callback** (called when `CurrentPosition` attributes change):
|
||||
- `onChange()`: Registered with `onChange()` - called when `CurrentPositionLiftPercent100ths` or `CurrentPositionTiltPercent100ths` change (after `setLiftPercentage()` or `setTiltPercentage()` are called). Updates RGB LED visualization to reflect current positions
|
||||
|
||||
**Note:** The Target Position callbacks (`fullOpen()`, `fullClose()`, `goToLiftPercentage()`, `goToTiltPercentage()`, `stopMotor()`) call `setLiftPercentage()` or `setTiltPercentage()` to update the `CurrentPosition` attributes. This triggers the `onChange()` callback, which updates the visualization.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured
|
||||
- **Window covering not responding**: Verify callback functions are properly implemented and motor control is working
|
||||
- **Position not updating**: Check that `setLiftPercentage()` and `setTiltPercentage()` are being called with correct values
|
||||
- **State not persisting**: Check that the `Preferences` library is properly initialized and that flash memory is not corrupted
|
||||
- **RGB LED not working**: For RGB LED, verify the pin supports RGB LED control. For non-RGB boards, ensure the pin supports PWM (analogWrite)
|
||||
- **Tilt not working**: Ensure the covering type supports tilt (e.g., `BLIND_LIFT_AND_TILT`, `SHUTTER`, or `BLIND_TILT_ONLY`) and that it is specified in `begin()`
|
||||
- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port <PORT> erase_flash`
|
||||
- **No serial output**: Check baudrate (115200) and USB connection
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html)
|
||||
- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html)
|
||||
- [Matter Window Covering Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_window_covering.html)
|
||||
|
||||
## License
|
||||
|
||||
This example is licensed under the Apache License, Version 2.0.
|
||||
@@ -0,0 +1,4 @@
|
||||
fqbn_append: PartitionScheme=huge_app
|
||||
|
||||
requires:
|
||||
- CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
Reference in New Issue
Block a user