Added OLED and JSON Web Content Update functionality
This commit is contained in:
parent
1d80e34c4b
commit
87b1704335
|
@ -8,6 +8,8 @@
|
|||
RLJ Added usage of AsyncHTTPrequest to avoid hang issues with flaky internet connections during update poll
|
||||
However using AsyncTCP for the actual binary update causes other issues in the callback realm,
|
||||
so persisting with the original synchronous update method which blocks all user mode code.
|
||||
Modifications Mar 2020:
|
||||
RLJ Added FreeRTOS queue to separate callbacks from potential system calls - random reboots in some afterburners...
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
@ -20,19 +22,23 @@
|
|||
|
||||
extern void forceBootInit();
|
||||
|
||||
#define USE_QUEUE
|
||||
|
||||
|
||||
esp32FOTA::esp32FOTA(String firwmareType, int firwmareVersion)
|
||||
{
|
||||
_firwmareType = firwmareType;
|
||||
_firwmareVersion = firwmareVersion;
|
||||
useDeviceID = false;
|
||||
_firwmareType = firwmareType;
|
||||
_firwmareVersion = firwmareVersion;
|
||||
useDeviceID = false;
|
||||
// _endCallback = NULL;
|
||||
_queue = xQueueCreate(1, 256);
|
||||
}
|
||||
|
||||
// Utility to extract header value from headers
|
||||
String
|
||||
esp32FOTA::getHeaderValue(String header, String headerName)
|
||||
{
|
||||
return header.substring(strlen(headerName.c_str()));
|
||||
return header.substring(strlen(headerName.c_str()));
|
||||
}
|
||||
|
||||
// OTA Logic
|
||||
|
@ -40,165 +46,165 @@ void
|
|||
esp32FOTA::execOTA()
|
||||
{
|
||||
|
||||
WiFiClient client;
|
||||
int contentLength = 0;
|
||||
bool isValidContentType = false;
|
||||
WiFiClient client;
|
||||
int contentLength = 0;
|
||||
bool isValidContentType = false;
|
||||
|
||||
Serial.println("Connecting to: " + String(_host));
|
||||
// Connect to Webserver
|
||||
if (client.connect(_host.c_str(), _port))
|
||||
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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (millis() - timeout > 5000)
|
||||
{
|
||||
Serial.println("Client Timeout !");
|
||||
client.stop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
while (client.available())
|
||||
{
|
||||
// Connect to webserver failed
|
||||
// May be try?
|
||||
// Probably a choppy network?
|
||||
Serial.println("Connection to " + String(_host) + " failed. Please check your setup");
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
// Check what is the contentLength and if content type is `application/octet-stream`
|
||||
Serial.println("contentLength : " + String(contentLength) + ", isValidContentType : " + String(isValidContentType));
|
||||
if ( _onComplete != NULL) {
|
||||
if(!_onComplete(contentLength)) {
|
||||
Serial.println("ESP32FOTA: OnComplete handler returned false");
|
||||
Update.abort();
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
if (Update.end())
|
||||
{
|
||||
Serial.println("OTA done!");
|
||||
if (Update.isFinished())
|
||||
{
|
||||
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 ( _onComplete != NULL) {
|
||||
if(!_onComplete(contentLength)) {
|
||||
Serial.println("ESP32FOTA: OnComplete handler returned false");
|
||||
Update.abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (Update.end())
|
||||
{
|
||||
Serial.println("OTA done!");
|
||||
if (Update.isFinished())
|
||||
{
|
||||
Serial.println("Update successfully completed. Rebooting.");
|
||||
if(_onSuccess != NULL) {
|
||||
_onSuccess();
|
||||
}
|
||||
ESP.restart();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(_onFail != NULL) {
|
||||
_onFail();
|
||||
}
|
||||
Serial.println("Update not finished? Something went wrong!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(_onFail != NULL) {
|
||||
_onFail();
|
||||
}
|
||||
Serial.println("Error Occurred. Error #: " + String(Update.getError()));
|
||||
}
|
||||
Serial.println("Update successfully completed. Rebooting.");
|
||||
if(_onSuccess != NULL) {
|
||||
_onSuccess();
|
||||
}
|
||||
ESP.restart();
|
||||
}
|
||||
else
|
||||
{
|
||||
// not enough space to begin OTA
|
||||
// Understand the partitions and
|
||||
// space availability
|
||||
Serial.println("Not enough space to begin OTA");
|
||||
client.flush();
|
||||
if(_onFail != NULL) {
|
||||
_onFail();
|
||||
}
|
||||
Serial.println("Update not finished? Something went wrong!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(_onFail != NULL) {
|
||||
_onFail();
|
||||
}
|
||||
Serial.println("Error Occurred. Error #: " + String(Update.getError()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("There was no content in the response");
|
||||
client.flush();
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
// Synchronous mode update check - may hang on flakey Internet connections
|
||||
|
@ -206,100 +212,100 @@ bool
|
|||
esp32FOTA::execHTTPcheck()
|
||||
{
|
||||
|
||||
String useURL;
|
||||
String useURL;
|
||||
|
||||
if (useDeviceID)
|
||||
{
|
||||
// String deviceID = getDeviceID() ;
|
||||
useURL = _checkURL + "?id=" + getDeviceID();
|
||||
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)
|
||||
{
|
||||
_newVersion = plversion;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_newVersion = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
useURL = _checkURL;
|
||||
Serial.println("Error on HTTP request");
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
_newVersion = plversion;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_newVersion = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Serial.println("Error on HTTP request");
|
||||
return false;
|
||||
}
|
||||
|
||||
http.end(); //Free the resources
|
||||
}
|
||||
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;
|
||||
char deviceid[21];
|
||||
uint64_t chipid;
|
||||
chipid = ESP.getEfuseMac();
|
||||
sprintf(deviceid, "%" PRIu64, chipid);
|
||||
String thisID(deviceid);
|
||||
return thisID;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -347,20 +353,30 @@ esp32FOTA::onFail( std::function<void()> func ) {
|
|||
|
||||
|
||||
// Callback for when AsyncTCP ready state changes
|
||||
void FOTA_PollCallback(void* optParm, asyncHTTPrequest* pRequest, int readyState){
|
||||
if(readyState == 4) { // response
|
||||
String JSONinfo(pRequest->responseText());
|
||||
Serial.println(JSONinfo);
|
||||
Serial.println();
|
||||
esp32FOTA* pFOTA = (esp32FOTA*) optParm;
|
||||
if(pFOTA) {
|
||||
if(pFOTA->decodeResponse(JSONinfo)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if(readyState == 1) { // connection established
|
||||
pRequest->send();
|
||||
// queue data to be processed later in user loop
|
||||
void FOTA_PollCallback(void* optParm, asyncHTTPrequest* pRequest, int readyState)
|
||||
{
|
||||
if(readyState == 4) { // response
|
||||
|
||||
|
||||
#ifdef USE_QUEUE
|
||||
esp32FOTA* pFOTA = (esp32FOTA*)optParm;
|
||||
pFOTA->queueDLdata(pRequest);
|
||||
#else
|
||||
String JSONinfo(pRequest->responseText());
|
||||
Serial.println(JSONinfo);
|
||||
Serial.println();
|
||||
esp32FOTA* pFOTA = (esp32FOTA*) optParm;
|
||||
if(pFOTA) {
|
||||
if(pFOTA->decodeResponse(JSONinfo)) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
if(readyState == 1) { // connection established
|
||||
pRequest->send();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -372,7 +388,7 @@ esp32FOTA::setCheckURL(const char* host)
|
|||
void
|
||||
esp32FOTA::setupAsync(const char* host)
|
||||
{
|
||||
_versionTest.setDebug(true);
|
||||
// _versionTest.setDebug(true);
|
||||
}
|
||||
|
||||
// Asynchronous update check - performs more reliably with flakey Internet connections
|
||||
|
@ -381,7 +397,7 @@ esp32FOTA::execAsyncHTTPcheck()
|
|||
{
|
||||
_newVersion = 0;
|
||||
if(_versionTest.readyState() == 0 || _versionTest.readyState() == 4) {
|
||||
Serial.println("Querying server");
|
||||
Serial.println("Querying firmware update server");
|
||||
_versionTest.onReadyStateChange(FOTA_PollCallback, this);
|
||||
_versionTest.onBuildHeaders(NULL);
|
||||
_versionTest.onData(NULL);
|
||||
|
@ -432,13 +448,46 @@ esp32FOTA::decodeResponse(char* resp)
|
|||
|
||||
if (plversion > _firwmareVersion && fwtype == _firwmareType)
|
||||
{
|
||||
_newVersion = plversion;
|
||||
return true;
|
||||
_newVersion = plversion;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_newVersion = 0;
|
||||
return false;
|
||||
_newVersion = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
esp32FOTA::queueDLdata(asyncHTTPrequest* pRequest)
|
||||
{
|
||||
sFOTAqueue entry;
|
||||
|
||||
int len = pRequest->available();
|
||||
if(len <= sizeof(sFOTAqueue::data)) {
|
||||
entry.len = len;
|
||||
pRequest->responseRead(entry.data, len);
|
||||
BaseType_t awoken;
|
||||
xQueueSendFromISR(_queue, &entry, &awoken);
|
||||
}
|
||||
}
|
||||
|
||||
// routine called regularly by the "loop" task - ie not IRQL
|
||||
// it is not safe to do system things in the AsyncTCP callbacks!
|
||||
void
|
||||
esp32FOTA::process()
|
||||
{
|
||||
sFOTAqueue entry;
|
||||
if(xQueueReceive(_queue, &entry, 0)) {
|
||||
int16_t len = entry.len;
|
||||
|
||||
char working[256];
|
||||
memcpy(working, entry.data, 255);
|
||||
working[len] = 0;
|
||||
String JSONinfo(working);
|
||||
Serial.println(JSONinfo);
|
||||
Serial.println();
|
||||
decodeResponse(JSONinfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,12 @@
|
|||
//#include <Arduino.h>
|
||||
#include <functional>
|
||||
#include "../../asyncHTTPrequest/src/asyncHTTPrequest.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
struct sFOTAqueue{
|
||||
uint8_t len;
|
||||
uint8_t data[255];
|
||||
};
|
||||
|
||||
class esp32FOTA
|
||||
{
|
||||
|
@ -35,6 +41,8 @@ public:
|
|||
void execAsyncHTTPcheck();
|
||||
bool decodeResponse(String payload);
|
||||
bool decodeResponse(char* resp);
|
||||
void process();
|
||||
void queueDLdata(asyncHTTPrequest* request);
|
||||
|
||||
private:
|
||||
String getHeaderValue(String header, String headerName);
|
||||
|
@ -50,6 +58,8 @@ private:
|
|||
std::function<void()> _onSuccess;
|
||||
std::function<void()> _onFail;
|
||||
asyncHTTPrequest _versionTest;
|
||||
QueueHandle_t _queue;
|
||||
String _pollResponse;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1568,7 +1568,7 @@ void checkDebugCommands()
|
|||
TxManage.queueOffRequest();
|
||||
}
|
||||
else if(rxVal == 'h') {
|
||||
getWebContent();
|
||||
getWebContent(true);
|
||||
}
|
||||
else if(rxVal == 'r') {
|
||||
ESP.restart(); // reset the esp
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "TempSensorScreen.h"
|
||||
#include "FrostScreen.h"
|
||||
#include "HumidityScreen.h"
|
||||
#include "WebPageUpdateScreen.h"
|
||||
#include <Wire.h>
|
||||
#include "../cfg/pins.h"
|
||||
#include "../cfg/BTCConfig.h"
|
||||
|
@ -96,74 +97,6 @@ extern CScreenManager ScreenManager;
|
|||
// Identifier: DieselSplash
|
||||
// Draw Mode: Horizontal
|
||||
//
|
||||
/*const uint8_t DieselSplash [] PROGMEM = {
|
||||
// 'Splash3, 128x64px
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x06, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x3e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00,
|
||||
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||
0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x08, 0x00, 0x00, 0x01, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x88, 0x00, 0x00,
|
||||
0x00, 0x10, 0x00, 0x00, 0x20, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x84, 0x00, 0x00,
|
||||
0x00, 0x18, 0x00, 0x00, 0x20, 0x40, 0x00, 0x20, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x84, 0x00, 0x00,
|
||||
0x00, 0x14, 0x00, 0x00, 0x40, 0x40, 0x00, 0x10, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x84, 0x00, 0x00,
|
||||
0x00, 0x52, 0x00, 0x00, 0x40, 0x20, 0x00, 0x08, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00,
|
||||
0x00, 0x34, 0x00, 0x00, 0x40, 0x10, 0x00, 0x04, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
|
||||
0x00, 0x18, 0x00, 0x00, 0x80, 0x10, 0x00, 0x02, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
|
||||
0x00, 0x34, 0x00, 0x00, 0x80, 0x08, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
|
||||
0x00, 0x52, 0x00, 0x00, 0x80, 0x08, 0x01, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
|
||||
0x00, 0x14, 0x00, 0x01, 0x00, 0x04, 0x3e, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
|
||||
0x00, 0x18, 0x00, 0x01, 0x00, 0x07, 0xc0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
|
||||
0x00, 0x10, 0x00, 0x06, 0x80, 0x1c, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0xc4, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x18, 0x40, 0x64, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3c, 0x78, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3c, 0x40, 0x84, 0x00, 0x00, 0x01, 0x80, 0x00, 0x01, 0xc0, 0x40, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x26, 0x23, 0x04, 0x00, 0x00, 0x00, 0x60, 0x00, 0x1e, 0x00, 0x40, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x41, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x43, 0x1c, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x01, 0xe0, 0x00, 0x40, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x41, 0xf8, 0x02, 0x00, 0x00, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x40, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x40, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x40, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x40, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x60, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x30, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x10, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x19, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0f, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x07, 0xf8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0xf8, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x1f, 0x20, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x03, 0xe8, 0x20, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x7c, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x08, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x46, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x50, 0x00, 0x00,
|
||||
0x00, 0x02, 0x28, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x50, 0x00, 0x00,
|
||||
0x00, 0x02, 0x28, 0x73, 0x2d, 0xc9, 0x5a, 0x8c, 0xb0, 0x20, 0x31, 0xdd, 0x66, 0x53, 0x2c, 0x00,
|
||||
0x00, 0x03, 0xee, 0x44, 0xb1, 0x29, 0x63, 0x52, 0xc0, 0x20, 0x4a, 0x51, 0x89, 0x54, 0xb0, 0x00,
|
||||
0x00, 0x02, 0x28, 0x47, 0xa1, 0x29, 0x42, 0x5e, 0x80, 0x20, 0x4a, 0x51, 0x09, 0x57, 0xa0, 0x00,
|
||||
0x00, 0x02, 0x28, 0x44, 0x21, 0x2b, 0x42, 0x50, 0x80, 0x21, 0x4a, 0x51, 0x09, 0x54, 0x20, 0x00,
|
||||
0x00, 0x02, 0x28, 0x33, 0x21, 0xc5, 0x42, 0x4c, 0x80, 0x1e, 0x32, 0x4d, 0x06, 0x53, 0x20, 0x00
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
const uint8_t DieselSplash [] PROGMEM =
|
||||
|
@ -489,6 +422,7 @@ CScreenManager::_loadScreens()
|
|||
if(NVstore.getUserSettings().menuMode == 0 || NVstore.getUserSettings().menuMode == 2) {
|
||||
menuloop.clear();
|
||||
menuloop.push_back(new CVersionInfoScreen(*_pDisplay, *this)); // GPIO settings screen
|
||||
menuloop.push_back(new CWebPageUpdateScreen(*_pDisplay, *this)); // Web Page update screen
|
||||
if(NVstore.getUserSettings().menuMode == 0) {
|
||||
menuloop.push_back(new CHourMeterScreen(*_pDisplay, *this)); // Hour Meter screen
|
||||
}
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* This file is part of the "bluetoothheater" distribution
|
||||
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
|
||||
*
|
||||
* Copyright (C) 2020 Ray Jones <ray@mrjones.id.au>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "128x64OLED.h"
|
||||
#include "WebPageUpdateScreen.h"
|
||||
#include "KeyPad.h"
|
||||
#include "../Utility/helpers.h"
|
||||
#include "fonts/Arial.h"
|
||||
#include "../WiFi/BTCWiFi.h"
|
||||
#include "../WiFi/BTCWebServer.h"
|
||||
|
||||
|
||||
CWebPageUpdateScreen::CWebPageUpdateScreen(C128x64_OLED& display, CScreenManager& mgr) : CUIEditScreen(display, mgr)
|
||||
{
|
||||
_holdoff = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CWebPageUpdateScreen::onSelect()
|
||||
{
|
||||
CScreen::onSelect();
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CWebPageUpdateScreen::show()
|
||||
{
|
||||
|
||||
_display.clearDisplay();
|
||||
|
||||
// standard version information screens,
|
||||
// animation of update available via animate() if firmware update is available on web server
|
||||
_showTitle("Web Content Update");
|
||||
|
||||
int col = _display.xCentre();
|
||||
if(_rowSel == 0) {
|
||||
if(isWifiSTA()) {
|
||||
_printMenuText(col, 16, "Press Up to update", false, eCentreJustify);
|
||||
_printMenuText(col, 26, "web page content ", false, eCentreJustify);
|
||||
_printMenuText(col, 36, "stored in SPIFFS. ", false, eCentreJustify);
|
||||
}
|
||||
else {
|
||||
_printMenuText(col, 16, "WiFi STA connection", false, eCentreJustify);
|
||||
_printMenuText(col, 26, "must be active to ", false, eCentreJustify);
|
||||
_printMenuText(col, 36, "update web content!", false, eCentreJustify);
|
||||
}
|
||||
|
||||
_printMenuText(_display.xCentre(), 53, " \021 \020 ", true, eCentreJustify); // " < > "
|
||||
_printMenuText(_display.xCentre(), 53, "Exit", false, eCentreJustify); // " < Exit > "
|
||||
}
|
||||
else if(_rowSel == 1) {
|
||||
_display.writeFillRect(12, 21, 104, 26, WHITE);
|
||||
CTransientFont AF(_display, &arial_8ptBoldFontInfo);
|
||||
_printInverted(col, 24, "Press Center to", true, eCentreJustify);
|
||||
_printInverted(col, 34, "confirm update ", true, eCentreJustify);
|
||||
}
|
||||
else if(_rowSel == 2) {
|
||||
_printMenuText(col, 22, "Getting:", false, eCentreJustify);
|
||||
const char* filename = _getFileName();
|
||||
_printMenuText(col, 34, filename, false, eCentreJustify);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CWebPageUpdateScreen::animate()
|
||||
{
|
||||
int col = _display.xCentre();
|
||||
if(_rowSel == 2) {
|
||||
_printMenuText(col, 22, "Getting:", false, eCentreJustify);
|
||||
const char* filename = _getFileName();
|
||||
_display.fillRect(0,34,_display.width(), 10, BLACK);
|
||||
_printMenuText(col, 34, filename, false, eCentreJustify);
|
||||
return true;
|
||||
}
|
||||
if(_rowSel == 3) {
|
||||
_display.writeFillRect(12, 21, 104, 26, WHITE);
|
||||
CTransientFont AF(_display, &arial_8ptBoldFontInfo);
|
||||
_printInverted(col, 29, "ERROR OCCURED", true, eCentreJustify);
|
||||
|
||||
long tDelta = millis() - _holdoff;
|
||||
if(tDelta > 0) {
|
||||
_holdoff = 0;
|
||||
_rowSel = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CWebPageUpdateScreen::keyHandler(uint8_t event)
|
||||
{
|
||||
if(event & keyPressed) {
|
||||
// UP press
|
||||
if(event & key_Up) {
|
||||
if(_rowSel == 0) {
|
||||
if(isWifiSTA())
|
||||
_rowSel = 1;
|
||||
}
|
||||
else {
|
||||
_rowSel = 0;
|
||||
}
|
||||
}
|
||||
// DOWN press
|
||||
if(event & key_Down) {
|
||||
_rowSel = 0;
|
||||
}
|
||||
// LEFT press
|
||||
if(event & key_Left) {
|
||||
if(_rowSel == 0)
|
||||
_ScreenManager.prevMenu();
|
||||
_rowSel = 0;
|
||||
}
|
||||
// RIGHT press
|
||||
if(event & key_Right) {
|
||||
if(_rowSel == 0)
|
||||
_ScreenManager.nextMenu();
|
||||
_rowSel = 0;
|
||||
}
|
||||
// CENTRE press
|
||||
if(event & key_Centre) {
|
||||
if(_rowSel == 1) {
|
||||
getWebContent(true);
|
||||
_rowSel = 2;
|
||||
}
|
||||
else {
|
||||
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ScreenManager.reqUpdate();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char*
|
||||
CWebPageUpdateScreen::_getFileName()
|
||||
{
|
||||
const char* livename = getWebContent(false);
|
||||
|
||||
if(strcmp(livename, "DONE") == 0) {
|
||||
_rowSel = 0;
|
||||
}
|
||||
if(strcmp(livename, "ERROR") == 0) {
|
||||
_holdoff = (millis() + 2000) | 1;
|
||||
_rowSel = 3;
|
||||
}
|
||||
|
||||
return livename;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* This file is part of the "bluetoothheater" distribution
|
||||
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
|
||||
*
|
||||
* Copyright (C) 2020 Ray Jones <ray@mrjones.id.au>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WEBPAGEUPDATESCREEN_H__
|
||||
#define __WEBPAGEUPDATESCREEN_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "UIEditScreen.h"
|
||||
|
||||
class C128x64_OLED;
|
||||
class CScreenManager;
|
||||
|
||||
|
||||
class CWebPageUpdateScreen : public CUIEditScreen
|
||||
{
|
||||
std::string _filename;
|
||||
unsigned long _holdoff;
|
||||
const char* _getFileName();
|
||||
public:
|
||||
CWebPageUpdateScreen(C128x64_OLED& display, CScreenManager& mgr);
|
||||
bool show();
|
||||
bool animate();
|
||||
bool keyHandler(uint8_t event);
|
||||
void onSelect();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -409,11 +409,7 @@ void updateJSONclients(bool report)
|
|||
if (report) {
|
||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
||||
}
|
||||
sendWebSocketString( jsonStr );
|
||||
mqttPublishJSON(jsonStr);
|
||||
std::string expand = jsonStr;
|
||||
Expand(expand);
|
||||
getBluetoothClient().send( expand.c_str() );
|
||||
sendJSONtext(jsonStr);
|
||||
}
|
||||
}
|
||||
// update extended params
|
||||
|
@ -422,11 +418,7 @@ void updateJSONclients(bool report)
|
|||
if (report) {
|
||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
||||
}
|
||||
sendWebSocketString( jsonStr );
|
||||
mqttPublishJSON(jsonStr);
|
||||
std::string expand = jsonStr;
|
||||
Expand(expand);
|
||||
getBluetoothClient().send( expand.c_str() );
|
||||
sendJSONtext(jsonStr);
|
||||
}
|
||||
}
|
||||
// update timer parameters
|
||||
|
@ -437,11 +429,7 @@ void updateJSONclients(bool report)
|
|||
if (report) {
|
||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
||||
}
|
||||
sendWebSocketString( jsonStr );
|
||||
mqttPublishJSON(jsonStr);
|
||||
std::string expand = jsonStr;
|
||||
Expand(expand);
|
||||
getBluetoothClient().send( expand.c_str() );
|
||||
sendJSONtext(jsonStr);
|
||||
bNewTimerInfo = true;
|
||||
}
|
||||
}
|
||||
|
@ -460,11 +448,7 @@ void updateJSONclients(bool report)
|
|||
if (report) {
|
||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
||||
}
|
||||
sendWebSocketString( jsonStr );
|
||||
mqttPublishJSON(jsonStr);
|
||||
std::string expand = jsonStr;
|
||||
Expand(expand);
|
||||
getBluetoothClient().send( expand.c_str() );
|
||||
sendJSONtext(jsonStr);
|
||||
}
|
||||
|
||||
// report MQTT params
|
||||
|
@ -473,11 +457,7 @@ void updateJSONclients(bool report)
|
|||
if (report) {
|
||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
||||
}
|
||||
sendWebSocketString( jsonStr );
|
||||
mqttPublishJSON(jsonStr);
|
||||
std::string expand = jsonStr;
|
||||
Expand(expand);
|
||||
getBluetoothClient().send( expand.c_str() );
|
||||
sendJSONtext(jsonStr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -487,11 +467,7 @@ void updateJSONclients(bool report)
|
|||
if (report) {
|
||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
||||
}
|
||||
sendWebSocketString( jsonStr );
|
||||
mqttPublishJSON(jsonStr);
|
||||
std::string expand = jsonStr;
|
||||
Expand(expand);
|
||||
getBluetoothClient().send( expand.c_str() );
|
||||
sendJSONtext(jsonStr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -501,11 +477,7 @@ void updateJSONclients(bool report)
|
|||
if (report) {
|
||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
||||
}
|
||||
sendWebSocketString( jsonStr );
|
||||
mqttPublishJSON(jsonStr);
|
||||
std::string expand = jsonStr;
|
||||
Expand(expand);
|
||||
getBluetoothClient().send( expand.c_str() );
|
||||
sendJSONtext(jsonStr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -514,11 +486,7 @@ void updateJSONclients(bool report)
|
|||
if (report) {
|
||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
||||
}
|
||||
sendWebSocketString( jsonStr );
|
||||
mqttPublishJSON(jsonStr);
|
||||
std::string expand = jsonStr;
|
||||
Expand(expand);
|
||||
getBluetoothClient().send( expand.c_str() );
|
||||
sendJSONtext(jsonStr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -538,7 +506,8 @@ void resetAllJSONmoderators()
|
|||
resetJSONSysModerator(); // initJSONSysModerator();
|
||||
GPIOmoderator.reset();
|
||||
// create and send a validation code (then client knows AB is capable of reboot over JSON)
|
||||
doJSONreboot(0);
|
||||
doJSONreboot(0);
|
||||
sendJSONtext("{\"LoadWebContent\":\"Supported\"}");
|
||||
}
|
||||
|
||||
void initJSONMQTTmoderator()
|
||||
|
@ -596,6 +565,8 @@ void sendJSONtext(const char* jsonStr)
|
|||
{
|
||||
sendWebSocketString( jsonStr );
|
||||
mqttPublishJSON(jsonStr);
|
||||
std::string expand = jsonStr;
|
||||
Expand(expand);
|
||||
getBluetoothClient().send( jsonStr );
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ void resetJSONSysModerator();
|
|||
void resetJSONMQTTmoderator();
|
||||
void validateTimer(int ID);
|
||||
void doJSONreboot(uint16_t code);
|
||||
void sendJSONtext(const char* JSONstr);
|
||||
|
||||
template<class T>
|
||||
const char* createJSON(const char* name, T value)
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "HourMeter.h"
|
||||
#include "macros.h"
|
||||
#include "BTC_JSON.h"
|
||||
#include "../WiFi/BTCWebServer.h"
|
||||
|
||||
|
||||
// a class to track the blue wire receive / transmit states
|
||||
|
@ -439,5 +440,12 @@ void DecodeCmd(const char* cmd, String& payload)
|
|||
int16_t code = payload.toInt();
|
||||
doJSONreboot(code);
|
||||
}
|
||||
else if(strcmp("LoadWebContent", cmd) == 0) {
|
||||
getWebContent(true);
|
||||
}
|
||||
}
|
||||
|
||||
void setHoldoff(unsigned long& holdoff, unsigned long period)
|
||||
{
|
||||
holdoff = (millis() + period) | 1;
|
||||
}
|
|
@ -177,5 +177,6 @@ enum eOTAmodes {
|
|||
eOTAnormal, eOTAbrowser, eOTAWWW
|
||||
};
|
||||
|
||||
void setHoldoff(unsigned long& holdoff, unsigned long period);
|
||||
|
||||
#endif // __UTIL_CLASSES_H__
|
||||
|
|
|
@ -55,7 +55,7 @@ extern void checkSplashScreenUpdate();
|
|||
sBrowserUpload BrowserUpload;
|
||||
WebServer server(80);
|
||||
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||
CWebContentDL WebContentDL;
|
||||
CGetWebContent GetWebContent;
|
||||
|
||||
bool bRxWebData = false; // flags for OLED animation
|
||||
bool bTxWebData = false;
|
||||
|
@ -85,7 +85,17 @@ void onUploadProgression();
|
|||
void onRename();
|
||||
void build404Response(String& content, String file);
|
||||
void build500Response(String& content, String file);
|
||||
void manageWegContentUpdate();
|
||||
|
||||
|
||||
const char* getWebContent(bool start) {
|
||||
|
||||
if(isWifiSTA() && start) {
|
||||
GetWebContent.start();
|
||||
}
|
||||
|
||||
return GetWebContent.getFilename();
|
||||
}
|
||||
|
||||
|
||||
void initWebServer(void) {
|
||||
|
||||
|
@ -149,7 +159,7 @@ bool doWebServer(void)
|
|||
{
|
||||
webSocket.loop();
|
||||
server.handleClient();
|
||||
manageWegContentUpdate();
|
||||
GetWebContent.manage();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -872,7 +882,7 @@ body {
|
|||
<body>
|
||||
<h1>SPIFFS partition has been formatted</h1>
|
||||
<h3>You must now upload the web content.</h3>
|
||||
<p>Latest web content can be downloaded from <a href='http://www.mrjones.id.au/afterburner/firmware.html' target='_blank'>http://www.mrjones.id.au/afterburner/firmware.html</a>
|
||||
<p>Latest web content can be downloaded from <a href='http://afterburner.mrjones.id.au/firmware.html' target='_blank'>http://afterburner.mrjones.id.au/firmware.html</a>
|
||||
<h4 class="throb">Please ensure you unzip the web page content, then upload all the files contained.</h4>
|
||||
<p><button onclick=location.assign('/update')>Upload web content</button>
|
||||
</body>
|
||||
|
@ -1027,7 +1037,7 @@ for (uint8_t i = 0; i < server.args(); i++) {
|
|||
content += R"=====(<hr>
|
||||
<p>Please check the URL.<br>
|
||||
If OK please try uploading the file from the web content.
|
||||
<p>Latest web content can be downloaded from <a href="http://www.mrjones.id.au/afterburner/firmware.html" target="_blank">http://www.mrjones.id.au/afterburner/firmware.html</a>
|
||||
<p>Latest web content can be downloaded from <a href="http://afterburner.mrjones.id.au/firmware.html" target="_blank">http://afterburner.mrjones.id.au/firmware.html</a>
|
||||
<h4 class="throb">Please ensure you unzip the web page content, then upload all the files contained.</h4>
|
||||
<p><a href="/update"><button>Upload web content</button></a><br>
|
||||
)=====";
|
||||
|
@ -1054,7 +1064,7 @@ content += file;
|
|||
content += R"=====(" </i></b> exists, but cannot be streamed?
|
||||
<hr>
|
||||
<p>Recommended remedy is to re-format the SPIFFS partition, then reload the web content files.
|
||||
<br>Latest web content can be downloaded from <a href="http://www.mrjones.id.au/afterburner/firmware.html" target="_blank">http://www.mrjones.id.au/afterburner/firmware.html</a> <i>(opens in new page)</i>.
|
||||
<br>Latest web content can be downloaded from <a href="http://afterburner.mrjones.id.au/firmware.html" target="_blank">http://afterburner.mrjones.id.au/firmware.html</a> <i>(opens in new page)</i>.
|
||||
<p>To format the SPIFFS partition, press <button class='redbutton' onClick=location.assign('/formatspiffs')>Format SPIFFS</button>
|
||||
<p>You will then need to upload each file of the web content by using the subsequent "<b>Upload</b>" button.
|
||||
<hr>
|
||||
|
@ -1064,41 +1074,4 @@ content += R"=====(" </i></b> exists, but cannot be streamed?
|
|||
)=====";
|
||||
}
|
||||
|
||||
static int webContentState = 0;
|
||||
|
||||
void getWebContent() {
|
||||
webContentState = 1;
|
||||
// WebContentDL.get("index.html.gz");
|
||||
// getWebContent("favicon.ico");
|
||||
}
|
||||
|
||||
|
||||
void manageWegContentUpdate()
|
||||
{
|
||||
switch(webContentState) {
|
||||
case 1:
|
||||
DebugPort.println("Requesting index.html.gz from Afterburner web site");
|
||||
WebContentDL.get("index.html.gz");
|
||||
webContentState++;
|
||||
break;
|
||||
case 2:
|
||||
WebContentDL.process();
|
||||
if(!WebContentDL.busy()) {
|
||||
DebugPort.println("Completed index.html.gz from Afterburner web site");
|
||||
webContentState++;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
DebugPort.println("Requesting favicon.ico from Afterburner web site");
|
||||
WebContentDL.get("favicon.ico");
|
||||
webContentState++;
|
||||
break;
|
||||
case 4:
|
||||
WebContentDL.process();
|
||||
if(!WebContentDL.busy()) {
|
||||
DebugPort.println("Completed favicon.ico from Afterburner web site");
|
||||
webContentState = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ bool sendWebSocketString(const char* Str);
|
|||
bool isWebSocketClientChange();
|
||||
void listSPIFFS(const char * dirname, uint8_t levels, String& HTMLreport, int withHTMLanchors=0);
|
||||
|
||||
void getWebContent();
|
||||
const char* getWebContent(bool start);
|
||||
void getWebContent(const char* filename);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -126,9 +126,9 @@ void DoOTA()
|
|||
FOTA.onComplete(CheckFirmwareCRC); // upload complete, but not yet verified
|
||||
FOTA.onSuccess(onSuccess);
|
||||
#ifdef TESTFOTA
|
||||
FOTA.setCheckURL("http://www.mrjones.id.au/afterburner/fota/fotatest.json");
|
||||
FOTA.setCheckURL("http://afterburner.mrjones.id.au/fota/fotatest.json");
|
||||
#else
|
||||
FOTA.setCheckURL("http://www.mrjones.id.au/afterburner/fota/fota.json");
|
||||
FOTA.setCheckURL("http://afterburner.mrjones.id.au/fota/fota.json");
|
||||
#endif
|
||||
|
||||
#ifdef SYNCHRONOUS_FOTA
|
||||
|
@ -174,6 +174,8 @@ void DoOTA()
|
|||
|
||||
int isUpdateAvailable(bool test)
|
||||
{
|
||||
FOTA.process(); // manage any queued responses
|
||||
|
||||
if(test) {
|
||||
if(FOTAauth >= 1) {
|
||||
return FOTA.getNewVersion();
|
||||
|
|
|
@ -1,9 +1,37 @@
|
|||
/*
|
||||
* This file is part of the "bluetoothheater" distribution
|
||||
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
|
||||
*
|
||||
* Copyright (C) 2020 Ray Jones
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// seek a web page update from the afterburner web server
|
||||
|
||||
#include "WebContentDL.h"
|
||||
#include "../Utility/DebugPort.h"
|
||||
#include "../Utility/helpers.h"
|
||||
#include "../Utility/BTC_JSON.h"
|
||||
|
||||
// #define DUMP_WEB_BYTES
|
||||
|
||||
// callback function for bulk of file download.
|
||||
// It appears the callback may well be running at an elevated priority, perhaps IRQL
|
||||
// and that causes random core crashes when accessing SPIFFS.
|
||||
// Instead me marshall the data via FreeRTOS queue to be handled at a definite user level later.
|
||||
void WebPageDataCB(void* pClass, asyncHTTPrequest* request, size_t available)
|
||||
{
|
||||
CWebContentDL* pParent = (CWebContentDL*)pClass;
|
||||
|
@ -17,25 +45,29 @@ void WebPageDataCB(void* pClass, asyncHTTPrequest* request, size_t available)
|
|||
}
|
||||
|
||||
|
||||
// callback function for completion of the Async TCP "GET" request.
|
||||
// Not all file data may be processed yet...
|
||||
void WebPageRequestCB(void* pClass, asyncHTTPrequest* request, int readyState)
|
||||
{
|
||||
CWebContentDL* pParent = (CWebContentDL*)pClass;
|
||||
if(readyState == 4){
|
||||
if(readyState == 4) {
|
||||
while(request->available()) {
|
||||
pParent->queueDLdata(request->available(), request);
|
||||
}
|
||||
pParent->finalise();
|
||||
pParent->finalise(request->responseHTTPcode() == 200); // mark end of file data, causes SPIFFS file to be closed.
|
||||
|
||||
request->close();
|
||||
request->close(); // graceful close the Async TCP connection
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
CWebContentDL::CWebContentDL()
|
||||
{
|
||||
// _request.setDebug(true);
|
||||
_request.setDebug(true);
|
||||
_request.onReadyStateChange(WebPageRequestCB, this);
|
||||
_request.onData(WebPageDataCB, this);
|
||||
_queue = xQueueCreate(10, sizeof(sQueueEntry));
|
||||
_queue = NULL;
|
||||
_fileActive = false;
|
||||
_bytecount = 0;
|
||||
_queuecount = 0;
|
||||
|
@ -43,71 +75,83 @@ CWebContentDL::CWebContentDL()
|
|||
|
||||
CWebContentDL::~CWebContentDL()
|
||||
{
|
||||
vQueueDelete(_queue);
|
||||
_closequeue();
|
||||
}
|
||||
|
||||
bool
|
||||
CWebContentDL::busy() const
|
||||
{
|
||||
return _fileActive || (_request.readyState() != 0 && _request.readyState() != 4) ;
|
||||
if(_fileActive)
|
||||
return true;
|
||||
return _request.readyState() != 0 && _request.readyState() != 4;
|
||||
}
|
||||
|
||||
bool
|
||||
CWebContentDL::OK() const
|
||||
{
|
||||
return _bOK;
|
||||
}
|
||||
|
||||
void CWebContentDL::get(const char* filename)
|
||||
{
|
||||
if(_request.readyState() == 0 || _request.readyState() == 4){
|
||||
// ensure leading forward slash, required for SPIFFS
|
||||
_filename = "";
|
||||
if(filename[0] != '/') _filename = "/";
|
||||
_filename += filename;
|
||||
// replace with sanitised name
|
||||
filename = _filename.c_str();
|
||||
|
||||
DebugPort.printf("Loading file to SPIFFS: '%s'\r\n", filename);
|
||||
if(SPIFFS.exists(filename)) {
|
||||
DebugPort.println("Removing existing file from SPIFFS");
|
||||
SPIFFS.remove(filename);
|
||||
}
|
||||
|
||||
_file = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist)
|
||||
_fileActive = true;
|
||||
_openqueue();
|
||||
_openfile(filename);
|
||||
_bytecount = 0;
|
||||
_queuecount = 0;
|
||||
_bOK = false;
|
||||
|
||||
String URL = "http://afterburner.mrjones.id.au/fota/web";
|
||||
URL += filename;
|
||||
std::string URL = "http://afterburner.mrjones.id.au/fota/web";
|
||||
URL += _filename;
|
||||
_request.open("GET", URL.c_str());
|
||||
_request.send();
|
||||
}
|
||||
}
|
||||
|
||||
void CWebContentDL::process()
|
||||
// routine called regualrly by the "loop" task - ie not IRQL
|
||||
// it is no safe to write to SPIFFS in the AsyncTCP callbacks!
|
||||
void
|
||||
CWebContentDL::process()
|
||||
{
|
||||
sQueueEntry entry;
|
||||
while(xQueueReceive(_queue, &entry, 0)) {
|
||||
|
||||
while(_queue != NULL && xQueueReceive(_queue, &entry, 0)) {
|
||||
int16_t len = entry.len;
|
||||
if(len == -1) {
|
||||
if(_file) {
|
||||
_file.close();
|
||||
_fileActive = false;
|
||||
}
|
||||
_closefile();
|
||||
_closequeue();
|
||||
_bOK = true;
|
||||
DebugPort.printf("Downloaded %s (%d bytes) - CLOSED OK\r\n", _filename.c_str(), _bytecount);
|
||||
|
||||
}
|
||||
else if(len == -2) {
|
||||
_closefile();
|
||||
SPIFFS.remove(_filename.c_str()); // remove the bad file from SPIFFS
|
||||
_closequeue();
|
||||
DebugPort.printf("HTTP ERROR ENCOUNTERED: %s\r\n", _filename.c_str());
|
||||
}
|
||||
else if(len > 0) {
|
||||
if(_file) {
|
||||
if(_file.write(entry.data, len) != len) { // Write the received bytes to the file
|
||||
_file.close();
|
||||
_fileActive = false;
|
||||
DebugPort.printf("Web content downlod - FILE_WRITE error: removing %s\r\n", _filename.c_str());
|
||||
_closefile();
|
||||
DebugPort.printf("Web content download - FILE_WRITE error: removing %s\r\n", _filename.c_str());
|
||||
SPIFFS.remove(_filename.c_str()); // remove the bad file from SPIFFS
|
||||
}
|
||||
else {
|
||||
#ifdef DUMP_WEB_BYTES
|
||||
for(int i=0; i< len;) {
|
||||
for(int j=0; j< 32 && i<len; j++) {
|
||||
DebugPort.printf("%02X ", entry.data[i++]);
|
||||
if((i & 0xf) == 0)
|
||||
DebugPort.print(" ");
|
||||
if((i & 0x7) == 0)
|
||||
DebugPort.print(" ");
|
||||
}
|
||||
DebugPort.print("\r\n");
|
||||
}
|
||||
#endif
|
||||
_bytecount += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
// DebugPort.printf("Len=%d Queuecount=%d/%d total=%d\r\n", entry.len, entry.count, queuecount, webpagecount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,30 +165,234 @@ CWebContentDL::queueDLdata(int size, asyncHTTPrequest* request)
|
|||
|
||||
int16_t read = request->responseRead(entry.data, size);
|
||||
|
||||
if(read > 0) {
|
||||
// available -= read;
|
||||
entry.len = read;
|
||||
entry.count = ++_queuecount;
|
||||
|
||||
BaseType_t awoken;
|
||||
xQueueSendFromISR(_queue, &entry, &awoken);
|
||||
if(_queue == NULL) {
|
||||
DebugPort.println("CWebContentDL::queueDLdata - no queue!");
|
||||
}
|
||||
else if(read <= 0) {
|
||||
DebugPort.println("CWebContentDL::queueDLdata - read error?");
|
||||
}
|
||||
else {
|
||||
DebugPort.println(" page read error?");
|
||||
// available -= read;
|
||||
if(request->responseHTTPcode() == 200) { // only push to queue if HTTP OK
|
||||
entry.len = read;
|
||||
entry.count = ++_queuecount;
|
||||
|
||||
BaseType_t awoken;
|
||||
xQueueSendFromISR(_queue, &entry, &awoken);
|
||||
}
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
void
|
||||
CWebContentDL::finalise()
|
||||
CWebContentDL::finalise(bool OK)
|
||||
{
|
||||
sQueueEntry entry;
|
||||
if(_queue != NULL) {
|
||||
sQueueEntry entry;
|
||||
|
||||
entry.len = -1;
|
||||
entry.count = -1;
|
||||
BaseType_t awoken;
|
||||
xQueueSendFromISR(_queue, &entry, &awoken);
|
||||
entry.len = OK ? -1 : -2;
|
||||
entry.count = -1;
|
||||
BaseType_t awoken;
|
||||
xQueueSendFromISR(_queue, &entry, &awoken);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CWebContentDL::abort()
|
||||
{
|
||||
_request.close();
|
||||
|
||||
_closefile();
|
||||
}
|
||||
|
||||
void
|
||||
CWebContentDL::_closefile()
|
||||
{
|
||||
if(_file) {
|
||||
_file.close();
|
||||
_fileActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CWebContentDL::_openqueue()
|
||||
{
|
||||
if(_queue == NULL) {
|
||||
_queue = xQueueCreate(10, sizeof(sQueueEntry));
|
||||
_queuecount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CWebContentDL::_closequeue()
|
||||
{
|
||||
if(_queue)
|
||||
vQueueDelete(_queue);
|
||||
_queue = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CWebContentDL::_setfilename(const char* filename)
|
||||
{
|
||||
// ensure leading forward slash, required for SPIFFS
|
||||
_filename = "";
|
||||
if(filename[0] != '/') _filename = "/";
|
||||
_filename += filename;
|
||||
}
|
||||
|
||||
void
|
||||
CWebContentDL::_openfile(const char* filename)
|
||||
{
|
||||
_setfilename(filename);
|
||||
filename = _filename.c_str(); // replace with sanitised name
|
||||
|
||||
DebugPort.printf("Loading file to SPIFFS: '%s'\r\n", filename);
|
||||
if(SPIFFS.exists(filename)) {
|
||||
DebugPort.println(" Already exists! - removing");
|
||||
SPIFFS.remove(filename);
|
||||
}
|
||||
|
||||
_file = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS
|
||||
_fileActive = true;
|
||||
}
|
||||
|
||||
const char*
|
||||
CWebContentDL::getState()
|
||||
{
|
||||
return _filename.c_str();
|
||||
}
|
||||
|
||||
|
||||
CGetWebContent::CGetWebContent()
|
||||
{
|
||||
_state = 0;
|
||||
_holdoff = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CGetWebContent::start() {
|
||||
_state = 1;
|
||||
manage();
|
||||
}
|
||||
|
||||
void
|
||||
CGetWebContent::_get(const char* filename)
|
||||
{
|
||||
_filename = filename;
|
||||
DebugPort.printf("Requesting %s from Afterburner web site\r\n", _filename.c_str());
|
||||
handler.get(_filename.c_str());
|
||||
setHoldoff(_holdoff, 15000);
|
||||
}
|
||||
|
||||
bool
|
||||
CGetWebContent::_done()
|
||||
{
|
||||
if(!handler.busy()) {
|
||||
DebugPort.printf("Completed %s from Afterburner web site\r\n", _filename.c_str());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CGetWebContent::manage()
|
||||
{
|
||||
switch(_state) {
|
||||
case 1:
|
||||
_get("index.html.gz");
|
||||
_state++;
|
||||
break;
|
||||
case 2:
|
||||
handler.process();
|
||||
if(_timeout()) {
|
||||
handler.abort();
|
||||
_state = -1;
|
||||
}
|
||||
if(_done()) {
|
||||
if(!handler.OK()) {
|
||||
setHoldoff(_holdoff, 1000);
|
||||
_state = -2;
|
||||
}
|
||||
else {
|
||||
_sendJSON();
|
||||
_state++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
_get("favicon.ico");
|
||||
_state++;
|
||||
break;
|
||||
case 4:
|
||||
handler.process();
|
||||
if(_timeout()) {
|
||||
handler.abort();
|
||||
_state = -1;
|
||||
}
|
||||
if(_done()) {
|
||||
setHoldoff(_holdoff, 1000);
|
||||
if(!handler.OK()) {
|
||||
setHoldoff(_holdoff, 1000);
|
||||
_state = -2;
|
||||
}
|
||||
else {
|
||||
_state++;
|
||||
_sendJSON();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if(_timeout()) {
|
||||
_state = 0;
|
||||
_sendJSON("DONE");
|
||||
}
|
||||
break;
|
||||
case -2:
|
||||
if(_timeout()) {
|
||||
_state = -1;
|
||||
_sendJSON("ERROR");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CGetWebContent::_timeout() {
|
||||
if(_holdoff) {
|
||||
long tDelta = millis() - _holdoff;
|
||||
if(tDelta > 0) {
|
||||
_holdoff = 0;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const char*
|
||||
CGetWebContent::getFilename()
|
||||
{
|
||||
if(_state == -1)
|
||||
return "ERROR";
|
||||
if(_state == 0)
|
||||
return "DONE";
|
||||
return _filename.c_str();
|
||||
}
|
||||
|
||||
void
|
||||
CGetWebContent::_sendJSON(const char* name)
|
||||
{
|
||||
std::string JSONmsg;
|
||||
|
||||
JSONmsg = "{\"LoadWebContent\":\"";
|
||||
if(name == NULL)
|
||||
JSONmsg += _filename;
|
||||
else
|
||||
JSONmsg += name;
|
||||
JSONmsg += "\"}";
|
||||
sendJSONtext(JSONmsg.c_str());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
/*
|
||||
* This file is part of the "bluetoothheater" distribution
|
||||
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
|
||||
*
|
||||
* Copyright (C) 2020 Ray Jones
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// seek a web page update from the afterburner web server
|
||||
|
||||
#include "../../asyncHTTPrequest/src/asyncHTTPrequest.h"
|
||||
|
@ -21,6 +42,12 @@ class CWebContentDL {
|
|||
int _bytecount;
|
||||
int _queuecount;
|
||||
QueueHandle_t _queue;
|
||||
bool _bOK;
|
||||
void _closefile();
|
||||
void _openfile(const char* filename);
|
||||
void _openqueue();
|
||||
void _closequeue();
|
||||
void _setfilename(const char* filename);
|
||||
public:
|
||||
CWebContentDL();
|
||||
~CWebContentDL();
|
||||
|
@ -28,10 +55,31 @@ public:
|
|||
void process();
|
||||
// callback handlers
|
||||
int16_t queueDLdata(int size, asyncHTTPrequest* request);
|
||||
void finalise();
|
||||
void finalise(bool OK);
|
||||
bool busy() const;
|
||||
bool OK() const;
|
||||
void abort();
|
||||
const char* getState();
|
||||
};
|
||||
|
||||
class CGetWebContent
|
||||
{
|
||||
unsigned long _holdoff;
|
||||
int _state;
|
||||
std::string _filename;
|
||||
void _get(const char* filename);
|
||||
bool _done();
|
||||
bool _timeout();
|
||||
void _sendJSON(const char* filename=NULL);
|
||||
CWebContentDL handler;
|
||||
public:
|
||||
CGetWebContent();
|
||||
void start();
|
||||
void manage();
|
||||
const char* getFilename();
|
||||
};
|
||||
|
||||
|
||||
void WebPageRequestCB(void* optParm, asyncHTTPrequest* request, int readyState);
|
||||
void WebPageDataCB(void* optParm, asyncHTTPrequest*, size_t available);
|
||||
|
||||
|
|
Loading…
Reference in New Issue