mirror of
https://github.com/paperdash/device-epd.git
synced 2024-11-10 07:10:32 +00:00
#13 basic working version of OTA
This commit is contained in:
parent
94a53071a7
commit
93ed45f572
@ -22,10 +22,12 @@
|
|||||||
Weather
|
Weather
|
||||||
<v-icon>$wb_sunny</v-icon>
|
<v-icon>$wb_sunny</v-icon>
|
||||||
</v-tab>
|
</v-tab>
|
||||||
|
<!--
|
||||||
<v-tab>
|
<v-tab>
|
||||||
Cloud
|
Cloud
|
||||||
<v-icon>$cloud</v-icon>
|
<v-icon>$cloud</v-icon>
|
||||||
</v-tab>
|
</v-tab>
|
||||||
|
-->
|
||||||
</v-tabs>
|
</v-tabs>
|
||||||
|
|
||||||
<v-card v-if="settings" class="mx-auto" width="400">
|
<v-card v-if="settings" class="mx-auto" width="400">
|
||||||
@ -45,6 +47,65 @@
|
|||||||
label="i8n:Theme"
|
label="i8n:Theme"
|
||||||
placeholder
|
placeholder
|
||||||
></v-select>
|
></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-card-text>
|
||||||
</v-tab-item>
|
</v-tab-item>
|
||||||
<v-tab-item>
|
<v-tab-item>
|
||||||
@ -108,6 +169,7 @@
|
|||||||
></v-select>
|
></v-select>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-tab-item>
|
</v-tab-item>
|
||||||
|
<!--
|
||||||
<v-tab-item>
|
<v-tab-item>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-select
|
<v-select
|
||||||
@ -130,6 +192,7 @@
|
|||||||
></v-text-field>
|
></v-text-field>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-tab-item>
|
</v-tab-item>
|
||||||
|
-->
|
||||||
</v-tabs-items>
|
</v-tabs-items>
|
||||||
|
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
@ -149,6 +212,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import apiDevice from "../api/device";
|
import apiDevice from "../api/device";
|
||||||
import weatherFindLocation from "./../components/WeatherFindLocation";
|
import weatherFindLocation from "./../components/WeatherFindLocation";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Settings",
|
name: "Settings",
|
||||||
@ -186,7 +250,14 @@ export default {
|
|||||||
weatherUnit: [
|
weatherUnit: [
|
||||||
{ text: "Imperial", value: "" },
|
{ text: "Imperial", value: "" },
|
||||||
{ text: "Metrisch", value: "metric" }
|
{ text: "Metrisch", value: "metric" }
|
||||||
]
|
],
|
||||||
|
|
||||||
|
dialogSystemUpdate: false,
|
||||||
|
system: {
|
||||||
|
firmware: null,
|
||||||
|
updateProgress: 0,
|
||||||
|
updateResult: null
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
created() {
|
created() {
|
||||||
this.$vuetify.icons.values.tv = {
|
this.$vuetify.icons.values.tv = {
|
||||||
@ -225,10 +296,28 @@ export default {
|
|||||||
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/wb_sunny/baseline.svg"
|
/* 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: () =>
|
component: () =>
|
||||||
import(
|
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("/");
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
67
src/app.cpp
67
src/app.cpp
@ -1,4 +1,5 @@
|
|||||||
#include <SPIFFS.h>
|
#include <SPIFFS.h>
|
||||||
|
#include <Update.h>
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include "ESPAsyncWebServer.h"
|
#include "ESPAsyncWebServer.h"
|
||||||
#include "ArduinoJson.h"
|
#include "ArduinoJson.h"
|
||||||
@ -21,8 +22,14 @@ void setupWifiConnect();
|
|||||||
void setupCurrentImage();
|
void setupCurrentImage();
|
||||||
void setupApiFace();
|
void setupApiFace();
|
||||||
void setupApiUpdate();
|
void setupApiUpdate();
|
||||||
|
void setupOTA();
|
||||||
|
|
||||||
|
//flag to use from web update to update display
|
||||||
bool updateDisplayRequired = false;
|
bool updateDisplayRequired = false;
|
||||||
|
|
||||||
|
//flag to use from web update to reboot the ESP
|
||||||
|
bool shouldReboot = false;
|
||||||
|
|
||||||
// bmp
|
// bmp
|
||||||
void write16(AsyncResponseStream &f, uint16_t v);
|
void write16(AsyncResponseStream &f, uint16_t v);
|
||||||
void write32(AsyncResponseStream &f, uint32_t v);
|
void write32(AsyncResponseStream &f, uint32_t v);
|
||||||
@ -51,6 +58,7 @@ void setupApp()
|
|||||||
setupCurrentImage();
|
setupCurrentImage();
|
||||||
setupApiFace();
|
setupApiFace();
|
||||||
setupApiUpdate();
|
setupApiUpdate();
|
||||||
|
setupOTA();
|
||||||
|
|
||||||
server.onNotFound([](AsyncWebServerRequest *request) {
|
server.onNotFound([](AsyncWebServerRequest *request) {
|
||||||
request->send(404);
|
request->send(404);
|
||||||
@ -102,6 +110,13 @@ void setupApp()
|
|||||||
|
|
||||||
void loopApp()
|
void loopApp()
|
||||||
{
|
{
|
||||||
|
if (shouldReboot)
|
||||||
|
{
|
||||||
|
Serial.println("Rebooting...");
|
||||||
|
delay(100);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
|
||||||
if (updateDisplayRequired)
|
if (updateDisplayRequired)
|
||||||
{
|
{
|
||||||
Serial.println("loop app update display");
|
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)
|
void write16(AsyncResponseStream &f, uint16_t v)
|
||||||
{
|
{
|
||||||
f.write(uint8_t(v));
|
f.write(uint8_t(v));
|
||||||
|
Loading…
Reference in New Issue
Block a user