Skip to content

Commit 29acdc6

Browse files
committed
feat(matter): adds new fan endpoint and example
1 parent 9f5f95e commit 29acdc6

File tree

4 files changed

+580
-0
lines changed

4 files changed

+580
-0
lines changed
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Matter Manager
16+
#include <Matter.h>
17+
#include <WiFi.h>
18+
19+
// List of Matter Endpoints for this Node
20+
// Fan Endpoint - On/Off control + Speed Percent Control + Fan Modes
21+
MatterFan Fan;
22+
23+
// set your board USER BUTTON pin here - used for toggling on/off
24+
const uint8_t buttonPin = 0; // Set your pin here. Using BOOT Button. C6/C3 use GPIO9.
25+
26+
// set your board Analog Pin here - used for changing the Fan speed
27+
const uint8_t analogPin = A0; // Analog Pin depends on each board
28+
29+
// WiFi is manually set and started
30+
const char *ssid = "your-ssid"; // Change this to your WiFi SSID
31+
const char *password = "your-password"; // Change this to your WiFi password
32+
33+
void setup() {
34+
// Initialize the USER BUTTON (Boot button) GPIO that will toggle the Fan (on/off)
35+
pinMode(buttonPin, INPUT_PULLUP);
36+
// Initialize the Analog Pin A0 used to read input voltage and to set the Fan speed accordingly
37+
pinMode(analogPin, INPUT);
38+
analogReadResolution(10); // 10 bits resolution reading 0..1023
39+
40+
Serial.begin(115200);
41+
while (!Serial) {
42+
delay(100);
43+
}
44+
45+
// We start by connecting to a WiFi network
46+
Serial.print("Connecting to ");
47+
Serial.println(ssid);
48+
// enable IPv6
49+
WiFi.enableIPv6(true);
50+
// Manually connect to WiFi
51+
WiFi.begin(ssid, password);
52+
// Wait for connection
53+
while (WiFi.status() != WL_CONNECTED) {
54+
delay(500);
55+
Serial.print(".");
56+
}
57+
Serial.println("\r\nWiFi connected");
58+
Serial.println("IP address: ");
59+
Serial.println(WiFi.localIP());
60+
delay(500);
61+
62+
// On Boot or Reset, Fan is set at 0% speed, OFF, changing between OFF, ON, SMART and HIGH
63+
Fan.begin(0, MatterFan::FAN_MODE_OFF, MatterFan::FAN_MODE_SEQ_OFF_HIGH);
64+
65+
// callback functions would control Fan motor
66+
// the Matter Controller will send new data whenver the User APP or Automation request
67+
68+
// single feature callbacks take place before the generic (all features) callback
69+
// This callback will be executed whenever the speed percent matter attribute is updated
70+
Fan.onChangeSpeedPercent([](uint8_t speedPercent) {
71+
// setting speed to Zero, while the Fan is ON, shall turn the Fan off
72+
if (speedPercent == 0 && Fan.getMode() != MatterFan::FAN_MODE_OFF) {
73+
// ATTR_SET do not update the attribute, just set it to avoid inifinite loop
74+
return Fan.setOnOff(false, Fan.ATTR_SET);
75+
}
76+
// changing the speed to higher than Zero, while the Fan is OFF, shall turn the Fan on
77+
if (speedPercent > 0 && Fan.getMode() == MatterFan::FAN_MODE_OFF) {
78+
// ATTR_SET do not update the attribute, just set it to avoid inifinite loop
79+
return Fan.setOnOff(true, Fan.ATTR_SET);
80+
}
81+
// for other case, just return true
82+
return true;
83+
});
84+
85+
// This callback will be executed whenever the fan mode matter attribute is updated
86+
// This will take action when user APP starts the Fan by changing the mode
87+
Fan.onChangeMode([](MatterFan::FanMode_t fanMode) {
88+
// when the Fan is turned on using Mode Selection, while it is OFF, shall start it by setting the speed to 50%
89+
if (Fan.getSpeedPercent() == 0 && fanMode != MatterFan::FAN_MODE_OFF) {
90+
Serial.println("Starting Smart Mode -- set speed to 50%");
91+
// ATTR_SET do not update the attribute, just set it to avoid inifinite loop
92+
return Fan.setSpeedPercent(50, Fan.ATTR_SET);
93+
}
94+
return true;
95+
});
96+
97+
// Generic callback will be executed as soon as a single feature callback is done
98+
// In this example, it will just print status messages
99+
Fan.onChange([](MatterFan::FanMode_t fanMode, uint8_t speedPercent) {
100+
// just report state
101+
Serial.printf("Fan State: Mode %s | %d%% speed.\r\n", Fan.getFanModeString(fanMode), speedPercent);
102+
// returns success
103+
return true;
104+
});
105+
106+
// Matter beginning - Last step, after all EndPoints are initialized
107+
Matter.begin();
108+
// This may be a restart of a already commissioned Matter accessory
109+
if (Matter.isDeviceCommissioned()) {
110+
Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use.");
111+
}
112+
}
113+
114+
// Builtin Button control
115+
uint32_t button_time_stamp = 0; // debouncing control
116+
bool button_state = false; // false = released | true = pressed
117+
const uint32_t debouceTime = 250; // button debouncing time (ms)
118+
const uint32_t decommissioningTimeout = 10000; // keep the button pressed for 10s to decommission the Matter Fabric
119+
120+
void loop() {
121+
// Check Matter Accessory Commissioning state, which may change during execution of loop()
122+
if (!Matter.isDeviceCommissioned()) {
123+
Serial.println("");
124+
Serial.println("Matter Node is not commissioned yet.");
125+
Serial.println("Initiate the device discovery in your Matter environment.");
126+
Serial.println("Commission it to your Matter hub with the manual pairing code or QR code");
127+
Serial.printf("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str());
128+
Serial.printf("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str());
129+
// waits for Matter Generic Switch Commissioning.
130+
uint32_t timeCount = 0;
131+
while (!Matter.isDeviceCommissioned()) {
132+
delay(100);
133+
if ((timeCount++ % 50) == 0) { // 50*100ms = 5 sec
134+
Serial.println("Matter Node not commissioned yet. Waiting for commissioning.");
135+
}
136+
}
137+
Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use.");
138+
}
139+
140+
// A builtin button is used to trigger and send a command to the Matter Controller
141+
// Check if the button has been pressed
142+
if (digitalRead(buttonPin) == LOW && !button_state) {
143+
// deals with button debouncing
144+
button_time_stamp = millis(); // record the time while the button is pressed.
145+
button_state = true; // pressed.
146+
}
147+
148+
// Onboard User Button is used as a smart button or to decommission it
149+
uint32_t time_diff = millis() - button_time_stamp;
150+
if (button_state && time_diff > debouceTime && digitalRead(buttonPin) == HIGH) {
151+
button_state = false; // released
152+
// builtin button is released - send a click event to the Matter Controller
153+
Fan.toggle();
154+
Serial.printf("User button released. Setting the Fan %s.\r\n", Fan > 0 ? "ON" : "OFF");
155+
156+
// Factory reset is triggered if the button is pressed longer than 10 seconds
157+
if (time_diff > decommissioningTimeout) {
158+
Serial.println("Decommissioning the Generic Switch Matter Accessory. It shall be commissioned again.");
159+
Matter.decommission();
160+
}
161+
}
162+
163+
// checks Analog pin and adjust the speed only if it has changed
164+
static int lastRead = 0;
165+
// analog values (0..1023) / 110 => mapped into 10 steps (0..9)
166+
int anaVal = analogRead(analogPin) / 110;
167+
if (lastRead != anaVal) {
168+
// speed percent moves in steps of 10. Range is 10..100
169+
if (Fan.setSpeedPercent((anaVal + 1) * 10)) {
170+
lastRead = anaVal;
171+
}
172+
}
173+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"fqbn_append": "PartitionScheme=huge_app",
3+
"requires": [
4+
"CONFIG_SOC_WIFI_SUPPORTED=y",
5+
"CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y"
6+
]
7+
}

0 commit comments

Comments
 (0)