diff --git a/src/AmsData.h b/src/AmsData.h index 05d506f3..0f8c87df 100644 --- a/src/AmsData.h +++ b/src/AmsData.h @@ -69,7 +69,7 @@ protected: String listId, meterId, meterModel; time_t meterTimestamp = 0; uint16_t activeImportPower = 0, reactiveImportPower = 0, activeExportPower = 0, reactiveExportPower = 0; - double l1voltage = 0, l2voltage = 0, l3voltage = 0, l1current = 0, l2current = 0, l3current = 0; + float l1voltage = 0, l2voltage = 0, l3voltage = 0, l1current = 0, l2current = 0, l3current = 0; float powerFactor = 0, l1PowerFactor = 0, l2PowerFactor = 0, l3PowerFactor = 0; float activeImportCounter = 0, reactiveImportCounter = 0, activeExportCounter = 0, reactiveExportCounter = 0; bool threePhase = false, twoPhase = false, counterEstimated = false; diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index b6966391..87da55bd 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -686,11 +686,12 @@ void swapWifiMode() { } int len = 0; -uint8_t buf[BUF_SIZE]; +uint8_t* buf = NULL; MbusAssembler* ma = NULL; int currentMeterType = -1; bool readHanPort() { if(!hanSerial->available()) return false; + if(buf == NULL) buf = (uint8_t*) malloc(BUF_SIZE); if(currentMeterType == -1) { hanSerial->readBytes(buf, BUF_SIZE); @@ -844,17 +845,19 @@ bool readHanPort() { hw.ledBlink(LED_INTERNAL, 1); if(mqttEnabled && mqttHandler != NULL && mqtt != NULL) { if(mqttHandler->publish(&data, &meterState)) { + mqtt->loop(); + delay(10); if(data.getListType() == 3 && eapi != NULL) { mqttHandler->publishPrices(eapi); + mqtt->loop(); + delay(10); } if(data.getListType() >= 2) { mqttHandler->publishSystem(&hw); + mqtt->loop(); + delay(10); } } - if(mqtt != NULL) { - mqtt->loop(); - delay(10); - } } time_t now = time(nullptr); diff --git a/src/IEC6205675.cpp b/src/IEC6205675.cpp index 76f04d2d..0457b0c7 100644 --- a/src/IEC6205675.cpp +++ b/src/IEC6205675.cpp @@ -352,7 +352,7 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, uint8_t distribution if(l2current == 0.0 && l1current > 0.0 && l3current > 0.0) { l2current = (((activeImportPower - activeExportPower) * sqrt(3)) - (l1voltage * l1current) - (l3voltage * l3current)) / l2voltage; if(activeExportPower == 0.0) { - l2current = max((double) 0.0, l2current); + l2current = max((float) 0.0, l2current); } } } else if(twoPhase && l1current > 0.0 && l2current > 0.0 && l3current > 0.0) { @@ -394,6 +394,7 @@ CosemData* IEC6205675::getCosemDataAt(uint8_t index, const char* ptr) { pos += 2; } i++; + if(pos-ptr > 900) break; } while(item->base.type != HDLC_FLAG); return NULL; } @@ -437,6 +438,7 @@ CosemData* IEC6205675::findObis(uint8_t* obis, int matchlength, const char* ptr) default: pos += 2; } + if(pos-ptr > 900) break; } while(item->base.type != HDLC_FLAG); return NULL; } diff --git a/src/IEC6205675.h b/src/IEC6205675.h index fabd7211..089da58c 100644 --- a/src/IEC6205675.h +++ b/src/IEC6205675.h @@ -31,26 +31,12 @@ private: uint8_t AMS_OBIS_METER_ID_2[4] = { 0, 0, 5, 255 }; uint8_t AMS_OBIS_METER_TIMESTAMP[4] = { 1, 0, 0, 255 }; uint8_t AMS_OBIS_ACTIVE_IMPORT[4] = { 1, 7, 0, 255 }; - uint8_t AMS_OBIS_ACTIVE_IMPORT_L1[4] = { 21, 7, 0, 255 }; - uint8_t AMS_OBIS_ACTIVE_IMPORT_L2[4] = { 41, 7, 0, 255 }; - uint8_t AMS_OBIS_ACTIVE_IMPORT_L3[4] = { 61, 7, 0, 255 }; uint8_t AMS_OBIS_ACTIVE_EXPORT[4] = { 2, 7, 0, 255 }; - uint8_t AMS_OBIS_ACTIVE_EXPORT_L1[4] = { 22, 7, 0, 255 }; - uint8_t AMS_OBIS_ACTIVE_EXPORT_L2[4] = { 42, 7, 0, 255 }; - uint8_t AMS_OBIS_ACTIVE_EXPORT_L3[4] = { 62, 7, 0, 255 }; uint8_t AMS_OBIS_REACTIVE_IMPORT[4] = { 3, 7, 0, 255 }; - uint8_t AMS_OBIS_REACTIVE_IMPORT_L1[4] = { 23, 7, 0, 255 }; - uint8_t AMS_OBIS_REACTIVE_IMPORT_L2[4] = { 43, 7, 0, 255 }; - uint8_t AMS_OBIS_REACTIVE_IMPORT_L3[4] = { 63, 7, 0, 255 }; uint8_t AMS_OBIS_REACTIVE_EXPORT[4] = { 4, 7, 0, 255 }; - uint8_t AMS_OBIS_REACTIVE_EXPORT_L1[4] = { 24, 7, 0, 255 }; - uint8_t AMS_OBIS_REACTIVE_EXPORT_L2[4] = { 44, 7, 0, 255 }; - uint8_t AMS_OBIS_REACTIVE_EXPORT_L3[4] = { 64, 7, 0, 255 }; - uint8_t AMS_OBIS_CURRENT[4] = { 11, 7, 0, 255 }; uint8_t AMS_OBIS_CURRENT_L1[4] = { 31, 7, 0, 255 }; uint8_t AMS_OBIS_CURRENT_L2[4] = { 51, 7, 0, 255 }; uint8_t AMS_OBIS_CURRENT_L3[4] = { 71, 7, 0, 255 }; - uint8_t AMS_OBIS_VOLTAGE[4] = { 12, 7, 0, 255 }; uint8_t AMS_OBIS_VOLTAGE_L1[4] = { 32, 7, 0, 255 }; uint8_t AMS_OBIS_VOLTAGE_L2[4] = { 52, 7, 0, 255 }; uint8_t AMS_OBIS_VOLTAGE_L3[4] = { 72, 7, 0, 255 }; diff --git a/src/entsoe/EntsoeApi.cpp b/src/entsoe/EntsoeApi.cpp index 3226e930..eef9dfd2 100644 --- a/src/entsoe/EntsoeApi.cpp +++ b/src/entsoe/EntsoeApi.cpp @@ -9,6 +9,8 @@ #endif EntsoeApi::EntsoeApi(RemoteDebug* Debug) { + this->buf = (char*) malloc(BufferSize); + debugger = Debug; client.setInsecure(); @@ -120,8 +122,7 @@ bool EntsoeApi::loop() { breakTime(e1, d1); breakTime(e2, d2); - char url[256]; - snprintf(url, sizeof(url), "%s?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s", + 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://transparency.entsoe.eu/api", getToken(), d1.Year+1970, d1.Month, d1.Day, 23, 00, d2.Year+1970, d2.Month, d2.Day, 23, 00, @@ -135,9 +136,9 @@ bool EntsoeApi::loop() { if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Fetching prices for today\n"); - if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", url); + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", buf); EntsoeA44Parser* a44 = new EntsoeA44Parser(); - if(retrieve(url, a44) && a44->getPoint(0) != ENTSOE_NO_VALUE) { + if(retrieve(buf, a44) && a44->getPoint(0) != ENTSOE_NO_VALUE) { today = a44; return true; } else if(a44 != NULL) { @@ -160,8 +161,7 @@ bool EntsoeApi::loop() { breakTime(e1, d1); breakTime(e2, d2); - char url[256]; - snprintf(url, sizeof(url), "%s?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s", + 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://transparency.entsoe.eu/api", getToken(), d1.Year+1970, d1.Month, d1.Day, 23, 00, d2.Year+1970, d2.Month, d2.Day, 23, 00, @@ -174,9 +174,9 @@ bool EntsoeApi::loop() { #endif if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Fetching prices for tomorrow\n"); - if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", url); + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", buf); EntsoeA44Parser* a44 = new EntsoeA44Parser(); - if(retrieve(url, a44) && a44->getPoint(0) != ENTSOE_NO_VALUE) { + if(retrieve(buf, a44) && a44->getPoint(0) != ENTSOE_NO_VALUE) { tomorrow = a44; return true; } else if(a44 != NULL) { @@ -273,7 +273,6 @@ float EntsoeApi::getCurrencyMultiplier(const char* from, const char* to) { if(now > lastCurrencyFetch && (now - lastCurrencyFetch) < 900000) { lastCurrencyFetch = now; - char url[256]; DnbCurrParser p; #if defined(ESP32) @@ -282,17 +281,17 @@ float EntsoeApi::getCurrencyMultiplier(const char* from, const char* to) { ESP.wdtFeed(); #endif - snprintf(url, sizeof(url), "https://data.norges-bank.no/api/data/EXR/M.%s.NOK.SP?lastNObservations=1", from); + snprintf(buf, BufferSize, "https://data.norges-bank.no/api/data/EXR/M.%s.NOK.SP?lastNObservations=1", from); if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Retrieving %s to NOK conversion\n", from); - if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", url); - if(retrieve(url, &p)) { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", buf); + if(retrieve(buf, &p)) { if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) got exchange rate %.4f\n", p.getValue()); currencyMultiplier = p.getValue(); if(strncmp(to, "NOK", 3) != 0) { - snprintf(url, sizeof(url), "https://data.norges-bank.no/api/data/EXR/M.%s.NOK.SP?lastNObservations=1", to); + snprintf(buf, BufferSize, "https://data.norges-bank.no/api/data/EXR/M.%s.NOK.SP?lastNObservations=1", to); if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Retrieving %s to NOK conversion\n", to); - if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", url); - if(retrieve(url, &p)) { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", buf); + if(retrieve(buf, &p)) { if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) got exchange rate %.4f\n", p.getValue()); currencyMultiplier /= p.getValue(); } else { diff --git a/src/entsoe/EntsoeApi.h b/src/entsoe/EntsoeApi.h index 9ec5d788..6c07179a 100644 --- a/src/entsoe/EntsoeApi.h +++ b/src/entsoe/EntsoeApi.h @@ -45,6 +45,9 @@ private: Timezone* tz = NULL; + static const uint16_t BufferSize = 256; + char* buf; + float currencyMultiplier = ENTSOE_DEFAULT_MULTIPLIER; bool retrieve(const char* url, Stream* doc); diff --git a/src/mqtt/DomoticzMqttHandler.cpp b/src/mqtt/DomoticzMqttHandler.cpp index 262b2d92..1edd15b0 100644 --- a/src/mqtt/DomoticzMqttHandler.cpp +++ b/src/mqtt/DomoticzMqttHandler.cpp @@ -10,8 +10,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState) { if(energy > 0.0) { char val[16]; snprintf(val, 16, "%.1f;%.1f", (data->getActiveImportPower()/1.0), energy*1000.0); - char json[192]; - snprintf_P(json, sizeof(json), DOMOTICZ_JSON, + snprintf_P(json, BufferSize, DOMOTICZ_JSON, config.elidx, val ); @@ -25,8 +24,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState) { if (config.vl1idx > 0){ char val[16]; snprintf(val, 16, "%.2f", data->getL1Voltage()); - char json[192]; - snprintf_P(json, sizeof(json), DOMOTICZ_JSON, + snprintf_P(json, BufferSize, DOMOTICZ_JSON, config.vl1idx, val ); @@ -36,8 +34,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState) { if (config.vl2idx > 0){ char val[16]; snprintf(val, 16, "%.2f", data->getL2Voltage()); - char json[192]; - snprintf_P(json, sizeof(json), DOMOTICZ_JSON, + snprintf_P(json, BufferSize, DOMOTICZ_JSON, config.vl2idx, val ); @@ -47,8 +44,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState) { if (config.vl3idx > 0){ char val[16]; snprintf(val, 16, "%.2f", data->getL3Voltage()); - char json[192]; - snprintf_P(json, sizeof(json), DOMOTICZ_JSON, + snprintf_P(json, BufferSize, DOMOTICZ_JSON, config.vl3idx, val ); @@ -58,8 +54,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState) { if (config.cl1idx > 0){ char val[16]; snprintf(val, 16, "%.1f;%.1f;%.1f", data->getL1Current(), data->getL2Current(), data->getL3Current()); - char json[192]; - snprintf_P(json, sizeof(json), DOMOTICZ_JSON, + snprintf_P(json, BufferSize, DOMOTICZ_JSON, config.cl1idx, val ); diff --git a/src/mqtt/DomoticzMqttHandler.h b/src/mqtt/DomoticzMqttHandler.h index 408f0d75..2dc28366 100644 --- a/src/mqtt/DomoticzMqttHandler.h +++ b/src/mqtt/DomoticzMqttHandler.h @@ -8,14 +8,19 @@ class DomoticzMqttHandler : public AmsMqttHandler { public: DomoticzMqttHandler(MQTTClient* mqtt, DomoticzConfig config) : AmsMqttHandler(mqtt) { this->config = config; + this->json = (char*) malloc(BufferSize); }; bool publish(AmsData* data, AmsData* previousState); bool publishTemperatures(AmsConfiguration*, HwTools*); bool publishPrices(EntsoeApi*); bool publishSystem(HwTools*); + static const uint16_t BufferSize = 192; + private: DomoticzConfig config; int energy = 0.0; + char* json; }; + #endif diff --git a/src/mqtt/JsonMqttHandler.cpp b/src/mqtt/JsonMqttHandler.cpp index 9c35bd50..21dd0ac1 100644 --- a/src/mqtt/JsonMqttHandler.cpp +++ b/src/mqtt/JsonMqttHandler.cpp @@ -13,8 +13,7 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState) { return false; if(data->getListType() == 1) { - char json[256]; - snprintf_P(json, sizeof(json), JSON1_JSON, + snprintf_P(json, BufferSize, JSON1_JSON, WiFi.macAddress().c_str(), clientId.c_str(), (uint32_t) (millis64()/1000), @@ -26,8 +25,7 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState) { ); return mqtt->publish(topic, json); } else if(data->getListType() == 2) { - char json[512]; - snprintf_P(json, sizeof(json), JSON2_JSON, + snprintf_P(json, BufferSize, JSON2_JSON, WiFi.macAddress().c_str(), clientId.c_str(), (uint32_t) (millis64()/1000), @@ -52,8 +50,7 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState) { return mqtt->publish(topic, json); } else if(data->getListType() == 3) { if(data->getPowerFactor() == 0) { - char json[768]; - snprintf_P(json, sizeof(json), JSON3_JSON, + snprintf_P(json, BufferSize, JSON3_JSON, WiFi.macAddress().c_str(), clientId.c_str(), (uint32_t) (millis64()/1000), @@ -82,8 +79,7 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState) { ); return mqtt->publish(topic, json); } else { - char json[768]; - snprintf_P(json, sizeof(json), JSON3PF_JSON, + snprintf_P(json, BufferSize, JSON3PF_JSON, WiFi.macAddress().c_str(), clientId.c_str(), (uint32_t) (millis64()/1000), @@ -229,8 +225,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) { sprintf(ts6hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour); } - char json[384]; - snprintf_P(json, sizeof(json), JSONPRICES_JSON, + snprintf_P(json, BufferSize, JSONPRICES_JSON, WiFi.macAddress().c_str(), values[0], values[1], @@ -257,8 +252,7 @@ bool JsonMqttHandler::publishSystem(HwTools* hw) { if(init || topic.isEmpty() || !mqtt->connected()) return false; - char json[192]; - snprintf_P(json, sizeof(json), JSONSYS_JSON, + snprintf_P(json, BufferSize, JSONSYS_JSON, WiFi.macAddress().c_str(), clientId.c_str(), (uint32_t) (millis64()/1000), diff --git a/src/mqtt/JsonMqttHandler.h b/src/mqtt/JsonMqttHandler.h index c8f45d03..72fe247c 100644 --- a/src/mqtt/JsonMqttHandler.h +++ b/src/mqtt/JsonMqttHandler.h @@ -9,16 +9,20 @@ public: this->clientId = clientId; this->topic = String(topic); this->hw = hw; + this->json = (char*) malloc(BufferSize); }; bool publish(AmsData* data, AmsData* previousState); bool publishTemperatures(AmsConfiguration*, HwTools*); bool publishPrices(EntsoeApi*); bool publishSystem(HwTools*); + static const uint16_t BufferSize = 768; + private: String clientId; String topic; HwTools* hw; bool init = false; + char* json; }; #endif diff --git a/src/mqtt/RawMqttHandler.h b/src/mqtt/RawMqttHandler.h index f312875c..639a7e4b 100644 --- a/src/mqtt/RawMqttHandler.h +++ b/src/mqtt/RawMqttHandler.h @@ -14,6 +14,8 @@ public: bool publishPrices(EntsoeApi*); bool publishSystem(HwTools*); + static const uint16_t BufferSize = 128; + private: String topic; bool full; diff --git a/src/web/AmsWebServer.cpp b/src/web/AmsWebServer.cpp index 0ea83a97..d5aeacb9 100644 --- a/src/web/AmsWebServer.cpp +++ b/src/web/AmsWebServer.cpp @@ -54,6 +54,7 @@ AmsWebServer::AmsWebServer(RemoteDebug* Debug, HwTools* hw) { this->debugger = Debug; this->hw = hw; + this->json = (char*) malloc(JsonSize); } void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, MeterConfig* meterConfig, AmsData* meterState, AmsDataStorage* ds) { @@ -754,8 +755,7 @@ void AmsWebServer::dataJson() { if(eapi != NULL && strlen(eapi->getToken()) > 0) price = eapi->getValueForHour(0); - char json[512]; - snprintf_P(json, sizeof(json), DATA_JSON, + snprintf_P(json, JsonSize, DATA_JSON, maxPwr == 0 ? meterState->isThreePhase() ? 20000 : 10000 : maxPwr, meterConfig->productionCapacity, meterConfig->mainFuse == 0 ? 32 : meterConfig->mainFuse, @@ -806,8 +806,7 @@ void AmsWebServer::dayplotJson() { if(ds == NULL) { notFound(); } else { - char json[384]; - snprintf_P(json, sizeof(json), DAYPLOT_JSON, + snprintf_P(json, JsonSize, DAYPLOT_JSON, ds->getHour(0) / 1000.0, ds->getHour(1) / 1000.0, ds->getHour(2) / 1000.0, @@ -849,8 +848,7 @@ void AmsWebServer::monthplotJson() { if(ds == NULL) { notFound(); } else { - char json[512]; - snprintf_P(json, sizeof(json), MONTHPLOT_JSON, + snprintf_P(json, JsonSize, MONTHPLOT_JSON, ds->getDay(1) / 1000.0, ds->getDay(2) / 1000.0, ds->getDay(3) / 1000.0, @@ -901,8 +899,7 @@ void AmsWebServer::energyPriceJson() { prices[i] = eapi == NULL ? ENTSOE_NO_VALUE : eapi->getValueForHour(i); } - char json[768]; - snprintf_P(json, sizeof(json), ENERGYPRICE_JSON, + snprintf_P(json, JsonSize, ENERGYPRICE_JSON, eapi == NULL ? "" : eapi->getCurrency(), prices[0] == ENTSOE_NO_VALUE ? "null" : String(prices[0], 2).c_str(), prices[1] == ENTSOE_NO_VALUE ? "null" : String(prices[1], 2).c_str(), diff --git a/src/web/AmsWebServer.h b/src/web/AmsWebServer.h index ba4d952f..b26df31c 100644 --- a/src/web/AmsWebServer.h +++ b/src/web/AmsWebServer.h @@ -55,6 +55,9 @@ private: File file; bool performRestart = false; + static const uint16_t JsonSize = 768; + char* json; + #if defined(ESP8266) ESP8266WebServer server; #elif defined(ESP32) // ARDUINO_ARCH_ESP32