ESP32_ChinaDieselHeater_Con.../src/Afterburner/src/Libraries/esp32FOTA/src/esp32fota.cpp

274 lines
7.6 KiB
C++

/*
esp32 firmware OTA
Date: December 2018
Author: Chris Joyce <https://chrisjoyce911/esp32FOTA>
Purpose: Perform an OTA update from a bin located on a webserver (HTTP Only)
*/
#include "esp32fota.h"
#include "Arduino.h"
#include <WiFi.h>
#include <HTTPClient.h>
#include <Update.h>
#include "ArduinoJson.h"
extern void forceBootInit();
esp32FOTA::esp32FOTA(String firwmareType, int firwmareVersion)
{
_firwmareType = firwmareType;
_firwmareVersion = firwmareVersion;
useDeviceID = false;
}
// Utility to extract header value from headers
String esp32FOTA::getHeaderValue(String header, String headerName)
{
return header.substring(strlen(headerName.c_str()));
}
// OTA Logic
void esp32FOTA::execOTA()
{
WiFiClient client;
int contentLength = 0;
bool isValidContentType = false;
Serial.println("Connecting to: " + String(_host));
// Connect to Webserver
if (client.connect(_host.c_str(), _port))
{
// Connection Succeed.
// Fecthing the bin
Serial.println("Fetching Bin: " + String(_bin));
// Get the contents of the bin file
client.print(String("GET ") + _bin + " HTTP/1.1\r\n" +
"Host: " + _host + "\r\n" +
"Cache-Control: no-cache\r\n" +
"Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.available() == 0)
{
if (millis() - timeout > 5000)
{
Serial.println("Client Timeout !");
client.stop();
return;
}
}
while (client.available())
{
// read line till /n
String line = client.readStringUntil('\n');
// remove space, to check if the line is end of headers
line.trim();
if (!line.length())
{
//headers ended
break; // and get the OTA started
}
// Check if the HTTP Response is 200
// else break and Exit Update
if (line.startsWith("HTTP/1.1"))
{
if (line.indexOf("200") < 0)
{
Serial.println("Got a non 200 status code from server. Exiting OTA Update.");
break;
}
}
// extract headers here
// Start with content length
if (line.startsWith("Content-Length: "))
{
contentLength = atoi((getHeaderValue(line, "Content-Length: ")).c_str());
Serial.println("Got " + String(contentLength) + " bytes from server");
}
// Next, the content type
if (line.startsWith("Content-Type: "))
{
String contentType = getHeaderValue(line, "Content-Type: ");
Serial.println("Got " + contentType + " payload.");
if (contentType == "application/octet-stream")
{
isValidContentType = true;
}
}
}
}
else
{
// Connect to webserver failed
// May be try?
// Probably a choppy network?
Serial.println("Connection to " + String(_host) + " failed. Please check your setup");
// retry??
// execOTA();
}
// Check what is the contentLength and if content type is `application/octet-stream`
Serial.println("contentLength : " + String(contentLength) + ", isValidContentType : " + String(isValidContentType));
// check contentLength and content type
if (contentLength && isValidContentType)
{
// Check if there is enough to OTA Update
bool canBegin = Update.begin(contentLength);
// If yes, begin
if (canBegin)
{
Serial.println("Begin OTA. This may take 2 - 5 mins to complete. Things might be quite for a while.. Patience!");
// No activity would appear on the Serial monitor
// So be patient. This may take 2 - 5mins to complete
size_t written = Update.writeStream(client);
if (written == contentLength)
{
Serial.println("Written : " + String(written) + " successfully");
}
else
{
Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?");
// retry??
// execOTA();
}
if (Update.end())
{
Serial.println("OTA done!");
if (Update.isFinished())
{
Serial.println("Update successfully completed. Rebooting.");
forceBootInit();
ESP.restart();
}
else
{
Serial.println("Update not finished? Something went wrong!");
}
}
else
{
Serial.println("Error Occurred. Error #: " + String(Update.getError()));
}
}
else
{
// not enough space to begin OTA
// Understand the partitions and
// space availability
Serial.println("Not enough space to begin OTA");
client.flush();
}
}
else
{
Serial.println("There was no content in the response");
client.flush();
}
}
bool esp32FOTA::execHTTPcheck()
{
String useURL;
if (useDeviceID)
{
// String deviceID = getDeviceID() ;
useURL = checkURL + "?id=" + getDeviceID();
}
else
{
useURL = checkURL;
}
WiFiClient client;
_port = 80;
Serial.println("Getting HTTP");
Serial.println(useURL);
Serial.println("------");
if ((WiFi.status() == WL_CONNECTED))
{ //Check the current connection status
HTTPClient http;
http.begin(useURL); //Specify the URL
int httpCode = http.GET(); //Make the request
if (httpCode == 200)
{ //Check is a file was returned
String payload = http.getString();
int str_len = payload.length() + 1;
char* JSONMessage = new char[str_len];
payload.toCharArray(JSONMessage, str_len);
StaticJsonBuffer<300> JSONBuffer; //Memory pool
JsonObject &parsed = JSONBuffer.parseObject(JSONMessage); //Parse message
if (!parsed.success())
{ //Check for errors in parsing
delete[] JSONMessage;
Serial.println("Parsing failed");
delay(5000);
return false;
}
const char *pltype = parsed["type"];
int plversion = parsed["version"];
const char *plhost = parsed["host"];
_port = parsed["port"];
const char *plbin = parsed["bin"];
String jshost(plhost);
String jsbin(plbin);
_host = jshost;
_bin = jsbin;
String fwtype(pltype);
delete[] JSONMessage;
if (plversion > _firwmareVersion && fwtype == _firwmareType)
{
return true;
}
else
{
return false;
}
}
else
{
Serial.println("Error on HTTP request");
return false;
}
http.end(); //Free the resources
}
return false;
}
String esp32FOTA::getDeviceID()
{
char deviceid[21];
uint64_t chipid;
chipid = ESP.getEfuseMac();
sprintf(deviceid, "%" PRIu64, chipid);
String thisID(deviceid);
return thisID;
}