mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-01-14 15:54:47 +00:00
Improved firmware upgrade
This commit is contained in:
parent
9c8788225d
commit
be116d5b35
@ -11,6 +11,7 @@
|
||||
|
||||
#define CONFIG_SYSTEM_START 8
|
||||
#define CONFIG_METER_START 32
|
||||
#define CONFIG_UPGRADE_INFO_START 216
|
||||
#define CONFIG_UI_START 248
|
||||
#define CONFIG_GPIO_START 266
|
||||
#define CONFIG_ENTSOE_START 290
|
||||
@ -213,6 +214,13 @@ struct TempSensorConfig {
|
||||
bool common;
|
||||
};
|
||||
|
||||
struct UpgradeInformation {
|
||||
char fromVersion[8];
|
||||
char toVersion[8];
|
||||
int16_t exitCode;
|
||||
int16_t errorCode;
|
||||
}; // 20
|
||||
|
||||
class AmsConfiguration {
|
||||
public:
|
||||
bool hasConfig();
|
||||
@ -297,6 +305,10 @@ public:
|
||||
|
||||
bool isSensorAddressEqual(uint8_t a[8], uint8_t b[8]);
|
||||
|
||||
bool getUpgradeInformation(UpgradeInformation&);
|
||||
bool setUpgradeInformation(int16_t exitCode, int16_t errorCode, const char* currentVersion, const char* nextVersion);
|
||||
void clearUpgradeInformation(UpgradeInformation&);
|
||||
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
|
||||
@ -7,6 +7,6 @@
|
||||
String toHex(uint8_t* in);
|
||||
String toHex(uint8_t* in, uint16_t size);
|
||||
void fromHex(uint8_t *out, String in, uint16_t size);
|
||||
void stripNonAscii(uint8_t* in, uint16_t size, bool extended = false);
|
||||
bool stripNonAscii(uint8_t* in, uint16_t size, bool extended = false);
|
||||
|
||||
#endif
|
||||
@ -679,6 +679,45 @@ void AmsConfiguration::clearUiConfig(UiConfig& config) {
|
||||
config.showTemperaturePlot = 2;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::setUpgradeInformation(int16_t exitCode, int16_t errorCode, const char* currentVersion, const char* nextVersion) {
|
||||
UpgradeInformation upinfo;
|
||||
upinfo.exitCode = exitCode;
|
||||
upinfo.errorCode = errorCode;
|
||||
strcpy(upinfo.fromVersion, currentVersion);
|
||||
strcpy(upinfo.toVersion, nextVersion);
|
||||
|
||||
stripNonAscii((uint8_t*) upinfo.fromVersion, 8);
|
||||
stripNonAscii((uint8_t*) upinfo.toVersion, 8);
|
||||
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.put(CONFIG_UPGRADE_INFO_START, upinfo);
|
||||
bool ret = EEPROM.commit();
|
||||
EEPROM.end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::getUpgradeInformation(UpgradeInformation& upinfo) {
|
||||
if(hasConfig()) {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(CONFIG_UPGRADE_INFO_START, upinfo);
|
||||
EEPROM.end();
|
||||
if(stripNonAscii((uint8_t*) upinfo.fromVersion, 8) || stripNonAscii((uint8_t*) upinfo.toVersion, 8)) {
|
||||
clearUpgradeInformation(upinfo);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
clearUpgradeInformation(upinfo);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AmsConfiguration::clearUpgradeInformation(UpgradeInformation& upinfo) {
|
||||
upinfo.exitCode = -1;
|
||||
upinfo.errorCode = 0;
|
||||
memset(upinfo.fromVersion, 0, 8);
|
||||
memset(upinfo.toVersion, 0, 8);
|
||||
}
|
||||
|
||||
|
||||
void AmsConfiguration::clear() {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
@ -734,6 +773,10 @@ void AmsConfiguration::clear() {
|
||||
clearUiConfig(ui);
|
||||
EEPROM.put(CONFIG_UI_START, ui);
|
||||
|
||||
UpgradeInformation upinfo;
|
||||
clearUpgradeInformation(upinfo);
|
||||
EEPROM.put(CONFIG_UPGRADE_INFO_START, upinfo);
|
||||
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, EEPROM_CLEARED_INDICATOR);
|
||||
EEPROM.commit();
|
||||
EEPROM.end();
|
||||
|
||||
@ -22,7 +22,8 @@ void fromHex(uint8_t *out, String in, uint16_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
void stripNonAscii(uint8_t* in, uint16_t size, bool extended) {
|
||||
bool stripNonAscii(uint8_t* in, uint16_t size, bool extended) {
|
||||
bool ret = false;
|
||||
for(uint16_t i = 0; i < size; i++) {
|
||||
if(in[i] == 0) { // Clear the rest with null-terminator
|
||||
memset(in+i, 0, size-i);
|
||||
@ -30,9 +31,12 @@ void stripNonAscii(uint8_t* in, uint16_t size, bool extended) {
|
||||
}
|
||||
if(extended && (in[i] < 32 || in[i] == 127 || in[i] == 129 || in[i] == 141 || in[i] == 143 || in[i] == 144 || in[i] == 157)) {
|
||||
memset(in+i, ' ', 1);
|
||||
ret = true;
|
||||
} else if(in[i] < 32 || in[i] > 126) {
|
||||
memset(in+i, ' ', 1);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
memset(in+size-1, 0, 1); // Make sure the last character is null-terminator
|
||||
return ret;
|
||||
}
|
||||
18
lib/SvelteUi/app/dist/index.js
vendored
18
lib/SvelteUi/app/dist/index.js
vendored
File diff suppressed because one or more lines are too long
@ -26,6 +26,13 @@ let sysinfo = {
|
||||
upgrading: false,
|
||||
ui: {},
|
||||
security: 0,
|
||||
boot_reason: 0,
|
||||
upgrade: {
|
||||
x: -1,
|
||||
e: 0,
|
||||
f: null,
|
||||
t: null
|
||||
},
|
||||
trying: null
|
||||
};
|
||||
export const sysinfoStore = writable(sysinfo);
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
s.upgrading = true;
|
||||
return s;
|
||||
});
|
||||
upgrade(nextVersion);
|
||||
upgrade(nextVersion.tag_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,6 +155,11 @@
|
||||
<div class="my-2">
|
||||
Installed version: {sysinfo.version}
|
||||
</div>
|
||||
{#if sysinfo.upgrade.t && sysinfo.upgrade.t != sysinfo.version}
|
||||
<div class="my-2">
|
||||
<div class="bd-yellow">Previous upgrade attempt ({sysinfo.upgrade.t}) does not match current version ({sysinfo.version}) [{sysinfo.upgrade.x}/{sysinfo.upgrade.e}]</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if nextVersion}
|
||||
<div class="my-2 flex">
|
||||
Latest version:
|
||||
|
||||
@ -2,8 +2,8 @@ export function upgradeWarningText(board) {
|
||||
return 'WARNING: ' + board + ' must be connected to an external power supply during firmware upgrade. Failure to do so may cause power-down during upload resulting in non-functioning unit.'
|
||||
}
|
||||
|
||||
export async function upgrade() {
|
||||
const response = await fetch('/upgrade', {
|
||||
export async function upgrade(expected_version) {
|
||||
const response = await fetch('/upgrade?expected_version='+expected_version, {
|
||||
method: 'POST'
|
||||
});
|
||||
await response.json();
|
||||
|
||||
@ -17,18 +17,18 @@ export default defineConfig({
|
||||
plugins: [svelte()],
|
||||
server: {
|
||||
proxy: {
|
||||
"/data.json": "http://192.168.233.235",
|
||||
"/energyprice.json": "http://192.168.233.235",
|
||||
"/dayplot.json": "http://192.168.233.235",
|
||||
"/monthplot.json": "http://192.168.233.235",
|
||||
"/temperature.json": "http://192.168.233.235",
|
||||
"/sysinfo.json": "http://192.168.233.235",
|
||||
"/configuration.json": "http://192.168.233.235",
|
||||
"/tariff.json": "http://192.168.233.235",
|
||||
"/save": "http://192.168.233.235",
|
||||
"/reboot": "http://192.168.233.235",
|
||||
"/configfile": "http://192.168.233.235",
|
||||
"/upgrade": "http://192.168.233.235"
|
||||
"/data.json": "http://192.168.233.244",
|
||||
"/energyprice.json": "http://192.168.233.244",
|
||||
"/dayplot.json": "http://192.168.233.244",
|
||||
"/monthplot.json": "http://192.168.233.244",
|
||||
"/temperature.json": "http://192.168.233.244",
|
||||
"/sysinfo.json": "http://192.168.233.244",
|
||||
"/configuration.json": "http://192.168.233.244",
|
||||
"/tariff.json": "http://192.168.233.244",
|
||||
"/save": "http://192.168.233.244",
|
||||
"/reboot": "http://192.168.233.244",
|
||||
"/configfile": "http://192.168.233.244",
|
||||
"/upgrade": "http://192.168.233.244"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -97,6 +97,7 @@ private:
|
||||
void handleSave();
|
||||
void reboot();
|
||||
void upgrade();
|
||||
void upgradeFromUrl(String url, String nextVersion);
|
||||
void firmwareHtml();
|
||||
void firmwarePost();
|
||||
void firmwareUpload();
|
||||
|
||||
@ -37,5 +37,11 @@
|
||||
"s": %d
|
||||
},
|
||||
"security": %d,
|
||||
"boot_reason": %d
|
||||
"boot_reason": %d,
|
||||
"upgrade": {
|
||||
"x": %d,
|
||||
"e": %d,
|
||||
"f": "%s",
|
||||
"t": "%s"
|
||||
}
|
||||
}
|
||||
@ -254,6 +254,9 @@ void AmsWebServer::sysinfoJson() {
|
||||
UiConfig ui;
|
||||
config->getUiConfig(ui);
|
||||
|
||||
UpgradeInformation upinfo;
|
||||
config->getUpgradeInformation(upinfo);
|
||||
|
||||
String meterModel = meterState->getMeterModel();
|
||||
if(!meterModel.isEmpty())
|
||||
meterModel.replace("\\", "\\\\");
|
||||
@ -314,10 +317,14 @@ void AmsWebServer::sysinfoJson() {
|
||||
ui.showTemperaturePlot,
|
||||
webConfig.security,
|
||||
#if defined(ESP32)
|
||||
rtc_get_reset_reason(0)
|
||||
rtc_get_reset_reason(0),
|
||||
#else
|
||||
ESP.getResetInfoPtr()->reason
|
||||
ESP.getResetInfoPtr()->reason,
|
||||
#endif
|
||||
upinfo.exitCode,
|
||||
upinfo.errorCode,
|
||||
upinfo.fromVersion,
|
||||
upinfo.toVersion
|
||||
);
|
||||
|
||||
stripNonAscii((uint8_t*) buf, size+1);
|
||||
@ -1542,44 +1549,61 @@ void AmsWebServer::upgrade() {
|
||||
if(server.hasArg(F("version"))) {
|
||||
url += "/" + server.arg(F("version"));
|
||||
}
|
||||
|
||||
WiFiClient client;
|
||||
#if defined(ESP8266)
|
||||
String chipType = F("esp8266");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
String chipType = F("esp32s2");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
String chipType = F("esp32c3");
|
||||
#elif defined(ESP32)
|
||||
#if defined(CONFIG_FREERTOS_UNICORE)
|
||||
String chipType = F("esp32solo");
|
||||
#else
|
||||
String chipType = F("esp32");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
ESPhttpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
t_httpUpdate_return ret = ESPhttpUpdate.update(client, url, VERSION);
|
||||
#elif defined(ESP32)
|
||||
HTTPUpdate httpUpdate;
|
||||
httpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
HTTPUpdateResult ret = httpUpdate.update(client, url, String(VERSION) + "-" + chipType);
|
||||
#endif
|
||||
|
||||
switch(ret) {
|
||||
case HTTP_UPDATE_FAILED:
|
||||
debugger->printf(PSTR("Update failed"));
|
||||
break;
|
||||
case HTTP_UPDATE_NO_UPDATES:
|
||||
debugger->printf(PSTR("No Update"));
|
||||
break;
|
||||
case HTTP_UPDATE_OK:
|
||||
debugger->printf(PSTR("Update OK"));
|
||||
break;
|
||||
}
|
||||
upgradeFromUrl(url, server.arg(F("expected_version")));
|
||||
}
|
||||
}
|
||||
|
||||
void AmsWebServer::upgradeFromUrl(String url, String nextVersion) {
|
||||
config->setUpgradeInformation(0xFF, 0xFF, VERSION, nextVersion.c_str());
|
||||
|
||||
WiFiClient client;
|
||||
#if defined(ESP8266)
|
||||
String chipType = F("esp8266");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
String chipType = F("esp32s2");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
String chipType = F("esp32c3");
|
||||
#elif defined(ESP32)
|
||||
#if defined(CONFIG_FREERTOS_UNICORE)
|
||||
String chipType = F("esp32solo");
|
||||
#else
|
||||
String chipType = F("esp32");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
ESP8266HTTPUpdate httpUpdate = ESP8266HTTPUpdate(60000);
|
||||
String currentVersion = VERSION;
|
||||
#elif defined(ESP32)
|
||||
HTTPUpdate httpUpdate = HTTPUpdate(60000);
|
||||
String currentVersion = String(VERSION) + "-" + chipType;
|
||||
#endif
|
||||
|
||||
httpUpdate.rebootOnUpdate(false);
|
||||
httpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
HTTPUpdateResult ret = httpUpdate.update(client, url, currentVersion);
|
||||
int lastError = httpUpdate.getLastError();
|
||||
|
||||
config->setUpgradeInformation(ret, ret == HTTP_UPDATE_OK ? 0 : lastError, VERSION, nextVersion.c_str());
|
||||
switch(ret) {
|
||||
case HTTP_UPDATE_FAILED:
|
||||
debugger->printf(PSTR("Update failed\n"));
|
||||
break;
|
||||
case HTTP_UPDATE_NO_UPDATES:
|
||||
debugger->printf(PSTR("No Update\n"));
|
||||
break;
|
||||
case HTTP_UPDATE_OK:
|
||||
debugger->printf(PSTR("Update OK\n"));
|
||||
debugger->flush();
|
||||
#if defined(ESP8266)
|
||||
ESP.reset();
|
||||
#elif defined(ESP32)
|
||||
ESP.restart();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AmsWebServer::firmwareHtml() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Serving /firmware.html over http..."));
|
||||
|
||||
@ -1607,41 +1631,7 @@ void AmsWebServer::firmwarePost() {
|
||||
if(!url.isEmpty() && (url.startsWith(F("http://")) || url.startsWith(F("https://")))) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Custom firmware URL was provided"));
|
||||
|
||||
WiFiClient client;
|
||||
#if defined(ESP8266)
|
||||
String chipType = F("esp8266");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
String chipType = F("esp32s2");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
String chipType = F("esp32c3");
|
||||
#elif defined(ESP32)
|
||||
#if defined(CONFIG_FREERTOS_UNICORE)
|
||||
String chipType = F("esp32solo");
|
||||
#else
|
||||
String chipType = F("esp32");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
ESPhttpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
t_httpUpdate_return ret = ESPhttpUpdate.update(client, url, VERSION);
|
||||
#elif defined(ESP32)
|
||||
HTTPUpdate httpUpdate;
|
||||
httpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
HTTPUpdateResult ret = httpUpdate.update(client, url, String(VERSION) + "-" + chipType);
|
||||
#endif
|
||||
|
||||
switch(ret) {
|
||||
case HTTP_UPDATE_FAILED:
|
||||
debugger->printf(PSTR("Update failed"));
|
||||
break;
|
||||
case HTTP_UPDATE_NO_UPDATES:
|
||||
debugger->printf(PSTR("No Update"));
|
||||
break;
|
||||
case HTTP_UPDATE_OK:
|
||||
debugger->printf(PSTR("Update OK"));
|
||||
break;
|
||||
}
|
||||
upgradeFromUrl(url, "");
|
||||
server.send(200, MIME_PLAIN, "OK");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ ADC_MODE(ADC_VCC);
|
||||
#if defined(ESP32)
|
||||
#include <esp_task_wdt.h>
|
||||
#endif
|
||||
#define WDT_TIMEOUT 60
|
||||
#define WDT_TIMEOUT 90
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#include <driver/uart.h>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user