Skip to content

Commit 19df21e

Browse files
committed
ESP32 supported
1 parent 58ae946 commit 19df21e

File tree

179 files changed

+387771
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

179 files changed

+387771
-2
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#include "Arduino.h"
2+
#include "WiFi.h"
3+
#include "arduino_homekit_server.h"
4+
#include "ESPButton.h"
5+
6+
extern "C" homekit_server_config_t config;
7+
extern "C" homekit_characteristic_t name;
8+
extern "C" char ACCESSORY_NAME[32];
9+
extern "C" void led_toggle();
10+
extern "C" void accessory_init();
11+
12+
#define PIN_BTN 0
13+
14+
const char *ssid = "your-ssid";
15+
const char *password = "your-password";
16+
17+
void setup() {
18+
Serial.begin(115200);
19+
20+
WiFi.mode(WIFI_STA);
21+
WiFi.persistent(false);
22+
WiFi.disconnect(false);
23+
WiFi.setAutoReconnect(true);
24+
WiFi.begin(ssid, password);
25+
26+
printf("\n");
27+
printf("SketchSize: %d B\n", ESP.getSketchSize());
28+
printf("FreeSketchSpace: %d B\n", ESP.getFreeSketchSpace());
29+
printf("FlashChipSize: %d B\n", ESP.getFlashChipSize());
30+
//printf("FlashChipRealSize: %d B\n", ESP.getFlashChipRealSize());
31+
printf("FlashChipSpeed: %d\n", ESP.getFlashChipSpeed());
32+
printf("SdkVersion: %s\n", ESP.getSdkVersion());
33+
//printf("FullVersion: %s\n", ESP.getFullVersion().c_str());
34+
//printf("CpuFreq: %dMHz\n", ESP.getCpuFreqMHz());
35+
printf("FreeHeap: %d B\n", ESP.getFreeHeap());
36+
//printf("ResetInfo: %s\n", ESP.getResetInfo().c_str());
37+
//printf("ResetReason: %s\n", ESP.getResetReason().c_str());
38+
DEBUG_HEAP();
39+
40+
//Init Button
41+
pinMode(PIN_BTN, INPUT_PULLUP);
42+
ESPButton.add(0, PIN_BTN, LOW, false, true);
43+
ESPButton.setCallback([](uint8_t id, ESPButtonEvent event) {
44+
printf("ButtonEvent: %s\n", ESPButton.getButtonEventDescription(event));
45+
if (event == ESPBUTTONEVENT_SINGLECLICK) {
46+
led_toggle();
47+
} else if (event == ESPBUTTONEVENT_DOUBLECLICK) {
48+
49+
} else if (event == ESPBUTTONEVENT_LONGCLICK) {
50+
homekit_storage_reset();
51+
esp_restart();
52+
}
53+
});
54+
ESPButton.begin();
55+
homekit_setup();
56+
}
57+
58+
void loop() {
59+
ESPButton.loop();
60+
uint32_t time = millis();
61+
static uint32_t next_heap_millis = 0;
62+
if (time > next_heap_millis) {
63+
INFO("heap: %u, sockets: %d", ESP.getFreeHeap(), arduino_homekit_connected_clients_count());
64+
next_heap_millis = time + 5000;
65+
}
66+
delay(5);
67+
}
68+
69+
void homekit_setup() {
70+
accessory_init();
71+
// We create one FreeRTOS-task for HomeKit
72+
// No need to call arduino_homekit_loop
73+
arduino_homekit_setup(&config);
74+
}
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
/*
2+
* ESPButton.h
3+
* Ticker-scan based Button Handler with debounce.
4+
* Default scan interval is 16ms (60FPS).
5+
* All added Buttons are scanned by a global Ticker (by os timer).
6+
* [!!!] All events are triggered in interrupt, so you can NOT use delay() in callback!
7+
*
8+
* Usage:
9+
* in setup():
10+
* pinMode(pin, INPUT_PULLUP / INPUT /... );
11+
* ESPButton.add(id, pin, pin_down_digital);
12+
* ESPButton.setCallback(...); // handle your ButtonEvent by id
13+
* ESPButton.begin(); // call begin to start scan.
14+
* in loop():
15+
* ESPButton.loop(); // will notify the event in loop (not in interrupt timer)
16+
*
17+
* Created on: 2020-03-08
18+
* Last update: 2020-04-14
19+
* Author: Wang Bin
20+
*/
21+
22+
#ifndef ESPBUTTON_H_
23+
#define ESPBUTTON_H_
24+
25+
#include <Arduino.h>
26+
#include <functional>
27+
#include <Ticker.h>
28+
29+
#define ESPBUTTON_DEBUG(message, ...) //printf_P(PSTR("[%7d] ESPButton: " message "\n"), millis(), ##__VA_ARGS__)
30+
31+
typedef struct _ESPButtonEntry {
32+
uint8_t id = -1;
33+
uint8_t pin = -1;
34+
uint8_t pin_down_digital = LOW; //按下状态时的digital值
35+
36+
bool stable_down = false; //稳定状态的下的按键状态 (true: down, false: up)
37+
uint32_t stable_threshold = 40; //如果按键状态维持一段时间未变化就认为是stable
38+
bool is_stable = false; //当前是否是稳定状态,只有稳定状态下才会进一步处理
39+
bool raw_down = false; //未消抖的原始按键状态
40+
uint32_t raw_changed_time = 0; //未消抖的原始按键状态的改变的时间
41+
42+
//void (*ext_digitalRead)(uint8_t pin);
43+
//如果该pin不是ESP芯片的引脚,而是从其他的扩展芯片读取的,就需要传入ext_digitalRead
44+
std::function<uint8_t(uint8_t pin)> ext_digitalRead = nullptr;
45+
//======
46+
bool longclicked = false; //用来保证一次按下只能触发一次长按
47+
bool down_handled = false; //标志着是否已经处理了该次down按下事件(比如已经触发了长按)
48+
//down->up,在规定时间内再次down就是双击,否则超时就是单击
49+
bool wait_doubleclick = false; //标志着是否等待着双击事件
50+
uint32_t down_time = 0; //ms
51+
uint32_t up_time = 0;
52+
53+
uint32_t longclick_threshold = 5000;
54+
uint32_t doubleclick_threshold = 150; //按下释放后在此时间间隔内又按下认为是双击
55+
56+
bool longclick_enable = true;
57+
bool doubleclick_enable = true;
58+
//======
59+
struct _ESPButtonEntry *next;
60+
} ESPButtonEntry;
61+
62+
enum ESPButtonEvent {
63+
ESPBUTTONEVENT_NONE = 0,
64+
ESPBUTTONEVENT_SINGLECLICK,
65+
ESPBUTTONEVENT_DOUBLECLICK,
66+
ESPBUTTONEVENT_LONGCLICK
67+
};
68+
class ESPButtonClass;
69+
70+
static void _esp32_ticker_cb(ESPButtonClass *esp_button);
71+
72+
class ESPButtonClass {
73+
74+
public:
75+
76+
typedef std::function<void(uint8_t id, ESPButtonEvent event)> espbutton_callback;
77+
78+
Ticker ticker;
79+
ESPButtonEntry *entries = nullptr;
80+
espbutton_callback callback;
81+
ESPButtonEvent notify_event = ESPBUTTONEVENT_NONE;
82+
uint8_t notify_id = 0;
83+
84+
ESPButtonClass() {
85+
}
86+
~ESPButtonClass() {
87+
}
88+
89+
void begin() {
90+
ticker.detach();
91+
#if defined(ESP8266)
92+
ticker.attach_ms(16, std::bind(&ESPButtonClass::tick, this));
93+
#elif defined(ESP32)
94+
ticker.attach_ms(16, _esp32_ticker_cb, this);
95+
#endif
96+
}
97+
98+
ESPButtonEntry* add(uint8_t _id, uint8_t _pin, uint8_t _pin_down_digital,
99+
bool _doubleclick_enable = false, bool _longclick_enable = true) {
100+
ESPButtonEntry *entry = new ESPButtonEntry();
101+
entry->id = _id;
102+
entry->pin = _pin;
103+
entry->pin_down_digital = _pin_down_digital;
104+
entry->doubleclick_enable = _doubleclick_enable;
105+
entry->longclick_enable = _longclick_enable;
106+
107+
//初始化entry的状态??暂时不需要,我们就是认为按键默认就是未按下的
108+
//entry->laststate_is_down = digitalReadEntryIsDown(entry);
109+
//加入链表
110+
entry->next = entries;
111+
entries = entry;
112+
return entry;
113+
}
114+
115+
void setCallback(espbutton_callback _callback) {
116+
callback = _callback;
117+
}
118+
119+
PGM_P getButtonEventDescription(ESPButtonEvent e) {
120+
switch (e) {
121+
case ESPBUTTONEVENT_SINGLECLICK:
122+
return PSTR("SingleClick");
123+
case ESPBUTTONEVENT_DOUBLECLICK:
124+
return PSTR("DoubleClick");
125+
case ESPBUTTONEVENT_LONGCLICK:
126+
return PSTR("LongClick");
127+
default:
128+
return PSTR("<unknown event>");
129+
}
130+
}
131+
132+
void tick() {
133+
ESPButtonEntry *entry = entries;
134+
while (entry) {
135+
tickEntry(entry);
136+
entry = entry->next;
137+
}
138+
}
139+
140+
void loop() {
141+
if (callback && (notify_event != ESPBUTTONEVENT_NONE)) {
142+
callback(notify_id, notify_event);
143+
notify_id = 0;
144+
notify_event = ESPBUTTONEVENT_NONE;
145+
}
146+
}
147+
148+
private:
149+
150+
bool digitalReadEntryIsDown(ESPButtonEntry *entry) {
151+
if (entry->ext_digitalRead) {
152+
return entry->ext_digitalRead(entry->pin) == entry->pin_down_digital;
153+
}
154+
return digitalRead(entry->pin) == entry->pin_down_digital;
155+
}
156+
157+
void tickEntry(ESPButtonEntry *entry) {
158+
const uint32_t t = millis();
159+
const bool down = digitalReadEntryIsDown(entry);
160+
if (down != entry->raw_down) {
161+
entry->raw_down = down;
162+
entry->is_stable = false;
163+
entry->raw_changed_time = t;
164+
ESPBUTTON_DEBUG("change (%s)", down ? PSTR("down") : PSTR("up"));
165+
} else { // down == raw_down
166+
// 在stable_threshold时间内一直没有变化,认为是stable
167+
if (!entry->is_stable) {
168+
if (t - entry->raw_changed_time > entry->stable_threshold) {
169+
ESPBUTTON_DEBUG("t: %d, raw: %d", t, entry->raw_changed_time);ESPBUTTON_DEBUG("stable (%s)", down ? PSTR("down") : PSTR("up"));
170+
entry->is_stable = true;
171+
}
172+
}
173+
}
174+
if (!entry->is_stable) {
175+
//ESPBUTTON_DEBUG("not stable");
176+
return;
177+
}
178+
//以上代码能检测出超过一定时间的稳定了的状态,等稳定了之后再做处理
179+
180+
if (entry->stable_down == down) {
181+
handleEntryUnchanged(entry);
182+
return;
183+
} else {
184+
entry->stable_down = down;
185+
handleEntryChanged(entry);
186+
}
187+
188+
}
189+
190+
void handleEntryChanged(ESPButtonEntry *entry) {
191+
const bool down = entry->stable_down;
192+
//仅有单击事件就在down的时候直接回调? 暂时不这么做,类比实体开关,按下不松手的时候,就是一直开着的状态
193+
//逻辑如下:
194+
//单击:按下->释放->且释放一段时间内没有第二次按下
195+
//双击:按下->释放->且释放一段时间内执行第二次按下时触发
196+
//长按:按下一段时间内未释放
197+
if (down) { //down
198+
if (entry->wait_doubleclick && entry->doubleclick_enable) {
199+
//规定时间内第二次down了,认为是双击
200+
//亲测,一般情况下我的双击up->第二次down的间隔是80~100左右
201+
ESPBUTTON_DEBUG("doubleclick, wait %d", (millis() - entry->up_time));
202+
entry->down_handled = true;
203+
notifyEvent(entry, ESPBUTTONEVENT_DOUBLECLICK);
204+
} else {
205+
//第一次按下
206+
entry->down_handled = false;
207+
}
208+
entry->down_time = millis();
209+
entry->longclicked = false;
210+
entry->wait_doubleclick = false;
211+
} else { //up
212+
if (!entry->down_handled) {
213+
if (entry->doubleclick_enable) {
214+
//在loop中延时等待第二次按下
215+
entry->up_time = millis();
216+
entry->wait_doubleclick = true;
217+
} else {
218+
entry->down_handled = true;
219+
notifyEvent(entry, ESPBUTTONEVENT_SINGLECLICK);
220+
}
221+
}
222+
}
223+
224+
}
225+
226+
void handleEntryUnchanged(ESPButtonEntry *entry) {
227+
bool down = entry->stable_down;
228+
if (down) { //down
229+
if (entry->longclick_enable) {
230+
if (!entry->longclicked && !entry->down_handled) {
231+
if (millis() - entry->down_time > entry->longclick_threshold) {
232+
entry->longclicked = true;
233+
entry->down_handled = true;
234+
notifyEvent(entry, ESPBUTTONEVENT_LONGCLICK);
235+
}
236+
}
237+
}
238+
} else { //up
239+
entry->longclicked = false;
240+
if (entry->wait_doubleclick && entry->doubleclick_enable) {
241+
if (millis() - entry->up_time > entry->doubleclick_threshold) {
242+
entry->wait_doubleclick = false;
243+
entry->down_handled = true;
244+
//key2DoClick();
245+
notifyEvent(entry, ESPBUTTONEVENT_SINGLECLICK);
246+
}
247+
}
248+
249+
}
250+
}
251+
252+
void notifyEvent(ESPButtonEntry *entry, ESPButtonEvent event) {
253+
ESPBUTTON_DEBUG("Button(%d): %s", entry->id, getButtonEventDescription(event));
254+
// Save the Event and notify it in loop
255+
if (notify_event != ESPBUTTONEVENT_NONE) {
256+
ESPBUTTON_DEBUG("Warnning! Previous Button Event is not handled in loop!");
257+
}
258+
notify_event = event;
259+
notify_id = entry->id;
260+
// if (callback) {
261+
// callback(entry->id, event);
262+
// }
263+
}
264+
265+
};
266+
267+
ESPButtonClass ESPButton;
268+
269+
static void _esp32_ticker_cb(ESPButtonClass *esp_button) {
270+
esp_button->tick();
271+
}
272+
273+
#endif /* ESPBUTTON_H_ */

0 commit comments

Comments
 (0)