From 95dada180c7c9c8c0c721ed5c997474adcaadf29 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Mon, 16 Nov 2015 19:29:33 +0100 Subject: [PATCH 01/33] first httpClient --- .../ESP8266httpClient/library.properties | 9 + .../src/ESP8266httpClient.cpp | 195 ++++++++++++++++++ .../ESP8266httpClient/src/ESP8266httpClient.h | 78 +++++++ 3 files changed, 282 insertions(+) create mode 100644 libraries/ESP8266httpClient/library.properties create mode 100644 libraries/ESP8266httpClient/src/ESP8266httpClient.cpp create mode 100644 libraries/ESP8266httpClient/src/ESP8266httpClient.h diff --git a/libraries/ESP8266httpClient/library.properties b/libraries/ESP8266httpClient/library.properties new file mode 100644 index 000000000..55110c143 --- /dev/null +++ b/libraries/ESP8266httpClient/library.properties @@ -0,0 +1,9 @@ +name=ESP8266httpClient +version=1.0 +author=Markus Sattler +maintainer=Markus Sattler +sentence=http Client for ESP8266 +paragraph= +category=Communication +url=https://github.com/Links2004/Arduino/tree/libraries/ESP8266httpClient +architectures=esp8266 diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp new file mode 100644 index 000000000..969f5fa02 --- /dev/null +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp @@ -0,0 +1,195 @@ +/** + * ESP8266httpClient.cpp + * + * Created on: 02.11.2015 + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the ESP8266httpClient for Arduino. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include + +#include "ESP8266httpClient.h" + +httpClient::httpClient() { + _tcp = NULL; + _tcps = NULL; +} + +httpClient::~httpClient() { + if(connected()) { + _tcp->stop(); + } +} + + +void httpClient::begin(const char *host, uint16_t port, const char * url, bool https, const char * httpsFingerprint) { + _host = host; + _port = port; + _url = url; + _https = https; + _httpsFingerprint = httpsFingerprint; +} + +void httpClient::begin(String host, uint16_t port, String url, bool https, String httpsFingerprint) { + begin(host.c_str(), port, url.c_str(), https, httpsFingerprint.c_str()); +} + +/** + * connected + * @return connected status + */ +bool httpClient::connected() { + if(_tcp) { + return _tcp->connected(); + } + return false; +} + +bool httpClient::GET() { + + bool status; + status = connect(); + if(status) { + status = sendHeader("GET"); + } + + return status; +} + +/** + * sends a post request to the server + * @param payload uint8_t * + * @param size size_t + * @return status + */ +bool httpClient::POST(uint8_t * payload, size_t size) { + + bool status; + status = connect(); + if(status) { + addHeader("Content-Length", String(size)); + status = sendHeader("POST"); + } + + if(status) { + status = _tcp->write(&payload[0], size); + } + + return status; +} + +bool httpClient::POST(String payload) { + return POST((uint8_t *) payload.c_str(), payload.length()); +} + +/** + * returns the stram of the tcp connection + * @return WiFiClient + */ +WiFiClient & httpClient::getStream(void) { + if(connected()) { + return *_tcp; + } + // todo return error? +} + +/** + * adds Headder to the request + * @param name + * @param value + * @param first + */ +void httpClient::addHeader(const String& name, const String& value, bool first) { + + String headerLine = name; + headerLine += ": "; + headerLine += value; + headerLine += "\r\n"; + + if(first) { + _Headers = headerLine + _Headers; + } else { + _Headers += headerLine; + } +} + +/** + * init TCP connection and handle ssl verify if needed + * @return true if connection is ok + */ +bool httpClient::connect(void) { + + if(connected()) { + DEBUG_HTTPCLIENT("[HTTP-Client] connect. already connected!\n"); + return true; + } + + if(_https) { + DEBUG_HTTPCLIENT("[HTTP-Client] connect https...\n"); + _tcps = new WiFiClientSecure(); + _tcp = _tcps; + } else { + DEBUG_HTTPCLIENT("[HTTP-Client] connect...\n"); + _tcp = new WiFiClient(); + } + + + if(!_tcp->connect(_host.c_str(), _port)) { + DEBUG_HTTPCLIENT("[HTTP-Client] failed connect to %s:%u.\n", _host.c_str(), _port); + return false; + } + + DEBUG_HTTPCLIENT("[HTTP-Client] connected to %s:%u.\n", _host.c_str(), _port); + + if(_https) { + if(_tcps->verify(_httpsFingerprint.c_str(), _host.c_str())) { + DEBUG_HTTPCLIENT("[HTTP-Client] https certificate matches\n"); + } else { + DEBUG_HTTPCLIENT("[HTTP-Client] https certificate doesn't match!\n"); + _tcp->stop(); + return false; + } + } + + // set Timeout for readBytesUntil and readStringUntil + _tcp->setTimeout(HTTPCLIENT_TCP_TIMEOUT); + +#ifdef ESP8266 + _tcp->setNoDelay(true); +#endif + return connected(); +} + +/** + * sends HTTP request header + * @param type (GET, POST, ...) + * @return status + */ +bool httpClient::sendHeader(const char * type) { + String header = String(type) + " " + _url + " HTTP/1.1\r\n" + "Host: " + _host + "\r\n" + "User-Agent: ESP8266httpClient\r\n" + "Connection: close\r\n" + + _Headers + + "\r\n"; + + return _tcp->write(header.c_str(), header.length()); +} diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.h b/libraries/ESP8266httpClient/src/ESP8266httpClient.h new file mode 100644 index 000000000..e3e34312a --- /dev/null +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.h @@ -0,0 +1,78 @@ +/** + * ESP8266httpClient.h + * + * Created on: 02.11.2015 + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the ESP8266httpClient for Arduino. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef ESP8266HTTPCLIENT_H_ +#define ESP8266HTTPCLIENT_H_ + +#define DEBUG_HTTPCLIENT(...) Serial1.printf( __VA_ARGS__ ) + +#ifndef DEBUG_HTTPCLIENT +#define DEBUG_HTTPCLIENT(...) +#endif + +#define HTTPCLIENT_TCP_TIMEOUT (1000) + +class httpClient { + public: + httpClient(); + ~httpClient(); + + void begin(const char *host, uint16_t port, const char * url = "/", bool https = false, const char * httpsFingerprint = ""); + void begin(String host, uint16_t port, String url = "/", bool https = false, String httpsFingerprint = ""); + + bool connected(void); + + bool GET(); + bool POST(uint8_t * payload, size_t size); + bool POST(String payload); + + void addHeader(const String& name, const String& value, bool first = false); + + + + WiFiClient & getStream(void); + + protected: + WiFiClient * _tcp; + WiFiClientSecure * _tcps; + + String _host; + uint16_t _port; + + String _url; + bool _https; + String _httpsFingerprint; + + String _Headers; + + bool connect(void); + + bool sendHeader(const char * type); + + +}; + + + +#endif /* ESP8266HTTPCLIENT_H_ */ From 70ca494a7f31eb6bdc59cb51e452652a297f9434 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Tue, 17 Nov 2015 17:40:14 +0100 Subject: [PATCH 02/33] add Response header handling --- .../src/ESP8266httpClient.cpp | 146 ++++++++++++++++-- .../ESP8266httpClient/src/ESP8266httpClient.h | 35 ++++- 2 files changed, 164 insertions(+), 17 deletions(-) diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp index 969f5fa02..8be06cf3f 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp @@ -31,19 +31,29 @@ httpClient::httpClient() { _tcp = NULL; _tcps = NULL; + + _headerKeysCount = 0; + _currentHeaders = NULL; + + _returnCode = 0; + _size = 0; } httpClient::~httpClient() { if(connected()) { _tcp->stop(); } -} + if(_currentHeaders) { + delete[] _currentHeaders; + } + _headerKeysCount = 0; +} void httpClient::begin(const char *host, uint16_t port, const char * url, bool https, const char * httpsFingerprint) { _host = host; _port = port; - _url = url; + _url = url; _https = https; _httpsFingerprint = httpsFingerprint; } @@ -63,7 +73,11 @@ bool httpClient::connected() { return false; } -bool httpClient::GET() { +/** + * send a GET request + * @return http code + */ +int httpClient::GET() { bool status; status = connect(); @@ -71,16 +85,20 @@ bool httpClient::GET() { status = sendHeader("GET"); } - return status; + if(status) { + return handleHeaderResponse(); + } + + return 0; } /** * sends a post request to the server * @param payload uint8_t * * @param size size_t - * @return status + * @return http code */ -bool httpClient::POST(uint8_t * payload, size_t size) { +int httpClient::POST(uint8_t * payload, size_t size) { bool status; status = connect(); @@ -93,10 +111,13 @@ bool httpClient::POST(uint8_t * payload, size_t size) { status = _tcp->write(&payload[0], size); } - return status; + if(status) { + return handleHeaderResponse(); + } + return 0; } -bool httpClient::POST(String payload) { +int httpClient::POST(String payload) { return POST((uint8_t *) payload.c_str(), payload.length()); } @@ -131,6 +152,56 @@ void httpClient::addHeader(const String& name, const String& value, bool first) } } +void httpClient::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { + _headerKeysCount = headerKeysCount; + if(_currentHeaders) + delete[] _currentHeaders; + _currentHeaders = new RequestArgument[_headerKeysCount]; + for(int i = 0; i < _headerKeysCount; i++) { + _currentHeaders[i].key = headerKeys[i]; + } +} + +String httpClient::header(const char* name) { + for(int i = 0; i < _headerKeysCount; ++i) { + if(_currentHeaders[i].key == name) + return _currentHeaders[i].value; + } + return String(); +} + +String httpClient::header(int i) { + if(i < _headerKeysCount) + return _currentHeaders[i].value; + return String(); +} + +String httpClient::headerName(int i) { + if(i < _headerKeysCount) + return _currentHeaders[i].key; + return String(); +} + +int httpClient::headers() { + return _headerKeysCount; +} + +bool httpClient::hasHeader(const char* name) { + for(int i = 0; i < _headerKeysCount; ++i) { + if((_currentHeaders[i].key == name) && (_currentHeaders[i].value.length() > 0)) + return true; + } + return false; +} + +/** + * size of message body / payload + * @return 0 if no info or > 0 when Content-Length is set by server + */ +size_t httpClient::getSize(void) { + return _size; +} + /** * init TCP connection and handle ssl verify if needed * @return true if connection is ok @@ -151,7 +222,6 @@ bool httpClient::connect(void) { _tcp = new WiFiClient(); } - if(!_tcp->connect(_host.c_str(), _port)) { DEBUG_HTTPCLIENT("[HTTP-Client] failed connect to %s:%u.\n", _host.c_str(), _port); return false; @@ -184,12 +254,64 @@ bool httpClient::connect(void) { * @return status */ bool httpClient::sendHeader(const char * type) { + if(!connected()) { + return false; + } String header = String(type) + " " + _url + " HTTP/1.1\r\n" "Host: " + _host + "\r\n" "User-Agent: ESP8266httpClient\r\n" - "Connection: close\r\n" + - _Headers + - "\r\n"; + "Connection: close\r\n" + _Headers + "\r\n"; return _tcp->write(header.c_str(), header.length()); } + +/** + * reads the respone from the server + * @return int http code + */ +int httpClient::handleHeaderResponse() { + + if(!connected()) { + return false; + } + + while(connected()) { + size_t len = _tcp->available(); + if(len > 0) { + String headerLine = _tcp->readStringUntil('\n'); + headerLine.trim(); // remove \r + + DEBUG_HTTPCLIENT("[HTTP][handleHeaderResponse] RX: '%s'\n", headerLine.c_str()); + + if(headerLine.startsWith("HTTP/1.")) { + _returnCode = headerLine.substring(9, headerLine.indexOf(' ', 9)).toInt(); + } else if(headerLine.indexOf(':')) { + String headerName = headerLine.substring(0, headerLine.indexOf(':')); + String headerValue = headerLine.substring(headerLine.indexOf(':') + 2); + + if(headerName.equalsIgnoreCase("Content-Length")) { + _size = headerValue.toInt(); + } + + for(size_t i = 0; i < _headerKeysCount; i++) { + if(_currentHeaders[i].key == headerName) { + _currentHeaders[i].value = headerValue; + return true; + } + } + + } + + if(headerLine == "") { + DEBUG_HTTPCLIENT("[HTTP][handleHeaderResponse] code: '%s'\n", String(_returnCode).c_str()); + if(_size) { + DEBUG_HTTPCLIENT("[HTTP][handleHeaderResponse] size: '%s'\n", String(_size).c_str()); + } + return _returnCode; + } + + } else { + delay(0); + } + } +} diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.h b/libraries/ESP8266httpClient/src/ESP8266httpClient.h index e3e34312a..1ffe8f094 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.h +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.h @@ -43,20 +43,38 @@ class httpClient { bool connected(void); - bool GET(); - bool POST(uint8_t * payload, size_t size); - bool POST(String payload); + /// request handling + int GET(); + int POST(uint8_t * payload, size_t size); + int POST(String payload); void addHeader(const String& name, const String& value, bool first = false); + /// Response handling + void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); + String header(const char* name); // get request header value by name + String header(int i); // get request header value by number + String headerName(int i); // get request header name by number + int headers(); // get header count + bool hasHeader(const char* name); // check if header exists + size_t getSize(void); + WiFiClient & getStream(void); protected: + + struct RequestArgument { + String key; + String value; + }; + + WiFiClient * _tcp; WiFiClientSecure * _tcps; + /// request handling String _host; uint16_t _port; @@ -66,10 +84,17 @@ class httpClient { String _Headers; + /// Response handling + RequestArgument* _currentHeaders; + size_t _headerKeysCount; + + int _returnCode; + size_t _size; + + bool connect(void); - bool sendHeader(const char * type); - + int handleHeaderResponse(); }; From 51660bbfa2a9787689e52c89a22ab653dd68bbdd Mon Sep 17 00:00:00 2001 From: krzychb Date: Wed, 18 Nov 2015 22:28:06 +0100 Subject: [PATCH 03/33] Initial release of Web Browser section Updated Introduction and Adruino IDE sections Updated versions of platform packages Addedd information about Digest-MD5 authentication and MD5 checksum Updated TOC Update ota_updates.md --- doc/ota_updates/ota-web-browser-form-ok.png | Bin 0 -> 29267 bytes doc/ota_updates/ota-web-browser-form.png | Bin 0 -> 38999 bytes doc/ota_updates/ota-web-path-to-binary.png | Bin 0 -> 105520 bytes .../ota-web-serial-monitor-ready.png | Bin 0 -> 41356 bytes .../ota-web-serial-monitor-reboot.png | Bin 0 -> 77643 bytes .../ota-web-show-verbose-compilation.png | Bin 0 -> 41505 bytes doc/ota_updates/ota_updates.md | 210 ++++++++++++++---- 7 files changed, 170 insertions(+), 40 deletions(-) create mode 100644 doc/ota_updates/ota-web-browser-form-ok.png create mode 100644 doc/ota_updates/ota-web-browser-form.png create mode 100644 doc/ota_updates/ota-web-path-to-binary.png create mode 100644 doc/ota_updates/ota-web-serial-monitor-ready.png create mode 100644 doc/ota_updates/ota-web-serial-monitor-reboot.png create mode 100644 doc/ota_updates/ota-web-show-verbose-compilation.png diff --git a/doc/ota_updates/ota-web-browser-form-ok.png b/doc/ota_updates/ota-web-browser-form-ok.png new file mode 100644 index 0000000000000000000000000000000000000000..ed44e9cbba449993132ab8477dd4618a0ddb04b5 GIT binary patch literal 29267 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 E1C?%a9RL6T literal 0 HcmV?d00001 diff --git a/doc/ota_updates/ota-web-browser-form.png b/doc/ota_updates/ota-web-browser-form.png new file mode 100644 index 0000000000000000000000000000000000000000..87872393f6abfe25f441fa1bce1c9b52cb1cf35c GIT binary patch literal 38999 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 !@lr1K0g%Yxu|l=W4%m!j&-c8WVkob&TkKQ zeuB;yp_@0$#jneZ#SfU-|7m`u`Va}b*5T7Bi3ZmCzq-4Vx(5?y&&5T(!Tc+BPX$a~ z#I;ox!o|T2#nsyTAhR=ee2((43;(*@_)eRRv+(e60e@pdO<3-9SI>;7tTg0~G#pLn zN3fLv&v5sMj6qJ>P2}CG#GQw21b1avrt#iAT&=0YjrvApT`EFYT)de3%~y@vq$&bg zWmTmB8e6=#Z*$mKGEWtUIj@qxN-am7;e3X5$v9QFIge6@sE4I2%d+gt72|p8q8{>Z zbDs?Ikgv2S!jwmCS645U5oJjgx0SGn=W;*1j<+jri>tD!VHw`Be7mN8)!&r(oi(N` z{ug(TaWx|u-m&tBEoLWOYgq=O4;>c22{60%?s0Psa_KI;_9uUtj@hx3!!r5e?w+Sz z>lvaCn_{crnl7&@H4lk>B|o#30iSXDG=dKuK?#Mg)z*V=R@Vu*|J!eIgChKL3J{Wi z3C_n(z}i1h{H#?pB%r6lPK6*ZD{<^oqZ}vF)Ht2b@k)L!rPLXLi39C*V$Z z^*kCNIilf?8djL{Ozvpe%B<6-k=W2oIhl?P?%oJIn~%WU3pi6*qn`?S?&fXG3X8+y z=mbpl48&49XS6gm2)-SWm%W5%`3v3E{7r1a(S=DErwqBAqzj$;M+H|%reU?7QfEq zN=b=eM8)k}3Re{FFpIP-Q8=S#jh;Iq-iSMTc2x+tC!9z{|E;^QAUq!PBagsC`#$&F zvRjxI9E$~%Fxkxyi)@|HOqRPCBc@7(uMt-&!_<(FVY(Wp>xdf9@0-!ocT4zc`P*Vy z#!2bhQKXc;r75GYUyajBrW?d5`3>sU<()mX zZyeUPW7ww2b=3OCZIXW0b?hk4Se(ZoU&rlmUkv-9gw=i*shiP0g!MHz=djt8b6iLCvelXSj}rX);~L{e0`F z@kKsfHcC_4xk5}}Ht2ZqOzxOc$J}9GWh-0oM^aAU+s!*MHzXFb!{XtRa{;TjDQ|^j zxK9m=!Tg9Ln8a|mam3w*1~L0ZKDi~JvM*i;rtv$9(@4~z$)m4RAJ+Q1bXoy5pIlbM zyn_0$kfwh2wQaPQVZHjiM(e1RQT@iMspc6t$`7u@&w}}fTSh;^(uL(ukwsW7({5S* z%vcReDa*!Xoh8fM*|u5 z$uRxzSVyD&v~O3d=iDv^?HI$pF(h-7jYO9U45}ofxD=XuNI;r302Wyjx!O~Nt7dL%1K{cLC&L;)#TOH z$9dGSSZ1H|$go&hHBIDG%c}88ojSEIug|ZfYx*kl>%+1y+IW(t-*TO9ik}LLI>{Gd z_Brk5P0Dvu__uCST}m9MiFC2dKBp_;3Yo5MFOeqltMR<7l@cfFk<+Mj`9)Z!87y-; zwZmb3Uu3+HuACA_KCjnJ-8yobQci?b>C3D2$~^jb5f*JLY05gv^;5<1oX1F9p3CX# zCtuXfY0`h8byTG+tM!U?6U$0Du3OD3+EMbePtxU4;?=(B(u6p_R%#xtl=8yovNFE? zI;v$U5APF>6hj4s>JEaXxD?K!WhRfbkHh^nKRF%QmG{UN9q=7kY+> zV_gXwb4SlF!?12y)JtNYR7r3@bUZ~`?gV$X+&hH(1cLhlYe!U5q4Vc2&@ILVF{e{6 zzU?rK<2N*_X;PXrOUg>*X2>dx;*;!^!?DMYnSzT^<`Mb z>tmeG`qAqs^qlJ`(iMq1WZ2X?8my}-uE(fv9ZTjj=({dWpRP;O=F_dCKF&D5kWt+x z*HH;~xQ@nUMEtYcGS-h;M^58qAtj&iwPiG6%4e{S9r;Ew?9UIVgF3h$KV}_;cv%}~ zaNM$#WhI}uhi63@pebE`}I5iWSXgC;Gb1|j`Bz3 z&F?X$gMPNFSf0VNqX6)`5?)FCl$YJ1Lx*tho_YA{U%~OdZfR+G<}qO^?pa||`k}n0(%ILB z`FjFv!ShEX%q2W!kvdBl9Q9gJIVP4 z^?bmy)G&Vqy!GCF`QGve4{)zlpWaG!-n-YT$=lpvnEj5zFP@kBM19e|Po3Y~)=KHE z_wS4E#kRKI!~Odm_szIoK8fPvfK21!XtO7G3?*X*R_zLPBXI7~N&``H@|_i#)lxQ}r1 z!t~wGhC3fLJl@P-CNWeq0lgJBi%ucR&ldq9M{udUjt*Qt=o(Naem;8(jdT#VFZ*+e z4*YwyC`vqnut0zK`LX;E6cUbWHFYRBb{0itcTjcxGR~bTMSbh@^^GqO{8>H&xIev% zlGIF;Yd(O`)_4o0SBvGhFrUk{p*SNE3CHtLeEtfq-nffLEq73K_O|lP)F0#SqcrC_ zYFgTq@28sGi#oR4c`V!TIJk@E);g4=9mk~`HR5Yt{AI7k`YK#Ln}X7sduYDfXjH~f zT&Av~7#H$#P}R^v%kA^DumM8n5PxIgu2GsPah?1wl4Hk?DZMwlU$c{zJHcI8?uX!T z)(GySeZw&&I2Oa4JPGdmp9yz9XxKX7Pe}0xU|IZCqL$`*oC!OKRf|_*!_uW#wqP#C z&9lVe!aKP4;0~hJY{bgd$5GSPBFj*DwGQL3u3i)27s^}Tf(N(?%isMk^clSf%a$w> zAHiO>YCZBRt8vUB1{sAF$o1ckY5fCn3-{2}@WXBJ#VsZ##t`n0&tdBS^AZN{NY#B6 zsp^y+HZGrs(&zjl(B13<7&CSVHtmZ++M!d($gV~G`CyFi;*KgM&x^Zju;^}qh=N)( z+<&CwyEGn>RF46vW;(WRz^>Epu{HEES?UCKGA8OObFh2FtDq=6q;o=h92tfi>Edu7 zS5vI9cFs7Qy8|>g$^5FCTghNJ6^O7yX$1dPDr;PaUTPfs{NgI}u*|=PQ!RI%DKkC% zaC^&r6v2IRa14eydSKcQ!2RgaqvH0DZ&OwAfm(Sv5f&pSAUvlQZBL%yDOs`!dnRL? zr7volY7n>83LCeiqW1B9Do<7p9jKygBUu~Dtz}aa9iUt%)h8??jwfq|Kl{gDKGMZe zc^TJHUZrn!cL~>5u=lk;!!xg$;Pyn!B6!r+Miy2B?zP<~KsO;b$PV+zgyH66y6`lZ z=#P>3;?@rCPtIfWfBawg@6VUP??R)9x|8LGoffN5_MC9P1ocjC~c_Fu<0yXSL!m&V_#G&m0Gn$Y_623$UQ8@nTmg_T}U$4>3-T-Z+O zfvC$*asO^Tn)p~(j?cSvJc+V&j5ghECZp#8Zk#-bt;=R2ullJte$`{InJn)-|6M^)a-u!j^X|l!F@(3!JRC3$FmoV;O-NF$w3nC zQ+IU?ceY*<5)$O?q%!SFOueE5>RjYLjGGjQ>PPobFQ$yq!B%@meChk{-Acq;Zo&Ks zi!pQfyLj!RZ?G?_0FC#Wapi~;M)r9Zo!|Hn^Y+BzW(^&@H_pL%`_;&`I970r09`Mqt<};Ah!X61 z^-r+y%S3ioCQhZN<3edQ9^Nm+&hISXd;BtTL+vqtbO>%z?(0XKG5YiF==^$5EZQGO z{i)Zzt65!V9^Z_LiZX!v)3$uVv2ypzGjHw0`=i37MYj(eK^2@jLYM@kv`f(%sggZ@0JbVV{ZcKYfex zmSRh4QaBUbcM;t0lGR;X z*MOQ^XJJinrzqUJbr>_=o`a2+WAW}g-7tDnFv{rot}i|XtI6Nsjjmr{=Bk-ky=*?t zS2y95+Xj65QFpxh#vAx@ybUr7j$me&|1bXIzy5?hM@rCASp?rrQ}N*&ui&$9=O8@u zI$by#49`UZ{EZto%$EDVh&!pmU0Ch}_Z)(|`mqj%`v{+KObUv{PzMi8`2n~eIdVi; z2W-XjGOLzAp5|wPk1dnY(%Og`imR!iv>FC%9a$JvIJA8NzWm+-#Vt=!e%uz5ht9?M zYbP+Q$2i1ZXVbO{j$^;T;?P`#ZJUQ_Yr@b>Y`U6ghv5?~kaNNbuk~Dm;s=k=lII2M zs5CS+l;Pm2xmaSGA-?`!o#c!;ORbQ5s}Xh7znVLAYx}qeyI=l2x_#OY-+kK;{l4yt zEwPvI@IfJVe7z1H$BJ+^#13=EMB~ogL=5|EHcr&@9QHN@%^rb`@t4WUmoMN~*O@PF z5fKqaaL>c`*LvV|Qxm)dv?ox71{kD){Nq2>`~ZYsd?A;aKbVmMd6 z#A7T0^#WP$&4^yH7q;FC+K+#bfjGYlcy&~6q8J5!)AhW3wmY;OT%CIXOi^OH$!@~P4wfyUIe3!=K z*y`~vj)Uqt+-QG%yaG(4x!U|~<-i*WWKfHmJp;ze&SqtxZ z{jen91iUsaz*6fJI>K6T*z#L^J$NxLmR*FyDi?@D;$a1LeepVMa;lMSO}1cbLb7io`!YOO8W*B3B)A#+= z`#yi)&-0wmea^X`&vTt~T}O$;%?!K3uw={o(jqcWtZ&=%s*89s?9GjYR1<$jJ-?&Y zA0X+KQ&}&kR)U*i3@$s*KmOw$Dbiv@EpJ5~u0qE`YA-dnjHkR60BVKKkRZw`+cYVs z=Zlv(lw@fjd~)By0eWmWo~fsqC5JnHr005Co(qY7yDZ-AAE;-?DQp+NfBceI2j!b( zf#z*NU0gMT_P9G5Cs?>3;{(YVMsm}$C8uXM9>Y7RE=0!re3n${&e|By44#K$&uJPG zY3l6m8FZjmH@9#nvs<&}loz;m)a%c{ycPY>ib~B%!G>=DyexeDcDmKg^0ek}`+J=~ zf6a{n4LYJ^`Q>vIR;7j;0@k{%catS?Cj({(x;uyfaBMb&=f0a@LDSol4ezgYb#-VU zxS96KF7ISaJhZiIB-IyAODSKgb(utN+Do1yYROPmu+Qh3ld#FK;{dB7LqD?E*!O5z zd-RbSd^40aDXZN(@E{U1QI3FMk?j{8*de~dBDV;`TF(9 zKf8}m@J%!hy6)0r6vFq)3c9*YrWHKi*8%+`O4ZVT%uIHOPaQfO>KGtZ%ZfB<9Y+fFW+vXq|9O$Kur)qIZ*g9nxK&#}J^5AMDhkCGlU zysB13>#xlk-#)dY(p+(KJmTwd3X{?C)#?vVa*k%M=ht{Kje{k$B?g1JcEY{gnqxQUs1e1@BNJLJRo~{ zYxck`<=#*W7w)p$2%J={R3hW+zJDTc z83njP>c0V1Sy?&QEX!=J;wf)blQ#Wa2NJ87B$|wf;pf^nG<}x*I%%)FsT!6! z392)fx~$~zqFZ@_;e&6zi#sTcv=)V(lA%&j_zK%uQI%WvxEE?GaJ@P|A*@OUF3}xR z`fD?dt&ZjZtUYs{`=(y*fujs=z@7$1@2D;)L|7cswboj;^ktXL- z@uJmiDClsL?B_e3ZjiZsGxJk&%--QN*2y4?yCv{DDS>RgPUf@ekEd2Tz#^RXRpgRd zVv3Wyw$Yg5DarCkv}lRtsmQgQpW3y9>@7h8=dJrB3%ovdH+n-w)-t6rBi6=svzt;f z0xc`MR=ENUDF*^yoK&-T+BH{k72Q6062AN#D#TgOl2dCAhcY3}YP=sl5c?yV$+K%S z){yDCbJ$hS_txnFS2p)zYz!X!ti6I%C5NrgE!c;3KLBXn?<+|F|_Q3 z2(g{y#7^x{x^!GiLe=VN`Fh{7%0F03oHYsg{FRIgG8V4=oSJvpYj8j_xbD^1a|dUr z?UdQNEmu}pQ`ObIYba%I{p@vU46}K|)<2$;>h+8Amo=+PpBSb_%9d}Nj}PA+(o-iK zIquCVV+YBrV~p8Yv;p1@ zf;CcDYM3#}5^&#q^tizJG9rwLJaEzGtXR5^S|d`$Z-dIZnPkL__g;`OPrN~p-N}z$ z#n4Yz<;i00KKor-ySFEG@~QrCs4KqFT16@p{*pLBtJevyI%=_+L|dLe;RRR5>OlV) z{z@w7q*z>sl-F1G=sW(%wZeCmCcqWkdtdBF#?0#!*m6y4w%hmy z?)kImpMySiSYOWkHQLlw2&FLvdGWb7Gn(;Q_y*-U6FX=8{v^&`=R9cY`_MZp0Pi{- zH8nG%=~GP8ElM^5UWVc6&29@1v3_(4C=x9xQI#yDCp#Kr;J93wnCcKZ-IH zl^E%L%l5XL)D0@QGSUQeY&FKmv;l#n-jzX9?` z%+?)i#LWQs;evvKPfYI*M*rks0u-04^zVvTN!k1$RiuddM|_S?g)OO15w~9Pq5@X% zhJy|_xy#W#!s5L;X0Ggd^In5)8nS_N5+)fNU`~gYz;YuP3R9-EbdI^}$uFcQs8Gw{ z%e8o}EGYYWK8`MtTY*eRVo3{>DCopcL^&Hqg`Gd>c_WY+6~?K@YM8$Fc1)uS&~ zMwTgFx+9ZM1?eTNbUvxM^t{6=R;78mH4sWoTc+2Op{)na&m7ly4_}VGZ6_L|5g+vT|8H z@ij9=V@;wHRduws%6zJ+TWw|Dn6N}_}wU^2s%A-^p5rL?*_qu2b#d5D_1`CSQXHm z9&~HZoaAx*V2+poF=LkpSy?W_^)%RsMbTR~EvZ8ChG*z>>9ez0?tF4JobB=P+J!>Q zN3>OWeAik~Szj#mzimjLT5gzJusy>!%Ydi%^BN?Kw1uB7nHcOB+)PVZ_gbo9^QJ#( zCikz@847OSNp@+hDWhRk$PD}d*l_eEota^tYsL!^D3+XlNhM)9PCQH|JR~vAiD#yo zkXd?%pnC21SrauP0C?i6r+>FKJ1?)qV0}^w+3k?VQlrs~Rr{X|Tx2275mj0P1BQv< zP%fDrE?_niJ+~z))_xZzULX<>=%ia67Anl8Yhv(Jub|>x%UkioN(*K1R!FgZW6VxX zmmU#&E@JmH0fa8`cr#>Va`GO~VRf@5a(^cm2eMNE+4EyX@i9$OtW}G$xZsL)ayV}< z#|BsUf%|jNZ%u(=;O4gJ4oOYS{DJ7dxE-OeW1-I5+5;PVBm*ZSB^~{ZkkJM3!e)56 zEMBbptsc?9JFZ3t@g3Z=7`O#5ZT+5n9N z2D#-@4z8P^-_zM0T$jUeTHQ>0eQ$1&AI|9-QY`!96ny}AdOq4aJ3C8<0W-66bBo6~ zKIWn2dB~7vQqod#4RTxax&{P$YWCzw8i)Grc0jj%D`vqaj{0tW&V#J>Y9xClDbf); zc8f`{qaXD(Jd&f^-XNCP627FW8^!3)reWgn(bl8G8+$PHiJqVq)NH%nv2e(^;aDX3 z@;sUIx4A_Ar!-wTFZ-a3->C2VzG_uA_c>(wn?AfNNRG<+UqP&5tL#(#>x70@_+QM-Ltt0a?Ajkrx99VTVg3uYdH zn_DsG{uWxL8IGH+x!~C2jITwj*zUC~{e_W9x%=^&5xAT%(M0ORfeUfLR*c$K%3a=G ztX(b3pcI@hhZupx0;UsY97ztJ^%!s=JV>NT?Cq)wsah!O!&`86{T?+E5nQB}%+cwQ z&58WIm{{<G>J@Y$dC{+YI&gN+=zaHdBsa^)hrQSz*vvSgN*GEtyaL;4R^U9>C> zM*tcx_lF8fsfMiix?9$BtJ&#oKBZ68V>HId<6Ntmp##ZaSPzb74n& zxe!cnjd@2MAVlVmA;01GB~y<+n+Ti@f@*K{%k3zf2znWNW^+k>`5_Qt_g^bM0{MQh z#@r-xq8U2a!9ZroK|G&$+K#?(rcfV+8k1D6r^=06G#I|x&VKe0`m9vuA54U67Wi0==gB%6~ zI}cDq1T%G=&<)I_JD&gzgj+Fn{+g1Me8+R1Nq6%`v;Jp;5f&{Zh}O%iTq#WM4@ZcF z4HAWros}fy-@viUr@_=xBLOUMh4KQTi2)Hf5ps+tQ8TXRx~?poI5~sJWe1T+M6X;7 zey86e#(NjCcP`@*(5(C(QLTGFU_b|Lz18NYLE+v6HU4wM#dbj$?#&5ySojj)%}Ez3 zYVf7Tlb1YJ=+7&HDw4jot(NWz|Ldw+$!D>W)X1WC3fulTan05MVro4A9&|YJo#p)r z+yr7e%u*o%+{YrVl-K&yqF0t*AnqPF{n9GG6-

