Skip to content

Commit

Permalink
Add basic update progress page
Browse files Browse the repository at this point in the history
  • Loading branch information
noisymime committed Sep 10, 2024
1 parent 81af58b commit debd9a9
Show file tree
Hide file tree
Showing 13 changed files with 382 additions and 139 deletions.
64 changes: 0 additions & 64 deletions data/js/updates.js

This file was deleted.

2 changes: 1 addition & 1 deletion src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include <ArduinoJson.h>

#define PRODUCT_NAME "AirBear"
#define FIRMWARE_VERSION "0.0.6"
#define FIRMWARE_VERSION "0.0.3"

#define FAKE_RPM

Expand Down
134 changes: 74 additions & 60 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ void setup()
initTimers();
initBLE();
initWiFi();
updateFromRemote(); //Check for pending remote firmware updates

delay(1000);
Serial.println("Connection Type: " + String(config.getUChar("connection_type")));
Expand All @@ -37,74 +36,88 @@ void setup()
{
initTCP();
}
if( (config.getUChar("connection_type") == CONNECTION_TYPE_WIFI) )

if(updatesPending())
{
//Init file system
if (!SPIFFS.begin(true)) {
Serial.println("An error has occurred while mounting SPIFFS");
}
initSSE();
initSerialData();

//Init the web server
// Web Server Root URL
//When updates are pending, only show the minimum pages
server.on("/updateStatus", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/json", update_progress_json(request));
});
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(SPIFFS, "/index.html", "text/html");
});

server.on("/data", HTTP_GET, [](AsyncWebServerRequest *request) {
String jsonOutput;
serializeJson(readings_JSON, jsonOutput);
//request->send(200, "text/json", JSON.stringify(readings_JSON));
request->send(200, "text/json", jsonOutput.c_str());
});

server.serveStatic("/", SPIFFS, "/");

request->send(200, "text/html", updateInProgressPage());
});
}
else
{
//If not using the web dash then the root URL will produce the config page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/html", webConfigRequest(request));
});
}
if( (config.getUChar("connection_type") == CONNECTION_TYPE_WIFI) && (updatesPending() == false) )
{
//Init file system
if (!SPIFFS.begin(true)) {
Serial.println("An error has occurred while mounting SPIFFS");
}
initSSE();
initSerialData();

//Init the web server
// Web Server Root URL
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(SPIFFS, "/index.html", "text/html");
});

server.on("/data", HTTP_GET, [](AsyncWebServerRequest *request) {
String jsonOutput;
serializeJson(readings_JSON, jsonOutput);
//request->send(200, "text/json", JSON.stringify(readings_JSON));
request->send(200, "text/json", jsonOutput.c_str());
});

server.serveStatic("/", SPIFFS, "/");

server.on(WEB_CONFIG_URL, HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/html", webConfigRequest(request));
});

server.on(WEB_CONFIG_URL, HTTP_POST, [](AsyncWebServerRequest *request) {
request->send(200, "text/html", webConfigPOSTRequest(request));
});

//Updates the firmware AND data from remote URLs
server.on(UPDATE_REMOTE_URL, HTTP_POST, [](AsyncWebServerRequest *request) {
request->send(200, "text/html", saveRemoteFW_URLs(request));
ESP.restart();
});
//Scan the wifi networks and return them as JSON
server.on("/wifi", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/json", scanWifi(request));
});

server.on(UPDATE_DATA_UPLOAD_URL, HTTP_POST, [](AsyncWebServerRequest *request) {
}
else
{
//If not using the web dash then the root URL will produce the config page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/html", webConfigRequest(request));
});
}

server.on(WEB_CONFIG_URL, HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/html", webConfigRequest(request));
});

server.on(WEB_CONFIG_URL, HTTP_POST, [](AsyncWebServerRequest *request) {
request->send(200, "text/html", webConfigPOSTRequest(request));
});

//Updates the firmware AND data from remote URLs
server.on(UPDATE_REMOTE_URL, HTTP_POST, [](AsyncWebServerRequest *request) {
request->send(200, "text/html", saveRemoteFW_URLs(request));
delay(1000); //Wait 1 second to allow the page to be sent before restarting
ESP.restart();
});
//Scan the wifi networks and return them as JSON
server.on("/wifi", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/json", scanWifi(request));
});

server.on(UPDATE_DATA_UPLOAD_URL, HTTP_POST, [](AsyncWebServerRequest *request) {
//This runs when the uplaod is completed
partitionUploadComplete(request);
},[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
//This runs each time a new chunk is received
partitionUploadChunk(request, filename, index, data, len, final, U_SPIFFS);
}
);
server.on(UPDATE_FW_UPLOAD_URL, HTTP_POST, [](AsyncWebServerRequest *request) {
//This runs when the uplaod is completed
partitionUploadComplete(request);
},[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
},[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
//This runs each time a new chunk is received
partitionUploadChunk(request, filename, index, data, len, final, U_SPIFFS);
}
);
server.on(UPDATE_FW_UPLOAD_URL, HTTP_POST, [](AsyncWebServerRequest *request) {
//This runs when the uplaod is completed
partitionUploadComplete(request);
},[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
//This runs each time a new chunk is received
partitionUploadChunk(request, filename, index, data, len, final, U_FLASH);
}
);

partitionUploadChunk(request, filename, index, data, len, final, U_FLASH);
}
);
}


// Start server
Expand All @@ -116,6 +129,7 @@ void setup()

server.begin();

updateFromRemote(); //Check for pending remote firmware updates

