mirror of
https://github.com/m5stack/M5Stack.git
synced 2026-05-20 10:06:46 -07:00
+31
-2
@@ -11,10 +11,16 @@ void M5Stack::begin()
|
||||
pinMode(BEEP_PIN, OUTPUT);
|
||||
digitalWrite(BEEP_PIN, 0);
|
||||
|
||||
// LED init
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
|
||||
// Setup the button with an internal pull-up
|
||||
btn_pins[BTN_A] = BUTTON_A_PIN;
|
||||
btn_pins[BTN_B] = BUTTON_B_PIN;
|
||||
btn_pins[BTN_C] = BUTTON_C_PIN;
|
||||
pinMode(BUTTON_A_PIN, INPUT_PULLUP);
|
||||
pinMode(BUTTON_B_PIN, INPUT_PULLUP);
|
||||
pinMode(BUTTON_C_PIN, INPUT_PULLUP);
|
||||
|
||||
// M5.lcd INIT
|
||||
lcd.begin();
|
||||
@@ -33,7 +39,7 @@ void M5Stack::loop()
|
||||
{
|
||||
// buttons reads each button btn_states and store it
|
||||
for (uint8_t thisButton = 0; thisButton < NUM_BTN; thisButton++) {
|
||||
pinMode(btn_pins[thisButton], INPUT_PULLUP); //enable internal pull up resistors
|
||||
// pinMode(btn_pins[thisButton], INPUT_PULLUP); //enable internal pull up resistors
|
||||
if (digitalRead(btn_pins[thisButton]) == LOW) { //if button pressed
|
||||
btn_states[thisButton]++; //increase button hold time
|
||||
} else {
|
||||
@@ -44,7 +50,7 @@ void M5Stack::loop()
|
||||
else
|
||||
btn_states[thisButton] = 0xFF; //button just released
|
||||
}
|
||||
pinMode(btn_pins[thisButton], INPUT); //disable internal pull up resistors to save power
|
||||
// pinMode(btn_pins[thisButton], INPUT); //disable internal pull up resistors to save power
|
||||
}
|
||||
|
||||
// TFTLCD button update
|
||||
@@ -82,6 +88,29 @@ uint8_t M5Stack::bootSetup()
|
||||
return select_app_id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn ON LED
|
||||
*/
|
||||
void M5Stack::ledOn() {
|
||||
digitalWrite(LED_PIN, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn OFF LED
|
||||
*/
|
||||
void M5Stack::ledOff() {
|
||||
digitalWrite(LED_PIN, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ledTrig LED
|
||||
*/
|
||||
void M5Stack::ledTrig() {
|
||||
static bool tgbit;
|
||||
digitalWrite(LED_PIN, tgbit);
|
||||
tgbit = !tgbit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true when 'button' is pressed.
|
||||
* The button has to be released for it to be triggered again.
|
||||
|
||||
@@ -16,12 +16,23 @@
|
||||
#include "utility/bootmenu.h"
|
||||
#include "utility/config.h"
|
||||
|
||||
#ifdef ENABLE_DEBUG
|
||||
#define M5PUTLOG(X) Serial.printf(X)
|
||||
#else
|
||||
#define M5PUTLOG(X)
|
||||
#endif
|
||||
|
||||
class M5Stack {
|
||||
public:
|
||||
void begin();
|
||||
uint8_t bootSetup();
|
||||
void loop();
|
||||
|
||||
//LED
|
||||
void ledOn();
|
||||
void ledOff();
|
||||
void ledTrig();
|
||||
|
||||
// button API
|
||||
bool pressed(uint8_t button);
|
||||
bool released(uint8_t button);
|
||||
|
||||
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,40 @@
|
||||
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
|
||||
|
||||
//needed for library
|
||||
// #include <DNSServer.h>
|
||||
#include <ESPmDNS.h>
|
||||
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
|
||||
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
Serial.begin(115200);
|
||||
|
||||
//WiFiManager
|
||||
//Local intialization. Once its business is done, there is no need to keep it around
|
||||
WiFiManager wifiManager;
|
||||
//reset saved settings
|
||||
//wifiManager.resetSettings();
|
||||
|
||||
//set custom ip for portal
|
||||
//wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
|
||||
|
||||
//fetches ssid and pass from eeprom and tries to connect
|
||||
//if it does not connect it starts an access point with the specified name
|
||||
//here "AutoConnectAP"
|
||||
//and goes into a blocking loop awaiting configuration
|
||||
wifiManager.autoConnect("AutoConnectAP");
|
||||
//or use this for auto generated name ESP + ChipID
|
||||
//wifiManager.autoConnect();
|
||||
|
||||
|
||||
//if you get here you have connected to the WiFi
|
||||
Serial.println("connected...yeey :)");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,195 @@
|
||||
/**************************************************************
|
||||
WiFiManager is a library for the ESP8266/Arduino platform
|
||||
(https://github.com/esp8266/Arduino) to enable easy
|
||||
configuration and reconfiguration of WiFi credentials using a Captive Portal
|
||||
inspired by:
|
||||
http://www.esp8266.com/viewtopic.php?f=29&t=2520
|
||||
https://github.com/chriscook8/esp-arduino-apboot
|
||||
https://github.com/esp8266/Arduino/tree/esp8266/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortalAdvanced
|
||||
Built by AlexT https://github.com/tzapu
|
||||
Licensed under MIT license
|
||||
**************************************************************/
|
||||
|
||||
#ifndef WiFiManager_h
|
||||
#define WiFiManager_h
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WebServer.h>
|
||||
// #include <DNSServer.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <memory>
|
||||
|
||||
// extern "C" {
|
||||
// #include "user_interface.h"
|
||||
// }
|
||||
|
||||
const char HTTP_HEAD[] PROGMEM = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/><title>{v}</title>";
|
||||
const char HTTP_STYLE[] PROGMEM = "<style>.c{text-align: center;} div,input{padding:5px;font-size:1em;} input{width:95%;} body{text-align: center;font-family:verdana;} button{border:0;border-radius:0.3rem;background-color:#1fa3ec;color:#fff;line-height:2.4rem;font-size:1.2rem;width:100%;} .q{float: right;width: 64px;text-align: right;} .l{background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAALVBMVEX///8EBwfBwsLw8PAzNjaCg4NTVVUjJiZDRUUUFxdiZGSho6OSk5Pg4eFydHTCjaf3AAAAZElEQVQ4je2NSw7AIAhEBamKn97/uMXEGBvozkWb9C2Zx4xzWykBhFAeYp9gkLyZE0zIMno9n4g19hmdY39scwqVkOXaxph0ZCXQcqxSpgQpONa59wkRDOL93eAXvimwlbPbwwVAegLS1HGfZAAAAABJRU5ErkJggg==\") no-repeat left center;background-size: 1em;}</style>";
|
||||
const char HTTP_SCRIPT[] PROGMEM = "<script>function c(l){document.getElementById('s').value=l.innerText||l.textContent;document.getElementById('p').focus();}</script>";
|
||||
const char HTTP_HEAD_END[] PROGMEM = "</head><body><div style='text-align:left;display:inline-block;min-width:260px;'>";
|
||||
const char HTTP_PORTAL_OPTIONS[] PROGMEM = "<form action=\"/wifi\" method=\"get\"><button>Configure WiFi</button></form><br/><form action=\"/0wifi\" method=\"get\"><button>Configure WiFi (No Scan)</button></form><br/><form action=\"/i\" method=\"get\"><button>Info</button></form><br/><form action=\"/r\" method=\"post\"><button>Reset</button></form>";
|
||||
const char HTTP_ITEM[] PROGMEM = "<div><a href='#p' onclick='c(this)'>{v}</a> <span class='q {i}'>{r}%</span></div>";
|
||||
const char HTTP_FORM_START[] PROGMEM = "<form method='get' action='wifisave'><input id='s' name='s' length=32 placeholder='SSID'><br/><input id='p' name='p' length=64 type='password' placeholder='password'><br/>";
|
||||
const char HTTP_FORM_PARAM[] PROGMEM = "<br/><input id='{i}' name='{n}' length={l} placeholder='{p}' value='{v}' {c}>";
|
||||
const char HTTP_FORM_END[] PROGMEM = "<br/><button type='submit'>save</button></form>";
|
||||
const char HTTP_SCAN_LINK[] PROGMEM = "<br/><div class=\"c\"><a href=\"/wifi\">Scan</a></div>";
|
||||
const char HTTP_SAVED[] PROGMEM = "<div>Credentials Saved<br />Trying to connect ESP to network.<br />If it fails reconnect to AP to try again</div>";
|
||||
const char HTTP_END[] PROGMEM = "</div></body></html>";
|
||||
|
||||
#define WIFI_MANAGER_MAX_PARAMS 10
|
||||
|
||||
class WiFiManagerParameter {
|
||||
public:
|
||||
WiFiManagerParameter(const char *custom);
|
||||
WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length);
|
||||
WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom);
|
||||
|
||||
const char *getID();
|
||||
const char *getValue();
|
||||
const char *getPlaceholder();
|
||||
int getValueLength();
|
||||
const char *getCustomHTML();
|
||||
private:
|
||||
const char *_id;
|
||||
const char *_placeholder;
|
||||
char *_value;
|
||||
int _length;
|
||||
const char *_customHTML;
|
||||
|
||||
void init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom);
|
||||
|
||||
friend class WiFiManager;
|
||||
};
|
||||
|
||||
|
||||
class WiFiManager
|
||||
{
|
||||
public:
|
||||
WiFiManager();
|
||||
|
||||
boolean autoConnect();
|
||||
boolean autoConnect(char const *apName, char const *apPassword = NULL);
|
||||
|
||||
//if you want to always start the config portal, without trying to connect first
|
||||
boolean startConfigPortal();
|
||||
boolean startConfigPortal(char const *apName, char const *apPassword = NULL);
|
||||
|
||||
// get the AP name of the config portal, so it can be used in the callback
|
||||
String getConfigPortalSSID();
|
||||
|
||||
void resetSettings();
|
||||
|
||||
//sets timeout before webserver loop ends and exits even if there has been no setup.
|
||||
//usefully for devices that failed to connect at some point and got stuck in a webserver loop
|
||||
//in seconds setConfigPortalTimeout is a new name for setTimeout
|
||||
void setConfigPortalTimeout(unsigned long seconds);
|
||||
void setTimeout(unsigned long seconds);
|
||||
|
||||
//sets timeout for which to attempt connecting, usefull if you get a lot of failed connects
|
||||
void setConnectTimeout(unsigned long seconds);
|
||||
|
||||
|
||||
void setDebugOutput(boolean debug);
|
||||
//defaults to not showing anything under 8% signal quality if called
|
||||
void setMinimumSignalQuality(int quality = 8);
|
||||
//sets a custom ip /gateway /subnet configuration
|
||||
void setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn);
|
||||
//sets config for a static IP
|
||||
void setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn);
|
||||
//called when AP mode and config portal is started
|
||||
void setAPCallback( void (*func)(WiFiManager*) );
|
||||
//called when settings have been changed and connection was successful
|
||||
void setSaveConfigCallback( void (*func)(void) );
|
||||
//adds a custom parameter
|
||||
void addParameter(WiFiManagerParameter *p);
|
||||
//if this is set, it will exit after config, even if connection is unsucessful.
|
||||
void setBreakAfterConfig(boolean shouldBreak);
|
||||
//if this is set, try WPS setup when starting (this will delay config portal for up to 2 mins)
|
||||
//TODO
|
||||
//if this is set, customise style
|
||||
void setCustomHeadElement(const char* element);
|
||||
//if this is true, remove duplicated Access Points - defaut true
|
||||
void setRemoveDuplicateAPs(boolean removeDuplicates);
|
||||
|
||||
private:
|
||||
std::unique_ptr<ESPmDNS> dnsServer;
|
||||
std::unique_ptr<WebServer> server;
|
||||
|
||||
//const int WM_DONE = 0;
|
||||
//const int WM_WAIT = 10;
|
||||
|
||||
//const String HTTP_HEAD = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/><title>{v}</title>";
|
||||
|
||||
void setupConfigPortal();
|
||||
void startWPS();
|
||||
|
||||
const char* _apName = "no-net";
|
||||
const char* _apPassword = NULL;
|
||||
String _ssid = "";
|
||||
String _pass = "";
|
||||
unsigned long _configPortalTimeout = 0;
|
||||
unsigned long _connectTimeout = 0;
|
||||
unsigned long _configPortalStart = 0;
|
||||
|
||||
IPAddress _ap_static_ip;
|
||||
IPAddress _ap_static_gw;
|
||||
IPAddress _ap_static_sn;
|
||||
IPAddress _sta_static_ip;
|
||||
IPAddress _sta_static_gw;
|
||||
IPAddress _sta_static_sn;
|
||||
|
||||
int _paramsCount = 0;
|
||||
int _minimumQuality = -1;
|
||||
boolean _removeDuplicateAPs = true;
|
||||
boolean _shouldBreakAfterConfig = false;
|
||||
boolean _tryWPS = false;
|
||||
|
||||
const char* _customHeadElement = "";
|
||||
|
||||
//String getEEPROMString(int start, int len);
|
||||
//void setEEPROMString(int start, int len, String string);
|
||||
|
||||
int status = WL_IDLE_STATUS;
|
||||
int connectWifi(String ssid, String pass);
|
||||
uint8_t waitForConnectResult();
|
||||
|
||||
void handleRoot();
|
||||
void handleWifi(boolean scan);
|
||||
void handleWifiSave();
|
||||
void handleInfo();
|
||||
void handleReset();
|
||||
void handleNotFound();
|
||||
void handle204();
|
||||
boolean captivePortal();
|
||||
boolean configPortalHasTimeout();
|
||||
|
||||
// DNS server
|
||||
const byte DNS_PORT = 53;
|
||||
|
||||
//helpers
|
||||
int getRSSIasQuality(int RSSI);
|
||||
boolean isIp(String str);
|
||||
String toStringIp(IPAddress ip);
|
||||
|
||||
boolean connect;
|
||||
boolean _debug = true;
|
||||
|
||||
void (*_apcallback)(WiFiManager*) = NULL;
|
||||
void (*_savecallback)(void) = NULL;
|
||||
|
||||
WiFiManagerParameter* _params[WIFI_MANAGER_MAX_PARAMS];
|
||||
|
||||
template <typename Generic>
|
||||
void DEBUG_WM(Generic text);
|
||||
|
||||
template <class T>
|
||||
auto optionalIPFromString(T *obj, const char *s) -> decltype( obj->fromString(s) ) {
|
||||
return obj->fromString(s);
|
||||
}
|
||||
auto optionalIPFromString(...) -> bool {
|
||||
DEBUG_WM("NO fromString METHOD ON IPAddress, you need ESP8266 core 2.1.0 or newer for Custom IP configuration to work.");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,81 @@
|
||||
#include <M5Stack.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
bool getParamFromTFCard(const char* filename, const char* keyword, char* strout) {
|
||||
// fs file read
|
||||
File fsFile;
|
||||
uint8_t fsbuffer[255];
|
||||
// const char* filename = "/azure-config.json";
|
||||
if(SD.exists(filename)) {
|
||||
fsFile = SD.open(filename, "r");
|
||||
if(fsFile) {
|
||||
Serial.printf("Success open file:\r\n");
|
||||
fsFile.read(fsbuffer, fsFile.size());
|
||||
Serial.printf("\r\n");
|
||||
fsbuffer[fsFile.size()] = 0;
|
||||
Serial.printf("%s", fsbuffer);
|
||||
} else {
|
||||
Serial.printf("Fail open file!\r\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Memory pool for JSON object tree.
|
||||
//
|
||||
// Inside the brackets, 200 is the size of the pool in bytes,
|
||||
// If the JSON object is more complex, you need to increase that value.
|
||||
StaticJsonBuffer<200> jsonBuffer;
|
||||
|
||||
// StaticJsonBuffer allocates memory on the stack, it can be
|
||||
// replaced by DynamicJsonBuffer which allocates in the heap.
|
||||
// It's simpler but less efficient.
|
||||
//
|
||||
// DynamicJsonBuffer jsonBuffer;
|
||||
|
||||
// Root of the object tree.
|
||||
//
|
||||
// It's a reference to the JsonObject, the actual bytes are inside the
|
||||
// JsonBuffer with all the other nodes of the object tree.
|
||||
// Memory is freed when jsonBuffer goes out of scope.
|
||||
JsonObject& root = jsonBuffer.parseObject(fsbuffer);
|
||||
|
||||
// Test if parsing succeeds.
|
||||
if (!root.success()) {
|
||||
Serial.println("parseObject() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fetch values.
|
||||
//
|
||||
// Most of the time, you can rely on the implicit casts.
|
||||
// In other case, you can do root["time"].as<long>();
|
||||
const char* value = root[keyword];
|
||||
|
||||
// Copy values.
|
||||
strcpy((char*)strout, value);
|
||||
Serial.printf("Keyword:%s\r\nValue:%s\r\n", keyword, strout);
|
||||
return true;
|
||||
}
|
||||
|
||||
// the setup routine runs once when M5Stack starts up
|
||||
void setup(){
|
||||
|
||||
// initialize the M5Stack object
|
||||
m5.begin();
|
||||
|
||||
// lcd display
|
||||
m5.lcd.printf("JSON test");
|
||||
|
||||
char ssid[30];
|
||||
if(getParamFromTFCard("/azure-config.json", "WiFi_SSID", ssid)) {
|
||||
Serial.printf("Read Value:%s", ssid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// the loop routine runs over and over again forever
|
||||
void loop(){
|
||||
|
||||
m5.loop();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"WiFi_SSID":"MasterHax_2.4G",
|
||||
"WiFi_PASSWORD":"wittyercheese551",
|
||||
"AzureDeviceID":"test001",
|
||||
"ConnectingString":"m5statck-abcde"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <M5Stack.h>
|
||||
|
||||
// the setup routine runs once when M5Stack starts up
|
||||
void setup(){
|
||||
// initialize the M5Stack object
|
||||
m5.begin();
|
||||
}
|
||||
|
||||
// the loop routine runs over and over again forever
|
||||
void loop(){
|
||||
|
||||
m5.lcd.drawPicture("/ROBOT2.bmp");
|
||||
m5.lcd.drawPicture("/ROBOT3.bmp");
|
||||
m5.lcd.drawPicture("/ROBOT4.bmp");
|
||||
m5.lcd.drawPicture("/ROBOT5.bmp");
|
||||
|
||||
m5.loop();
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
#include <M5Stack.h>
|
||||
#include <WiFi.h>
|
||||
// #include <DNSServer.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <WiFiClient.h>
|
||||
// #include <EEPROM.h>
|
||||
#include <WebServer.h>
|
||||
#include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
const IPAddress apIP(192, 168, 1, 1);
|
||||
const char* apSSID = "M5STACK_SETUP";
|
||||
boolean settingMode;
|
||||
String ssidList;
|
||||
char wifi_ssid[40];
|
||||
char wifi_password[40];
|
||||
|
||||
// DNSServer dnsServer;
|
||||
WebServer webServer(80);
|
||||
|
||||
void writeFile(fs::FS &fs, const char * path, const char * message) {
|
||||
Serial.printf("Writing file: %s\n", path);
|
||||
|
||||
File file = fs.open(path, FILE_WRITE);
|
||||
if (!file) {
|
||||
Serial.println("Failed to open file for writing");
|
||||
return;
|
||||
}
|
||||
if (file.print(message)) {
|
||||
Serial.println("File written");
|
||||
} else {
|
||||
Serial.println("Write failed");
|
||||
}
|
||||
}
|
||||
|
||||
void deleteFile(fs::FS &fs, const char * path) {
|
||||
Serial.printf("Deleting file: %s\n", path);
|
||||
if (fs.remove(path)) {
|
||||
Serial.println("File deleted");
|
||||
} else {
|
||||
Serial.println("Delete failed");
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
m5.begin();
|
||||
// EEPROM.begin(512);
|
||||
delay(10);
|
||||
if (restoreConfig()) {
|
||||
if (checkConnection()) {
|
||||
settingMode = false;
|
||||
startWebServer();
|
||||
return;
|
||||
}
|
||||
}
|
||||
settingMode = true;
|
||||
setupMode();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (settingMode) {
|
||||
// dnsServer.processNextRequest();
|
||||
}
|
||||
webServer.handleClient();
|
||||
}
|
||||
|
||||
boolean restoreConfig() {
|
||||
// char fsbuffer[200];
|
||||
const char* filename = "/wifi-config.json";
|
||||
Serial.printf("Reading %s\r\n", filename);
|
||||
if (SD.exists(filename)) {
|
||||
//file exists, reading and loading
|
||||
Serial.println("reading config file");
|
||||
File configFile = SD.open(filename, "r");
|
||||
if (configFile) {
|
||||
Serial.println("opened config file");
|
||||
size_t size = configFile.size();
|
||||
// Allocate a buffer to store contents of the file.
|
||||
std::unique_ptr<char[]> fsbuffer(new char[size]);
|
||||
|
||||
configFile.readBytes(fsbuffer.get(), size);
|
||||
// configFile.readBytes(fsbuffer, size);
|
||||
fsbuffer[size] = 0;
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
// JsonObject& json = jsonBuffer.parseObject(fsbuffer);
|
||||
JsonObject& json = jsonBuffer.parseObject(fsbuffer.get());
|
||||
json.printTo(Serial);
|
||||
if (json.success()) {
|
||||
Serial.println("\nparsed json");
|
||||
// const char* wifi = json["WiFi_SSID"];
|
||||
// const char* passwd = json["WiFi_PASSWORD"];
|
||||
strcpy(wifi_ssid, json["WiFi_SSID"]);
|
||||
strcpy(wifi_password, json["WiFi_PASSWORD"]);
|
||||
Serial.printf("SSID:%s\r\n", wifi_ssid);
|
||||
Serial.printf("PASSWORD:%s\r\n", wifi_password);
|
||||
WiFi.begin(wifi_ssid, wifi_password);
|
||||
return true;
|
||||
} else {
|
||||
Serial.println("failed to load json config");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Serial.printf("file isn't exists.\r\n");
|
||||
writeFile(SD, "/wifi-config.json", "{\"WiFi_SSID\":\"xMasterHax_2.4G\",\"WiFi_PASSWORD\":\"wittyercheese551\",\"AzureDeviceID\":\"test001\",\"ConnectingString\":\"m5statck-abcde\"}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean checkConnection() {
|
||||
int count = 0;
|
||||
Serial.print("Waiting for Wi-Fi connection");
|
||||
while ( count < 30 ) {
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Serial.println();
|
||||
Serial.println("Connected!");
|
||||
return (true);
|
||||
}
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
count++;
|
||||
}
|
||||
Serial.println("Timed out.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void startWebServer() {
|
||||
if (settingMode) {
|
||||
Serial.print("Starting Web Server at ");
|
||||
Serial.println(WiFi.softAPIP());
|
||||
webServer.on("/settings", []() {
|
||||
String s = "<h1>Wi-Fi Settings</h1><p>Please enter your password by selecting the SSID.</p>";
|
||||
s += "<form method=\"get\" action=\"setap\"><label>SSID: </label><select name=\"ssid\">";
|
||||
s += ssidList;
|
||||
s += "</select><br>Password: <input name=\"pass\" length=64 type=\"password\"><input type=\"submit\"></form>";
|
||||
webServer.send(200, "text/html", makePage("Wi-Fi Settings", s));
|
||||
});
|
||||
webServer.on("/setap", []() {
|
||||
// for (int i = 0; i < 96; ++i) {
|
||||
// EEPROM.write(i, 0);
|
||||
// }
|
||||
String ssid = urlDecode(webServer.arg("ssid"));
|
||||
Serial.print("SSID: ");
|
||||
Serial.println(ssid);
|
||||
String pass = urlDecode(webServer.arg("pass"));
|
||||
Serial.print("Password: ");
|
||||
Serial.println(pass);
|
||||
Serial.println("Writing SSID to EEPROM...");
|
||||
|
||||
//----------------file--------------------
|
||||
const char* filename = "/wifi-config.json";
|
||||
if (SD.exists(filename)) {
|
||||
//file exists, reading and loading
|
||||
Serial.println("reading config file");
|
||||
File configFile = SD.open(filename, "r");
|
||||
if (configFile) {
|
||||
Serial.println("opened config file");
|
||||
size_t size = configFile.size();
|
||||
// Allocate a buffer to store contents of the file.
|
||||
std::unique_ptr<char[]> fsbuffer(new char[size]);
|
||||
|
||||
configFile.readBytes(fsbuffer.get(), size);
|
||||
// configFile.readBytes(fsbuffer, size);
|
||||
fsbuffer[size] = 0;
|
||||
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.parseObject(fsbuffer.get());
|
||||
root[String("WiFi_SSID")] = ssid;
|
||||
root[String("WiFi_PASSWORD")] = pass;
|
||||
|
||||
String output;
|
||||
root.printTo(output);
|
||||
Serial.printf("Save Json.\r\n");
|
||||
Serial.print(output);
|
||||
configFile.close();
|
||||
|
||||
File configFile = SD.open(filename, "w");
|
||||
if (!configFile) {
|
||||
Serial.println("Failed to open file for writing");
|
||||
return;
|
||||
}
|
||||
|
||||
if (configFile.print(output)) {
|
||||
Serial.println("File written");
|
||||
} else {
|
||||
Serial.println("Write failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------
|
||||
|
||||
for (int i = 0; i < ssid.length(); ++i) {
|
||||
// EEPROM.write(i, ssid[i]);
|
||||
}
|
||||
Serial.println("Writing Password to EEPROM...");
|
||||
for (int i = 0; i < pass.length(); ++i) {
|
||||
// EEPROM.write(32 + i, pass[i]);
|
||||
}
|
||||
// EEPROM.commit();
|
||||
|
||||
|
||||
Serial.println("Write EEPROM done!");
|
||||
String s = "<h1>Setup complete.</h1><p>device will be connected to \"";
|
||||
s += ssid;
|
||||
s += "\" after the restart.";
|
||||
webServer.send(200, "text/html", makePage("Wi-Fi Settings", s));
|
||||
delay(3000);
|
||||
ESP.restart();
|
||||
});
|
||||
webServer.onNotFound([]() {
|
||||
String s = "<h1>AP mode</h1><p><a href=\"/settings\">Wi-Fi Settings</a></p>";
|
||||
webServer.send(200, "text/html", makePage("AP mode", s));
|
||||
});
|
||||
}
|
||||
else {
|
||||
Serial.print("Starting Web Server at ");
|
||||
Serial.println(WiFi.localIP());
|
||||
webServer.on("/", []() {
|
||||
String s = "<h1>STA mode</h1><p><a href=\"/reset\">Reset Wi-Fi Settings</a></p>";
|
||||
webServer.send(200, "text/html", makePage("STA mode", s));
|
||||
});
|
||||
webServer.on("/reset", []() {
|
||||
deleteFile(SD, "/wifi-config.json");
|
||||
String s = "<h1>Wi-Fi settings was reset.</h1><p>Please reset device.</p>";
|
||||
webServer.send(200, "text/html", makePage("Reset Wi-Fi Settings", s));
|
||||
delay(3000);
|
||||
ESP.restart();
|
||||
});
|
||||
}
|
||||
webServer.begin();
|
||||
}
|
||||
|
||||
void setupMode() {
|
||||
WiFi.mode(WIFI_MODE_STA);
|
||||
WiFi.disconnect();
|
||||
delay(100);
|
||||
int n = WiFi.scanNetworks();
|
||||
delay(100);
|
||||
Serial.println("");
|
||||
for (int i = 0; i < n; ++i) {
|
||||
ssidList += "<option value=\"";
|
||||
ssidList += WiFi.SSID(i);
|
||||
ssidList += "\">";
|
||||
ssidList += WiFi.SSID(i);
|
||||
ssidList += "</option>";
|
||||
}
|
||||
delay(100);
|
||||
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
|
||||
WiFi.softAP(apSSID);
|
||||
WiFi.mode(WIFI_MODE_AP);
|
||||
// WiFi.softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet);
|
||||
// WiFi.softAP(const char* ssid, const char* passphrase = NULL, int channel = 1, int ssid_hidden = 0);
|
||||
// dnsServer.start(53, "*", apIP);
|
||||
startWebServer();
|
||||
Serial.print("Starting Access Point at \"");
|
||||
Serial.print(apSSID);
|
||||
Serial.println("\"");
|
||||
}
|
||||
|
||||
String makePage(String title, String contents) {
|
||||
String s = "<!DOCTYPE html><html><head>";
|
||||
s += "<meta name=\"viewport\" content=\"width=device-width,user-scalable=0\">";
|
||||
s += "<title>";
|
||||
s += title;
|
||||
s += "</title></head><body>";
|
||||
s += contents;
|
||||
s += "</body></html>";
|
||||
return s;
|
||||
}
|
||||
|
||||
String urlDecode(String input) {
|
||||
String s = input;
|
||||
s.replace("%20", " ");
|
||||
s.replace("+", " ");
|
||||
s.replace("%21", "!");
|
||||
s.replace("%22", "\"");
|
||||
s.replace("%23", "#");
|
||||
s.replace("%24", "$");
|
||||
s.replace("%25", "%");
|
||||
s.replace("%26", "&");
|
||||
s.replace("%27", "\'");
|
||||
s.replace("%28", "(");
|
||||
s.replace("%29", ")");
|
||||
s.replace("%30", "*");
|
||||
s.replace("%31", "+");
|
||||
s.replace("%2C", ",");
|
||||
s.replace("%2E", ".");
|
||||
s.replace("%2F", "/");
|
||||
s.replace("%2C", ",");
|
||||
s.replace("%3A", ":");
|
||||
s.replace("%3A", ";");
|
||||
s.replace("%3C", "<");
|
||||
s.replace("%3D", "=");
|
||||
s.replace("%3E", ">");
|
||||
s.replace("%3F", "?");
|
||||
s.replace("%40", "@");
|
||||
s.replace("%5B", "[");
|
||||
s.replace("%5C", "\\");
|
||||
s.replace("%5D", "]");
|
||||
s.replace("%5E", "^");
|
||||
s.replace("%5F", "-");
|
||||
s.replace("%60", "`");
|
||||
return s;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* 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_
|
||||
|
||||
#include <memory>
|
||||
#include <Arduino.h>
|
||||
#include <WiFiClient.h>
|
||||
|
||||
#ifdef DEBUG_ESP_HTTP_CLIENT
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define DEBUG_HTTPCLIENT(...) DEBUG_ESP_PORT.printf( __VA_ARGS__ )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_HTTPCLIENT
|
||||
#define DEBUG_HTTPCLIENT(...)
|
||||
#endif
|
||||
|
||||
#define HTTPCLIENT_DEFAULT_TCP_TIMEOUT (5000)
|
||||
|
||||
/// HTTP client errors
|
||||
#define HTTPC_ERROR_CONNECTION_REFUSED (-1)
|
||||
#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)
|
||||
#define HTTPC_ERROR_NO_HTTP_SERVER (-7)
|
||||
#define HTTPC_ERROR_TOO_LESS_RAM (-8)
|
||||
#define HTTPC_ERROR_ENCODING (-9)
|
||||
#define HTTPC_ERROR_STREAM_WRITE (-10)
|
||||
#define HTTPC_ERROR_READ_TIMEOUT (-11)
|
||||
|
||||
/// size for the stream handling
|
||||
#define HTTP_TCP_BUFFER_SIZE (1460)
|
||||
|
||||
/// HTTP codes see RFC7231
|
||||
typedef enum {
|
||||
HTTP_CODE_CONTINUE = 100,
|
||||
HTTP_CODE_SWITCHING_PROTOCOLS = 101,
|
||||
HTTP_CODE_PROCESSING = 102,
|
||||
HTTP_CODE_OK = 200,
|
||||
HTTP_CODE_CREATED = 201,
|
||||
HTTP_CODE_ACCEPTED = 202,
|
||||
HTTP_CODE_NON_AUTHORITATIVE_INFORMATION = 203,
|
||||
HTTP_CODE_NO_CONTENT = 204,
|
||||
HTTP_CODE_RESET_CONTENT = 205,
|
||||
HTTP_CODE_PARTIAL_CONTENT = 206,
|
||||
HTTP_CODE_MULTI_STATUS = 207,
|
||||
HTTP_CODE_ALREADY_REPORTED = 208,
|
||||
HTTP_CODE_IM_USED = 226,
|
||||
HTTP_CODE_MULTIPLE_CHOICES = 300,
|
||||
HTTP_CODE_MOVED_PERMANENTLY = 301,
|
||||
HTTP_CODE_FOUND = 302,
|
||||
HTTP_CODE_SEE_OTHER = 303,
|
||||
HTTP_CODE_NOT_MODIFIED = 304,
|
||||
HTTP_CODE_USE_PROXY = 305,
|
||||
HTTP_CODE_TEMPORARY_REDIRECT = 307,
|
||||
HTTP_CODE_PERMANENT_REDIRECT = 308,
|
||||
HTTP_CODE_BAD_REQUEST = 400,
|
||||
HTTP_CODE_UNAUTHORIZED = 401,
|
||||
HTTP_CODE_PAYMENT_REQUIRED = 402,
|
||||
HTTP_CODE_FORBIDDEN = 403,
|
||||
HTTP_CODE_NOT_FOUND = 404,
|
||||
HTTP_CODE_METHOD_NOT_ALLOWED = 405,
|
||||
HTTP_CODE_NOT_ACCEPTABLE = 406,
|
||||
HTTP_CODE_PROXY_AUTHENTICATION_REQUIRED = 407,
|
||||
HTTP_CODE_REQUEST_TIMEOUT = 408,
|
||||
HTTP_CODE_CONFLICT = 409,
|
||||
HTTP_CODE_GONE = 410,
|
||||
HTTP_CODE_LENGTH_REQUIRED = 411,
|
||||
HTTP_CODE_PRECONDITION_FAILED = 412,
|
||||
HTTP_CODE_PAYLOAD_TOO_LARGE = 413,
|
||||
HTTP_CODE_URI_TOO_LONG = 414,
|
||||
HTTP_CODE_UNSUPPORTED_MEDIA_TYPE = 415,
|
||||
HTTP_CODE_RANGE_NOT_SATISFIABLE = 416,
|
||||
HTTP_CODE_EXPECTATION_FAILED = 417,
|
||||
HTTP_CODE_MISDIRECTED_REQUEST = 421,
|
||||
HTTP_CODE_UNPROCESSABLE_ENTITY = 422,
|
||||
HTTP_CODE_LOCKED = 423,
|
||||
HTTP_CODE_FAILED_DEPENDENCY = 424,
|
||||
HTTP_CODE_UPGRADE_REQUIRED = 426,
|
||||
HTTP_CODE_PRECONDITION_REQUIRED = 428,
|
||||
HTTP_CODE_TOO_MANY_REQUESTS = 429,
|
||||
HTTP_CODE_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
|
||||
HTTP_CODE_INTERNAL_SERVER_ERROR = 500,
|
||||
HTTP_CODE_NOT_IMPLEMENTED = 501,
|
||||
HTTP_CODE_BAD_GATEWAY = 502,
|
||||
HTTP_CODE_SERVICE_UNAVAILABLE = 503,
|
||||
HTTP_CODE_GATEWAY_TIMEOUT = 504,
|
||||
HTTP_CODE_HTTP_VERSION_NOT_SUPPORTED = 505,
|
||||
HTTP_CODE_VARIANT_ALSO_NEGOTIATES = 506,
|
||||
HTTP_CODE_INSUFFICIENT_STORAGE = 507,
|
||||
HTTP_CODE_LOOP_DETECTED = 508,
|
||||
HTTP_CODE_NOT_EXTENDED = 510,
|
||||
HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED = 511
|
||||
} t_http_codes;
|
||||
|
||||
typedef enum {
|
||||
HTTPC_TE_IDENTITY,
|
||||
HTTPC_TE_CHUNKED
|
||||
} transferEncoding_t;
|
||||
|
||||
class TransportTraits;
|
||||
typedef std::unique_ptr<TransportTraits> TransportTraitsPtr;
|
||||
|
||||
class HTTPClient
|
||||
{
|
||||
public:
|
||||
HTTPClient();
|
||||
~HTTPClient();
|
||||
|
||||
bool begin(String url);
|
||||
bool begin(String url, String httpsFingerprint);
|
||||
bool begin(String host, uint16_t port, String uri = "/");
|
||||
bool begin(String host, uint16_t port, String uri, String httpsFingerprint);
|
||||
// deprecated, use the overload above instead
|
||||
bool begin(String host, uint16_t port, String uri, bool https, String httpsFingerprint) __attribute__ ((deprecated));
|
||||
|
||||
void end(void);
|
||||
|
||||
bool connected(void);
|
||||
|
||||
void setReuse(bool reuse); /// keep-alive
|
||||
void setUserAgent(const String& userAgent);
|
||||
void setAuthorization(const char * user, const char * password);
|
||||
void setAuthorization(const char * auth);
|
||||
void setTimeout(uint16_t timeout);
|
||||
|
||||
void useHTTP10(bool usehttp10 = true);
|
||||
|
||||
/// request handling
|
||||
int GET();
|
||||
int POST(uint8_t * payload, size_t size);
|
||||
int POST(String payload);
|
||||
int PUT(uint8_t * payload, size_t size);
|
||||
int PUT(String payload);
|
||||
int sendRequest(const char * type, String payload);
|
||||
int sendRequest(const char * type, uint8_t * payload = NULL, size_t size = 0);
|
||||
int sendRequest(const char * type, Stream * stream, size_t size = 0);
|
||||
|
||||
void addHeader(const String& name, const String& value, bool first = false, bool replace = true);
|
||||
|
||||
/// Response handling
|
||||
void collectHeaders(const char* headerKeys[], const size_t headerKeysCount);
|
||||
String header(const char* name); // get request header value by name
|
||||
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
|
||||
|
||||
|
||||
int getSize(void);
|
||||
|
||||
WiFiClient& getStream(void);
|
||||
WiFiClient* getStreamPtr(void);
|
||||
int writeToStream(Stream* stream);
|
||||
String getString(void);
|
||||
|
||||
static String errorToString(int error);
|
||||
|
||||
protected:
|
||||
struct RequestArgument {
|
||||
String key;
|
||||
String value;
|
||||
};
|
||||
|
||||
bool beginInternal(String url, const char* expectedProtocol);
|
||||
void clear();
|
||||
int returnError(int error);
|
||||
bool connect(void);
|
||||
bool sendHeader(const char * type);
|
||||
int handleHeaderResponse();
|
||||
int writeToStreamDataBlock(Stream * stream, int len);
|
||||
|
||||
|
||||
TransportTraitsPtr _transportTraits;
|
||||
std::unique_ptr<WiFiClient> _tcp;
|
||||
|
||||
/// request handling
|
||||
String _host;
|
||||
uint16_t _port = 0;
|
||||
bool _reuse = false;
|
||||
uint16_t _tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
|
||||
bool _useHTTP10 = false;
|
||||
|
||||
String _uri;
|
||||
String _protocol;
|
||||
String _headers;
|
||||
String _userAgent = "ESP8266HTTPClient";
|
||||
String _base64Authorization;
|
||||
|
||||
/// Response handling
|
||||
RequestArgument* _currentHeaders = nullptr;
|
||||
size_t _headerKeysCount = 0;
|
||||
|
||||
int _returnCode = 0;
|
||||
int _size = -1;
|
||||
bool _canReuse = false;
|
||||
transferEncoding_t _transferEncoding = HTTPC_TE_IDENTITY;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* ESP8266HTTPClient_H_ */
|
||||
@@ -0,0 +1,391 @@
|
||||
/**
|
||||
*
|
||||
* @file ESP8266HTTPUpdate.cpp
|
||||
* @date 21.06.2015
|
||||
* @author Markus Sattler
|
||||
*
|
||||
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
* This file is part of the ESP8266 Http Updater.
|
||||
*
|
||||
* 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 "ESP8266httpUpdate.h"
|
||||
#include <StreamString.h>
|
||||
|
||||
// extern "C" uint32_t _SPIFFS_start;
|
||||
// extern "C" uint32_t _SPIFFS_end;
|
||||
|
||||
ESP8266HTTPUpdate::ESP8266HTTPUpdate(void)
|
||||
{
|
||||
}
|
||||
|
||||
ESP8266HTTPUpdate::~ESP8266HTTPUpdate(void)
|
||||
{
|
||||
}
|
||||
|
||||
HTTPUpdateResult ESP8266HTTPUpdate::update(const String& url, const String& currentVersion,
|
||||
const String& httpsFingerprint, bool reboot)
|
||||
{
|
||||
rebootOnUpdate(reboot);
|
||||
return update(url, currentVersion, httpsFingerprint);
|
||||
}
|
||||
|
||||
HTTPUpdateResult ESP8266HTTPUpdate::update(const String& url, const String& currentVersion)
|
||||
{
|
||||
HTTPClient http;
|
||||
http.begin(url);
|
||||
return handleUpdate(http, currentVersion, false);
|
||||
}
|
||||
|
||||
HTTPUpdateResult ESP8266HTTPUpdate::update(const String& url, const String& currentVersion,
|
||||
const String& httpsFingerprint)
|
||||
{
|
||||
HTTPClient http;
|
||||
http.begin(url, httpsFingerprint);
|
||||
return handleUpdate(http, currentVersion, false);
|
||||
}
|
||||
|
||||
HTTPUpdateResult ESP8266HTTPUpdate::updateSpiffs(const String& url, const String& currentVersion, const String& httpsFingerprint)
|
||||
{
|
||||
HTTPClient http;
|
||||
http.begin(url, httpsFingerprint);
|
||||
return handleUpdate(http, currentVersion, true);
|
||||
}
|
||||
|
||||
HTTPUpdateResult ESP8266HTTPUpdate::updateSpiffs(const String& url, const String& currentVersion)
|
||||
{
|
||||
HTTPClient http;
|
||||
http.begin(url);
|
||||
return handleUpdate(http, currentVersion, true);
|
||||
}
|
||||
|
||||
HTTPUpdateResult ESP8266HTTPUpdate::update(const String& host, uint16_t port, const String& uri, const String& currentVersion,
|
||||
bool https, const String& httpsFingerprint, bool reboot)
|
||||
{
|
||||
rebootOnUpdate(reboot);
|
||||
if (httpsFingerprint.length() == 0) {
|
||||
return update(host, port, uri, currentVersion);
|
||||
} else {
|
||||
return update(host, port, uri, currentVersion, httpsFingerprint);
|
||||
}
|
||||
}
|
||||
|
||||
HTTPUpdateResult ESP8266HTTPUpdate::update(const String& host, uint16_t port, const String& uri,
|
||||
const String& currentVersion)
|
||||
{
|
||||
HTTPClient http;
|
||||
http.begin(host, port, uri);
|
||||
return handleUpdate(http, currentVersion, false);
|
||||
}
|
||||
HTTPUpdateResult ESP8266HTTPUpdate::update(const String& host, uint16_t port, const String& url,
|
||||
const String& currentVersion, const String& httpsFingerprint)
|
||||
{
|
||||
HTTPClient http;
|
||||
http.begin(host, port, url, httpsFingerprint);
|
||||
return handleUpdate(http, currentVersion, false);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* return error code as int
|
||||
* @return int error code
|
||||
*/
|
||||
int ESP8266HTTPUpdate::getLastError(void)
|
||||
{
|
||||
return _lastError;
|
||||
}
|
||||
|
||||
/**
|
||||
* return error code as String
|
||||
* @return String error
|
||||
*/
|
||||
String ESP8266HTTPUpdate::getLastErrorString(void)
|
||||
{
|
||||
|
||||
if(_lastError == 0) {
|
||||
return String(); // no error
|
||||
}
|
||||
|
||||
// error from Update class
|
||||
if(_lastError > 0) {
|
||||
StreamString error;
|
||||
Update.printError(error);
|
||||
error.trim(); // remove line ending
|
||||
return String(F("Update error: ")) + error;
|
||||
}
|
||||
|
||||
// error from http client
|
||||
if(_lastError > -100) {
|
||||
return String(F("HTTP error: ")) + HTTPClient::errorToString(_lastError);
|
||||
}
|
||||
|
||||
switch(_lastError) {
|
||||
case HTTP_UE_TOO_LESS_SPACE:
|
||||
return F("To less space");
|
||||
case HTTP_UE_SERVER_NOT_REPORT_SIZE:
|
||||
return F("Server not Report Size");
|
||||
case HTTP_UE_SERVER_FILE_NOT_FOUND:
|
||||
return F("File not Found (404)");
|
||||
case HTTP_UE_SERVER_FORBIDDEN:
|
||||
return F("Forbidden (403)");
|
||||
case HTTP_UE_SERVER_WRONG_HTTP_CODE:
|
||||
return F("Wrong HTTP code");
|
||||
case HTTP_UE_SERVER_FAULTY_MD5:
|
||||
return F("Faulty MD5");
|
||||
case HTTP_UE_BIN_VERIFY_HEADER_FAILED:
|
||||
return F("Verify bin header failed");
|
||||
case HTTP_UE_BIN_FOR_WRONG_FLASH:
|
||||
return F("bin for wrong flash size");
|
||||
}
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param http HTTPClient *
|
||||
* @param currentVersion const char *
|
||||
* @return HTTPUpdateResult
|
||||
*/
|
||||
HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& currentVersion, bool spiffs)
|
||||
{
|
||||
|
||||
HTTPUpdateResult ret = HTTP_UPDATE_FAILED;
|
||||
|
||||
// use HTTP/1.0 for update since the update handler not support any transfer Encoding
|
||||
http.useHTTP10(true);
|
||||
http.setTimeout(8000);
|
||||
http.setUserAgent(F("ESP8266-http-Update"));
|
||||
// http.addHeader(F("x-ESP8266-STA-MAC"), WiFi.macAddress());
|
||||
// http.addHeader(F("x-ESP8266-AP-MAC"), WiFi.softAPmacAddress());
|
||||
// http.addHeader(F("x-ESP8266-free-space"), String(ESP.getFreeSketchSpace()));
|
||||
// http.addHeader(F("x-ESP8266-sketch-size"), String(ESP.getSketchSize()));
|
||||
// http.addHeader(F("x-ESP8266-sketch-md5"), String(ESP.getSketchMD5()));
|
||||
// http.addHeader(F("x-ESP8266-chip-size"), String(ESP.getFlashChipRealSize()));
|
||||
// http.addHeader(F("x-ESP8266-sdk-version"), ESP.getSdkVersion());
|
||||
|
||||
if(spiffs) {
|
||||
http.addHeader(F("x-ESP8266-mode"), F("spiffs"));
|
||||
} else {
|
||||
http.addHeader(F("x-ESP8266-mode"), F("sketch"));
|
||||
}
|
||||
|
||||
if(currentVersion && currentVersion[0] != 0x00) {
|
||||
http.addHeader(F("x-ESP8266-version"), currentVersion);
|
||||
}
|
||||
|
||||
const char * headerkeys[] = { "x-MD5" };
|
||||
size_t headerkeyssize = sizeof(headerkeys) / sizeof(char*);
|
||||
|
||||
// track these headers
|
||||
http.collectHeaders(headerkeys, headerkeyssize);
|
||||
|
||||
int code = http.GET();
|
||||
int len = http.getSize();
|
||||
|
||||
if(code <= 0) {
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] HTTP error: %s\n", http.errorToString(code).c_str());
|
||||
_lastError = code;
|
||||
http.end();
|
||||
return HTTP_UPDATE_FAILED;
|
||||
}
|
||||
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Header read fin.\n");
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Server header:\n");
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - code: %d\n", code);
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - len: %d\n", len);
|
||||
|
||||
if(http.hasHeader("x-MD5")) {
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - MD5: %s\n", http.header("x-MD5").c_str());
|
||||
}
|
||||
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] ESP8266 info:\n");
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - free Space: %d\n", ESP.getFreeSketchSpace());
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - current Sketch Size: %d\n", ESP.getSketchSize());
|
||||
|
||||
if(currentVersion && currentVersion[0] != 0x00) {
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - current version: %s\n", currentVersion.c_str() );
|
||||
}
|
||||
|
||||
switch(code) {
|
||||
case HTTP_CODE_OK: ///< OK (Start Update)
|
||||
if(len > 0) {
|
||||
bool startUpdate = true;
|
||||
// if(spiffs) {
|
||||
// size_t spiffsSize = ((size_t) &_SPIFFS_end - (size_t) &_SPIFFS_start);
|
||||
// if(len > (int) spiffsSize) {
|
||||
// DEBUG_HTTP_UPDATE("[httpUpdate] spiffsSize to low (%d) needed: %d\n", spiffsSize, len);
|
||||
// startUpdate = false;
|
||||
// }
|
||||
// } else {
|
||||
// if(0/*len > (int) ESP.getFreeSketchSpace()*/) {
|
||||
// // DEBUG_HTTP_UPDATE("[httpUpdate] FreeSketchSpace to low (%d) needed: %d\n", ESP.getFreeSketchSpace(), len);
|
||||
// startUpdate = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
if(!startUpdate) {
|
||||
_lastError = HTTP_UE_TOO_LESS_SPACE;
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
} else {
|
||||
|
||||
WiFiClient * tcp = http.getStreamPtr();
|
||||
|
||||
// WiFiUDP::stop();
|
||||
// WiFiClient::stopAllExcept(tcp);
|
||||
|
||||
delay(100);
|
||||
|
||||
int command;
|
||||
|
||||
if(spiffs) {
|
||||
command = U_SPIFFS;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] runUpdate spiffs...\n");
|
||||
} else {
|
||||
command = U_FLASH;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] runUpdate flash...\n");
|
||||
Serial.print("[httpUpdate] runUpdate flash...\n");
|
||||
}
|
||||
|
||||
// if(!spiffs) {
|
||||
// uint8_t buf[4];
|
||||
// if(tcp->peekBytes(&buf[0], 4) != 4) {
|
||||
// DEBUG_HTTP_UPDATE("[httpUpdate] peekBytes magic header failed\n");
|
||||
// _lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED;
|
||||
// http.end();
|
||||
// return HTTP_UPDATE_FAILED;
|
||||
// }
|
||||
|
||||
// check for valid first magic byte
|
||||
// if(buf[0] != 0xE9) {
|
||||
// DEBUG_HTTP_UPDATE("[httpUpdate] magic header not starts with 0xE9\n");
|
||||
// _lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED;
|
||||
// http.end();
|
||||
// return HTTP_UPDATE_FAILED;
|
||||
// }
|
||||
|
||||
// uint32_t bin_flash_size = ESP.magicFlashChipSize((buf[3] & 0xf0) >> 4);
|
||||
|
||||
// check if new bin fits to SPI flash
|
||||
// if(bin_flash_size > ESP.getFlashChipRealSize()) {
|
||||
// DEBUG_HTTP_UPDATE("[httpUpdate] magic header, new bin not fits SPI Flash\n");
|
||||
// _lastError = HTTP_UE_BIN_FOR_WRONG_FLASH;
|
||||
// http.end();
|
||||
// return HTTP_UPDATE_FAILED;
|
||||
// }
|
||||
// }
|
||||
|
||||
if(runUpdate(*tcp, len, http.header("x-MD5"), command)) {
|
||||
ret = HTTP_UPDATE_OK;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update ok\n");
|
||||
Serial.print("[httpUpdate] Update ok\n");
|
||||
http.end();
|
||||
|
||||
if(_rebootOnUpdate && !spiffs) {
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
} else {
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update failed\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_lastError = HTTP_UE_SERVER_NOT_REPORT_SIZE;
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Content-Length is 0 or not set by Server?!\n");
|
||||
}
|
||||
break;
|
||||
case HTTP_CODE_NOT_MODIFIED:
|
||||
///< Not Modified (No updates)
|
||||
ret = HTTP_UPDATE_NO_UPDATES;
|
||||
break;
|
||||
case HTTP_CODE_NOT_FOUND:
|
||||
_lastError = HTTP_UE_SERVER_FILE_NOT_FOUND;
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
break;
|
||||
case HTTP_CODE_FORBIDDEN:
|
||||
_lastError = HTTP_UE_SERVER_FORBIDDEN;
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
break;
|
||||
default:
|
||||
_lastError = HTTP_UE_SERVER_WRONG_HTTP_CODE;
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] HTTP Code is (%d)\n", code);
|
||||
//http.writeToStream(&Serial1);
|
||||
break;
|
||||
}
|
||||
|
||||
http.end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* write Update to flash
|
||||
* @param in Stream&
|
||||
* @param size uint32_t
|
||||
* @param md5 String
|
||||
* @return true if Update ok
|
||||
*/
|
||||
bool ESP8266HTTPUpdate::runUpdate(Stream& in, uint32_t size, String md5, int command)
|
||||
{
|
||||
|
||||
StreamString error;
|
||||
|
||||
if(!Update.begin(size, command)) {
|
||||
_lastError = Update.getError();
|
||||
Update.printError(error);
|
||||
error.trim(); // remove line ending
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update.begin failed! (%s)\n", error.c_str());
|
||||
Serial.printf("[httpUpdate] Update.begin failed! (%s)\n", error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(md5.length()) {
|
||||
if(!Update.setMD5(md5.c_str())) {
|
||||
_lastError = HTTP_UE_SERVER_FAULTY_MD5;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update.setMD5 failed! (%s)\n", md5.c_str());
|
||||
Serial.printf("[httpUpdate] Update.setMD5 failed! (%s)\n", md5.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(Update.writeStream(in) != size) {
|
||||
_lastError = Update.getError();
|
||||
Update.printError(error);
|
||||
error.trim(); // remove line ending
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update.writeStream failed! (%s)\n", error.c_str());
|
||||
Serial.printf("[httpUpdate] Update.writeStream failed! (%s)\n", error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!Update.end()) {
|
||||
_lastError = Update.getError();
|
||||
Update.printError(error);
|
||||
error.trim(); // remove line ending
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update.end failed! (%s)\n", error.c_str());
|
||||
Serial.printf("[httpUpdate] Update.end failed! (%s)\n", error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_HTTPUPDATE)
|
||||
ESP8266HTTPUpdate ESPhttpUpdate;
|
||||
#endif
|
||||
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
*
|
||||
* @file ESP8266HTTPUpdate.h
|
||||
* @date 21.06.2015
|
||||
* @author Markus Sattler
|
||||
*
|
||||
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
* This file is part of the ESP8266 Http Updater.
|
||||
*
|
||||
* 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 ESP8266HTTPUPDATE_H_
|
||||
#define ESP8266HTTPUPDATE_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include "ESP8266HTTPClient.h"
|
||||
#include "Update.h"
|
||||
#include "WiFiUdp.h"
|
||||
|
||||
|
||||
#define DEBUG_ESP_HTTP_UPDATE
|
||||
|
||||
#ifdef DEBUG_ESP_HTTP_UPDATE
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define DEBUG_HTTP_UPDATE(...) DEBUG_ESP_PORT.printf( __VA_ARGS__ )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_HTTP_UPDATE
|
||||
#define DEBUG_HTTP_UPDATE(...)
|
||||
#endif
|
||||
|
||||
/// note we use HTTP client errors too so we start at 100
|
||||
#define HTTP_UE_TOO_LESS_SPACE (-100)
|
||||
#define HTTP_UE_SERVER_NOT_REPORT_SIZE (-101)
|
||||
#define HTTP_UE_SERVER_FILE_NOT_FOUND (-102)
|
||||
#define HTTP_UE_SERVER_FORBIDDEN (-103)
|
||||
#define HTTP_UE_SERVER_WRONG_HTTP_CODE (-104)
|
||||
#define HTTP_UE_SERVER_FAULTY_MD5 (-105)
|
||||
#define HTTP_UE_BIN_VERIFY_HEADER_FAILED (-106)
|
||||
#define HTTP_UE_BIN_FOR_WRONG_FLASH (-107)
|
||||
|
||||
enum HTTPUpdateResult {
|
||||
HTTP_UPDATE_FAILED,
|
||||
HTTP_UPDATE_NO_UPDATES,
|
||||
HTTP_UPDATE_OK
|
||||
};
|
||||
|
||||
typedef HTTPUpdateResult t_httpUpdate_return; // backward compatibility
|
||||
|
||||
class ESP8266HTTPUpdate
|
||||
{
|
||||
public:
|
||||
ESP8266HTTPUpdate(void);
|
||||
~ESP8266HTTPUpdate(void);
|
||||
|
||||
void rebootOnUpdate(bool reboot)
|
||||
{
|
||||
_rebootOnUpdate = reboot;
|
||||
}
|
||||
|
||||
// This function is deprecated, use rebootOnUpdate and the next one instead
|
||||
t_httpUpdate_return update(const String& url, const String& currentVersion,
|
||||
const String& httpsFingerprint, bool reboot) __attribute__((deprecated));
|
||||
t_httpUpdate_return update(const String& url, const String& currentVersion = "");
|
||||
t_httpUpdate_return update(const String& url, const String& currentVersion,
|
||||
const String& httpsFingerprint);
|
||||
|
||||
// This function is deprecated, use one of the overloads below along with rebootOnUpdate
|
||||
t_httpUpdate_return update(const String& host, uint16_t port, const String& uri, const String& currentVersion,
|
||||
bool https, const String& httpsFingerprint, bool reboot) __attribute__((deprecated));
|
||||
|
||||
t_httpUpdate_return update(const String& host, uint16_t port, const String& uri = "/",
|
||||
const String& currentVersion = "");
|
||||
t_httpUpdate_return update(const String& host, uint16_t port, const String& url,
|
||||
const String& currentVersion, const String& httpsFingerprint);
|
||||
|
||||
// This function is deprecated, use rebootOnUpdate and the next one instead
|
||||
t_httpUpdate_return updateSpiffs(const String& url, const String& currentVersion,
|
||||
const String& httpsFingerprint, bool reboot) __attribute__((deprecated));
|
||||
t_httpUpdate_return updateSpiffs(const String& url, const String& currentVersion = "");
|
||||
t_httpUpdate_return updateSpiffs(const String& url, const String& currentVersion, const String& httpsFingerprint);
|
||||
|
||||
|
||||
int getLastError(void);
|
||||
String getLastErrorString(void);
|
||||
|
||||
protected:
|
||||
t_httpUpdate_return handleUpdate(HTTPClient& http, const String& currentVersion, bool spiffs = false);
|
||||
bool runUpdate(Stream& in, uint32_t size, String md5, int command = U_FLASH);
|
||||
|
||||
int _lastError;
|
||||
bool _rebootOnUpdate = true;
|
||||
};
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_HTTPUPDATE)
|
||||
extern ESP8266HTTPUpdate ESPhttpUpdate;
|
||||
#endif
|
||||
|
||||
#endif /* ESP8266HTTPUPDATE_H_ */
|
||||
@@ -0,0 +1,161 @@
|
||||
#ifndef ESP8266UPDATER_H
|
||||
#define ESP8266UPDATER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <MD5Builder.h>
|
||||
#include "esp_partition.h"
|
||||
|
||||
#define UPDATE_ERROR_OK (0)
|
||||
#define UPDATE_ERROR_WRITE (1)
|
||||
#define UPDATE_ERROR_ERASE (2)
|
||||
#define UPDATE_ERROR_READ (3)
|
||||
#define UPDATE_ERROR_SPACE (4)
|
||||
#define UPDATE_ERROR_SIZE (5)
|
||||
#define UPDATE_ERROR_STREAM (6)
|
||||
#define UPDATE_ERROR_MD5 (7)
|
||||
#define UPDATE_ERROR_MAGIC_BYTE (8)
|
||||
#define UPDATE_ERROR_ACTIVATE (9)
|
||||
#define UPDATE_ERROR_NO_PARTITION (10)
|
||||
#define UPDATE_ERROR_BAD_ARGUMENT (11)
|
||||
#define UPDATE_ERROR_ABORT (12)
|
||||
|
||||
#define UPDATE_SIZE_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
#define U_FLASH 0
|
||||
#define U_SPIFFS 100
|
||||
#define U_AUTH 200
|
||||
|
||||
class UpdateClass {
|
||||
public:
|
||||
UpdateClass();
|
||||
/*
|
||||
Call this to check the space needed for the update
|
||||
Will return false if there is not enough space
|
||||
*/
|
||||
bool begin(size_t size=UPDATE_SIZE_UNKNOWN, int command = U_FLASH);
|
||||
|
||||
/*
|
||||
Writes a buffer to the flash and increments the address
|
||||
Returns the amount written
|
||||
*/
|
||||
size_t write(uint8_t *data, size_t len);
|
||||
|
||||
/*
|
||||
Writes the remaining bytes from the Stream to the flash
|
||||
Uses readBytes() and sets UPDATE_ERROR_STREAM on timeout
|
||||
Returns the bytes written
|
||||
Should be equal to the remaining bytes when called
|
||||
Usable for slow streams like Serial
|
||||
*/
|
||||
size_t writeStream(Stream &data);
|
||||
|
||||
/*
|
||||
If all bytes are written
|
||||
this call will write the config to eboot
|
||||
and return true
|
||||
If there is already an update running but is not finished and !evenIfRemainanig
|
||||
or there is an error
|
||||
this will clear everything and return false
|
||||
the last error is available through getError()
|
||||
evenIfRemaining is helpfull when you update without knowing the final size first
|
||||
*/
|
||||
bool end(bool evenIfRemaining = false);
|
||||
|
||||
/*
|
||||
Aborts the running update
|
||||
*/
|
||||
void abort();
|
||||
|
||||
/*
|
||||
Prints the last error to an output stream
|
||||
*/
|
||||
void printError(Stream &out);
|
||||
|
||||
/*
|
||||
sets the expected MD5 for the firmware (hexString)
|
||||
*/
|
||||
bool setMD5(const char * expected_md5);
|
||||
|
||||
/*
|
||||
returns the MD5 String of the sucessfully ended firmware
|
||||
*/
|
||||
String md5String(void){ return _md5.toString(); }
|
||||
|
||||
/*
|
||||
populated the result with the md5 bytes of the sucessfully ended firmware
|
||||
*/
|
||||
void md5(uint8_t * result){ return _md5.getBytes(result); }
|
||||
|
||||
//Helpers
|
||||
uint8_t getError(){ return _error; }
|
||||
void clearError(){ _error = UPDATE_ERROR_OK; }
|
||||
bool hasError(){ return _error != UPDATE_ERROR_OK; }
|
||||
bool isRunning(){ return _size > 0; }
|
||||
bool isFinished(){ return _progress == _size; }
|
||||
size_t size(){ return _size; }
|
||||
size_t progress(){ return _progress; }
|
||||
size_t remaining(){ return _size - _progress; }
|
||||
|
||||
/*
|
||||
Template to write from objects that expose
|
||||
available() and read(uint8_t*, size_t) methods
|
||||
faster than the writeStream method
|
||||
writes only what is available
|
||||
*/
|
||||
template<typename T>
|
||||
size_t write(T &data){
|
||||
size_t written = 0;
|
||||
if (hasError() || !isRunning())
|
||||
return 0;
|
||||
|
||||
size_t available = data.available();
|
||||
while(available) {
|
||||
if(_bufferLen + available > remaining()){
|
||||
available = remaining() - _bufferLen;
|
||||
}
|
||||
if(_bufferLen + available > 4096) {
|
||||
size_t toBuff = 4096 - _bufferLen;
|
||||
data.read(_buffer + _bufferLen, toBuff);
|
||||
_bufferLen += toBuff;
|
||||
if(!_writeBuffer())
|
||||
return written;
|
||||
written += toBuff;
|
||||
} else {
|
||||
data.read(_buffer + _bufferLen, available);
|
||||
_bufferLen += available;
|
||||
written += available;
|
||||
if(_bufferLen == remaining()) {
|
||||
if(!_writeBuffer()) {
|
||||
return written;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(remaining() == 0)
|
||||
return written;
|
||||
available = data.available();
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
private:
|
||||
void _reset();
|
||||
void _abort(uint8_t err);
|
||||
bool _writeBuffer();
|
||||
bool _verifyHeader(uint8_t data);
|
||||
bool _verifyEnd();
|
||||
|
||||
uint8_t _error;
|
||||
uint8_t *_buffer;
|
||||
size_t _bufferLen;
|
||||
size_t _size;
|
||||
uint32_t _progress;
|
||||
uint32_t _command;
|
||||
const esp_partition_t* _partition;
|
||||
|
||||
String _target_md5;
|
||||
MD5Builder _md5;
|
||||
};
|
||||
|
||||
extern UpdateClass Update;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,279 @@
|
||||
#include "Update.h"
|
||||
#include "Arduino.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_image_format.h"
|
||||
|
||||
static const char * _err2str(uint8_t _error){
|
||||
if(_error == UPDATE_ERROR_OK){
|
||||
return ("No Error");
|
||||
} else if(_error == UPDATE_ERROR_WRITE){
|
||||
return ("Flash Write Failed");
|
||||
} else if(_error == UPDATE_ERROR_ERASE){
|
||||
return ("Flash Erase Failed");
|
||||
} else if(_error == UPDATE_ERROR_READ){
|
||||
return ("Flash Read Failed");
|
||||
} else if(_error == UPDATE_ERROR_SPACE){
|
||||
return ("Not Enough Space");
|
||||
} else if(_error == UPDATE_ERROR_SIZE){
|
||||
return ("Bad Size Given");
|
||||
} else if(_error == UPDATE_ERROR_STREAM){
|
||||
return ("Stream Read Timeout");
|
||||
} else if(_error == UPDATE_ERROR_MD5){
|
||||
return ("MD5 Check Failed");
|
||||
} else if(_error == UPDATE_ERROR_MAGIC_BYTE){
|
||||
return ("Wrong Magic Byte");
|
||||
} else if(_error == UPDATE_ERROR_ACTIVATE){
|
||||
return ("Could Not Activate The Firmware");
|
||||
} else if(_error == UPDATE_ERROR_NO_PARTITION){
|
||||
return ("Partition Could Not be Found");
|
||||
} else if(_error == UPDATE_ERROR_BAD_ARGUMENT){
|
||||
return ("Bad Argument");
|
||||
} else if(_error == UPDATE_ERROR_ABORT){
|
||||
return ("Aborted");
|
||||
}
|
||||
return ("UNKNOWN");
|
||||
}
|
||||
|
||||
UpdateClass::UpdateClass()
|
||||
: _error(0)
|
||||
, _buffer(0)
|
||||
, _bufferLen(0)
|
||||
, _size(0)
|
||||
, _progress(0)
|
||||
, _command(U_FLASH)
|
||||
, _partition(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateClass::_reset() {
|
||||
if (_buffer)
|
||||
delete[] _buffer;
|
||||
_buffer = 0;
|
||||
_bufferLen = 0;
|
||||
_progress = 0;
|
||||
_size = 0;
|
||||
_command = U_FLASH;
|
||||
}
|
||||
|
||||
bool UpdateClass::begin(size_t size, int command) {
|
||||
if(_size > 0){
|
||||
log_w("already running");
|
||||
return false;
|
||||
}
|
||||
|
||||
_reset();
|
||||
_error = 0;
|
||||
|
||||
if(size == 0) {
|
||||
_error = UPDATE_ERROR_SIZE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (command == U_FLASH) {
|
||||
_partition = esp_ota_get_next_update_partition(NULL);
|
||||
if(!_partition){
|
||||
_error = UPDATE_ERROR_NO_PARTITION;
|
||||
return false;
|
||||
}
|
||||
log_d("OTA Partition: %s", _partition->label);
|
||||
}
|
||||
else if (command == U_SPIFFS) {
|
||||
_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL);
|
||||
if(!_partition){
|
||||
_error = UPDATE_ERROR_NO_PARTITION;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
_error = UPDATE_ERROR_BAD_ARGUMENT;
|
||||
log_e("bad command %u", command);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(size == UPDATE_SIZE_UNKNOWN){
|
||||
size = _partition->size;
|
||||
} else if(size > _partition->size){
|
||||
_error = UPDATE_ERROR_SIZE;
|
||||
log_e("too large %u > %u", size, _partition->size);
|
||||
return false;
|
||||
}
|
||||
|
||||
//initialize
|
||||
_buffer = (uint8_t*)malloc(SPI_FLASH_SEC_SIZE);
|
||||
if(!_buffer){
|
||||
log_e("malloc failed");
|
||||
return false;
|
||||
}
|
||||
_size = size;
|
||||
_command = command;
|
||||
_md5.begin();
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateClass::_abort(uint8_t err){
|
||||
_reset();
|
||||
_error = err;
|
||||
}
|
||||
|
||||
void UpdateClass::abort(){
|
||||
_abort(UPDATE_ERROR_ABORT);
|
||||
}
|
||||
|
||||
bool UpdateClass::_writeBuffer(){
|
||||
if(!ESP.flashEraseSector((_partition->address + _progress)/SPI_FLASH_SEC_SIZE)){
|
||||
_abort(UPDATE_ERROR_ERASE);
|
||||
return false;
|
||||
}
|
||||
if (!ESP.flashWrite(_partition->address + _progress, (uint32_t*)_buffer, _bufferLen)) {
|
||||
_abort(UPDATE_ERROR_WRITE);
|
||||
return false;
|
||||
}
|
||||
_md5.add(_buffer, _bufferLen);
|
||||
_progress += _bufferLen;
|
||||
_bufferLen = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UpdateClass::_verifyHeader(uint8_t data) {
|
||||
if(_command == U_FLASH) {
|
||||
if(data != ESP_IMAGE_HEADER_MAGIC) {
|
||||
_abort(UPDATE_ERROR_MAGIC_BYTE);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if(_command == U_SPIFFS) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UpdateClass::_verifyEnd() {
|
||||
if(_command == U_FLASH) {
|
||||
uint8_t buf[4];
|
||||
if(!ESP.flashRead(_partition->address, (uint32_t*)buf, 4)) {
|
||||
_abort(UPDATE_ERROR_READ);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(buf[0] != ESP_IMAGE_HEADER_MAGIC) {
|
||||
_abort(UPDATE_ERROR_MAGIC_BYTE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(esp_ota_set_boot_partition(_partition)){
|
||||
_abort(UPDATE_ERROR_ACTIVATE);
|
||||
return false;
|
||||
}
|
||||
_reset();
|
||||
return true;
|
||||
} else if(_command == U_SPIFFS) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UpdateClass::setMD5(const char * expected_md5){
|
||||
if(strlen(expected_md5) != 32)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_target_md5 = expected_md5;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UpdateClass::end(bool evenIfRemaining){
|
||||
if(hasError() || _size == 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isFinished() && !evenIfRemaining){
|
||||
log_e("premature end: res:%u, pos:%u/%u\n", getError(), progress(), _size);
|
||||
_abort(UPDATE_ERROR_ABORT);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(evenIfRemaining) {
|
||||
if(_bufferLen > 0) {
|
||||
_writeBuffer();
|
||||
}
|
||||
_size = progress();
|
||||
}
|
||||
|
||||
_md5.calculate();
|
||||
if(_target_md5.length()) {
|
||||
if(_target_md5 != _md5.toString()){
|
||||
_abort(UPDATE_ERROR_MD5);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return _verifyEnd();
|
||||
}
|
||||
|
||||
size_t UpdateClass::write(uint8_t *data, size_t len) {
|
||||
if(hasError() || !isRunning()){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(len > remaining()){
|
||||
_abort(UPDATE_ERROR_SPACE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t left = len;
|
||||
|
||||
while((_bufferLen + left) > SPI_FLASH_SEC_SIZE) {
|
||||
size_t toBuff = SPI_FLASH_SEC_SIZE - _bufferLen;
|
||||
memcpy(_buffer + _bufferLen, data + (len - left), toBuff);
|
||||
_bufferLen += toBuff;
|
||||
if(!_writeBuffer()){
|
||||
return len - left;
|
||||
}
|
||||
left -= toBuff;
|
||||
}
|
||||
memcpy(_buffer + _bufferLen, data + (len - left), left);
|
||||
_bufferLen += left;
|
||||
if(_bufferLen == remaining()){
|
||||
if(!_writeBuffer()){
|
||||
return len - left;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t UpdateClass::writeStream(Stream &data) {
|
||||
size_t written = 0;
|
||||
size_t toRead = 0;
|
||||
if(hasError() || !isRunning())
|
||||
return 0;
|
||||
|
||||
// if(!_verifyHeader(data.peek())) {
|
||||
// Serial.print("_reset\r\n");
|
||||
// _reset();
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
while(remaining()) {
|
||||
toRead = data.readBytes(_buffer + _bufferLen, (SPI_FLASH_SEC_SIZE - _bufferLen));
|
||||
if(toRead == 0) { //Timeout
|
||||
delay(100);
|
||||
toRead = data.readBytes(_buffer + _bufferLen, (SPI_FLASH_SEC_SIZE - _bufferLen));
|
||||
if(toRead == 0) { //Timeout
|
||||
_abort(UPDATE_ERROR_STREAM);
|
||||
return written;
|
||||
}
|
||||
}
|
||||
_bufferLen += toRead;
|
||||
if((_bufferLen == remaining() || _bufferLen == SPI_FLASH_SEC_SIZE) && !_writeBuffer())
|
||||
return written;
|
||||
written += toRead;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
void UpdateClass::printError(Stream &out){
|
||||
out.println(_err2str(_error));
|
||||
}
|
||||
|
||||
UpdateClass Update;
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* httpUpdate.ino
|
||||
*
|
||||
* Created on: 27.11.2015
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiMulti.h>
|
||||
|
||||
#include "ESP8266HTTPClient.h"
|
||||
#include "ESP8266httpUpdate.h"
|
||||
#include <WiFiClientSecure.h>
|
||||
|
||||
#define USE_SERIAL Serial
|
||||
|
||||
WiFiMulti wifiMulti;
|
||||
|
||||
void setup() {
|
||||
|
||||
USE_SERIAL.begin(115200);
|
||||
// USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
// Serial.print("update success!\r\n");
|
||||
|
||||
for(uint8_t t = 4; t > 0; t--) {
|
||||
USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
|
||||
USE_SERIAL.flush();
|
||||
delay(100);
|
||||
}
|
||||
|
||||
WiFi.begin("MasterHax_2.4G", "wittyercheese551");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println("WiFi connected");
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
// wifiMulti.addAP("MasterHax_2.4G", "wittyercheese551");
|
||||
// Serial.println("Connecting Wifi...");
|
||||
// if(wifiMulti.run() == WL_CONNECTED) {
|
||||
// Serial.println("");
|
||||
// Serial.println("WiFi connected");
|
||||
// Serial.println("IP address: ");
|
||||
// Serial.println(WiFi.localIP());
|
||||
// }
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// wait for WiFi connection
|
||||
// if((wifiMulti.run() == WL_CONNECTED)) {
|
||||
if(1) {
|
||||
Serial.printf("connect...\n");
|
||||
t_httpUpdate_return ret = ESPhttpUpdate.update("http://olcunuug8.bkt.clouddn.com/httpUpdate.ino.esp32.bin");
|
||||
//t_httpUpdate_return ret = ESPhttpUpdate.update("https://server/file.bin");
|
||||
|
||||
switch(ret) {
|
||||
case HTTP_UPDATE_FAILED:
|
||||
USE_SERIAL.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
|
||||
break;
|
||||
|
||||
case HTTP_UPDATE_NO_UPDATES:
|
||||
USE_SERIAL.println("HTTP_UPDATE_NO_UPDATES");
|
||||
break;
|
||||
|
||||
case HTTP_UPDATE_OK:
|
||||
USE_SERIAL.println("HTTP_UPDATE_OK");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user