mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-03-17 23:43:16 +00:00
Compare commits
8 Commits
v2.5.5
...
fix/amn550
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6af74d919 | ||
|
|
0b4884652f | ||
|
|
82aeae8699 | ||
|
|
a7333653b0 | ||
|
|
24e63d5e32 | ||
|
|
eb7c266378 | ||
|
|
cf8c48ab99 | ||
|
|
78a1cd78ea |
@@ -591,7 +591,6 @@ void AmsConfiguration::clearGpio(GpioConfig& config, bool all) {
|
||||
config.tempAnalogSensorPin = 0xFF;
|
||||
config.vccPin = 0xFF;
|
||||
config.ledDisablePin = 0xFF;
|
||||
config.powersaving = 0;
|
||||
|
||||
if(all) {
|
||||
config.vccOffset = 0;
|
||||
@@ -600,6 +599,7 @@ void AmsConfiguration::clearGpio(GpioConfig& config, bool all) {
|
||||
config.vccResistorGnd = 0;
|
||||
config.vccResistorVcc = 0;
|
||||
config.ledBehaviour = LED_BEHAVIOUR_DEFAULT;
|
||||
config.powersaving = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#define AMS_UPDATE_ERR_SUCCESS_CONFIRMED 123
|
||||
|
||||
#define UPDATE_BUF_SIZE 4096
|
||||
#define UPDATE_MAX_BLOCK_RETRY 25
|
||||
#define UPDATE_MAX_REBOOT_RETRY 12
|
||||
|
||||
class AmsFirmwareUpdater {
|
||||
public:
|
||||
|
||||
@@ -74,7 +74,7 @@ void AmsFirmwareUpdater::setUpgradeInformation(UpgradeInformation& upinfo) {
|
||||
#endif
|
||||
debugger->printf_P(PSTR("Resuming uprade to %s\n"), updateStatus.toVersion);
|
||||
|
||||
if(updateStatus.reboot_count++ < 8) {
|
||||
if(updateStatus.reboot_count++ < UPDATE_MAX_REBOOT_RETRY) {
|
||||
updateStatus.errorCode = AMS_UPDATE_ERR_OK;
|
||||
} else {
|
||||
updateStatus.errorCode = AMS_UPDATE_ERR_REBOOT;
|
||||
@@ -129,7 +129,7 @@ void AmsFirmwareUpdater::loop() {
|
||||
HTTPClient http;
|
||||
start = millis();
|
||||
if(!fetchFirmwareChunk(http)) {
|
||||
if(updateStatus.retry_count++ == 3) {
|
||||
if(updateStatus.retry_count++ > UPDATE_MAX_BLOCK_RETRY) {
|
||||
updateStatus.errorCode = AMS_UPDATE_ERR_FETCH;
|
||||
updateStatusChanged = true;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name" : "%s%s",
|
||||
"stat_t" : "%s%s",
|
||||
"uniq_id" : "%s_%s",
|
||||
"obj_id" : "%s_%s",
|
||||
"default_entity_id" : "sensor.%s_%s",
|
||||
"val_tpl" : "{{ value_json.%s | is_defined }}",
|
||||
"expire_after" : %d,
|
||||
"dev" : {
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
bool applyBoardConfig(uint8_t boardType, GpioConfig& gpioConfig, MeterConfig& meterConfig, uint8_t hanPin);
|
||||
void setup(SystemConfig* sys, GpioConfig* gpio);
|
||||
float getVcc();
|
||||
void setMaxVcc(float maxVcc);
|
||||
uint8_t getTempSensorCount();
|
||||
TempSensorData* getTempSensorData(uint8_t);
|
||||
bool updateTemperatures();
|
||||
@@ -68,7 +69,7 @@ private:
|
||||
uint8_t vccPin, vccGnd_r, vccVcc_r;
|
||||
float vccOffset, vccMultiplier;
|
||||
float vcc = 3.3; // Last known Vcc
|
||||
float maxVcc = 3.25; // Best to have this close to max as a start, in case Pow-U reboots and starts off with a low voltage, we dont want that to be perceived as max
|
||||
float maxVcc = 3.28; // Best to have this close to max as a start, in case Pow-U reboots and starts off with a low voltage, we dont want that to be perceived as max
|
||||
unsigned long lastVccRead = 0;
|
||||
|
||||
uint16_t analogRange = 1024;
|
||||
|
||||
@@ -677,4 +677,8 @@ bool HwTools::isVoltageOptimal(float range) {
|
||||
|
||||
uint8_t HwTools::getBoardType() {
|
||||
return boardType;
|
||||
}
|
||||
|
||||
void HwTools::setMaxVcc(float vcc) {
|
||||
this->maxVcc = min(3.3f, vcc);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
2
lib/SvelteUi/app/dist/index.js
vendored
2
lib/SvelteUi/app/dist/index.js
vendored
File diff suppressed because one or more lines are too long
@@ -130,7 +130,7 @@ export function uiVisibility(choice, state) {
|
||||
}
|
||||
|
||||
export function wiki(page) {
|
||||
let ret = "https://wiki.amsleser.no/";
|
||||
let ret = "https://wiki.amsleser.no";
|
||||
if(page) {
|
||||
ret += "/en/firmware#" + page;
|
||||
}
|
||||
|
||||
@@ -1389,10 +1389,10 @@ void AmsWebServer::handleSave() {
|
||||
memset(meterConfig.authenticationKey, 0, 16);
|
||||
}
|
||||
|
||||
meterConfig.wattageMultiplier = server.arg(F("mmw")).toFloat() * 1000;
|
||||
meterConfig.voltageMultiplier = server.arg(F("mmv")).toFloat() * 1000;
|
||||
meterConfig.amperageMultiplier = server.arg(F("mma")).toFloat() * 1000;
|
||||
meterConfig.accumulatedMultiplier = server.arg(F("mmc")).toFloat() * 1000;
|
||||
meterConfig.wattageMultiplier = server.arg(F("mmw")).toDouble() * 1000.0;
|
||||
meterConfig.voltageMultiplier = server.arg(F("mmv")).toDouble() * 1000.0;
|
||||
meterConfig.amperageMultiplier = server.arg(F("mma")).toDouble() * 1000.0;
|
||||
meterConfig.accumulatedMultiplier = server.arg(F("mmc")).toDouble() * 1000.0;
|
||||
config->setMeterConfig(meterConfig);
|
||||
}
|
||||
|
||||
@@ -1408,7 +1408,7 @@ void AmsWebServer::handleSave() {
|
||||
if(!psk.equals("***")) {
|
||||
strcpy(network.psk, psk.c_str());
|
||||
}
|
||||
network.power = server.arg(F("ww")).toFloat() * 10;
|
||||
network.power = server.arg(F("ww")).toDouble() * 10.0;
|
||||
network.sleep = server.arg(F("wz")).toInt();
|
||||
network.use11b = server.hasArg(F("wb")) && server.arg(F("wb")) == F("true");
|
||||
}
|
||||
@@ -1569,9 +1569,9 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
|
||||
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;
|
||||
gpioConfig->vccBootLimit = server.hasArg(F("ivb")) && !server.arg(F("ivb")).isEmpty() ? server.arg(F("ivb")).toFloat() * 10 : 0;
|
||||
gpioConfig->vccOffset = server.hasArg(F("ivo")) && !server.arg(F("ivo")).isEmpty() ? server.arg(F("ivo")).toDouble() * 100.0 : 0;
|
||||
gpioConfig->vccMultiplier = server.hasArg(F("ivm")) && !server.arg(F("ivm")).isEmpty() ? server.arg(F("ivm")).toDouble() * 1000.0 : 1000;
|
||||
gpioConfig->vccBootLimit = server.hasArg(F("ivb")) && !server.arg(F("ivb")).isEmpty() ? server.arg(F("ivb")).toDouble() * 10.0 : 0;
|
||||
config->setGpioConfig(*gpioConfig);
|
||||
}
|
||||
|
||||
@@ -1686,7 +1686,7 @@ void AmsWebServer::handleSave() {
|
||||
snprintf_P(buf, BufferSize, PSTR("rd%d"), i);
|
||||
pc.direction = server.arg(buf).toInt();
|
||||
snprintf_P(buf, BufferSize, PSTR("rv%d"), i);
|
||||
pc.value = server.arg(buf).toFloat() * 10000;
|
||||
pc.value = server.arg(buf).toDouble() * 10000.0;
|
||||
snprintf_P(buf, BufferSize, PSTR("rn%d"), i);
|
||||
String name = server.arg(buf);
|
||||
strcpy(pc.name, name.c_str());
|
||||
|
||||
@@ -190,10 +190,15 @@ CloudConnector *cloud = NULL;
|
||||
#if defined(ZMART_CHARGE)
|
||||
ZmartChargeCloudConnector *zcloud = NULL;
|
||||
#endif
|
||||
|
||||
#define MAX_BOOT_CYCLES 6
|
||||
|
||||
#if defined(ESP32)
|
||||
__NOINIT_ATTR EnergyAccountingRealtimeData rtd;
|
||||
RTC_DATA_ATTR uint8_t bootcount = 0;
|
||||
#else
|
||||
EnergyAccountingRealtimeData rtd;
|
||||
uint32_t bootcount = 0;
|
||||
#endif
|
||||
EnergyAccounting ea(&Debug, &rtd);
|
||||
|
||||
@@ -326,6 +331,31 @@ void rxerr(int err) {
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t incrementBootCycleCounter(bool deepSleep) {
|
||||
#if defined(ESP8266)
|
||||
if(deepSleep) {
|
||||
if(ESP.rtcUserMemoryRead(0, &bootcount, sizeof(bootcount))) {
|
||||
bootcount++;
|
||||
ESP.rtcUserMemoryWrite(0, &bootcount, sizeof(bootcount));
|
||||
}
|
||||
return bootcount;
|
||||
} else {
|
||||
return ++bootcount;
|
||||
}
|
||||
#else
|
||||
return ++bootcount;
|
||||
#endif
|
||||
}
|
||||
void resetBootCycleCounter(bool deepSleep) {
|
||||
#if defined(ESP8266)
|
||||
bootcount = 0;
|
||||
if(deepSleep) {
|
||||
ESP.rtcUserMemoryWrite(0, &bootcount, sizeof(bootcount));
|
||||
}
|
||||
#else
|
||||
bootcount = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
@@ -380,20 +410,6 @@ void setup() {
|
||||
}
|
||||
}
|
||||
|
||||
hw.ledBlink(LED_INTERNAL, 1);
|
||||
hw.ledBlink(LED_RED, 1);
|
||||
hw.ledBlink(LED_YELLOW, 1);
|
||||
hw.ledBlink(LED_GREEN, 1);
|
||||
hw.ledBlink(LED_BLUE, 1);
|
||||
|
||||
PriceServiceConfig price;
|
||||
if(config.getPriceServiceConfig(price)) {
|
||||
ps = new PriceService(&Debug);
|
||||
ps->setup(price);
|
||||
ws.setPriceService(ps);
|
||||
}
|
||||
ws.setPriceSettings(price.area, price.currency);
|
||||
ea.setCurrency(price.currency);
|
||||
bool shared = false;
|
||||
Serial.flush();
|
||||
Serial.end();
|
||||
@@ -441,22 +457,51 @@ void setup() {
|
||||
yield();
|
||||
#endif
|
||||
|
||||
float vcc = hw.getVcc();
|
||||
|
||||
if(!hw.ledOn(LED_YELLOW)) {
|
||||
hw.ledOn(LED_INTERNAL);
|
||||
}
|
||||
debugI_P(PSTR("AMS reader %s started"), FirmwareVersion::VersionString);
|
||||
debugI_P(PSTR("Configuration version: %d, board type: %d"), config.getConfigVersion(), sysConfig.boardType);
|
||||
float vcc = hw.getVcc();
|
||||
debugI_P(PSTR("Voltage: %.2fV"), vcc);
|
||||
|
||||
float vccBootLimit = gpioConfig.vccBootLimit == 0 ? 0 : min(3.29, gpioConfig.vccBootLimit / 10.0); // Make sure it is never above 3.3v
|
||||
if(vcc > 2.5 && vccBootLimit > 2.5 && vccBootLimit < 3.3 && (gpioConfig.apPin == 0xFF || digitalRead(gpioConfig.apPin) == HIGH)) { // Skip if user is holding AP button while booting (HIGH = button is released)
|
||||
if (vcc < vccBootLimit) {
|
||||
{
|
||||
Debug.printf_P(PSTR("(setup) Voltage is too low (%.2f < %.2f), sleeping\n"), vcc, vccBootLimit);
|
||||
bool deepSleep = true;
|
||||
#if defined(ESP32)
|
||||
float allowedDrift = bootcount * 0.01;
|
||||
#else
|
||||
float allowedDrift = gpioConfig.vccBootLimit == 0 ? 0.05 : 3.3 - min(3.29, gpioConfig.vccBootLimit / 10.0); // Make sure boot limit is never above 3.3v
|
||||
deepSleep = gpioConfig.vccBootLimit > 0; // If a boot limit is set, we are assume the hardware has been configured for deep sleep (Hint: GPIO16)
|
||||
#endif
|
||||
while(!hw.isVoltageOptimal(allowedDrift)) {
|
||||
uint8_t bootCycles = incrementBootCycleCounter(deepSleep);
|
||||
debugW_P(PSTR("Voltage is outside optimal range (%.2fV)"), allowedDrift);
|
||||
if(gpioConfig.apPin != 0xFF && digitalRead(gpioConfig.apPin) == LOW) {
|
||||
debugW_P(PSTR("AP button is pressed, skipping voltage wait"));
|
||||
} else if(bootCycles < MAX_BOOT_CYCLES) {
|
||||
int secs = MAX_BOOT_CYCLES - bootCycles;
|
||||
if(deepSleep) {
|
||||
debugI_P(PSTR("Sleeping for %d seconds to allow capacitor charge (%d.cycle)"), secs, bootCycles);
|
||||
Serial.flush();
|
||||
ESP.deepSleep(secs * 1000000); // Deep sleep to allow output cap to charge up
|
||||
return;
|
||||
} else {
|
||||
debugI_P(PSTR("Waiting (no sleep) for %d seconds to allow capacitor charge (%d.cycle)"), secs, bootCycles);
|
||||
delay(secs * 1000); // Just delay to allow output cap to charge up
|
||||
vcc = hw.getVcc();
|
||||
debugI_P(PSTR("Voltage: %.2fV"), vcc);
|
||||
}
|
||||
ESP.deepSleep(10000000); //Deep sleep to allow output cap to charge up
|
||||
}
|
||||
} else {
|
||||
debugE_P(PSTR("Voltage not reaching optimal level after multiple attempts, continuing boot"));
|
||||
hw.setMaxVcc(vcc); // Since we had to sleep, set max Vcc to current level because this is probably the highest we will get
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if defined(ESP8266)
|
||||
resetBootCycleCounter(deepSleep);
|
||||
#endif
|
||||
hw.ledOff(LED_YELLOW);
|
||||
hw.ledOff(LED_INTERNAL);
|
||||
|
||||
if(!hw.ledOn(LED_GREEN)) {
|
||||
hw.ledOn(LED_INTERNAL);
|
||||
@@ -472,6 +517,12 @@ void setup() {
|
||||
hw.ledOff(LED_GREEN);
|
||||
hw.ledOff(LED_INTERNAL);
|
||||
|
||||
hw.ledBlink(LED_INTERNAL, 1);
|
||||
hw.ledBlink(LED_RED, 1);
|
||||
hw.ledBlink(LED_YELLOW, 1);
|
||||
hw.ledBlink(LED_GREEN, 1);
|
||||
hw.ledBlink(LED_BLUE, 1);
|
||||
|
||||
WiFi.disconnect(true);
|
||||
WiFi.softAPdisconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
@@ -537,6 +588,15 @@ void setup() {
|
||||
toggleSetupMode();
|
||||
}
|
||||
|
||||
PriceServiceConfig price;
|
||||
if(config.getPriceServiceConfig(price)) {
|
||||
ps = new PriceService(&Debug);
|
||||
ps->setup(price);
|
||||
ws.setPriceService(ps);
|
||||
}
|
||||
ws.setPriceSettings(price.area, price.currency);
|
||||
ea.setCurrency(price.currency);
|
||||
|
||||
EnergyAccountingConfig *eac = new EnergyAccountingConfig();
|
||||
if(!config.getEnergyAccountingConfig(*eac)) {
|
||||
config.clearEnergyAccountingConfig(*eac);
|
||||
@@ -633,7 +693,12 @@ void loop() {
|
||||
handleEnergySpeedometer();
|
||||
#endif
|
||||
#endif
|
||||
handlePriceService(now);
|
||||
|
||||
// In case of BUS powered meters, we need to be sure voltage is stable before fetching prices. But we refuse to wait forever, so max 30 seconds
|
||||
if(now > 30000 || hw.isVoltageOptimal(0.01)) {
|
||||
handlePriceService(now);
|
||||
}
|
||||
|
||||
#if defined(AMS_CLOUD)
|
||||
handleCloud();
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user