diff --git a/lib/AmsDataStorage/src/AmsDataStorage.cpp b/lib/AmsDataStorage/src/AmsDataStorage.cpp index e67ee814..ff114397 100644 --- a/lib/AmsDataStorage/src/AmsDataStorage.cpp +++ b/lib/AmsDataStorage/src/AmsDataStorage.cpp @@ -54,8 +54,8 @@ bool AmsDataStorage::update(AmsData* data) { breakTime(now-3600, utcYesterday); breakTime(tz->toLocal(now-3600), ltzYesterDay); - uint64_t importCounter = data->getActiveImportCounter() * 1000; - uint64_t exportCounter = data->getActiveExportCounter() * 1000; + uint32_t importCounter = data->getActiveImportCounter() * 1000; + uint32_t exportCounter = data->getActiveExportCounter() * 1000; // Clear hours between last update and now if(day.lastMeterReadTime > now) { diff --git a/lib/DomoticzMqttHandler/src/DomoticzMqttHandler.cpp b/lib/DomoticzMqttHandler/src/DomoticzMqttHandler.cpp index b4dc88de..e0147ef0 100644 --- a/lib/DomoticzMqttHandler/src/DomoticzMqttHandler.cpp +++ b/lib/DomoticzMqttHandler/src/DomoticzMqttHandler.cpp @@ -9,12 +9,12 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyA } if(energy > 0.0) { char val[16]; - snprintf(val, 16, "%.1f;%.1f", (data->getActiveImportPower()/1.0), energy*1000.0); + snprintf_P(val, 16, PSTR("%.1f;%.1f"), (data->getActiveImportPower()/1.0), energy*1000.0); snprintf_P(json, BufferSize, DOMOTICZ_JSON, config.elidx, val ); - ret = mqtt->publish("domoticz/in", json); + ret = mqtt->publish(F("domoticz/in"), json); } } @@ -23,22 +23,22 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyA if (config.vl1idx > 0){ char val[16]; - snprintf(val, 16, "%.2f", data->getL1Voltage()); + snprintf_P(val, 16, PSTR("%.2f"), data->getL1Voltage()); snprintf_P(json, BufferSize, DOMOTICZ_JSON, config.vl1idx, val ); - ret |= mqtt->publish("domoticz/in", json); + ret |= mqtt->publish(F("domoticz/in"), json); } if (config.vl2idx > 0){ char val[16]; - snprintf(val, 16, "%.2f", data->getL2Voltage()); + snprintf_P(val, 16, PSTR("%.2f"), data->getL2Voltage()); snprintf_P(json, BufferSize, DOMOTICZ_JSON, config.vl2idx, val ); - ret |= mqtt->publish("domoticz/in", json); + ret |= mqtt->publish(F("domoticz/in"), json); } if (config.vl3idx > 0){ @@ -48,7 +48,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyA config.vl3idx, val ); - ret |= mqtt->publish("domoticz/in", json); + ret |= mqtt->publish(F("domoticz/in"), json); } if (config.cl1idx > 0){ @@ -58,7 +58,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyA config.cl1idx, val ); - ret |= mqtt->publish("domoticz/in", json); + ret |= mqtt->publish(F("domoticz/in"), json); } return ret; } diff --git a/lib/EnergyAccounting/include/EnergyAccounting.h b/lib/EnergyAccounting/include/EnergyAccounting.h index def816cf..98e40316 100644 --- a/lib/EnergyAccounting/include/EnergyAccounting.h +++ b/lib/EnergyAccounting/include/EnergyAccounting.h @@ -54,35 +54,35 @@ public: bool save(); bool isInitialized(); - double getUseThisHour(); - double getUseToday(); - double getUseThisMonth(); + float getUseThisHour(); + float getUseToday(); + float getUseThisMonth(); - double getProducedThisHour(); - double getProducedToday(); - double getProducedThisMonth(); + float getProducedThisHour(); + float getProducedToday(); + float getProducedThisMonth(); - double getCostThisHour(); - double getCostToday(); - double getCostYesterday(); - double getCostThisMonth(); + float getCostThisHour(); + float getCostToday(); + float getCostYesterday(); + float getCostThisMonth(); uint16_t getCostLastMonth(); - double getIncomeThisHour(); - double getIncomeToday(); - double getIncomeYesterday(); - double getIncomeThisMonth(); + float getIncomeThisHour(); + float getIncomeToday(); + float getIncomeYesterday(); + float getIncomeThisMonth(); uint16_t getIncomeLastMonth(); - double getMonthMax(); + float getMonthMax(); uint8_t getCurrentThreshold(); EnergyAccountingPeak getPeak(uint8_t); EnergyAccountingData getData(); void setData(EnergyAccountingData&); - void setFixedPrice(double price); - double getPriceForHour(uint8_t h); + void setFixedPrice(float price); + float getPriceForHour(uint8_t h); private: RemoteDebug* debugger = NULL; @@ -93,10 +93,10 @@ private: EnergyAccountingConfig *config = NULL; Timezone *tz = NULL; uint8_t currentHour = 0, currentDay = 0, currentThresholdIdx = 0; - double use = 0, costHour = 0, costDay = 0; - double produce = 0, incomeHour = 0, incomeDay = 0; + float use = 0, costHour = 0, costDay = 0; + float produce = 0, incomeHour = 0, incomeDay = 0; EnergyAccountingData data = { 0, 0, 0, 0, 0, 0 }; - double fixedPrice = 0; + float fixedPrice = 0; void calcDayCost(); bool updateMax(uint16_t val, uint8_t day); diff --git a/lib/EnergyAccounting/src/EnergyAccounting.cpp b/lib/EnergyAccounting/src/EnergyAccounting.cpp index 55c249bf..670df27a 100644 --- a/lib/EnergyAccounting/src/EnergyAccounting.cpp +++ b/lib/EnergyAccounting/src/EnergyAccounting.cpp @@ -68,7 +68,7 @@ bool EnergyAccounting::update(AmsData* amsData) { init = true; } - double price = getPriceForHour(0); + float price = getPriceForHour(0); if(!initPrice && price != ENTSOE_NO_VALUE) { if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EnergyAccounting) Initializing prices at %lu\n"), (int32_t) now); calcDayCost(); @@ -124,14 +124,14 @@ bool EnergyAccounting::update(AmsData* amsData) { } unsigned long ms = this->lastUpdateMillis > amsData->getLastUpdateMillis() ? 0 : amsData->getLastUpdateMillis() - this->lastUpdateMillis; - double kwhi = (amsData->getActiveImportPower() * (((double) ms) / 3600000.0)) / 1000.0; - double kwhe = (amsData->getActiveExportPower() * (((double) ms) / 3600000.0)) / 1000.0; + float kwhi = (amsData->getActiveImportPower() * (((float) ms) / 3600000.0)) / 1000.0; + float kwhe = (amsData->getActiveExportPower() * (((float) ms) / 3600000.0)) / 1000.0; lastUpdateMillis = amsData->getLastUpdateMillis(); if(kwhi > 0) { if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(EnergyAccounting) Adding %.4f kWh import\n"), kwhi); use += kwhi; if(price != ENTSOE_NO_VALUE) { - double cost = price * kwhi; + float cost = price * kwhi; if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(EnergyAccounting) and %.4f %s\n"), cost / 100.0, eapi->getCurrency()); costHour += cost; costDay += cost; @@ -141,7 +141,7 @@ bool EnergyAccounting::update(AmsData* amsData) { if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(EnergyAccounting) Adding %.4f kWh export\n"), kwhe); produce += kwhe; if(price != ENTSOE_NO_VALUE) { - double income = price * kwhe; + float income = price * kwhe; if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(EnergyAccounting) and %.4f %s\n"), income / 100.0, eapi->getCurrency()); incomeHour += income; incomeDay += income; @@ -168,7 +168,7 @@ void EnergyAccounting::calcDayCost() { incomeDay = 0; } for(int i = 0; i < currentHour; i++) { - double price = getPriceForHour(i - local.Hour); + float price = getPriceForHour(i - local.Hour); if(price == ENTSOE_NO_VALUE) break; breakTime(now - ((local.Hour - i) * 3600), utc); int16_t wh = ds->getHourImport(utc.Hour); @@ -181,12 +181,12 @@ void EnergyAccounting::calcDayCost() { } } -double EnergyAccounting::getUseThisHour() { +float EnergyAccounting::getUseThisHour() { return use; } -double EnergyAccounting::getUseToday() { - double ret = 0.0; +float EnergyAccounting::getUseToday() { + float ret = 0.0; time_t now = time(nullptr); if(now < BUILD_EPOCH) return 0.0; if(tz == NULL) return 0.0; @@ -199,22 +199,22 @@ double EnergyAccounting::getUseToday() { return ret + getUseThisHour(); } -double EnergyAccounting::getUseThisMonth() { +float EnergyAccounting::getUseThisMonth() { time_t now = time(nullptr); if(now < BUILD_EPOCH) return 0.0; - double ret = 0; + float ret = 0; for(int i = 0; i < currentDay; i++) { ret += ds->getDayImport(i) / 1000.0; } return ret + getUseToday(); } -double EnergyAccounting::getProducedThisHour() { +float EnergyAccounting::getProducedThisHour() { return produce; } -double EnergyAccounting::getProducedToday() { - double ret = 0.0; +float EnergyAccounting::getProducedToday() { + float ret = 0.0; time_t now = time(nullptr); if(now < BUILD_EPOCH) return 0.0; tmElements_t utc, local; @@ -226,10 +226,10 @@ double EnergyAccounting::getProducedToday() { return ret + getProducedThisHour(); } -double EnergyAccounting::getProducedThisMonth() { +float EnergyAccounting::getProducedThisMonth() { time_t now = time(nullptr); if(now < BUILD_EPOCH) return 0.0; - double ret = 0; + float ret = 0; for(int i = 0; i < currentDay; i++) { ret += ds->getDayExport(i) / 1000.0; } @@ -237,19 +237,19 @@ double EnergyAccounting::getProducedThisMonth() { } -double EnergyAccounting::getCostThisHour() { +float EnergyAccounting::getCostThisHour() { return costHour; } -double EnergyAccounting::getCostToday() { +float EnergyAccounting::getCostToday() { return costDay; } -double EnergyAccounting::getCostYesterday() { +float EnergyAccounting::getCostYesterday() { return data.costYesterday / 10.0; } -double EnergyAccounting::getCostThisMonth() { +float EnergyAccounting::getCostThisMonth() { return data.costThisMonth + getCostToday(); } @@ -257,19 +257,19 @@ uint16_t EnergyAccounting::getCostLastMonth() { return data.costLastMonth; } -double EnergyAccounting::getIncomeThisHour() { +float EnergyAccounting::getIncomeThisHour() { return incomeHour; } -double EnergyAccounting::getIncomeToday() { +float EnergyAccounting::getIncomeToday() { return incomeDay; } -double EnergyAccounting::getIncomeYesterday() { +float EnergyAccounting::getIncomeYesterday() { return data.incomeYesterday / 10.0; } -double EnergyAccounting::getIncomeThisMonth() { +float EnergyAccounting::getIncomeThisMonth() { return data.incomeThisMonth + getIncomeToday(); } @@ -283,7 +283,7 @@ uint8_t EnergyAccounting::getCurrentThreshold() { return config->thresholds[currentThresholdIdx]; } -double EnergyAccounting::getMonthMax() { +float EnergyAccounting::getMonthMax() { if(config == NULL) return 0.0; uint8_t count = 0; @@ -503,11 +503,11 @@ bool EnergyAccounting::updateMax(uint16_t val, uint8_t day) { return false; } -void EnergyAccounting::setFixedPrice(double price) { +void EnergyAccounting::setFixedPrice(float price) { this->fixedPrice = price; } -double EnergyAccounting::getPriceForHour(uint8_t h) { +float EnergyAccounting::getPriceForHour(uint8_t h) { if(fixedPrice > 0.0) return fixedPrice; if(eapi == NULL) return ENTSOE_NO_VALUE; return eapi->getValueForHour(h); diff --git a/lib/EntsoePriceApi/src/EntsoeApi.cpp b/lib/EntsoePriceApi/src/EntsoeApi.cpp index e4364589..dc20aad3 100644 --- a/lib/EntsoePriceApi/src/EntsoeApi.cpp +++ b/lib/EntsoePriceApi/src/EntsoeApi.cpp @@ -92,8 +92,8 @@ float EntsoeApi::getValueForHour(time_t ts, int8_t hour) { if(pos >= 48) return ENTSOE_NO_VALUE; - double value = ENTSOE_NO_VALUE; - double multiplier = config->multiplier / 1000.0; + float value = ENTSOE_NO_VALUE; + float multiplier = config->multiplier / 1000.0; if(pos >= hoursToday) { if(tomorrow == NULL) return ENTSOE_NO_VALUE; @@ -272,14 +272,14 @@ float EntsoeApi::getCurrencyMultiplier(const char* from, const char* to, time_t ESP.wdtFeed(); #endif - snprintf(buf, BufferSize, "https://data.norges-bank.no/api/data/EXR/M.%s.NOK.SP?lastNObservations=1", from); + snprintf_P(buf, BufferSize, PSTR("https://data.norges-bank.no/api/data/EXR/M.%s.NOK.SP?lastNObservations=1"), from); if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(EntsoeApi) Retrieving %s to NOK conversion\n"), from); if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EntsoeApi) url: %s\n"), buf); if(retrieve(buf, &p)) { if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EntsoeApi) got exchange rate %.4f\n"), p.getValue()); currencyMultiplier = p.getValue(); if(strncmp(to, "NOK", 3) != 0) { - snprintf(buf, BufferSize, "https://data.norges-bank.no/api/data/EXR/M.%s.NOK.SP?lastNObservations=1", to); + snprintf_P(buf, BufferSize, PSTR("https://data.norges-bank.no/api/data/EXR/M.%s.NOK.SP?lastNObservations=1"), to); if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(EntsoeApi) Retrieving %s to NOK conversion\n"), to); if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EntsoeApi) url: %s\n"), buf); if(retrieve(buf, &p)) { @@ -310,8 +310,8 @@ PricesContainer* EntsoeApi::fetchPrices(time_t t) { breakTime(tz->toUTC(e1), d1); // To get day and hour for CET/CEST at UTC midnight breakTime(tz->toUTC(e2), d2); - snprintf(buf, BufferSize, "%s?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s", - "https://web-api.tp.entsoe.eu/api", getToken(), + snprintf_P(buf, BufferSize, PSTR("https://web-api.tp.entsoe.eu/api?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s"), + getToken(), d1.Year+1970, d1.Month, d1.Day, d1.Hour, 00, d2.Year+1970, d2.Month, d2.Day, d2.Hour, 00, config->area, config->area); @@ -334,8 +334,7 @@ PricesContainer* EntsoeApi::fetchPrices(time_t t) { } } else if(hub) { String data; - snprintf(buf, BufferSize, "%s/%s/%d/%d/%d?currency=%s", - "http://hub.amsleser.no/hub/price", + snprintf_P(buf, BufferSize, PSTR("http://hub.amsleser.no/hub/price/%s/%d/%d/%d?currency=%s"), config->area, tm.Year+1970, tm.Month, @@ -368,7 +367,7 @@ PricesContainer* EntsoeApi::fetchPrices(time_t t) { debugPrint(content, 0, data.length()); } - DataParserContext ctx; + DataParserContext ctx = {0,0,0,0}; ctx.length = data.length(); GCMParser gcm(key, auth); int8_t gcmRet = gcm.parse(content, ctx); diff --git a/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp b/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp index e7ee1c3d..81318eb3 100644 --- a/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp +++ b/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp @@ -120,7 +120,8 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En ); mqtt->publish(topic + "/realtime", json); } - + mqtt->loop(); + delay(10); return true; } @@ -138,7 +139,7 @@ bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwT if(data != NULL) { char* pos = buf+strlen(buf); String id = toHex(data->address, 8); - snprintf(pos, 26, "\"%s\":%.2f,", + snprintf_P(pos, 26, PSTR("\"%s\":%.2f,"), id.c_str(), data->lastRead ); diff --git a/lib/HwTools/include/HwTools.h b/lib/HwTools/include/HwTools.h index dacac70c..29085a02 100644 --- a/lib/HwTools/include/HwTools.h +++ b/lib/HwTools/include/HwTools.h @@ -37,13 +37,13 @@ struct AdcConfig { class HwTools { public: void setup(GpioConfig*, AmsConfiguration*); - double getVcc(); + float getVcc(); uint8_t getTempSensorCount(); TempSensorData* getTempSensorData(uint8_t); bool updateTemperatures(); - double getTemperature(); - double getTemperatureAnalog(); - double getTemperature(uint8_t address[8]); + float getTemperature(); + float getTemperatureAnalog(); + float getTemperature(uint8_t address[8]); int getWifiRssi(); bool ledOn(uint8_t color); bool ledOff(uint8_t color); diff --git a/lib/HwTools/src/HwTools.cpp b/lib/HwTools/src/HwTools.cpp index eae2a1d7..feffb7d3 100644 --- a/lib/HwTools/src/HwTools.cpp +++ b/lib/HwTools/src/HwTools.cpp @@ -213,8 +213,8 @@ void HwTools::getAdcChannel(uint8_t pin, AdcConfig& config) { #endif } -double HwTools::getVcc() { - double volts = 0.0; +float HwTools::getVcc() { + float volts = 0.0; if(config->vccPin != 0xFF) { #if defined(ESP32) if(voltAdc.unit != 0xFF) { @@ -257,7 +257,7 @@ double HwTools::getVcc() { if(volts == 0.0) return 0.0; if(config->vccResistorGnd > 0 && config->vccResistorVcc > 0) { - volts *= ((double) (config->vccResistorGnd + config->vccResistorVcc) / config->vccResistorGnd); + volts *= ((float) (config->vccResistorGnd + config->vccResistorVcc) / config->vccResistorGnd); } @@ -348,10 +348,10 @@ bool HwTools::isSensorAddressEqual(uint8_t a[8], uint8_t b[8]) { return true; } -double HwTools::getTemperature() { +float HwTools::getTemperature() { uint8_t c = 0; - double ret = 0; - double analogTemp = getTemperatureAnalog(); + float ret = 0; + float analogTemp = getTemperatureAnalog(); if(analogTemp != DEVICE_DISCONNECTED_C) { ret += analogTemp; c++; @@ -366,10 +366,10 @@ double HwTools::getTemperature() { } return c == 0 ? DEVICE_DISCONNECTED_C : ret/c; } -double HwTools::getTemperatureAnalog() { +float HwTools::getTemperatureAnalog() { if(config->tempAnalogSensorPin != 0xFF) { float adcCalibrationFactor = 1.06587; - int volts = ((double) analogRead(config->tempAnalogSensorPin) / analogRange) * 3.3; + int volts = ((float) analogRead(config->tempAnalogSensorPin) / analogRange) * 3.3; return ((volts * adcCalibrationFactor) - 0.4) / 0.0195; } return DEVICE_DISCONNECTED_C; diff --git a/lib/SvelteUi/src/AmsWebServer.cpp b/lib/SvelteUi/src/AmsWebServer.cpp index 5250125c..e6b4e120 100644 --- a/lib/SvelteUi/src/AmsWebServer.cpp +++ b/lib/SvelteUi/src/AmsWebServer.cpp @@ -158,11 +158,11 @@ void AmsWebServer::loop() { bool AmsWebServer::checkSecurity(byte level, bool send401) { bool access = WiFi.getMode() == WIFI_AP || webConfig.security < level; - if(!access && webConfig.security >= level && server.hasHeader("Authorization")) { + if(!access && webConfig.security >= level && server.hasHeader(F("Authorization"))) { String expectedAuth = String(webConfig.username) + ":" + String(webConfig.password); - String providedPwd = server.header("Authorization"); - providedPwd.replace("Basic ", ""); + String providedPwd = server.header(F("Authorization")); + providedPwd.replace(F("Basic "), F("")); #if defined(ESP8266) String expectedBase64 = base64::encode(expectedAuth, false); @@ -256,11 +256,11 @@ void AmsWebServer::sysinfoJson() { String meterModel = meterState->getMeterModel(); if(!meterModel.isEmpty()) - meterModel.replace("\\", "\\\\"); + meterModel.replace(F("\\"), F("\\\\")); String meterId = meterState->getMeterId(); if(!meterId.isEmpty()) - meterId.replace("\\", "\\\\"); + meterId.replace(F("\\"), F("\\\\")); int size = snprintf_P(buf, BufferSize, SYSINFO_JSON, VERSION, @@ -342,11 +342,7 @@ void AmsWebServer::sysinfoJson() { } if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Rebooting")); delay(1000); - #if defined(ESP8266) - ESP.reset(); - #elif defined(ESP32) - ESP.restart(); - #endif + ESP.restart(); performRestart = false; } } @@ -417,7 +413,7 @@ void AmsWebServer::dataJson() { mqttStatus = 3; } - double price = ea->getPriceForHour(0); + float price = ea->getPriceForHour(0); String peaks = ""; for(uint8_t i = 1; i <= ea->getConfig()->hours; i++) { @@ -712,7 +708,7 @@ void AmsWebServer::temperatureJson() { return; int count = hw->getTempSensorCount(); - snprintf(buf, 16, "{\"c\":%d,\"s\":[", count); + snprintf_P(buf, 16, PSTR("{\"c\":%d,\"s\":["), count); for(int i = 0; i < count; i++) { TempSensorData* data = hw->getTempSensorData(i); @@ -730,7 +726,7 @@ void AmsWebServer::temperatureJson() { delay(10); } char* pos = buf+strlen(buf); - snprintf(count == 0 ? pos : pos-1, 8, "]}"); + snprintf_P(count == 0 ? pos : pos-1, 8, PSTR("]}")); server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE); server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE); @@ -964,7 +960,7 @@ void AmsWebServer::configurationJson() { haconf.discoveryNameTag ); server.sendContent(buf); - server.sendContent("}"); + server.sendContent_P(PSTR("}")); } void AmsWebServer::handleSave() { @@ -1211,10 +1207,10 @@ void AmsWebServer::handleSave() { memset(meterConfig->authenticationKey, 0, 16); } - meterConfig->wattageMultiplier = server.arg(F("mmw")).toDouble() * 1000; - meterConfig->voltageMultiplier = server.arg(F("mmv")).toDouble() * 1000; - meterConfig->amperageMultiplier = server.arg(F("mma")).toDouble() * 1000; - meterConfig->accumulatedMultiplier = server.arg(F("mmc")).toDouble() * 1000; + 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; config->setMeterConfig(*meterConfig); } @@ -1478,11 +1474,7 @@ void AmsWebServer::handleSave() { } if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Rebooting")); delay(1000); - #if defined(ESP8266) - ESP.reset(); - #elif defined(ESP32) - ESP.restart(); - #endif + ESP.restart(); performRestart = false; } } @@ -1500,11 +1492,7 @@ void AmsWebServer::reboot() { if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Rebooting")); delay(1000); - #if defined(ESP8266) - ESP.reset(); - #elif defined(ESP32) - ESP.restart(); - #endif + ESP.restart(); performRestart = false; } @@ -1584,11 +1572,7 @@ void AmsWebServer::upgradeFromUrl(String url, String nextVersion) { case HTTP_UPDATE_OK: debugger->printf_P(PSTR("Update OK\n")); debugger->flush(); - #if defined(ESP8266) - ESP.reset(); - #elif defined(ESP32) - ESP.restart(); - #endif + ESP.restart(); break; } } @@ -1642,8 +1626,8 @@ void AmsWebServer::firmwareUpload() { if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("No file, falling back to post\n")); return; } - if(!filename.endsWith(".bin")) { - server.send(500, MIME_PLAIN, "500: couldn't create file"); + if(!filename.endsWith(F(".bin"))) { + server.send_P(500, MIME_PLAIN, PSTR("500: couldn't create file")); } else { #if defined(ESP32) esp_task_wdt_delete(NULL); @@ -1656,7 +1640,7 @@ void AmsWebServer::firmwareUpload() { uploadFile(FILE_FIRMWARE); if(upload.status == UPLOAD_FILE_END) { rebootForUpgrade = true; - server.sendHeader("Location","/"); + server.sendHeader(HEADER_LOCATION,F("/")); server.send(302); } } @@ -1769,11 +1753,7 @@ void AmsWebServer::factoryResetPost() { if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Rebooting")); delay(1000); - #if defined(ESP8266) - ESP.reset(); - #elif defined(ESP32) - ESP.restart(); - #endif + ESP.restart(); } void AmsWebServer::robotstxt() { @@ -2220,7 +2200,7 @@ void AmsWebServer::configFileDownload() { ead.peaks[4].day, ead.peaks[4].value / 100.0 )); - server.sendContent("\n"); + server.sendContent_P(PSTR("\n")); } } @@ -2231,12 +2211,12 @@ void AmsWebServer::configFileUpload() { HTTPUpload& upload = uploadFile(FILE_CFG); if(upload.status == UPLOAD_FILE_END) { performRestart = true; - server.sendHeader("Location","/"); + server.sendHeader(HEADER_LOCATION,F("/")); server.send(303); } } void AmsWebServer::redirectToMain() { - server.sendHeader("Location","/"); + server.sendHeader(HEADER_LOCATION,F("/")); server.send(302); } \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 298d0cc1..e58a8310 100755 --- a/platformio.ini +++ b/platformio.ini @@ -2,7 +2,7 @@ extra_configs = platformio-user.ini [common] -lib_deps = EEPROM, LittleFS, DNSServer, 256dpi/MQTT@2.5.0, OneWireNg@0.10.0, DallasTemperature@3.9.1, EspSoftwareSerial@6.14.1, https://github.com/gskjold/RemoteDebug.git, Time@1.6.1, Timezone@1.2.4, AmsConfiguration, AmsData, AmsDataStorage, HwTools, Uptime, AmsDecoder, EntsoePriceApi, EnergyAccounting, RawMqttHandler, JsonMqttHandler, DomoticzMqttHandler, HomeAssistantMqttHandler, SvelteUi +lib_deps = EEPROM, LittleFS, DNSServer, git@github.com:256dpi/arduino-mqtt.git, OneWireNg@0.10.0, DallasTemperature@3.9.1, EspSoftwareSerial@6.14.1, https://github.com/gskjold/RemoteDebug.git, Time@1.6.1, Timezone@1.2.4, AmsConfiguration, AmsData, AmsDataStorage, HwTools, Uptime, AmsDecoder, EntsoePriceApi, EnergyAccounting, RawMqttHandler, JsonMqttHandler, DomoticzMqttHandler, HomeAssistantMqttHandler, SvelteUi lib_ignore = OneWire extra_scripts = pre:scripts/addversion.py diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index 3b1f2a13..d50b36f1 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -30,7 +30,7 @@ ADC_MODE(ADC_VCC); #if defined(ESP32) #include #endif -#define WDT_TIMEOUT 90 +#define WDT_TIMEOUT 60 #if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) #include @@ -64,6 +64,14 @@ ADC_MODE(ADC_VCC); #include "RemoteDebug.h" +#define debugV_P(x, ...) if (Debug.isActive(Debug.VERBOSE)) {Debug.printf_P(x, ##__VA_ARGS__);Debug.println();} +#define debugD_P(x, ...) if (Debug.isActive(Debug.DEBUG)) {Debug.printf_P(x, ##__VA_ARGS__);Debug.println();} +#define debugI_P(x, ...) if (Debug.isActive(Debug.INFO)) {Debug.printf_P(x, ##__VA_ARGS__);Debug.println();} +#define debugW_P(x, ...) if (Debug.isActive(Debug.WARNING)) {Debug.printf_P(x, ##__VA_ARGS__);Debug.println();} +#define debugE_P(x, ...) if (Debug.isActive(Debug.ERROR)) {Debug.printf_P(x, ##__VA_ARGS__);Debug.println();} +#define debugA_P(x, ...) if (Debug.isActive(Debug.ANY)) {Debug.printf_P(x, ##__VA_ARGS__);Debug.println();} + + #define BUF_SIZE_COMMON (2048) #define BUF_SIZE_HAN (1280) @@ -218,8 +226,8 @@ void setup() { float vcc = hw.getVcc(); if (Debug.isActive(RemoteDebug::INFO)) { - debugI("AMS bridge started"); - debugI("Voltage: %.2fV", vcc); + debugI_P(PSTR("AMS bridge started")); + 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 @@ -239,11 +247,11 @@ void setup() { bool hasFs = false; #if defined(ESP32) - debugD("ESP32 LittleFS"); + debugD_P(PSTR("ESP32 LittleFS")); hasFs = LittleFS.begin(true); - debugD(" size: %d", LittleFS.totalBytes()); + debugD_P(PSTR(" size: %d"), LittleFS.totalBytes()); #else - debugD("ESP8266 LittleFS"); + debugD_P(PSTR("ESP8266 LittleFS")); hasFs = LittleFS.begin(); #endif delay(1); @@ -255,16 +263,16 @@ void setup() { bool flashed = false; if(LittleFS.exists(FILE_FIRMWARE)) { if (!config.hasConfig()) { - debugI("Device has no config, yet a firmware file exists, deleting file."); + debugI_P(PSTR("Device has no config, yet a firmware file exists, deleting file.")); } else if (gpioConfig.apPin == 0xFF || digitalRead(gpioConfig.apPin) == HIGH) { - if(Debug.isActive(RemoteDebug::INFO)) debugI("Found firmware"); + if(Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Found firmware")); #if defined(ESP8266) WiFi.setSleepMode(WIFI_LIGHT_SLEEP); WiFi.forceSleepBegin(); #endif int i = 0; while(hw.getVcc() > 1.0 && hw.getVcc() < 3.2 && i < 3) { - if(Debug.isActive(RemoteDebug::INFO)) debugI(" vcc not optimal, light sleep 10s"); + if(Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR(" vcc not optimal, light sleep 10s")); #if defined(ESP8266) delay(10000); #elif defined(ESP32) @@ -274,14 +282,14 @@ void setup() { i++; } - debugI(" flashing"); + debugI_P(PSTR(" flashing")); File firmwareFile = LittleFS.open(FILE_FIRMWARE, (char*) "r"); - debugD(" firmware size: %d", firmwareFile.size()); + debugD_P(PSTR(" firmware size: %d"), firmwareFile.size()); uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; - debugD(" available: %d", maxSketchSpace); + debugD_P(PSTR(" available: %d"), maxSketchSpace); if (!Update.begin(maxSketchSpace, U_FLASH)) { if(Debug.isActive(RemoteDebug::ERROR)) { - debugE("Unable to start firmware update"); + debugE_P(PSTR("Unable to start firmware update")); Update.printError(Serial); } } else { @@ -294,26 +302,22 @@ void setup() { } firmwareFile.close(); } else { - debugW("AP button pressed, skipping firmware update and deleting firmware file."); + debugW_P(PSTR("AP button pressed, skipping firmware update and deleting firmware file.")); } LittleFS.remove(FILE_FIRMWARE); } else if(LittleFS.exists(FILE_CFG)) { - if(Debug.isActive(RemoteDebug::INFO)) debugI("Found config"); + if(Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Found config")); configFileParse(); flashed = true; } LittleFS.end(); if(flashed) { if(Debug.isActive(RemoteDebug::INFO)) { - debugI("Firmware update complete, restarting"); + debugI_P(PSTR("Firmware update complete, restarting")); Serial.flush(); } delay(250); -#if defined(ESP8266) - ESP.reset(); -#elif defined(ESP32) ESP.restart(); -#endif return; } } @@ -338,7 +342,7 @@ void setup() { ds.load(); } else { if(Debug.isActive(RemoteDebug::INFO)) { - debugI("No configuration, booting AP"); + debugI_P(PSTR("No configuration, booting AP")); } swapWifiMode(); } @@ -401,7 +405,7 @@ void loop() { longPressActive = false; } else { // Single press action - debugD("Button was clicked, no action configured"); + debugD_P(PSTR("Button was clicked, no action configured")); } buttonActive = false; } @@ -421,7 +425,7 @@ void loop() { meterState.setLastError(METER_ERROR_BUFFER); if(rxBufferSize < MAX_RX_BUFFER_SIZE) { rxBufferSize += 64; - debugI("Increasing RX buffer to %d bytes", rxBufferSize); + debugI_P(PSTR("Increasing RX buffer to %d bytes"), rxBufferSize); config.setMeterChanged(); } } @@ -430,7 +434,7 @@ void loop() { if(swSerial->overflow()) { meterState.setLastError(METER_ERROR_BUFFER); rxBufferSize += 64; - debugI("Increasing RX buffer to %d bytes", rxBufferSize); + debugI_P(PSTR("Increasing RX buffer to %d bytes"), rxBufferSize); config.setMeterChanged(); } } @@ -492,17 +496,17 @@ void loop() { Debug.stop(); } if(Debug.isActive(RemoteDebug::INFO)) { - debugI("Successfully connected to WiFi!"); - debugI("IP: %s", WiFi.localIP().toString().c_str()); - debugI("GW: %s", WiFi.gatewayIP().toString().c_str()); - debugI("DNS: %s", WiFi.dnsIP().toString().c_str()); + debugI_P(PSTR("Successfully connected to WiFi!")); + debugI_P(PSTR("IP: %s"), WiFi.localIP().toString().c_str()); + debugI_P(PSTR("GW: %s"), WiFi.gatewayIP().toString().c_str()); + debugI_P(PSTR("DNS: %s"), WiFi.dnsIP().toString().c_str()); } if(strlen(wifi.hostname) > 0 && wifi.mdns) { - debugD("mDNS is enabled, using host: %s", wifi.hostname); + debugD_P(PSTR("mDNS is enabled, using host: %s"), wifi.hostname); if(MDNS.begin(wifi.hostname)) { MDNS.addService(F("http"), F("tcp"), 80); } else { - debugE("Failed to set up mDNS!"); + debugE_P(PSTR("Failed to set up mDNS!")); } } } @@ -568,7 +572,7 @@ void loop() { ea.setFixedPrice(entsoe.fixedPrice / 1000.0); } } catch(const std::exception& e) { - debugE("Exception in ENTSO-E loop (%s)", e.what()); + debugE_P(PSTR("Exception in ENTSO-E loop (%s)"), e.what()); } ws.loop(); } @@ -613,7 +617,7 @@ void loop() { if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) { mqttHandler->publishTemperatures(&config, &hw); } - debugD("Used %ld ms to update temperature", millis()-start); + debugD_P(PSTR("Used %ld ms to update temperature"), millis()-start); } } if(now - lastSysupdate > 60000) { @@ -624,7 +628,7 @@ void loop() { } } } catch(const std::exception& e) { - debugE("Exception in readHanPort (%s)", e.what()); + debugE_P(PSTR("Exception in readHanPort (%s)"), e.what()); meterState.setLastError(METER_ERROR_EXCEPTION); } try { @@ -632,13 +636,13 @@ void loop() { if(now - meterAutodetectLastChange > 20000 && (meterConfig.baud == 0 || meterConfig.parity == 0)) { meterAutodetect = true; meterAutoIndex++; // Default is to try the first one in setup() - debugI("Meter serial autodetect, swapping to: %d, %d, %s", bauds[meterAutoIndex], parities[meterAutoIndex], inverts[meterAutoIndex] ? "true" : "false"); + debugI_P(PSTR("Meter serial autodetect, swapping to: %d, %d, %s"), bauds[meterAutoIndex], parities[meterAutoIndex], inverts[meterAutoIndex] ? "true" : "false"); if(meterAutoIndex >= 4) meterAutoIndex = 0; setupHanPort(gpioConfig, bauds[meterAutoIndex], parities[meterAutoIndex], inverts[meterAutoIndex]); meterAutodetectLastChange = now; } } else if(meterAutodetect) { - debugI("Meter serial autodetected, saving: %d, %d, %s", bauds[meterAutoIndex], parities[meterAutoIndex], inverts[meterAutoIndex] ? "true" : "false"); + debugI_P(PSTR("Meter serial autodetected, saving: %d, %d, %s"), bauds[meterAutoIndex], parities[meterAutoIndex], inverts[meterAutoIndex] ? "true" : "false"); meterAutodetect = false; meterConfig.baud = bauds[meterAutoIndex]; meterConfig.parity = parities[meterAutoIndex]; @@ -647,7 +651,7 @@ void loop() { setupHanPort(gpioConfig, meterConfig.baud, meterConfig.parity, meterConfig.invert); } } catch(const std::exception& e) { - debugE("Exception in meter autodetect (%s)", e.what()); + debugE_P(PSTR("Exception in meter autodetect (%s)"), e.what()); meterState.setLastError(METER_ERROR_AUTODETECT); } @@ -659,37 +663,39 @@ void loop() { #endif } +#if defined(ESP32) void rxerr(int err) { if(err == 0) return; switch(err) { case 1: - debugE("Serial break error"); + debugE_P(PSTR("Serial break error")); break; case 2: - debugE("Serial buffer full"); + debugE_P(PSTR("Serial buffer full")); if(rxBufferSize < MAX_RX_BUFFER_SIZE) { rxBufferSize += 64; - debugI("Increasing RX buffer to %d bytes", rxBufferSize); + debugI_P(PSTR("Increasing RX buffer to %d bytes"), rxBufferSize); config.setMeterChanged(); } break; case 3: - debugE("Serial FIFO overflow"); + debugE_P(PSTR("Serial FIFO overflow")); break; case 4: - debugE("Serial frame error"); + debugE_P(PSTR("Serial frame error")); break; case 5: - debugE("Serial parity error"); + debugE_P(PSTR("Serial parity error")); break; } meterState.setLastError(90+err); } +#endif void setupHanPort(GpioConfig& gpioConfig, uint32_t baud, uint8_t parityOrdinal, bool invert) { uint8_t pin = gpioConfig.hanPin; - if(Debug.isActive(RemoteDebug::INFO)) Debug.printf(PSTR("(setupHanPort) Setting up HAN on pin %d with baud %d and parity %d\n"), pin, baud, parityOrdinal); + if(Debug.isActive(RemoteDebug::INFO)) Debug.printf(PSTR("(setupHanPort) Setting up HAN on pin %d with baud %d and parity %d\n")), pin, baud, parityOrdinal; if(baud == 0) { baud = bauds[meterAutoIndex]; @@ -726,12 +732,12 @@ void setupHanPort(GpioConfig& gpioConfig, uint32_t baud, uint8_t parityOrdinal, #endif if(pin == 0) { - debugE("Invalid GPIO configured for HAN"); + debugE_P(PSTR("Invalid GPIO configured for HAN")); return; } if(hwSerial != NULL) { - debugD("Hardware serial"); + debugD_P(PSTR("Hardware serial")); Serial.flush(); #if defined(ESP8266) SerialConfig serialConfig; @@ -766,10 +772,10 @@ void setupHanPort(GpioConfig& gpioConfig, uint32_t baud, uint8_t parityOrdinal, #if defined(ESP8266) if(pin == 3) { - debugI("Switching UART0 to pin 1 & 3"); + debugI_P(PSTR("Switching UART0 to pin 1 & 3")); Serial.pins(1,3); } else if(pin == 113) { - debugI("Switching UART0 to pin 15 & 13"); + debugI_P(PSTR("Switching UART0 to pin 15 & 13")); Serial.pins(15,13); } #endif @@ -784,7 +790,7 @@ void setupHanPort(GpioConfig& gpioConfig, uint32_t baud, uint8_t parityOrdinal, swSerial = NULL; } } else { - debugD("Software serial"); + debugD_P(PSTR("Software serial")); Serial.flush(); if(swSerial == NULL) { @@ -819,7 +825,7 @@ void setupHanPort(GpioConfig& gpioConfig, uint32_t baud, uint8_t parityOrdinal, // The library automatically sets the pullup in Serial.begin() if(!gpioConfig.hanPinPullup) { - debugI("HAN pin pullup disabled"); + debugI_P(PSTR("HAN pin pullup disabled")); pinMode(gpioConfig.hanPin, INPUT); } @@ -844,7 +850,7 @@ void errorBlink() { switch(lastError++) { case 0: if(lastErrorBlink - meterState.getLastUpdateMillis() > 30000) { - debugW("No HAN data received last 30s, single blink"); + debugW_P(PSTR("No HAN data received last 30s, single blink")); hw.ledBlink(LED_RED, 1); // If no message received from AMS in 30 sec, blink once if(meterState.getLastError() == 0) meterState.setLastError(METER_ERROR_NO_DATA); return; @@ -852,14 +858,14 @@ void errorBlink() { break; case 1: if(mqttEnabled && mqtt != NULL && mqtt->lastError() != 0) { - debugW("MQTT connection not available, double blink"); + debugW_P(PSTR("MQTT connection not available, double blink")); hw.ledBlink(LED_RED, 2); // If MQTT error, blink twice return; } break; case 2: if(WiFi.getMode() != WIFI_AP && WiFi.status() != WL_CONNECTED) { - debugW("WiFi not connected, tripe blink"); + debugW_P(PSTR("WiFi not connected, tripe blink")); hw.ledBlink(LED_RED, 3); // If WiFi not connected, blink three times return; } @@ -882,7 +888,7 @@ void swapWifiMode() { yield(); if (mode != WIFI_AP || !config.hasConfig()) { - if(Debug.isActive(RemoteDebug::INFO)) debugI("Swapping to AP mode"); + if(Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Swapping to AP mode")); //wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, 0); // Disable default gw @@ -906,10 +912,10 @@ void swapWifiMode() { dnsServer->start(53, PSTR("*"), WiFi.softAPIP()); #if defined(DEBUG_MODE) Debug.setSerialEnabled(true); - Debug.begin("192.168.4.1", 23, RemoteDebug::VERBOSE); + Debug.begin(F("192.168.4.1"), 23, RemoteDebug::VERBOSE); #endif } else { - if(Debug.isActive(RemoteDebug::INFO)) debugI("Swapping to STA mode"); + if(Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Swapping to STA mode")); if(dnsServer != NULL) { delete dnsServer; dnsServer = NULL; @@ -934,7 +940,8 @@ bool readHanPort() { return false; } - DataParserContext ctx = {0}; + DataParserContext ctx = {0,0,0,0}; + strcpy_P((char*) ctx.system_title, PSTR("")); int pos = DATA_PARSE_INCOMPLETE; // For each byte received, check if we have a complete frame we can handle while(hanSerial->available() && pos == DATA_PARSE_INCOMPLETE) { @@ -942,7 +949,7 @@ bool readHanPort() { if(len >= BUF_SIZE_HAN) { hanSerial->readBytes(hanBuffer, BUF_SIZE_HAN); len = 0; - debugI("Buffer overflow, resetting"); + debugI_P(PSTR("Buffer overflow, resetting")); return false; } hanBuffer[len++] = hanSerial->read(); @@ -950,12 +957,12 @@ bool readHanPort() { pos = unwrapData((uint8_t *) hanBuffer, ctx); if(ctx.type > 0 && pos >= 0) { if(ctx.type == DATA_TAG_DLMS) { - debugD("Received valid DLMS at %d", pos); + debugD_P(PSTR("Received valid DLMS at %d"), pos); } else if(ctx.type == DATA_TAG_DSMR) { - debugD("Received valid DSMR at %d", pos); + debugD_P(PSTR("Received valid DSMR at %d"), pos); } else { // TODO: Move this so that payload is sent to MQTT - debugE("Unknown tag %02X at pos %d", ctx.type, pos); + debugE_P(PSTR("Unknown tag %02X at pos %d"), ctx.type, pos); len = 0; return false; } @@ -965,7 +972,7 @@ bool readHanPort() { return false; } else if(pos == DATA_PARSE_UNKNOWN_DATA) { meterState.setLastError(pos); - debugV("Unknown data payload:"); + debugV_P(PSTR("Unknown data payload:")); len = len + hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len); if(Debug.isActive(RemoteDebug::VERBOSE)) debugPrint(hanBuffer, 0, len); len = 0; @@ -1003,12 +1010,12 @@ bool readHanPort() { mqtt->loop(); } - debugV("Using application data:"); + debugV_P(PSTR("Using application data:")); if(Debug.isActive(RemoteDebug::VERBOSE)) debugPrint((byte*) payload, 0, ctx.length); // Rudimentary detector for L&G proprietary format, this is terrible code... Fix later if(payload[0] == CosemTypeStructure && payload[2] == CosemTypeArray && payload[1] == payload[3]) { - debugV("LNG"); + debugV_P(PSTR("LNG")); data = LNG(payload, meterState.getMeterType(), &meterConfig, ctx, &Debug); } else if(payload[0] == CosemTypeStructure && payload[2] == CosemTypeLongUnsigned && @@ -1018,10 +1025,10 @@ bool readHanPort() { payload[14] == CosemTypeLongUnsigned && payload[17] == CosemTypeLongUnsigned ) { - debugV("LNG2"); + debugV_P(PSTR("LNG2")); data = LNG2(payload, meterState.getMeterType(), &meterConfig, ctx, &Debug); } else { - debugV("DLMS"); + debugV_P(PSTR("DLMS")); // TODO: Split IEC6205675 into DataParserKaifa and DataParserObis. This way we can add other means of parsing, for those other proprietary formats data = IEC6205675(payload, meterState.getMeterType(), &meterConfig, ctx); } @@ -1043,10 +1050,10 @@ bool readHanPort() { time_t now = time(nullptr); if(now < BUILD_EPOCH && data.getListType() >= 3) { if(data.getMeterTimestamp() > BUILD_EPOCH) { - debugI("Using timestamp from meter"); + debugI_P(PSTR("Using timestamp from meter")); now = data.getMeterTimestamp(); } else if(data.getPackageTimestamp() > BUILD_EPOCH) { - debugI("Using timestamp from meter (DLMS)"); + debugI_P(PSTR("Using timestamp from meter (DLMS)")); now = data.getPackageTimestamp(); } if(now > BUILD_EPOCH) { @@ -1062,24 +1069,24 @@ bool readHanPort() { bool saveData = false; if(!ds.isHappy() && now > BUILD_EPOCH) { - debugD("Its time to update data storage"); + debugD_P(PSTR("Its time to update data storage")); tmElements_t tm; breakTime(now, tm); if(tm.Minute == 0) { - debugV(" using actual data"); + debugV_P(PSTR(" using actual data")); saveData = ds.update(&data); } else if(meterState.getListType() >= 3) { - debugV(" using estimated data"); + debugV_P(PSTR(" using estimated data")); saveData = ds.update(&meterState); } if(saveData) { - debugI("Saving data"); + debugI_P(PSTR("Saving data")); ds.save(); } } if(ea.update(&data)) { - debugI("Saving energy accounting"); + debugI_P(PSTR("Saving energy accounting")); ea.save(); } } @@ -1091,37 +1098,37 @@ void printHanReadError(int pos) { if(Debug.isActive(RemoteDebug::WARNING)) { switch(pos) { case DATA_PARSE_BOUNDRY_FLAG_MISSING: - debugW("Boundry flag missing"); + debugW_P(PSTR("Boundry flag missing")); break; case DATA_PARSE_HEADER_CHECKSUM_ERROR: - debugW("Header checksum error"); + debugW_P(PSTR("Header checksum error")); break; case DATA_PARSE_FOOTER_CHECKSUM_ERROR: - debugW("Frame checksum error"); + debugW_P(PSTR("Frame checksum error")); break; case DATA_PARSE_INCOMPLETE: - debugW("Received frame is incomplete"); + debugW_P(PSTR("Received frame is incomplete")); break; case GCM_AUTH_FAILED: - debugW("Decrypt authentication failed"); + debugW_P(PSTR("Decrypt authentication failed")); break; case GCM_ENCRYPTION_KEY_FAILED: - debugW("Setting decryption key failed"); + debugW_P(PSTR("Setting decryption key failed")); break; case GCM_DECRYPT_FAILED: - debugW("Decryption failed"); + debugW_P(PSTR("Decryption failed")); break; case MBUS_FRAME_LENGTH_NOT_EQUAL: - debugW("Frame length mismatch"); + debugW_P(PSTR("Frame length mismatch")); break; case DATA_PARSE_INTERMEDIATE_SEGMENT: - debugI("Intermediate segment received"); + debugI_P(PSTR("Intermediate segment received")); break; case DATA_PARSE_UNKNOWN_DATA: - debugW("Unknown data format %02X", hanBuffer[0]); + debugW_P(PSTR("Unknown data format %02X"), hanBuffer[0]); break; default: - debugW("Unspecified error while reading data: %d", pos); + debugW_P(PSTR("Unspecified error while reading data: %d"), pos); } } } @@ -1163,7 +1170,7 @@ void WiFi_connect() { ESP.restart(); return; } - if (Debug.isActive(RemoteDebug::INFO)) debugI("Not connected to WiFi, closing resources"); + if (Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Not connected to WiFi, closing resources")); if(mqtt != NULL) { mqtt->disconnect(); mqtt->loop(); @@ -1197,7 +1204,7 @@ void WiFi_connect() { } wifiTimeout = WIFI_CONNECTION_TIMEOUT; - if (Debug.isActive(RemoteDebug::INFO)) debugI("Connecting to WiFi network: %s", wifi.ssid); + if (Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Connecting to WiFi network: %s"), wifi.ssid); wifiReconnectCount++; @@ -1224,7 +1231,7 @@ void WiFi_connect() { dns2.fromString(F("208.67.220.220")); // Add OpenDNS as second by default if nothing is configured } if(!WiFi.config(ip, gw, sn, dns1, dns2)) { - debugE("Static IP configuration is invalid, not using"); + debugE_P(PSTR("Static IP configuration is invalid, not using")); } } else { #if defined(ESP32) @@ -1258,13 +1265,13 @@ void WiFi_connect() { } yield(); } else { - if (Debug.isActive(RemoteDebug::ERROR)) debugI("Unable to start WiFi"); + if (Debug.isActive(RemoteDebug::ERROR)) debugI_P(PSTR("Unable to start WiFi")); } } } void mqttMessageReceived(String &topic, String &payload) { - debugI("Received message for topic %s", topic.c_str() ); + debugI_P(PSTR("Received message for topic %s"), topic.c_str() ); //if(meterConfig.source == METER_SOURCE_MQTT) { //DataParserContext ctx = {static_cast(payload.length()/2)}; //fromHex(hanBuffer, payload, ctx.length); @@ -1314,7 +1321,7 @@ int16_t unwrapData(uint8_t *buf, DataParserContext &context) { if(res >= 0) doRet = true; break; default: - debugE("Ended up in default case while unwrapping...(tag %02X)", tag); + debugE_P(PSTR("Ended up in default case while unwrapping...(tag %02X)"), tag); return DATA_PARSE_UNKNOWN_DATA; } lastTag = tag; @@ -1325,7 +1332,7 @@ int16_t unwrapData(uint8_t *buf, DataParserContext &context) { if(Debug.isActive(RemoteDebug::VERBOSE)) { switch(tag) { case DATA_TAG_HDLC: - debugV("HDLC frame:"); + debugV_P(PSTR("HDLC frame:")); // If MQTT bytestream payload is selected (mqttHandler == NULL), send the payload to MQTT if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) { mqtt->publish(topic.c_str(), toHex(buf, curLen)); @@ -1333,7 +1340,7 @@ int16_t unwrapData(uint8_t *buf, DataParserContext &context) { } break; case DATA_TAG_MBUS: - debugV("MBUS frame:"); + debugV_P(PSTR("MBUS frame:")); // If MQTT bytestream payload is selected (mqttHandler == NULL), send the payload to MQTT if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) { mqtt->publish(topic.c_str(), toHex(buf, curLen)); @@ -1341,19 +1348,19 @@ int16_t unwrapData(uint8_t *buf, DataParserContext &context) { } break; case DATA_TAG_GBT: - debugV("GBT frame:"); + debugV_P(PSTR("GBT frame:")); break; case DATA_TAG_GCM: - debugV("GCM frame:"); + debugV_P(PSTR("GCM frame:")); break; case DATA_TAG_LLC: - debugV("LLC frame:"); + debugV_P(PSTR("LLC frame:")); break; case DATA_TAG_DLMS: - debugV("DLMS frame:"); + debugV_P(PSTR("DLMS frame:")); break; case DATA_TAG_DSMR: - debugV("DSMR frame:"); + debugV_P(PSTR("DSMR frame:")); if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) { mqtt->publish(topic.c_str(), (char*) buf); mqtt->loop(); @@ -1384,7 +1391,7 @@ int16_t unwrapData(uint8_t *buf, DataParserContext &context) { // Use start byte of new buffer position as tag for next round in loop tag = (*buf); } - debugE("Got to end of unwrap method..."); + debugE_P(PSTR("Got to end of unwrap method...")); return DATA_PARSE_UNKNOWN_DATA; } @@ -1392,7 +1399,7 @@ unsigned long lastMqttRetry = -10000; void MQTT_connect() { MqttConfig mqttConfig; if(!config.getMqttConfig(mqttConfig) || strlen(mqttConfig.host) == 0) { - if(Debug.isActive(RemoteDebug::WARNING)) debugW("No MQTT config"); + if(Debug.isActive(RemoteDebug::WARNING)) debugW_P(PSTR("No MQTT config")); mqttEnabled = false; ws.setMqttEnabled(false); return; @@ -1405,7 +1412,7 @@ void MQTT_connect() { lastMqttRetry = millis(); if(Debug.isActive(RemoteDebug::INFO)) { - debugD("Disconnecting MQTT before connecting"); + debugD_P(PSTR("Disconnecting MQTT before connecting")); } mqtt->disconnect(); @@ -1421,7 +1428,8 @@ void MQTT_connect() { } yield(); } else { - mqtt = new MQTTClient(1024); + mqtt = new MQTTClient(128); + mqtt->dropOverflow(true); ws.setMqtt(mqtt); } @@ -1459,15 +1467,15 @@ void MQTT_connect() { time_t epoch = time(nullptr); if(mqttConfig.ssl) { if(epoch < BUILD_EPOCH) { - debugI("NTP not ready for MQTT SSL"); + debugI_P(PSTR("NTP not ready for MQTT SSL")); return; } - debugI("MQTT SSL is configured (%dkb free heap)", ESP.getFreeHeap()); + debugI_P(PSTR("MQTT SSL is configured (%dkb free heap)"), ESP.getFreeHeap()); if(mqttSecureClient == NULL) { mqttSecureClient = new WiFiClientSecure(); #if defined(ESP8266) mqttSecureClient->setBufferSizes(512, 512); - debugD("ESP8266 firmware does not have enough memory..."); + debugD_P(PSTR("ESP8266 firmware does not have enough memory...")); return; #endif @@ -1475,7 +1483,7 @@ void MQTT_connect() { File file; if(LittleFS.exists(FILE_MQTT_CA)) { - debugI("Found MQTT CA file (%dkb free heap)", ESP.getFreeHeap()); + debugI_P(PSTR("Found MQTT CA file (%dkb free heap)"), ESP.getFreeHeap()); file = LittleFS.open(FILE_MQTT_CA, (char*) "r"); #if defined(ESP8266) BearSSL::X509List *serverTrustedCA = new BearSSL::X509List(file); @@ -1487,25 +1495,25 @@ void MQTT_connect() { if(LittleFS.exists(FILE_MQTT_CERT) && LittleFS.exists(FILE_MQTT_KEY)) { #if defined(ESP8266) - debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap()); + debugI_P(PSTR("Found MQTT certificate file (%dkb free heap)"), ESP.getFreeHeap()); file = LittleFS.open(FILE_MQTT_CERT, (char*) "r"); BearSSL::X509List *serverCertList = new BearSSL::X509List(file); file.close(); - debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap()); + debugI_P(PSTR("Found MQTT key file (%dkb free heap)"), ESP.getFreeHeap()); file = LittleFS.open(FILE_MQTT_KEY, (char*) "r"); BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(file); file.close(); - debugD("Setting client certificates (%dkb free heap)", ESP.getFreeHeap()); + debugD_P(PSTR("Setting client certificates (%dkb free heap)"), ESP.getFreeHeap()); mqttSecureClient->setClientRSACert(serverCertList, serverPrivKey); #elif defined(ESP32) - debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap()); + debugI_P(PSTR("Found MQTT certificate file (%dkb free heap)"), ESP.getFreeHeap()); file = LittleFS.open(FILE_MQTT_CERT, (char*) "r"); mqttSecureClient->loadCertificate(file, file.size()); file.close(); - debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap()); + debugI_P(PSTR("Found MQTT key file (%dkb free heap)"), ESP.getFreeHeap()); file = LittleFS.open(FILE_MQTT_KEY, (char*) "r"); mqttSecureClient->loadPrivateKey(file, file.size()); file.close(); @@ -1515,7 +1523,7 @@ void MQTT_connect() { } LittleFS.end(); - debugD("MQTT SSL setup complete (%dkb free heap)", ESP.getFreeHeap()); + debugD_P(PSTR("MQTT SSL setup complete (%dkb free heap)"), ESP.getFreeHeap()); } } } @@ -1525,7 +1533,7 @@ void MQTT_connect() { } if(Debug.isActive(RemoteDebug::INFO)) { - debugI("Connecting to MQTT %s:%d", mqttConfig.host, mqttConfig.port); + debugI_P(PSTR("Connecting to MQTT %s:%d"), mqttConfig.host, mqttConfig.port); } mqtt->begin(mqttConfig.host, mqttConfig.port, *mqttClient); @@ -1533,7 +1541,7 @@ void MQTT_connect() { #if defined(ESP8266) if(mqttSecureClient) { time_t epoch = time(nullptr); - debugD("Setting NTP time %lu for secure MQTT connection", epoch); + debugD_P(PSTR("Setting NTP time %lu for secure MQTT connection"), epoch); mqttSecureClient->setX509Time(epoch); } #endif @@ -1541,7 +1549,7 @@ void MQTT_connect() { // Connect to a unsecure or secure MQTT server if ((strlen(mqttConfig.username) == 0 && mqtt->connect(mqttConfig.clientId)) || (strlen(mqttConfig.username) > 0 && mqtt->connect(mqttConfig.clientId, mqttConfig.username, mqttConfig.password))) { - if (Debug.isActive(RemoteDebug::INFO)) debugI("Successfully connected to MQTT!"); + if (Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Successfully connected to MQTT!")); if(mqttHandler != NULL) { mqttHandler->publishSystem(&hw, eapi, &ea); @@ -1551,11 +1559,11 @@ void MQTT_connect() { if (strlen(mqttConfig.subscribeTopic) > 0) { mqtt->onMessage(mqttMessageReceived); mqtt->subscribe(String(mqttConfig.subscribeTopic) + "/#"); - debugI(" Subscribing to [%s]\n", mqttConfig.subscribeTopic); + debugI_P(PSTR(" Subscribing to [%s]\n"), mqttConfig.subscribeTopic); } } else { if (Debug.isActive(RemoteDebug::ERROR)) { - debugE("Failed to connect to MQTT: %d", mqtt->lastError()); + debugE_P(PSTR("Failed to connect to MQTT: %d"), mqtt->lastError()); #if defined(ESP8266) if(mqttSecureClient) { mqttSecureClient->getLastSSLError((char*) commonBuffer, BUF_SIZE_COMMON); @@ -1568,10 +1576,10 @@ void MQTT_connect() { } void configFileParse() { - debugD("Parsing config file"); + debugD_P(PSTR("Parsing config file")); if(!LittleFS.exists(FILE_CFG)) { - debugW("Config file does not exist"); + debugW_P(PSTR("Config file does not exist")); return; } @@ -1612,7 +1620,7 @@ void configFileParse() { for(uint16_t i = 0; i < size; i++) { if(buf[i] < 32 || buf[i] > 126) { memset(buf+i, 0, size-i); - debugD("Found non-ascii, shortening line from %d to %d", size, i); + debugD_P(PSTR("Found non-ascii, shortening line from %d to %d"), size, i); size = i; break; } @@ -1745,13 +1753,13 @@ void configFileParse() { gpio.vccPin = String(buf+11).toInt(); } else if(strncmp_P(buf, PSTR("gpioVccOffset "), 14) == 0) { if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; - gpio.vccOffset = String(buf+14).toDouble() * 100; + gpio.vccOffset = String(buf+14).toFloat() * 100; } else if(strncmp_P(buf, PSTR("gpioVccMultiplier "), 18) == 0) { if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; - gpio.vccMultiplier = String(buf+18).toDouble() * 1000; + gpio.vccMultiplier = String(buf+18).toFloat() * 1000; } else if(strncmp_P(buf, PSTR("gpioVccBootLimit "), 17) == 0) { if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; - gpio.vccBootLimit = String(buf+17).toDouble() * 10; + gpio.vccBootLimit = String(buf+17).toFloat() * 10; } else if(strncmp_P(buf, PSTR("gpioVccResistorGnd "), 19) == 0) { if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; gpio.vccResistorGnd = String(buf+19).toInt(); @@ -1805,7 +1813,7 @@ void configFileParse() { strcpy(entsoe.currency, buf+15); } else if(strncmp_P(buf, PSTR("entsoeMultiplier "), 17) == 0) { if(!lEntsoe) { config.getEntsoeConfig(entsoe); lEntsoe = true; }; - entsoe.multiplier = String(buf+17).toDouble() * 1000; + entsoe.multiplier = String(buf+17).toFloat() * 1000; } else if(strncmp_P(buf, PSTR("thresholds "), 11) == 0) { if(!lEac) { config.getEnergyAccountingConfig(eac); lEac = true; }; int i = 0; @@ -1918,18 +1926,18 @@ void configFileParse() { long val = String(pch).toInt(); ead.month = val; } else if(i == 2) { - double val = String(pch).toDouble(); + float val = String(pch).toFloat(); if(val > 0.0) { ead.peaks[0] = { 1, (uint16_t) (val*100) }; } } else if(i == 3) { - double val = String(pch).toDouble(); + float val = String(pch).toFloat(); ead.costYesterday = val * 10; } else if(i == 4) { - double val = String(pch).toDouble(); + float val = String(pch).toFloat(); ead.costThisMonth = val; } else if(i == 5) { - double val = String(pch).toDouble(); + float val = String(pch).toFloat(); ead.costLastMonth = val; } else if(i >= 6 && i < 18) { uint8_t hour = i-6; @@ -1940,7 +1948,7 @@ void configFileParse() { pch = strtok (NULL, " "); i++; { - double val = String(pch).toDouble(); + float val = String(pch).toFloat(); ead.peaks[peak].value = val * 100; } peak++; @@ -1950,22 +1958,22 @@ void configFileParse() { long val = String(pch).toInt(); ead.month = val; } else if(i == 2) { - double val = String(pch).toDouble(); + float val = String(pch).toFloat(); ead.costYesterday = val * 10; } else if(i == 3) { - double val = String(pch).toDouble(); + float val = String(pch).toFloat(); ead.costThisMonth = val; } else if(i == 4) { - double val = String(pch).toDouble(); + float val = String(pch).toFloat(); ead.costLastMonth = val; } else if(i == 5) { - double val = String(pch).toDouble(); + float val = String(pch).toFloat(); ead.incomeYesterday= val * 10; } else if(i == 6) { - double val = String(pch).toDouble(); + float val = String(pch).toFloat(); ead.incomeThisMonth = val; } else if(i == 7) { - double val = String(pch).toDouble(); + float val = String(pch).toFloat(); ead.incomeLastMonth = val; } else if(i >= 8 && i < 20) { uint8_t hour = i-8; @@ -1976,7 +1984,7 @@ void configFileParse() { pch = strtok (NULL, " "); i++; { - double val = String(pch).toDouble(); + float val = String(pch).toFloat(); ead.peaks[peak].value = val * 100; } peak++; @@ -1992,11 +2000,11 @@ void configFileParse() { memset(buf, 0, 1024); } - debugD("Deleting config file"); + debugD_P(PSTR("Deleting config file")); file.close(); LittleFS.remove(FILE_CFG); - debugI("Saving configuration now..."); + debugI_P(PSTR("Saving configuration now...")); Serial.flush(); if(lSys) config.setSystemConfig(sys); if(lWiFi) config.setWiFiConfig(wifi); diff --git a/src/IEC6205621.cpp b/src/IEC6205621.cpp index 3eb39c94..b3446f62 100644 --- a/src/IEC6205621.cpp +++ b/src/IEC6205621.cpp @@ -9,25 +9,25 @@ IEC6205621::IEC6205621(const char* p) { lastUpdateMillis = millis(); listId = payload.substring(payload.startsWith("/") ? 1 : 0, payload.indexOf("\n")); - if(listId.startsWith("ADN")) { + if(listId.startsWith(F("ADN"))) { meterType = AmsTypeAidon; listId = listId.substring(0,4); - } else if(listId.startsWith("KFM")) { + } else if(listId.startsWith(F("KFM"))) { meterType = AmsTypeKaifa; listId = listId.substring(0,4); - } else if(listId.startsWith("KMP")) { + } else if(listId.startsWith(F("KMP"))) { meterType = AmsTypeKamstrup; listId = listId.substring(0,4); - } else if(listId.startsWith("ISk")) { + } else if(listId.startsWith(F("ISk"))) { meterType = AmsTypeIskra; listId = listId.substring(0,5); - } else if(listId.startsWith("XMX")) { + } else if(listId.startsWith(F("XMX"))) { meterType = AmsTypeLandisGyr; listId = listId.substring(0,6); - } else if(listId.startsWith("Ene") || listId.startsWith("EST")) { + } else if(listId.startsWith(F("Ene")) || listId.startsWith(F("EST"))) { meterType = AmsTypeSagemcom; listId = listId.substring(0,4); - } else if(listId.startsWith("LGF")) { + } else if(listId.startsWith(F("LGF"))) { meterType = AmsTypeLandisGyr; listId = listId.substring(0,4); } else { @@ -35,21 +35,21 @@ IEC6205621::IEC6205621(const char* p) { listId = listId.substring(0,4); } - meterId = extract(payload, "96.1.0"); + meterId = extract(payload, F("96.1.0")); if(meterId.isEmpty()) { - meterId = extract(payload, "0.0.5"); + meterId = extract(payload, F("0.0.5")); } - meterModel = extract(payload, "96.1.1"); + meterModel = extract(payload, F("96.1.1")); if(meterModel.isEmpty()) { - meterModel = extract(payload, "96.1.7"); + meterModel = extract(payload, F("96.1.7")); if(meterModel.isEmpty()) { - meterModel = payload.substring(payload.indexOf(listId) + listId.length(), payload.indexOf("\n")); + meterModel = payload.substring(payload.indexOf(listId) + listId.length(), payload.indexOf(F("\n"))); meterModel.trim(); } } - String timestamp = extract(payload, "1.0.0"); + String timestamp = extract(payload, F("1.0.0")); if(timestamp.length() > 10) { tmElements_t tm; tm.Year = (timestamp.substring(0,2).toInt() + 2000) - 1970; @@ -61,36 +61,36 @@ IEC6205621::IEC6205621(const char* p) { meterTimestamp = makeTime(tm); // TODO: Adjust for time zone } - activeImportPower = (uint16_t) (extractDouble(payload, "1.7.0")); - activeExportPower = (uint16_t) (extractDouble(payload, "2.7.0")); - reactiveImportPower = (uint16_t) (extractDouble(payload, "3.7.0")); - reactiveExportPower = (uint16_t) (extractDouble(payload, "4.7.0")); + activeImportPower = (uint16_t) (extractDouble(payload, F("1.7.0"))); + activeExportPower = (uint16_t) (extractDouble(payload, F("2.7.0"))); + reactiveImportPower = (uint16_t) (extractDouble(payload, F("3.7.0"))); + reactiveExportPower = (uint16_t) (extractDouble(payload, F("4.7.0"))); if(activeImportPower > 0) listType = 1; - l1voltage = extractDouble(payload, "32.7.0"); - l2voltage = extractDouble(payload, "52.7.0"); - l3voltage = extractDouble(payload, "72.7.0"); + l1voltage = extractFloat(payload, F("32.7.0")); + l2voltage = extractFloat(payload, F("52.7.0")); + l3voltage = extractFloat(payload, F("72.7.0")); - l1current = extractDouble(payload, "31.7.0"); - l2current = extractDouble(payload, "51.7.0"); - l3current = extractDouble(payload, "71.7.0"); + l1current = extractFloat(payload, F("31.7.0")); + l2current = extractFloat(payload, F("51.7.0")); + l3current = extractFloat(payload, F("71.7.0")); - l1activeImportPower = extractDouble(payload, "21.7.0"); - l2activeImportPower = extractDouble(payload, "41.7.0"); - l3activeImportPower = extractDouble(payload, "61.7.0"); + l1activeImportPower = extractFloat(payload, F("21.7.0")); + l2activeImportPower = extractFloat(payload, F("41.7.0")); + l3activeImportPower = extractFloat(payload, F("61.7.0")); - l1activeExportPower = extractDouble(payload, "22.7.0"); - l2activeExportPower = extractDouble(payload, "42.7.0"); - l3activeExportPower = extractDouble(payload, "62.7.0"); + l1activeExportPower = extractFloat(payload, F("22.7.0")); + l2activeExportPower = extractFloat(payload, F("42.7.0")); + l3activeExportPower = extractFloat(payload, F("62.7.0")); if(l1voltage > 0 || l2voltage > 0 || l3voltage > 0) listType = 2; double val = 0.0; - val = extractDouble(payload, "1.8.0"); + val = extractDouble(payload, F("1.8.0")); if(val == 0) { for(int i = 1; i < 9; i++) { val += extractDouble(payload, "1.8." + String(i,10)); @@ -98,7 +98,7 @@ IEC6205621::IEC6205621(const char* p) { } if(val > 0) activeImportCounter = val / 1000; - val = extractDouble(payload, "2.8.0"); + val = extractDouble(payload, F("2.8.0")); if(val == 0) { for(int i = 1; i < 9; i++) { val += extractDouble(payload, "2.8." + String(i,10)); @@ -106,7 +106,7 @@ IEC6205621::IEC6205621(const char* p) { } if(val > 0) activeExportCounter = val / 1000; - val = extractDouble(payload, "3.8.0"); + val = extractDouble(payload, F("3.8.0")); if(val == 0) { for(int i = 1; i < 9; i++) { val += extractDouble(payload, "3.8." + String(i,10)); @@ -114,7 +114,7 @@ IEC6205621::IEC6205621(const char* p) { } if(val > 0) reactiveImportCounter = val / 1000; - val = extractDouble(payload, "4.8.0"); + val = extractDouble(payload, F("4.8.0")); if(val == 0) { for(int i = 1; i < 9; i++) { val += extractDouble(payload, "4.8." + String(i,10)); @@ -135,7 +135,7 @@ IEC6205621::IEC6205621(const char* p) { String IEC6205621::extract(String payload, String obis) { int a = payload.indexOf(String(":" + obis + "(")); if(a > 0) { - int b = payload.indexOf(")", a); + int b = payload.indexOf(F(")"), a); if(b > a) { return payload.substring(a+obis.length()+2, b); } @@ -149,9 +149,22 @@ double IEC6205621::extractDouble(String payload, String obis) { return 0.0; } - int a = str.indexOf("*"); + int a = str.indexOf(F("*")); String val = str.substring(0,a); String unit = str.substring(a+1); - return unit.startsWith("k") ? val.toDouble() * 1000 : val.toDouble(); + return unit.startsWith(F("k")) ? val.toDouble() * 1000 : val.toDouble(); +} + +float IEC6205621::extractFloat(String payload, String obis) { + String str = extract(payload, obis); + if(str.isEmpty()) { + return 0.0; + } + + int a = str.indexOf(F("*")); + String val = str.substring(0,a); + String unit = str.substring(a+1); + + return unit.startsWith(F("k")) ? val.toFloat() * 1000 : val.toFloat(); } diff --git a/src/IEC6205621.h b/src/IEC6205621.h index be42e2ef..172bfa20 100644 --- a/src/IEC6205621.h +++ b/src/IEC6205621.h @@ -11,5 +11,6 @@ public: private: String extract(String payload, String obis); double extractDouble(String payload, String obis); + float extractFloat(String payload, String obis); }; #endif diff --git a/src/IEC6205675.cpp b/src/IEC6205675.cpp index bb1b663f..f86dbcd3 100644 --- a/src/IEC6205675.cpp +++ b/src/IEC6205675.cpp @@ -4,7 +4,7 @@ #include "ntohll.h" IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterConfig, DataParserContext &ctx) { - double val; + float val; char str[64]; TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; @@ -24,7 +24,7 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo memcpy(str, data->oct.data, data->oct.length); str[data->oct.length] = 0x00; String listId = String(str); - if(listId.startsWith("KFM_001")) { + if(listId.startsWith(F("KFM_001"))) { this->listId = listId; meterType = AmsTypeKaifa; @@ -160,6 +160,7 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo } } // Try system title + /* if(meterType == AmsTypeUnknown) { if(memcmp(ctx.system_title, "SAGY", 4) == 0) { meterType = AmsTypeSagemcom; @@ -167,6 +168,7 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo meterType = AmsTypeKaifa; } } + */ if(meterType == AmsTypeKamstrup || meterType == AmsTypeAidon) { this->packageTimestamp = this->packageTimestamp > 0 ? tz.toUTC(this->packageTimestamp) : 0; @@ -539,14 +541,14 @@ uint8_t IEC6205675::getString(uint8_t* obis, int matchlength, const char* ptr, c return 0; } -double IEC6205675::getNumber(uint8_t* obis, int matchlength, const char* ptr) { +float IEC6205675::getNumber(uint8_t* obis, int matchlength, const char* ptr) { CosemData* item = findObis(obis, matchlength, ptr); return getNumber(item); } -double IEC6205675::getNumber(CosemData* item) { +float IEC6205675::getNumber(CosemData* item) { if(item != NULL) { - double ret = 0.0; + float ret = 0.0; char* pos = ((char*) item); switch(item->base.type) { case CosemTypeLongSigned: { diff --git a/src/IEC6205675.h b/src/IEC6205675.h index 9b5f9093..d3b2aa10 100644 --- a/src/IEC6205675.h +++ b/src/IEC6205675.h @@ -21,8 +21,8 @@ private: CosemData* getCosemDataAt(uint8_t index, const char* ptr); CosemData* findObis(uint8_t* obis, int matchlength, const char* ptr); uint8_t getString(uint8_t* obis, int matchlength, const char* ptr, char* target); - double getNumber(uint8_t* obis, int matchlength, const char* ptr); - double getNumber(CosemData*); + float getNumber(uint8_t* obis, int matchlength, const char* ptr); + float getNumber(CosemData*); time_t getTimestamp(uint8_t* obis, int matchlength, const char* ptr); uint8_t AMS_OBIS_VERSION[4] = { 0, 2, 129, 255 };