Skip to content

Commit 4c0eba2

Browse files
committed
publish
1 parent 3f5afb3 commit 4c0eba2

Some content is hidden

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

123 files changed

+61021
-0
lines changed

README.md

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Arduino Homekit ESP8266
2+
3+
### Apple HomeKit accessory server library for ESP8266 Arduino
4+
5+
This Arduino library is a native Apple HomeKit accessory implementation for the ESP8266, and works without any additional bridges.
6+
7+
This project is mainly based on [esp-homekit](https://github.com/maximkulkin/esp-homekit) for [ESP-OPEN-RTOS](https://github.com/SuperHouse/esp-open-rtos).
8+
9+
I ported the RTOS-based implementation of [esp-homekit](https://github.com/maximkulkin/esp-homekit) to the pure Arduino environment, aimed at easy and fast building project using Arduino IDE (or Eclipse with sloeber, PlatformIO).
10+
11+
Enjoy the "one-key" build, "one-key" upload, and work to link various other Arduino libraries with Apple Homekit!
12+
13+
Here is a [discussion](https://github.com/HomeACcessoryKid/Arduino-HomeKit/issues/1) about the RTOS is required for running Apple HomeKit, and this project is a proof of concept that Apple HomeKit can be implemented and work fine without the RTOS.
14+
15+
### Setup code of the example sketch
16+
17+
``111-11-111``
18+
19+
20+
### Usage
21+
22+
1. Define your accessory in a .c file to enjoy the convenient "Macro" style declaration. You can also define your accessory in a .ino file using C++ code.
23+
```C
24+
homekit_accessory_t *accessories[] = ...
25+
homekit_server_config_t config = {
26+
.accessories = accessories,
27+
.password = "111-11-111",
28+
//.on_event = on_homekit_event, //optional
29+
//.setupId = "ABCD" //optional
30+
};
31+
```
32+
2. In your sketch
33+
```C
34+
#include <arduino_homekit_server.h>;
35+
36+
//access the config defined in C code
37+
extern "C" homekit_server_config_t config;
38+
39+
void setup() {
40+
WiFi.begin(ssid, password);
41+
arduino_homekit_setup(&config);
42+
}
43+
44+
void loop() {
45+
arduino_homekit_loop();
46+
}
47+
```
48+
Done.
49+
50+
### Performance
51+
52+
Notice: You should set the ESP8266 CPU to run at 160MHz (at least during the pairing process), to avoid the tcp-socket disconnection from iOS device caused by timeout.
53+
54+
* Preinit: ~9.1s (You can see the accessory on your iOS HOME app after Preinit)
55+
* Pair Setup Step 1/3: ~0s (The heavy crypto computation is done in Preinit)
56+
* Pair Setup Step 2/3: ~12.1s
57+
* Pair Setup Step 3/3: ~0.8s (The pair-setup is only processed when first paired with iOS device)
58+
* Pair Verify Step 1/2: ~0.3s
59+
* Pair Verify Step 2/2: ~0.8s (The Verify Step is required every time iOS connects or reconnects to ESP8266 to establish secure session)
60+
61+
All pairing process takes ~14s after you input the setup-code on your iPhone. Notice that Preinit require ~9s before you can start to pair.
62+
63+
64+
### Heap (memory)
65+
66+
The heap is critical for ESP8266 with full TCP/IP support. ESP8266 easily crashes when the memory is lower than ~5000.
67+
68+
I tried to make WolfSSL crypto work safely on ESP8266 with better performance and lower memory or a trade-off. See details in next section.
69+
70+
Here are the free heap values of running the example sketch:
71+
72+
* Boot: ~26000
73+
* Preinit over: ~22000
74+
* Pairing: ~17000 (or even low when crypto computing)
75+
* Paired and connected with one iOS device: ~21700
76+
* Paired and no iOS device connected: ~23400
77+
78+
79+
### WolfSSL
80+
81+
* Based on wolfssl-3.13.0-stable.
82+
* Clean source code: the unused files are removed.
83+
* `CURVE25519_SMALL` and `ED25519_SMALL`: ESP8266 can not directly run without `SMALL` defined since the memory is not sufficient. But the NO `SMALL` version is faster. I mark the big `ge_precomp base[32][8]` with PROGMEM to store it in Flash (around 70KB). Also the `ge_double_scalarmult_vartime` can not run caused by lack of heap. I define `ESP_GE_DOUBLE_SCALARMULT_VARTIME_LOWMEM` in `user_settings.h` to use LOWMEM version of `ge_double_scalarmult_vartime` in `ge_low_mem.c`. This is a trade-off of performance and memory. If you want more Flash space, you should define `CURVE25519_SMALL` and `ED25519_SMALL` and undefine `ESP_GE_DOUBLE_SCALARMULT_VARTIME_LOWMEM` in `user_settings.h`.
84+
* `integer.c`(big integer operations): `MP_16BIT` and `ESP_FORCE_S_MP_EXPTMOD` are defined for better performance in ESP8266. `ESP_INTEGER_WINSIZE` (value is 3) is defined to avoid crash caused by memory exhaust and the values of {3, 4, 5} are of similar performance (this will lead the Pair Verify Steps take 1.2s + 0.9s).
85+
86+
### Storage
87+
88+
* The pairing data is stored in the `EEPROM` address in ESP8266 Arduino core.
89+
* This project does not use the `EEPROM` library with data-cache to reduce memory use (directly call flash_read and write).
90+
* The `EEPROM` is 4096B in ESP8266, this project uses max [0, 1408B).
91+
* See the comments in `storge.c` and [esp8266-EEPROM-doc](https://arduino-esp8266.readthedocs.io/en/2.6.3/libraries.html#eeprom).
92+
* `EEPROM` of [1408, 4096) is safe for you to use.
93+
* This project do NOT use `FS(file system)`, so you can use `FS` freely.
94+
95+
96+
### WatchDog
97+
98+
* There are software and hardware watchdogs in ESP8266 Arduino core. The heavy crypto computing will lead to watchdog reset.
99+
* There are disable/enable api of software-watchdog in ESP8266 Arduino core.
100+
* I found the [esp_hw_wdt](https://github.com/ComSuite/esp_hw_wdt) to disable/enable the hardware-watchdog.
101+
* The two watchdogs are disabled while `Preinit` and `Pair Setup Step 2/3`.
102+
103+
### Recommended settings in IDE
104+
105+
* Module: Generic ESP8266 Module (to enable full settings)
106+
* FlashSize: at least 470KB for sketch (see `WolfSSL` section if you want a smaller sketch)
107+
* LwIP Variant: v2 Lower Memory (for lower memory use)
108+
* Debug Level: None (for lower memory use)
109+
* Espressif FW: nonos-sdk 2.2.1+119(191122) (which I used to build this project)
110+
* SSL Support: Basic SSL ciphers (lower ROM use)
111+
* VTables: Flash (does not matter maybe)
112+
* Erase Flash: select `All Flash Contents` when you first upload
113+
* CPU Frequency: 160MHz (must)
114+
115+
### Arduino port
116+
117+
* `ESP8266WiFi` (WiFiServer and WiFiClient) is used for tcp connection.
118+
* `ESP8266mDNS` is used for advertising (Bonjour)
119+
120+
### TODO
121+
122+
* ESP32 Arduino version (ESP32 Arduino is base on RTOS and it is not hard to port).
123+
124+
125+
### More examples and demos
126+
127+
* Check [esp-homekit-demo](https://github.com/maximkulkin/esp-homekit-demo)
128+
129+
### Troubleshooting
130+
131+
* Check your serial output with [example_serial_output.txt](https://raw.github.com/Mixiaoxiao/Arduino-HomeKit-ESP8266/master/example_serial_output.txt)
132+
133+
### Thanks
134+
- [esp-homekit](https://github.com/maximkulkin/esp-homekit)
135+
- [esp-homekit-demo](https://github.com/maximkulkin/esp-homekit-demo)
136+
- [esp_hw_wdt](https://github.com/ComSuite/esp_hw_wdt)
137+
- [WolfSSL/WolfCrypt](https://www.wolfssl.com/products/wolfcrypt-2/)
138+

example_serial_output.txt

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
SketchSize: 473312 B
2+
FreeSketchSpace: 487424 B
3+
FlashChipSize: 4194304 B
4+
FlashChipRealSize: 4194304 B
5+
FlashChipSpeed: 40000000
6+
SdkVersion: 2.2.2-dev(a58da79)
7+
FullVersion: SDK:2.2.2-dev(a58da79)/Core:2.6.3=20603000/lwIP:STABLE-2_1_2_RELEASE/glue:1.2-16-ge23a07e/BearSSL:89454af
8+
CpuFreq: 160MHz
9+
FreeHeap: 26152 B
10+
ResetInfo: Fatal exception:0 flag:6 (EXT_SYS_RST) epc1:0x00000000 epc2:0x00000000 epc3:0x00000000 excvaddr:0x00000000 depc:0x00000000
11+
ResetReason: External System
12+
OFF
13+
>>> [ 111] HomeKit: Starting server
14+
*** [Storage] homekit_storage_init: EEPROM max: 4096 B
15+
*** [Storage] homekit_storage_init: Pairing_data size: 80
16+
*** [Storage] homekit_storage_init: MAX pairing count: 16
17+
*** [Storage] homekit_storage_init: _EEPROM_start: 0xfb000 (1028096)
18+
*** [Storage] homekit_storage_init: _SPIFFS_start: 0xeb000 (962560)
19+
>>> [ 142] HomeKit: Using existing accessory ID: F4:E1:C6:6F:24:6C
20+
>>> [ 148] HomeKit: Preinit pairing context
21+
>>> [ 152] HomeKit: Using user-specified password: 111-11-111
22+
=== integer.c s_mp_exptmod, winsize=6, redmode=0
23+
=== crypto_srp_init took: 6041ms
24+
=== integer.c s_mp_exptmod, winsize=5, redmode=0
25+
=== crypto_srp_get_public_key took: 3094ms
26+
>>> [ 9320] HomeKit: arduino_homekit_preinit success
27+
>>> [ 9325] HomeKit: Configuring mDNS
28+
>>> [ 9328] HomeKit: MDNS.begin->ESP8266_LED_4CBB41
29+
>>> [ 9335] HomeKit: Init server over
30+
>>> [ 10540] HomeKit: heap: 22696, sockets: 0
31+
>>> [ 12943] HomeKit: WiFi connected, ip: 192.168.1.100, mask: 255.255.255.0, gw: 192.168.1.253
32+
>>> [ 12952] HomeKit: MDNS is restarted
33+
>>> [ 15545] HomeKit: heap: 21376, sockets: 0
34+
>>> [ 16755] HomeKit: WiFiServer receives a new client (current 0, max 4)
35+
>>> [ 16762] HomeKit: Got new client connection: local 192.168.1.100:5556, remote 192.168.1.101:51130
36+
>>> [ 16772] HomeKit: [Client 1073703676] Pair Setup Step 1/3
37+
### [ 16779] pair_setup took 7ms
38+
>>> [ 18921] HomeKit: [Client 1073703676] Pair Setup Step 2/3
39+
=== integer.c s_mp_exptmod, winsize=6, redmode=0
40+
=== integer.c s_mp_exptmod, winsize=5, redmode=0
41+
=== crypto_srp_compute_key took: 12105ms
42+
### [ 31049] pair_setup took 12128ms
43+
>>> [ 31053] HomeKit: heap: 18920, sockets: 1
44+
>>> [ 31171] HomeKit: [Client 1073703676] Pair Setup Step 3/3
45+
>>> [ 31946] HomeKit: Added pairing with CF87DA6B-7078-44BB-AC04-27B6F2B26D37
46+
>>> [ 32019] HomeKit: Free saved_preinit_pairing_context
47+
>>> [ 32025] HomeKit: [Client 1073703676] Successfully paired
48+
### [ 32030] pair_setup took 859ms
49+
>>> [ 32107] HomeKit: [Client 1073703676] Disconnected!
50+
>>> [ 32112] HomeKit: [Client 1073703676] Closing client connection
51+
>>> [ 32139] HomeKit: WiFiServer receives a new client (current 0, max 4)
52+
>>> [ 32146] HomeKit: Got new client connection: local 192.168.1.100:5556, remote 192.168.1.101:51131
53+
>>> [ 32156] HomeKit: [Client 1073699516] Pair Verify Step 1/2
54+
### [ 32478] pair_verify took 322ms
55+
>>> [ 32481] HomeKit: Free heap: 21040
56+
>>> [ 32517] HomeKit: [Client 1073699516] Pair Verify Step 2/2
57+
>>> [ 32523] HomeKit: [Client 1073699516] Found pairing with CF87DA6B-7078-44BB-AC04-27B6F2B26D37
58+
>>> [ 33302] HomeKit: [Client 1073699516] Verification successful, secure session established
59+
### [ 33310] pair_verify took 794ms
60+
>>> [ 33314] HomeKit: Free heap: 21152
61+
>>> [ 33518] HomeKit: [Client 1073699516] Get Accessories
62+
### [ 33560] get_accessories took 43ms
63+
>>> [ 33642] HomeKit: [Client 1073699516] Update Characteristics
64+
### [ 33652] update_characteristics took 10ms
65+
>>> [ 33679] HomeKit: [Client 1073699516] Update Characteristics
66+
### [ 33689] update_characteristics took 10ms
67+
>>> [ 33735] HomeKit: [Client 1073699516] Update Characteristics
68+
### [ 33745] update_characteristics took 10ms
69+
>>> [ 33762] HomeKit: [Client 1073699516] Get Characteristics
70+
>>> [ 35874] HomeKit: [Client 1073699516] Get Characteristics
71+
>>> [ 36056] HomeKit: heap: 19672, sockets: 1
72+
>>> [ 36280] HomeKit: [Client 1073699516] Update Characteristics
73+
accessory identify
74+
ON 100 (pwm: 0 of 1023)
75+
OFF
76+
ON 100 (pwm: 0 of 1023)
77+
OFF
78+
ON 100 (pwm: 0 of 1023)
79+
OFF
80+
### [ 36899] update_characteristics took 619ms
81+
>>> [ 39555] HomeKit: [Client 1073699516] Update Characteristics
82+
accessory identify
83+
ON 100 (pwm: 0 of 1023)
84+
OFF
85+
ON 100 (pwm: 0 of 1023)
86+
OFF
87+
ON 100 (pwm: 0 of 1023)
88+
OFF
89+
### [ 40174] update_characteristics took 619ms
90+
>>> [ 41060] HomeKit: heap: 21688, sockets: 1
91+
>>> [ 44367] HomeKit: [Client 1073699516] Get Characteristics
92+
>>> [ 45699] HomeKit: [Client 1073699516] Update Characteristics
93+
OFF
94+
ON 34 (pwm: 675 of 1023)
95+
### [ 45712] update_characteristics took 13ms
96+
>>> [ 46062] HomeKit: heap: 21688, sockets: 1
97+
>>> [ 46724] HomeKit: [Client 1073699516] Update Characteristics
98+
ON 78 (pwm: 225 of 1023)
99+
ON 78 (pwm: 225 of 1023)
100+
### [ 46740] update_characteristics took 16ms
101+
>>> [ 47070] HomeKit: [Client 1073699516] Update Characteristics
102+
ON 100 (pwm: 0 of 1023)
103+
ON 100 (pwm: 0 of 1023)
104+
### [ 47085] update_characteristics took 15ms
105+
>>> [ 51063] HomeKit: heap: 21688, sockets: 1
106+
>>> [ 55120] HomeKit: [Client 1073699516] Update Characteristics
107+
OFF
108+
### [ 55130] update_characteristics took 10ms
109+
>>> [ 55832] HomeKit: [Client 1073699516] Update Characteristics
110+
ON 100 (pwm: 0 of 1023)
111+
### [ 55843] update_characteristics took 11ms
112+
>>> [ 56065] HomeKit: heap: 21728, sockets: 1
113+
>>> [ 57271] HomeKit: [Client 1073699516] Update Characteristics
114+
OFF
115+
### [ 57280] update_characteristics took 9ms
116+
>>> [ 57579] HomeKit: [Client 1073699516] Update Characteristics
117+
ON 100 (pwm: 0 of 1023)
118+
### [ 57591] update_characteristics took 12ms
119+
>>> [ 59216] HomeKit: [Client 1073699516] Update Characteristics
120+
OFF
121+
### [ 59225] update_characteristics took 9ms
122+
>>> [ 61067] HomeKit: heap: 21728, sockets: 1
123+
124+
>>> [1086714] HomeKit: heap: 23360, sockets: 0

examples/simple_led/ButtonDebounce.h

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#pragma once
2+
#ifndef BUTTON_DEBOUNCE_H_
3+
#define BUTTON_DEBOUNCE_H_
4+
5+
#include <Arduino.h>
6+
#include <functional>
7+
#include <FunctionalInterrupt.h> //attachInterrupt可以传function
8+
9+
//Ref debounce_time = 35 , dbTime=25
10+
//https://github.com/evert-arias/EasyButton/blob/master/src/EasyButton.h
11+
//https://github.com/JChristensen/JC_Button/blob/master/src/JC_Button.h
12+
13+
14+
/**
15+
* ButtonDebounce
16+
* WangBin 2019.12.26
17+
*
18+
* Example:
19+
* ButtonDebounce flashButton(D3, INPUT_PULLUP, LOW);
20+
* flashButton.setCallback(keyCallback);
21+
* flashButton.setInterrupt(interrupt_callback); // mark "IRAM_ATTR" on ESP32
22+
* call flashButton.update() in interrupt_callback
23+
* use flashButton.checkIsDown() to check the debounced state
24+
*/
25+
26+
27+
class ButtonDebounce {
28+
29+
private:
30+
31+
std::function<void(const bool)> callback;
32+
uint32_t lastchange_ms = 0;
33+
uint32_t debounce_ms = 35;
34+
bool laststate_is_down = false; // true is down;
35+
int pin_down_digital = LOW;
36+
int pin;
37+
38+
bool readIsDown() {
39+
return pin_down_digital == digitalRead(pin);
40+
}
41+
42+
public:
43+
//IRAM_ATTR
44+
ButtonDebounce(uint8_t pin, uint8_t pin_mode, uint8_t pin_down_digital,
45+
uint32_t debounce_ms = 35) : //冒号后赋值和this赋值等价
46+
pin(pin), pin_down_digital(pin_down_digital), debounce_ms(debounce_ms) {
47+
// callback(callback),
48+
//this->pin = pin;
49+
//this->pin_down_digital = pin_down_digital;
50+
//this->debounce_ms = debounce_ms;
51+
pinMode(pin, pin_mode);
52+
// if (attach_interrupt) {
53+
// using namespace std::placeholders;
54+
//// std::function<void(const ButtonDebounce&, void)> ttt = &ButtonDebounce::buttonInterruptFunc;
55+
// std::function<void()> tvctt = std::bind(&ButtonDebounce::buttonInterruptFunc, this);
56+
//// std::function<void()> tvctt = &ButtonDebounce::buttonInterruptFunc; // @suppress("Invalid arguments")
57+
//// void (*ff)(void);
58+
//// ff = tvctt;
59+
//// ff = [](void) {
60+
//// ButtonDebounce::update();
61+
//// };
62+
// attachInterrupt(digitalPinToInterrupt(pin),
63+
// tvctt, CHANGE);
64+
// }
65+
66+
}
67+
68+
void update(bool down) {
69+
const uint32_t t = millis();
70+
if (t - lastchange_ms < debounce_ms) {
71+
lastchange_ms = t;
72+
//debounce
73+
//Serial.println(F("[ButtonDebounce] debounce"));
74+
} else {
75+
if (laststate_is_down == down) {
76+
//same state
77+
//Serial.println(F("[ButtonDebounce] same state"));
78+
} else { //state changed, up->down or down->up
79+
lastchange_ms = t;
80+
laststate_is_down = down;
81+
if (callback) {
82+
callback(down);
83+
}
84+
}
85+
}
86+
}
87+
88+
void update() {
89+
bool down = readIsDown();
90+
update(down);
91+
}
92+
93+
//返回当前debouce后的按钮状态
94+
bool checkIsDown(){
95+
return laststate_is_down;
96+
}
97+
98+
void setCallback(std::function<void(const bool down)> callback) {
99+
this->callback = callback;
100+
}
101+
//interrupt_function 需标记为 IRAM_ATTR
102+
void setInterrupt(std::function<void(void)> interrupt_function) {
103+
if (interrupt_function) {
104+
attachInterrupt(digitalPinToInterrupt(pin), interrupt_function, CHANGE);
105+
}
106+
}
107+
108+
};
109+
110+
#endif

0 commit comments

Comments
 (0)