#13 basic working version of OTA

This commit is contained in:
Thomas Ballmann 2020-05-02 12:23:00 +02:00
parent 94a53071a7
commit 93ed45f572
2 changed files with 202 additions and 3 deletions

View File

@ -22,10 +22,12 @@
Weather
<v-icon>$wb_sunny</v-icon>
</v-tab>
<!--
<v-tab>
Cloud
<v-icon>$cloud</v-icon>
</v-tab>
-->
</v-tabs>
<v-card v-if="settings" class="mx-auto" width="400">
@ -45,6 +47,65 @@
label="i8n:Theme"
placeholder
></v-select>
<v-dialog v-model="dialogSystemUpdate" max-width="400">
<template v-slot:activator="{ on }">
<v-btn class="my-5" block small outlined color="warning" v-on="on">System update</v-btn>
</template>
<v-card :loading="system.updateProgress > 0">
<template v-slot:progress>
<v-progress-linear
v-model="system.updateProgress"
:indeterminate="system.updateProgress === 100"
height="10"
></v-progress-linear>
</template>
<v-card-title class="headline">System update</v-card-title>
<v-card-text>
<!--
<v-alert border="left" type="warning" outlined>
Sed in libero ut nibh placerat accumsan. Phasellus leo dolor, tempus non, auctor et
</v-alert>
-->
<v-file-input
v-model="system.firmware"
show-size
accept="application/octet-stream"
label="Firmware"
></v-file-input>
</v-card-text>
<v-card-actions>
<v-btn text href="https://github.com/paperdash" target="_blank">Get firmware</v-btn>
<v-spacer></v-spacer>
<v-btn
outlined
color="warning"
ref="firmware"
@click="onSystemUpdate()"
>Update system</v-btn>
<!--
<v-btn color="green darken-1" text @click="dialogSystemUpdate = false">Disagree</v-btn>
<v-btn color="green darken-1" text @click="dialogSystemUpdate = false">Agree</v-btn>
-->
</v-card-actions>
</v-card>
<v-dialog :value="system.updateResult !== null" persistent max-width="400">
<v-card>
<v-card-title class="headline">
update result...
{{ system.updateResult }}
</v-card-title>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn text @click="onUpdateDone()">OK</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-dialog>
</v-card-text>
</v-tab-item>
<v-tab-item>
@ -108,6 +169,7 @@
></v-select>
</v-card-text>
</v-tab-item>
<!--
<v-tab-item>
<v-card-text>
<v-select
@ -130,6 +192,7 @@
></v-text-field>
</v-card-text>
</v-tab-item>
-->
</v-tabs-items>
<v-card-actions>
@ -149,6 +212,7 @@
<script>
import apiDevice from "../api/device";
import weatherFindLocation from "./../components/WeatherFindLocation";
import axios from "axios";
export default {
name: "Settings",
@ -186,7 +250,14 @@ export default {
weatherUnit: [
{ text: "Imperial", value: "" },
{ text: "Metrisch", value: "metric" }
]
],
dialogSystemUpdate: false,
system: {
firmware: null,
updateProgress: 0,
updateResult: null
}
}),
created() {
this.$vuetify.icons.values.tv = {
@ -225,10 +296,28 @@ export default {
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/wb_sunny/baseline.svg"
)
};
this.$vuetify.icons.values.update = {
this.$vuetify.icons.values.system_update = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/update/baseline.svg"
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/system_update_alt/baseline.svg"
)
};
this.$vuetify.icons.values.file = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/attach_file/baseline.svg"
)
};
this.$vuetify.icons.values.warning = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/warning/baseline.svg"
)
};
this.$vuetify.icons.values.clear = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/clear/baseline.svg"
)
};
@ -249,6 +338,49 @@ export default {
this.$router.push("/");
});
},
onSystemUpdate() {
let self = this;
self.system.updateProgress = 0;
const config = {
onUploadProgress: function(progressEvent) {
let percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
self.system.updateProgress = percentCompleted;
}
};
let formData = new FormData();
formData.append("update", this.system.firmware);
axios
.post("/update", formData, config)
.then(response => {
console.log(response.data);
self.system.updateProgress = null;
self.system.updateResult = response.data.success;
})
.catch(response => {
console.log(response);
self.system.updateProgress = null;
self.system.updateResult = false;
});
},
onUpdateDone() {
if (this.system.updateResult === true) {
window.location = "/";
} else {
this.system.firmware = null;
this.system.updateProgress = 0;
this.system.updateResult = null;
}
}
}
};

View File

@ -1,4 +1,5 @@
#include <SPIFFS.h>
#include <Update.h>
#include "app.h"
#include "ESPAsyncWebServer.h"
#include "ArduinoJson.h"
@ -21,8 +22,14 @@ void setupWifiConnect();
void setupCurrentImage();
void setupApiFace();
void setupApiUpdate();
void setupOTA();
//flag to use from web update to update display
bool updateDisplayRequired = false;
//flag to use from web update to reboot the ESP
bool shouldReboot = false;
// bmp
void write16(AsyncResponseStream &f, uint16_t v);
void write32(AsyncResponseStream &f, uint32_t v);
@ -51,6 +58,7 @@ void setupApp()
setupCurrentImage();
setupApiFace();
setupApiUpdate();
setupOTA();
server.onNotFound([](AsyncWebServerRequest *request) {
request->send(404);
@ -102,6 +110,13 @@ void setupApp()
void loopApp()
{
if (shouldReboot)
{
Serial.println("Rebooting...");
delay(100);
ESP.restart();
}
if (updateDisplayRequired)
{
Serial.println("loop app update display");
@ -396,6 +411,58 @@ void setupApiUpdate()
});
}
void setupOTA()
{
// Simple Firmware Update Form
/*
server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request) {
// TODO in die pwa auslagern
request->send(200, "text/html", "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>");
});
*/
server.on(
"/update", HTTP_POST, [](AsyncWebServerRequest *request) {
shouldReboot = !Update.hasError();
AsyncWebServerResponse *response = request->beginResponse(200, "application/ld+json; charset=utf-8", shouldReboot ? "{\"success\": true}" : "{\"success\": false}");
response->addHeader("Connection", "close");
request->send(response);
},
[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
if (!index)
{
Serial.printf("Update Start: %s\n", filename.c_str());
// bool canBegin = Update.begin(contentLength, U_FLASH);
// bool canBegin = Update.begin(contentLength, U_SPIFFS);
if (!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000))
{
Update.printError(Serial);
}
}
if (!Update.hasError())
{
if (Update.write(data, len) != len)
{
Update.printError(Serial);
}
}
if (final)
{
if (Update.end(true))
{
Serial.printf("Update Success: %uB\n", index + len);
}
else
{
Update.printError(Serial);
}
}
});
}
void write16(AsyncResponseStream &f, uint16_t v)
{
f.write(uint8_t(v));