3.3.7
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user