From e97a739f0328e3a2542e956b40b8e624f00a5903 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Mon, 15 Jan 2018 00:20:23 +0100 Subject: [PATCH] Added HTTP OTA updater for ESP32 Added Easter Egg Improved ArduinoOTA stability on ESP8266 Added function that starts the AP if you press the button for 7 secs Added yet unused methods for color conversion --- readme.md | 2 +- .../webserver/ESP8266HTTPUpdateServer.cpp | 104 ++++++++++++++++++ .../webserver/ESP8266HTTPUpdateServer.h | 74 +++++++++++++ wled00/src/dependencies/webserver/README.md | 2 + wled00/wled00.ino | 7 +- wled00/wled05_init.ino | 34 +++--- wled00/wled09_button.ino | 2 + wled00/wled14_colors.ino | 27 +++++ 8 files changed, 233 insertions(+), 19 deletions(-) create mode 100644 wled00/src/dependencies/webserver/ESP8266HTTPUpdateServer.cpp create mode 100644 wled00/src/dependencies/webserver/ESP8266HTTPUpdateServer.h create mode 100644 wled00/wled14_colors.ino diff --git a/readme.md b/readme.md index c8b4cc64..88ca67e8 100644 --- a/readme.md +++ b/readme.md @@ -15,7 +15,7 @@ Now also with experimental ESP32 support. - Notifier function (multiple ESPs sync color via UDP broadcast) - Support for power pushbutton - Custom Theater Chase -- Full OTA software update capability (only ESP8266) +- Full OTA software update capability (HTTP and ArduinoOTA) - Password protected OTA page for added security (OTA lock) - Alexa smart home device server (including dimming) - NTP and experimental analog clock function diff --git a/wled00/src/dependencies/webserver/ESP8266HTTPUpdateServer.cpp b/wled00/src/dependencies/webserver/ESP8266HTTPUpdateServer.cpp new file mode 100644 index 00000000..5fc501e6 --- /dev/null +++ b/wled00/src/dependencies/webserver/ESP8266HTTPUpdateServer.cpp @@ -0,0 +1,104 @@ +#include +#include +#include +#ifdef ARDUINO_ARCH_ESP32 +#include "WebServer.h" +#include +#else +#include +#endif +#include +#include "ESP8266HTTPUpdateServer.h" + + +const char* ESP8266HTTPUpdateServer::_serverIndex = +R"(

WLED Software Update


Get the latest binaries on the project GitHub page!
+ Unsure which binary is correct? Go to the /build subpage to find the details of this version.
+ Double check to be sure to upload a valid .bin firmware file for your ESP! Otherwise you'll need USB recovery!

