mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-03-30 12:45:45 +00:00
* OTA update for ESP32 targets
This commit is contained in:
21
arch/esp32/AsyncElegantOTA/LICENSE
Normal file
21
arch/esp32/AsyncElegantOTA/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Ayush Sharma
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
2
arch/esp32/AsyncElegantOTA/keywords.txt
Normal file
2
arch/esp32/AsyncElegantOTA/keywords.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
AsyncElegantOTA KEYWORD1
|
||||
begin KEYWORD2
|
||||
9
arch/esp32/AsyncElegantOTA/library.properties
Normal file
9
arch/esp32/AsyncElegantOTA/library.properties
Normal file
@@ -0,0 +1,9 @@
|
||||
name=AsyncElegantOTA
|
||||
version=2.2.8
|
||||
author=Ayush Sharma
|
||||
category=Communication
|
||||
maintainer=Ayush Sharma <asrocks5@gmail.com>
|
||||
sentence=Perform OTAs for ESP8266 & ESP32 Asynchronously.
|
||||
paragraph=A User Interface Library which provides interactive elements for your Over the Air Updates on ESP8266/ESP32.
|
||||
url=https://github.com/ayushsharma82/AsyncElegantOTA
|
||||
architectures=esp8266,esp32
|
||||
129
arch/esp32/AsyncElegantOTA/src/AsyncElegantOTA.cpp
Normal file
129
arch/esp32/AsyncElegantOTA/src/AsyncElegantOTA.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#include <AsyncElegantOTA.h>
|
||||
|
||||
AsyncElegantOtaClass AsyncElegantOTA;
|
||||
|
||||
void AsyncElegantOtaClass::setID(const char* id){
|
||||
_id = id;
|
||||
}
|
||||
|
||||
void AsyncElegantOtaClass::begin(AsyncWebServer *server, const char* username, const char* password){
|
||||
_server = server;
|
||||
|
||||
if(strlen(username) > 0){
|
||||
_authRequired = true;
|
||||
_username = username;
|
||||
_password = password;
|
||||
}else{
|
||||
_authRequired = false;
|
||||
_username = "";
|
||||
_password = "";
|
||||
}
|
||||
|
||||
_server->on("/update/identity", HTTP_GET, [&](AsyncWebServerRequest *request){
|
||||
if(_authRequired){
|
||||
if(!request->authenticate(_username.c_str(), _password.c_str())){
|
||||
return request->requestAuthentication();
|
||||
}
|
||||
}
|
||||
#if defined(ESP8266)
|
||||
request->send(200, "application/json", "{\"id\": \""+_id+"\", \"hardware\": \"ESP8266\"}");
|
||||
#elif defined(ESP32)
|
||||
request->send(200, "application/json", "{\"id\": \""+_id+"\", \"hardware\": \"ESP32\"}");
|
||||
#endif
|
||||
});
|
||||
|
||||
_server->on("/update", HTTP_GET, [&](AsyncWebServerRequest *request){
|
||||
if(_authRequired){
|
||||
if(!request->authenticate(_username.c_str(), _password.c_str())){
|
||||
return request->requestAuthentication();
|
||||
}
|
||||
}
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", ELEGANT_HTML, ELEGANT_HTML_SIZE);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
_server->on("/update", HTTP_POST, [&](AsyncWebServerRequest *request) {
|
||||
if(_authRequired){
|
||||
if(!request->authenticate(_username.c_str(), _password.c_str())){
|
||||
return request->requestAuthentication();
|
||||
}
|
||||
}
|
||||
// the request handler is triggered after the upload has finished...
|
||||
// create the response, add header, and send response
|
||||
AsyncWebServerResponse *response = request->beginResponse((Update.hasError())?500:200, "text/plain", (Update.hasError())?"FAIL":"OK");
|
||||
response->addHeader("Connection", "close");
|
||||
response->addHeader("Access-Control-Allow-Origin", "*");
|
||||
request->send(response);
|
||||
restart();
|
||||
}, [&](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
|
||||
//Upload handler chunks in data
|
||||
if(_authRequired){
|
||||
if(!request->authenticate(_username.c_str(), _password.c_str())){
|
||||
return request->requestAuthentication();
|
||||
}
|
||||
}
|
||||
|
||||
if (!index) {
|
||||
if(!request->hasParam("MD5", true)) {
|
||||
return request->send(400, "text/plain", "MD5 parameter missing");
|
||||
}
|
||||
|
||||
if(!Update.setMD5(request->getParam("MD5", true)->value().c_str())) {
|
||||
return request->send(400, "text/plain", "MD5 parameter invalid");
|
||||
}
|
||||
|
||||
#if defined(ESP8266)
|
||||
int cmd = (filename == "filesystem") ? U_FS : U_FLASH;
|
||||
Update.runAsync(true);
|
||||
size_t fsSize = ((size_t) &_FS_end - (size_t) &_FS_start);
|
||||
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
|
||||
if (!Update.begin((cmd == U_FS)?fsSize:maxSketchSpace, cmd)){ // Start with max available size
|
||||
#elif defined(ESP32)
|
||||
int cmd = (filename == "filesystem") ? U_SPIFFS : U_FLASH;
|
||||
if (!Update.begin(UPDATE_SIZE_UNKNOWN, cmd)) { // Start with max available size
|
||||
#endif
|
||||
Update.printError(Serial);
|
||||
return request->send(400, "text/plain", "OTA could not begin");
|
||||
}
|
||||
}
|
||||
|
||||
// Write chunked data to the free sketch space
|
||||
if(len){
|
||||
if (Update.write(data, len) != len) {
|
||||
return request->send(400, "text/plain", "OTA could not begin");
|
||||
}
|
||||
}
|
||||
|
||||
if (final) { // if the final flag is set then this is the last frame of data
|
||||
if (!Update.end(true)) { //true to set the size to the current progress
|
||||
Update.printError(Serial);
|
||||
return request->send(400, "text/plain", "Could not end OTA");
|
||||
}
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// deprecated, keeping for backward compatibility
|
||||
void AsyncElegantOtaClass::loop() {
|
||||
}
|
||||
|
||||
void AsyncElegantOtaClass::restart() {
|
||||
yield();
|
||||
delay(1000);
|
||||
yield();
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
String AsyncElegantOtaClass::getID(){
|
||||
String id = "";
|
||||
#if defined(ESP8266)
|
||||
id = String(ESP.getChipId());
|
||||
#elif defined(ESP32)
|
||||
id = String((uint32_t)ESP.getEfuseMac(), HEX);
|
||||
#endif
|
||||
id.toUpperCase();
|
||||
return id;
|
||||
}
|
||||
52
arch/esp32/AsyncElegantOTA/src/AsyncElegantOTA.h
Normal file
52
arch/esp32/AsyncElegantOTA/src/AsyncElegantOTA.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef AsyncElegantOTA_h
|
||||
#define AsyncElegantOTA_h
|
||||
|
||||
#warning AsyncElegantOTA library is deprecated, Please consider moving to newer ElegantOTA library which now comes with an Async Mode. Learn More: https://docs.elegantota.pro/async-mode/
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "stdlib_noniso.h"
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include "ESP8266WiFi.h"
|
||||
#include "ESPAsyncTCP.h"
|
||||
#include "flash_hal.h"
|
||||
#include "FS.h"
|
||||
#elif defined(ESP32)
|
||||
#include "WiFi.h"
|
||||
#include "AsyncTCP.h"
|
||||
#include "Update.h"
|
||||
#include "esp_int_wdt.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#endif
|
||||
|
||||
#include "Hash.h"
|
||||
#include "ESPAsyncWebServer.h"
|
||||
#include "FS.h"
|
||||
|
||||
#include "elegantWebpage.h"
|
||||
|
||||
|
||||
class AsyncElegantOtaClass{
|
||||
|
||||
public:
|
||||
void
|
||||
setID(const char* id),
|
||||
begin(AsyncWebServer *server, const char* username = "", const char* password = ""),
|
||||
loop(),
|
||||
restart();
|
||||
|
||||
private:
|
||||
AsyncWebServer *_server;
|
||||
|
||||
String getID();
|
||||
|
||||
String _id = getID();
|
||||
String _username = "";
|
||||
String _password = "";
|
||||
bool _authRequired = false;
|
||||
|
||||
};
|
||||
|
||||
extern AsyncElegantOtaClass AsyncElegantOTA;
|
||||
|
||||
#endif
|
||||
38
arch/esp32/AsyncElegantOTA/src/Hash.h
Normal file
38
arch/esp32/AsyncElegantOTA/src/Hash.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file Hash.h
|
||||
* @date 20.05.2015
|
||||
* @author Markus Sattler
|
||||
*
|
||||
* 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 HASH_H_
|
||||
#define HASH_H_
|
||||
|
||||
//#define DEBUG_SHA1
|
||||
|
||||
void sha1(const uint8_t* data, uint32_t size, uint8_t hash[20]);
|
||||
void sha1(const char* data, uint32_t size, uint8_t hash[20]);
|
||||
void sha1(const String& data, uint8_t hash[20]);
|
||||
|
||||
String sha1(const uint8_t* data, uint32_t size);
|
||||
String sha1(const char* data, uint32_t size);
|
||||
String sha1(const String& data);
|
||||
|
||||
#endif /* HASH_H_ */
|
||||
1799
arch/esp32/AsyncElegantOTA/src/elegantWebpage.h
Normal file
1799
arch/esp32/AsyncElegantOTA/src/elegantWebpage.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -40,7 +40,10 @@ extra_scripts = merge-bin.py
|
||||
build_flags = ${arduino_base.build_flags}
|
||||
; -D ESP32_CPU_FREQ=80 ; change it to your need
|
||||
build_src_filter = ${arduino_base.build_src_filter}
|
||||
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
me-no-dev/ESPAsyncWebServer @ ^3.6.0
|
||||
file://arch/esp32/AsyncElegantOTA
|
||||
|
||||
; ----------------- NRF52 ---------------------
|
||||
[nrf52_base]
|
||||
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
virtual void reboot() = 0;
|
||||
virtual void powerOff() { /* no op */ }
|
||||
virtual uint8_t getStartupReason() const = 0;
|
||||
virtual bool startOTAUpdate() { return false; } // not supported
|
||||
virtual bool startOTAUpdate(const char* id, char reply[]) { return false; } // not supported
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -129,9 +129,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
||||
strcpy(reply, "ERR: clock cannot go backwards");
|
||||
}
|
||||
} else if (memcmp(command, "start ota", 9) == 0) {
|
||||
if (_board->startOTAUpdate()) {
|
||||
strcpy(reply, "OK");
|
||||
} else {
|
||||
if (!_board->startOTAUpdate(_prefs->node_name, reply)) {
|
||||
strcpy(reply, "Error");
|
||||
}
|
||||
} else if (memcmp(command, "clock", 5) == 0) {
|
||||
|
||||
32
src/helpers/ESP32Board.cpp
Normal file
32
src/helpers/ESP32Board.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
#include "ESP32Board.h"
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <AsyncElegantOTA.h>
|
||||
|
||||
bool ESP32Board::startOTAUpdate(const char* id, char reply[]) {
|
||||
WiFi.softAP("MeshCore-OTA", NULL);
|
||||
|
||||
sprintf(reply, "Started: http://%s/update", WiFi.softAPIP().toString().c_str());
|
||||
MESH_DEBUG_PRINTLN("startOTAUpdate: %s", reply);
|
||||
|
||||
static char id_buf[60];
|
||||
sprintf(id_buf, "%s (%s)", id, getManufacturerName());
|
||||
static char home_buf[90];
|
||||
sprintf(home_buf, "<H2>Hi! I am a MeshCore Repeater. ID: %s</H2>", id);
|
||||
|
||||
AsyncWebServer* server = new AsyncWebServer(80);
|
||||
|
||||
server->on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
request->send(200, "text/html", home_buf);
|
||||
});
|
||||
|
||||
AsyncElegantOTA.setID(id_buf);
|
||||
AsyncElegantOTA.begin(server); // Start ElegantOTA
|
||||
server->begin();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -74,6 +74,8 @@ public:
|
||||
void reboot() override {
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
bool startOTAUpdate(const char* id, char reply[]) override;
|
||||
};
|
||||
|
||||
class ESP32RTCClock : public mesh::RTCClock {
|
||||
|
||||
@@ -37,7 +37,7 @@ void RAK4631Board::begin() {
|
||||
delay(10); // give sx1262 some time to power up
|
||||
}
|
||||
|
||||
bool RAK4631Board::startOTAUpdate() {
|
||||
bool RAK4631Board::startOTAUpdate(const char* id, char reply[]) {
|
||||
// Config the peripheral connection with maximum bandwidth
|
||||
// more SRAM required by SoftDevice
|
||||
// Note: All config***() function must be called before begin()
|
||||
@@ -76,5 +76,6 @@ bool RAK4631Board::startOTAUpdate() {
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
|
||||
|
||||
strcpy(reply, "OK - started");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -50,5 +50,5 @@ public:
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
bool startOTAUpdate() override;
|
||||
bool startOTAUpdate(const char* id, char reply[]) override;
|
||||
};
|
||||
|
||||
@@ -42,7 +42,7 @@ static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
|
||||
}
|
||||
|
||||
|
||||
bool TrackerT1000eBoard::startOTAUpdate() {
|
||||
bool TrackerT1000eBoard::startOTAUpdate(const char* id, char reply[]) {
|
||||
// Config the peripheral connection with maximum bandwidth
|
||||
// more SRAM required by SoftDevice
|
||||
// Note: All config***() function must be called before begin()
|
||||
@@ -81,6 +81,7 @@ bool TrackerT1000eBoard::startOTAUpdate() {
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
|
||||
|
||||
strcpy(reply, "OK - started");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -90,5 +90,5 @@ public:
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
// bool startOTAUpdate() override;
|
||||
// bool startOTAUpdate(const char* id, char reply[]) override;
|
||||
};
|
||||
@@ -42,7 +42,7 @@ void T114Board::begin() {
|
||||
delay(10); // give sx1262 some time to power up
|
||||
}
|
||||
|
||||
bool T114Board::startOTAUpdate() {
|
||||
bool T114Board::startOTAUpdate(const char* id, char reply[]) {
|
||||
// Config the peripheral connection with maximum bandwidth
|
||||
// more SRAM required by SoftDevice
|
||||
// Note: All config***() function must be called before begin()
|
||||
@@ -81,5 +81,6 @@ bool T114Board::startOTAUpdate() {
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
|
||||
|
||||
strcpy(reply, "OK - started");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -60,5 +60,5 @@ public:
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
bool startOTAUpdate() override;
|
||||
bool startOTAUpdate(const char* id, char reply[]) override;
|
||||
};
|
||||
|
||||
@@ -35,7 +35,7 @@ void TechoBoard::begin() {
|
||||
delay(10); // give sx1262 some time to power up
|
||||
}
|
||||
|
||||
bool TechoBoard::startOTAUpdate() {
|
||||
bool TechoBoard::startOTAUpdate(const char* id, char reply[]) {
|
||||
// Config the peripheral connection with maximum bandwidth
|
||||
// more SRAM required by SoftDevice
|
||||
// Note: All config***() function must be called before begin()
|
||||
@@ -74,5 +74,6 @@ bool TechoBoard::startOTAUpdate() {
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
|
||||
|
||||
strcpy(reply, "OK - started");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -49,5 +49,5 @@ public:
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
bool startOTAUpdate() override;
|
||||
bool startOTAUpdate(const char* id, char reply[]) override;
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
|
||||
MESH_DEBUG_PRINTLN("BLE client disconnected");
|
||||
}
|
||||
|
||||
bool FaketecBoard::startOTAUpdate() {
|
||||
bool FaketecBoard::startOTAUpdate(const char* id, char reply[]) {
|
||||
// Config the peripheral connection with maximum bandwidth
|
||||
// more SRAM required by SoftDevice
|
||||
// Note: All config***() function must be called before begin()
|
||||
@@ -78,5 +78,6 @@ bool FaketecBoard::startOTAUpdate() {
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
|
||||
|
||||
strcpy(reply, "OK - started");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -61,5 +61,5 @@ public:
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
bool startOTAUpdate() override;
|
||||
bool startOTAUpdate(const char* id, char reply[]) override;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user