q(U-gl>R4biBY~|)X;z$UTfZ3 z--}(A2sh7uX+efra|?7!kzIzI^r+-vR)hao3t}cBgh!>#TY5mko=q4(Je{?*ySxXl z^4|se(ZQ0=0OGvrq1+fC*asr}YA$f4`fKplzncw}h7(#`=wB(Ft{6KL8497+pp<00Qm;XOlkjiHzVg3zD}Q5UjP9QgF!IKYL3H93sbbOTl?UP$d2MoWYlW zy_3D|3k(oyRXMXgtv9x41q_U+@K7N=1Ham_pH=^N)rt_@Y+X=??=q4i3-|Q=>o7^d z&`WUU%0<%O45oqs3BMwyvEP=t)P`OiFd=K7?PUSMSi>8x|DH_F{)8$CrCqw-P}bfh z7!{I$RuKZ+7y$Usm9X@O=H2c>yofydWM*h+81`#(Jny%FL+*(|MFRVnptK;1WNl+# zEQ5MrQB%J2h&$pgkg)H?oSGG`fcd<_^F6PfTk6~3<2GJq9kDWEO&v8Ahf2w&U+JFam*gn=q|PDdm5iVN;O??Y%_a6XD( z!_e=j|GTD$l;ix%2wbe%;Yo$Gc?R$bcyaqRqfBM*VA0bN&>YH8<%(nve`jmMcsdV9%(^TQE8k!j10s5tZN`@2V$3BHKKC zUBPfpPqVM`W)8016*A3$XRd8+2W5>F_>bZ{2!{psbZo~54+*VMXT7aEu4jyos>h?Q z`xOsOF?MFG-%0z@e{vROOX{&n-SjmGoXn2X6Pv_66rs1IYc0)WwlB0ql8iIe#~(d5 zluKJEdW# z&Yd^)$uYKMhqy5-TQ26vgHVA(w7OYG%ShavgRpM%`aM)OkGRSWU6u3Pkfj) zFb|%gYhbCF88T&WW!)Kju?4)?Nw}nP?VkUjTQI}gNoP%9W0ujfXY**{bIUO)JN@VJGd6P zU~)g=hj;A6Mgkhp@8v5(cVJxaXDa}b2j0Dahv4~8Ca}{4nlLE~-5wYIpk6a;4tAUX zc}cRL>y<}RTyb>CyNGVtFM6Ruh|^xo$9#l)-N)4~bs0H8v;Ey|Jsh_=C-p7Oaf@!U zZU9)RDp&{~w?mws_seW&bEJv4_PcWD-Q6#nG({>QyeK8~DE@+b$5lw3p$RsOW9Y)p z317-fDYKg~YFGe-Mz5&b3s|33GFpQPp?kilp1u{A#|cU?FD7)PZ{K7#7EIFeHvUq? zof|g9%p-dKAolH5(43*I1y7&Dk%;m6kJo~w1ux!jPyI~X5*kfZOMd1JlNM3u^kMv9 zv%Ja@Z$vMLh+MC*34eE7 znygSmrtdXg%;i;A;hrzZ`)s4L9YeU^sv@WMtG`TLd_&3_<4jmLpJI3*DzS1Z>X#=! zf+s%~O+GM=dLtEmrv91Cd%-7RC-02TJFg6i&*jal!oG_0t;uddU0vAR#}qgbw$aSe z&0h2OlWMYzIp*i(l`sz^I7H_!dFxmEPpQ$;{f7if^YC9Bx%?o+CF1o^TVJc@o=wF60T4zVi~s-t literal 0 HcmV?d00001 diff --git a/doc/ota_updates/ota-web-path-to-binary.png b/doc/ota_updates/ota-web-path-to-binary.png new file mode 100644 index 0000000000000000000000000000000000000000..9237d878055659799ea0320533f25f79740e2574 GIT binary patch literal 105520 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 literal 0 HcmV?d00001 diff --git a/doc/ota_updates/ota-web-serial-monitor-ready.png b/doc/ota_updates/ota-web-serial-monitor-ready.png new file mode 100644 index 0000000000000000000000000000000000000000..5ce011170c9f77b04a52ee42fe7ef69b2db1668c GIT binary patch literal 41356 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%0DNJxIg4epxx* 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%0Dl|sJE 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 literal 0 HcmV?d00001 diff --git a/doc/ota_updates/ota-web-serial-monitor-reboot.png b/doc/ota_updates/ota-web-serial-monitor-reboot.png new file mode 100644 index 0000000000000000000000000000000000000000..0fd469e11614fb75d42f223b21974b7d404e5c23 GIT binary patch literal 77643 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
6^VknA8oCr^sfB(6Smgtd&e_;s)%xe6 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 b^!p_1Pegk23#WPR0EfED6Xo*9mLdNST;>JB literal 0 HcmV?d00001 diff --git a/doc/ota_updates/ota_updates.md b/doc/ota_updates/ota_updates.md index 09916e27f..bac75e9ec 100644 --- a/doc/ota_updates/ota_updates.md +++ b/doc/ota_updates/ota_updates.md @@ -3,26 +3,43 @@ title: OTA Update --- ## Table of Contents - * [Basic Requirements](#basic-requirements) - * [Arduino IDE](#arduino-ide) - * [HTTP Server](#http-server) - * [Stream Interface](#stream-interface) +* [Introduction](#introduction) + * [Security](#security) + * [Safety](#safety) + * [Basic Requirements](#basic-requirements) +* [Arduino IDE](#arduino-ide) + * [Requirements](#requirements) + * [Application Example](#application-example) + * [Classic OTA](#classic-ota) + * [ArduinoOTA](#arduinoota) +* [Web Browser](#web-browser) + * [Requirements](#requirements-1) + * [Implementation Overview](#implementation-overview) + * [Application Example](#application-example-1) +* [HTTP Server](#http-server) +* [Stream Interface](#stream-interface) +* [Updater class](#updater-class) + ## Introduction -OTA (Over the Air) update is the process of loading the firmware to ESP module using WiFi connection rather that a serial port. Such functionality became extremely useful in case of limited or no physical access to the module. +OTA (Over the Air) update is the process of loading the firmware to ESP module using Wi-Fi connection rather that a serial port. Such functionality became extremely useful in case of limited or no physical access to the module. -OTA may be done from: - - [Arduino IDE](#arduino-ide) - - [HTTP server](#http-server) +OTA may be done using: +* [Arduino IDE](#arduino-ide) +* [Web Browser](#web-browser) +* [HTTP Server](#http-server) -In any case first firmware upload have to be done over a serial port. If OTA routines are correctly implemented in sketch, then all subsequent uploads may be done over the air. +Arduino IDE option is intended primarily for software development phase. The two other options would be more useful after deployment, to provide module with application updates manually with a web browser or automatically using a http server. + +In any case first firmware upload have to be done over a serial port. If OTA routines are correctly implemented in a sketch, then all subsequent uploads may be done over the air. + +There is no imposed security on OTA process from being hacked. It is up to developer to ensure that updates are allowed only from legitimate / trusted source. Once update is complete, module restarts and new code is executed. Developer should ensure that application running on module is shut down and restarted in a safe manner. Chapters below provide additional information regarding security and safety of OTA process. -There is no imposed security on OTA process from being hacked. It is up to developer to ensure that updates are allowed only from legitimate / trusted source. Once update is complete module restarts and new code is executed. Developer should ensure that application running on module is shut down and restarted in safe manner. Chapters below provide additinal information regarding security and safety of OTA process. ### Security -Module has to be exposed wirelessly to get it updated with a new code. That poses chances of module being violently hacked and loaded with some other firmware. To reduce likelihood of being hacked consider protecting your uploads with a password, selecting certain OTA port, etc. +Module has to be exposed wirelessly to get it updated with a new sketch. That poses chances of module being violently hacked and loaded with some other code. To reduce likelihood of being hacked consider protecting your uploads with a password, selecting certain OTA port, etc. Check functionality provided with [ArduinoOTA](https://github.com/esp8266/Arduino/tree/master/libraries/ArduinoOTA) library that may improve security: ```cpp @@ -30,7 +47,10 @@ void setPort(uint16_t port); void setHostname(const char *hostname); void setPassword(const char *password); ``` -If possible implement other means of protection from being hacked, e.g. exposing module for uploads only according to specific schedule, trigger OTA only be user pressing dedicated “Update” button, etc. +Certain protection functionality is already built in and do not require any additional coding by developer. [ArduinoOTA](https://github.com/esp8266/Arduino/tree/master/libraries/ArduinoOTA) and espota.py use [Digest-MD5](https://en.wikipedia.org/wiki/Digest_access_authentication) to authenticate upload. Integrity of transferred data is verified on ESP side using [MD5](https://en.wikipedia.org/wiki/MD5) checksum. + +Make your own risk analysis and depending on application decide what library functions to implement. If required consider implementation of other means of protection from being hacked, e.g. exposing module for uploads only according to specific schedule, trigger OTA only be user pressing dedicated “Update” button, etc. + ### Safety @@ -46,14 +66,14 @@ void onProgress(OTA_CALLBACK_PROGRESS(fn)); void onError(OTA_CALLBACK_ERROR (fn)); ``` -The following chapters provide more details and specific methods of doing OTA. - - -## Basic Requirements +### Basic Requirements - Flash chip size is 2x the size of the sketch. +The following chapters provide more details and specific methods of doing OTA. + + ## Arduino IDE Uploading modules wirelessly from Arduino IDE is intended for the following typical scenarios: @@ -61,75 +81,175 @@ Uploading modules wirelessly from Arduino IDE is intended for the following typi - for updating small quantity of modules - only if modules are available on the same network as the computer with Arduino IDE -#### Requirements + +### Requirements - The ESP and the computer must be connected to the same network. -#### Let's Do It + +### Application Example Currently there are two software configurations that support OTA updates -- [Classic OTA](#classic-ota-configuration): Arduino IDE 1.6.5 and [stable](https://github.com/esp8266/Arduino#staging-version-) (July 23, 2015) or [staging](https://github.com/esp8266/Arduino#staging-version-) (Sep 30, 2015) platform package that provides first OTA implementation, yet without support for [ArduinoOTA](https://github.com/esp8266/Arduino/tree/master/libraries/ArduinoOTA) library. This particular configuration is intended for less experienced users. It soon will be depreciated once implementation below is fully released. +- [Classic OTA](#classic-ota-configuration): Arduino IDE 1.6.5 and 1.6.5-947-g39819f0 (of July 23, 2015) or 1.6.5-1160-gef26c5f (of Sep 30, 2015) version of platform package that provides first OTA implementation, yet without support for [ArduinoOTA](https://github.com/esp8266/Arduino/tree/master/libraries/ArduinoOTA) library. This particular configuration is easier to configure in Arduino IDE and therefore suggested for less experienced users. It soon will be depreciated once implementation below is fully released. - [ArduinoOTA](#arduinoota-configuration): Arduino-PR-4107-BUILD-421 and latest git version of platform package that includes [ArduinoOTA](https://github.com/esp8266/Arduino/tree/master/libraries/ArduinoOTA) library. This configuration features preliminary build of Arduino IDE and is intended for more experienced users. Please mid your step. -Instructions below demonstrate how to configure both [Classic OTA](#classic-ota-configuration) and [ArduinoOTA](#arduinoota-configuration) using NodeMCU 1.0 board with ESP-12E. +Instructions below demonstrate how to configure both [Classic OTA](#classic-ota-configuration) and [ArduinoOTA](#arduinoota-configuration) using NodeMCU 1.0 (ESP-12E Module) board. -##### Classic OTA Configuration + +#### Classic OTA 1. Before you begin, please make sure that you have the following installed: - - Arduino IDE and ESP8266 board support as described under https://github.com/esp8266/Arduino#installing-with-boards-manager - - [Python](https://www.python.org/) 2.7.10 (do not install Python 3.5.0 that is not supported): + - Arduino IDE and ESP8266 board support as described under https://github.com/esp8266/Arduino#installing-with-boards-manager + - [Python](https://www.python.org/) 2.7 (do not install Python 3.5 that is not supported): - **Note:** Windows users should select “Add python.exe to Path” (see below – this option is not selected by default) + **Note:** Windows users should select “Add python.exe to Path” (see below – this option is not selected by default). ![Python installation set up](ota-ide-python-configuration.png) 2. Now prepare the sketch and configuration for the upload over a serial port. - - Start Arduino IDE and load sketch DNS_SD_Arduino_OTA.ino available under File > Examples > ESP8266mDNS + - Start Arduino IDE and load sketch DNS_SD_Arduino_OTA.ino available under File > Examples > ESP8266mDNS ![OTA sketch selection](ota-ide-sketch-selection.png) - **Note:** This sketch is available only for stable (July 23, 2015) and staging (Sep 30, 2015) releases installed in Arduino IDE using https://github.com/esp8266/Arduino#installing-with-boards-manager. It was removed in [#980](https://github.com/esp8266/Arduino/pull/980) from Github repository. + **Note:** This sketch is available only for 1.6.5-947-g39819f0 (of July 23, 2015) and 1.6.5-1160-gef26c5f (of Sep 30, 2015) versions of platform packages installed in Arduino IDE using https://github.com/esp8266/Arduino#installing-with-boards-manager. It was removed in [#980](https://github.com/esp8266/Arduino/pull/980) from GitHub repository. - - Update ssid and pass in the sketch so the module can join your WiFi network + - Update ssid and pass in the sketch so the module can join your Wi-Fi network ![ssid and pass entry](ota-ide-ssid-pass-entry.png) - - Configure upload parameters as below (you may need to adjust configuration if you are using a different module): + - Configure upload parameters as below (you may need to adjust configuration if you are using a different module): ![configuration of serial upload](ota-ide-serial-upload-configuration.png) -3. Upload the sketch (Ctrl+U). Once done open Serial Monitor (Ctrl+Shift+M) and check if the module has joined your WiFi network. +3. Upload the sketch (Ctrl+U). Once done open Serial Monitor (Ctrl+Shift+M) and check if module has joined your Wi-Fi network. - ![check if module joined network](ota-ide-module-joined-wifi.png) + ![check if module joined network](ota-ide-module-joined-wifi.png) 4. Only if module is connected to network, after a couple of seconds, the esp8266-ota port will show up in Arduino IDE: - ![selection og OTA port](ota-ide-ota-port-selection.png) + ![selection og OTA port](ota-ide-ota-port-selection.png) 5. Now get ready for your first OTA upload by changing configuration settings as follows: - ![configuration of OTA upload](ota-ide-ota-upload-configuration.png) + ![configuration of OTA upload](ota-ide-ota-upload-configuration.png) - **Note:** If you do not see “Upload Using: OTA” option available for “NodeMCU 1.0 (ESP-12E Module)” board, please upload the latest [boards.txt](https://github.com/esp8266/Arduino/blob/master/boards.txt) file from Github repository, replace existing file and restart Arduino IDE. + **Note:** If you do not see “Upload Using: OTA” option available for “NodeMCU 1.0 (ESP-12E Module)” board, please upload the latest [boards.txt](https://github.com/esp8266/Arduino/blob/master/boards.txt) file from GitHub repository, replace existing file and restart Arduino IDE. 6. If you have successfully completed all the above steps, you can upload (Ctrl+U) the same (or any other) sketch over OTA: - ![OTA upload complete](ota-ide-ota-upload-complete.png) + ![OTA upload complete](ota-ide-ota-upload-complete.png) **Note** To be able to upload your sketch over and over again using OTA, you need to embed OTA routines inside. Please use DNS_SD_Arduino_OTA.ino as an example. -##### ArduinoOTA Configuration -1. Get the following software: - - Arduino-PR-4107-BUILD-421 - https://github.com/esp8266/Arduino/pull/984#issuecomment-155905800 - - Latest git version of pacakge - https://github.com/esp8266/Arduino#using-git-version- - - Python 2.7.10 +#### ArduinoOTA -2. Proceed to step 2 under [Classic OTA Configuration](#classic-ota-configuration) using BasicOTA.ino or OTALeds.ino skech instead. +1. Upload and install the following software: + - Arduino-PR-4107-BUILD-421 - https://github.com/esp8266/Arduino/pull/984#issuecomment-155905800 + - Latest git version of platform package - https://github.com/esp8266/Arduino#using-git-version- + - Python 2.7 + +2. Proceed to step 2 under [Classic OTA Configuration](#classic-ota-configuration) using BasicOTA.ino or OTALeds.ino sketch instead. 3. Carry on with remaining steps. +## Web Browser + +Updates described in this chapter are done with a web browser that can be useful in the following typical scenarios: +- after application deployment if loading directly from Arduino IDE is inconvenient or not possible +- after deployment if user is unable to expose module for OTA from external update server +- to provide updates after deployment to small quantity of modules when setting an update server is not practicable + + +### Requirements + +- The ESP and the computer must be connected to the same network. + + +### Implementation Overview + +Updates with a web browswer are implemented using ```ESP8266HTTPUpdateServer``` class together with ```ESP8266WebServer``` and ```ESP8266mDNS``` classes. The following code is required to get it work: + +setup() + +```cpp + MDNS.begin(host); + + httpUpdater.setup(&httpServer); + httpServer.begin(); + + MDNS.addService("http", "tcp", 80); +``` + +loop() + +```cpp + httpServer.handleClient(); +``` + + +### Application Example + +The sample implementation provided below has been done using: + +- example sketch WebUpdater.ino available in ESP8266HTTPUpdateServer library +- NodeMCU 1.0 (ESP-12E Module) + +You can use another module if it meets “Flash chip size is 2x the size of the sketch” requirement. + + +1. Before you begin, please make sure that you have the following software installed: + + - Arduino IDE and 2.0.0-rc1 (of Nov 17, 2015) version of platform package as described under https://github.com/esp8266/Arduino#installing-with-boards-manager + - Host software depending on O/S you use: + 1. Avahi http://avahi.org/ for Linux + 2. Bonjour http://www.apple.com/support/bonjour/ for Windows + 3. Mac OSX and iOS - support is already built in / no any extra s/w is required + +2. Prepare the sketch and configuration for initial upload with a serial port. + - Start Arduino IDE and load sketch WebUpdater.ino available under File > Examples > ESP8266HTTPUpdateServer. + - Update ssid and pass in the sketch so the module can join your Wi-Fi network. + - Open File > Preferences, look for “Show verbose output during:” and check out “compilation” option. + + ![Preferences - enablig verbose output during compilation](ota-web-show-verbose-compilation.png) + + **Note:** This setting will be required in step 5 below. You can uncheck this setting it afterwards. + +3. Upload sketch (Ctrl+U). Once done open Serial Monitor (Ctrl+Shift+M) and check if you see the following message displayed, that contains url for OTA update. + + ![Serial Monitor - after first load using serial](ota-web-serial-monitor-ready.png) + + **Note:** Such message will be shown only after module successfully joins network and is ready for an OTA upload: + +4. Now open web browser and enter the url provided on Serial Monitor, i.e. http://esp8266-webupdate.local/update. Once entered, browser should display a form like below that has been served by your module. The form invites you to choose a file for update. + + ![OTA update form in web browser](ota-web-browser-form.png) + + **Note:** If entering “http://esp8266-webupdate.local/update” does not work, try replacing “esp8266-webupdate” with module’s IP address. For example, if your module IP is “192.168.1.100” then url should be “http://192.168.1.100/update”. This workaround is useful in case the host software installed in step 2 does not work. If still nothing works and there are no clues on Serial Monitor, try to diagnose issue by opening provided url in Google Chrome, pressing F12 and checking contents of “Console” and “Network” tabs. Chrome provides some advanced logging on these tabs. + + +5. To obtain the file navigate to directory used by Arduino IDE to store results of compilation. You can check the path to this file in compilation log shown in IDE debug window as marked below. + + ![Compilation complete - path to binary file](ota-web-path-to-binary.png) + +6. Now press “Choose File” in web browser, go to directory identified in step 5 above, find the file “WebUpdater.cpp.bin” and upload it. If upload is successful you will see “OK” on web browser like below. + + ![OTA update complete](ota-web-browser-form-ok.png) + + Module will reboot that should be visible on Serial Monitor: + + ![Serial Monitor - after OTA update](ota-web-serial-monitor-reboot.png) + +Just after reboot you should see exactly the same message “HTTPUpdateServer ready! Open http:// esp8266-webupdate.local /update in your browser” like in step 3. This is because module has been loaded again with the same code – first using serial port, and then using OTA. + +Once you are comfortable with this procedure go ahead and modify WebUpdater.ino sketch to print some additional messages, compile it, locate new binary file and upload it using web browser to see entered changes on a Serial Monitor. + +You can also add OTA routines to your own sketch following guidelines in [Implementation Overview](#implementation-overview) above. If this is done correctly you should be always able to upload new sketch over the previous one using a web browser. + +In case OTA update fails dead after entering modifications in your sketch, you can always recover module by loading it over a serial port. Then diagnose the issue with sketch using Serial Monitor. Once the issue is fixed try OTA again. + + ## HTTP Server ```ESPhttpUpdate``` class can check for updates and download a binary file from HTTP web server. @@ -261,6 +381,16 @@ header($_SERVER["SERVER_PROTOCOL"].' 500 no version for ESP MAC', true, 500); ``` +## Stream Interface + +TODO describe Stream Interface + +The Stream Interface is the base for all other update modes like OTA, http Server / client. + + ## Updater class TODO describe Updater class + +Updater is in the Core and deals with writing the firmware to the flash, checking its integrity and telling the bootloader to load the new firmware on the next boot. + From d2982d3555eed0c9922d3eca763ec4f46c6ad0c1 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Thu, 19 Nov 2015 22:49:40 +0200 Subject: [PATCH 04/33] Make ArduinoOTA AUTH async still up to the user to call ArduinoOTA.handle() to start the upload --- libraries/ArduinoOTA/ArduinoOTA.cpp | 233 +++++++++++++++++----------- libraries/ArduinoOTA/ArduinoOTA.h | 10 +- 2 files changed, 147 insertions(+), 96 deletions(-) diff --git a/libraries/ArduinoOTA/ArduinoOTA.cpp b/libraries/ArduinoOTA/ArduinoOTA.cpp index 744c208cc..ed2421a8d 100644 --- a/libraries/ArduinoOTA/ArduinoOTA.cpp +++ b/libraries/ArduinoOTA/ArduinoOTA.cpp @@ -1,9 +1,23 @@ -#include -#include +#define LWIP_OPEN_SRC +#include #include #include "ArduinoOTA.h" #include "MD5Builder.h" +extern "C" { + #include "osapi.h" + #include "ets_sys.h" + #include "user_interface.h" +} + +#include "lwip/opt.h" +#include "lwip/udp.h" +#include "lwip/inet.h" +#include "lwip/igmp.h" +#include "lwip/mem.h" +#include "include/UdpContext.h" +#include + //#define OTA_DEBUG 1 ArduinoOTAClass::ArduinoOTAClass() @@ -16,6 +30,7 @@ ArduinoOTAClass::ArduinoOTAClass() , _end_callback(NULL) , _progress_callback(NULL) , _error_callback(NULL) +, _udp_ota(0) { } @@ -59,7 +74,6 @@ void ArduinoOTAClass::setPassword(const char * password) { void ArduinoOTAClass::begin() { if (_initialized) return; - _initialized = true; if (!_hostname.length()) { char tmp[15]; @@ -70,7 +84,12 @@ void ArduinoOTAClass::begin() { _port = 8266; } - _udp_ota.begin(_port); + _udp_ota = new UdpContext; + _udp_ota->ref(); + + if(!_udp_ota->listen(*IP_ADDR_ANY, _port)) + return; + _udp_ota->onRx(std::bind(&ArduinoOTAClass::_onRx, this)); MDNS.begin(_hostname.c_str()); if (_password.length()) { @@ -78,12 +97,123 @@ void ArduinoOTAClass::begin() { } else { MDNS.enableArduino(_port); } + _initialized = true; _state = OTA_IDLE; #if OTA_DEBUG Serial.printf("OTA server at: %s.local:%u\n", _hostname.c_str(), _port); #endif } +int ArduinoOTAClass::parseInt(){ + char data[16]; + uint8_t index = 0; + char value; + while(_udp_ota->peek() == ' ') _udp_ota->read(); + while(true){ + value = _udp_ota->peek(); + if(value < '0' || value > '9'){ + data[index++] = '\0'; + return atoi(data); + } + data[index++] = _udp_ota->read(); + } + return 0; +} + +String ArduinoOTAClass::readStringUntil(char end){ + String res = ""; + char value; + while(true){ + value = _udp_ota->read(); + if(value == '\0' || value == end){ + return res; + } + res += value; + } + return res; +} + +void ArduinoOTAClass::_onRx(){ + if(!_udp_ota->next()) return; + ip_addr_t ota_ip; + + if (_state == OTA_IDLE) { + int cmd = parseInt(); + if (cmd != U_FLASH && cmd != U_SPIFFS) + return; + _ota_ip = _udp_ota->getRemoteAddress(); + _cmd = cmd; + _ota_port = parseInt(); + _size = parseInt(); + _udp_ota->read(); + _md5 = readStringUntil('\n'); + _md5.trim(); + if(_md5.length() != 32) + return; + + ota_ip.addr = (uint32_t)_ota_ip; + + if (_password.length()){ + MD5Builder nonce_md5; + nonce_md5.begin(); + nonce_md5.add(String(micros())); + nonce_md5.calculate(); + _nonce = nonce_md5.toString(); + + char auth_req[38]; + sprintf(auth_req, "AUTH %s", _nonce.c_str()); + _udp_ota->append((const char *)auth_req, strlen(auth_req)); + _udp_ota->send(&ota_ip, _udp_ota->getRemotePort()); + _state = OTA_WAITAUTH; + return; + } else { + _udp_ota->append("OK", 2); + _udp_ota->send(&ota_ip, _udp_ota->getRemotePort()); + _state = OTA_RUNUPDATE; + } + } else if (_state == OTA_WAITAUTH) { + int cmd = parseInt(); + if (cmd != U_AUTH) { + _state = OTA_IDLE; + return; + } + _udp_ota->read(); + String cnonce = readStringUntil(' '); + String response = readStringUntil('\n'); + if (cnonce.length() != 32 || response.length() != 32) { + _state = OTA_IDLE; + return; + } + + MD5Builder _passmd5; + _passmd5.begin(); + _passmd5.add(_password); + _passmd5.calculate(); + String passmd5 = _passmd5.toString(); + + String challenge = passmd5 + ":" + String(_nonce) + ":" + cnonce; + MD5Builder _challengemd5; + _challengemd5.begin(); + _challengemd5.add(challenge); + _challengemd5.calculate(); + String result = _challengemd5.toString(); + + ota_ip.addr = (uint32_t)_ota_ip; + if(result.equals(response)){ + _udp_ota->append("OK", 2); + _udp_ota->send(&ota_ip, _udp_ota->getRemotePort()); + _state = OTA_RUNUPDATE; + } else { + _udp_ota->append("Authentication Failed", 21); + _udp_ota->send(&ota_ip, _udp_ota->getRemotePort()); + if (_error_callback) _error_callback(OTA_AUTH_ERROR); + _state = OTA_IDLE; + } + } + + while(_udp_ota->next()) _udp_ota->flush(); +} + void ArduinoOTAClass::_runUpdate() { if (!Update.begin(_size, _cmd)) { #if OTA_DEBUG @@ -92,7 +222,7 @@ void ArduinoOTAClass::_runUpdate() { if (_error_callback) { _error_callback(OTA_BEGIN_ERROR); } - _udp_ota.begin(_port); + _udp_ota->listen(*IP_ADDR_ANY, _port); _state = OTA_IDLE; return; } @@ -112,7 +242,7 @@ void ArduinoOTAClass::_runUpdate() { #if OTA_DEBUG Serial.printf("Connect Failed\n"); #endif - _udp_ota.begin(_port); + _udp_ota->listen(*IP_ADDR_ANY, _port); if (_error_callback) { _error_callback(OTA_CONNECT_ERROR); } @@ -128,7 +258,7 @@ void ArduinoOTAClass::_runUpdate() { #if OTA_DEBUG Serial.printf("Recieve Failed\n"); #endif - _udp_ota.begin(_port); + _udp_ota->listen(*IP_ADDR_ANY, _port); if (_error_callback) { _error_callback(OTA_RECIEVE_ERROR); } @@ -156,7 +286,7 @@ void ArduinoOTAClass::_runUpdate() { } ESP.restart(); } else { - _udp_ota.begin(_port); + _udp_ota->listen(*IP_ADDR_ANY, _port); if (_error_callback) { _error_callback(OTA_END_ERROR); } @@ -169,94 +299,9 @@ void ArduinoOTAClass::_runUpdate() { } void ArduinoOTAClass::handle() { - if (!_udp_ota) { - _udp_ota.begin(_port); -#if OTA_DEBUG - Serial.println("OTA restarted"); -#endif - } - - if (!_udp_ota.parsePacket()) return; - - if (_state == OTA_IDLE) { - int cmd = _udp_ota.parseInt(); - if (cmd != U_FLASH && cmd != U_SPIFFS) - return; - _ota_ip = _udp_ota.remoteIP(); - _cmd = cmd; - _ota_port = _udp_ota.parseInt(); - _size = _udp_ota.parseInt(); - _udp_ota.read(); - _md5 = _udp_ota.readStringUntil('\n'); - _md5.trim(); - if(_md5.length() != 32) - return; - -#if OTA_DEBUG - Serial.print("Update Start: ip:"); - Serial.print(_ota_ip); - Serial.printf(", port:%d, size:%d, md5:%s\n", _ota_port, _size, _md5.c_str()); -#endif - - _udp_ota.beginPacket(_ota_ip, _udp_ota.remotePort()); - if (_password.length()){ - MD5Builder nonce_md5; - nonce_md5.begin(); - nonce_md5.add(String(micros())); - nonce_md5.calculate(); - _nonce = nonce_md5.toString(); - _udp_ota.printf("AUTH %s", _nonce.c_str()); - _udp_ota.endPacket(); - _state = OTA_WAITAUTH; - return; - } else { - _udp_ota.print("OK"); - _udp_ota.endPacket(); - _state = OTA_RUNUPDATE; - } - } else if (_state == OTA_WAITAUTH) { - int cmd = _udp_ota.parseInt(); - if (cmd != U_AUTH) { - _state = OTA_IDLE; - return; - } - _udp_ota.read(); - String cnonce = _udp_ota.readStringUntil(' '); - String response = _udp_ota.readStringUntil('\n'); - if (cnonce.length() != 32 || response.length() != 32) { - _state = OTA_IDLE; - return; - } - - MD5Builder _passmd5; - _passmd5.begin(); - _passmd5.add(_password); - _passmd5.calculate(); - String passmd5 = _passmd5.toString(); - - String challenge = passmd5 + ":" + String(_nonce) + ":" + cnonce; - MD5Builder _challengemd5; - _challengemd5.begin(); - _challengemd5.add(challenge); - _challengemd5.calculate(); - String result = _challengemd5.toString(); - - if(result.equals(response)){ - _udp_ota.beginPacket(_ota_ip, _udp_ota.remotePort()); - _udp_ota.print("OK"); - _udp_ota.endPacket(); - _state = OTA_RUNUPDATE; - } else { - _udp_ota.beginPacket(_ota_ip, _udp_ota.remotePort()); - _udp_ota.print("Authentication Failed"); - _udp_ota.endPacket(); - if (_error_callback) _error_callback(OTA_AUTH_ERROR); - _state = OTA_IDLE; - } - } - if (_state == OTA_RUNUPDATE) { _runUpdate(); + _state = OTA_IDLE; } } diff --git a/libraries/ArduinoOTA/ArduinoOTA.h b/libraries/ArduinoOTA/ArduinoOTA.h index 5d5161e5e..bdb839397 100644 --- a/libraries/ArduinoOTA/ArduinoOTA.h +++ b/libraries/ArduinoOTA/ArduinoOTA.h @@ -1,7 +1,10 @@ #ifndef __ARDUINO_OTA_H #define __ARDUINO_OTA_H -class WiFiUDP; +#include +#include + +class UdpContext; #define OTA_CALLBACK(callback) void (*callback)() #define OTA_CALLBACK_PROGRESS(callback) void (*callback)(unsigned int, unsigned int) @@ -41,7 +44,7 @@ class ArduinoOTAClass String _password; String _hostname; String _nonce; - WiFiUDP _udp_ota; + UdpContext *_udp_ota; bool _initialized; ota_state_t _state; int _size; @@ -56,6 +59,9 @@ class ArduinoOTAClass OTA_CALLBACK_PROGRESS(_progress_callback); void _runUpdate(void); + void _onRx(void); + int parseInt(void); + String readStringUntil(char end); }; extern ArduinoOTAClass ArduinoOTA; From 50eb6d9ff241e744b0344daaf04334b205ca3dd3 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Thu, 19 Nov 2015 22:52:52 +0200 Subject: [PATCH 05/33] Make RequestHandler handle uploads --- .../ESP8266WebServer/src/ESP8266WebServer.cpp | 18 +++---- .../ESP8266WebServer/src/ESP8266WebServer.h | 14 +++--- libraries/ESP8266WebServer/src/Parsing.cpp | 23 +++++++-- .../src/detail/RequestHandler.h | 3 ++ .../src/detail/RequestHandlersImpl.h | 47 +++++++++++++++---- 5 files changed, 77 insertions(+), 28 deletions(-) diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp index 04bda3152..de128d48e 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp @@ -33,6 +33,7 @@ ESP8266WebServer::ESP8266WebServer(IPAddress addr, int port) : _server(addr, port) +, _currentHandler(0) , _firstHandler(0) , _lastHandler(0) , _currentArgCount(0) @@ -44,6 +45,7 @@ ESP8266WebServer::ESP8266WebServer(IPAddress addr, int port) ESP8266WebServer::ESP8266WebServer(int port) : _server(port) +, _currentHandler(0) , _firstHandler(0) , _lastHandler(0) , _currentArgCount(0) @@ -74,7 +76,11 @@ void ESP8266WebServer::on(const char* uri, ESP8266WebServer::THandlerFunction ha } void ESP8266WebServer::on(const char* uri, HTTPMethod method, ESP8266WebServer::THandlerFunction fn) { - _addRequestHandler(new FunctionRequestHandler(fn, uri, method)); + on(uri, method, fn, _fileUploadHandler); +} + +void ESP8266WebServer::on(const char* uri, HTTPMethod method, ESP8266WebServer::THandlerFunction fn, ESP8266WebServer::THandlerFunction ufn) { + _addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method)); } void ESP8266WebServer::addHandler(RequestHandler* handler) { @@ -352,13 +358,7 @@ void ESP8266WebServer::onNotFound(THandlerFunction fn) { } void ESP8266WebServer::_handleRequest() { - RequestHandler* handler; - for (handler = _firstHandler; handler; handler = handler->next()) { - if (handler->handle(*this, _currentMethod, _currentUri)) - break; - } - - if (!handler){ + if (!_currentHandler){ #ifdef DEBUG DEBUG_OUTPUT.println("request handler not found"); #endif @@ -369,6 +369,8 @@ void ESP8266WebServer::_handleRequest() { else { send(404, "text/plain", String("Not found: ") + _currentUri); } + } else { + _currentHandler->handle(*this, _currentMethod, _currentUri); } uint16_t maxWait = HTTP_MAX_CLOSE_WAIT; diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index 65e44378f..16c9ae5a5 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -40,12 +40,6 @@ enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END, class ESP8266WebServer; -#include "detail/RequestHandler.h" - -namespace fs { -class FS; -} - typedef struct { HTTPUploadStatus status; String filename; @@ -56,6 +50,12 @@ typedef struct { uint8_t buf[HTTP_UPLOAD_BUFLEN]; } HTTPUpload; +#include "detail/RequestHandler.h" + +namespace fs { +class FS; +} + class ESP8266WebServer { public: @@ -69,6 +69,7 @@ public: typedef std::function THandlerFunction; void on(const char* uri, THandlerFunction handler); void on(const char* uri, HTTPMethod method, THandlerFunction fn); + void on(const char* uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); void addHandler(RequestHandler* handler); void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL ); void onNotFound(THandlerFunction fn); //called when handler is not assigned @@ -155,6 +156,7 @@ protected: String _hostHeader; + RequestHandler* _currentHandler; RequestHandler* _firstHandler; RequestHandler* _lastHandler; THandlerFunction _notFoundHandler; diff --git a/libraries/ESP8266WebServer/src/Parsing.cpp b/libraries/ESP8266WebServer/src/Parsing.cpp index 0458a9980..318b0f547 100644 --- a/libraries/ESP8266WebServer/src/Parsing.cpp +++ b/libraries/ESP8266WebServer/src/Parsing.cpp @@ -81,6 +81,14 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) { DEBUG_OUTPUT.println(searchStr); #endif + //attach handler + RequestHandler* handler; + for (handler = _firstHandler; handler; handler = handler->next()) { + if (handler->canHandle(_currentMethod, _currentUri)) + break; + } + _currentHandler = handler; + String formData; // below is needed only when POST type request if (method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE){ @@ -279,7 +287,8 @@ void ESP8266WebServer::_parseArguments(String data) { void ESP8266WebServer::_uploadWriteByte(uint8_t b){ if (_currentUpload.currentSize == HTTP_UPLOAD_BUFLEN){ - if (_fileUploadHandler) _fileUploadHandler(); + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); _currentUpload.totalSize += _currentUpload.currentSize; _currentUpload.currentSize = 0; } @@ -397,7 +406,8 @@ bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t DEBUG_OUTPUT.print(" Type: "); DEBUG_OUTPUT.println(_currentUpload.type); #endif - if (_fileUploadHandler) _fileUploadHandler(); + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); _currentUpload.status = UPLOAD_FILE_WRITE; uint8_t argByte = _uploadReadByte(client); readfile: @@ -433,10 +443,12 @@ readfile: client.readBytes(endBuf, boundary.length()); if (strstr((const char*)endBuf, boundary.c_str()) != NULL){ - if (_fileUploadHandler) _fileUploadHandler(); + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); _currentUpload.totalSize += _currentUpload.currentSize; _currentUpload.status = UPLOAD_FILE_END; - if (_fileUploadHandler) _fileUploadHandler(); + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); #ifdef DEBUG DEBUG_OUTPUT.print("End File: "); DEBUG_OUTPUT.print(_currentUpload.filename); @@ -503,6 +515,7 @@ readfile: bool ESP8266WebServer::_parseFormUploadAborted(){ _currentUpload.status = UPLOAD_FILE_ABORTED; - if (_fileUploadHandler) _fileUploadHandler(); + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); return false; } diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandler.h b/libraries/ESP8266WebServer/src/detail/RequestHandler.h index dd3d15733..5a998bfbd 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandler.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandler.h @@ -3,7 +3,10 @@ class RequestHandler { public: + virtual bool canHandle(HTTPMethod method, String uri) { return false; } + virtual bool canUpload(String uri) { return false; } virtual bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) { return false; } + virtual void upload(ESP8266WebServer& server, String requestUri, HTTPUpload& upload) {} RequestHandler* next() { return _next; } void next(RequestHandler* r) { _next = r; } diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index accddee21..9ce8441e1 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -5,28 +5,49 @@ class FunctionRequestHandler : public RequestHandler { public: - FunctionRequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method) + FunctionRequestHandler(ESP8266WebServer::THandlerFunction fn, ESP8266WebServer::THandlerFunction ufn, const char* uri, HTTPMethod method) : _fn(fn) + , _ufn(ufn) , _uri(uri) , _method(method) { } - bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override { + bool canHandle(HTTPMethod requestMethod, String requestUri) override { if (_method != HTTP_ANY && _method != requestMethod) return false; if (requestUri != _uri) return false; + return true; + } + + bool canUpload(String requestUri) override { + if (!_ufn || !canHandle(HTTP_POST, requestUri)) + return false; + + return true; + } + + bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override { + if (!canHandle(requestMethod, requestUri)) + return false; + _fn(); return true; } + void upload(ESP8266WebServer& server, String requestUri, HTTPUpload& upload) override { + if (canUpload(requestUri)) + _ufn(); + } + protected: String _uri; HTTPMethod _method; ESP8266WebServer::THandlerFunction _fn; + ESP8266WebServer::THandlerFunction _ufn; }; class StaticRequestHandler : public RequestHandler { @@ -41,13 +62,26 @@ public: DEBUGV("StaticRequestHandler: path=%s uri=%s isFile=%d, cache_header=%s\r\n", path, uri, _isFile, cache_header); _baseUriLength = _uri.length(); } - bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override { + + bool canHandle(HTTPMethod requestMethod, String requestUri) override { if (requestMethod != HTTP_GET) return false; - DEBUGV("StaticRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), _uri.c_str()); + if (!requestUri.startsWith(_uri)) return false; + if (requestUri != _uri) + return false; + + return true; + } + + bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override { + if (!canHandle(requestMethod, requestUri)) + return false; + + DEBUGV("StaticRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), _uri.c_str()); + String path(_path); if(path.endsWith("/")) path += "index.htm"; @@ -57,11 +91,6 @@ public: // URI in request to get the file path. path += requestUri.substring(_baseUriLength); } - - else if (requestUri != _uri) { - // Base URI points to a file but request doesn't match this URI exactly - return false; - } DEBUGV("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile); String contentType = getContentType(path); From 0063d80c740c3a605cb298169452104c34e0d892 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Thu, 19 Nov 2015 23:20:03 +0200 Subject: [PATCH 06/33] "Fix" sketches and libs to use the new upload api --- .../src/ESP8266HTTPUpdateServer.cpp | 11 ++++------- .../examples/FSBrowser/FSBrowser.ino | 7 +++---- .../examples/SDWebServer/SDWebServer.ino | 3 +-- .../examples/WebUpdate/WebUpdate.ino | 14 ++++++-------- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp index 2ed37c502..fa7b7ac35 100644 --- a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp +++ b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp @@ -36,12 +36,9 @@ void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server) _server->sendHeader("Access-Control-Allow-Origin", "*"); _server->send(200, "text/plain", (Update.hasError())?"FAIL":"OK"); ESP.restart(); - }); - - // handler for the file upload, get's the sketch bytes, and writes - // them through the Update object. - _server->onFileUpload([&](){ - if(_server->uri() != "/update") return; + },[&](){ + // handler for the file upload, get's the sketch bytes, and writes + // them through the Update object HTTPUpload& upload = _server->upload(); if(upload.status == UPLOAD_FILE_START){ if (_serial_output) @@ -70,6 +67,6 @@ void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server) Update.end(); if (_serial_output) Serial.println("Update was aborted"); } - yield(); + delay(0); }); } diff --git a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino index f8b43e34d..4df717d70 100644 --- a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino +++ b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino @@ -207,10 +207,9 @@ void setup(void){ server.on("/edit", HTTP_PUT, handleFileCreate); //delete file server.on("/edit", HTTP_DELETE, handleFileDelete); - //called after file upload - server.on("/edit", HTTP_POST, [](){ server.send(200, "text/plain", ""); }); - //called when a file is received inside POST data - server.onFileUpload(handleFileUpload); + //first callback is called after the request has ended with all parsed arguments + //second callback handles file uploads at that location + server.on("/edit", HTTP_POST, [](){ server.send(200, "text/plain", ""); }, handleFileUpload); //called when the url is not defined here //use it to load content from SPIFFS diff --git a/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino b/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino index c62cadfd6..b42b1d097 100644 --- a/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino +++ b/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino @@ -256,9 +256,8 @@ void setup(void){ server.on("/list", HTTP_GET, printDirectory); server.on("/edit", HTTP_DELETE, handleDelete); server.on("/edit", HTTP_PUT, handleCreate); - server.on("/edit", HTTP_POST, [](){ returnOK(); }); + server.on("/edit", HTTP_POST, [](){ returnOK(); }, handleFileUpload); server.onNotFound(handleNotFound); - server.onFileUpload(handleFileUpload); server.begin(); DBG_OUTPUT_PORT.println("HTTP server started"); diff --git a/libraries/ESP8266WebServer/examples/WebUpdate/WebUpdate.ino b/libraries/ESP8266WebServer/examples/WebUpdate/WebUpdate.ino index 665dd6199..c5e67ef33 100644 --- a/libraries/ESP8266WebServer/examples/WebUpdate/WebUpdate.ino +++ b/libraries/ESP8266WebServer/examples/WebUpdate/WebUpdate.ino @@ -27,8 +27,12 @@ void setup(void){ server.sendHeader("Access-Control-Allow-Origin", "*"); server.send(200, "text/html", serverIndex); }); - server.onFileUpload([](){ - if(server.uri() != "/update") return; + server.on("/update", HTTP_POST, [](){ + server.sendHeader("Connection", "close"); + server.sendHeader("Access-Control-Allow-Origin", "*"); + server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK"); + ESP.restart(); + },[](){ HTTPUpload& upload = server.upload(); if(upload.status == UPLOAD_FILE_START){ Serial.setDebugOutput(true); @@ -52,12 +56,6 @@ void setup(void){ } yield(); }); - server.on("/update", HTTP_POST, [](){ - server.sendHeader("Connection", "close"); - server.sendHeader("Access-Control-Allow-Origin", "*"); - server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK"); - ESP.restart(); - }); server.begin(); MDNS.addService("http", "tcp", 80); From 8bf1e98f24f03a1bc73fe8243bfc0aa01b688e5b Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sat, 21 Nov 2015 20:04:38 +0300 Subject: [PATCH 07/33] Improve debug output on critical errors --- cores/esp8266/abi.cpp | 15 ++++---- cores/esp8266/core_esp8266_main.cpp | 14 ++------ cores/esp8266/core_esp8266_postmortem.c | 36 ++++++++++++++++++- cores/esp8266/debug.h | 16 ++++++++- .../ESP8266WiFi/src/WiFiClientSecure.cpp | 7 ++-- 5 files changed, 64 insertions(+), 24 deletions(-) diff --git a/cores/esp8266/abi.cpp b/cores/esp8266/abi.cpp index 91e999a0c..b38f16453 100644 --- a/cores/esp8266/abi.cpp +++ b/cores/esp8266/abi.cpp @@ -17,14 +17,16 @@ */ #include +#include +#include extern "C" { #include "ets_sys.h" #include "os_type.h" #include "osapi.h" #include "mem.h" -#include "user_interface.h" } + void *operator new(size_t size) { size = ((size + 3) & ~((size_t)0x3)); return os_malloc(size); @@ -47,27 +49,26 @@ extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__)); extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__)); void __cxa_pure_virtual(void) { - abort(); + panic(); } void __cxa_deleted_virtual(void) { - abort(); + panic(); } namespace std { void __throw_bad_function_call() { - abort(); + panic(); } void __throw_length_error(char const*) { - abort(); + panic(); } void __throw_bad_alloc() { - abort(); + panic(); } } // TODO: rebuild windows toolchain to make this unnecessary: void* __dso_handle; - diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 5ea7a1be7..92c48312d 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -66,13 +66,6 @@ static os_event_t g_loop_queue[LOOP_QUEUE_SIZE]; static uint32_t g_micros_at_task_start; - -extern "C" void abort() { - do { - *((int*)0) = 0; - } while(true); -} - extern "C" void esp_yield() { if (cont_can_yield(&g_cont)) { cont_yield(&g_cont); @@ -89,7 +82,7 @@ extern "C" void __yield() { esp_yield(); } else { - abort(); + panic(); } } @@ -117,9 +110,8 @@ static void loop_wrapper() { static void loop_task(os_event_t *events) { g_micros_at_task_start = system_get_time(); cont_run(&g_cont, &loop_wrapper); - if(cont_check(&g_cont) != 0) { - ets_printf("\r\nsketch stack overflow detected\r\n"); - abort(); + if (cont_check(&g_cont) != 0) { + panic(); } } diff --git a/cores/esp8266/core_esp8266_postmortem.c b/cores/esp8266/core_esp8266_postmortem.c index 1fd929e85..1af8f57ca 100644 --- a/cores/esp8266/core_esp8266_postmortem.c +++ b/cores/esp8266/core_esp8266_postmortem.c @@ -22,6 +22,7 @@ #include #include #include +#include "debug.h" #include "ets_sys.h" #include "user_interface.h" #include "esp8266_peri.h" @@ -30,6 +31,11 @@ extern void __real_system_restart_local(); extern cont_t g_cont; +static const char* s_panic_file = 0; +static int s_panic_line = 0; +static const char* s_panic_func = 0; + +static bool s_abort_called = false; void uart_write_char_d(char c); static void uart0_write_char_d(char c); @@ -56,7 +62,13 @@ void __wrap_system_restart_local() { ets_install_putc1(&uart_write_char_d); - if (rst_info.reason == REASON_EXCEPTION_RST) { + if (s_panic_line) { + ets_printf("\nPanic %s:%d %s\n", s_panic_file, s_panic_line, s_panic_func); + } + else if (s_abort_called) { + ets_printf("Abort called\n"); + } + else if (rst_info.reason == REASON_EXCEPTION_RST) { ets_printf("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n", rst_info.exccause, rst_info.epc1, rst_info.epc2, rst_info.epc3, rst_info.excvaddr, rst_info.depc); } @@ -158,3 +170,25 @@ static void uart1_write_char_d(char c) { } USF(1) = c; } +void abort() __attribute__((noreturn)); + +void abort(){ + // cause exception + s_abort_called = true; + do { + *((int*)0) = 0; + } while(true); +} + +void __assert_func(const char *file, int line, const char *func, const char *what) { + s_panic_file = file; + s_panic_line = line; + s_panic_func = func; +} + +void __panic_func(const char* file, int line, const char* func) { + s_panic_file = file; + s_panic_line = line; + s_panic_func = func; + abort(); +} diff --git a/cores/esp8266/debug.h b/cores/esp8266/debug.h index fe389bb2d..9cf5980ef 100644 --- a/cores/esp8266/debug.h +++ b/cores/esp8266/debug.h @@ -2,7 +2,9 @@ #define ARD_DEBUG_H #include -//#define DEBUGV(...) ets_printf(__VA_ARGS__) +#include + +#define DEBUGV(...) ets_printf(__VA_ARGS__) #ifndef DEBUGV #define DEBUGV(...) @@ -14,4 +16,16 @@ void hexdump(uint8_t *mem, uint32_t len, uint8_t cols = 16); void hexdump(uint8_t *mem, uint32_t len, uint8_t cols); #endif +#ifdef __cplusplus +extern "C" { +#endif + +void __panic_func(const char* file, int line, const char* func) __attribute__((noreturn)); +#define panic() __panic_func(__FILE__, __LINE__, __func__) + +#ifdef __cplusplus +} +#endif + + #endif//ARD_DEBUG_H diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp b/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp index 3369c3448..ef737c6d4 100644 --- a/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp +++ b/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp @@ -273,7 +273,7 @@ int WiFiClientSecure::available() { uint8_t WiFiClientSecure::connected() { if (!_client) return 0; - + if (_client->state() == ESTABLISHED) return 1; @@ -384,8 +384,7 @@ extern "C" void* ax_port_malloc(size_t size, const char* file, int line) { if (result == nullptr) { DEBUG_TLS_MEM_PRINT("%s:%d malloc %d failed, left %d\r\n", file, line, size, ESP.getFreeHeap()); - - while(true){} + panic(); } if (size >= 1024) DEBUG_TLS_MEM_PRINT("%s:%d malloc %d, left %d\r\n", file, line, size, ESP.getFreeHeap()); @@ -402,7 +401,7 @@ extern "C" void* ax_port_realloc(void* ptr, size_t size, const char* file, int l void* result = realloc(ptr, size); if (result == nullptr) { DEBUG_TLS_MEM_PRINT("%s:%d realloc %d failed, left %d\r\n", file, line, size, ESP.getFreeHeap()); - while(true){} + panic(); } if (size >= 1024) DEBUG_TLS_MEM_PRINT("%s:%d realloc %d, left %d\r\n", file, line, size, ESP.getFreeHeap()); From 40da463ee631133a16fc8ddde7c82d507060068b Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sat, 21 Nov 2015 20:06:10 +0300 Subject: [PATCH 08/33] ESP8266WiFi library: add persistent option, fix #1054 --- libraries/ESP8266WiFi/src/ESP8266WiFi.cpp | 105 ++++++++++++++++++---- libraries/ESP8266WiFi/src/ESP8266WiFi.h | 7 +- 2 files changed, 95 insertions(+), 17 deletions(-) diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp index 665ef46ea..1ffcd2450 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp @@ -36,6 +36,7 @@ extern "C" { #include "WiFiClient.h" #include "WiFiUdp.h" +#include "debug.h" extern "C" void esp_schedule(); extern "C" void esp_yield(); @@ -44,6 +45,7 @@ ESP8266WiFiClass::ESP8266WiFiClass() : _smartConfigStarted(false) , _smartConfigDone(false) , _useStaticIp(false) +, _persistent(true) { uint8 m = wifi_get_opmode(); _useClientMode = (m & WIFI_STA); @@ -51,6 +53,12 @@ ESP8266WiFiClass::ESP8266WiFiClass() wifi_set_event_handler_cb((wifi_event_handler_cb_t)&ESP8266WiFiClass::_eventCallback); } +void ESP8266WiFiClass::persistent(bool persistent) +{ + _persistent = persistent; +} + + void ESP8266WiFiClass::mode(WiFiMode m) { if(wifi_get_opmode() == (uint8)m) { @@ -69,9 +77,7 @@ void ESP8266WiFiClass::mode(WiFiMode m) _useClientMode = false; } - ETS_UART_INTR_DISABLE(); - wifi_set_opmode(m); - ETS_UART_INTR_ENABLE(); + _mode(m); } WiFiMode ESP8266WiFiClass::getMode() @@ -86,15 +92,44 @@ void ESP8266WiFiClass::_mode(WiFiMode m) } ETS_UART_INTR_DISABLE(); - wifi_set_opmode(m); + if (_persistent) + wifi_set_opmode(m); + else + wifi_set_opmode_current(m); ETS_UART_INTR_ENABLE(); + } -int ESP8266WiFiClass::begin(char* ssid, char *passphrase, int32_t channel, uint8_t bssid[6]){ +static bool sta_config_equal(const station_config& lhs, const station_config& rhs) +{ + if (strcmp(reinterpret_cast(lhs.ssid), reinterpret_cast(rhs.ssid)) != 0) + return false; + + if (strcmp(reinterpret_cast(lhs.password), reinterpret_cast(rhs.password)) != 0) + return false; + + if (lhs.bssid_set) { + if (!rhs.bssid_set) + return false; + + if (memcmp(lhs.bssid, rhs.bssid, 6) != 0) + return false; + } + else { + if (rhs.bssid_set) + return false; + } + + return true; +} + +int ESP8266WiFiClass::begin(char* ssid, char *passphrase, int32_t channel, const uint8_t* bssid) +{ return begin((const char*) ssid, (const char*) passphrase, channel, bssid); } -int ESP8266WiFiClass::begin(const char* ssid, const char *passphrase, int32_t channel, uint8_t bssid[6]){ +int ESP8266WiFiClass::begin(const char* ssid, const char *passphrase, int32_t channel, const uint8_t* bssid) +{ _useClientMode = true; if(_useApMode) { @@ -106,12 +141,12 @@ int ESP8266WiFiClass::begin(const char* ssid, const char *passphrase, int32_t ch } if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) { - // fail SSID to long or missing! + // fail SSID too long or missing! return WL_CONNECT_FAILED; } if(passphrase && strlen(passphrase) > 63) { - // fail passphrase to long! + // fail passphrase too long! return WL_CONNECT_FAILED; } @@ -131,8 +166,18 @@ int ESP8266WiFiClass::begin(const char* ssid, const char *passphrase, int32_t ch conf.bssid_set = 0; } + struct station_config current_conf; + wifi_station_get_config(¤t_conf); + if (sta_config_equal(current_conf, conf)) { + DEBUGV("sta config unchanged"); + return status(); + } + ETS_UART_INTR_DISABLE(); - wifi_station_set_config(&conf); + if (_persistent) + wifi_station_set_config(&conf); + else + wifi_station_set_config_current(&conf); wifi_station_connect(); ETS_UART_INTR_ENABLE(); @@ -203,8 +248,10 @@ int ESP8266WiFiClass::softAPdisconnect(bool wifioff) *conf.ssid = 0; *conf.password = 0; ETS_UART_INTR_DISABLE(); - wifi_softap_set_config(&conf); - wifi_station_disconnect(); + if (_persistent) + wifi_softap_set_config(&conf); + else + wifi_softap_set_config_current(&conf); ETS_UART_INTR_ENABLE(); if(wifioff) { @@ -228,7 +275,10 @@ int ESP8266WiFiClass::disconnect(bool wifioff) *conf.ssid = 0; *conf.password = 0; ETS_UART_INTR_DISABLE(); - wifi_station_set_config(&conf); + if (_persistent) + wifi_station_set_config(&conf); + else + wifi_station_set_config_current(&conf); wifi_station_disconnect(); ETS_UART_INTR_ENABLE(); @@ -247,6 +297,20 @@ int ESP8266WiFiClass::disconnect(bool wifioff) return 0; } +static bool softap_config_equal(const softap_config& lhs, const softap_config& rhs) +{ + if (strcmp(reinterpret_cast(lhs.ssid), reinterpret_cast(rhs.ssid)) != 0) + return false; + if (strcmp(reinterpret_cast(lhs.password), reinterpret_cast(rhs.password)) != 0) + return false; + if (lhs.channel != rhs.channel) + return false; + if (lhs.ssid_hidden != rhs.ssid_hidden) + return false; + return true; +} + + void ESP8266WiFiClass::softAP(const char* ssid) { softAP(ssid, 0); @@ -264,8 +328,8 @@ void ESP8266WiFiClass::softAP(const char* ssid, const char* passphrase, int chan _mode(WIFI_AP); } - if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) { - // fail SSID to long or missing! + if(!ssid || strlen(ssid) || strlen(ssid) > 31) { + // fail SSID too long or missing! return; } @@ -294,8 +358,19 @@ void ESP8266WiFiClass::softAP(const char* ssid, const char* passphrase, int chan strcpy(reinterpret_cast(conf.password), passphrase); } + struct softap_config conf_current; + wifi_softap_get_config(&conf_current); + if (!softap_config_equal(conf, conf_current)) + { + DEBUGV("softap config unchanged"); + return; + } + ETS_UART_INTR_DISABLE(); - wifi_softap_set_config(&conf); + if (_persistent) + wifi_softap_set_config(&conf); + else + wifi_softap_set_config_current(&conf); ETS_UART_INTR_ENABLE(); } diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFi.h b/libraries/ESP8266WiFi/src/ESP8266WiFi.h index 4c1330b2e..0d732ab4c 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFi.h +++ b/libraries/ESP8266WiFi/src/ESP8266WiFi.h @@ -44,6 +44,8 @@ public: ESP8266WiFiClass(); + void persistent(bool persistent); + void mode(WiFiMode); WiFiMode getMode(); @@ -56,8 +58,8 @@ public: * @param channel Optional. Channel of AP * @return */ - int begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0, uint8_t bssid[6] = NULL); - int begin(char* ssid, char *passphrase = NULL, int32_t channel = 0, uint8_t bssid[6] = NULL); + int begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL); + int begin(char* ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL); // Use sdk config to connect. int begin(); @@ -385,6 +387,7 @@ protected: bool _useApMode; bool _useClientMode; bool _useStaticIp; + bool _persistent; static bool _scanAsync; static bool _scanStarted; From ab16b2fe0d496cf603d02213dcd7333381fa4b42 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sat, 21 Nov 2015 20:09:18 +0300 Subject: [PATCH 09/33] Fix typo --- libraries/ESP8266WiFi/src/ESP8266WiFi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp index 1ffcd2450..59b82e290 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp @@ -328,7 +328,7 @@ void ESP8266WiFiClass::softAP(const char* ssid, const char* passphrase, int chan _mode(WIFI_AP); } - if(!ssid || strlen(ssid) || strlen(ssid) > 31) { + if(!ssid || *ssid == 0 || strlen(ssid) > 31) { // fail SSID too long or missing! return; } From 4b8fb2093fa9dcabe19e4d836c9fb5fc7becf250 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sat, 21 Nov 2015 20:18:38 +0300 Subject: [PATCH 10/33] Fix warning about gettimeofday (#1058) --- cores/esp8266/time.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cores/esp8266/time.c b/cores/esp8266/time.c index 7410b4f16..e75c04915 100644 --- a/cores/esp8266/time.c +++ b/cores/esp8266/time.c @@ -124,4 +124,5 @@ int gettimeofday(struct timeval *tp, void *tzp) tp->tv_sec = (s_bootTime + millis()) / 1000; tp->tv_usec = micros() * 1000; } + return 0; } From 94a7f63cda2516a3ec35be7a11faf098dda31014 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Sat, 21 Nov 2015 21:04:07 +0200 Subject: [PATCH 11/33] fix static handler --- .../ESP8266WebServer/src/detail/RequestHandlersImpl.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index 9ce8441e1..54522b1d9 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -70,9 +70,6 @@ public: if (!requestUri.startsWith(_uri)) return false; - if (requestUri != _uri) - return false; - return true; } @@ -91,6 +88,11 @@ public: // URI in request to get the file path. path += requestUri.substring(_baseUriLength); } + + else if (requestUri != _uri) { + // Base URI points to a file but request doesn't match this URI exactly + return false; + } DEBUGV("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile); String contentType = getContentType(path); From fe9dc913b40588a1227bb4c149c158ea6ffe217b Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Sat, 21 Nov 2015 21:14:11 +0200 Subject: [PATCH 12/33] unref udp if exists --- libraries/ArduinoOTA/ArduinoOTA.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libraries/ArduinoOTA/ArduinoOTA.cpp b/libraries/ArduinoOTA/ArduinoOTA.cpp index ed2421a8d..9b55733bb 100644 --- a/libraries/ArduinoOTA/ArduinoOTA.cpp +++ b/libraries/ArduinoOTA/ArduinoOTA.cpp @@ -34,6 +34,13 @@ ArduinoOTAClass::ArduinoOTAClass() { } +ArduinoOTAClass::~ArduinoOTAClass(){ + if(_udp_ota){ + _udp_ota->unref(); + _udp_ota = 0; + } +} + void ArduinoOTAClass::onStart(OTA_CALLBACK(fn)) { _start_callback = fn; } @@ -50,9 +57,6 @@ void ArduinoOTAClass::onError(OTA_CALLBACK_ERROR(fn)) { _error_callback = fn; } -ArduinoOTAClass::~ArduinoOTAClass() { -} - void ArduinoOTAClass::setPort(uint16_t port) { if (!_initialized && !_port && port) { _port = port; @@ -84,6 +88,11 @@ void ArduinoOTAClass::begin() { _port = 8266; } + if(_udp_ota){ + _udp_ota->unref(); + _udp_ota = 0; + } + _udp_ota = new UdpContext; _udp_ota->ref(); From bc48022118f3c18cce659795d73628df7e47dc86 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Sat, 21 Nov 2015 21:29:54 +0200 Subject: [PATCH 13/33] spend more time understanding the logic --- .../ESP8266WebServer/src/detail/RequestHandlersImpl.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index 54522b1d9..4ff6a3a42 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -67,8 +67,8 @@ public: if (requestMethod != HTTP_GET) return false; - if (!requestUri.startsWith(_uri)) - return false; + if (_isFile && requestUri != _uri || !requestUri.startsWith(_uri)) + return false; return true; } @@ -88,11 +88,6 @@ public: // URI in request to get the file path. path += requestUri.substring(_baseUriLength); } - - else if (requestUri != _uri) { - // Base URI points to a file but request doesn't match this URI exactly - return false; - } DEBUGV("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile); String contentType = getContentType(path); From 1e7b9688a53927f6f67dac80bac3fb51328ab4a2 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 22 Nov 2015 11:09:48 +0100 Subject: [PATCH 14/33] add examples/BasicHttpClient/BasicHttpClient.ino fix get size only fingerprint when strlen > 0 --- .../BasicHttpClient/BasicHttpClient.ino | 77 +++++++++++++++++++ .../src/ESP8266httpClient.cpp | 30 +++++--- .../ESP8266httpClient/src/ESP8266httpClient.h | 4 +- 3 files changed, 99 insertions(+), 12 deletions(-) create mode 100644 libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino diff --git a/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino b/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino new file mode 100644 index 000000000..23a5e49da --- /dev/null +++ b/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino @@ -0,0 +1,77 @@ +/** + * BasicHttpClient.ino + * + * Created on: 24.05.2015 + * + */ + +#include + +#include +#include + +#include + + +ESP8266WiFiMulti WiFiMulti; + +void setup() { + Serial.begin(115200); + + + Serial.println(); + Serial.println(); + Serial.println(); + + + for(uint8_t t = 4; t > 0; t--) { + Serial.printf("[SETUP] WAIT %d...\n", t); + Serial.flush(); + delay(1000); + } + + WiFiMulti.addAP("SSID", "PASSWORD"); + + //WiFi.disconnect(); + while(WiFiMulti.run() != WL_CONNECTED) { + delay(100); + } +} + +void loop() { + if((WiFiMulti.run() == WL_CONNECTED)) { + httpClient http; + + Serial.print("[HTTP] begin...\n"); + + http.begin("192.168.1.12", 80, "/test.html"); + + Serial.print("[HTTP] GET...\n"); + if(http.GET()) { + + Serial.print("[HTTP] GET... ok.\n"); + + size_t len = http.getSize(); + + uint8_t buff[128] = { 0 }; + WiFiClient stream = http.getStream(); + while(http.connected() && len > 0) { + size_t size = stream.available(); + int c = stream.readBytes(buff, ((size > 128) ? 128 : size)); + + Serial.write(buff, c); + len -= c; + + delay(0); + } + Serial.println(); + Serial.print("[HTTP] connection closed or file end.\n"); + + } else { + + Serial.print("[HTTP] GET... fail.\n"); + } + + delay(10000); + } +} diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp index 8be06cf3f..125f363e1 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp @@ -36,7 +36,7 @@ httpClient::httpClient() { _currentHeaders = NULL; _returnCode = 0; - _size = 0; + _size = -1; } httpClient::~httpClient() { @@ -51,11 +51,18 @@ httpClient::~httpClient() { } void httpClient::begin(const char *host, uint16_t port, const char * url, bool https, const char * httpsFingerprint) { + _host = host; _port = port; _url = url; _https = https; _httpsFingerprint = httpsFingerprint; + + _returnCode = 0; + _size = -1; + + _Headers = ""; + } void httpClient::begin(String host, uint16_t port, String url, bool https, String httpsFingerprint) { @@ -121,6 +128,15 @@ int httpClient::POST(String payload) { return POST((uint8_t *) payload.c_str(), payload.length()); } + +/** + * size of message body / payload + * @return -1 if no info or > 0 when Content-Length is set by server + */ +int httpClient::getSize(void) { + return _size; +} + /** * returns the stram of the tcp connection * @return WiFiClient @@ -194,13 +210,7 @@ bool httpClient::hasHeader(const char* name) { return false; } -/** - * size of message body / payload - * @return 0 if no info or > 0 when Content-Length is set by server - */ -size_t httpClient::getSize(void) { - return _size; -} + /** * init TCP connection and handle ssl verify if needed @@ -209,7 +219,7 @@ size_t httpClient::getSize(void) { bool httpClient::connect(void) { if(connected()) { - DEBUG_HTTPCLIENT("[HTTP-Client] connect. already connected!\n"); + DEBUG_HTTPCLIENT("[HTTP-Client] connect. already connected, reuse!\n"); return true; } @@ -229,7 +239,7 @@ bool httpClient::connect(void) { DEBUG_HTTPCLIENT("[HTTP-Client] connected to %s:%u.\n", _host.c_str(), _port); - if(_https) { + if(_https && _httpsFingerprint.length() > 0) { if(_tcps->verify(_httpsFingerprint.c_str(), _host.c_str())) { DEBUG_HTTPCLIENT("[HTTP-Client] https certificate matches\n"); } else { diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.h b/libraries/ESP8266httpClient/src/ESP8266httpClient.h index 1ffe8f094..57f186912 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.h +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.h @@ -59,7 +59,7 @@ class httpClient { bool hasHeader(const char* name); // check if header exists - size_t getSize(void); + int getSize(void); WiFiClient & getStream(void); @@ -89,7 +89,7 @@ class httpClient { size_t _headerKeysCount; int _returnCode; - size_t _size; + int _size; bool connect(void); From 0a8f5be2575d0e6f354082e4b5ea35181949f7a7 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 22 Nov 2015 11:27:32 +0100 Subject: [PATCH 15/33] add more documentation and cleanup the example --- .../BasicHttpClient/BasicHttpClient.ino | 91 ++++++++++++------- 1 file changed, 56 insertions(+), 35 deletions(-) diff --git a/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino b/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino index 23a5e49da..99df11e76 100644 --- a/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino +++ b/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino @@ -12,66 +12,87 @@ #include +#define USE_SERIAL Serial1 ESP8266WiFiMulti WiFiMulti; void setup() { - Serial.begin(115200); + USE_SERIAL.begin(115200); + // USE_SERIAL.setDebugOutput(true); - Serial.println(); - Serial.println(); - Serial.println(); + USE_SERIAL.println(); + USE_SERIAL.println(); + USE_SERIAL.println(); - - for(uint8_t t = 4; t > 0; t--) { - Serial.printf("[SETUP] WAIT %d...\n", t); - Serial.flush(); - delay(1000); - } + for(uint8_t t = 4; t > 0; t--) { + USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); + USE_SERIAL.flush(); + delay(1000); + } WiFiMulti.addAP("SSID", "PASSWORD"); - //WiFi.disconnect(); - while(WiFiMulti.run() != WL_CONNECTED) { - delay(100); - } } void loop() { + // wait for WiFi connection if((WiFiMulti.run() == WL_CONNECTED)) { + httpClient http; - Serial.print("[HTTP] begin...\n"); - + USE_SERIAL.print("[HTTP] begin...\n"); + // configure traged server and url http.begin("192.168.1.12", 80, "/test.html"); - Serial.print("[HTTP] GET...\n"); - if(http.GET()) { + USE_SERIAL.print("[HTTP] GET...\n"); + // start connection and send HTTP header + int httpCode = http.GET(); + if(httpCode) { + // HTTP header has been send and Server response header has been handled - Serial.print("[HTTP] GET... ok.\n"); + USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); - size_t len = http.getSize(); + // file found at server + if(httpCode == 200) { - uint8_t buff[128] = { 0 }; - WiFiClient stream = http.getStream(); - while(http.connected() && len > 0) { - size_t size = stream.available(); - int c = stream.readBytes(buff, ((size > 128) ? 128 : size)); + // get lenght of document (is -1 when Server sends no Content-Length header) + int len = http.getSize(); - Serial.write(buff, c); - len -= c; + // create buffer for read + uint8_t buff[128] = { 0 }; + + // get tcp stream + WiFiClient stream = http.getStream(); + + // read all data from server + while(http.connected() && (len > 0 || len == -1)) { + // get available data size + size_t size = stream.available(); + + if(size) { + // read up to 128 byte + int c = stream.readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); + + // write it to Serial + USE_SERIAL.write(buff, c); + + if(len > 0) { + len -= c; + } + } + delay(1); + } + + USE_SERIAL.println(); + USE_SERIAL.print("[HTTP] connection closed or file end.\n"); - delay(0); } - Serial.println(); - Serial.print("[HTTP] connection closed or file end.\n"); - } else { - - Serial.print("[HTTP] GET... fail.\n"); + USE_SERIAL.print("[HTTP] GET... faild, no connection or no HTTP server\n"); } - - delay(10000); } + + delay(10000); } + From 464b9f2bfbf6499b80b783d8dd7192d7a8bfb55c Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 22 Nov 2015 15:00:14 +0100 Subject: [PATCH 16/33] improve error handling add httpClient::sendRequest ( universal request send ) --- .../src/ESP8266httpClient.cpp | 79 +++++++++++-------- .../ESP8266httpClient/src/ESP8266httpClient.h | 9 +++ 2 files changed, 53 insertions(+), 35 deletions(-) diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp index 125f363e1..3bca9b596 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp @@ -85,18 +85,7 @@ bool httpClient::connected() { * @return http code */ int httpClient::GET() { - - bool status; - status = connect(); - if(status) { - status = sendHeader("GET"); - } - - if(status) { - return handleHeaderResponse(); - } - - return 0; + return sendRequest("GET"); } /** @@ -106,28 +95,45 @@ int httpClient::GET() { * @return http code */ int httpClient::POST(uint8_t * payload, size_t size) { - - bool status; - status = connect(); - if(status) { - addHeader("Content-Length", String(size)); - status = sendHeader("POST"); - } - - if(status) { - status = _tcp->write(&payload[0], size); - } - - if(status) { - return handleHeaderResponse(); - } - return 0; + return sendRequest("POST", payload, size); } int httpClient::POST(String payload) { return POST((uint8_t *) payload.c_str(), payload.length()); } +/** + * sendRequest + * @param type const char * "GET", "POST", .... + * @param payload uint8_t * data for the message body if null not send + * @param size size_t size for the message body if 0 not send + * @return -1 if no info or > 0 when Content-Length is set by server + */ +int httpClient::sendRequest(const char * type, uint8_t * payload, size_t size) { + // connect ro server + if(!connect()) { + return HTTPC_ERROR_CONNECTION_REFUSED; + } + + if(payload && size > 0) { + addHeader("Content-Length", String(size)); + } + + // send Header + if(!sendHeader(type)) { + return HTTPC_ERROR_SEND_HEADER_FAILD; + } + + // send Payload if needed + if(payload && size > 0) { + if(_tcp->write(&payload[0], size) != size) { + return HTTPC_ERROR_SEND_PAYLOAD_FAILD; + } + } + + // handle Server Response (Header) + return handleHeaderResponse(); +} /** * size of message body / payload @@ -145,6 +151,9 @@ WiFiClient & httpClient::getStream(void) { if(connected()) { return *_tcp; } + + DEBUG_HTTPCLIENT("[HTTP-Client] no stream to return!?\n"); + // todo return error? } @@ -210,8 +219,6 @@ bool httpClient::hasHeader(const char* name) { return false; } - - /** * init TCP connection and handle ssl verify if needed * @return true if connection is ok @@ -282,7 +289,7 @@ bool httpClient::sendHeader(const char * type) { int httpClient::handleHeaderResponse() { if(!connected()) { - return false; + return HTTPC_ERROR_NOT_CONNECTED; } while(connected()) { @@ -291,7 +298,7 @@ int httpClient::handleHeaderResponse() { String headerLine = _tcp->readStringUntil('\n'); headerLine.trim(); // remove \r - DEBUG_HTTPCLIENT("[HTTP][handleHeaderResponse] RX: '%s'\n", headerLine.c_str()); + DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] RX: '%s'\n", headerLine.c_str()); if(headerLine.startsWith("HTTP/1.")) { _returnCode = headerLine.substring(9, headerLine.indexOf(' ', 9)).toInt(); @@ -306,16 +313,16 @@ int httpClient::handleHeaderResponse() { for(size_t i = 0; i < _headerKeysCount; i++) { if(_currentHeaders[i].key == headerName) { _currentHeaders[i].value = headerValue; - return true; + break; } } } if(headerLine == "") { - DEBUG_HTTPCLIENT("[HTTP][handleHeaderResponse] code: '%s'\n", String(_returnCode).c_str()); + DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] code: '%s'\n", String(_returnCode).c_str()); if(_size) { - DEBUG_HTTPCLIENT("[HTTP][handleHeaderResponse] size: '%s'\n", String(_size).c_str()); + DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] size: '%s'\n", String(_size).c_str()); } return _returnCode; } @@ -324,4 +331,6 @@ int httpClient::handleHeaderResponse() { delay(0); } } + + return HTTPC_ERROR_CONNECTION_LOST; } diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.h b/libraries/ESP8266httpClient/src/ESP8266httpClient.h index 57f186912..59399b8da 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.h +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.h @@ -33,6 +33,14 @@ #define HTTPCLIENT_TCP_TIMEOUT (1000) +/// HTTP client errors +#define HTTPC_ERROR_CONNECTION_REFUSED (-1) +#define HTTPC_ERROR_SEND_HEADER_FAILD (-2) +#define HTTPC_ERROR_SEND_PAYLOAD_FAILD (-3) +#define HTTPC_ERROR_NOT_CONNECTED (-4) +#define HTTPC_ERROR_CONNECTION_LOST (-5) + + class httpClient { public: httpClient(); @@ -47,6 +55,7 @@ class httpClient { int GET(); int POST(uint8_t * payload, size_t size); int POST(String payload); + int sendRequest(const char * type, uint8_t * payload = NULL, size_t size = 0); void addHeader(const String& name, const String& value, bool first = false); From ca092f47541c4229cf2130f387ecec62ef169f03 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 22 Nov 2015 15:01:38 +0100 Subject: [PATCH 17/33] fix warnings --- libraries/ESP8266httpClient/src/ESP8266httpClient.cpp | 10 +++++----- libraries/ESP8266httpClient/src/ESP8266httpClient.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp index 3bca9b596..b5030de58 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp @@ -182,26 +182,26 @@ void httpClient::collectHeaders(const char* headerKeys[], const size_t headerKey if(_currentHeaders) delete[] _currentHeaders; _currentHeaders = new RequestArgument[_headerKeysCount]; - for(int i = 0; i < _headerKeysCount; i++) { + for(size_t i = 0; i < _headerKeysCount; i++) { _currentHeaders[i].key = headerKeys[i]; } } String httpClient::header(const char* name) { - for(int i = 0; i < _headerKeysCount; ++i) { + for(size_t i = 0; i < _headerKeysCount; ++i) { if(_currentHeaders[i].key == name) return _currentHeaders[i].value; } return String(); } -String httpClient::header(int i) { +String httpClient::header(size_t i) { if(i < _headerKeysCount) return _currentHeaders[i].value; return String(); } -String httpClient::headerName(int i) { +String httpClient::headerName(size_t i) { if(i < _headerKeysCount) return _currentHeaders[i].key; return String(); @@ -212,7 +212,7 @@ int httpClient::headers() { } bool httpClient::hasHeader(const char* name) { - for(int i = 0; i < _headerKeysCount; ++i) { + for(size_t i = 0; i < _headerKeysCount; ++i) { if((_currentHeaders[i].key == name) && (_currentHeaders[i].value.length() > 0)) return true; } diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.h b/libraries/ESP8266httpClient/src/ESP8266httpClient.h index 59399b8da..802a484f7 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.h +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.h @@ -62,8 +62,8 @@ class httpClient { /// Response handling void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); String header(const char* name); // get request header value by name - String header(int i); // get request header value by number - String headerName(int i); // get request header name by number + String header(size_t i); // get request header value by number + String headerName(size_t i); // get request header name by number int headers(); // get header count bool hasHeader(const char* name); // check if header exists From e6c661e7bafe7720725c83e6852ace17e009f892 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 22 Nov 2015 15:34:10 +0100 Subject: [PATCH 18/33] allow reuse of tcp connection to send multiple request to one server add writeToStream function for easy payload usage --- .../reuseConnection/reuseConnection.ino | 65 ++++++++++++ .../src/ESP8266httpClient.cpp | 100 ++++++++++++++++-- .../ESP8266httpClient/src/ESP8266httpClient.h | 8 +- 3 files changed, 165 insertions(+), 8 deletions(-) create mode 100644 libraries/ESP8266httpClient/examples/reuseConnection/reuseConnection.ino diff --git a/libraries/ESP8266httpClient/examples/reuseConnection/reuseConnection.ino b/libraries/ESP8266httpClient/examples/reuseConnection/reuseConnection.ino new file mode 100644 index 000000000..7179b1f82 --- /dev/null +++ b/libraries/ESP8266httpClient/examples/reuseConnection/reuseConnection.ino @@ -0,0 +1,65 @@ +/** + * reuseConnection.ino + * + * Created on: 22.11.2015 + * + */ + + +#include + +#include +#include + +#include + +#define USE_SERIAL Serial1 + +ESP8266WiFiMulti WiFiMulti; + +httpClient http; + +void setup() { + + USE_SERIAL.begin(115200); + // USE_SERIAL.setDebugOutput(true); + + USE_SERIAL.println(); + USE_SERIAL.println(); + USE_SERIAL.println(); + + for(uint8_t t = 4; t > 0; t--) { + USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); + USE_SERIAL.flush(); + delay(1000); + } + + WiFiMulti.addAP("SSID", "PASSWORD"); + + +} + +void loop() { + // wait for WiFi connection + if((WiFiMulti.run() == WL_CONNECTED)) { + + http.begin("192.168.1.12", 80, "/test.html"); + + int httpCode = http.GET(); + if(httpCode) { + USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); + + // file found at server + if(httpCode == 200) { + http.writeToStream(&USE_SERIAL); + } + } else { + USE_SERIAL.print("[HTTP] GET... faild, no connection or no HTTP server\n"); + } + } + + delay(1000); +} + + + diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp index b5030de58..41e3cd7f4 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp @@ -32,11 +32,15 @@ httpClient::httpClient() { _tcp = NULL; _tcps = NULL; + _reuse = false; + _headerKeysCount = 0; _currentHeaders = NULL; _returnCode = 0; _size = -1; + _canReuse = false; + } httpClient::~httpClient() { @@ -52,6 +56,8 @@ httpClient::~httpClient() { void httpClient::begin(const char *host, uint16_t port, const char * url, bool https, const char * httpsFingerprint) { + DEBUG_HTTPCLIENT("[HTTP-Client][begin] host: %s port:%d url: %s https: %d httpsFingerprint: %s\n", host, port, url, https, httpsFingerprint); + _host = host; _port = port; _url = url; @@ -69,6 +75,19 @@ void httpClient::begin(String host, uint16_t port, String url, bool https, Strin begin(host.c_str(), port, url.c_str(), https, httpsFingerprint.c_str()); } +/** + * end + * called after the payload is handeld + */ +void httpClient::end(void) { + if((!_reuse || !_canReuse) && connected()) { + DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp stop \n"); + _tcp->stop(); + } else { + DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp keep open for reuse\n"); + } +} + /** * connected * @return connected status @@ -80,6 +99,16 @@ bool httpClient::connected() { return false; } + +/** + * try to reuse the connection to the server + * keep-alive + * @param reuse bool + */ +void httpClient::setReuse(bool reuse) { + _reuse = reuse; +} + /** * send a GET request * @return http code @@ -157,6 +186,53 @@ WiFiClient & httpClient::getStream(void) { // todo return error? } +/** + * write all message body / payload to Stream + * @param stream Stream * + * @return bytes written + */ +int httpClient::writeToStream(Stream * stream) { + + if(!stream) { + return -1; + } + + // get lenght of document (is -1 when Server sends no Content-Length header) + int len = _size; + int bytesWritten = 0; + + // create buffer for read + uint8_t buff[1460] = { 0 }; + + // read all data from server + while(connected() && (len > 0 || len == -1)) { + + // get available data size + size_t size = _tcp->available(); + + if(size) { + int c = _tcp->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); + + // write it to Stream + bytesWritten += stream->write(buff, c); + + if(len > 0) { + len -= c; + } + } + delay(1); + } + + DEBUG_HTTPCLIENT("[HTTP-Client] connection closed or file end.\n"); + + if(_size && _size != bytesWritten) { + DEBUG_HTTPCLIENT("[HTTP-Client] bytesWritten %d and size %d missmatch!.\n", bytesWritten, _size); + } + + end(); + return bytesWritten; +} + /** * adds Headder to the request * @param name @@ -226,7 +302,7 @@ bool httpClient::hasHeader(const char* name) { bool httpClient::connect(void) { if(connected()) { - DEBUG_HTTPCLIENT("[HTTP-Client] connect. already connected, reuse!\n"); + DEBUG_HTTPCLIENT("[HTTP-Client] connect. already connected, try reuse!\n"); return true; } @@ -235,7 +311,7 @@ bool httpClient::connect(void) { _tcps = new WiFiClientSecure(); _tcp = _tcps; } else { - DEBUG_HTTPCLIENT("[HTTP-Client] connect...\n"); + DEBUG_HTTPCLIENT("[HTTP-Client] connect http...\n"); _tcp = new WiFiClient(); } @@ -277,7 +353,14 @@ bool httpClient::sendHeader(const char * type) { String header = String(type) + " " + _url + " HTTP/1.1\r\n" "Host: " + _host + "\r\n" "User-Agent: ESP8266httpClient\r\n" - "Connection: close\r\n" + _Headers + "\r\n"; + "Connection: "; + + if(_reuse) { + header += "keep-alive"; + } else { + header += "close"; + } + header += "\r\n" + _Headers + "\r\n"; return _tcp->write(header.c_str(), header.length()); } @@ -310,19 +393,22 @@ int httpClient::handleHeaderResponse() { _size = headerValue.toInt(); } + if(headerName.equalsIgnoreCase("Connection")) { + _canReuse = headerValue.equalsIgnoreCase("keep-alive"); + } + for(size_t i = 0; i < _headerKeysCount; i++) { - if(_currentHeaders[i].key == headerName) { + if(_currentHeaders[i].key.equalsIgnoreCase(headerName)) { _currentHeaders[i].value = headerValue; break; } } - } if(headerLine == "") { - DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] code: '%s'\n", String(_returnCode).c_str()); + DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] code: %d\n", _returnCode); if(_size) { - DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] size: '%s'\n", String(_size).c_str()); + DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] size: %d\n", _size); } return _returnCode; } diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.h b/libraries/ESP8266httpClient/src/ESP8266httpClient.h index 802a484f7..794b5c63d 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.h +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.h @@ -48,9 +48,12 @@ class httpClient { void begin(const char *host, uint16_t port, const char * url = "/", bool https = false, const char * httpsFingerprint = ""); void begin(String host, uint16_t port, String url = "/", bool https = false, String httpsFingerprint = ""); + void end(void); bool connected(void); + void setReuse(bool reuse); /// keep-alive + /// request handling int GET(); int POST(uint8_t * payload, size_t size); @@ -71,6 +74,7 @@ class httpClient { int getSize(void); WiFiClient & getStream(void); + int writeToStream(Stream * stream); protected: @@ -86,6 +90,8 @@ class httpClient { /// request handling String _host; uint16_t _port; + bool _reuse; + String _url; bool _https; @@ -99,7 +105,7 @@ class httpClient { int _returnCode; int _size; - + bool _canReuse; bool connect(void); bool sendHeader(const char * type); From be91d96774850155922604b9415678245231eaad Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 22 Nov 2015 15:46:23 +0100 Subject: [PATCH 19/33] improve debug out and error handling --- .../src/ESP8266httpClient.cpp | 29 +++++++++++++------ .../ESP8266httpClient/src/ESP8266httpClient.h | 1 + 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp index 41e3cd7f4..117901d40 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp @@ -80,11 +80,15 @@ void httpClient::begin(String host, uint16_t port, String url, bool https, Strin * called after the payload is handeld */ void httpClient::end(void) { - if((!_reuse || !_canReuse) && connected()) { - DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp stop \n"); - _tcp->stop(); + if(connected()) { + if(_reuse && _canReuse) { + DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp keep open for reuse\n"); + } else { + DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp stop\n"); + _tcp->stop(); + } } else { - DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp keep open for reuse\n"); + DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp is closed\n"); } } @@ -189,12 +193,16 @@ WiFiClient & httpClient::getStream(void) { /** * write all message body / payload to Stream * @param stream Stream * - * @return bytes written + * @return bytes written ( negative values are error codes ) */ int httpClient::writeToStream(Stream * stream) { if(!stream) { - return -1; + return HTTPC_ERROR_NO_STREAM; + } + + if(!connected()) { + return HTTPC_ERROR_NOT_CONNECTED; } // get lenght of document (is -1 when Server sends no Content-Length header) @@ -219,14 +227,17 @@ int httpClient::writeToStream(Stream * stream) { if(len > 0) { len -= c; } + + delay(0); + } else { + delay(1); } - delay(1); } - DEBUG_HTTPCLIENT("[HTTP-Client] connection closed or file end.\n"); + DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] connection closed or file end (written: %d).\n", bytesWritten); if(_size && _size != bytesWritten) { - DEBUG_HTTPCLIENT("[HTTP-Client] bytesWritten %d and size %d missmatch!.\n", bytesWritten, _size); + DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] bytesWritten %d and size %d missmatch!.\n", bytesWritten, _size); } end(); diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.h b/libraries/ESP8266httpClient/src/ESP8266httpClient.h index 794b5c63d..5421acf22 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.h +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.h @@ -39,6 +39,7 @@ #define HTTPC_ERROR_SEND_PAYLOAD_FAILD (-3) #define HTTPC_ERROR_NOT_CONNECTED (-4) #define HTTPC_ERROR_CONNECTION_LOST (-5) +#define HTTPC_ERROR_NO_STREAM (-6) class httpClient { From 34fcc911bc57840ff667a12b8ee92cf238722595 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Sun, 22 Nov 2015 15:57:32 +0100 Subject: [PATCH 20/33] Url decode added for search parameters --- .../ESP8266WebServer/src/ESP8266WebServer.h | 1 + libraries/ESP8266WebServer/src/Parsing.cpp | 33 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index 65e44378f..e6b9259c2 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -132,6 +132,7 @@ protected: uint8_t _uploadReadByte(WiFiClient& client); void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength); bool _collectHeader(const char* headerName, const char* headerValue); + String urlDecode(const String& text); struct RequestArgument { String key; diff --git a/libraries/ESP8266WebServer/src/Parsing.cpp b/libraries/ESP8266WebServer/src/Parsing.cpp index 0458a9980..a30ea60fa 100644 --- a/libraries/ESP8266WebServer/src/Parsing.cpp +++ b/libraries/ESP8266WebServer/src/Parsing.cpp @@ -255,7 +255,7 @@ void ESP8266WebServer::_parseArguments(String data) { } RequestArgument& arg = _currentArgs[iarg]; arg.key = data.substring(pos, equal_sign_index); - arg.value = data.substring(equal_sign_index + 1, next_arg_index); + arg.value = urlDecode(data.substring(equal_sign_index + 1, next_arg_index)); #ifdef DEBUG DEBUG_OUTPUT.print("arg "); DEBUG_OUTPUT.print(iarg); @@ -501,6 +501,37 @@ readfile: return false; } +String ESP8266WebServer::urlDecode(const String& text) +{ + String decoded = ""; + char temp[] = "0x00"; + unsigned int len = text.length(); + unsigned int i = 0; + while (i < len) + { + char decodedChar; + char encodedChar = text.charAt(i++); + if ((encodedChar == '%') && (i + 1 < len)) + { + temp[2] = text.charAt(i++); + temp[3] = text.charAt(i++); + + decodedChar = strtol(temp, NULL, 16); + } + else { + if (encodedChar == '+') + { + decodedChar = ' '; + } + else { + decodedChar = encodedChar; // normal ascii char + } + } + decoded += decodedChar; + } + return decoded; +} + bool ESP8266WebServer::_parseFormUploadAborted(){ _currentUpload.status = UPLOAD_FILE_ABORTED; if (_fileUploadHandler) _fileUploadHandler(); From 6ed7dfe537da5d7a2ae08dab08ba6655f4d084b7 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 22 Nov 2015 15:58:15 +0100 Subject: [PATCH 21/33] improve handling of non http servers --- libraries/ESP8266httpClient/src/ESP8266httpClient.cpp | 10 +++++++++- libraries/ESP8266httpClient/src/ESP8266httpClient.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp index 117901d40..d7f5ec80d 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp @@ -386,6 +386,9 @@ int httpClient::handleHeaderResponse() { return HTTPC_ERROR_NOT_CONNECTED; } + _returnCode = -1; + _size = -1; + while(connected()) { size_t len = _tcp->available(); if(len > 0) { @@ -421,7 +424,12 @@ int httpClient::handleHeaderResponse() { if(_size) { DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] size: %d\n", _size); } - return _returnCode; + if(_returnCode) { + return _returnCode; + } else { + DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] Remote host is not an HTTP Server!"); + return HTTPC_ERROR_NO_HTTP_SERVER; + } } } else { diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.h b/libraries/ESP8266httpClient/src/ESP8266httpClient.h index 5421acf22..ddc0cea35 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.h +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.h @@ -40,6 +40,7 @@ #define HTTPC_ERROR_NOT_CONNECTED (-4) #define HTTPC_ERROR_CONNECTION_LOST (-5) #define HTTPC_ERROR_NO_STREAM (-6) +#define HTTPC_ERROR_NO_HTTP_SERVER (-7) class httpClient { From 497ab250406c8591ab1abb620c16224588ff7517 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 22 Nov 2015 16:37:29 +0100 Subject: [PATCH 22/33] fix some memory leek still looses 40Byte some where?! --- .../src/ESP8266httpClient.cpp | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp index d7f5ec80d..1e27af2a3 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp @@ -28,6 +28,9 @@ #include "ESP8266httpClient.h" +/** + * constractor + */ httpClient::httpClient() { _tcp = NULL; _tcps = NULL; @@ -43,17 +46,35 @@ httpClient::httpClient() { } +/** + * deconstractor + */ httpClient::~httpClient() { - if(connected()) { + + if(_tcps) { + _tcps->stop(); + _tcps->~WiFiClientSecure(); + _tcps = NULL; + _tcp = NULL; + } else if(_tcp) { _tcp->stop(); + _tcp->~WiFiClient(); + _tcp = NULL; } if(_currentHeaders) { delete[] _currentHeaders; } - _headerKeysCount = 0; } +/** + * begin + * @param host const char * + * @param port uint16_t + * @param url const char * + * @param https bool + * @param httpsFingerprint const char * + */ void httpClient::begin(const char *host, uint16_t port, const char * url, bool https, const char * httpsFingerprint) { DEBUG_HTTPCLIENT("[HTTP-Client][begin] host: %s port:%d url: %s https: %d httpsFingerprint: %s\n", host, port, url, https, httpsFingerprint); @@ -98,7 +119,7 @@ void httpClient::end(void) { */ bool httpClient::connected() { if(_tcp) { - return _tcp->connected(); + return (_tcp->connected() || (_tcp->available() > 0)); } return false; } @@ -317,12 +338,22 @@ bool httpClient::connect(void) { return true; } + if(_https) { DEBUG_HTTPCLIENT("[HTTP-Client] connect https...\n"); + if(_tcps) { + _tcps->~WiFiClient(); + _tcps = NULL; + _tcp = NULL; + } _tcps = new WiFiClientSecure(); _tcp = _tcps; } else { DEBUG_HTTPCLIENT("[HTTP-Client] connect http...\n"); + if(_tcp) { + _tcp->~WiFiClient(); + _tcp = NULL; + } _tcp = new WiFiClient(); } From a5aa33f81a5eecb1aaca36a3481e27e54f7838b2 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 22 Nov 2015 22:39:31 +0100 Subject: [PATCH 23/33] disable DEBUGV --- cores/esp8266/debug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp8266/debug.h b/cores/esp8266/debug.h index 9cf5980ef..98bdaf03c 100644 --- a/cores/esp8266/debug.h +++ b/cores/esp8266/debug.h @@ -4,7 +4,7 @@ #include #include -#define DEBUGV(...) ets_printf(__VA_ARGS__) +//#define DEBUGV(...) ets_printf(__VA_ARGS__) #ifndef DEBUGV #define DEBUGV(...) From c8aac83c4723601ce4ff97db619eafb3a80d9435 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Sun, 22 Nov 2015 22:39:58 +0100 Subject: [PATCH 24/33] add :del message to unref --- libraries/ESP8266WiFi/src/include/ClientContext.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/ESP8266WiFi/src/include/ClientContext.h b/libraries/ESP8266WiFi/src/include/ClientContext.h index f4dfae09d..283fa1057 100644 --- a/libraries/ESP8266WiFi/src/include/ClientContext.h +++ b/libraries/ESP8266WiFi/src/include/ClientContext.h @@ -97,6 +97,7 @@ class ClientContext { close(); if(_discard_cb) _discard_cb(_discard_cb_arg, this); + DEBUGV(":del\r\n"); delete this; } } From 866921c54a889a7cb96cc3c24c304d6809dbb603 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 23 Nov 2015 20:21:16 +0300 Subject: [PATCH 25/33] Documentation update --- doc/boards.md | 81 +++--- doc/changes.md | 2 +- doc/filesystem.md | 253 +++++++++++++++++++ doc/installing.md | 80 ++++++ doc/libraries.md | 153 ++++++++++++ doc/ota_updates/ota_updates.md | 154 ++++++------ doc/reference.md | 408 +------------------------------ doc/reference_items.yml | 15 ++ package/esp8266-arudino-doc.bash | 15 +- 9 files changed, 642 insertions(+), 519 deletions(-) create mode 100644 doc/filesystem.md create mode 100644 doc/installing.md create mode 100644 doc/libraries.md create mode 100644 doc/reference_items.yml diff --git a/doc/boards.md b/doc/boards.md index 9aec334de..5c3104be6 100644 --- a/doc/boards.md +++ b/doc/boards.md @@ -2,24 +2,36 @@ title: Supported Hardware --- -- [Adafruit HUZZAH ESP8266 (ESP-12)](#adafruit-huzzah-esp8266-esp-12) -- [NodeMCU 0.9](#nodemcu-0-9) -- [NodeMCU 1.0](#nodemcu-1-0) -- [Olimex MOD-WIFI-ESP8266-DEV](#olimex-mod-wifi-esp8266-dev) -- [Olimex MOD-WIFI-ESP8266](#olimex-mod-wifi-esp8266) -- [SparkFun ESP8266 Thing](#sparkfun-esp8266-thing) -- [SweetPea ESP-210](#sweetpea-esp-210) -- [Generic ESP8266 modules](#generic-esp8266-modules) -- [WeMos D1](#wemos-d1) -- [WeMos D1 mini](#wemos-d1-mini) +## Table of contents + * [Adafruit HUZZAH ESP8266 (ESP\-12)](#adafruit-huzzah-esp8266-esp-12) + * [NodeMCU 0\.9
](#nodemcu-09-) + * [Pin mapping](#pin-mapping) + * [NodeMCU 1\.0](#nodemcu-10) + * [Olimex MOD\-WIFI\-ESP8266\-DEV](#olimex-mod-wifi-esp8266-dev) + * [Olimex MOD\-WIFI\-ESP8266](#olimex-mod-wifi-esp8266) + * [SparkFun ESP8266 Thing](#sparkfun-esp8266-thing) + * [SweetPea ESP\-210](#sweetpea-esp-210) + * [Generic ESP8266 modules](#generic-esp8266-modules) + * [Serial Adapter](#serial-adapter) + * [Minimal Hardware Setup for Bootloading and Usage](#minimal-hardware-setup-for-bootloading-and-usage) + * [ESP to Serial](#esp-to-serial) + * [Minimal Hardware Setup for Bootloading only](#minimal-hardware-setup-for-bootloading-only) + * [Minimal Hardware Setup for Running only](#minimal-hardware-setup-for-running-only) + * [Minimal](#minimal) + * [Improved Stability](#improved-stability) + * [Boot Messages and Modes](#boot-messages-and-modes) + * [rst cause](#rst-cause) + * [boot mode](#boot-mode) + * [WeMos D1](#wemos-d1) + * [WeMos D1 mini](#wemos-d1-mini) -### Adafruit HUZZAH ESP8266 (ESP-12) +## Adafruit HUZZAH ESP8266 (ESP-12) *TODO: add notes* -### NodeMCU 0.9 +## NodeMCU 0.9 -#### Pin mapping +### Pin mapping Pin numbers written on the board itself do not correspond to ESP8266 GPIO pin numbers. Constants are defined to make using this board easier: @@ -39,7 +51,7 @@ static const uint8_t D10 = 1; If you want to use NodeMCU pin 5, use D5 for pin number, and it will be translated to 'real' GPIO pin 14. -### NodeMCU 1.0 +## NodeMCU 1.0 This module is sold under many names for around $6.50 on AliExpress and it's one of the cheapest, fully integrated ESP8266 solutions. @@ -51,7 +63,7 @@ The board also features a NCP1117 voltage regulator, a blue LED on GPIO16 and a Full pinout and PDF schematics can be found [here](https://github.com/nodemcu/nodemcu-devkit-v1.0) -### Olimex MOD-WIFI-ESP8266-DEV +## Olimex MOD-WIFI-ESP8266-DEV This board comes with 2 MB of SPI flash and optional accessories (e.g. evaluation board ESP8266-EVB or BAT-BOX for batteries). @@ -65,21 +77,21 @@ UART pins for programming and serial I/O are GPIO1 (TXD, pin 3) and GPIO3 (RXD, Get the board schematics [here](https://github.com/OLIMEX/ESP8266/blob/master/HARDWARE/MOD-WIFI-ESP8266-DEV/MOD-WIFI-ESP8266-DEV_schematic.pdf) -### Olimex MOD-WIFI-ESP8266 +## Olimex MOD-WIFI-ESP8266 This is a stripped down version of the above. Behaves identically in terms of jumpers but has less pins readily available for I/O. Still 2 MB of SPI flash. -### SparkFun ESP8266 Thing ### +## SparkFun ESP8266 Thing ### Product page: https://www.sparkfun.com/products/13231 *TODO: add notes* -### SweetPea ESP-210 +## SweetPea ESP-210 *TODO: add notes* -### Generic ESP8266 modules +## Generic ESP8266 modules These modules come in different form factors and pinouts. See the page at ESP8266 community wiki for more info: [ESP8266 Module Family](http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family). @@ -94,10 +106,10 @@ In order to use these modules, make sure to observe the following: - **Put ESP8266 into bootloader mode** before uploading code. -### Serial Adapter +## Serial Adapter There are many different USB to Serial adapters / boards. -To be able to put ESP8266 into bootloader mode using serial handshaking lines, you need the adapter which breaks out RTS and DTR outputs. CTS and DSR are not useful for upload (they are inputs). Make sure the adapter can work with 3.3V IO voltage: it should have a jumper or a switch to select between 5V and 3.3V, or be marked as 3.3V only. +To be able to put ESP8266 into bootloader mode using serial handshaking lines, you need the adapter which breaks out RTS and DTR outputs. CTS and DSR are not useful for upload (they are inputs). Make sure the adapter can work with 3.3V IO voltage: it should have a jumper or a switch to select between 5V and 3.3V, or be marked as 3.3V only. Adapters based around the following ICs should work: @@ -107,7 +119,7 @@ Adapters based around the following ICs should work: PL2303-based adapters are known not to work on Mac OS X. See https://github.com/igrr/esptool-ck/issues/9 for more info. -### Minimal Hardware Setup for Bootloading and Usage +## Minimal Hardware Setup for Bootloading and Usage | PIN | Resistor | Serial Adapter | @@ -127,10 +139,10 @@ PL2303-based adapters are known not to work on Mac OS X. See https://github.com/ - GPIO2 is alternative TX for the boot loader mode - **Directly connecting a pin to VCC or GND is not a substitute for a PullUp or PullDown resistor, doing this can break upload management and the serial console, instability has also been noted in some cases.** -### ESP to Serial +## ESP to Serial ![ESP to Serial](ESP_to_serial.png) -#### Minimal Hardware Setup for Bootloading only ## +### Minimal Hardware Setup for Bootloading only ## ESPxx Hardware | PIN | Resistor | Serial Adapter | @@ -147,7 +159,7 @@ ESPxx Hardware * Note - if no RTS is used a manual power toggle is needed -#### Minimal Hardware Setup for Running only ## +### Minimal Hardware Setup for Running only ## ESPxx Hardware @@ -159,13 +171,13 @@ ESPxx Hardware | GPIO15 | PullDown | | | CH_PD | PullUp | | -### Minimal +## Minimal ![ESP min](ESP_min.png) -### Improved Stability +## Improved Stability ![ESP improved stability](ESP_improved_stability.png) -### Boot Messages and Modes +## Boot Messages and Modes The ESP module checks at every boot the Pins 0, 2 and 15. based on them its boots in different modes: @@ -182,10 +194,10 @@ at startup the ESP prints out the current boot mode example: rst cause:2, boot mode:(3,6) ``` -note: +note: - GPIO2 is used as TX output and the internal Pullup is enabled on boot. -#### rst cause +### rst cause | Number | Description | | ------ | ---------------------- | @@ -193,10 +205,10 @@ note: | 1 | normal boot | | 2 | reset pin | | 3 | software reset | -| 4 | watchdog reset | +| 4 | watchdog reset | -#### boot mode +### boot mode the first value respects the pin setup of the Pins 0, 2 and 15. @@ -214,7 +226,8 @@ the first value respects the pin setup of the Pins 0, 2 and 15. note: - number = ((GPIO15 << 2) | (GPIO0 << 1) | GPIO2); -### WeMos D1 +## WeMos D1 Product page: http://wemos.cc -### WeMos D1 mini + +## WeMos D1 mini Product page: http://wemos.cc diff --git a/doc/changes.md b/doc/changes.md index bed3d0da6..b9b440c91 100644 --- a/doc/changes.md +++ b/doc/changes.md @@ -1,5 +1,5 @@ --- -title: Change log +title: Change Log --- *Current release* diff --git a/doc/filesystem.md b/doc/filesystem.md new file mode 100644 index 000000000..31aa148ab --- /dev/null +++ b/doc/filesystem.md @@ -0,0 +1,253 @@ +--- +title: File System +--- + +## Table of Contents + * [Flash layout](#flash-layout) + * [Uploading files to file system](#uploading-files-to-file-system) + * [File system object (SPIFFS)](#file-system-object-spiffs) + * [begin](#begin) + * [format](#format) + * [open](#open) + * [exists](#exists) + * [openDir](#opendir) + * [remove](#remove) + * [rename](#rename) + * [info](#info) + * [Filesystem information structure](#filesystem-information-structure) + * [Directory object (Dir)](#directory-object-dir) + * [File object](#file-object) + * [seek](#seek) + * [position](#position) + * [size](#size) + * [name](#name) + * [close](#close) + + +## Flash layout + +Even though file system is stored on the same flash chip as the program, programming new sketch will not modify file system contents. This allows to use file system to store sketch data, configuration files, or content for Web server. + +The following diagram illustrates flash layout used in Arduino environment: + + |--------------|-------|---------------|--|--|--|--|--| + ^ ^ ^ ^ ^ + Sketch OTA update File system EEPROM WiFi config (SDK) + +File system size depends on the flash chip size. Depending on the board which is selected in IDE, you have the following options for flash size: + +Board | Flash chip size, bytes | File system size, bytes +------|-----------------|----------------- +Generic module | 512k | 64k +Generic module | 1M | 64k, 128k, 256k, 512k +Generic module | 2M | 1M +Generic module | 4M | 3M +Adafruit HUZZAH | 4M | 1M, 3M +NodeMCU 0.9 | 4M | 1M, 3M +NodeMCU 1.0 | 4M | 1M, 3M +Olimex MOD-WIFI-ESP8266(-DEV)| 2M | 1M +SparkFun Thing | 512k | 64k +SweetPea ESP-210 | 4M | 1M, 3M +WeMos D1 & D1 mini | 4M | 1M, 3M + +**Note:** to use any of file system functions in the sketch, add the following include to the sketch: + +```c++ +#include "FS.h" +``` + +## Uploading files to file system + +*ESP8266FS* is a tool which integrates into the Arduino IDE. It adds a menu item to *Tools* menu for uploading the contents of sketch data directory into ESP8266 flash file system. + +- Download the tool: https://github.com/esp8266/arduino-esp8266fs-plugin/releases/download/0.1.3/ESP8266FS-0.1.3.zip. +- In your Arduino sketchbook directory, create `tools` directory if it doesn't exist yet +- Unpack the tool into `tools` directory (the path will look like `/Arduino/tools/ESP8266FS/tool/esp8266fs.jar`) +- Restart Arduino IDE +- Open a sketch (or create a new one and save it) +- Go to sketch directory (choose Sketch > Show Sketch Folder) +- Create a directory named `data` and any files you want in the file system there +- Make sure you have selected a board, port, and closed Serial Monitor +- Select Tools > ESP8266 Sketch Data Upload. This should start uploading the files into ESP8266 flash file system. When done, IDE status bar will display `SPIFFS Image Uploaded` message. + + +## File system object (SPIFFS) + +### begin + +```c++ +SPIFFS.begin() +``` + +This method mounts SPIFFS file system. It must be called before any other +FS APIs are used. Returns *true* if file system was mounted successfully, false +otherwise. + +### format + +```c++ +SPIFFS.format() +``` + +Formats the file system. May be called either before or after calling `begin`. +Returns *true* if formatting was successful. + +### open + +```c++ +SPIFFS.open(path, mode) +``` + +Opens a file. `path` should be an absolute path starting with a slash +(e.g. `/dir/filename.txt`). `mode` is a string specifying access mode. It can be +one of "r", "w", "a", "r+", "w+", "a+". Meaning of these modes is the same as +for `fopen` C function. + +Returns *File* object. To check whether the file was opened successfully, use +the boolean operator. + +```c++ +File f = SPIFFS.open("/f.txt", "w"); +if (!f) { + Serial.println("file open failed"); +} +``` + +### exists + +```c++ +SPIFFS.exists(path) +``` + +Returns *true* if a file with given path exists, *false* otherwise. + +### openDir + +```c++ +SPIFFS.openDir(path) +``` + +Opens a directory given its absolute path. Returns a *Dir* object. To check if +directory was opened successfully, use the boolean operator, similar to opening +a file. + +### remove + +```c++ +SPIFFS.remove(path) +``` + +Deletes the file given its absolute path. Returns *true* if file was deleted successfully. + +### rename + +```c++ +SPIFFS.rename(pathFrom, pathTo) +``` + +Renames file from `pathFrom` to `pathTo`. Paths must be absolute. Returns *true* +if file was renamed successfully. + +### info + +```c++ +FSInfo fs_info; +SPIFFS.info(fs_info); +``` + +Fills [FSInfo structure](#filesystem-information-structure) with information about +the file system. Returns `true` is successful, `false` otherwise. + +## Filesystem information structure + +```c++ +struct FSInfo { + size_t totalBytes; + size_t usedBytes; + size_t blockSize; + size_t pageSize; + size_t maxOpenFiles; + size_t maxPathLength; +}; +``` + +This is the structure which may be filled using FS::info method. Field names +are self-explanatory. + +## Directory object (Dir) + +The purpose of *Dir* object is to iterate over files inside a directory. +It provides three methods: `next()`, `fileName()`, and `openFile(mode)`. + +The following example shows how it should be used: + +```c++ +Dir dir = SPIFFS.openDir("/data"); +while (dir.next()) { + Serial.print(dir.fileName()); + File f = dir.openFile("r"); + Serial.println(f.size()); +} +``` + +`dir.next()` returns true while there are files in the directory to iterate over. +It must be called before calling `fileName` and `openFile` functions. + +`openFile` method takes *mode* argument which has the same meaning as for `SPIFFS.open` function. + +## File object + +`SPIFFS.open` and `dir.openFile` functions return a *File* object. This object +supports all the functions of *Stream*, so you can use `readBytes`, `findUntil`, +`parseInt`, `println`, and all other *Stream* methods. + +There are also some functions which are specific to *File* object. + +### seek + +```c++ +file.seek(offset, mode) +``` + +This function behaves like `fseek` C function. Depending on the value of `mode`, +it moves current position in a file as follows: + +- if `mode` is `SeekSet`, position is set to `offset` bytes from the beginning. +- if `mode` is `SeekCur`, current position is moved by `offset` bytes. +- if `mode` is `SeekEnd`, position is set to `offset` bytes from the end of the +file. + +Returns *true* if position was set successfully. + +### position + +```c++ +file.position() +``` + +Returns the current position inside the file, in bytes. + +### size + +```c++ +file.size() +``` + +Returns file size, in bytes. + + +### name + +```c++ +String name = file.name(); +``` + +Returns file name, as `const char*`. Convert it to *String* for storage. + +### close + +```c++ +file.close() +``` + +Close the file. No other operations should be performed on *File* object after `close` function was called. diff --git a/doc/installing.md b/doc/installing.md new file mode 100644 index 000000000..16ba27a00 --- /dev/null +++ b/doc/installing.md @@ -0,0 +1,80 @@ +--- +title: Installation +--- + +## Boards Manager ## + +This is the suggested installation method for end users. + +### Prerequisites +- Arduino 1.6.5, get it from [Arduino website](https://www.arduino.cc/en/Main/OldSoftwareReleases#previous). Arduino 1.6.6 has several issues, so we recommend to stick with 1.6.5 for now. +- Internet connection + +### Instructions +- Start Arduino and open Preferences window. +- Enter ```http://arduino.esp8266.com/stable/package_esp8266com_index.json``` into *Additional Board Manager URLs* field. You can add multiple URLs, separating them with commas. +- Open Boards Manager from Tools > Board menu and find *esp8266* platform. +- Select the version you need from a drop-down box. +- Click *install* button. +- Don't forget to select your ESP8266 board from Tools > Board menu after installation. + +You may optionally use *staging* boards manager package link: +`http://arduino.esp8266.com/staging/package_esp8266com_index.json`. This may contain some new features, but at the same time, some things might be broken. + +## Using git version + +This is the suggested installation method for contributors and library developers. + +### Prerequisites + +- Arduino 1.6.5 (or newer, if you know what you are doing) +- git +- python 2.7 +- terminal, console, or command prompt (depending on you OS) +- Internet connection + +### Instructions + +- Open the console and go to Arduino directory. This can be either your *sketchbook* directory (usually `/Arduino`), or the directory of Arduino application itself, the choice is up to you. +- Clone this repository into hardware/esp8266com/esp8266 directory. Alternatively, clone it elsewhere and create a symlink, if your OS supports them. + + ```bash + cd hardware + mkdir esp8266com + cd esp8266com + git clone https://github.com/esp8266/Arduino.git esp8266 + ``` + You should end up with the following directory structure: + + ```bash + Arduino + | + --- hardware + | + --- esp8266com + | + --- esp8266 + | + --- bootloaders + --- cores + --- doc + --- libraries + --- package + --- tests + --- tools + --- variants + --- platform.txt + --- programmers.txt + --- README.md + --- boards.txt + --- LICENSE + ``` + +- Download binary tools + + ```bash + cd esp8266/tools + python get.py + ``` + +- Restart Arduino diff --git a/doc/libraries.md b/doc/libraries.md new file mode 100644 index 000000000..210ef2f81 --- /dev/null +++ b/doc/libraries.md @@ -0,0 +1,153 @@ +--- +title: Libraries +--- + +## Table of Contents + * [WiFi(ESP8266WiFi library)](#wifiesp8266wifi-library) + * [Ticker](#ticker) + * [EEPROM](#eeprom) + * [I2C (Wire library)](#i2c-wire-library) + * [SPI](#spi) + * [SoftwareSerial](#softwareserial) + * [ESP\-specific APIs](#esp-specific-apis) + * [OneWire](#onewire) + * [mDNS and DNS\-SD responder (ESP8266mDNS library)](#mdns-and-dns-sd-responder-esp8266mdns-library) + * [SSDP responder (ESP8266SSDP)](#ssdp-responder-esp8266ssdp) + * [DNS server (DNSServer library)](#dns-server-dnsserver-library) + * [Servo](#servo) + * [Other libraries (not included with the IDE)](#other-libraries-not-included-with-the-ide) + +## WiFi(ESP8266WiFi library) + +This is mostly similar to WiFi shield library. Differences include: + +- `WiFi.mode(m)`: set mode to `WIFI_AP`, `WIFI_STA`, `WIFI_AP_STA` or `WIFI_OFF`. +- call `WiFi.softAP(ssid)` to set up an open network +- call `WiFi.softAP(ssid, password)` to set up a WPA2-PSK network (password should be at least 8 characters) +- `WiFi.macAddress(mac)` is for STA, `WiFi.softAPmacAddress(mac)` is for AP. +- `WiFi.localIP()` is for STA, `WiFi.softAPIP()` is for AP. +- `WiFi.printDiag(Serial)` will print out some diagnostic info +- `WiFiUDP` class supports sending and receiving multicast packets on STA interface. +When sending a multicast packet, replace `udp.beginPacket(addr, port)` with +`udp.beginPacketMulticast(addr, port, WiFi.localIP())`. +When listening to multicast packets, replace `udp.begin(port)` with +`udp.beginMulticast(WiFi.localIP(), multicast_ip_addr, port)`. +You can use `udp.destinationIP()` to tell whether the packet received was +sent to the multicast or unicast address. + +`WiFiServer`, `WiFiClient`, and `WiFiUDP` behave mostly the same way as with WiFi shield library. +Four samples are provided for this library. +You can see more commands here: [http://www.arduino.cc/en/Reference/WiFi](http://www.arduino.cc/en/Reference/WiFi) + +## Ticker + +Library for calling functions repeatedly with a certain period. Two examples included. + +It is currently not recommended to do blocking IO operations (network, serial, file) from Ticker +callback functions. Instead, set a flag inside the ticker callback and check for that flag inside the loop function. + +## EEPROM + +This is a bit different from standard EEPROM class. You need to call `EEPROM.begin(size)` +before you start reading or writing, size being the number of bytes you want to use. +Size can be anywhere between 4 and 4096 bytes. + +`EEPROM.write` does not write to flash immediately, instead you must call `EEPROM.commit()` +whenever you wish to save changes to flash. `EEPROM.end()` will also commit, and will +release the RAM copy of EEPROM contents. + +EEPROM library uses one sector of flash located just after the SPIFFS. + +Three examples included. + +## I2C (Wire library) + +Wire library currently supports master mode up to approximately 450KHz. +Before using I2C, pins for SDA and SCL need to be set by calling +`Wire.begin(int sda, int scl)`, i.e. `Wire.begin(0, 2)` on ESP-01, +else they default to pins 4(SDA) and 5(SCL). + +## SPI + +SPI library supports the entire Arduino SPI API including transactions, including setting phase (CPHA). +Setting the Clock polarity (CPOL) is not supported, yet (SPI_MODE2 and SPI_MODE3 not working). + +## SoftwareSerial + +An ESP8266 port of SoftwareSerial library done by Peter Lerup (@plerup) supports baud rate up to 115200 and multiples SoftwareSerial instances. See https://github.com/plerup/espsoftwareserial if you want to suggest an improvement or open an issue related to SoftwareSerial. + +## ESP-specific APIs + +APIs related to deep sleep and watchdog timer are available in the `ESP` object, only available in Alpha version. + +`ESP.deepSleep(microseconds, mode)` will put the chip into deep sleep. `mode` is one of `WAKE_RF_DEFAULT`, `WAKE_RFCAL`, `WAKE_NO_RFCAL`, `WAKE_RF_DISABLED`. (GPIO16 needs to be tied to RST to wake from deepSleep.) + +`ESP.restart()` restarts the CPU. + +`ESP.getFreeHeap()` returns the free heap size. + +`ESP.getChipId()` returns the ESP8266 chip ID as a 32-bit integer. + +Several APIs may be used to get flash chip info: + +`ESP.getFlashChipId()` returns the flash chip ID as a 32-bit integer. + +`ESP.getFlashChipSize()` returns the flash chip size, in bytes, as seen by the SDK (may be less than actual size). + +`ESP.getFlashChipSpeed(void)` returns the flash chip frequency, in Hz. + +`ESP.getCycleCount()` returns the cpu instruction cycle count since start as an unsigned 32-bit. This is useful for accurate timing of very short actions like bit banging. + +`ESP.getVcc()` may be used to measure supply voltage. ESP needs to reconfigure the ADC +at startup in order for this feature to be available. Add the following line to the top +of your sketch to use `getVcc`: + +```c++ +ADC_MODE(ADC_VCC); +``` + +TOUT pin has to be disconnected in this mode. + +Note that by default ADC is configured to read from TOUT pin using `analogRead(A0)`, and +`ESP.getVCC()` is not available. + +## OneWire + +Library was adapted to work with ESP8266 by including register definitions into OneWire.h +Note that if you already have OneWire library in your Arduino/libraries folder, it will be used +instead of the one that comes with this package. + +## mDNS and DNS-SD responder (ESP8266mDNS library) + +Allows the sketch to respond to multicast DNS queries for domain names like "foo.local", and DNS-SD (service dicovery) queries. +See attached example for details. + +## SSDP responder (ESP8266SSDP) + +SSDP is another service discovery protocol, supported on Windows out of the box. See attached example for reference. + +## DNS server (DNSServer library) + +Implements a simple DNS server that can be used in both STA and AP modes. The DNS server currently supports only one domain (for all other domains it will reply with NXDOMAIN or custom status code). With it clients can open a web server running on ESP8266 using a domain name, not an IP address. +See attached example for details. + +## Servo + +This library exposes the ability to control RC (hobby) servo motors. It will support upto 24 servos on any available output pin. By defualt the first 12 servos will use Timer0 and currently this will not interfere with any other support. Servo counts above 12 will use Timer1 and features that use it will be effected. +While many RC servo motors will accept the 3.3V IO data pin from a ESP8266, most will not be able to run off 3.3v and will require another power source that matches their specifications. Make sure to connect the grounds between the ESP8266 and the servo motor power supply. + +## Other libraries (not included with the IDE) + +Libraries that don't rely on low-level access to AVR registers should work well. Here are a few libraries that were verified to work: + +- [arduinoWebSockets](https://github.com/Links2004/arduinoWebSockets) - WebSocket Server and Client compatible with ESP8266 (RFC6455) +- [aREST](https://github.com/marcoschwartz/aREST) REST API handler library. +- [Blynk](https://github.com/blynkkk/blynk-library) - easy IoT framework for Makers (check out the [Kickstarter page](http://tiny.cc/blynk-kick)). +- [DallasTemperature](https://github.com/milesburton/Arduino-Temperature-Control-Library.git) +- [DHT-sensor-library](https://github.com/adafruit/DHT-sensor-library) - Arduino library for the DHT11/DHT22 temperature and humidity sensors. Download latest v1.1.1 library and no changes are necessary. Older versions should initialize DHT as follows: `DHT dht(DHTPIN, DHTTYPE, 15)` +- [NeoPixel](https://github.com/adafruit/Adafruit_NeoPixel) - Adafruit's NeoPixel library, now with support for the ESP8266 (use version 1.0.2 or higher from Arduino's library manager). +- [NeoPixelBus](https://github.com/Makuna/NeoPixelBus) - Arduino NeoPixel library compatible with ESP8266. Use the "NeoPixelAnimator" branch for ESP8266 to get HSL color support and more. +- [PubSubClient](https://github.com/Imroy/pubsubclient) MQTT library by @Imroy. +- [RTC](https://github.com/Makuna/Rtc) - Arduino Library for Ds1307 & Ds3231 compatible with ESP8266. +- [Souliss, Smart Home](https://github.com/souliss/souliss) - Framework for Smart Home based on Arduino, Android and openHAB. +- [ST7735](https://github.com/nzmichaelh/Adafruit-ST7735-Library) - Adafruit's ST7735 library modified to be compatible with ESP8266. Just make sure to modify the pins in the examples as they are still AVR specific. diff --git a/doc/ota_updates/ota_updates.md b/doc/ota_updates/ota_updates.md index bac75e9ec..b7963a114 100644 --- a/doc/ota_updates/ota_updates.md +++ b/doc/ota_updates/ota_updates.md @@ -3,22 +3,29 @@ title: OTA Update --- ## Table of Contents -* [Introduction](#introduction) - * [Security](#security) - * [Safety](#safety) - * [Basic Requirements](#basic-requirements) -* [Arduino IDE](#arduino-ide) - * [Requirements](#requirements) - * [Application Example](#application-example) - * [Classic OTA](#classic-ota) - * [ArduinoOTA](#arduinoota) -* [Web Browser](#web-browser) - * [Requirements](#requirements-1) - * [Implementation Overview](#implementation-overview) - * [Application Example](#application-example-1) -* [HTTP Server](#http-server) -* [Stream Interface](#stream-interface) -* [Updater class](#updater-class) + * [Introduction](#introduction) + * [Security](#security) + * [Safety](#safety) + * [Basic Requirements](#basic-requirements) + * [Arduino IDE](#arduino-ide) + * [Requirements](#requirements) + * [Application Example](#application-example) + * [Classic OTA](#classic-ota) + * [ArduinoOTA](#arduinoota) + * [Web Browser](#web-browser) + * [Requirements](#requirements-1) + * [Implementation Overview](#implementation-overview) + * [Application Example](#application-example-1) + * [HTTP Server](#http-server) + * [Requirements](#requirements-2) + * [Arduino code](#arduino-code) + * [Simple updater](#simple-updater) + * [Advanced updater](#advanced-updater) + * [Server request handling](#server-request-handling) + * [Simple updater](#simple-updater-1) + * [Advanced updater](#advanced-updater-1) + * [Stream Interface](#stream-interface) + * [Updater class](#updater-class) ## Introduction @@ -26,11 +33,12 @@ title: OTA Update OTA (Over the Air) update is the process of loading the firmware to ESP module using Wi-Fi connection rather that a serial port. Such functionality became extremely useful in case of limited or no physical access to the module. OTA may be done using: + * [Arduino IDE](#arduino-ide) * [Web Browser](#web-browser) * [HTTP Server](#http-server) -Arduino IDE option is intended primarily for software development phase. The two other options would be more useful after deployment, to provide module with application updates manually with a web browser or automatically using a http server. +Arduino IDE option is intended primarily for software development phase. The two other options would be more useful after deployment, to provide module with application updates manually with a web browser or automatically using a http server. In any case first firmware upload have to be done over a serial port. If OTA routines are correctly implemented in a sketch, then all subsequent uploads may be done over the air. @@ -39,14 +47,16 @@ There is no imposed security on OTA process from being hacked. It is up to devel ### Security -Module has to be exposed wirelessly to get it updated with a new sketch. That poses chances of module being violently hacked and loaded with some other code. To reduce likelihood of being hacked consider protecting your uploads with a password, selecting certain OTA port, etc. +Module has to be exposed wirelessly to get it updated with a new sketch. That poses chances of module being violently hacked and loaded with some other code. To reduce likelihood of being hacked consider protecting your uploads with a password, selecting certain OTA port, etc. Check functionality provided with [ArduinoOTA](https://github.com/esp8266/Arduino/tree/master/libraries/ArduinoOTA) library that may improve security: + ```cpp void setPort(uint16_t port); -void setHostname(const char *hostname); -void setPassword(const char *password); +void setHostname(const char* hostname); +void setPassword(const char* password); ``` + Certain protection functionality is already built in and do not require any additional coding by developer. [ArduinoOTA](https://github.com/esp8266/Arduino/tree/master/libraries/ArduinoOTA) and espota.py use [Digest-MD5](https://en.wikipedia.org/wiki/Digest_access_authentication) to authenticate upload. Integrity of transferred data is verified on ESP side using [MD5](https://en.wikipedia.org/wiki/MD5) checksum. Make your own risk analysis and depending on application decide what library functions to implement. If required consider implementation of other means of protection from being hacked, e.g. exposing module for uploads only according to specific schedule, trigger OTA only be user pressing dedicated “Update” button, etc. @@ -54,11 +64,12 @@ Make your own risk analysis and depending on application decide what library fun ### Safety -OTA process takes ESP’s resources and bandwidth during upload. Then module is restarted and a new sketch executed. Analyse and test how it affects functionality of your existing and new sketch. +OTA process takes ESP’s resources and bandwidth during upload. Then module is restarted and a new sketch executed. Analyse and test how it affects functionality of your existing and new sketch. If ESP is placed in remote location and controlling some equipment, you should put additional attention what happens if operation of this equipment is suddenly interrupted by update process. Therefore decide how to put this equipment into safe state before starting the update. For instance your module may be controlling a garden watering system in a sequence. If this sequence is not properly shut down and a water valve left open, your garden may be flooded if this valve is not closed after OTA is finished and module restarts. -The following functions are provided with [ArduinoOTA](https://github.com/esp8266/Arduino/tree/master/libraries/ArduinoOTA) library and intended to handle functionality of your application during specific stages of OTA on or on an OTA error: +The following functions are provided with [ArduinoOTA](https://github.com/esp8266/Arduino/tree/master/libraries/ArduinoOTA) library and intended to handle functionality of your application during specific stages of OTA or on an OTA error: + ```cpp void onStart(OTA_CALLBACK(fn)); void onEnd(OTA_CALLBACK(fn)); @@ -88,8 +99,10 @@ Uploading modules wirelessly from Arduino IDE is intended for the following typi ### Application Example -Currently there are two software configurations that support OTA updates -- [Classic OTA](#classic-ota-configuration): Arduino IDE 1.6.5 and 1.6.5-947-g39819f0 (of July 23, 2015) or 1.6.5-1160-gef26c5f (of Sep 30, 2015) version of platform package that provides first OTA implementation, yet without support for [ArduinoOTA](https://github.com/esp8266/Arduino/tree/master/libraries/ArduinoOTA) library. This particular configuration is easier to configure in Arduino IDE and therefore suggested for less experienced users. It soon will be depreciated once implementation below is fully released. +Currently there are two software configurations that support OTA updates. + +- [Classic OTA](#classic-ota-configuration): Arduino IDE 1.6.5 and 1.6.5-947-g39819f0 (of July 23, 2015) or 1.6.5-1160-gef26c5f (of Sep 30, 2015) version of platform package that provides first OTA implementation, yet without support for [ArduinoOTA](https://github.com/esp8266/Arduino/tree/master/libraries/ArduinoOTA) library. This particular configuration is easier to configure in Arduino IDE and therefore suggested for less experienced users. It soon will be depreciated once implementation below is fully released. + - [ArduinoOTA](#arduinoota-configuration): Arduino-PR-4107-BUILD-421 and latest git version of platform package that includes [ArduinoOTA](https://github.com/esp8266/Arduino/tree/master/libraries/ArduinoOTA) library. This configuration features preliminary build of Arduino IDE and is intended for more experienced users. Please mid your step. Instructions below demonstrate how to configure both [Classic OTA](#classic-ota-configuration) and [ArduinoOTA](#arduinoota-configuration) using NodeMCU 1.0 (ESP-12E Module) board. @@ -98,46 +111,39 @@ Instructions below demonstrate how to configure both [Classic OTA](#classic-ota- #### Classic OTA 1. Before you begin, please make sure that you have the following installed: - - Arduino IDE and ESP8266 board support as described under https://github.com/esp8266/Arduino#installing-with-boards-manager - - [Python](https://www.python.org/) 2.7 (do not install Python 3.5 that is not supported): + - Arduino IDE and ESP8266 board support as described under https://github.com/esp8266/Arduino#installing-with-boards-manager + - [Python](https://www.python.org/) 2.7 (do not install Python 3.5 that is not supported): - **Note:** Windows users should select “Add python.exe to Path” (see below – this option is not selected by default). + **Note:** Windows users should select “Add python.exe to Path” (see below – this option is not selected by default). - ![Python installation set up](ota-ide-python-configuration.png) + ![Python installation set up](ota-ide-python-configuration.png) 2. Now prepare the sketch and configuration for the upload over a serial port. + - Start Arduino IDE and load sketch DNS_SD_Arduino_OTA.ino available under File > Examples > ESP8266mDNS + ![OTA sketch selection](ota-ide-sketch-selection.png) + **Note:** This sketch is available only for 1.6.5-947-g39819f0 (of July 23, 2015) and 1.6.5-1160-gef26c5f (of Sep 30, 2015) versions of platform packages installed in Arduino IDE using https://github.com/esp8266/Arduino#installing-with-boards-manager. It was removed in [#980](https://github.com/esp8266/Arduino/pull/980) from GitHub repository. + - Update ssid and pass in the sketch so the module can join your Wi-Fi network + ![ssid and pass entry](ota-ide-ssid-pass-entry.png) + - Configure upload parameters as below (you may need to adjust configuration if you are using a different module): + ![configuration of serial upload](ota-ide-serial-upload-configuration.png) - - Start Arduino IDE and load sketch DNS_SD_Arduino_OTA.ino available under File > Examples > ESP8266mDNS +3. Upload the sketch (Ctrl+U). Once done open Serial Monitor (Ctrl+Shift+M) and check if module has joined your Wi-Fi network. - ![OTA sketch selection](ota-ide-sketch-selection.png) - - **Note:** This sketch is available only for 1.6.5-947-g39819f0 (of July 23, 2015) and 1.6.5-1160-gef26c5f (of Sep 30, 2015) versions of platform packages installed in Arduino IDE using https://github.com/esp8266/Arduino#installing-with-boards-manager. It was removed in [#980](https://github.com/esp8266/Arduino/pull/980) from GitHub repository. - - - Update ssid and pass in the sketch so the module can join your Wi-Fi network - - ![ssid and pass entry](ota-ide-ssid-pass-entry.png) - - - Configure upload parameters as below (you may need to adjust configuration if you are using a different module): - - ![configuration of serial upload](ota-ide-serial-upload-configuration.png) - -3. Upload the sketch (Ctrl+U). Once done open Serial Monitor (Ctrl+Shift+M) and check if module has joined your Wi-Fi network. - - ![check if module joined network](ota-ide-module-joined-wifi.png) + ![check if module joined network](ota-ide-module-joined-wifi.png) 4. Only if module is connected to network, after a couple of seconds, the esp8266-ota port will show up in Arduino IDE: - ![selection og OTA port](ota-ide-ota-port-selection.png) + ![selection og OTA port](ota-ide-ota-port-selection.png) 5. Now get ready for your first OTA upload by changing configuration settings as follows: - ![configuration of OTA upload](ota-ide-ota-upload-configuration.png) + ![configuration of OTA upload](ota-ide-ota-upload-configuration.png) - **Note:** If you do not see “Upload Using: OTA” option available for “NodeMCU 1.0 (ESP-12E Module)” board, please upload the latest [boards.txt](https://github.com/esp8266/Arduino/blob/master/boards.txt) file from GitHub repository, replace existing file and restart Arduino IDE. + **Note:** If you do not see “Upload Using: OTA” option available for “NodeMCU 1.0 (ESP-12E Module)” board, please upload the latest [boards.txt](https://github.com/esp8266/Arduino/blob/master/boards.txt) file from GitHub repository, replace existing file and restart Arduino IDE. 6. If you have successfully completed all the above steps, you can upload (Ctrl+U) the same (or any other) sketch over OTA: - ![OTA upload complete](ota-ide-ota-upload-complete.png) + ![OTA upload complete](ota-ide-ota-upload-complete.png) **Note** To be able to upload your sketch over and over again using OTA, you need to embed OTA routines inside. Please use DNS_SD_Arduino_OTA.ino as an example. @@ -157,6 +163,7 @@ Instructions below demonstrate how to configure both [Classic OTA](#classic-ota- ## Web Browser Updates described in this chapter are done with a web browser that can be useful in the following typical scenarios: + - after application deployment if loading directly from Arduino IDE is inconvenient or not possible - after deployment if user is unable to expose module for OTA from external update server - to provide updates after deployment to small quantity of modules when setting an update server is not practicable @@ -200,46 +207,39 @@ You can use another module if it meets “Flash chip size is 2x the size of the 1. Before you begin, please make sure that you have the following software installed: - - - Arduino IDE and 2.0.0-rc1 (of Nov 17, 2015) version of platform package as described under https://github.com/esp8266/Arduino#installing-with-boards-manager - - Host software depending on O/S you use: - 1. Avahi http://avahi.org/ for Linux - 2. Bonjour http://www.apple.com/support/bonjour/ for Windows - 3. Mac OSX and iOS - support is already built in / no any extra s/w is required + - Arduino IDE and 2.0.0-rc1 (of Nov 17, 2015) version of platform package as described under https://github.com/esp8266/Arduino#installing-with-boards-manager + - Host software depending on O/S you use: + 1. Avahi http://avahi.org/ for Linux + 2. Bonjour http://www.apple.com/support/bonjour/ for Windows + 3. Mac OSX and iOS - support is already built in / no any extra s/w is required 2. Prepare the sketch and configuration for initial upload with a serial port. - - Start Arduino IDE and load sketch WebUpdater.ino available under File > Examples > ESP8266HTTPUpdateServer. - - Update ssid and pass in the sketch so the module can join your Wi-Fi network. - - Open File > Preferences, look for “Show verbose output during:” and check out “compilation” option. + - Start Arduino IDE and load sketch WebUpdater.ino available under File > Examples > ESP8266HTTPUpdateServer. + - Update ssid and pass in the sketch so the module can join your Wi-Fi network. + - Open File > Preferences, look for “Show verbose output during:” and check out “compilation” option. + ![Preferences - enablig verbose output during compilation](ota-web-show-verbose-compilation.png) + **Note:** This setting will be required in step 5 below. You can uncheck this setting afterwards. - ![Preferences - enablig verbose output during compilation](ota-web-show-verbose-compilation.png) - - **Note:** This setting will be required in step 5 below. You can uncheck this setting it afterwards. - -3. Upload sketch (Ctrl+U). Once done open Serial Monitor (Ctrl+Shift+M) and check if you see the following message displayed, that contains url for OTA update. - - ![Serial Monitor - after first load using serial](ota-web-serial-monitor-ready.png) - - **Note:** Such message will be shown only after module successfully joins network and is ready for an OTA upload: +3. Upload sketch (Ctrl+U). Once done open Serial Monitor (Ctrl+Shift+M) and check if you see the following message displayed, that contains url for OTA update. + ![Serial Monitor - after first load using serial](ota-web-serial-monitor-ready.png) + **Note:** Such message will be shown only after module successfully joins network and is ready for an OTA upload: 4. Now open web browser and enter the url provided on Serial Monitor, i.e. http://esp8266-webupdate.local/update. Once entered, browser should display a form like below that has been served by your module. The form invites you to choose a file for update. - - ![OTA update form in web browser](ota-web-browser-form.png) - - **Note:** If entering “http://esp8266-webupdate.local/update” does not work, try replacing “esp8266-webupdate” with module’s IP address. For example, if your module IP is “192.168.1.100” then url should be “http://192.168.1.100/update”. This workaround is useful in case the host software installed in step 2 does not work. If still nothing works and there are no clues on Serial Monitor, try to diagnose issue by opening provided url in Google Chrome, pressing F12 and checking contents of “Console” and “Network” tabs. Chrome provides some advanced logging on these tabs. + ![OTA update form in web browser](ota-web-browser-form.png) + **Note:** If entering “http://esp8266-webupdate.local/update” does not work, try replacing “esp8266-webupdate” with module’s IP address. For example, if your module IP is “192.168.1.100” then url should be “http://192.168.1.100/update”. This workaround is useful in case the host software installed in step 2 does not work. If still nothing works and there are no clues on Serial Monitor, try to diagnose issue by opening provided url in Google Chrome, pressing F12 and checking contents of “Console” and “Network” tabs. Chrome provides some advanced logging on these tabs. -5. To obtain the file navigate to directory used by Arduino IDE to store results of compilation. You can check the path to this file in compilation log shown in IDE debug window as marked below. +5. To obtain the file navigate to directory used by Arduino IDE to store results of compilation. You can check the path to this file in compilation log shown in IDE debug window as marked below. - ![Compilation complete - path to binary file](ota-web-path-to-binary.png) + ![Compilation complete - path to binary file](ota-web-path-to-binary.png) 6. Now press “Choose File” in web browser, go to directory identified in step 5 above, find the file “WebUpdater.cpp.bin” and upload it. If upload is successful you will see “OK” on web browser like below. - ![OTA update complete](ota-web-browser-form-ok.png) + ![OTA update complete](ota-web-browser-form-ok.png) - Module will reboot that should be visible on Serial Monitor: + Module will reboot that should be visible on Serial Monitor: - ![Serial Monitor - after OTA update](ota-web-serial-monitor-reboot.png) + ![Serial Monitor - after OTA update](ota-web-serial-monitor-reboot.png) Just after reboot you should see exactly the same message “HTTPUpdateServer ready! Open http:// esp8266-webupdate.local /update in your browser” like in step 3. This is because module has been loaded again with the same code – first using serial port, and then using OTA. @@ -319,6 +319,7 @@ Example header data: With this information the script now can check if a update is needed. It is also possible to deliver different binaries based on the MAC address for example. Script example: + ```php https://www.pjrc.com/teensy/td_libs_OneWire.html)](#onewire-from-httpswwwpjrccomteensytd_libs_onewirehtml) - * [mDNS and DNS-SD responder (ESP8266mDNS library)](#mdns-and-dns-sd-responder-esp8266mdns-library) - * [SSDP responder (ESP8266SSDP)](#ssdp-responder-esp8266ssdp) - * [DNS server (DNSServer library)](#dns-server-dnsserver-library) - * [Servo](#servo) - * [Other libraries (not included with the IDE)](#other-libraries-not-included-with-the-ide) - -Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc) + * [Table of Contents](#table-of-contents) + * [Digital IO](#digital-io) + * [Analog input](#analog-input) + * [Analog output](#analog-output) + * [Timing and delays](#timing-and-delays) + * [Serial](#serial) + * [Progmem](#progmem) ## Digital IO @@ -142,366 +111,3 @@ const char HTTP[] PROGMEM = "http:"; response2 += FPSTR(HTTP); } ``` - -## File system - -Even though file system is stored on the same flash chip as the program, programming new sketch will not modify file system contents. This allows to use file system to store sketch data, configuration files, or content for Web server. - -The following diagram illustrates flash layout used in Arduino environment: - - |--------------|-------|---------------|--|--|--|--|--| - ^ ^ ^ ^ ^ - Sketch OTA update File system EEPROM WiFi config (SDK) - -File system size depends on the flash chip size. Depending on the board which is selected in IDE, you have the following options for flash size: - -Board | Flash chip size, bytes | File system size, bytes -------|-----------------|----------------- -Generic module | 512k | 64k -Generic module | 1M | 64k, 128k, 256k, 512k -Generic module | 2M | 1M -Generic module | 4M | 3M -Adafruit HUZZAH | 4M | 1M, 3M -NodeMCU 0.9 | 4M | 1M, 3M -NodeMCU 1.0 | 4M | 1M, 3M -Olimex MOD-WIFI-ESP8266(-DEV)| 2M | 1M -SparkFun Thing | 512k | 64k -SweetPea ESP-210 | 4M | 1M, 3M -WeMos D1 & D1 mini | 4M | 1M, 3M - -**Note:** to use any of file system functions in the sketch, add the following include to the sketch: - -```c++ -#include "FS.h" -``` - -### Uploading files to file system - -*ESP8266FS* is a tool which integrates into the Arduino IDE. It adds a menu item to *Tools* menu for uploading the contents of sketch data directory into ESP8266 flash file system. - -- Download the tool: https://github.com/esp8266/arduino-esp8266fs-plugin/releases/download/0.1.3/ESP8266FS-0.1.3.zip. -- In your Arduino sketchbook directory, create `tools` directory if it doesn't exist yet -- Unpack the tool into `tools` directory (the path will look like `/Arduino/tools/ESP8266FS/tool/esp8266fs.jar`) -- Restart Arduino IDE -- Open a sketch (or create a new one and save it) -- Go to sketch directory (choose Sketch > Show Sketch Folder) -- Create a directory named `data` and any files you want in the file system there -- Make sure you have selected a board, port, and closed Serial Monitor -- Select Tools > ESP8266 Sketch Data Upload. This should start uploading the files into ESP8266 flash file system. When done, IDE status bar will display `SPIFFS Image Uploaded` message. - - -### File system object (SPIFFS) - -#### begin - -```c++ -SPIFFS.begin() -``` - -This method mounts SPIFFS file system. It must be called before any other -FS APIs are used. Returns *true* if file system was mounted successfully, false -otherwise. - -#### format - -```c++ -SPIFFS.format() -``` - -Formats the file system. May be called either before or after calling `begin`. -Returns *true* if formatting was successful. - -#### open - -```c++ -SPIFFS.open(path, mode) -``` - -Opens a file. `path` should be an absolute path starting with a slash -(e.g. `/dir/filename.txt`). `mode` is a string specifying access mode. It can be -one of "r", "w", "a", "r+", "w+", "a+". Meaning of these modes is the same as -for `fopen` C function. - -Returns *File* object. To check whether the file was opened successfully, use -the boolean operator. - -```c++ -File f = SPIFFS.open("/f.txt", "w"); -if (!f) { - Serial.println("file open failed"); -} -``` - -#### exists - -```c++ -SPIFFS.exists(path) -``` - -Returns *true* if a file with given path exists, *false* otherwise. - -#### openDir - -```c++ -SPIFFS.openDir(path) -``` - -Opens a directory given its absolute path. Returns a *Dir* object. To check if -directory was opened successfully, use the boolean operator, similar to opening -a file. - -#### remove - -```c++ -SPIFFS.remove(path) -``` - -Deletes the file given its absolute path. Returns *true* if file was deleted successfully. - -#### rename - -```c++ -SPIFFS.rename(pathFrom, pathTo) -``` - -Renames file from `pathFrom` to `pathTo`. Paths must be absolute. Returns *true* -if file was renamed successfully. - -#### info - -```c++ -FSInfo fs_info; -SPIFFS.info(fs_info); -``` - -Fills [FSInfo structure](#filesystem-information-structure) with information about -the file system. Returns `true` is successful, `false` otherwise. - -### Filesystem information structure - -```c++ -struct FSInfo { - size_t totalBytes; - size_t usedBytes; - size_t blockSize; - size_t pageSize; - size_t maxOpenFiles; - size_t maxPathLength; -}; -``` - -This is the structure which may be filled using FS::info method. Field names -are self-explanatory. - -### Directory object (Dir) - -The purpose of *Dir* object is to iterate over files inside a directory. -It provides three methods: `next()`, `fileName()`, and `openFile(mode)`. - -The following example shows how it should be used: - -```c++ -Dir dir = SPIFFS.openDir("/data"); -while (dir.next()) { - Serial.print(dir.fileName()); - File f = dir.openFile("r"); - Serial.println(f.size()); -} -``` - -`dir.next()` returns true while there are files in the directory to iterate over. -It must be called before calling `fileName` and `openFile` functions. - -`openFile` method takes *mode* argument which has the same meaning as for `SPIFFS.open` function. - -### File object - -`SPIFFS.open` and `dir.openFile` functions return a *File* object. This object -supports all the functions of *Stream*, so you can use `readBytes`, `findUntil`, -`parseInt`, `println`, and all other *Stream* methods. - -There are also some functions which are specific to *File* object. - -#### seek - -```c++ -file.seek(offset, mode) -``` - -This function behaves like `fseek` C function. Depending on the value of `mode`, -it moves current position in a file as follows: - -- if `mode` is `SeekSet`, position is set to `offset` bytes from the beginning. -- if `mode` is `SeekCur`, current position is moved by `offset` bytes. -- if `mode` is `SeekEnd`, position is set to `offset` bytes from the end of the -file. - -Returns *true* if position was set successfully. - -#### position - -```c++ -file.position() -``` - -Returns the current position inside the file, in bytes. - -#### size - -```c++ -file.size() -``` - -Returns file size, in bytes. - - -#### name - -```c++ -String name = file.name(); -``` - -Returns file name, as `const char*`. Convert it to *String* for storage. - -#### close - -```c++ -file.close() -``` - -Close the file. No other operations should be performed on *File* object after `close` function was called. - -## WiFi(ESP8266WiFi library) - -This is mostly similar to WiFi shield library. Differences include: - -- `WiFi.mode(m)`: set mode to `WIFI_AP`, `WIFI_STA`, `WIFI_AP_STA` or `WIFI_OFF`. -- call `WiFi.softAP(ssid)` to set up an open network -- call `WiFi.softAP(ssid, password)` to set up a WPA2-PSK network (password should be at least 8 characters) -- `WiFi.macAddress(mac)` is for STA, `WiFi.softAPmacAddress(mac)` is for AP. -- `WiFi.localIP()` is for STA, `WiFi.softAPIP()` is for AP. -- `WiFi.printDiag(Serial)` will print out some diagnostic info -- `WiFiUDP` class supports sending and receiving multicast packets on STA interface. -When sending a multicast packet, replace `udp.beginPacket(addr, port)` with -`udp.beginPacketMulticast(addr, port, WiFi.localIP())`. -When listening to multicast packets, replace `udp.begin(port)` with -`udp.beginMulticast(WiFi.localIP(), multicast_ip_addr, port)`. -You can use `udp.destinationIP()` to tell whether the packet received was -sent to the multicast or unicast address. - -`WiFiServer`, `WiFiClient`, and `WiFiUDP` behave mostly the same way as with WiFi shield library. -Four samples are provided for this library. -You can see more commands here: [http://www.arduino.cc/en/Reference/WiFi](http://www.arduino.cc/en/Reference/WiFi) - -## Ticker - -Library for calling functions repeatedly with a certain period. Two examples included. - -It is currently not recommended to do blocking IO operations (network, serial, file) from Ticker -callback functions. Instead, set a flag inside the ticker callback and check for that flag inside the loop function. - -## EEPROM - -This is a bit different from standard EEPROM class. You need to call `EEPROM.begin(size)` -before you start reading or writing, size being the number of bytes you want to use. -Size can be anywhere between 4 and 4096 bytes. - -`EEPROM.write` does not write to flash immediately, instead you must call `EEPROM.commit()` -whenever you wish to save changes to flash. `EEPROM.end()` will also commit, and will -release the RAM copy of EEPROM contents. - -EEPROM library uses one sector of flash located just after the SPIFFS. - -Three examples included. - -## I2C (Wire library) - -Wire library currently supports master mode up to approximately 450KHz. -Before using I2C, pins for SDA and SCL need to be set by calling -`Wire.begin(int sda, int scl)`, i.e. `Wire.begin(0, 2)` on ESP-01, -else they default to pins 4(SDA) and 5(SCL). - -## SPI - -SPI library supports the entire Arduino SPI API including transactions, including setting phase (CPHA). -Setting the Clock polarity (CPOL) is not supported, yet (SPI_MODE2 and SPI_MODE3 not working). - -## SoftwareSerial - -An ESP8266 port of SoftwareSerial library done by Peter Lerup (@plerup) supports baud rate up to 115200 and multiples SoftwareSerial instances. See the https://github.com/plerup/espsoftwareserial if you want to suggest an improvement or open an issue related to SoftwareSerial. - -## ESP-specific APIs - -APIs related to deep sleep and watchdog timer are available in the `ESP` object, only available in Alpha version. - -`ESP.deepSleep(microseconds, mode)` will put the chip into deep sleep. `mode` is one of `WAKE_RF_DEFAULT`, `WAKE_RFCAL`, `WAKE_NO_RFCAL`, `WAKE_RF_DISABLED`. (GPIO16 needs to be tied to RST to wake from deepSleep.) - -`ESP.restart()` restarts the CPU. - -`ESP.getFreeHeap()` returns the free heap size. - -`ESP.getChipId()` returns the ESP8266 chip ID as a 32-bit integer. - -Several APIs may be used to get flash chip info: - -`ESP.getFlashChipId()` returns the flash chip ID as a 32-bit integer. - -`ESP.getFlashChipSize()` returns the flash chip size, in bytes, as seen by the SDK (may be less than actual size). - -`ESP.getFlashChipSpeed(void)` returns the flash chip frequency, in Hz. - -`ESP.getCycleCount()` returns the cpu instruction cycle count since start as an unsigned 32-bit. This is useful for accurate timing of very short actions like bit banging. - -`ESP.getVcc()` may be used to measure supply voltage. ESP needs to reconfigure the ADC -at startup in order for this feature to be available. Add the following line to the top -of your sketch to use `getVcc`: - -```c++ -ADC_MODE(ADC_VCC); -``` - -TOUT pin has to be disconnected in this mode. - -Note that by default ADC is configured to read from TOUT pin using `analogRead(A0)`, and -`ESP.getVCC()` is not available. - -## OneWire (from https://www.pjrc.com/teensy/td_libs_OneWire.html) - -Library was adapted to work with ESP8266 by including register definitions into OneWire.h -Note that if you already have OneWire library in your Arduino/libraries folder, it will be used -instead of the one that comes with this package. - -## mDNS and DNS-SD responder (ESP8266mDNS library) - -Allows the sketch to respond to multicast DNS queries for domain names like "foo.local", and DNS-SD (service dicovery) queries. -See attached example for details. - -## SSDP responder (ESP8266SSDP) - -SSDP is another service discovery protocol, supported on Windows out of the box. See attached example for reference. - -## DNS server (DNSServer library) - -Implements a simple DNS server that can be used in both STA and AP modes. The DNS server currently supports only one domain (for all other domains it will reply with NXDOMAIN or custom status code). With it clients can open a web server running on ESP8266 using a domain name, not an IP address. -See attached example for details. - -## Servo - -This library exposes the ability to control RC (hobby) servo motors. It will support upto 24 servos on any available output pin. By defualt the first 12 servos will use Timer0 and currently this will not interfere with any other support. Servo counts above 12 will use Timer1 and features that use it will be effected. -While many RC servo motors will accept the 3.3V IO data pin from a ESP8266, most will not be able to run off 3.3v and will require another power source that matches their specifications. Make sure to connect the grounds between the ESP8266 and the servo motor power supply. - -## Other libraries (not included with the IDE) - -Libraries that don't rely on low-level access to AVR registers should work well. Here are a few libraries that were verified to work: - -- [arduinoWebSockets](https://github.com/Links2004/arduinoWebSockets) - WebSocket Server and Client compatible with ESP8266 (RFC6455) -- [aREST](https://github.com/marcoschwartz/aREST) REST API handler library. -- [Blynk](https://github.com/blynkkk/blynk-library) - easy IoT framework for Makers (check out the [Kickstarter page](http://tiny.cc/blynk-kick)). -- [DallasTemperature](https://github.com/milesburton/Arduino-Temperature-Control-Library.git) -- [DHT-sensor-library](https://github.com/adafruit/DHT-sensor-library) - Arduino library for the DHT11/DHT22 temperature and humidity sensors. Download latest v1.1.1 library and no changes are necessary. Older versions should initialize DHT as follows: `DHT dht(DHTPIN, DHTTYPE, 15)` -- [NeoPixel](https://github.com/adafruit/Adafruit_NeoPixel) - Adafruit's NeoPixel library, now with support for the ESP8266 (use version 1.0.2 or higher from Arduino's library manager). -- [NeoPixelBus](https://github.com/Makuna/NeoPixelBus) - Arduino NeoPixel library compatible with ESP8266. Use the "NeoPixelAnimator" branch for ESP8266 to get HSL color support and more. -- [PubSubClient](https://github.com/Imroy/pubsubclient) MQTT library by @Imroy. -- [RTC](https://github.com/Makuna/Rtc) - Arduino Library for Ds1307 & Ds3231 compatible with ESP8266. -- [Souliss, Smart Home](https://github.com/souliss/souliss) - Framework for Smart Home based on Arduino, Android and openHAB. -- [ST7735](https://github.com/nzmichaelh/Adafruit-ST7735-Library) - Adafruit's ST7735 library modified to be compatible with ESP8266. Just make sure to modify the pins in the examples as they are still AVR specific. diff --git a/doc/reference_items.yml b/doc/reference_items.yml new file mode 100644 index 000000000..342609edd --- /dev/null +++ b/doc/reference_items.yml @@ -0,0 +1,15 @@ +# This file defines the order in which documents will appear in the menu + +- path: /doc/installing.html + +- path: /doc/reference.html + +- path: /doc/libraries.html + +- path: /doc/filesystem.html + +- path: /doc/ota_updates/ota_updates.html + +- path: /doc/boards.html + +- path: /doc/changes.html diff --git a/package/esp8266-arudino-doc.bash b/package/esp8266-arudino-doc.bash index 474cf66e9..25e3dc036 100755 --- a/package/esp8266-arudino-doc.bash +++ b/package/esp8266-arudino-doc.bash @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # @file esp8266-arudino-doc.bash @@ -11,15 +11,16 @@ # Packages needed by this script: # * linux commands: ln, cp, mkdir, rm, wget # * git -# * jekyll # -# ruby libraries: +# ruby gems: +# * jekyll # * redcarpet # * rb-pygments # # gem install [lib] # +set -e # some variable definitions tmp_path=$1 @@ -37,11 +38,11 @@ echo " version: "$version echo " release date: "$release_date echo " build date: "$build_date echo " put documentation into: "$destination_path -echo "documentatino template url: "$doc_template_url +echo "documentation template url: "$doc_template_url echo " url: "$url # continue? -read -e -p "Dou you wish to continue (y/n)? " -n 1 -i "y" decision +read -e -p "Dou you wish to continue (y/n)? " -n 1 decision if echo "$decision" | grep -iq "^y" ;then echo "okay" else @@ -99,8 +100,10 @@ ln -s ../$version _site # add subtitle and basurl echo "url: \"$url\"" > _config_local.yml -echo "subtitle: \"ver. $version, built on $build_date\"" >> _config_local.yml +echo "version: $version" >> _config_local.yml +echo "build_date: $build_date" >> _config_local.yml echo "baseurl: /Arduino/versions/$version" >> _config_local.yml +mv doc/reference_items.yml _data/reference_items.yml # build with jekyll jekyll build --config _config.yml,_config_local.yml From 319caba2403c9f5680180449bc6165f35842541a Mon Sep 17 00:00:00 2001 From: Eric Wilkison Date: Mon, 23 Nov 2015 12:39:40 -0800 Subject: [PATCH 26/33] Fix: WebServer eating first char from header value --- libraries/ESP8266WebServer/src/Parsing.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/ESP8266WebServer/src/Parsing.cpp b/libraries/ESP8266WebServer/src/Parsing.cpp index 318b0f547..8d740cf7a 100644 --- a/libraries/ESP8266WebServer/src/Parsing.cpp +++ b/libraries/ESP8266WebServer/src/Parsing.cpp @@ -107,7 +107,8 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) { break; } headerName = req.substring(0, headerDiv); - headerValue = req.substring(headerDiv + 2); + headerValue = req.substring(headerDiv + 1); + headerValue.trim(); _collectHeader(headerName.c_str(),headerValue.c_str()); #ifdef DEBUG From 5d7a3e939c00706d6318272a0c0216d1e426b2eb Mon Sep 17 00:00:00 2001 From: Martin Ayotte Date: Tue, 24 Nov 2015 15:11:20 -0500 Subject: [PATCH 27/33] add BergMicro Flash IDs --- cores/esp8266/Esp.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp index a2ecd4efe..5d39874fb 100644 --- a/cores/esp8266/Esp.cpp +++ b/cores/esp8266/Esp.cpp @@ -283,6 +283,16 @@ uint32_t EspClass::getFlashChipSizeByChipId(void) { case 0x1340EF: // W25Q40 return (512_kB); + // BergMicro + case 0x1640E0: // BG25Q32 + return (4_MB); + case 0x1540E0: // BG25Q16 + return (2_MB); + case 0x1440E0: // BG25Q80 + return (1_MB); + case 0x1340E0: // BG25Q40 + return (512_kB); + default: return 0; } From 8b67051d1ea9c108b8d27df7a7412504236fcb1e Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Wed, 25 Nov 2015 12:33:33 +0100 Subject: [PATCH 28/33] add StreamString class (implement the Stream interface for String) --- cores/esp8266/StreamString.cpp | 68 ++++++++++++++++++++++++++++++++++ cores/esp8266/StreamString.h | 40 ++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 cores/esp8266/StreamString.cpp create mode 100644 cores/esp8266/StreamString.h diff --git a/cores/esp8266/StreamString.cpp b/cores/esp8266/StreamString.cpp new file mode 100644 index 000000000..9aace2b47 --- /dev/null +++ b/cores/esp8266/StreamString.cpp @@ -0,0 +1,68 @@ +/** + StreamString.cpp + + Copyright (c) 2015 Markus Sattler. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + */ + +#include +#include "StreamString.h" + +size_t StreamString::write(const uint8_t *buffer, size_t size) { + if(reserve(length() + size + 1)) { + for(size_t i = 0; i < size; i++) { + if(write(*buffer)) { + buffer++; + } else { + return i; + } + } + + } + return 0; +} + +size_t StreamString::write(uint8_t data) { + return concat((char) data); +} + +int StreamString::available() { + return length(); +} + +int StreamString::read() { + if(length()) { + char c = charAt(0); + remove(0, 1); + return c; + + } + return -1; +} + +int StreamString::peek() { + if(length()) { + char c = charAt(0); + return c; + } + return -1; +} + +void StreamString::flush() { +} + diff --git a/cores/esp8266/StreamString.h b/cores/esp8266/StreamString.h new file mode 100644 index 000000000..4f9f458ae --- /dev/null +++ b/cores/esp8266/StreamString.h @@ -0,0 +1,40 @@ +/** + StreamString.h + + Copyright (c) 2015 Markus Sattler. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef STREAMSTRING_H_ +#define STREAMSTRING_H_ + + +class StreamString: public Stream, public String { + + size_t write(const uint8_t *buffer, size_t size); + size_t write(uint8_t data); + + int available(); + int read(); + int peek(); + void flush(); + +}; + + +#endif /* STREAMSTRING_H_ */ From e4a5250a1aa7253208ae27b9d5e74aca4106374d Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Wed, 25 Nov 2015 12:33:59 +0100 Subject: [PATCH 29/33] add getString function --- .../src/ESP8266httpClient.cpp | 35 +++++++++++++++++++ .../ESP8266httpClient/src/ESP8266httpClient.h | 4 ++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp index 1e27af2a3..7e3fd6fec 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "ESP8266httpClient.h" @@ -198,6 +199,7 @@ int httpClient::getSize(void) { } /** + * deprecated Note: this is not working with https! * returns the stram of the tcp connection * @return WiFiClient */ @@ -211,6 +213,20 @@ WiFiClient & httpClient::getStream(void) { // todo return error? } +/** + * returns the stram of the tcp connection + * @return WiFiClient * + */ +WiFiClient * httpClient::getStreamPtr(void) { + if(connected()) { + return _tcp; + } + + DEBUG_HTTPCLIENT("[HTTP-Client] no stream to return!?\n"); + return NULL; +} + +WiFiClient * getStreamPtr(void); /** * write all message body / payload to Stream * @param stream Stream * @@ -265,6 +281,25 @@ int httpClient::writeToStream(Stream * stream) { return bytesWritten; } +/** + * return all payload as String (may need lot of ram or trigger out of memmory!) + * @return String + */ +String httpClient::getString(void) { + StreamString sstring; + + if(_size) { + // try to reserve needed memmory + if(!sstring.reserve((_size + 1))) { + DEBUG_HTTPCLIENT("[HTTP-Client][getString] too less memory to resive as string! need: %d\n", (_size + 1)); + return String("--too less memory--"); + } + } + + writeToStream(&sstring); + return sstring; +} + /** * adds Headder to the request * @param name diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.h b/libraries/ESP8266httpClient/src/ESP8266httpClient.h index ddc0cea35..9d69f3ed3 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.h +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.h @@ -75,8 +75,10 @@ class httpClient { int getSize(void); - WiFiClient & getStream(void); + WiFiClient & getStream(void) __attribute__ ((deprecated)) ; + WiFiClient * getStreamPtr(void); int writeToStream(Stream * stream); + String getString(void); protected: From 59b4c82d60854234a80e4fa3bd0d1619e9690700 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Wed, 25 Nov 2015 12:40:25 +0100 Subject: [PATCH 30/33] add new Basic example based of getString note: keep in mind the ram usage! --- .../BasicHttpClient/BasicHttpClient.ino | 38 +------ .../StreamHttpClient/StreamHttpClient.ino | 98 +++++++++++++++++++ 2 files changed, 102 insertions(+), 34 deletions(-) create mode 100644 libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino diff --git a/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino b/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino index 99df11e76..0cdceb975 100644 --- a/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino +++ b/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino @@ -43,50 +43,20 @@ void loop() { USE_SERIAL.print("[HTTP] begin...\n"); // configure traged server and url - http.begin("192.168.1.12", 80, "/test.html"); + //http.begin("192.168.1.12", 443, "/test.html", true, "7a 9c f4 db 40 d3 62 5a 6e 21 bc 5c cc 66 c8 3e a1 45 59 38"); //HTTPS + http.begin("192.168.1.12", 80, "/test.html"); //HTTP USE_SERIAL.print("[HTTP] GET...\n"); // start connection and send HTTP header int httpCode = http.GET(); if(httpCode) { // HTTP header has been send and Server response header has been handled - USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); // file found at server if(httpCode == 200) { - - // get lenght of document (is -1 when Server sends no Content-Length header) - int len = http.getSize(); - - // create buffer for read - uint8_t buff[128] = { 0 }; - - // get tcp stream - WiFiClient stream = http.getStream(); - - // read all data from server - while(http.connected() && (len > 0 || len == -1)) { - // get available data size - size_t size = stream.available(); - - if(size) { - // read up to 128 byte - int c = stream.readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); - - // write it to Serial - USE_SERIAL.write(buff, c); - - if(len > 0) { - len -= c; - } - } - delay(1); - } - - USE_SERIAL.println(); - USE_SERIAL.print("[HTTP] connection closed or file end.\n"); - + String payload = http.getString(); + USE_SERIAL.println(payload); } } else { USE_SERIAL.print("[HTTP] GET... faild, no connection or no HTTP server\n"); diff --git a/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino b/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino new file mode 100644 index 000000000..a9aa981be --- /dev/null +++ b/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino @@ -0,0 +1,98 @@ +/** + * StreamHttpClient.ino + * + * Created on: 24.05.2015 + * + */ + +#include + +#include +#include + +#include + +#define USE_SERIAL Serial + +ESP8266WiFiMulti WiFiMulti; + +void setup() { + + USE_SERIAL.begin(115200); + // USE_SERIAL.setDebugOutput(true); + + USE_SERIAL.println(); + USE_SERIAL.println(); + USE_SERIAL.println(); + + for(uint8_t t = 4; t > 0; t--) { + USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); + USE_SERIAL.flush(); + delay(1000); + } + + WiFiMulti.addAP("SSID", "PASSWORD"); + +} + +void loop() { + // wait for WiFi connection + if((WiFiMulti.run() == WL_CONNECTED)) { + + httpClient http; + + USE_SERIAL.print("[HTTP] begin...\n"); + // configure traged server and url + http.begin("192.168.1.12", 80, "/test.html"); + + USE_SERIAL.print("[HTTP] GET...\n"); + // start connection and send HTTP header + int httpCode = http.GET(); + if(httpCode) { + // HTTP header has been send and Server response header has been handled + + USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); + + // file found at server + if(httpCode == 200) { + + // get lenght of document (is -1 when Server sends no Content-Length header) + int len = http.getSize(); + + // create buffer for read + uint8_t buff[128] = { 0 }; + + // get tcp stream + WiFiClient * stream = http.getStream(); + + // read all data from server + while(http.connected() && (len > 0 || len == -1)) { + // get available data size + size_t size = stream->available(); + + if(size) { + // read up to 128 byte + int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); + + // write it to Serial + USE_SERIAL.write(buff, c); + + if(len > 0) { + len -= c; + } + } + delay(1); + } + + USE_SERIAL.println(); + USE_SERIAL.print("[HTTP] connection closed or file end.\n"); + + } + } else { + USE_SERIAL.print("[HTTP] GET... faild, no connection or no HTTP server\n"); + } + } + + delay(10000); +} + From 761b73c5ad35e6d28683bd4a163ca8bd0fc7bed5 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Wed, 25 Nov 2015 12:42:24 +0100 Subject: [PATCH 31/33] correct StreamHttpClient.ino example --- .../examples/StreamHttpClient/StreamHttpClient.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino b/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino index a9aa981be..f64599fbb 100644 --- a/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino +++ b/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino @@ -63,7 +63,7 @@ void loop() { uint8_t buff[128] = { 0 }; // get tcp stream - WiFiClient * stream = http.getStream(); + WiFiClient * stream = http.getStreamPtr(); // read all data from server while(http.connected() && (len > 0 || len == -1)) { From 75fb6e200276210b235019d1f49ddd91c12c4b3c Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Wed, 25 Nov 2015 12:50:49 +0100 Subject: [PATCH 32/33] disable DEBUG_HTTPCLIENT --- .../examples/StreamHttpClient/StreamHttpClient.ino | 2 +- libraries/ESP8266httpClient/src/ESP8266httpClient.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino b/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino index f64599fbb..9b64dab1c 100644 --- a/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino +++ b/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino @@ -19,7 +19,7 @@ ESP8266WiFiMulti WiFiMulti; void setup() { USE_SERIAL.begin(115200); - // USE_SERIAL.setDebugOutput(true); + // USE_SERIAL.setDebugOutput(true); USE_SERIAL.println(); USE_SERIAL.println(); diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.h b/libraries/ESP8266httpClient/src/ESP8266httpClient.h index 9d69f3ed3..60a765f82 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.h +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.h @@ -25,7 +25,7 @@ #ifndef ESP8266HTTPCLIENT_H_ #define ESP8266HTTPCLIENT_H_ -#define DEBUG_HTTPCLIENT(...) Serial1.printf( __VA_ARGS__ ) +//#define DEBUG_HTTPCLIENT(...) Serial1.printf( __VA_ARGS__ ) #ifndef DEBUG_HTTPCLIENT #define DEBUG_HTTPCLIENT(...) From 9089448d2574366d2fa7f69df5d39c5094eaa40a Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Wed, 25 Nov 2015 12:53:28 +0100 Subject: [PATCH 33/33] fixed typo --- .../BasicHttpClient/BasicHttpClient.ino | 4 ++-- .../StreamHttpClient/StreamHttpClient.ino | 2 +- .../reuseConnection/reuseConnection.ino | 4 ++-- .../src/ESP8266httpClient.cpp | 19 ++++++++++--------- .../ESP8266httpClient/src/ESP8266httpClient.h | 4 ++-- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino b/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino index 0cdceb975..15526e096 100644 --- a/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino +++ b/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino @@ -12,7 +12,7 @@ #include -#define USE_SERIAL Serial1 +#define USE_SERIAL Serial ESP8266WiFiMulti WiFiMulti; @@ -59,7 +59,7 @@ void loop() { USE_SERIAL.println(payload); } } else { - USE_SERIAL.print("[HTTP] GET... faild, no connection or no HTTP server\n"); + USE_SERIAL.print("[HTTP] GET... failed, no connection or no HTTP server\n"); } } diff --git a/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino b/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino index 9b64dab1c..43b6d4d8b 100644 --- a/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino +++ b/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino @@ -89,7 +89,7 @@ void loop() { } } else { - USE_SERIAL.print("[HTTP] GET... faild, no connection or no HTTP server\n"); + USE_SERIAL.print("[HTTP] GET... failed, no connection or no HTTP server\n"); } } diff --git a/libraries/ESP8266httpClient/examples/reuseConnection/reuseConnection.ino b/libraries/ESP8266httpClient/examples/reuseConnection/reuseConnection.ino index 7179b1f82..4610cb972 100644 --- a/libraries/ESP8266httpClient/examples/reuseConnection/reuseConnection.ino +++ b/libraries/ESP8266httpClient/examples/reuseConnection/reuseConnection.ino @@ -13,7 +13,7 @@ #include -#define USE_SERIAL Serial1 +#define USE_SERIAL Serial ESP8266WiFiMulti WiFiMulti; @@ -54,7 +54,7 @@ void loop() { http.writeToStream(&USE_SERIAL); } } else { - USE_SERIAL.print("[HTTP] GET... faild, no connection or no HTTP server\n"); + USE_SERIAL.print("[HTTP] GET... failed, no connection or no HTTP server\n"); } } diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp index 7e3fd6fec..69becd195 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp @@ -99,7 +99,7 @@ void httpClient::begin(String host, uint16_t port, String url, bool https, Strin /** * end - * called after the payload is handeld + * called after the payload is handled */ void httpClient::end(void) { if(connected()) { @@ -176,13 +176,13 @@ int httpClient::sendRequest(const char * type, uint8_t * payload, size_t size) { // send Header if(!sendHeader(type)) { - return HTTPC_ERROR_SEND_HEADER_FAILD; + return HTTPC_ERROR_SEND_HEADER_FAILED; } // send Payload if needed if(payload && size > 0) { if(_tcp->write(&payload[0], size) != size) { - return HTTPC_ERROR_SEND_PAYLOAD_FAILD; + return HTTPC_ERROR_SEND_PAYLOAD_FAILED; } } @@ -200,7 +200,7 @@ int httpClient::getSize(void) { /** * deprecated Note: this is not working with https! - * returns the stram of the tcp connection + * returns the stream of the tcp connection * @return WiFiClient */ WiFiClient & httpClient::getStream(void) { @@ -214,7 +214,7 @@ WiFiClient & httpClient::getStream(void) { } /** - * returns the stram of the tcp connection + * returns the stream of the tcp connection * @return WiFiClient * */ WiFiClient * httpClient::getStreamPtr(void) { @@ -242,7 +242,7 @@ int httpClient::writeToStream(Stream * stream) { return HTTPC_ERROR_NOT_CONNECTED; } - // get lenght of document (is -1 when Server sends no Content-Length header) + // get length of document (is -1 when Server sends no Content-Length header) int len = _size; int bytesWritten = 0; @@ -282,7 +282,7 @@ int httpClient::writeToStream(Stream * stream) { } /** - * return all payload as String (may need lot of ram or trigger out of memmory!) + * return all payload as String (may need lot of ram or trigger out of memory!) * @return String */ String httpClient::getString(void) { @@ -300,8 +300,9 @@ String httpClient::getString(void) { return sstring; } + /** - * adds Headder to the request + * adds Header to the request * @param name * @param value * @param first @@ -443,7 +444,7 @@ bool httpClient::sendHeader(const char * type) { } /** - * reads the respone from the server + * reads the response from the server * @return int http code */ int httpClient::handleHeaderResponse() { diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.h b/libraries/ESP8266httpClient/src/ESP8266httpClient.h index 60a765f82..1f3d33bd5 100644 --- a/libraries/ESP8266httpClient/src/ESP8266httpClient.h +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.h @@ -35,8 +35,8 @@ /// HTTP client errors #define HTTPC_ERROR_CONNECTION_REFUSED (-1) -#define HTTPC_ERROR_SEND_HEADER_FAILD (-2) -#define HTTPC_ERROR_SEND_PAYLOAD_FAILD (-3) +#define HTTPC_ERROR_SEND_HEADER_FAILED (-2) +#define HTTPC_ERROR_SEND_PAYLOAD_FAILED (-3) #define HTTPC_ERROR_NOT_CONNECTED (-4) #define HTTPC_ERROR_CONNECTION_LOST (-5) #define HTTPC_ERROR_NO_STREAM (-6)