//By default the ESP32-C3 will output a bunch of diag messages on bootup over UART.
//This messes up the secondary serial on the Speeduino so these bootup messages are disabled.
Expand Down
7 changes: 7 additions & 0 deletions src/static/static_html.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "static_html.h"


String staticHTML_head()
{
return String("<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
}
8 changes: 8 additions & 0 deletions src/static/static_html.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef STATIC_HTML_H
#define STATIC_HTML_H

#include "../globals.h"

String staticHTML_head();

#endif
11 changes: 11 additions & 0 deletions src/static/static_js.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "static_js.h"

String staticJS_updates()
{
String js = "";
js += "<script>";
js += "function i(t){return document.getElementById(t)}function r(t,e){return t=t.replace('v',''),e=e.replace('v',''),t.startsWith(e+'-')?-1:e.startsWith(t+'-')?1:t.localeCompare(e,void 0,{numeric:!0,sensitivity:'case',caseFirst:'upper'})}function o(t){return t.browser_download_url.split('/').pop()}async function getLatestGithubRelease(t){var e,a=await(await fetch('https://api.github.com/repos/speeduino/AirBear/releases/latest')).json(),n=a.tag_name;if(1==r(i('latest_release_txt').innerHTML=n,t)){i('update_btn').disabled=!1;for(const s of a.assets)s.name.includes('littlefs')?(e='http://speeduino.com/fw/AirBear/'+n+'/'+o(s),i('newData_url').value=e):(e='http://speeduino.com/fw/AirBear/'+n+'/'+o(s),i('newFW_url').value=e)}}async function scanWifi(){var t=i('ssid');for(const a of(await(await fetch('/wifi')).json()).networks){var e=document.createElement('option');e.value=a.ssid,e.text=a.ssid,t.add(e)}}function toggleData(){var t=i('newData_url');t.disabled=!t.disabled}function a(t,e){t.innerHTML=e}function updateProgress(){setTimeout(async()=>{let t;try{var e=await fetch('/updateStatus');t=await e.json()}catch(t){updateProgress()}t&&(a(i('updateStatus'),t.updateStatus),a(i('updateComplete'),t.updateProgress),a(i('updateSize'),t.updateSize),e=Math.floor(t.updateProgress/t.updateSize*100),a(i('updatePercent'),e),98<=e?window.location.href='/':updateProgress())},1500)}";
js += "</script>";

return js;
}
8 changes: 8 additions & 0 deletions src/static/static_js.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef STATIC_JS_H
#define STATIC_JS_H

#include "../globals.h"

String staticJS_updates();

#endif
102 changes: 102 additions & 0 deletions src/static/static_js.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//This file is uglified using UglifyJS 3 and the config file within this directory.
//The output of this is placed into static_js.cpp
//This can be generaetd with the cmd: uglifyjs --config-file uglifyjs.config.json static_js.js

function getElementByID(id)
{
return document.getElementById(id)
}


function semverCompare(a, b)
{
a = a.replace('v','')
b = b.replace('v','')
if (a.startsWith(b + '-')) return -1
if (b.startsWith(a + '-')) return 1
return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'case', caseFirst: 'upper' })
}

function getfileName(asset)
{
return asset.browser_download_url.split('/').pop()
}

async function getLatestGithubRelease(currentVersion)
{
const jsonData = await (await fetch('https://api.github.com/repos/speeduino/AirBear/releases/latest')).json();
const latestVersion = jsonData.tag_name;
getElementByID('latest_release_txt').innerHTML = latestVersion
if(semverCompare(latestVersion, currentVersion) == 1) //Value of 1 means a > b
{
getElementByID('update_btn').disabled = false

for(const asset of jsonData.assets)
{
if(asset.name.includes('littlefs'))
{
const newData_url = 'http://speeduino.com/fw/AirBear/' + latestVersion + '/' + getfileName(asset)
getElementByID('newData_url').value = newData_url
console.log("Data file: " + newData_url)
}
else
{
const newFW_url = 'http://speeduino.com/fw/AirBear/' + latestVersion + '/' + getfileName(asset)
getElementByID('newFW_url').value = newFW_url
console.log("FW file: " + newFW_url)
}
}
}
}

async function scanWifi()
{
const s = getElementByID('ssid')
const jsonData = await (await fetch('/wifi')).json()
for(const network of jsonData.networks)
{
const opt = document.createElement('option');
opt.value = network.ssid;
opt.text = network.ssid;
s.add(opt)
}
}

function toggleData()
{
const dataField = getElementByID('newData_url')
dataField.disabled = !dataField.disabled
}

function setInnerHTML(id, val)
{
id.innerHTML = val
}

function updateProgress()
{
setTimeout(async () => {
let jsonData
try {
const response = await fetch('/updateStatus')
jsonData = await response.json();
}
catch (error)
{
console.log(error)
updateProgress()
}

if(jsonData)
{
setInnerHTML(getElementByID('updateStatus'), jsonData.updateStatus)
setInnerHTML(getElementByID('updateComplete'), jsonData.updateProgress)
setInnerHTML(getElementByID('updateSize'), jsonData.updateSize)
const percentComplete = Math.floor((jsonData.updateProgress / jsonData.updateSize) * 100)
setInnerHTML(getElementByID('updatePercent'), percentComplete)
console.log(percentComplete)
if(percentComplete >= 98) { window.location.href = '/' }
else { updateProgress() }
}
}, 1500);
}
Loading

0 comments on commit debd9a9

Please sign in to comment.