+
+ + +
+ )"; +const char* ESP8266HTTPUpdateServer::_failedResponse = R"(Update Failed!)"; +const char* ESP8266HTTPUpdateServer::_successResponse = "Update Successful! Rebooting, please wait for redirect..."; + +ESP8266HTTPUpdateServer::ESP8266HTTPUpdateServer(bool serial_debug) +{ + _serial_output = serial_debug; + _server = NULL; + _username = NULL; + _password = NULL; + _authenticated = false; +} + +#ifdef ARDUINO_ARCH_ESP32 +void ESP8266HTTPUpdateServer::setup(WebServer *server, const char * path, const char * username, const char * password) +#else +void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server, const char * path, const char * username, const char * password) +#endif +{ + _server = server; + _username = (char *)username; + _password = (char *)password; + + // handler for the /update form page + _server->on(path, HTTP_GET, [&](){ + if(_username != NULL && _password != NULL && !_server->authenticate(_username, _password)) + return _server->requestAuthentication(); + _server->send(200, "text/html", _serverIndex); + }); + + // handler for the /update form POST (once file upload finishes) + _server->on(path, HTTP_POST, [&](){ + if(!_authenticated) + return _server->requestAuthentication(); + _server->send(200, "text/html", Update.hasError() ? _failedResponse : _successResponse); + ESP.restart(); + },[&](){ + // 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) + Serial.setDebugOutput(true); + + _authenticated = (_username == NULL || _password == NULL || _server->authenticate(_username, _password)); + if(!_authenticated){ + if (_serial_output) + Serial.printf("Unauthenticated Update\n"); + return; + } + #ifndef ARDUINO_ARCH_ESP32 + WiFiUDP::stopAll(); + #endif + if (_serial_output) + Serial.printf("Update: %s\n", upload.filename.c_str()); + #ifdef ARDUINO_ARCH_ESP32 + uint32_t maxSketchSpace = 0x100000; //dirty workaround, limit to 1MB + #else + uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; + #endif + if(!Update.begin(maxSketchSpace)){//start with max available size + if (_serial_output) Update.printError(Serial); + } + } else if(_authenticated && upload.status == UPLOAD_FILE_WRITE){ + if (_serial_output) Serial.printf("."); + if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){ + if (_serial_output) Update.printError(Serial); + + } + } else if(_authenticated && upload.status == UPLOAD_FILE_END){ + if(Update.end(true)){ //true to set the size to the current progress + if (_serial_output) Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); + } else { + if (_serial_output) Update.printError(Serial); + } + if (_serial_output) Serial.setDebugOutput(false); + } else if(_authenticated && upload.status == UPLOAD_FILE_ABORTED){ + Update.end(); + if (_serial_output) Serial.println("Update was aborted"); + } + delay(0); + }); +} diff --git a/wled00/src/dependencies/webserver/ESP8266HTTPUpdateServer.h b/wled00/src/dependencies/webserver/ESP8266HTTPUpdateServer.h new file mode 100644 index 00000000..363d3bcc --- /dev/null +++ b/wled00/src/dependencies/webserver/ESP8266HTTPUpdateServer.h @@ -0,0 +1,74 @@ +#ifndef __HTTP_UPDATE_SERVER_H +#define __HTTP_UPDATE_SERVER_H + +#ifdef ARDUINO_ARCH_ESP32 +class WebServer; + +class ESP8266HTTPUpdateServer +{ + private: + bool _serial_output; + WebServer *_server; + static const char *_serverIndex; + static const char *_failedResponse; + static const char *_successResponse; + char * _username; + char * _password; + bool _authenticated; + public: + ESP8266HTTPUpdateServer(bool serial_debug=false); + + void setup(WebServer *server) + { + setup(server, NULL, NULL); + } + + void setup(WebServer *server, const char * path) + { + setup(server, path, NULL, NULL); + } + + void setup(WebServer *server, const char * username, const char * password) + { + setup(server, "/update", username, password); + } + + void setup(WebServer *server, const char * path, const char * username, const char * password); +}; +#else +class ESP8266WebServer; + +class ESP8266HTTPUpdateServer +{ + private: + bool _serial_output; + ESP8266WebServer *_server; + static const char *_serverIndex; + static const char *_failedResponse; + static const char *_successResponse; + char * _username; + char * _password; + bool _authenticated; + public: + ESP8266HTTPUpdateServer(bool serial_debug=false); + + void setup(ESP8266WebServer *server) + { + setup(server, NULL, NULL); + } + + void setup(ESP8266WebServer *server, const char * path) + { + setup(server, path, NULL, NULL); + } + + void setup(ESP8266WebServer *server, const char * username, const char * password) + { + setup(server, "/update", username, password); + } + + void setup(ESP8266WebServer *server, const char * path, const char * username, const char * password); +}; +#endif + +#endif diff --git a/wled00/src/dependencies/webserver/README.md b/wled00/src/dependencies/webserver/README.md index 5ec07c51..dc2178cf 100644 --- a/wled00/src/dependencies/webserver/README.md +++ b/wled00/src/dependencies/webserver/README.md @@ -1,3 +1,5 @@ +Notice by Aircoookie: Port of the ESP8266HTTPUpdateServer for ESP32 is also included in this directory. + # WebServer ESP8266/ESP32 WebServer library diff --git a/wled00/wled00.ino b/wled00/wled00.ino index 7bfb9d6e..fb7200f1 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -16,11 +16,11 @@ #include #include #include -#include #endif #include #include #include +#include "src/dependencies/webserver/ESP8266HTTPUpdateServer.h" #include "src/dependencies/time/Time.h" #include "src/dependencies/time/TimeLib.h" #include "src/dependencies/timezone/Timezone.h" @@ -29,7 +29,7 @@ #include "WS2812FX.h" //version in format yymmddb (b = daily build) -#define VERSION 1801140 +#define VERSION 1801150 const String versionName = "WLED 0.5dev"; //AP and OTA default passwords (change them!) @@ -171,6 +171,7 @@ byte bri_it = 0; byte bri_last = 127; boolean transitionActive = false; boolean buttonPressedBefore = false; +long buttonPressedTime = 0; boolean nightlightActive = false; boolean nightlightActive_old = false; int nightlightDelayMs; @@ -234,8 +235,8 @@ String escapedMac; WebServer server(80); #else ESP8266WebServer server(80); -ESP8266HTTPUpdateServer httpUpdater; //only for ESP8266 #endif +ESP8266HTTPUpdateServer httpUpdater; WiFiUDP notifierUdp; WiFiUDP ntpUdp; diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino index 792bf509..74ab4ed0 100644 --- a/wled00/wled05_init.ino +++ b/wled00/wled05_init.ino @@ -122,6 +122,9 @@ void wledInit() val += "mA currently\nNotice: This is just an estimate which does not take into account several factors (like effects and wire resistance). It is NOT an accurate measurement!"; server.send(200, "text/plain", val); }); + server.on("/teapot", HTTP_GET, [](){ + server.send(418, "text/plain", "418. I'm a teapot. (Tangible Embedded Advanced Project Of Twinkling)"); + }); server.on("/build", HTTP_GET, [](){ String info = "hard-coded build info:\r\n\n"; #ifdef ARDUINO_ARCH_ESP32 @@ -166,6 +169,7 @@ void wledInit() #endif server.send(200, "text/plain", info); }); + //if OTA is allowed if (!otaLock){ server.on("/edit", HTTP_GET, [](){ if(!handleFileRead("/edit.htm")) server.send(200, "text/html", PAGE_edit); @@ -179,14 +183,14 @@ void wledInit() server.on("/down", HTTP_GET, down); server.on("/cleareeprom", HTTP_GET, clearEEPROM); //init ota page - #ifndef ARDUINO_ARCH_ESP32 httpUpdater.setup(&server); //only for ESP8266 - #else - server.on("/update", HTTP_GET, [](){ - server.send(200, "text/plain", "OTA update is not supported on ESP32 at this time. You may want to use ArduinoOTA."); - }); - #endif //init ArduinoOTA + ArduinoOTA.onStart([]() { + #ifndef ARDUINO_ARCH_ESP32 + wifi_set_sleep_type(NONE_SLEEP_T); + #endif + DEBUG_PRINTLN("Start ArduinoOTA"); + }); ArduinoOTA.begin(); } else { @@ -233,7 +237,7 @@ void wledInit() strip.setBrightness(255); strip.start(); - + pinMode(buttonPin, INPUT_PULLUP); #ifdef CRONIXIE strip.driverModeCronixie(true); strip.setCronixieBacklight(cronixieBacklight); @@ -241,11 +245,18 @@ void wledInit() #endif if (bootPreset>0) applyPreset(bootPreset, turnOnAtBoot, true, true); colorUpdated(0); - pinMode(buttonPin, INPUT_PULLUP); + if(digitalRead(buttonPin) == LOW) buttonEnabled = false; //disable button if it is "pressed" unintentionally } void initAP(){ + String save = apssid; + #ifdef CRONIXIE + if (apssid.length() <1) apssid = "CRONIXIE-AP"; + #else + if (apssid.length() <1) apssid = "WLED-AP"; + #endif WiFi.softAP(apssid.c_str(), appass.c_str(), apchannel, aphide); + apssid = save; } void initCon() @@ -261,15 +272,8 @@ void initCon() { WiFi.disconnect(); DEBUG_PRINTLN("Can't connect. Opening AP..."); - String save = apssid; onlyAP = true; - #ifdef CRONIXIE - if (apssid.length() <1) apssid = "CRONIXIE-AP"; - #else - if (apssid.length() <1) apssid = "WLED-AP"; - #endif initAP(); - apssid = save; return; } } diff --git a/wled00/wled09_button.ino b/wled00/wled09_button.ino index d157fb30..98b64239 100644 --- a/wled00/wled09_button.ino +++ b/wled00/wled09_button.ino @@ -8,6 +8,7 @@ void handleButton() { if (digitalRead(buttonPin) == LOW && !buttonPressedBefore) { + buttonPressedTime = millis(); buttonPressedBefore = true; if (buttonMacro == 255) { @@ -29,6 +30,7 @@ void handleButton() delay(15); //debounce if (digitalRead(buttonPin) == HIGH) { + if (millis() - buttonPressedTime > 7000) initAP(); buttonPressedBefore = false; } } diff --git a/wled00/wled14_colors.ino b/wled00/wled14_colors.ino new file mode 100644 index 00000000..52a6e98f --- /dev/null +++ b/wled00/wled14_colors.ino @@ -0,0 +1,27 @@ +/* + * Color conversion methods + */ +void colorCTtoRGB(uint16_t mired, uint8_t* rgb) //white spectrum to rgb +{ + +} + +void colorHSBtoRGB(uint16_t hue, uint8_t sat, uint8_t bri, uint8_t* rgb) //hue, sat, bri to rgb +{ + +} + +void colorXYtoRGB(float x, float y, uint8_t* rgb) //coordinates to rgb (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy) +{ + float z = 1.0f - x - y; + //float Y = 1.0f; // Brightness, we handle this separately + float X = (1.0f / y) * x; + float Z = (1.0f / y) * z; + rgb[0] = (int)(X * 1.656492f - 0.354851f - Z * 0.255038f); + rgb[1] = (int)(-X * 0.707196f + 1.655397f + Z * 0.036152f); + rgb[2] = (int)(X * 0.051713f - 0.121364f + Z * 1.011530f); +} + +void colorRGBtoXY(uint8_t* rgb, float* xy){} //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy) + +void colorRGBtoRGBW(uint8_t* rgb, uint8_t* rgbw){} //rgb to rgbw, not imlemented yet