diff --git a/lib/HanReader/src/Aidon.h b/lib/HanReader/src/Aidon.h index ffe0dc87..dbac985a 100644 --- a/lib/HanReader/src/Aidon.h +++ b/lib/HanReader/src/Aidon.h @@ -3,7 +3,6 @@ #ifndef _AIDON_h #define _AIDON_h - enum class Aidon { List1 = 0x01, diff --git a/lib/HanReader/src/HanReader.cpp b/lib/HanReader/src/HanReader.cpp index 9d6df8b4..40b0eac6 100644 --- a/lib/HanReader/src/HanReader.cpp +++ b/lib/HanReader/src/HanReader.cpp @@ -80,10 +80,10 @@ void HanReader::debugPrint(byte *buffer, int start, int length) bool HanReader::read() { - if (han->available()) - { - byte newByte = han->read(); - return read(newByte); + while(han->available()) { + if(read(han->read())) { + return true; + } } return false; } diff --git a/lib/HanReader/src/Kamstrup.h b/lib/HanReader/src/Kamstrup.h index 71513916..7cb3470e 100644 --- a/lib/HanReader/src/Kamstrup.h +++ b/lib/HanReader/src/Kamstrup.h @@ -3,7 +3,6 @@ #ifndef _KAMSTRUP_h #define _KAMSTRUP_h - enum class Kamstrup { List3PhaseShort = 0x19, diff --git a/lib/HanToJson/library.properties b/lib/HanToJson/library.properties deleted file mode 100644 index 204ea958..00000000 --- a/lib/HanToJson/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=HanToJson -version=1.0.0 -author=roarfred -maintainer=roarfred -sentence=HAN reader data to Json -paragraph=HAN reader data to Json -category=Sensors -url=https://github.com/roarfred/AmsToMqttBridge -architectures=* diff --git a/lib/HanToJson/src/HanToJson.cpp b/lib/HanToJson/src/HanToJson.cpp deleted file mode 100644 index 77b6c9a5..00000000 --- a/lib/HanToJson/src/HanToJson.cpp +++ /dev/null @@ -1,287 +0,0 @@ -#include "HanToJson.h" -#include "Aidon.h" -#include "Kaifa.h" -#include "Kamstrup.h" - - -static void hanToJsonKaifa3phase(int listSize, JsonObject& data, HanReader& hanReader, Stream *debugger) -{ - if (listSize >= (int)Kaifa::List3PhaseShort) - { - data["lv"] = hanReader.getString( (int)Kaifa_List3Phase::ListVersionIdentifier); - data["id"] = hanReader.getString( (int)Kaifa_List3Phase::MeterID); - data["type"] = hanReader.getString( (int)Kaifa_List3Phase::MeterType); - data["P"] = hanReader.getInt( (int)Kaifa_List3Phase::ActiveImportPower); - data["Q"] = hanReader.getInt( (int)Kaifa_List3Phase::ReactiveImportPower); - data["PO"] = hanReader.getInt( (int)Kaifa_List3Phase::ActiveExportPower); - data["QO"] = hanReader.getInt( (int)Kaifa_List3Phase::ReactiveExportPower); - data["I1"] = ((double) hanReader.getInt((int)Kaifa_List3Phase::CurrentL1)) / 1000; - data["I2"] = ((double) hanReader.getInt((int)Kaifa_List3Phase::CurrentL2)) / 1000; - data["I3"] = ((double) hanReader.getInt((int)Kaifa_List3Phase::CurrentL3)) / 1000; - data["U1"] = ((double) hanReader.getInt((int)Kaifa_List3Phase::VoltageL1)) / 10; - data["U2"] = ((double) hanReader.getInt((int)Kaifa_List3Phase::VoltageL2)) / 10; - data["U3"] = ((double) hanReader.getInt((int)Kaifa_List3Phase::VoltageL3)) / 10; - } - - if (listSize >= (int)Kaifa::List3PhaseLong) - { - data["rtc"] = hanReader.getTime( (int)Kaifa_List3Phase::MeterClock); - data["tPI"] = hanReader.getInt( (int)Kaifa_List3Phase::CumulativeActiveImportEnergy); - data["tPO"] = hanReader.getInt( (int)Kaifa_List3Phase::CumulativeActiveExportEnergy); - data["tQI"] = hanReader.getInt( (int)Kaifa_List3Phase::CumulativeReactiveImportEnergy); - data["tQO"] = hanReader.getInt( (int)Kaifa_List3Phase::CumulativeReactiveExportEnergy); - } -} - -static void hanToJsonKaifa1phase(int listSize, JsonObject& data, HanReader& hanReader, Stream *debugger) -{ - if (listSize >= (int)Kaifa::List1PhaseShort) - { - data["lv"] = hanReader.getString( (int)Kaifa_List1Phase::ListVersionIdentifier); - data["id"] = hanReader.getString( (int)Kaifa_List1Phase::MeterID); - data["type"] = hanReader.getString( (int)Kaifa_List1Phase::MeterType); - data["P"] = hanReader.getInt( (int)Kaifa_List1Phase::ActiveImportPower); - data["Q"] = hanReader.getInt( (int)Kaifa_List1Phase::ReactiveImportPower); - data["PO"] = hanReader.getInt( (int)Kaifa_List1Phase::ActiveExportPower); - data["QO"] = hanReader.getInt( (int)Kaifa_List1Phase::ReactiveExportPower); - data["I1"] = ((double) hanReader.getInt((int)Kaifa_List1Phase::CurrentL1)) / 1000; - data["U1"] = ((double) hanReader.getInt((int)Kaifa_List1Phase::VoltageL1)) / 10; - } - - if (listSize >= (int)Kaifa::List1PhaseLong) - { - data["rtc"] = hanReader.getTime( (int)Kaifa_List1Phase::MeterClock); - data["tPI"] = hanReader.getInt( (int)Kaifa_List1Phase::CumulativeActiveImportEnergy); - data["tPO"] = hanReader.getInt( (int)Kaifa_List1Phase::CumulativeActiveExportEnergy); - data["tQI"] = hanReader.getInt( (int)Kaifa_List1Phase::CumulativeReactiveImportEnergy); - data["tQO"] = hanReader.getInt( (int)Kaifa_List1Phase::CumulativeReactiveExportEnergy); - } -} - -static void hanToJsonKaifa(JsonObject& data, HanReader& hanReader, Stream *debugger) -{ - int listSize = hanReader.getListSize(); - - if (listSize == (int)Kaifa::List1) - { - // Handle listSize == 1 specially - data["P"] = hanReader.getInt( (int)Kaifa_List1::ActivePowerImported); - return; - } - - switch (listSize) { - case (int)Kaifa::List3PhaseShort: - case (int)Kaifa::List3PhaseLong: - return hanToJsonKaifa3phase(listSize, data, hanReader, debugger); - case (int)Kaifa::List1PhaseShort: - case (int)Kaifa::List1PhaseLong: - return hanToJsonKaifa1phase(listSize, data, hanReader, debugger); - default: - if (debugger) debugger->printf("Warning: Unknown listSize %d\n", listSize); - return; - } -} - - -static void hanToJsonAidon3phase(int listSize, JsonObject& data, HanReader& hanReader, Stream *debugger) { - if (listSize >= (int)Aidon::List3PhaseShort) { - data["lv"] = hanReader.getString( (int)Aidon_List3Phase::ListVersionIdentifier); - data["id"] = hanReader.getString( (int)Aidon_List3Phase::MeterID); - data["type"] = hanReader.getString( (int)Aidon_List3Phase::MeterType); - data["P"] = hanReader.getInt( (int)Aidon_List3Phase::ActiveImportPower); - data["Q"] = hanReader.getInt( (int)Aidon_List3Phase::ReactiveImportPower); - data["PO"] = hanReader.getInt( (int)Aidon_List3Phase::ActiveExportPower); - data["QO"] = hanReader.getInt( (int)Aidon_List3Phase::ReactiveExportPower); - data["I1"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::CurrentL1)) / 10; - data["I2"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::CurrentL2)) / 10; - data["I3"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::CurrentL3)) / 10; - data["U1"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::VoltageL1)) / 10; - data["U2"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::VoltageL2)) / 10; - data["U3"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::VoltageL3)) / 10; - } - - if (listSize >= (int)Aidon::List3PhaseLong) - { - data["rtc"] = hanReader.getTime( (int)Aidon_List3Phase::Timestamp); - data["tPI"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::CumulativeActiveImportEnergy)) / 100; - data["tPO"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::CumulativeActiveExportEnergy)) / 100; - data["tQI"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::CumulativeReactiveImportEnergy)) / 100; - data["tQO"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::CumulativeReactiveExportEnergy)) / 100; - } -} - -static void hanToJsonAidon1phase(int listSize, JsonObject& data, HanReader& hanReader, Stream *debugger) -{ - if (listSize >= (int)Aidon::List1PhaseShort) - { - data["lv"] = hanReader.getString( (int)Aidon_List1Phase::ListVersionIdentifier); - data["id"] = hanReader.getString( (int)Aidon_List1Phase::MeterID); - data["type"] = hanReader.getString( (int)Aidon_List1Phase::MeterType); - data["P"] = hanReader.getInt( (int)Aidon_List1Phase::ActiveImportPower); - data["Q"] = hanReader.getInt( (int)Aidon_List1Phase::ReactiveImportPower); - data["PO"] = hanReader.getInt( (int)Aidon_List1Phase::ActiveExportPower); - data["QO"] = hanReader.getInt( (int)Aidon_List1Phase::ReactiveExportPower); - data["I1"] = ((double) hanReader.getInt( (int)Aidon_List1Phase::CurrentL1)) / 10; - data["U1"] = ((double) hanReader.getInt( (int)Aidon_List1Phase::VoltageL1)) / 10; - } - - if (listSize >= (int)Aidon::List1PhaseLong) - { - data["rtc"] = hanReader.getTime( (int)Aidon_List1Phase::Timestamp); - data["tPI"] = ((double) hanReader.getInt( (int)Aidon_List1Phase::CumulativeActiveImportEnergy)) / 100; - data["tPO"] = ((double) hanReader.getInt( (int)Aidon_List1Phase::CumulativeActiveExportEnergy)) / 100; - data["tQI"] = ((double) hanReader.getInt( (int)Aidon_List1Phase::CumulativeReactiveImportEnergy)) / 100; - data["tQO"] = ((double) hanReader.getInt( (int)Aidon_List1Phase::CumulativeReactiveExportEnergy)) / 100; - } -} - -static void hanToJsonAidon3phaseIT(int listSize, JsonObject& data, HanReader& hanReader, Stream *debugger) -{ - if (listSize >= (int)Aidon::List3PhaseITShort) - { - data["lv"] = hanReader.getString( (int)Aidon_List3PhaseIT::ListVersionIdentifier); - data["id"] = hanReader.getString( (int)Aidon_List3PhaseIT::MeterID); - data["type"] = hanReader.getString( (int)Aidon_List3PhaseIT::MeterType); - data["P"] = hanReader.getInt( (int)Aidon_List3PhaseIT::ActiveImportPower); - data["Q"] = hanReader.getInt( (int)Aidon_List3PhaseIT::ReactiveImportPower); - data["PO"] = hanReader.getInt( (int)Aidon_List3PhaseIT::ActiveExportPower); - data["QO"] = hanReader.getInt( (int)Aidon_List3PhaseIT::ReactiveExportPower); - data["I1"] = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CurrentL1)) / 10; - data["I2"] = 0; - data["I3"] = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CurrentL3)) / 10; - data["U1"] = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::VoltageL1)) / 10; - data["U2"] = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::VoltageL2)) / 10; - data["U3"] = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::VoltageL3)) / 10; - } - - if (listSize >= (int)Aidon::List3PhaseITLong) - { - data["rtc"] = hanReader.getTime( (int)Aidon_List3PhaseIT::Timestamp); - data["tPI"] = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CumulativeActiveImportEnergy)) / 100; - data["tPO"] = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CumulativeActiveExportEnergy)) / 100; - data["tQI"] = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CumulativeReactiveImportEnergy)) / 100; - data["tQO"] = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CumulativeReactiveExportEnergy)) / 100; - } -} - -static void hanToJsonAidon(JsonObject& data, HanReader& hanReader, Stream *debugger) -{ - int listSize = hanReader.getListSize(); - - // Based on the list number, get all details - // according to OBIS specifications for the meter - if (listSize == (int)Aidon::List1) - { - // Handle listSize == 1 specially - data["P"] = hanReader.getInt((int)Aidon_List1::ActiveImportPower); - return; - } - - switch (listSize) { - case (int)Aidon::List3PhaseShort: - case (int)Aidon::List3PhaseLong: - return hanToJsonAidon3phase(listSize, data, hanReader, debugger); - case (int)Aidon::List1PhaseShort: - case (int)Aidon::List1PhaseLong: - return hanToJsonAidon1phase(listSize, data, hanReader, debugger); - case (int)Aidon::List3PhaseITShort: - case (int)Aidon::List3PhaseITLong: - return hanToJsonAidon3phaseIT(listSize, data, hanReader, debugger); - default: - if (debugger) debugger->printf("Warning: Unknown listSize %d\n", listSize); - return; - } -} - -static void hanToJsonKamstrup3phase(int listSize, JsonObject& data, HanReader& hanReader, Stream *debugger) { - if (listSize >= (int)Kamstrup::List3PhaseShort) { - data["lv"] = hanReader.getString( (int)Kamstrup_List3Phase::ListVersionIdentifier); - data["id"] = hanReader.getString( (int)Kamstrup_List3Phase::MeterID); - data["type"] = hanReader.getString( (int)Kamstrup_List3Phase::MeterType); - data["P"] = hanReader.getInt( (int)Kamstrup_List3Phase::ActiveImportPower); - data["Q"] = hanReader.getInt( (int)Kamstrup_List3Phase::ReactiveImportPower); - data["PO"] = hanReader.getInt( (int)Kamstrup_List3Phase::ActiveExportPower); - data["QO"] = hanReader.getInt( (int)Kamstrup_List3Phase::ReactiveExportPower); - data["I1"] = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CurrentL1)) / 100; - data["I2"] = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CurrentL2)) / 100; - data["I3"] = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CurrentL3)) / 100; - data["U1"] = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL1); - data["U2"] = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL2); - data["U3"] = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL3); - } - - if (listSize >= (int)Kamstrup::List3PhaseLong) - { - data["rtc"] = hanReader.getTime( (int)Kamstrup_List3Phase::MeterClock); - data["tPI"] = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeActiveImportEnergy)) / 100; - data["tPO"] = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeActiveExportEnergy)) / 100; - data["tQI"] = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeReactiveImportEnergy)) / 100; - data["tQO"] = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeReactiveExportEnergy)) / 100; - } -} - -static void hanToJsonKamstrup1phase(int listSize, JsonObject& data, HanReader& hanReader, Stream *debugger) { - if (listSize >= (int)Kamstrup::List1PhaseShort) { - data["lv"] = hanReader.getString( (int)Kamstrup_List1Phase::ListVersionIdentifier); - data["id"] = hanReader.getString( (int)Kamstrup_List1Phase::MeterID); - data["type"] = hanReader.getString( (int)Kamstrup_List1Phase::MeterType); - data["P"] = hanReader.getInt( (int)Kamstrup_List1Phase::ActiveImportPower); - data["Q"] = hanReader.getInt( (int)Kamstrup_List1Phase::ReactiveImportPower); - data["PO"] = hanReader.getInt( (int)Kamstrup_List1Phase::ActiveExportPower); - data["QO"] = hanReader.getInt( (int)Kamstrup_List1Phase::ReactiveExportPower); - data["I1"] = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CurrentL1)) / 100; - data["U1"] = hanReader.getInt( (int)Kamstrup_List1Phase::VoltageL1); - } - - if (listSize >= (int)Kamstrup::List1PhaseLong) - { - data["rtc"] = hanReader.getTime( (int)Kamstrup_List1Phase::MeterClock); - data["tPI"] = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeActiveImportEnergy)) / 100; - data["tPO"] = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeActiveExportEnergy)) / 100; - data["tQI"] = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeReactiveImportEnergy)) / 100; - data["tQO"] = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeReactiveExportEnergy)) / 100; - } -} - -static void hanToJsonKamstrup(JsonObject& data, HanReader& hanReader, Stream *debugger) { - int listSize = hanReader.getListSize(); - - switch (listSize) { - case (int)Kamstrup::List3PhaseShort: - case (int)Kamstrup::List3PhaseLong: - return hanToJsonKamstrup3phase(listSize, data, hanReader, debugger); - case (int)Kamstrup::List1PhaseShort: - case (int)Kamstrup::List1PhaseLong: - return hanToJsonKamstrup1phase(listSize, data, hanReader, debugger); - default: - if (debugger) debugger->printf("Warning: Unknown listSize %d\n", listSize); - return; - } -} - -void hanToJson(JsonObject& data, byte meterType, HanReader& hanReader, Stream *debugger) -{ - // Based on the list number, get all details - // according to OBIS specifications for the meter - switch (meterType) - { - case 1: // Kaifa - return hanToJsonKaifa(data, hanReader, debugger); - case 2: // Aidon - return hanToJsonAidon(data, hanReader, debugger); - case 3: // Kamstrup - return hanToJsonKamstrup(data, hanReader, debugger); - default: - if (debugger) { - debugger->print("Meter type "); - debugger->print(meterType, HEX); - debugger->println(" is unknown"); - } - break; - } -} - -void hanToJson(JsonObject& data, byte meterType, HanReader& hanReader) -{ - return hanToJson(data, meterType, hanReader, NULL); -} diff --git a/lib/HanToJson/src/HanToJson.h b/lib/HanToJson/src/HanToJson.h deleted file mode 100644 index a06f4caf..00000000 --- a/lib/HanToJson/src/HanToJson.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _HANTOJSON_h -#define _HANTOJSON_h - -#if defined(ARDUINO) && ARDUINO >= 100 - #include "Arduino.h" -#else - #include "WProgram.h" -#endif - -#include -#include "HanReader.h" - -void hanToJson(JsonObject& data, byte meterType, HanReader& hanReader); -void hanToJson(JsonObject& root, byte meterType, HanReader& hanReader, Stream *debugPort); - - -#endif diff --git a/platformio.ini b/platformio.ini index 4dddf005..e4c322ba 100755 --- a/platformio.ini +++ b/platformio.ini @@ -4,7 +4,7 @@ extra_configs = platformio-user.ini [common] framework = arduino -lib_deps = HanReader@1.0.0, HanToJson@1.0.0, ArduinoJson@6.14.1, MQTT@^2.4.7, DallasTemperature@3.8.1, EspSoftwareSerial@6.7.1, Base64@^1.0.0 +lib_deps = HanReader@1.0.0, ArduinoJson@6.14.1, MQTT@^2.4.7, DallasTemperature@3.8.1, EspSoftwareSerial@6.7.1, Base64@^1.0.0 [env:hw1esp12e] platform = espressif8266 diff --git a/src/AmsData.cpp b/src/AmsData.cpp new file mode 100644 index 00000000..8bd1ed39 --- /dev/null +++ b/src/AmsData.cpp @@ -0,0 +1,348 @@ +#include "AmsData.h" +#include "Kaifa.h" +#include "Aidon.h" +#include "Kamstrup.h" + +AmsData::AmsData() {} + +AmsData::AmsData(int meterType, HanReader& hanReader) { + lastUpdateMillis = millis(); + packageTimestamp = hanReader.getPackageTime(); + + int listSize = hanReader.getListSize(); + switch(meterType) { + case METER_TYPE_KAIFA: + extractFromKaifa(hanReader, listSize); + break; + case METER_TYPE_AIDON: + extractFromAidon(hanReader, listSize); + break; + case METER_TYPE_KAMSTRUP: + extractFromKamstrup(hanReader, listSize); + break; + + } +} + +void AmsData::extractFromKaifa(HanReader& hanReader, int listSize) { + switch(listSize) { + case (int)Kaifa::List1: + listType = 1; + break; + case (int)Kaifa::List3PhaseShort: + threePhase = true; + case (int)Kaifa::List1PhaseShort: + listType = 2; + break; + case (int)Kaifa::List3PhaseLong: + threePhase = true; + case (int)Kaifa::List1PhaseLong: + listType = 3; + break; + } + + if(listSize == (int)Kaifa::List1) { + activeImportPower = hanReader.getInt((int)Kaifa_List1::ActivePowerImported); + } else { + switch(listSize) { + case (int)Kaifa::List3PhaseLong: + meterTimestamp = hanReader.getTime( (int)Kaifa_List3Phase::MeterClock); + activeImportCounter = hanReader.getInt( (int)Kaifa_List3Phase::CumulativeActiveImportEnergy); + activeExportCounter = hanReader.getInt( (int)Kaifa_List3Phase::CumulativeActiveExportEnergy); + reactiveImportCounter = hanReader.getInt( (int)Kaifa_List3Phase::CumulativeReactiveImportEnergy); + reactiveExportCounter = hanReader.getInt( (int)Kaifa_List3Phase::CumulativeReactiveExportEnergy); + case (int)Kaifa::List3PhaseShort: + listId = hanReader.getString( (int)Kaifa_List3Phase::ListVersionIdentifier); + meterId = hanReader.getString( (int)Kaifa_List3Phase::MeterID); + meterType = hanReader.getString( (int)Kaifa_List3Phase::MeterType); + activeImportPower = hanReader.getInt( (int)Kaifa_List3Phase::ActiveImportPower); + reactiveImportPower = hanReader.getInt( (int)Kaifa_List3Phase::ReactiveImportPower); + activeExportPower = hanReader.getInt( (int)Kaifa_List3Phase::ActiveExportPower); + reactiveExportPower = hanReader.getInt( (int)Kaifa_List3Phase::ReactiveExportPower); + l1current = ((double) hanReader.getInt((int)Kaifa_List3Phase::CurrentL1)) / 1000; + l2current = ((double) hanReader.getInt((int)Kaifa_List3Phase::CurrentL2)) / 1000; + l3current = ((double) hanReader.getInt((int)Kaifa_List3Phase::CurrentL3)) / 1000; + l1voltage = ((double) hanReader.getInt((int)Kaifa_List3Phase::VoltageL1)) / 10; + l2voltage = ((double) hanReader.getInt((int)Kaifa_List3Phase::VoltageL2)) / 10; + l3voltage = ((double) hanReader.getInt((int)Kaifa_List3Phase::VoltageL3)) / 10; + break; + case (int)Kaifa::List1PhaseLong: + meterTimestamp = hanReader.getTime( (int)Kaifa_List1Phase::MeterClock); + activeImportCounter = hanReader.getInt( (int)Kaifa_List1Phase::CumulativeActiveImportEnergy); + activeExportCounter = hanReader.getInt( (int)Kaifa_List1Phase::CumulativeActiveExportEnergy); + reactiveImportCounter = hanReader.getInt( (int)Kaifa_List1Phase::CumulativeReactiveImportEnergy); + reactiveExportCounter = hanReader.getInt( (int)Kaifa_List1Phase::CumulativeReactiveExportEnergy); + case (int)Kaifa::List1PhaseShort: + listId = hanReader.getString( (int)Kaifa_List1Phase::ListVersionIdentifier); + meterId = hanReader.getString( (int)Kaifa_List1Phase::MeterID); + meterType = hanReader.getString( (int)Kaifa_List1Phase::MeterType); + activeImportPower = hanReader.getInt( (int)Kaifa_List1Phase::ActiveImportPower); + reactiveImportPower = hanReader.getInt( (int)Kaifa_List1Phase::ReactiveImportPower); + activeExportPower = hanReader.getInt( (int)Kaifa_List1Phase::ActiveExportPower); + reactiveExportPower = hanReader.getInt( (int)Kaifa_List1Phase::ReactiveExportPower); + l1current = ((double) hanReader.getInt((int)Kaifa_List1Phase::CurrentL1)) / 1000; + l1voltage = ((double) hanReader.getInt((int)Kaifa_List1Phase::VoltageL1)) / 10; + break; + } + } +} + +void AmsData::extractFromAidon(HanReader& hanReader, int listSize) { + switch(listSize) { + case (int)Aidon::List1: + listType = 1; + break; + case (int)Aidon::List3PhaseITShort: + case (int)Aidon::List3PhaseShort: + threePhase = true; + case (int)Aidon::List1PhaseShort: + listType = 2; + break; + case (int)Aidon::List3PhaseITLong: + case (int)Aidon::List3PhaseLong: + threePhase = true; + case (int)Aidon::List1PhaseLong: + listType = 3; + break; + } + + if(listSize == (int)Aidon::List1) { + activeImportPower = hanReader.getInt((int)Aidon_List1::ActiveImportPower); + } else { + switch(listSize) { + case (int)Aidon::List3PhaseLong: + meterTimestamp = hanReader.getTime( (int)Aidon_List3Phase::Timestamp); + activeImportCounter = ((double) hanReader.getInt( (int)Aidon_List3Phase::CumulativeActiveImportEnergy)) / 100; + activeExportCounter = ((double) hanReader.getInt( (int)Aidon_List3Phase::CumulativeActiveExportEnergy)) / 100; + reactiveImportCounter = ((double) hanReader.getInt( (int)Aidon_List3Phase::CumulativeReactiveImportEnergy)) / 100; + reactiveExportCounter = ((double) hanReader.getInt( (int)Aidon_List3Phase::CumulativeReactiveExportEnergy)) / 100; + case (int)Aidon::List3PhaseShort: + listId = hanReader.getString( (int)Aidon_List3Phase::ListVersionIdentifier); + meterId = hanReader.getString( (int)Aidon_List3Phase::MeterID); + meterType = hanReader.getString( (int)Aidon_List3Phase::MeterType); + activeImportPower = hanReader.getInt( (int)Aidon_List3Phase::ActiveImportPower); + reactiveImportPower = hanReader.getInt( (int)Aidon_List3Phase::ReactiveImportPower); + activeExportPower = hanReader.getInt( (int)Aidon_List3Phase::ActiveExportPower); + reactiveExportPower = hanReader.getInt( (int)Aidon_List3Phase::ReactiveExportPower); + l1current = ((double) hanReader.getInt( (int)Aidon_List3Phase::CurrentL1)) / 10; + l2current = ((double) hanReader.getInt( (int)Aidon_List3Phase::CurrentL2)) / 10; + l3current = ((double) hanReader.getInt( (int)Aidon_List3Phase::CurrentL3)) / 10; + l1voltage = ((double) hanReader.getInt( (int)Aidon_List3Phase::VoltageL1)) / 10; + l2voltage = ((double) hanReader.getInt( (int)Aidon_List3Phase::VoltageL2)) / 10; + l3voltage = ((double) hanReader.getInt( (int)Aidon_List3Phase::VoltageL3)) / 10; + break; + case (int)Aidon::List1PhaseLong: + meterTimestamp = hanReader.getTime( (int)Aidon_List1Phase::Timestamp); + activeImportCounter = ((double) hanReader.getInt( (int)Aidon_List1Phase::CumulativeActiveImportEnergy)) / 100; + activeExportCounter = ((double) hanReader.getInt( (int)Aidon_List1Phase::CumulativeActiveExportEnergy)) / 100; + reactiveImportCounter = ((double) hanReader.getInt( (int)Aidon_List1Phase::CumulativeReactiveImportEnergy)) / 100; + reactiveExportCounter = ((double) hanReader.getInt( (int)Aidon_List1Phase::CumulativeReactiveExportEnergy)) / 100; + case (int)Aidon::List1PhaseShort: + listId = hanReader.getString( (int)Aidon_List1Phase::ListVersionIdentifier); + meterId = hanReader.getString( (int)Aidon_List1Phase::MeterID); + meterType = hanReader.getString( (int)Aidon_List1Phase::MeterType); + activeImportPower = hanReader.getInt( (int)Aidon_List1Phase::ActiveImportPower); + reactiveImportPower = hanReader.getInt( (int)Aidon_List1Phase::ReactiveImportPower); + activeExportPower = hanReader.getInt( (int)Aidon_List1Phase::ActiveExportPower); + reactiveExportPower = hanReader.getInt( (int)Aidon_List1Phase::ReactiveExportPower); + l1current = ((double) hanReader.getInt( (int)Aidon_List1Phase::CurrentL1)) / 10; + l1voltage = ((double) hanReader.getInt( (int)Aidon_List1Phase::VoltageL1)) / 10; + break; + case (int)Aidon::List3PhaseITLong: + meterTimestamp = hanReader.getTime( (int)Aidon_List3PhaseIT::Timestamp); + activeImportCounter = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CumulativeActiveImportEnergy)) / 100; + activeExportCounter = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CumulativeActiveExportEnergy)) / 100; + reactiveImportCounter = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CumulativeReactiveImportEnergy)) / 100; + reactiveExportCounter = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CumulativeReactiveExportEnergy)) / 100; + case (int)Aidon::List3PhaseITShort: + listId = hanReader.getString( (int)Aidon_List3PhaseIT::ListVersionIdentifier); + meterId = hanReader.getString( (int)Aidon_List3PhaseIT::MeterID); + meterType = hanReader.getString( (int)Aidon_List3PhaseIT::MeterType); + activeImportPower = hanReader.getInt( (int)Aidon_List3PhaseIT::ActiveImportPower); + reactiveImportPower = hanReader.getInt( (int)Aidon_List3PhaseIT::ReactiveImportPower); + activeExportPower = hanReader.getInt( (int)Aidon_List3PhaseIT::ActiveExportPower); + reactiveExportPower = hanReader.getInt( (int)Aidon_List3PhaseIT::ReactiveExportPower); + l1current = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CurrentL1)) / 10; + l3current = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CurrentL3)) / 10; + l1voltage = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::VoltageL1)) / 10; + l2voltage = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::VoltageL2)) / 10; + l3voltage = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::VoltageL3)) / 10; + threePhase = true; + break; + } + } +} + +void AmsData::extractFromKamstrup(HanReader& hanReader, int listSize) { + switch(listSize) { + case (int)Kamstrup::List3PhaseShort: + threePhase = true; + case (int)Kamstrup::List1PhaseShort: + listType = 2; + break; + case (int)Kamstrup::List3PhaseLong: + threePhase = true; + case (int)Kamstrup::List1PhaseLong: + listType = 3; + break; + } + + switch(listSize) { + case (int)Kamstrup::List3PhaseLong: + meterTimestamp = hanReader.getTime( (int)Kamstrup_List3Phase::MeterClock); + activeImportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeActiveImportEnergy)) / 100; + activeExportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeActiveExportEnergy)) / 100; + reactiveImportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeReactiveImportEnergy)) / 100; + reactiveExportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeReactiveExportEnergy)) / 100; + case (int)Kamstrup::List3PhaseShort: + listId = hanReader.getString( (int)Kamstrup_List3Phase::ListVersionIdentifier); + meterId = hanReader.getString( (int)Kamstrup_List3Phase::MeterID); + meterType = hanReader.getString( (int)Kamstrup_List3Phase::MeterType); + activeImportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ActiveImportPower); + reactiveImportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ReactiveImportPower); + activeExportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ActiveExportPower); + reactiveExportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ReactiveExportPower); + l1current = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CurrentL1)) / 100; + l2current = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CurrentL2)) / 100; + l3current = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CurrentL3)) / 100; + l1voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL1); + l2voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL2); + l3voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL3); + break; + case (int)Kamstrup::List1PhaseLong: + meterTimestamp = hanReader.getTime( (int)Kamstrup_List1Phase::MeterClock); + activeImportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeActiveImportEnergy)) / 100; + activeExportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeActiveExportEnergy)) / 100; + reactiveImportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeReactiveImportEnergy)) / 100; + reactiveExportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeReactiveExportEnergy)) / 100; + case (int)Kamstrup::List1PhaseShort: + listId = hanReader.getString( (int)Kamstrup_List1Phase::ListVersionIdentifier); + meterId = hanReader.getString( (int)Kamstrup_List1Phase::MeterID); + meterType = hanReader.getString( (int)Kamstrup_List1Phase::MeterType); + activeImportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ActiveImportPower); + reactiveImportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ReactiveImportPower); + activeExportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ActiveExportPower); + reactiveExportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ReactiveExportPower); + l1current = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CurrentL1)) / 100; + l1voltage = hanReader.getInt( (int)Kamstrup_List1Phase::VoltageL1); + break; + } +} + +void AmsData::apply(AmsData& other) { + this->lastUpdateMillis = other.getLastUpdateMillis(); + this->packageTimestamp = other.getPackageTimestamp(); + this->listType = max(this->listType, other.getListType()); + switch(other.getListType()) { + case 3: + this->meterTimestamp = other.getMeterTimestamp(); + this->activeImportCounter = other.getActiveImportCounter(); + this->activeExportCounter = other.getActiveExportCounter(); + this->reactiveImportCounter = other.getReactiveImportCounter(); + this->reactiveExportCounter = other.getReactiveExportCounter(); + case 2: + this->listId = other.getListId(); + this->meterId = other.getMeterId(); + this->meterType = other.getMeterType(); + this->reactiveImportPower = other.getReactiveImportPower(); + this->activeExportPower = other.getActiveExportPower(); + this->reactiveExportPower = other.getReactiveExportPower(); + this->l1current = other.getL1Current(); + this->l2current = other.getL2Current(); + this->l3current = other.getL3Current(); + this->l1voltage = other.getL1Voltage(); + this->l2voltage = other.getL2Voltage(); + this->l3voltage = other.getL3Voltage(); + this->threePhase = other.isThreePhase(); + case 1: + this->activeImportPower = other.getActiveImportPower(); + } +} + +unsigned long AmsData::getLastUpdateMillis() { + return this->lastUpdateMillis; +} + +unsigned long AmsData::getPackageTimestamp() { + return this->packageTimestamp; +} + +int AmsData::getListType() { + return this->listType; +} + +String AmsData::getListId() { + return this->listId; +} + +String AmsData::getMeterId() { + return this->meterId; +} + +String AmsData::getMeterType() { + return this->meterType; +} + +unsigned long AmsData::getMeterTimestamp() { + return this->meterTimestamp; +} + +int AmsData::getActiveImportPower() { + return this->activeImportPower; +} + +int AmsData::getReactiveImportPower() { + return this->reactiveImportPower; +} + +int AmsData::getActiveExportPower() { + return this->activeExportPower; +} + +int AmsData::getReactiveExportPower() { + return this->reactiveExportPower; +} + +double AmsData::getL1Voltage() { + return this->l1voltage; +} + +double AmsData::getL2Voltage() { + return this->l2voltage; +} + +double AmsData::getL3Voltage() { + return this->l3voltage; +} + +double AmsData::getL1Current() { + return this->l1current; +} + +double AmsData::getL2Current() { + return this->l2current; +} + +double AmsData::getL3Current() { + return this->l3current; +} + +double AmsData::getActiveImportCounter() { + return this->activeImportCounter; +} + +double AmsData::getReactiveImportCounter() { + return this->reactiveImportCounter; +} + +double AmsData::getActiveExportCounter() { + return this->activeExportCounter; +} + +double AmsData::getReactiveExportCounter() { + return this->reactiveExportCounter; +} + +bool AmsData::isThreePhase() { + return this->threePhase; +} diff --git a/src/AmsData.h b/src/AmsData.h new file mode 100644 index 00000000..80b6543a --- /dev/null +++ b/src/AmsData.h @@ -0,0 +1,66 @@ +#ifndef _AMSDATA_H +#define _AMSDATA_H + +#include "Arduino.h" +#include "HanReader.h" + +#define METER_TYPE_KAIFA 1 +#define METER_TYPE_AIDON 2 +#define METER_TYPE_KAMSTRUP 3 + +class AmsData { +public: + AmsData(); + AmsData(int meterType, HanReader& hanReader); + + void apply(AmsData& other); + + unsigned long getLastUpdateMillis(); + + unsigned long getPackageTimestamp(); + + int getListType(); + + String getListId(); + String getMeterId(); + String getMeterType(); + + unsigned long getMeterTimestamp(); + + int getActiveImportPower(); + int getReactiveImportPower(); + int getActiveExportPower(); + int getReactiveExportPower(); + + double getL1Voltage(); + double getL2Voltage(); + double getL3Voltage(); + + double getL1Current(); + double getL2Current(); + double getL3Current(); + + double getActiveImportCounter(); + double getReactiveImportCounter(); + double getActiveExportCounter(); + double getReactiveExportCounter(); + + bool isThreePhase(); + +private: + unsigned long lastUpdateMillis; + int listType; + unsigned long packageTimestamp; + String listId, meterId, meterType; + unsigned long meterTimestamp; + int activeImportPower, reactiveImportPower, activeExportPower, reactiveExportPower; + double l1voltage, l2voltage, l3voltage, l1current, l2current, l3current; + double activeImportCounter, reactiveImportCounter, activeExportCounter, reactiveExportCounter; + bool threePhase; + + void extractFromKaifa(HanReader& hanReader, int listSize); + void extractFromAidon(HanReader& hanReader, int listSize); + void extractFromKamstrup(HanReader& hanReader, int listSize); +}; + +#endif diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index 959b58d3..ae8afc34 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -28,23 +28,17 @@ HwTools hw; DNSServer dnsServer; -// Configuration AmsConfiguration config; -// Web server AmsWebServer ws; -// WiFi client and MQTT client WiFiClient *client; MQTTClient mqtt(384); -// Object used for debugging Stream* debugger = NULL; -// The HAN Port reader, used to read serial data and decode DLMS HanReader hanReader; -// the setup function runs once when you press reset or power the board void setup() { if(config.hasConfig()) { config.load(); @@ -117,12 +111,17 @@ void setup() { } #if SOFTWARE_SERIAL + if(debugger) debugger->println("HAN has software serial"); if(config.getMeterType() == 3) { hanSerial->begin(2400, SWSERIAL_8N1); } else { hanSerial->begin(2400, SWSERIAL_8E1); } #else + if(debugger) { + debugger->println("HAN has hardware serial"); + debugger->flush(); + } if(config.getMeterType() == 3) { hanSerial->begin(2400, SERIAL_8N1); } else { @@ -138,6 +137,11 @@ void setup() { // Compensate for the known Kaifa bug hanReader.compensateFor09HeaderBug = (config.getMeterType() == 1); + // Empty buffer before starting + while (hanSerial->available() > 0) { + hanSerial->read(); + } + ws.setup(&config, debugger, &mqtt); #if HAS_RGB_LED @@ -160,6 +164,10 @@ bool wifiConnected = false; unsigned long lastTemperatureRead = 0; double temperature = -127; +bool even = true; +unsigned long lastRead = 0; +unsigned long lastSuccessfulRead = 0; + void loop() { unsigned long now = millis(); if (digitalRead(AP_BUTTON_PIN) == LOW) { @@ -182,18 +190,16 @@ void loop() { buttonActive = false; } } - - if(now - lastTemperatureRead > 10000) { + + if(now - lastTemperatureRead > 5000) { temperature = hw.getTemperature(); lastTemperatureRead = now; } // Only do normal stuff if we're not booted as AP if (WiFi.getMode() != WIFI_AP) { - // Turn off the LED led_off(); - // Reconnect to WiFi and MQTT as needed if (WiFi.status() != WL_CONNECTED) { wifiConnected = false; WiFi_connect(); @@ -222,7 +228,11 @@ void loop() { else led_off(); } - readHanPort(); + if(lastRead-now > 100) { + yield(); + readHanPort(); + lastRead = now; + } ws.loop(); delay(1); // Needed for auto modem sleep } @@ -286,76 +296,43 @@ void mqttMessageReceived(String &topic, String &payload) // Ideas could be to query for values or to initiate OTA firmware update } -bool even = true; -unsigned long lastSuccessfulRead = 0; void readHanPort() { if (hanReader.read()) { lastSuccessfulRead = millis(); if(config.getMeterType() > 0) { - // Flash LED on, this shows us that data is received #if HAS_RGB_LED rgb_led(RGB_GREEN, 1); #else led_on(); #endif - // Get the timestamp (as unix time) from the package - time_t time = hanReader.getPackageTime(); - if (debugger) debugger->print("Time of the package is: "); - if (debugger) debugger->println(time); - - // Define a json object to keep the data - StaticJsonDocument<512> json; - - // Any generic useful info here - json["id"] = WiFi.macAddress(); - json["up"] = millis(); - json["t"] = time; - double vcc = hw.getVcc(); - if(vcc > 0) { - json["vcc"] = vcc; - } - float rssi = WiFi.RSSI(); - rssi = isnan(rssi) ? -100.0 : rssi; - json["rssi"] = rssi; - if(temperature != -127) { - json["temp"] = temperature; - } - - // Add a sub-structure to the json object, - // to keep the data from the meter itself - JsonObject data = json.createNestedObject("data"); - - hanToJson(data, config.getMeterType(), hanReader); + AmsData data(config.getMeterType(), hanReader); + ws.setData(data); if(!config.getMqttHost().isEmpty() && !config.getMqttPublishTopic().isEmpty()) { - // Write the json to the debug port + StaticJsonDocument<512> json; + hanToJson(json, data, hw, temperature); if (debugger) { debugger->print("Sending data to MQTT: "); serializeJsonPretty(json, *debugger); debugger->println(); } - // Publish the json to the MQTT server String msg; serializeJson(json, msg); - mqtt.publish(config.getMqttPublishTopic(), msg.c_str()); mqtt.loop(); - delay(10); // Needed to preserve power + delay(10); } - ws.setJson(json); - // Flash LED off - // Flash LED off #if HAS_RGB_LED rgb_led(RGB_GREEN, 0); #else led_off(); #endif - } else { + // Auto detect meter if not set for(int i = 1; i <= 3; i++) { String list; switch(i) { @@ -390,6 +367,7 @@ void readHanPort() { } } + // Switch parity if meter is still not detected if(config.getMeterType() == 0 && millis() - lastSuccessfulRead > 10000) { lastSuccessfulRead = millis(); if(debugger) debugger->println("No data for current setting, switching parity"); @@ -419,8 +397,7 @@ void WiFi_connect() { } lastWifiRetry = millis(); - if (debugger) - { + if (debugger) { debugger->println(); debugger->println(); debugger->print("Connecting to WiFi network "); @@ -433,7 +410,6 @@ void WiFi_connect() { WiFi.enableAP(false); WiFi.mode(WIFI_STA); -// WiFi.setOutputPower(0); if(!config.getWifiIp().isEmpty()) { IPAddress ip, gw, sn(255,255,255,0); ip.fromString(config.getWifiIp()); @@ -500,7 +476,7 @@ void sendMqttData(String data) return; // Build a json with the message in a "data" attribute - StaticJsonDocument<500> json; + StaticJsonDocument<128> json; json["id"] = WiFi.macAddress(); json["up"] = millis(); json["data"] = data; diff --git a/src/HanToJson.cpp b/src/HanToJson.cpp new file mode 100644 index 00000000..224c09a1 --- /dev/null +++ b/src/HanToJson.cpp @@ -0,0 +1,46 @@ +#include "HanToJson.h" + +void hanToJson(JsonDocument& json, AmsData& data, HwTools& hw, double temperature) { + json["id"] = WiFi.macAddress(); + json["up"] = millis(); + json["t"] = data.getPackageTimestamp(); + + double vcc = hw.getVcc(); + if(vcc > 0) { + json["vcc"] = vcc; + } + + json["rssi"] = hw.getWifiRssi(); + + if(temperature != DEVICE_DISCONNECTED_C) { + json["temp"] = temperature; + } + + // Add a sub-structure to the json object, + // to keep the data from the meter itself + JsonObject jd = json.createNestedObject("data"); + + switch(data.getListType()) { + case 3: + jd["rtc"] = data.getMeterTimestamp(); + jd["tPI"] = data.getActiveImportCounter(); + jd["tPO"] = data.getActiveExportCounter(); + jd["tQI"] = data.getReactiveImportCounter(); + jd["tQO"] = data.getReactiveExportCounter(); + case 2: + jd["lv"] = data.getListId(); + jd["id"] = data.getMeterId(); + jd["type"] = data.getMeterType(); + jd["Q"] = data.getReactiveImportPower(); + jd["PO"] = data.getActiveExportPower(); + jd["QO"] = data.getReactiveExportPower(); + jd["I1"] = data.getL1Current(); + jd["I2"] = data.getL2Current(); + jd["I3"] = data.getL3Current(); + jd["U1"] = data.getL1Voltage(); + jd["U2"] = data.getL2Voltage(); + jd["U3"] = data.getL3Voltage(); + case 1: + jd["P"] = data.getActiveImportPower(); + } +} diff --git a/src/HanToJson.h b/src/HanToJson.h new file mode 100644 index 00000000..302768b1 --- /dev/null +++ b/src/HanToJson.h @@ -0,0 +1,16 @@ +#ifndef _HANTOJSON_h +#define _HANTOJSON_h + +#if defined(ARDUINO) && ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include +#include "AmsData.h" +#include "HwTools.h" + +void hanToJson(JsonDocument& json, AmsData& data, HwTools& hw, double temperature); + +#endif diff --git a/src/HwTools.cpp b/src/HwTools.cpp index 867c2c6e..d88fcd6c 100644 --- a/src/HwTools.cpp +++ b/src/HwTools.cpp @@ -30,3 +30,7 @@ double HwTools::getTemperature() { return DEVICE_DISCONNECTED_C; } +int HwTools::getWifiRssi() { + int rssi = WiFi.RSSI(); + return isnan(rssi) ? -100.0 : rssi; +} \ No newline at end of file diff --git a/src/HwTools.h b/src/HwTools.h index eb332f28..7e5302ee 100644 --- a/src/HwTools.h +++ b/src/HwTools.h @@ -28,6 +28,7 @@ class HwTools { public: double getVcc(); double getTemperature(); + int getWifiRssi(); HwTools() { oneWire = new OneWire(TEMP_SENSOR_PIN); diff --git a/src/web/AmsWebServer.cpp b/src/web/AmsWebServer.cpp index 1263edc7..5fd0202e 100644 --- a/src/web/AmsWebServer.cpp +++ b/src/web/AmsWebServer.cpp @@ -35,65 +35,17 @@ void AmsWebServer::loop() { server.handleClient(); } -void AmsWebServer::setJson(StaticJsonDocument<512> json) { - if(!json.isNull()) { - p = json["data"]["P"].as(); - po = json["data"]["PO"].as(); - if(json["data"].containsKey("U1")) { - u1 = json["data"]["U1"].as(); - i1 = json["data"]["I1"].as(); - - if(json["data"].containsKey("U2")) { - u2 = json["data"]["U2"].as(); - i2 = json["data"]["I2"].as(); +void AmsWebServer::setData(AmsData& data) { + this->data.apply(data); - if(json["data"].containsKey("U3")) { - u3 = json["data"]["U3"].as(); - i3 = json["data"]["I3"].as(); - } - - // Only way to determine if you have more than one phase is to run this code here - if(maxPwr == 0 && config->hasConfig() && config->getMainFuse() > 0 && config->getDistributionSystem() > 0) { - int volt = config->getDistributionSystem() == 2 ? 400 : 230; - if(u2 > 0) { - maxPwr = config->getMainFuse() * sqrt(3) * volt; - } else { - maxPwr = config->getMainFuse() * 230; - } - } - } - - if(json["data"].containsKey("tPI")) { - tpi = json["data"]["tPI"].as(); - tpo = json["data"]["tPO"].as(); - tqi = json["data"]["tQI"].as(); - tqo = json["data"]["tQO"].as(); - } + if(maxPwr == 0 && data.getListType() > 1 && config->hasConfig() && config->getMainFuse() > 0 && config->getDistributionSystem() > 0) { + int volt = config->getDistributionSystem() == 2 ? 400 : 230; + if(data.isThreePhase()) { + maxPwr = config->getMainFuse() * sqrt(3) * volt; } else { - if(po > 0) { - json["data"]["PO"] = po; - } - if(u1 > 0) { - json["data"]["U1"] = u1; - json["data"]["I1"] = i1; - } - if(u2 > 0) { - json["data"]["U2"] = u2; - json["data"]["I2"] = i2; - } - if(u3 > 0) { - json["data"]["U3"] = u3; - json["data"]["I3"] = i3; - } - if(tpi > 0) { - json["data"]["tPI"] = tpi; - json["data"]["tPO"] = tpo; - json["data"]["tQI"] = tqi; - json["data"]["tQO"] = tqo; - } + maxPwr = config->getMainFuse() * 230; } - this->json = json; } } @@ -139,8 +91,19 @@ void AmsWebServer::indexHtml() { html.replace("boot.css", BOOTSTRAP_URL); } - html.replace("${data.P}", String(p)); - html.replace("${data.PO}", String(po)); + double u1 = data.getL1Voltage(); + double u2 = data.getL2Voltage(); + double u3 = data.getL3Voltage(); + double i1 = data.getL1Current(); + double i2 = data.getL2Current(); + double i3 = data.getL3Current(); + double tpi = data.getActiveImportCounter(); + double tpo = data.getActiveExportCounter(); + double tqi = data.getReactiveImportCounter(); + double tqo = data.getReactiveExportCounter(); + + html.replace("${data.P}", String(data.getActiveImportPower())); + html.replace("${data.PO}", String(data.getActiveExportPower())); html.replace("${display.production}", config->getProductionCapacity() > 0 ? "" : "none"); html.replace("${data.U1}", u1 > 0 ? String(u1, 1) : ""); @@ -168,9 +131,8 @@ void AmsWebServer::indexHtml() { html.replace("${temp}", temp > 0 ? String(temp, 1) : ""); html.replace("${display.temp}", temp != DEVICE_DISCONNECTED_C ? "" : "none"); - float rssi = WiFi.RSSI(); - rssi = isnan(rssi) ? -100.0 : rssi; - html.replace("${wifi.rssi}", vcc > 0 ? String(rssi, 0) : ""); + int rssi = hw.getWifiRssi(); + html.replace("${wifi.rssi}", vcc > 0 ? String(rssi) : ""); html.replace("${wifi.channel}", WiFi.channel() > 0 ? String(WiFi.channel()) : ""); html.replace("${wifi.ssid}", !WiFi.SSID().isEmpty() ? String(WiFi.SSID()) : ""); @@ -330,25 +292,58 @@ void AmsWebServer::dataJson() { StaticJsonDocument<768> json; String jsonStr; - if(!this->json.isNull() && this->json.containsKey("data")) { + if(data.getActiveImportPower() > 0) { int maxPwr = this->maxPwr; if(maxPwr == 0) { - if(u2 > 0) { + if(data.isThreePhase()) { maxPwr = 20000; } else { maxPwr = 10000; } } - json["up"] = this->json["up"]; - json["t"] = this->json["t"]; - json["data"] = this->json["data"]; + json["up"] = data.getLastUpdateMillis(); + json["t"] = data.getPackageTimestamp(); + json.createNestedObject("data"); + json["data"]["P"] = data.getActiveImportPower(); + json["data"]["PO"] = data.getActiveExportPower(); - json["p_pct"] = min(p*100/maxPwr, 100); + double u1 = data.getL1Voltage(); + double u2 = data.getL2Voltage(); + double u3 = data.getL3Voltage(); + double i1 = data.getL1Current(); + double i2 = data.getL2Current(); + double i3 = data.getL3Current(); + double tpi = data.getActiveImportCounter(); + double tpo = data.getActiveExportCounter(); + double tqi = data.getReactiveImportCounter(); + double tqo = data.getReactiveExportCounter(); + + if(u1 > 0) { + json["data"]["U1"] = u1; + json["data"]["I1"] = i1; + } + if(u2 > 0) { + json["data"]["U2"] = u2; + json["data"]["I2"] = i2; + } + if(u3 > 0) { + json["data"]["U3"] = u3; + json["data"]["I3"] = i3; + } + + if(tpi > 0) { + json["data"]["tPI"] = tpi; + json["data"]["tPO"] = tpo; + json["data"]["tQI"] = tqi; + json["data"]["tQO"] = tqo; + } + + json["p_pct"] = min(data.getActiveImportPower()*100/maxPwr, 100); if(config->getProductionCapacity() > 0) { int maxPrd = config->getProductionCapacity() * 1000; - json["po_pct"] = min(po*100/maxPrd, 100); + json["po_pct"] = min(data.getActiveExportPower()*100/maxPrd, 100); } } else { json["p_pct"] = -1; diff --git a/src/web/AmsWebServer.h b/src/web/AmsWebServer.h index f908bcee..888844c0 100644 --- a/src/web/AmsWebServer.h +++ b/src/web/AmsWebServer.h @@ -3,10 +3,11 @@ #define BOOTSTRAP_URL "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" -#include #include +#include #include "AmsConfiguration.h" #include "HwTools.h" +#include "AmsData.h" #if defined(ARDUINO) && ARDUINO >= 100 #include "Arduino.h" @@ -28,17 +29,16 @@ class AmsWebServer { public: void setup(AmsConfiguration* config, Stream* debugger, MQTTClient* mqtt); void loop(); - void setJson(StaticJsonDocument<512> json); + + void setData(AmsData& data); private: + int maxPwr; HwTools hw; AmsConfiguration* config; + AmsData data; Stream* debugger; MQTTClient* mqtt; - StaticJsonDocument<1024> json; - int maxPwr; - int p, po; - double u1, u2, u3, i1, i2, i3, tpi, tpo, tqi, tqo; #if defined(ESP8266) ESP8266WebServer server; diff --git a/web/index.html b/web/index.html index 8b861b52..e57688b5 100644 --- a/web/index.html +++ b/web/index.html @@ -217,7 +217,7 @@ var setStatus = function(id, status) { item.addClass('badge badge-' + status); }; -var interval = 10000; +var interval = 5000; var fetch = function() { $.ajax({ url: '/data.json',