Merge branch 'main' into feature/15min_prices

This commit is contained in:
Gunnar Skjold 2025-10-16 08:51:06 +02:00
commit a86cbf9c2e
9 changed files with 93 additions and 53 deletions

View File

@ -13,16 +13,17 @@
bool AmsConfiguration::getSystemConfig(SystemConfig& config) {
EEPROM.begin(EEPROM_SIZE);
uint8_t configVersion = EEPROM.read(EEPROM_CONFIG_ADDRESS);
EEPROM.get(CONFIG_SYSTEM_START, config);
EEPROM.end();
if(configVersion == EEPROM_CHECK_SUM) {
EEPROM.get(CONFIG_SYSTEM_START, config);
EEPROM.end();
return true;
} else {
if(configVersion == EEPROM_CLEARED_INDICATOR) {
if(configVersion == EEPROM_CLEARED_INDICATOR && config.boardType > 0 && config.boardType < 250) {
config.vendorConfigured = true;
} else {
config.vendorConfigured = false;
config.boardType = 0xFF;
clear();
}
config.userConfigured = false;
config.dataCollectionConsent = 0;
@ -282,8 +283,9 @@ void AmsConfiguration::ackWebChange() {
}
bool AmsConfiguration::getMeterConfig(MeterConfig& config) {
if(hasConfig()) {
EEPROM.begin(EEPROM_SIZE);
EEPROM.begin(EEPROM_SIZE);
uint8_t configVersion = EEPROM.read(EEPROM_CONFIG_ADDRESS);
if(configVersion == EEPROM_CHECK_SUM || configVersion == EEPROM_CLEARED_INDICATOR) {
EEPROM.get(CONFIG_METER_START, config);
EEPROM.end();
if(config.bufferSize < 1 || config.bufferSize > 64) {
@ -906,12 +908,12 @@ bool AmsConfiguration::getZmartChargeConfig(ZmartChargeConfig& config) {
EEPROM.end();
stripNonAscii((uint8_t*) config.token, 21);
stripNonAscii((uint8_t*) config.baseUrl, 64);
if(strlen(config.token) < 20) {
if(strlen(config.token) != 20 || !config.enabled) {
config.enabled = false;
memset(config.token, 0, 64);
memset(config.baseUrl, 0, 64);
}
if(strncmp_P(config.baseUrl, PSTR("https"), 5) != 0) {
if(strlen(config.baseUrl) == 0 || strncmp_P(config.baseUrl, PSTR("https"), 5) != 0) {
memset(config.baseUrl, 0, 64);
snprintf_P(config.baseUrl, 64, PSTR("https://main.zmartcharge.com/api"));
}
@ -926,8 +928,8 @@ bool AmsConfiguration::setZmartChargeConfig(ZmartChargeConfig& config) {
ZmartChargeConfig existing;
if(getZmartChargeConfig(existing)) {
zcChanged |= config.enabled != existing.enabled;
zcChanged |= memcmp(config.token, existing.token, 21) != 0;
zcChanged |= memcmp(config.token, existing.baseUrl, 64) != 0;
zcChanged |= strcmp(config.token, existing.token) != 0;
zcChanged |= strcmp(config.baseUrl, existing.baseUrl) != 0;
} else {
zcChanged = true;
}
@ -1025,6 +1027,10 @@ void AmsConfiguration::clear() {
clearCloudConfig(cloud);
EEPROM.put(CONFIG_CLOUD_START, cloud);
ZmartChargeConfig zc;
clearZmartChargeConfig(zc);
EEPROM.put(CONFIG_ZC_START, zc);
EEPROM.put(EEPROM_CONFIG_ADDRESS, EEPROM_CLEARED_INDICATOR);
EEPROM.commit();
EEPROM.end();
@ -1351,10 +1357,10 @@ void AmsConfiguration::print(Print* debugger)
debugger->printf_P(PSTR("Area: %s\r\n"), price.area);
debugger->printf_P(PSTR("Currency: %s\r\n"), price.currency);
debugger->printf_P(PSTR("ENTSO-E Token: %s\r\n"), price.entsoeToken);
debugger->println(F(""));
delay(10);
debugger->flush();
}
debugger->println(F(""));
delay(10);
debugger->flush();
}
UiConfig ui;
@ -1372,9 +1378,29 @@ void AmsConfiguration::print(Print* debugger)
String uuid = ESPRandom::uuidToString(cc.clientId);;
debugger->println(F("--Cloud configuration--"));
debugger->printf_P(PSTR("Enabled: %s\r\n"), cc.enabled ? "Yes" : "No");
debugger->printf_P(PSTR("Hostname: %s\r\n"), cc.hostname);
debugger->printf_P(PSTR("Client ID: %s\r\n"), uuid.c_str());
debugger->printf_P(PSTR("Interval: %d\r\n"), cc.interval);
if(cc.enabled) {
debugger->printf_P(PSTR("Hostname: %s\r\n"), cc.hostname);
debugger->printf_P(PSTR("Client ID: %s\r\n"), uuid.c_str());
debugger->printf_P(PSTR("Interval: %d\r\n"), cc.interval);
}
debugger->println(F(""));
delay(10);
debugger->flush();
}
#endif
#if defined(ZMART_CHARGE)
ZmartChargeConfig zc;
if(getZmartChargeConfig(zc)) {
debugger->println(F("--ZmartCharge configuration--"));
debugger->printf_P(PSTR("Enabled: %s\r\n"), zc.enabled ? "Yes" : "No");
if(zc.enabled) {
debugger->printf_P(PSTR("Base URL: '%s'\r\n"), zc.baseUrl);
debugger->printf_P(PSTR("Token: '%s'\r\n"), zc.token);
}
debugger->println(F(""));
delay(10);
debugger->flush();
}
#endif

View File

@ -62,7 +62,8 @@ protected:
HardwareSerial *hwSerial = NULL;
uint8_t rxBufferErrors = 0;
bool autodetect = false, validDataReceived = false;
bool autodetect = false;
uint8_t validDataReceived = 0;
unsigned long meterAutodetectLastChange = 0;
long rate = 10000;
uint32_t autodetectBaud = 0;

View File

@ -286,7 +286,7 @@ AmsData* PassiveMeterCommunicator::getData(AmsData& meterState) {
len = 0;
if(data != NULL) {
if(data->getListType() > 0) {
validDataReceived = true;
validDataReceived++;
if(rxBufferErrors > 0) rxBufferErrors--;
}
}
@ -586,15 +586,15 @@ void PassiveMeterCommunicator::setupHanPort(uint32_t baud, uint8_t parityOrdinal
autodetectBaud = baud = 2400;
}
if(parityOrdinal == 0) {
parityOrdinal = 11; // 8E1
}
#if defined(AMS_REMOTE_DEBUG)
if (debugger->isActive(RemoteDebug::INFO))
#endif
debugger->printf_P(PSTR("(setupHanPort) Setting up HAN on pin %d/%d with baud %d and parity %d\n"), rxpin, txpin, baud, parityOrdinal);
if(parityOrdinal == 0) {
parityOrdinal = 3; // 8N1
}
if(rxpin == 3 || rxpin == 113) {
#if ARDUINO_USB_CDC_ON_BOOT
hwSerial = &Serial0;
@ -799,6 +799,7 @@ HardwareSerial* PassiveMeterCommunicator::getHwSerial() {
void PassiveMeterCommunicator::rxerr(int err) {
if(err == 0) return;
if(lastError == 90+err) return; // Do not flood with same error
switch(err) {
case 2:
#if defined(AMS_REMOTE_DEBUG)
@ -836,10 +837,9 @@ void PassiveMeterCommunicator::rxerr(int err) {
unsigned long now = millis();
if(autodetect) {
meterAutodetectLastChange = 0;
} else if(meterAutodetectLastChange > 0 && now - meterAutodetectLastChange < 120000 && validDataReceived) {
} else if(validDataReceived > 2) {
meterConfig.parity = getNextParity(meterConfig.parity);
configChanged = true;
setupHanPort(meterConfig.baud, meterConfig.parity, meterConfig.invert);
}
break;
}
@ -849,12 +849,14 @@ void PassiveMeterCommunicator::rxerr(int err) {
void PassiveMeterCommunicator::handleAutodetect(unsigned long now) {
if(!autodetect) return;
if(now - meterAutodetectLastChange < 12000) return;
if(!validDataReceived) {
if(now - meterAutodetectLastChange > 12000 && (meterConfig.baud == 0 || meterConfig.parity == 0)) {
if(validDataReceived < 2) {
if(meterConfig.baud == 0 || meterConfig.parity == 0) {
autodetect = true;
if(lastError == 95) { // If parity error, switch parity
autodetectParity = getNextParity(autodetectParity);
lastError = 0;
} else {
autodetectCount++;
}

View File

@ -82,7 +82,7 @@ void PriceService::setTimezone(Timezone* tz) {
}
char* PriceService::getToken() {
return this->config->entsoeToken;
return ""; // Currently the implementation is not working, so lets disable it for al. Old code: this->config->entsoeToken;
}
char* PriceService::getCurrency() {

File diff suppressed because one or more lines are too long

View File

@ -340,8 +340,9 @@
</div>
<div class="my-1">
<label><input type="checkbox" name="pe" value="true" bind:checked={configuration.p.e} class="rounded mb-1"/> {translations.conf?.price?.enabled ?? "Enabled"}</label>
{#if configuration.p.e && sysinfo.chip != 'esp8266'}
<br/><input name="pt" bind:value={configuration.p.t} type="text" class="in-s" placeholder={translations.conf?.price?.api_key_placeholder ?? ""} pattern={charAndNumPattern}/>
{#if configuration.p.e && sysinfo.chip != 'esp8266' && configuration.p.t}
<input name="pt" type="hidden" bind:value={configuration.p.t}/>
<br/><input type="text" class="in-s" placeholder="ENTSO-E API key disabled, ref issue #1030" disabled/>
{/if}
</div>
<div class="my-1">

View File

@ -1244,6 +1244,17 @@ void AmsWebServer::handleSave() {
if(!checkSecurity(1))
return;
#if defined(AMS_REMOTE_DEBUG)
if (debugger->isActive(RemoteDebug::DEBUG)) {
#endif
debugger->printf(PSTR("Received %d args for /save\n"), server.args());
for(uint8_t i = 0; i < server.args(); i++) {
debugger->printf_P(PSTR(" %s: %s\n"), server.argName(i).c_str(), server.arg(i).c_str());
}
#if defined(AMS_REMOTE_DEBUG)
}
#endif
SystemConfig sys;
config->getSystemConfig(sys);

View File

@ -38,7 +38,7 @@ void ZmartChargeCloudConnector::update(AmsData& data) {
return;
}
if(((now - lastUpdate) / 1000) > (fast || lastFailed ? heartbeatFast : heartbeat)) {
if(lastUpdate == 0 || ((now - lastUpdate) / 1000) > (fast || lastFailed ? heartbeatFast : heartbeat)) {
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(ZmartCharge) Preparing to update cloud\n"));
memset(json, 0, BufferSize);
snprintf_P(json, BufferSize, ZC_LB_JSON,
@ -86,9 +86,9 @@ void ZmartChargeCloudConnector::update(AmsData& data) {
}
http->end();
} else {
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("(ZmartCharge) Communication error, returned status: %d\n"), status);
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf(http->errorToString(status).c_str());
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(http->getString().c_str());
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("(ZmartCharge) Communication error with %s, returned status: %d\n"), baseUrl, status);
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("%s\n", http->errorToString(status).c_str());
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("%s\n", http->getString().c_str());
http->end();
}

View File

@ -322,20 +322,15 @@ void setup() {
if(!config.getGpioConfig(gpioConfig)) {
config.clearGpio(gpioConfig);
}
if(config.getSystemConfig(sysConfig)) {
config.getMeterConfig(meterConfig);
if(sysConfig.boardType < 20) {
config.clearGpio(gpioConfig, false);
hw.applyBoardConfig(sysConfig.boardType, gpioConfig, meterConfig, meterConfig.rxPin);
config.setMeterConfig(meterConfig);
config.setGpioConfig(gpioConfig);
}
} else {
config.clearMeter(meterConfig);
sysConfig.boardType = 0;
sysConfig.vendorConfigured = false;
sysConfig.userConfigured = false;
sysConfig.dataCollectionConsent = false;
config.getSystemConfig(sysConfig);
config.getMeterConfig(meterConfig);
if(sysConfig.boardType < 20) {
Serial.printf_P(PSTR("Applying default GPIO configuration for board type %d\n"), sysConfig.boardType);
config.clearGpio(gpioConfig, false);
hw.applyBoardConfig(sysConfig.boardType, gpioConfig, meterConfig, meterConfig.rxPin);
config.setMeterConfig(meterConfig);
config.setGpioConfig(gpioConfig);
}
delay(1);
@ -363,6 +358,8 @@ void setup() {
if(!hw.ledBlink(LED_RED, 6)) {
hw.ledBlink(LED_INTERNAL, 6);
}
ESP.restart();
return;
}
}
}
@ -432,10 +429,11 @@ void setup() {
float vcc = hw.getVcc();
debugI_P(PSTR("AMS reader %s started"), FirmwareVersion::VersionString);
debugI_P(PSTR("Configuration version: %d, board type: %d"), config.getConfigVersion(), sysConfig.boardType);
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(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 > 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);
@ -1422,6 +1420,7 @@ bool readHanPort() {
}
if(mc->isConfigChanged()) {
mc->getCurrentConfig(meterConfig);
debugI_P(PSTR("Meter configuration based on auto-detect"));
config.setMeterConfig(meterConfig);
mc->ackConfigChanged();
}