Various changes for 2.5.0-rc3

This commit is contained in:
Gunnar Skjold 2025-11-21 12:17:10 +01:00
parent 9d307e3192
commit 6b6e5ac148
10 changed files with 130 additions and 83 deletions

View File

@ -55,6 +55,17 @@
#define FIRMWARE_CHANNEL_RC 2
#define FIRMWARE_CHANNEL_SNAPSHOT 3
#define REBOOT_CAUSE_WEB_SYSINFO_JSON 1
#define REBOOT_CAUSE_WEB_SAVE 2
#define REBOOT_CAUSE_WEB_REBOOT 3
#define REBOOT_CAUSE_WEB_FACTORY_RESET 4
#define REBOOT_CAUSE_BTN_FACTORY_RESET 5
#define REBOOT_CAUSE_REPARTITION 6
#define REBOOT_CAUSE_CONFIG_FILE_UPDATE 7
#define REBOOT_CAUSE_FIRMWARE_UPDATE 8
#define REBOOT_CAUSE_MQTT_DISCONNECTED 9
#define REBOOT_CAUSE_SMART_CONFIG 10
struct ResetDataContainer {
uint8_t cause;
uint8_t last_cause;
@ -69,7 +80,7 @@ struct SystemConfig {
char country[3];
uint8_t energyspeedometer;
uint8_t firmwareChannel;
}; // 8
}; // 9
struct NetworkConfig {
char ssid[32];
@ -164,7 +175,8 @@ struct GpioConfig {
uint16_t vccResistorVcc;
uint8_t ledDisablePin;
uint8_t ledBehaviour;
}; // 21
uint8_t powersaving;
}; // 22
struct GpioConfig103 {
uint8_t hanPin;

View File

@ -517,6 +517,7 @@ bool AmsConfiguration::getGpioConfig(GpioConfig& config) {
if(configVersion == EEPROM_CHECK_SUM || configVersion == EEPROM_CLEARED_INDICATOR) {
EEPROM.get(CONFIG_GPIO_START, config);
EEPROM.end();
if(config.powersaving > 4) config.powersaving = 0;
return true;
} else {
clearGpio(config);
@ -590,6 +591,7 @@ void AmsConfiguration::clearGpio(GpioConfig& config, bool all) {
config.tempAnalogSensorPin = 0xFF;
config.vccPin = 0xFF;
config.ledDisablePin = 0xFF;
config.powersaving = 0;
if(all) {
config.vccOffset = 0;
@ -1151,7 +1153,8 @@ bool AmsConfiguration::relocateConfig103() {
gpio103.vccResistorGnd,
gpio103.vccResistorVcc,
gpio103.ledDisablePin,
gpio103.ledBehaviour
gpio103.ledBehaviour,
0
};
WebConfig web = {web103.security};
@ -1323,6 +1326,7 @@ void AmsConfiguration::print(Print* debugger)
debugger->printf_P(PSTR("Vcc pin: %i\r\n"), gpio.vccPin);
debugger->printf_P(PSTR("LED disable pin: %i\r\n"), gpio.ledDisablePin);
debugger->printf_P(PSTR("LED behaviour: %i\r\n"), gpio.ledBehaviour);
debugger->printf_P(PSTR("Power saving: %i\r\n"), gpio.powersaving);
if(gpio.vccMultiplier > 0) {
debugger->printf_P(PSTR("Vcc multiplier: %f\r\n"), gpio.vccMultiplier / 1000.0);
}

View File

@ -47,6 +47,7 @@ public:
lwmqtt_err_t lastError();
bool connected();
bool loop();
bool isRebootSuggested();
virtual uint8_t getFormat() { return 0; };
@ -88,6 +89,7 @@ protected:
String subTopic;
AmsFirmwareUpdater* updater = NULL;
bool rebootSuggested = false;
};
#endif

View File

@ -177,7 +177,7 @@ bool AmsMqttHandler::loop() {
if (debugger->isActive(RemoteDebug::WARNING))
#endif
debugger->printf_P(PSTR("MQTT connection lost for over %d minutes, rebooting device\n"), mqttConfig.rebootMinutes);
ESP.restart();
rebootSuggested = true;
}
}
delay(10); // Needed to preserve power. After adding this, the voltage is super smooth on a HAN powered device
@ -188,4 +188,8 @@ bool AmsMqttHandler::loop() {
ESP.wdtFeed();
#endif
return ret;
}
bool AmsMqttHandler::isRebootSuggested() {
return rebootSuggested;
}

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,7 @@
import { sysinfoStore, networksStore } from './DataStores.js';
import fetchWithTimeout from './fetchWithTimeout';
import { translationsStore } from './TranslationService';
import { wiki, ipPattern, asciiPattern, asciiPatternExt, charAndNumPattern, hexPattern, numPattern } from './Helpers.js';
import { wiki, ipPattern, asciiPattern, asciiPatternExt, charAndNumPattern, hexPattern, numPattern, isBusPowered } from './Helpers.js';
import UartSelectOptions from './UartSelectOptions.svelte';
import Mask from './Mask.svelte'
import Badge from './Badge.svelte';
@ -915,6 +915,13 @@
</select>
</div>
{/if}
{#if isBusPowered(sysinfo.board)}
Power saving:
<select name="ip" bind:value={configuration.i.p} class="in-s">
<option value={0}>{translations.conf?.hw?.powersaving?.[0] ?? "Normal"}</option>
<option value={3}>{translations.conf?.hw?.powersaving?.[3] ?? "Extreme (Experimental)"}</option>
</select>
{/if}
{#if sysinfo.chip == 'esp8266'}
<input type="hidden" name="iv" value="true"/>
<div class="my-1 flex flex-wrap">

View File

@ -29,7 +29,7 @@
points.push({
label: realtime.h.u.toFixed(2),
value: realtime.h.u,
title: realtime.h.u.toFixed(2) + ' kWh',
title: (translations.common?.now ?? "Now") + ': ' + realtime.h.u.toFixed(2) + ' kWh',
color: ampcol(realtime.h.u/tariffData.c*100.0)
});
xTicks.push({
@ -40,14 +40,21 @@
if(tariffData && tariffData.p) {
for(i = 0; i < tariffData.p.length; i++) {
let peak = tariffData.p[i];
let daylabel = peak.d > 0 ? zeropad(peak.d) + "." + (translations.months ? translations.months?.[new Date().getMonth()] : zeropad(new Date().getMonth()+1)) : "-";
let title = daylabel;
let title = "";
let daylabel = "-";
if(peak.d > 0) {
daylabel = zeropad(peak.d) + ".";
title = zeropad(peak.d) + "." + (translations.months ? translations.months?.[new Date().getMonth()] : zeropad(new Date().getMonth()+1));
if(tariffData.p.length < 4) {
daylabel = title;
}
}
if(!isNaN(peak.h))
title = title + ' ' + zeropad(peak.h) + ':00';
title = title + ': ' + peak.v.toFixed(2) + ' kWh';
points.push({
label: peak.v.toFixed(2),
title: peak.v.toFixed(2) + ' kWh',
value: peak.v,
title: title,
color: dark ? '#5c2da5' : '#7c3aed'

View File

@ -32,5 +32,6 @@
"g": %d
},
"b": %.1f
}
},
"p": %d
},

View File

@ -516,10 +516,9 @@ void AmsWebServer::sysinfoJson() {
#endif
debugger->printf_P(PSTR("Rebooting\n"));
debugger->flush();
rdc->cause = REBOOT_CAUSE_WEB_SYSINFO_JSON;
delay(1000);
rdc->cause = 1;
ESP.restart();
performRestart = false;
}
}
@ -1080,7 +1079,8 @@ void AmsWebServer::configurationJson() {
gpioConfig->vccMultiplier / 1000.0,
gpioConfig->vccResistorVcc,
gpioConfig->vccResistorGnd,
gpioConfig->vccBootLimit / 10.0
gpioConfig->vccBootLimit / 10.0,
gpioConfig->powersaving
);
server.sendContent(buf);
snprintf_P(buf, BufferSize, CONF_UI_JSON,
@ -1562,6 +1562,11 @@ void AmsWebServer::handleSave() {
config->setGpioConfig(*gpioConfig);
}
if(server.hasArg(F("ip"))) {
gpioConfig->powersaving = server.hasArg(F("ip")) && !server.arg(F("ip")).isEmpty() ? server.arg(F("ip")).toInt() : 0;
config->setGpioConfig(*gpioConfig);
}
if(server.hasArg(F("iv")) && server.arg(F("iv")) == F("true")) {
gpioConfig->vccOffset = server.hasArg(F("ivo")) && !server.arg(F("ivo")).isEmpty() ? server.arg(F("ivo")).toFloat() * 100 : 0;
gpioConfig->vccMultiplier = server.hasArg(F("ivm")) && !server.arg(F("ivm")).isEmpty() ? server.arg(F("ivm")).toFloat() * 1000 : 1000;
@ -1780,9 +1785,8 @@ void AmsWebServer::handleSave() {
#endif
debugger->printf_P(PSTR("Rebooting\n"));
debugger->flush();
rdc->cause = REBOOT_CAUSE_WEB_SAVE;
delay(1000);
rdc->cause = 2;
performRestart = false;
ESP.restart();
}
}
@ -1797,14 +1801,12 @@ void AmsWebServer::reboot() {
delay(250);
#if defined(AMS_REMOTE_DEBUG)
if (debugger->isActive(RemoteDebug::INFO))
#endif
debugger->printf_P(PSTR("Rebooting\n"));
if (debugger->isActive(RemoteDebug::INFO))
#endif
debugger->printf_P(PSTR("Rebooting\n"));
debugger->flush();
delay(1000); rdc->cause = 3;
rdc->cause = 3;
performRestart = false;
rdc->cause = REBOOT_CAUSE_WEB_REBOOT;
delay(1000);
ESP.restart();
}
@ -2064,8 +2066,8 @@ void AmsWebServer::factoryResetPost() {
#endif
debugger->printf_P(PSTR("Rebooting\n"));
debugger->flush();
rdc->cause = REBOOT_CAUSE_WEB_FACTORY_RESET;
delay(1000);
rdc->cause = 5;
ESP.restart();
}

View File

@ -238,14 +238,24 @@ void handleEnergySpeedometer();
#if defined(AMS_CLOUD)
void handleCloud();
#endif
void handleMqtt();
void handleWebserver();
unsigned long handleMqtt();
unsigned long handleWebserver();
void handleSmartConfig();
void handleMeterConfig();
uint8_t pulses = 0;
void onPulse();
bool checkVoltageIfNeeded(float range) {
if(updater.getProgress() > 0) {
return true; // Skip voltage check during firmware update
}
if(gpioConfig.powersaving != 3) {
return true; // Skip voltage check if not in high power saving mode
}
return hw.isVoltageOptimal(range);
}
#if defined(ESP32)
uint8_t dnsState = 0;
ip_addr_t dns0;
@ -361,6 +371,8 @@ void setup() {
if(!hw.ledBlink(LED_RED, 6)) {
hw.ledBlink(LED_INTERNAL, 6);
}
rdc.cause = REBOOT_CAUSE_BTN_FACTORY_RESET;
delay(250);
ESP.restart();
return;
}
@ -451,6 +463,8 @@ void setup() {
}
#if defined(ESP32)
if(updater.relocateOrRepartitionIfNecessary()) {
rdc.cause = REBOOT_CAUSE_REPARTITION;
delay(250);
ESP.restart();
return;
}
@ -506,6 +520,7 @@ void setup() {
configFileParse();
debugI_P(PSTR("Config update complete, restarting"));
Debug.flush();
rdc.cause = REBOOT_CAUSE_CONFIG_FILE_UPDATE;
delay(250);
ESP.restart();
return;
@ -578,7 +593,7 @@ void loop() {
#endif
unsigned long end = millis();
if(end - start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to handle debug"), millis()-start);
debugW_P(PSTR("Used %dms to handle debug"), end-start);
}
handleButton(now);
@ -607,10 +622,8 @@ void loop() {
postConnect();
}
handleUpdater();
// Only do these tasks if we have super-smooth voltage
if(hw.isVoltageOptimal(0.1)) {
if(checkVoltageIfNeeded(0.1)) {
handleNtp();
#if defined(ESP8266)
handleMdns();
@ -631,20 +644,26 @@ void loop() {
debugW_P(PSTR("Vcc below level 1"));
}
unsigned long communicationTime = 0;
// Only do these task if we have smooth voltage
if(hw.isVoltageOptimal(0.2)) {
handleMqtt();
if(checkVoltageIfNeeded(0.2)) {
communicationTime += handleMqtt();
vccLevel2 = true;
} else if(vccLevel2) {
vccLevel2 = false;
debugW_P(PSTR("Vcc below level 2"));
}
handleWebserver();
communicationTime += handleWebserver();
if(communicationTime > 10 && updater.getProgress() >= 0) {
debugI_P(PSTR("Communication is active (%dms), forcing updater to wait"), communicationTime);
} else {
handleUpdater();
}
#if defined(ESP32)
// At this point, if the voltage is not optimal, disconnect from WiFi to preserve power
if(!hw.isVoltageOptimal(0.35)) {
if(!checkVoltageIfNeeded(0.35)) {
if(WiFi.getMode() == WIFI_STA) {
debugW_P(PSTR("Vcc dropped below limit, disconnecting WiFi for 5 seconds to preserve power"));
ch->disconnect(5000);
@ -687,28 +706,6 @@ void loop() {
if(end-start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to handle language update"), end-start);
}
start = millis();
updater.loop();
if(updater.isUpgradeInformationChanged()) {
UpgradeInformation upinfo;
updater.getUpgradeInformation(upinfo);
config.setUpgradeInformation(upinfo);
updater.ackUpgradeInformationChanged();
if(mqttHandler != NULL)
mqttHandler->publishFirmware();
if(upinfo.errorCode == AMS_UPDATE_ERR_SUCCESS_SIGNAL) {
debugW_P(PSTR("Rebooting to firmware version %s"), upinfo.toVersion);
upinfo.errorCode == AMS_UPDATE_ERR_SUCCESS_CONFIRMED;
config.setUpgradeInformation(upinfo);
delay(1000);
ESP.restart();
}
}
end = millis();
if(end-start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to handle firmware updater"), end-start);
}
}
} else {
handleSmartConfig();
@ -726,9 +723,9 @@ void loop() {
if(readHanPort() || now - meterState.getLastUpdateMillis() > 30000) {
end = millis();
if(end - start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to read HAN port (true)"), millis()-start);
debugW_P(PSTR("Used %dms to read HAN port (true)"), end-start);
}
if(hw.isVoltageOptimal(0.1)) {
if(checkVoltageIfNeeded(0.1)) {
handleTemperature(now);
handleSystem(now);
}
@ -736,7 +733,7 @@ void loop() {
} else {
end = millis();
if(end - start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to read HAN port (false)"), millis()-start);
debugW_P(PSTR("Used %dms to read HAN port (false)"), end-start);
}
}
if(millis() - meterState.getLastUpdateMillis() > 1800000 && !ds.isHappy(time(nullptr))) {
@ -781,7 +778,8 @@ void handleUpdater() {
debugW_P(PSTR("Rebooting to firmware version %s"), upinfo.toVersion);
upinfo.errorCode == AMS_UPDATE_ERR_SUCCESS_CONFIRMED;
config.setUpgradeInformation(upinfo);
delay(1000);
rdc.cause = REBOOT_CAUSE_FIRMWARE_UPDATE;
delay(250);
ESP.restart();
}
}
@ -824,7 +822,7 @@ void handleMdns() {
MDNS.update();
unsigned long end = millis();
if(end - start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to update mDNS"), millis()-start);
debugW_P(PSTR("Used %dms to update mDNS"), end-start);
}
}
}
@ -902,7 +900,8 @@ void handleCloud() {
}
#endif
void handleMqtt() {
unsigned long handleMqtt() {
unsigned long start = millis();
if (mqttEnabled || config.isMqttChanged()) {
if(mqttHandler == NULL || !mqttHandler->connected() || config.isMqttChanged()) {
if(mqttHandler != NULL && config.isMqttChanged()) {
@ -916,22 +915,29 @@ void handleMqtt() {
}
if(mqttHandler != NULL) {
unsigned long start = millis();
mqttHandler->loop();
unsigned long end = millis();
if(end - start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to handle mqtt"), millis()-start);
if(mqttHandler->isRebootSuggested()) {
debugW_P(PSTR("Rebooting as suggested by MQTT handler"));
rdc.cause = REBOOT_CAUSE_MQTT_DISCONNECTED;
delay(250);
ESP.restart();
}
}
unsigned long end = millis();
if(end - start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to handle mqtt"), end-start);
}
return end-start;
}
void handleWebserver() {
unsigned long handleWebserver() {
unsigned long start = millis();
ws.loop();
unsigned long end = millis();
if(end - start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to handle web"), millis()-start);
debugW_P(PSTR("Used %dms to handle web"), end-start);
}
return end-start;
}
void handleSmartConfig() {
@ -953,7 +959,8 @@ void handleSmartConfig() {
config.setSystemConfig(sys);
config.save();
delay(1000);
rdc.cause = REBOOT_CAUSE_SMART_CONFIG;
delay(250);
ESP.restart();
}
}
@ -1140,7 +1147,7 @@ void handleSystem(unsigned long now) {
lastSysupdate = now;
end = millis();
if(end - start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to send system update to MQTT"), millis()-start);
debugW_P(PSTR("Used %dms to send system update to MQTT"), end-start);
}
#if defined(ESP32)
@ -1168,7 +1175,7 @@ void handleTemperature(unsigned long now) {
}
end = millis();
if(end - start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to update temperature"), millis()-start);
debugW_P(PSTR("Used %dms to update temperature"), end-start);
}
}
}
@ -1181,19 +1188,19 @@ void handlePriceService(unsigned long now) {
if(ps->loop() && mqttHandler != NULL) {
end = millis();
if(end - start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to update prices"), millis()-start);
debugW_P(PSTR("Used %dms to update prices"), end-start);
}
start = millis();
mqttHandler->publishPrices(ps);
end = millis();
if(end - start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to publish prices to MQTT"), millis()-start);
debugW_P(PSTR("Used %dms to publish prices to MQTT"), end-start);
}
} else {
end = millis();
if(end - start > SLOW_PROC_TRIGGER_MS) {
debugW_P(PSTR("Used %dms to handle price API"), millis()-start);
debugW_P(PSTR("Used %dms to handle price API"), end-start);
}
}
}
@ -1294,7 +1301,7 @@ void connectToNetwork() {
return;
}
lastConnectRetry = millis();
if(!hw.isVoltageOptimal(0.1) && (millis() - lastConnectRetry) < 60000) {
if(!checkVoltageIfNeeded(0.1) && (millis() - lastConnectRetry) < 60000) {
debugW_P(PSTR("Voltage is not high enough to reconnect"));
return;
}
@ -1448,7 +1455,7 @@ void handleDataSuccess(AmsData* data) {
if(!setupMode && !hw.ledBlink(LED_GREEN, 1))
hw.ledBlink(LED_INTERNAL, 1);
if(mqttHandler != NULL && hw.isVoltageOptimal(0.2)) {
if(mqttHandler != NULL && checkVoltageIfNeeded(0.2)) {
#if defined(ESP32)
esp_task_wdt_reset();
#elif defined(ESP8266)
@ -1458,7 +1465,7 @@ void handleDataSuccess(AmsData* data) {
mqttHandler->publish(data, &meterState, &ea, ps);
}
#if defined(ESP32) && defined(ENERGY_SPEEDOMETER_PASS)
if(energySpeedometer != NULL && hw.isVoltageOptimal(0.1)) {
if(energySpeedometer != NULL && checkVoltageIfNeeded(0.1)) {
energySpeedometer->publish(&meterState, &meterState, &ea, ps);
}
#endif