diff --git a/lib/HanReader/examples/Kamstrup/mqtt/KamstrupMqtt.ino b/lib/HanReader/examples/Kamstrup/mqtt/KamstrupMqtt.ino deleted file mode 100644 index ba47176e..00000000 --- a/lib/HanReader/examples/Kamstrup/mqtt/KamstrupMqtt.ino +++ /dev/null @@ -1,197 +0,0 @@ -/* -* Simple sketch to simulate reading data from a Kamstrup -* AMS Meter. -* -* Created 24. October 2017 by Roar Fredriksen -* Modified 06. November 2017 by Ruben Andreassen -*/ - -#include -#include -#include - -#include -#include - -// The HAN Port reader -HanReader hanReader; - -// WiFi and MQTT endpoints -const char* ssid = "ssid"; -const char* password = "password"; -const char* mqtt_server = "ip or dns"; -const char* mqtt_topic = "sensors/out/espams"; -const char* device_name = "espams"; - -bool enableDebug = false; - -WiFiClient espClient; -PubSubClient client(espClient); - -void setup() { - //setupDebugPort(); //Comment out this line if you dont need debugging on Serial1 - setupWiFi(); - setupMqtt(); - - // initialize the HanReader - // (passing no han port, as we are feeding data manually, but provide Serial for debugging) - if (enableDebug) { - hanReader.setup(&Serial, 2400, SERIAL_8N1, &Serial1); - } else { - hanReader.setup(&Serial, 2400, SERIAL_8N1, NULL); - } -} - -void setupMqtt() -{ - client.setServer(mqtt_server, 1883); -} - -void setupDebugPort() -{ - enableDebug = true; - // Initialize the Serial port for debugging - Serial1.begin(115200); - while (!Serial1) {} - Serial1.setDebugOutput(true); - Serial1.println("Serial1"); - Serial1.println("Serial debugging port initialized"); -} - - -void setupWiFi() -{ - // Initialize wifi - if (enableDebug) { - Serial1.print("Connecting to "); - Serial1.println(ssid); - } - WiFi.mode(WIFI_STA); - WiFi.begin(ssid, password); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - if (enableDebug) Serial1.print("."); - } - - if (enableDebug) { - Serial1.println(""); - Serial1.println("WiFi connected"); - Serial1.println("IP address: "); - Serial1.println(WiFi.localIP()); - } -} - -void loop() { - loopMqtt(); - - // Read one byte from the port, and see if we got a full package - if (hanReader.read()) - { - // Get the list identifier - int listSize = hanReader.getListSize(); - - if (enableDebug) { - Serial1.println(""); - Serial1.print("List size: "); - Serial1.print(listSize); - Serial1.print(": "); - } - - // Only care for the ACtive Power Imported, which is found in the first list - if (listSize == (int)Kamstrup::List1 || listSize == (int)Kamstrup::List2) - { - // Define a json object to keep the data - StaticJsonBuffer jsonBuffer; - JsonObject& root = jsonBuffer.createObject(); - - // Any generic useful info here - root["dn"] = device_name; - root["up"] = millis(); - - // Add a sub-structure to the json object, - // to keep the data from the meter itself - JsonObject& data = root.createNestedObject("data"); - - data["ls"] = listSize; - - data["lvi"] = hanReader.getString((int)Kamstrup_List1::ListVersionIdentifier); - data["mid"] = hanReader.getString((int)Kamstrup_List1::MeterID); - data["mt"] = hanReader.getString((int)Kamstrup_List1::MeterType); - data["t"] = hanReader.getPackageTime(); - - data["aip"] = hanReader.getInt((int)Kamstrup_List1::ActiveImportPower); //power - data["aep"] = hanReader.getInt((int)Kamstrup_List1::ActiveExportPower); - data["rip"] = hanReader.getInt((int)Kamstrup_List1::ReactiveImportPower); - data["rep"] = hanReader.getInt((int)Kamstrup_List1::ReactiveExportPower); - - data["al1"] = (float)hanReader.getInt((int)Kamstrup_List1::CurrentL1) / 100.0; - data["al2"] = (float)hanReader.getInt((int)Kamstrup_List1::CurrentL2) / 100.0; - data["al3"] = (float)hanReader.getInt((int)Kamstrup_List1::CurrentL3) / 100.0; - - data["vl1"] = hanReader.getInt((int)Kamstrup_List1::VoltageL1); - data["vl2"] = hanReader.getInt((int)Kamstrup_List1::VoltageL2); - data["vl3"] = hanReader.getInt((int)Kamstrup_List1::VoltageL3); - - if (listSize == (int)Kamstrup::List2) - { - data["cl"] = hanReader.getTime((int)Kamstrup_List2::MeterClock); - data["caie"] = hanReader.getInt((int)Kamstrup_List2::CumulativeActiveImportEnergy); - data["caee"] = hanReader.getInt((int)Kamstrup_List2::CumulativeActiveExportEnergy); - data["crie"] = hanReader.getInt((int)Kamstrup_List2::CumulativeReactiveImportEnergy); - data["cree"] = hanReader.getInt((int)Kamstrup_List2::CumulativeReactiveExportEnergy); - } - - if (enableDebug) { - root.printTo(Serial1); - Serial1.println("JSON length"); - Serial1.println(root.measureLength()); - Serial1.println(""); - } - - // Publish the json to the MQTT server - char msg[MQTT_MAX_PACKET_SIZE]; - root.printTo(msg, MQTT_MAX_PACKET_SIZE); - bool result = client.publish(mqtt_topic, msg); - - if (enableDebug) { - Serial1.println("MQTT publish result:"); - Serial1.println(result); - } - } - } -} - - -// Ensure the MQTT lirary gets some attention too -void loopMqtt() -{ - if (!client.connected()) { - reconnectMqtt(); - } - client.loop(); -} - -void reconnectMqtt() { - // Loop until we're reconnected - while (!client.connected()) { - if (enableDebug) Serial1.print("Attempting MQTT connection..."); - // Attempt to connect - if (client.connect("ESP8266Client")) { - if (enableDebug) Serial1.println("connected"); - // Once connected, publish an announcement... - // client.publish("sensors", "hello world"); - // ... and resubscribe - // client.subscribe("inTopic"); - } - else { - if (enableDebug) { - Serial1.print("failed, rc="); - Serial1.print(client.state()); - Serial1.println(" try again in 5 seconds"); - } - // Wait 5 seconds before retrying - delay(5000); - } - } -} diff --git a/lib/HanReader/examples/Kamstrup/mqtt/README.md b/lib/HanReader/examples/Kamstrup/mqtt/README.md deleted file mode 100644 index d925fb09..00000000 --- a/lib/HanReader/examples/Kamstrup/mqtt/README.md +++ /dev/null @@ -1,95 +0,0 @@ -# Setup - -1. Copy AmsToMqttBridge\Code\Arduino\HanReader\src to Arduino\libraries -2. Download the following libraries and put them in Arduino\libraries - - ESP8266WiFi - - PubSubClient - - ArduinoJson -3. **Set MQTT_MAX_PACKET_SIZE in PubSubClient.h to at least 512 (i used 1024)** -4. Edit the following variables in the project: - - ssid - - password - - mqtt_server - - mqtt_topic - - device_name - -## Output example: -### List 1 -``` -{ - "dn": "espams", - "up": 1475902, - "data": { - "ls": 25, - "lvi": "Kamstrup_V0001", - "mid": "5706567274389702", - "mt": "6841121BN243101040", - "t": 1510088840, - "aip": 3499, - "aep": 0, - "rip": 0, - "rep": 424, - "al1": 10.27, - "al2": 6.37, - "al3": 11.79, - "vl1": 231, - "vl2": 226, - "vl3": 231 - } -} -``` -### List 2 -``` -{ - "dn": "espams", - "up": 1041212, - "data": { - "ls": 35, - "lvi": "Kamstrup_V0001", - "mid": "5706567274389702", - "mt": "6841121BN243101040", - "t": 1510088405, - "aip": 4459, - "aep": 0, - "rip": 0, - "rep": 207, - "al1": 14.72, - "al2": 6.39, - "al3": 15.02, - "vl1": 231, - "vl2": 227, - "vl3": 231, - "cl": 1510088405, - "caie": 588500, - "caee": 0, - "crie": 93, - "cree": 80831 - } -} -``` - -### List 1 and 2 fields -- dn = Device Name -- up = MS since last reboot -- ls = List Size -- lvi = List Version Identifier -- mid = Meter ID -- mt = Meter Type -- t = Time -- aie = Active Import Power -- aep = Active Export Power -- rip = Reactive Import Power -- rep = Reactive Export Power -- al1 = Current L1 -- al2 = Current L2 -- al3 = Current L3 -- cl1 = Voltage L1 -- cl2 = Voltage L2 -- cl3 = Voltage L3 - -### List 2 additional fields -- cl = Meter Clock -- caie = Cumulative Active Import Energy -- caee = Cumulative Active Export Energy -- crie = Cumulative Reactive Import Energy -- cree = Cumulative Reactive Export Energy \ No newline at end of file diff --git a/lib/HanReader/examples/read_han_simple/read_han_simple.ino b/lib/HanReader/examples/read_han_simple/read_han_simple.ino deleted file mode 100644 index eec49fa2..00000000 --- a/lib/HanReader/examples/read_han_simple/read_han_simple.ino +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Simple sketch to read MBus data from electrical meter - * As the protocol requires "Even" parity, and this is - * only supported on the hardware port of the ESP8266, - * we'll have to use Serial1 for debugging. - * - * This means you'll have to program the ESP using the - * regular RX/TX port, and then you must remove the FTDI - * and connect the MBus signal from the meter to the - * RS pin. The FTDI/RX can be moved to Pin2 for debugging - * - * Created 14. september 2017 by Roar Fredriksen - */ - -#include "HanReader.h" -#include "Kaifa.h" - -// The HAN Port reader -HanReader hanReader; - -void setup() { - setupDebugPort(); - - // initialize the HanReader - // (passing Serial as the HAN port and Serial1 for debugging) - hanReader.setup(&Serial, &Serial1); -} - -void setupDebugPort() -{ - // Initialize the Serial1 port for debugging - // (This port is fixed to Pin2 of the ESP8266) - Serial1.begin(115200); - while (!Serial1) {} - Serial1.setDebugOutput(true); - Serial1.println("Serial1"); - Serial1.println("Serial debugging port initialized"); -} - -void loop() { - // Read one byte from the port, and see if we got a full package - if (hanReader.read()) - { - // Get the list identifier - int listSize = hanReader.getListSize(); - - Serial1.println(""); - Serial1.print("List size: "); - Serial1.print(listSize); - Serial1.print(": "); - - // Only care for the ACtive Power Imported, which is found in the first list - if (listSize == (int)Kaifa::List1) - { - int power = hanReader.getInt((int)Kaifa_List1::ActivePowerImported); - Serial1.print("Power consumtion is right now: "); - Serial1.print(power); - Serial1.println(" W"); - } - } -} diff --git a/lib/HanReader/examples/reporting_han_data_to_mqtt/reporting_han_data_to_mqtt.ino b/lib/HanReader/examples/reporting_han_data_to_mqtt/reporting_han_data_to_mqtt.ino deleted file mode 100644 index 62a3f285..00000000 --- a/lib/HanReader/examples/reporting_han_data_to_mqtt/reporting_han_data_to_mqtt.ino +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Simple sketch to read MBus data from electrical meter - * As the protocol requires "Even" parity, and this is - * only supported on the hardware port of the ESP8266, - * we'll have to use Serial1 for debugging. - * - * This means you'll have to program the ESP using the - * regular RX/TX port, and then you must remove the FTDI - * and connect the MBus signal from the meter to the - * RS pin. The FTDI/RX can be moved to Pin2 for debugging - * - * Created 14. september 2017 by Roar Fredriksen - */ - -#include -#include -#include -#include "HanReader.h" -#include "Kaifa.h" - -// The HAN Port reader -HanReader hanReader; - -// WiFi and MQTT endpoints -const char* ssid = "Roar_Etne"; -const char* password = "**********"; -const char* mqtt_server = "192.168.10.203"; - -WiFiClient espClient; -PubSubClient client(espClient); - -void setup() { - setupDebugPort(); - setupWiFi(); - setupMqtt(); - - // initialize the HanReader - // (passing Serial as the HAN port and Serial1 for debugging) - hanReader.setup(&Serial, &Serial1); -} - -void setupMqtt() -{ - client.setServer(mqtt_server, 1883); -} - -void setupDebugPort() -{ - // Initialize the Serial1 port for debugging - // (This port is fixed to Pin2 of the ESP8266) - Serial1.begin(115200); - while (!Serial1) {} - Serial1.setDebugOutput(true); - Serial1.println("Serial1"); - Serial1.println("Serial debugging port initialized"); -} - -void setupWiFi() -{ - // Initialize wifi - Serial1.print("Connecting to "); - Serial1.println(ssid); - WiFi.mode(WIFI_STA); - WiFi.begin(ssid, password); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial1.print("."); - } - - Serial1.println(""); - Serial1.println("WiFi connected"); - Serial1.println("IP address: "); - Serial1.println(WiFi.localIP()); -} - -void loop() { - loopMqtt(); - - // Read one byt from the port, and see if we got a full package - if (hanReader.read()) - { - // Get the list identifier - int listSize = hanReader.getListSize(); - - Serial1.println(""); - Serial1.print("List size: "); - Serial1.print(listSize); - Serial1.print(": "); - - // Only care for the ACtive Power Imported, which is found in the first list - if (listSize == (int)Kaifa::List1 || listSize == (int)Kaifa::List2 || listSize == (int)Kaifa::List3) - { - if (listSize == (int)Kaifa::List1) - { - Serial1.println(" (list #1 has no ID)"); - } - else - { - String id = hanReader.getString((int)Kaifa_List2::ListVersionIdentifier); - Serial1.println(id); - } - - // Get the timestamp (as unix time) from the package - time_t time = hanReader.getPackageTime(); - Serial.print("Time of the package is: "); - Serial.println(time); - - // Define a json object to keep the data - StaticJsonBuffer<500> jsonBuffer; - JsonObject& root = jsonBuffer.createObject(); - - // Any generic useful info here - root["id"] = "espdebugger"; - root["up"] = millis(); - root["t"] = time; - - // Add a sub-structure to the json object, - // to keep the data from the meter itself - JsonObject& data = root.createNestedObject("data"); - - // Based on the list number, get all details - // according to OBIS specifications for the meter - if (listSize == (int)Kaifa::List1) - { - data["P"] = hanReader.getInt((int)Kaifa_List1::ActivePowerImported); - } - else if (listSize == (int)Kaifa::List2) - { - data["lv"] = hanReader.getString((int)Kaifa_List2::ListVersionIdentifier); - data["id"] = hanReader.getString((int)Kaifa_List2::MeterID); - data["type"] = hanReader.getString((int)Kaifa_List2::MeterType); - data["P"] = hanReader.getInt((int)Kaifa_List2::ActiveImportPower); - data["Q"] = hanReader.getInt((int)Kaifa_List2::ReactiveImportPower); - data["I1"] = hanReader.getInt((int)Kaifa_List2::CurrentL1); - data["I2"] = hanReader.getInt((int)Kaifa_List2::CurrentL2); - data["I3"] = hanReader.getInt((int)Kaifa_List2::CurrentL3); - data["U1"] = hanReader.getInt((int)Kaifa_List2::VoltageL1); - data["U2"] = hanReader.getInt((int)Kaifa_List2::VoltageL2); - data["U3"] = hanReader.getInt((int)Kaifa_List2::VoltageL3); - } - else if (listSize == (int)Kaifa::List3) - { - data["lv"] = hanReader.getString((int)Kaifa_List3::ListVersionIdentifier);; - data["id"] = hanReader.getString((int)Kaifa_List3::MeterID); - data["type"] = hanReader.getString((int)Kaifa_List3::MeterType); - data["P"] = hanReader.getInt((int)Kaifa_List3::ActiveImportPower); - data["Q"] = hanReader.getInt((int)Kaifa_List3::ReactiveImportPower); - data["I1"] = hanReader.getInt((int)Kaifa_List3::CurrentL1); - data["I2"] = hanReader.getInt((int)Kaifa_List3::CurrentL2); - data["I3"] = hanReader.getInt((int)Kaifa_List3::CurrentL3); - data["U1"] = hanReader.getInt((int)Kaifa_List3::VoltageL1); - data["U2"] = hanReader.getInt((int)Kaifa_List3::VoltageL2); - data["U3"] = hanReader.getInt((int)Kaifa_List3::VoltageL3); - data["tPI"] = hanReader.getInt((int)Kaifa_List3::CumulativeActiveImportEnergy); - data["tPO"] = hanReader.getInt((int)Kaifa_List3::CumulativeActiveExportEnergy); - data["tQI"] = hanReader.getInt((int)Kaifa_List3::CumulativeReactiveImportEnergy); - data["tQO"] = hanReader.getInt((int)Kaifa_List3::CumulativeReactiveExportEnergy); - } - - // Write the json to the debug port - root.printTo(Serial1); - Serial1.println(); - - // Publish the json to the MQTT server - char msg[1024]; - root.printTo(msg, 1024); - client.publish("sensors/out/espdebugger", msg); - } - } -} - -// Ensure the MQTT lirary gets some attention too -void loopMqtt() -{ - if (!client.connected()) { - reconnectMqtt(); - } - client.loop(); -} - -void reconnectMqtt() { - // Loop until we're reconnected - while (!client.connected()) { - Serial1.print("Attempting MQTT connection..."); - // Attempt to connect - if (client.connect("ESP8266Client")) { - Serial1.println("connected"); - // Once connected, publish an announcement... - // client.publish("sensors", "hello world"); - // ... and resubscribe - // client.subscribe("inTopic"); - } - else { - Serial1.print("failed, rc="); - Serial1.print(client.state()); - Serial1.println(" try again in 5 seconds"); - // Wait 5 seconds before retrying - delay(5000); - } - } -} diff --git a/lib/HanReader/keywords.txt b/lib/HanReader/keywords.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/HanReader/library.properties b/lib/HanReader/library.properties deleted file mode 100644 index c71a2d3f..00000000 --- a/lib/HanReader/library.properties +++ /dev/null @@ -1,10 +0,0 @@ -name=HanReader -version=1.0.1 -author=roarfred -maintainer=roarfred -sentence=HAN support -paragraph=HAN support -category=Sensors -url=https://github.com/roarfred/AmsToMqttBridge -architectures=* -depends=Timezone diff --git a/lib/HanReader/readme.txt b/lib/HanReader/readme.txt deleted file mode 100644 index 7f98d8d2..00000000 --- a/lib/HanReader/readme.txt +++ /dev/null @@ -1,19 +0,0 @@ -Arduino Compatible Cross Platform C++ Library Project : For more information see http://www.visualmicro.com - -This project works exactly the same way as an Arduino library. - -Add this project to any solution that contains an Arduino project and #include in code as you would any normal Arduino library headers. - -To enable intellisense and to support live build discovery outside of the "standard" Arduino library locations, ensure that the library is added as a shared project reference to the master Arduino project. To do this, right click the master project "References" node and then click "Add Reference". A window will open and the library will appear on the "Shared Projects" tab. Click the checkbox next to the library name to add the reference. If this library is moved the shared referencemust be removed and re-added. - -VS2017 has a bug, workround: After moving existing source code within a "library or shared project", close and re-open the solution. - -Visual Studio will display intellisense for libraries based on the platform/board that has been specified for the currently active "Startup Project" of the current solution. - - -IMPORTANT: The arduino.cc Library Rules must be followed when adding code or restructing libraries. - - - - -blog: http://www.visualmicro.com/post/2017/01/16/Arduino-Cross-Platform-Library-Development.aspx \ No newline at end of file diff --git a/lib/HanReader/src/Aidon.h b/lib/HanReader/src/Aidon.h deleted file mode 100644 index dbac985a..00000000 --- a/lib/HanReader/src/Aidon.h +++ /dev/null @@ -1,304 +0,0 @@ -// Aidon.h - -#ifndef _AIDON_h -#define _AIDON_h - -enum class Aidon -{ - List1 = 0x01, - List1PhaseShort = 0x09, - List1PhaseLong = 0x0E, - List3PhaseShort = 0x0D, - List3PhaseLong = 0x12, - List3PhaseITShort = 0x0C, - List3PhaseITLong = 0x11, -}; - -enum class Aidon_List1 -{ - ListSize, - IGN_0, - ActiveImportPower_OBIS, - ActiveImportPower, - IGN_1, - ActiveImportPowerInt8, - ActiveImportPowerEnum -}; - - -enum class Aidon_List1Phase -{ - ListSize, - IGN_0, - ListVersionIdentifier_OBIS, - ListVersionIdentifier, - IGN_1, - MeterID_OBIS, - MeterID, - IGN_2, - MeterType_OBIS, - MeterType, - IGN_3, - ActiveImportPower_OBIS, - ActiveImportPower, - IGN_4, - ActiveImportPowerInt8, - ActiveImportPowerEnum, - IGN_5, - ActiveExportPower_OBIS, - ActiveExportPower, - IGN_6, - ActiveExportPowerInt8, - ActiveExportPowerEnum, - IGN_7, - ReactiveImportPower_OBIS, - ReactiveImportPower, - IGN_8, - ReactiveImportPowerInt8, - ReactiveImportPowerEnum, - IGN_9, - ReactiveExportPower_OBIS, - ReactiveExportPower, - IGN_10, - ReactiveExportPowerInt8, - ReactiveExportPowerEnum, - IGN_11, - CurrentL1_OBIS, - CurrentL1, - IGN_12, - CurrentL1Int8, - CurrentL1Enum, - IGN_13, - VoltageL1_OBIS, - VoltageL1, - IGN_14, - VoltageL1Int8, - VoltageL1Enum, - IGN_15, - Timestamp_OBIS, - Timestamp, - IGN_16, - CumulativeActiveImportEnergy_OBIS, - CumulativeActiveImportEnergy, - IGN_17, - CumulativeActiveImportEnergyInt8, - CumulativeActiveImportEnergyEnum, - IGN_18, - CumulativeActiveExportEnergy_OBIS, - CumulativeActiveExportEnergy, - IGN_19, - CumulativeActiveExportEnergyInt8, - CumulativeActiveExportEnergyEnum, - IGN_20, - CumulativeReactiveImportEnergy_OBIS, - CumulativeReactiveImportEnergy, - IGN_21, - CumulativeReactiveImportEnergyInt8, - CumulativeReactiveImportEnergyEnum, - IGN_22, - CumulativeReactiveExportEnergy_OBIS, - CumulativeReactiveExportEnergy, - IGN_23, - CumulativeReactiveExportEnergyInt8, - CumulativeReactiveExportEnergyEnum -}; - -enum class Aidon_List3Phase -{ - ListSize, - IGN_0, - ListVersionIdentifier_OBIS, - ListVersionIdentifier, - IGN_1, - MeterID_OBIS, - MeterID, - IGN_2, - MeterType_OBIS, - MeterType, - IGN_3, - ActiveImportPower_OBIS, - ActiveImportPower, - IGN_4, - ActiveImportPowerInt8, - ActiveImportPowerEnum, - IGN_5, - ActiveExportPower_OBIS, - ActiveExportPower, - IGN_6, - ActiveExportPowerInt8, - ActiveExportPowerEnum, - IGN_7, - ReactiveImportPower_OBIS, - ReactiveImportPower, - IGN_8, - ReactiveImportPowerInt8, - ReactiveImportPowerEnum, - IGN_9, - ReactiveExportPower_OBIS, - ReactiveExportPower, - IGN_10, - ReactiveExportPowerInt8, - ReactiveExportPowerEnum, - IGN_11, - CurrentL1_OBIS, - CurrentL1, - IGN_12, - CurrentL1Int8, - CurrentL1Enum, - IGN_13, - CurrentL2_OBIS, - CurrentL2, - IGN_14, - CurrentL2Int8, - CurrentL2Enum, - IGN_15, - CurrentL3_OBIS, - CurrentL3, - IGN_16, - CurrentL3Int8, - CurrentL3Enum, - IGN_17, - VoltageL1_OBIS, - VoltageL1, - IGN_18, - VoltageL1Int8, - VoltageL1Enum, - IGN_19, - VoltageL2_OBIS, - VoltageL2, - IGN_20, - VoltageL2Int8, - VoltageL2Enum, - IGN_21, - VoltageL3_OBIS, - VoltageL3, - IGN_22, - VoltageL3Int8, - VoltageL3Enum, - IGN_23, - Timestamp_OBIS, - Timestamp, - IGN_24, - CumulativeActiveImportEnergy_OBIS, - CumulativeActiveImportEnergy, - IGN_25, - CumulativeActiveImportEnergyInt8, - CumulativeActiveImportEnergyEnum, - IGN_26, - CumulativeActiveExportEnergy_OBIS, - CumulativeActiveExportEnergy, - IGN_27, - CumulativeActiveExportEnergyInt8, - CumulativeActiveExportEnergyEnum, - IGN_28, - CumulativeReactiveImportEnergy_OBIS, - CumulativeReactiveImportEnergy, - IGN_29, - CumulativeReactiveImportEnergyInt8, - CumulativeReactiveImportEnergyEnum, - IGN_30, - CumulativeReactiveExportEnergy_OBIS, - CumulativeReactiveExportEnergy, - IGN_31, - CumulativeReactiveExportEnergyInt8, - CumulativeReactiveExportEnergyEnum -}; - -enum class Aidon_List3PhaseIT -{ - ListSize, - IGN_0, - ListVersionIdentifier_OBIS, - ListVersionIdentifier, - IGN_1, - MeterID_OBIS, - MeterID, - IGN_2, - MeterType_OBIS, - MeterType, - IGN_3, - ActiveImportPower_OBIS, - ActiveImportPower, - IGN_4, - ActiveImportPowerInt8, - ActiveImportPowerEnum, - IGN_5, - ActiveExportPower_OBIS, - ActiveExportPower, - IGN_6, - ActiveExportPowerInt8, - ActiveExportPowerEnum, - IGN_7, - ReactiveImportPower_OBIS, - ReactiveImportPower, - IGN_8, - ReactiveImportPowerInt8, - ReactiveImportPowerEnum, - IGN_9, - ReactiveExportPower_OBIS, - ReactiveExportPower, - IGN_10, - ReactiveExportPowerInt8, - ReactiveExportPowerEnum, - IGN_11, - CurrentL1_OBIS, - CurrentL1, - IGN_12, - CurrentL1Int8, - CurrentL1Enum, - IGN_13, - CurrentL3_OBIS, - CurrentL3, - IGN_14, - CurrentL3Int8, - CurrentL3Enum, - IGN_15, - VoltageL1_OBIS, - VoltageL1, - IGN_16, - VoltageL1Int8, - VoltageL1Enum, - IGN_17, - VoltageL2_OBIS, - VoltageL2, - IGN_18, - VoltageL2Int8, - VoltageL2Enum, - IGN_19, - VoltageL3_OBIS, - VoltageL3, - IGN_20, - VoltageL3Int8, - VoltageL3Enum, - IGN_21, - Timestamp_OBIS, - Timestamp, - IGN_22, - CumulativeActiveImportEnergy_OBIS, - CumulativeActiveImportEnergy, - IGN_23, - CumulativeActiveImportEnergyInt8, - CumulativeActiveImportEnergyEnum, - IGN_24, - CumulativeActiveExportEnergy_OBIS, - CumulativeActiveExportEnergy, - IGN_25, - CumulativeActiveExportEnergyInt8, - CumulativeActiveExportEnergyEnum, - IGN_26, - CumulativeReactiveImportEnergy_OBIS, - CumulativeReactiveImportEnergy, - IGN_27, - CumulativeReactiveImportEnergyInt8, - CumulativeReactiveImportEnergyEnum, - IGN_28, - CumulativeReactiveExportEnergy_OBIS, - CumulativeReactiveExportEnergy, - IGN_29, - CumulativeReactiveExportEnergyInt8, - CumulativeReactiveExportEnergyEnum -}; - - -#endif - diff --git a/lib/HanReader/src/Crc16.cpp b/lib/HanReader/src/Crc16.cpp deleted file mode 100644 index cb258c1d..00000000 --- a/lib/HanReader/src/Crc16.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "Crc16.h" - -Crc16Class::Crc16Class() { } - -unsigned short Crc16Class::ComputeChecksum(byte *data, int start, int length) { - ushort fcs = 0xffff; - for (int i = start; i < (start + length); i++) - { - byte index = (fcs ^ data[i]) & 0xff; - fcs = (ushort)((fcs >> 8) ^ crc16_ccitt_table_reverse[index]); - } - fcs ^= 0xffff; - return fcs; -} diff --git a/lib/HanReader/src/Crc16.h b/lib/HanReader/src/Crc16.h deleted file mode 100644 index a8c19872..00000000 --- a/lib/HanReader/src/Crc16.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef _CRC16_h -#define _CRC16_h - -#include "Arduino.h" - -const int crc16_ccitt_table_reverse [256] PROGMEM = { - 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, - 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, - 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, - 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, - 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, - 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, - 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, - 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, - 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, - 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, - 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, - 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, - 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, - 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, - 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, - 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, - 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, - 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, - 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, - 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, - 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, - 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, - 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, - 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, - 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, - 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, - 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, - 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, - 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, - 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, - 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, - 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 -}; - - -#if defined(ARDUINO) && ARDUINO >= 100 - #include "Arduino.h" -#else - #include "WProgram.h" -#endif - -class Crc16Class -{ - public: - Crc16Class(); - unsigned short ComputeChecksum(byte *data, int start, int length); -}; - -#endif - - diff --git a/lib/HanReader/src/DlmsReader.cpp b/lib/HanReader/src/DlmsReader.cpp deleted file mode 100644 index a6736401..00000000 --- a/lib/HanReader/src/DlmsReader.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include "DlmsReader.h" - -DlmsReader::DlmsReader() -{ - //this->Clear(); -} - -void DlmsReader::Clear() -{ - this->position = 0; - this->dataLength = 0; - this->destinationAddressLength = 0; - this->sourceAddressLength = 0; - this->frameFormatType = 0; -} - -bool DlmsReader::Read(byte data, Print* debugger) -{ - if (position == 0 && data != 0x7E) - { - // we haven't started yet, wait for the start flag (no need to capture any data yet) - return false; - } - else - { - // We have completed reading of one package, so clear and be ready for the next - if (dataLength > 0 && position >= dataLength + 2) { - if(debugger != NULL) { - debugger->printf("Preparing for next frame\n"); - } - Clear(); - } - - // Check if we're about to run into a buffer overflow - if (position >= DLMS_READER_BUFFER_SIZE) { - if(debugger != NULL) { - debugger->printf("Buffer overflow\n"); - debugPrint(buffer, 0, position, debugger); - } - Clear(); - } - - // Check if this is a second start flag, which indicates the previous one was a stop from the last package - if (position == 1 && data == 0x7E) - { - // just return, we can keep the one byte we had in the buffer - return false; - } - - // We have started, so capture every byte - buffer[position++] = data; - - if (position == 1) - { - // This was the start flag, we're not done yet - return false; - } - else if (position == 2) - { - // Capture the Frame Format Type - frameFormatType = (byte)(data & 0xF0); - if (!IsValidFrameFormat(frameFormatType)) { - if(debugger != NULL) { - debugger->printf("Incorrect frame format %02X\n", frameFormatType); - debugPrint(buffer, 0, position, debugger); - } - Clear(); - } - return false; - } - else if (position == 3) - { - // Capture the length of the data package - dataLength = ((buffer[1] & 0x0F) << 8) | buffer[2]; - return false; - } - else if (destinationAddressLength == 0) - { - // Capture the destination address - destinationAddressLength = GetAddress(3, destinationAddress, 0, DLMS_READER_MAX_ADDRESS_SIZE); - if (destinationAddressLength > 3) { - if(debugger != NULL) { - debugger->printf("Destination address length incorrect\n"); - debugPrint(buffer, 0, position, debugger); - } - Clear(); - } - return false; - } - else if (sourceAddressLength == 0) - { - // Capture the source address - sourceAddressLength = GetAddress(3 + destinationAddressLength, sourceAddress, 0, DLMS_READER_MAX_ADDRESS_SIZE); - if (sourceAddressLength > 3) { - if(debugger != NULL) { - debugger->printf("Source address length incorrect\n"); - debugPrint(buffer, 0, position, debugger); - } - Clear(); - } - return false; - } - else if (position == 4 + destinationAddressLength + sourceAddressLength + 2) - { - // Verify the header checksum - ushort headerChecksum = GetChecksum(position - 3); - if (headerChecksum != Crc16.ComputeChecksum(buffer, 1, position - 3)) { - if(debugger != NULL) { - debugger->printf("Header checksum is incorrect %02X\n", headerChecksum); - debugPrint(buffer, 0, position, debugger); - } - Clear(); - } - return false; - } - else if (position == dataLength + 1) - { - // Verify the data package checksum - ushort checksum = this->GetChecksum(position - 3); - if (checksum != Crc16.ComputeChecksum(buffer, 1, position - 3)) { - if(debugger != NULL) { - debugger->printf("Frame checksum is incorrect %02X\n", checksum); - debugPrint(buffer, 0, position, debugger); - } - Clear(); - } - return false; - } - else if (position == dataLength + 2) - { - // We're done, check the stop flag and signal we're done - if (data == 0x7E) - return true; - else - { - if(debugger != NULL) { - debugger->printf("Received incorrect end marker %02X\n", data); - debugPrint(buffer, 0, position, debugger); - } - Clear(); - return false; - } - } - } - return false; -} - -bool DlmsReader::IsValidFrameFormat(byte frameFormatType) -{ - return frameFormatType == 0xA0; -} - -int DlmsReader::GetRawData(byte *dataBuffer, int start, int length) -{ - if (dataLength > 0 && position == dataLength + 2) - { - int headerLength = 3 + destinationAddressLength + sourceAddressLength + 2; - int bytesWritten = 0; - for (int i = headerLength + 1; i < dataLength - 1; i++) - { - dataBuffer[i + start - headerLength - 1] = buffer[i]; - bytesWritten++; - } - return bytesWritten; - } - else - return 0; -} - -int DlmsReader::getBytesRead() { - return dataLength - (destinationAddressLength + sourceAddressLength + 7); -} - -byte* DlmsReader::getBuffer() { - return buffer + (3 + destinationAddressLength + sourceAddressLength + 2 + 1); -} - -byte* DlmsReader::getFullBuffer() { - return buffer; -} - -int DlmsReader::getFullBufferLength() { - return dataLength; -} - -int DlmsReader::GetAddress(int addressPosition, byte* addressBuffer, int start, int length) -{ - int addressBufferPos = start; - for (int i = addressPosition; i < position; i++) - { - addressBuffer[addressBufferPos++] = buffer[i]; - - // LSB=1 means this was the last address byte - if ((buffer[i] & 0x01) == 0x01) - break; - - // See if we've reached last byte, try again when we've got more data - else if (i == position - 1) - return 0; - } - return addressBufferPos - start; -} - -ushort DlmsReader::GetChecksum(int checksumPosition) -{ - return (ushort)(buffer[checksumPosition + 2] << 8 | - buffer[checksumPosition + 1]); -} - -void DlmsReader::debugPrint(byte *buffer, int start, int length, Print* debugger) { - for (int i = start; i < start + length; i++) { - if (buffer[i] < 0x10) - debugger->print("0"); - debugger->print(buffer[i], HEX); - debugger->print(" "); - if ((i - start + 1) % 16 == 0) - debugger->println(""); - else if ((i - start + 1) % 4 == 0) - debugger->print(" "); - - yield(); // Let other get some resources too - } - debugger->println(""); -} diff --git a/lib/HanReader/src/DlmsReader.h b/lib/HanReader/src/DlmsReader.h deleted file mode 100644 index bf86951f..00000000 --- a/lib/HanReader/src/DlmsReader.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef _DLMSREADER_h -#define _DLMSREADER_h - -#include "Crc16.h" - -#if defined(ARDUINO) && ARDUINO >= 100 - #include "Arduino.h" -#else - #include "WProgram.h" -#endif - -#define DLMS_READER_BUFFER_SIZE 512 -#define DLMS_READER_MAX_ADDRESS_SIZE 5 - -class DlmsReader -{ - public: - DlmsReader(); - bool Read(byte data, Print* Debug); - int GetRawData(byte *buffer, int start, int length); - int getBytesRead(); - byte* getBuffer(); - byte* getFullBuffer(); - int getFullBufferLength(); - - protected: - Crc16Class Crc16; - - private: - byte buffer[DLMS_READER_BUFFER_SIZE]; - int position; - int dataLength; - byte frameFormatType; - byte destinationAddress[DLMS_READER_MAX_ADDRESS_SIZE]; - byte destinationAddressLength; - byte sourceAddress[DLMS_READER_MAX_ADDRESS_SIZE]; - byte sourceAddressLength; - - void Clear(); - int GetAddress(int addressPosition, byte* buffer, int start, int length); - unsigned short GetChecksum(int checksumPosition); - bool IsValidFrameFormat(byte frameFormatType); - void WriteBuffer(); - void debugPrint(byte *buffer, int start, int length, Print* debugger); -}; - -#endif diff --git a/lib/HanReader/src/HanReader.cpp b/lib/HanReader/src/HanReader.cpp deleted file mode 100644 index 2fdd7832..00000000 --- a/lib/HanReader/src/HanReader.cpp +++ /dev/null @@ -1,424 +0,0 @@ -#include "HanReader.h" - -#if defined(ESP32) -#include "mbedtls/gcm.h" -#endif - -HanReader::HanReader() { - // Central European Time (Frankfurt, Paris) - TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; // Central European Summer Time - TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; // Central European Standard Time - localZone = new Timezone(CEST, CET); -} - -void HanReader::setup(Stream *hanPort, RemoteDebug *debug) -{ - han = hanPort; - bytesRead = 0; - debugger = debug; - - if (debug) debug->println("MBUS serial setup complete"); -} - -void HanReader::setup(Stream *hanPort){ - setup(hanPort, NULL); -} - -void HanReader::setEncryptionKey(uint8_t* encryption_key) { - this->encryption_key = encryption_key; -} - -void HanReader::setAuthenticationKey(uint8_t* authentication_key) { - this->authentication_key = authentication_key; -} - - -bool HanReader::read(byte data) { - if (reader.Read(data, debugger->isActive(RemoteDebug::DEBUG) ? debugger : NULL)) { - bytesRead = reader.getBytesRead(); - buffer = reader.getBuffer(); - if (debugger->isActive(RemoteDebug::INFO)) { - printI("Got valid DLMS data (%d bytes)", bytesRead); - if (debugger->isActive(RemoteDebug::DEBUG)) { - byte* full = reader.getFullBuffer(); - int size = reader.getFullBufferLength(); - printI("Full DLMS frame (%d bytes)", size); - debugPrint(full, 0, size); - } - } - - /* - Data should start with E6 E7 00 0F - and continue with four bytes for the InvokeId - */ - if (bytesRead < 9) { - printW("Invalid HAN data: Less than 9 bytes received"); - return false; - } - else if ( - buffer[0] != 0xE6 - || buffer[1] != 0xE7 - || buffer[2] != 0x00 - ) - { - printW("Invalid HAN data: Start should be E6 E7 00"); - return false; - } - - // Have not found any documentation supporting this, but 0x0F for all norwegian meters. - // Danish meters with encryption has 0xDB, so lets assume this has something to do with that. - switch(buffer[3]) { - case 0x0F: - dataHeader = 8; - break; - case 0xDB: - printI("Decrypting frame"); - if(!decryptFrame()) return false; - if (debugger->isActive(RemoteDebug::DEBUG)) { - printD("Data after decryption:"); - debugPrint(buffer, 0, bytesRead); - } - dataHeader = 26; - break; - } - - listSize = getInt(0, buffer, 0, bytesRead); - printI("HAN data is valid, listSize: %d", listSize); - return true; - } - - return false; -} - -const size_t headersize = 3; -const size_t footersize = 0; - -bool HanReader::decryptFrame() { - uint8_t system_title[8]; - memcpy(system_title, buffer + headersize + 2, 8); - if (debugger->isActive(RemoteDebug::DEBUG)) { - printD("System title:"); - debugPrint(system_title, 0, 8); - } - - uint8_t initialization_vector[12]; - memcpy(initialization_vector, system_title, 8); - memcpy(initialization_vector + 8, buffer + headersize + 14, 4); - if (debugger->isActive(RemoteDebug::DEBUG)) { - printD("Initialization vector:"); - debugPrint(initialization_vector, 0, 12); - } - - uint8_t additional_authenticated_data[17]; - memcpy(additional_authenticated_data, buffer + headersize + 13, 1); - memcpy(additional_authenticated_data + 1, authentication_key, 16); - if (debugger->isActive(RemoteDebug::DEBUG)) { - printD("Additional authenticated data:"); - debugPrint(additional_authenticated_data, 0, 17); - } - - uint8_t authentication_tag[12]; - memcpy(authentication_tag, buffer + headersize + bytesRead - headersize - footersize - 12, 12); - if (debugger->isActive(RemoteDebug::DEBUG)) { - printD("Authentication tag:"); - debugPrint(authentication_tag, 0, 12); - } - - if (debugger->isActive(RemoteDebug::DEBUG)) { - printD("Encryption key:"); - debugPrint(encryption_key, 0, 16); - } - -#if defined(ESP8266) - br_gcm_context gcmCtx; - br_aes_ct_ctr_keys bc; - br_aes_ct_ctr_init(&bc, encryption_key, 16); - br_gcm_init(&gcmCtx, &bc.vtable, br_ghash_ctmul32); - br_gcm_reset(&gcmCtx, initialization_vector, sizeof(initialization_vector)); - br_gcm_aad_inject(&gcmCtx, additional_authenticated_data, sizeof(additional_authenticated_data)); - br_gcm_flip(&gcmCtx); - br_gcm_run(&gcmCtx, 0, buffer + headersize + 18, bytesRead - headersize - footersize - 18 - 12); - if(br_gcm_check_tag_trunc(&gcmCtx, authentication_tag, 12) != 1) { - printE("authdecrypt failed"); - return false; - } -#elif defined(ESP32) - uint8_t cipher_text[bytesRead - headersize - footersize - 18 - 12]; - memcpy(cipher_text, buffer + headersize + 18, bytesRead - headersize - footersize - 12 - 18); - - mbedtls_gcm_context m_ctx; - mbedtls_gcm_init(&m_ctx); - int success = mbedtls_gcm_setkey(&m_ctx, MBEDTLS_CIPHER_ID_AES, encryption_key, 128); - if (0 != success ) { - printE("Setkey failed: " + String(success)); - return false; - } - success = mbedtls_gcm_auth_decrypt(&m_ctx, sizeof(cipher_text), initialization_vector, sizeof(initialization_vector), - additional_authenticated_data, sizeof(additional_authenticated_data), authentication_tag, sizeof(authentication_tag), - cipher_text, buffer + headersize + 18); - if (0 != success) { - printE("authdecrypt failed: " + String(success)); - return false; - } - mbedtls_gcm_free(&m_ctx); -#endif - return true; -} - -void HanReader::debugPrint(byte *buffer, int start, int length) { - for (int i = start; i < start + length; i++) { - if (buffer[i] < 0x10) - debugger->print("0"); - debugger->print(buffer[i], HEX); - debugger->print(" "); - if ((i - start + 1) % 16 == 0) - debugger->println(""); - else if ((i - start + 1) % 4 == 0) - debugger->print(" "); - - yield(); // Let other get some resources too - } - debugger->println(""); -} - -bool HanReader::read() { - while(han->available()) { - if(read(han->read())) { - return true; - } - } - return false; -} - -int HanReader::getListSize() { - return listSize; -} - -time_t HanReader::getPackageTime(bool respectTimezone, bool respectDsc) { - int packageTimePosition = dataHeader - + (compensateFor09HeaderBug ? 1 : 0); - - return getTime(buffer, packageTimePosition, bytesRead, respectTimezone, respectDsc); -} - -time_t HanReader::getTime(uint8_t objectId, bool respectTimezone, bool respectDsc) { - return getTime(objectId, respectTimezone, respectDsc, buffer, 0, bytesRead); -} - -int32_t HanReader::getInt(uint8_t objectId) { - return getInt(objectId, buffer, 0, bytesRead); -} - -uint32_t HanReader::getUint(uint8_t objectId) { - return getUint32(objectId, buffer, 0, bytesRead); -} - -String HanReader::getString(uint8_t objectId) { - return getString(objectId, buffer, 0, bytesRead); -} - -int HanReader::getBuffer(byte* buf) { - for (int i = 0; i < bytesRead; i++) { - buf[i] = buffer[i]; - } - return bytesRead; -} - -int HanReader::findValuePosition(uint8_t dataPosition, byte *buffer, int start, int length) { - // The first byte after the header gives the length - // of the extended header information (variable) - int headerSize = dataHeader + (compensateFor09HeaderBug ? 1 : 0); - int firstData = headerSize + buffer[headerSize] + 1; - - for (int i = start + firstData; i= -720) { - time -= tzMinutes * 60; - if(respectDsc && dsc) - time += 3600; - } else { - if(respectDsc && dsc) - time += 3600; - time = localZone->toUTC(time); - } - return time; - } else if(dataLength == 0) { - return (time_t)0L; - } else { - printW("Unknown time length: %d", dataLength); - // Date format not supported - return (time_t)0L; - } -} - -int HanReader::getInt(uint8_t dataPosition, byte *buffer, int start, int length) { - int valuePosition = findValuePosition(dataPosition, buffer, start, length); - - if (valuePosition > 0) { - switch (buffer[valuePosition++]) { - case 0x01: - case 0x02: - case 0x16: - return getUint8(dataPosition, buffer, start, length); - case 0x0F: - return getInt8(dataPosition, buffer, start, length); - case 0x12: - return getUint16(dataPosition, buffer, start, length); - case 0x10: - return getInt16(dataPosition, buffer, start, length); - case 0x06: - return getUint32(dataPosition, buffer, start, length); - } - } - return 0; -} - -int8_t HanReader::getInt8(uint8_t dataPosition, byte *buffer, int start, int length) { - int valuePosition = findValuePosition(dataPosition, buffer, start, length); - if (valuePosition > 0 && buffer[valuePosition++] == 0x0F) { - return buffer[valuePosition]; - } - return 0; -} - -int16_t HanReader::getInt16(uint8_t dataPosition, byte *buffer, int start, int length) { - int valuePosition = findValuePosition(dataPosition, buffer, start, length); - if (valuePosition > 0 && buffer[valuePosition++] == 0x10) { - return buffer[valuePosition] << 8 | buffer[valuePosition+1]; - } - return 0; -} - -uint8_t HanReader::getUint8(uint8_t dataPosition, byte *buffer, int start, int length) { - int valuePosition = findValuePosition(dataPosition, buffer, start, length); - if (valuePosition > 0) { - switch(buffer[valuePosition++]) { - case 0x01: - case 0x02: - case 0x16: - return buffer[valuePosition]; - } - } - return 0; -} - -uint16_t HanReader::getUint16(uint8_t dataPosition, byte *buffer, int start, int length) { - int valuePosition = findValuePosition(dataPosition, buffer, start, length); - if (valuePosition > 0 && buffer[valuePosition++] == 0x12) { - return buffer[valuePosition] << 8 | buffer[valuePosition+1]; - } - return 0; -} - -uint32_t HanReader::getUint32(uint8_t dataPosition, byte *buffer, int start, int length) { - int valuePosition = findValuePosition(dataPosition, buffer, start, length); - if (valuePosition > 0) { - if(buffer[valuePosition++] != 0x06) - return 0; - uint32_t value = 0; - for (int i = valuePosition; i < valuePosition + 4; i++) { - value = value << 8 | buffer[i]; - } - return value; - } - return 0; -} - -String HanReader::getString(uint8_t dataPosition, byte *buffer, int start, int length) { - int valuePosition = findValuePosition(dataPosition, buffer, start, length); - if (valuePosition > 0) { - String value = String(""); - for (int i = valuePosition + 2; i < valuePosition + buffer[valuePosition + 1] + 2; i++) { - value += String((char)buffer[i]); - } - return value; - } - return String(""); -} - -void HanReader::printD(String fmt, int arg) { - if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(String("(HanReader)" + fmt + "\n").c_str(), arg); -} - -void HanReader::printI(String fmt, int arg) { - if(debugger->isActive(RemoteDebug::INFO)) debugger->printf(String("(HanReader)" + fmt + "\n").c_str(), arg); -} - -void HanReader::printW(String fmt, int arg) { - if(debugger->isActive(RemoteDebug::WARNING)) debugger->printf(String("(HanReader)" + fmt + "\n").c_str(), arg); -} - -void HanReader::printW(String fmt, const char* arg) { - if(debugger->isActive(RemoteDebug::WARNING)) debugger->printf(String("(HanReader)" + fmt + "\n").c_str(), arg); -} - -void HanReader::printE(String fmt, int arg) { - if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf(String("(HanReader)" + fmt + "\n").c_str(), arg); -} diff --git a/lib/HanReader/src/HanReader.h b/lib/HanReader/src/HanReader.h deleted file mode 100644 index d85f018c..00000000 --- a/lib/HanReader/src/HanReader.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef _HANREADER_h -#define _HANREADER_h - -#if defined(ARDUINO) && ARDUINO >= 100 - #include "Arduino.h" -#else - #include "WProgram.h" -#endif - - -#include "DlmsReader.h" -#include -#include "RemoteDebug.h" - -class HanReader -{ -public: - uint dataHeader = 8; - bool compensateFor09HeaderBug = false; - - HanReader(); - void setup(Stream *hanPort); - void setup(Stream *hanPort, RemoteDebug *debug); - bool read(); - bool read(byte data); - int getListSize(); - time_t getPackageTime(bool respectTimezone, bool respectDsc); - int32_t getInt(uint8_t objectId); // Use this for uint8, int8, uint16, int16 - uint32_t getUint(uint8_t objectId); // Only for uint32 - String getString(uint8_t objectId); - time_t getTime(uint8_t objectId, bool respectTimezone, bool respectDsc); - int getBuffer(byte* buf); - - void setEncryptionKey(uint8_t* encryption_key); - void setAuthenticationKey(uint8_t* authentication_key); - -private: - RemoteDebug* debugger; - Stream *han; - byte* buffer; - int bytesRead; - DlmsReader reader; - int listSize; - Timezone *localZone; - uint8_t* encryption_key; - uint8_t* authentication_key; - - int findValuePosition(uint8_t dataPosition, byte *buffer, int start, int length); - - time_t getTime(uint8_t dataPosition, bool respectTimezone, bool respectDsc, byte *buffer, int start, int length); - time_t getTime(byte *buffer, int start, int length, bool respectTimezone, bool respectDsc); - int getInt(uint8_t dataPosition, byte *buffer, int start, int length); - int8_t getInt8(uint8_t dataPosition, byte *buffer, int start, int length); - uint8_t getUint8(uint8_t dataPosition, byte *buffer, int start, int length); - int16_t getInt16(uint8_t dataPosition, byte *buffer, int start, int length); - uint16_t getUint16(uint8_t dataPosition, byte *buffer, int start, int length); - uint32_t getUint32(uint8_t dataPosition, byte *buffer, int start, int length); - String getString(uint8_t dataPosition, byte *buffer, int start, int length); - - time_t toUnixTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second); - - bool decryptFrame(); - - void debugPrint(byte *buffer, int start, int length); - - void printD(String fmt, int arg=0); - void printI(String fmt, int arg=0); - void printW(String fmt, int arg=0); - void printW(String fmt, const char* arg); - void printE(String fmt, int arg=0); -}; - - -#endif diff --git a/lib/HanReader/src/Kaifa.h b/lib/HanReader/src/Kaifa.h deleted file mode 100644 index 7d46c5f6..00000000 --- a/lib/HanReader/src/Kaifa.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef _KAIFA_h -#define _KAIFA_h - -enum class Kaifa { - List1 = 0x01, - List1PhaseShort = 0x09, - List3PhaseShort = 0x0D, - List1PhaseLong = 0x0E, - List3PhaseLong = 0x12 -}; - -enum class Kaifa_List1 { - ListSize, - ActivePowerImported -}; - -enum class Kaifa_List3Phase { - ListSize, - ListVersionIdentifier, - MeterID, - MeterType, - ActiveImportPower, - ActiveExportPower, - ReactiveImportPower, - ReactiveExportPower, - CurrentL1, - CurrentL2, - CurrentL3, - VoltageL1, - VoltageL2, - VoltageL3, - MeterClock, - CumulativeActiveImportEnergy, - CumulativeActiveExportEnergy, - CumulativeReactiveImportEnergy, - CumulativeReactiveExportEnergy -}; - -enum class Kaifa_List1Phase { - ListSize, - ListVersionIdentifier, - MeterID, - MeterType, - ActiveImportPower, - ActiveExportPower, - ReactiveImportPower, - ReactiveExportPower, - CurrentL1, - VoltageL1, - MeterClock, - CumulativeActiveImportEnergy, - CumulativeActiveExportEnergy, - CumulativeReactiveImportEnergy, - CumulativeReactiveExportEnergy -}; - -#endif diff --git a/lib/HanReader/src/Kamstrup.h b/lib/HanReader/src/Kamstrup.h deleted file mode 100644 index ef7db21b..00000000 --- a/lib/HanReader/src/Kamstrup.h +++ /dev/null @@ -1,127 +0,0 @@ -// Kamstrup.h - -#ifndef _KAMSTRUP_h -#define _KAMSTRUP_h - -enum class Kamstrup -{ - List1PhaseShort = 0x11, - List1PhaseLong = 0x1B, - List3PhaseShort = 0x19, - List3PhaseLong = 0x23, - List3PhaseITShort = 0x17, - List3PhaseITLong = 0x21 -}; - -enum class Kamstrup_List3Phase -{ - ListSize, - ListVersionIdentifier, - MeterID_OBIS, - MeterID, - MeterType_OBIS, - MeterType, - ActiveImportPower_OBIS, - ActiveImportPower, - ActiveExportPower_OBIS, - ActiveExportPower, - ReactiveImportPower_OBIS, - ReactiveImportPower, - ReactiveExportPower_OBIS, - ReactiveExportPower, - CurrentL1_OBIS, - CurrentL1, - CurrentL2_OBIS, - CurrentL2, - CurrentL3_OBIS, - CurrentL3, - VoltageL1_OBIS, - VoltageL1, - VoltageL2_OBIS, - VoltageL2, - VoltageL3_OBIS, - VoltageL3, - MeterClock_OBIS, - MeterClock, - CumulativeActiveImportEnergy_OBIS, - CumulativeActiveImportEnergy, - CumulativeActiveExportEnergy_OBIS, - CumulativeActiveExportEnergy, - CumulativeReactiveImportEnergy_OBIS, - CumulativeReactiveImportEnergy, - CumulativeReactiveExportEnergy_OBIS, - CumulativeReactiveExportEnergy -}; - -enum class Kamstrup_List1Phase -{ - ListSize, - ListVersionIdentifier, - MeterID_OBIS, - MeterID, - MeterType_OBIS, - MeterType, - ActiveImportPower_OBIS, - ActiveImportPower, - ActiveExportPower_OBIS, - ActiveExportPower, - ReactiveImportPower_OBIS, - ReactiveImportPower, - ReactiveExportPower_OBIS, - ReactiveExportPower, - CurrentL1_OBIS, - CurrentL1, - VoltageL1_OBIS, - VoltageL1, - MeterClock_OBIS, - MeterClock, - CumulativeActiveImportEnergy_OBIS, - CumulativeActiveImportEnergy, - CumulativeActiveExportEnergy_OBIS, - CumulativeActiveExportEnergy, - CumulativeReactiveImportEnergy_OBIS, - CumulativeReactiveImportEnergy, - CumulativeReactiveExportEnergy_OBIS, - CumulativeReactiveExportEnergy -}; - -enum class Kamstrup_List3PhaseIT -{ - ListSize, - ListVersionIdentifier, - MeterID_OBIS, - MeterID, - MeterType_OBIS, - MeterType, - ActiveImportPower_OBIS, - ActiveImportPower, - ActiveExportPower_OBIS, - ActiveExportPower, - ReactiveImportPower_OBIS, - ReactiveImportPower, - ReactiveExportPower_OBIS, - ReactiveExportPower, - CurrentL1_OBIS, - CurrentL1, - CurrentL3_OBIS, - CurrentL3, - VoltageL1_OBIS, - VoltageL1, - VoltageL2_OBIS, - VoltageL2, - VoltageL3_OBIS, - VoltageL3, - MeterClock_OBIS, - MeterClock, - CumulativeActiveImportEnergy_OBIS, - CumulativeActiveImportEnergy, - CumulativeActiveExportEnergy_OBIS, - CumulativeActiveExportEnergy, - CumulativeReactiveImportEnergy_OBIS, - CumulativeReactiveImportEnergy, - CumulativeReactiveExportEnergy_OBIS, - CumulativeReactiveExportEnergy -}; - -#endif - diff --git a/lib/HanReader/src/Omnipower.h b/lib/HanReader/src/Omnipower.h deleted file mode 100644 index 809d6afb..00000000 --- a/lib/HanReader/src/Omnipower.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef _OMNIPOWER_h -#define _OMNIPOWER_h - -enum class Omnipower { - DLMS = 0x41 -}; - -enum class Omnipower_DLMS { - ListSize, - ListVersionIdentifier, - CumulativeActiveImportEnergy_OBIS, - CumulativeActiveImportEnergy, - CumulativeActiveExportEnergy_OBIS, - CumulativeActiveExportEnergy, - CumulativeReactiveImportEnergy_OBIS, - CumulativeReactiveImportEnergy, - CumulativeReactiveExportEnergy_OBIS, - CumulativeReactiveExportEnergy, - MeterNumber_OBIS, - MeterNumber, - ActiveImportPower_OBIS, - ActiveImportPower, - ActiveExportPower_OBIS, - ActiveExportPower, - ReactiveImportPower_OBIS, - ReactiveImportPower, - ReactiveExportPower_OBIS, - ReactiveExportPower, - MeterClock_OBIS, - MeterClock, - VoltageL1_OBIS, - VoltageL1, - VoltageL2_OBIS, - VoltageL2, - VoltageL3_OBIS, - VoltageL3, - CurrentL1_OBIS, - CurrentL1, - CurrentL2_OBIS, - CurrentL2, - CurrentL3_OBIS, - CurrentL3, - ActiveImportPowerL1_OBIS, - ActiveImportPowerL1, - ActiveImportPowerL2_OBIS, - ActiveImportPowerL2, - ActiveImportPowerL3_OBIS, - ActiveImportPowerL3, - PowerFactorL1_OBIS, - PowerFactorL1, - PowerFactorL2_OBIS, - PowerFactorL2, - PowerFactorL3_OBIS, - PowerFactorL3, - PowerFactor_OBIS, - PowerFactor, - ActiveExportPowerL1_OBIS, - ActiveExportPowerL1, - ActiveExportPowerL2_OBIS, - ActiveExportPowerL2, - ActiveExportPowerL3_OBIS, - ActiveExportPowerL3, - CumulativeActiveExportEnergyL1_OBIS, - CumulativeActiveExportEnergyL1, - CumulativeActiveExportEnergyL2_OBIS, - CumulativeActiveExportEnergyL2, - CumulativeActiveExportEnergyL3_OBIS, - CumulativeActiveExportEnergyL3, - CumulativeActiveImportEnergyL1_OBIS, - CumulativeActiveImportEnergyL1, - CumulativeActiveImportEnergyL2_OBIS, - CumulativeActiveImportEnergyL2, - CumulativeActiveImportEnergyL3_OBIS, - CumulativeActiveImportEnergyL3 -}; - -#endif diff --git a/src/AmsConfiguration.cpp b/src/AmsConfiguration.cpp index f587508b..a81ecc77 100644 --- a/src/AmsConfiguration.cpp +++ b/src/AmsConfiguration.cpp @@ -182,7 +182,12 @@ bool AmsConfiguration::getMeterConfig(MeterConfig& config) { bool AmsConfiguration::setMeterConfig(MeterConfig& config) { MeterConfig existing; if(getMeterConfig(existing)) { - meterChanged |= config.type != existing.type; + meterChanged |= config.baud != existing.baud; + meterChanged |= config.parity != existing.parity; + meterChanged |= config.invert != existing.invert; + meterChanged |= config.distributionSystem != existing.distributionSystem; + meterChanged |= config.mainFuse != existing.mainFuse; + meterChanged |= config.productionCapacity != existing.productionCapacity; meterChanged |= strcmp((char*) config.encryptionKey, (char*) existing.encryptionKey); meterChanged |= strcmp((char*) config.authenticationKey, (char*) existing.authenticationKey); } else { @@ -196,13 +201,14 @@ bool AmsConfiguration::setMeterConfig(MeterConfig& config) { } void AmsConfiguration::clearMeter(MeterConfig& config) { - config.type = 0; + config.baud = 2400; + config.parity = 11; // 8E1 + config.invert = false; config.distributionSystem = 0; config.mainFuse = 0; config.productionCapacity = 0; memset(config.encryptionKey, 0, 16); memset(config.authenticationKey, 0, 16); - config.substituteMissing = false; } bool AmsConfiguration::isMeterChanged() { @@ -521,16 +527,6 @@ bool AmsConfiguration::hasConfig() { EEPROM.end(); } switch(configVersion) { - case 82: - configVersion = -1; // Prevent loop - if(loadConfig82(EEPROM_CONFIG_ADDRESS+1)) { - configVersion = EEPROM_CHECK_SUM; - return true; - } else { - configVersion = 0; - return false; - } - break; case 83: configVersion = -1; // Prevent loop if(loadConfig83(EEPROM_CONFIG_ADDRESS+1)) { @@ -544,20 +540,26 @@ bool AmsConfiguration::hasConfig() { case 86: configVersion = -1; // Prevent loop if(relocateConfig86()) { - configVersion = EEPROM_CHECK_SUM; - return true; + configVersion = 87; + } else { + configVersion = 0; + return false; + } + case 87: + configVersion = -1; // Prevent loop + if(relocateConfig87()) { + configVersion = 88; } else { configVersion = 0; return false; } - break; - break; case EEPROM_CHECK_SUM: return true; default: configVersion = 0; return false; } + return configVersion == EEPROM_CHECK_SUM; } int AmsConfiguration::getConfigVersion() { @@ -602,107 +604,6 @@ void AmsConfiguration::saveTempSensors() { } } -bool AmsConfiguration::loadConfig82(int address) { - ConfigObject82 c; - EEPROM.begin(EEPROM_SIZE); - EEPROM.get(address, c); - - EntsoeConfig entsoe; - clearEntsoe(entsoe); - EEPROM.put(CONFIG_ENTSOE_START, entsoe); - - NtpConfig ntp; - clearNtp(ntp); - EEPROM.put(CONFIG_NTP_START, ntp); - - DomoticzConfig domo { - c.domoELIDX, - c.domoVL1IDX, - c.domoVL2IDX, - c.domoVL3IDX, - c.domoCL1IDX - }; - EEPROM.put(CONFIG_DOMOTICZ_START, domo); - - GpioConfig gpio { - c.hanPin, - c.apPin, - c.ledPin, - c.ledInverted, - c.ledPinRed, - c.ledPinGreen, - c.ledPinBlue, - c.ledRgbInverted, - c.tempSensorPin, - 0xFF, - c.vccPin, - 0, - c.vccMultiplier, - c.vccBootLimit - }; - EEPROM.put(CONFIG_GPIO_START, gpio); - - DebugConfig debug { - c.debugTelnet, - c.debugSerial, - c.debugLevel - }; - EEPROM.put(CONFIG_DEBUG_START, debug); - - MeterConfig meter { - c.meterType, - c.distributionSystem, - c.mainFuse, - c.productionCapacity, - {0}, - {0}, - c.substituteMissing - }; - EEPROM.put(CONFIG_METER_START, meter); - - WebConfig web { - c.authSecurity - }; - strcpy(web.username, c.authUser); - strcpy(web.password, c.authPassword); - EEPROM.put(CONFIG_WEB_START, web); - - MqttConfig mqtt; - strcpy(mqtt.host, c.mqttHost); - mqtt.port = c.mqttPort; - strcpy(mqtt.clientId, c.mqttClientId); - strcpy(mqtt.publishTopic, c.mqttPublishTopic); - strcpy(mqtt.subscribeTopic, c.mqttSubscribeTopic); - strcpy(mqtt.username, c.mqttUser); - strcpy(mqtt.password, c.mqttPassword); - mqtt.payloadFormat = c.mqttPayloadFormat; - mqtt.ssl = c.mqttSsl; - EEPROM.put(CONFIG_MQTT_START, mqtt); - - WiFiConfig wifi; - strcpy(wifi.ssid, c.wifiSsid); - strcpy(wifi.psk, c.wifiPassword); - strcpy(wifi.ip, c.wifiIp); - strcpy(wifi.gateway, c.wifiGw); - strcpy(wifi.subnet, c.wifiSubnet); - strcpy(wifi.dns1, c.wifiDns1); - strcpy(wifi.dns2, c.wifiDns2); - strcpy(wifi.hostname, c.wifiHostname); - wifi.mdns = true; - EEPROM.put(CONFIG_WIFI_START, wifi); - - SystemConfig sys { - c.boardType - }; - EEPROM.put(CONFIG_SYSTEM_START, sys); - - EEPROM.put(EEPROM_CONFIG_ADDRESS, EEPROM_CHECK_SUM); - bool ret = EEPROM.commit(); - EEPROM.end(); - - return ret; -} - bool AmsConfiguration::loadConfig83(int address) { ConfigObject83 c; EEPROM.begin(EEPROM_SIZE); @@ -755,13 +656,14 @@ bool AmsConfiguration::loadConfig83(int address) { EEPROM.put(CONFIG_DEBUG_START, debug); MeterConfig meter { - c.meterType, + 2400, + c.meterType == 3 || c.meterType == 4 ? 3 : 11, + false, c.distributionSystem, c.mainFuse, c.productionCapacity, {0}, - {0}, - c.substituteMissing + {0} }; memcpy(meter.encryptionKey, c.meterEncryptionKey, 16); memcpy(meter.authenticationKey, c.meterAuthenticationKey, 16); @@ -825,6 +727,25 @@ bool AmsConfiguration::relocateConfig86() { mqtt.payloadFormat = mqtt86.payloadFormat; mqtt.ssl = mqtt86.ssl; EEPROM.put(CONFIG_MQTT_START, mqtt); + EEPROM.put(EEPROM_CONFIG_ADDRESS, 87); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; +} + +bool AmsConfiguration::relocateConfig87() { + MeterConfig87 meter87; + MeterConfig meter; + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(CONFIG_METER_START_87, meter87); + meter.baud = 2400; + meter.parity = meter87.type == 3 || meter87.type == 4 ? 3 : 11; + meter.invert = false; + meter.distributionSystem = meter87.distributionSystem; + meter.mainFuse = meter87.mainFuse; + meter.productionCapacity = meter87.productionCapacity; + EEPROM.put(CONFIG_METER_START, meter); + EEPROM.put(EEPROM_CONFIG_ADDRESS, 88); bool ret = EEPROM.commit(); EEPROM.end(); return ret; @@ -986,11 +907,12 @@ void AmsConfiguration::print(Print* debugger) MeterConfig meter; if(getMeterConfig(meter)) { debugger->println("--Meter configuration--"); - debugger->printf("Type: %i\r\n", meter.type); + debugger->printf("Baud: %i\r\n", meter.baud); + debugger->printf("Parity: %i\r\n", meter.parity); + debugger->printf("Invert serial: %s\r\n", meter.invert ? "Yes" : "No"); debugger->printf("Distribution system: %i\r\n", meter.distributionSystem); debugger->printf("Main fuse: %i\r\n", meter.mainFuse); debugger->printf("Production Capacity: %i\r\n", meter.productionCapacity); - debugger->printf("Substitute missing: %s\r\n", meter.substituteMissing ? "Yes" : "No"); debugger->println(""); delay(10); Serial.flush(); diff --git a/src/AmsConfiguration.h b/src/AmsConfiguration.h index dc873aef..09cb5a3b 100644 --- a/src/AmsConfiguration.h +++ b/src/AmsConfiguration.h @@ -4,14 +4,14 @@ #include "Arduino.h" #define EEPROM_SIZE 1024 * 3 -#define EEPROM_CHECK_SUM 87 // Used to check if config is stored. Change if structure changes +#define EEPROM_CHECK_SUM 88 // Used to check if config is stored. Change if structure changes #define EEPROM_CONFIG_ADDRESS 0 #define EEPROM_TEMP_CONFIG_ADDRESS 2048 #define CONFIG_SYSTEM_START 8 #define CONFIG_WIFI_START 16 +#define CONFIG_METER_START 224 #define CONFIG_WEB_START 648 -#define CONFIG_METER_START 784 #define CONFIG_DEBUG_START 824 #define CONFIG_GPIO_START 832 #define CONFIG_DOMOTICZ_START 856 @@ -20,6 +20,7 @@ #define CONFIG_MQTT_START 1004 #define CONFIG_MQTT_START_86 224 +#define CONFIG_METER_START_87 784 struct SystemConfig { @@ -69,6 +70,17 @@ struct WebConfig { }; // 129 struct MeterConfig { + uint32_t baud; + uint8_t parity; + bool invert; + uint8_t distributionSystem; + uint8_t mainFuse; + uint8_t productionCapacity; + uint8_t encryptionKey[16]; + uint8_t authenticationKey[16]; +}; // 41 + +struct MeterConfig87 { uint8_t type; uint8_t distributionSystem; uint8_t mainFuse; @@ -190,60 +202,6 @@ struct ConfigObject83 { uint8_t tempAnalogSensorPin; }; -struct ConfigObject82 { - uint8_t boardType; - char wifiSsid[32]; - char wifiPassword[64]; - char wifiIp[15]; - char wifiGw[15]; - char wifiSubnet[15]; - char wifiDns1[15]; - char wifiDns2[15]; - char wifiHostname[32]; - char mqttHost[128]; - uint16_t mqttPort; - char mqttClientId[32]; - char mqttPublishTopic[64]; - char mqttSubscribeTopic[64]; - char mqttUser[64]; - char mqttPassword[64]; - uint8_t mqttPayloadFormat; - bool mqttSsl; - uint8_t authSecurity; - char authUser[64]; - char authPassword[64]; - - uint8_t meterType; - uint8_t distributionSystem; - uint8_t mainFuse; - uint8_t productionCapacity; - bool substituteMissing; - bool sendUnknown; - - bool debugTelnet; - bool debugSerial; - uint8_t debugLevel; - - uint8_t hanPin; - uint8_t apPin; - uint8_t ledPin; - bool ledInverted; - uint8_t ledPinRed; - uint8_t ledPinGreen; - uint8_t ledPinBlue; - bool ledRgbInverted; - uint8_t tempSensorPin; - uint8_t vccPin; - uint16_t vccMultiplier; - uint8_t vccBootLimit; - - uint16_t domoELIDX; - uint16_t domoVL1IDX; - uint16_t domoVL2IDX; - uint16_t domoVL3IDX; - uint16_t domoCL1IDX; -}; - struct TempSensorConfig { uint8_t address[8]; char name[16]; @@ -334,9 +292,9 @@ private: uint8_t tempSensorCount = 0; TempSensorConfig** tempSensors; - bool loadConfig82(int address); bool loadConfig83(int address); bool relocateConfig86(); + bool relocateConfig87(); int readString(int pAddress, char* pString[]); int readInt(int pAddress, int *pValue); diff --git a/src/AmsData.cpp b/src/AmsData.cpp index 52d642a5..b4f70160 100644 --- a/src/AmsData.cpp +++ b/src/AmsData.cpp @@ -109,25 +109,28 @@ AmsData::AmsData(const char* d, bool substituteMissing) { l3current = s32; } - int vdiv = 1; - int voltage = l1voltage == 0 ? l2voltage == 0 ? l3voltage == 0 ? 0 : l3voltage : l2voltage : l1voltage; - while(voltage > 1000) { - vdiv *= 10; - voltage /= 10; - } + if(listType == 2) { + int vdiv = 1; + int voltage = l1voltage == 0 ? l2voltage == 0 ? l3voltage == 0 ? 0 : l3voltage : l2voltage : l1voltage; + while(voltage > 1000) { + vdiv *= 10; + voltage /= 10; + } - l1voltage = l1voltage != 0 ? l1voltage / vdiv : 0; - l2voltage = l2voltage != 0 ? l2voltage / vdiv : 0; - l3voltage = l3voltage != 0 ? l3voltage / vdiv : 0; + l1voltage = l1voltage != 0 ? l1voltage / vdiv : 0; + l2voltage = l2voltage != 0 ? l2voltage / vdiv : 0; + l3voltage = l3voltage != 0 ? l3voltage / vdiv : 0; - if(meterType == AmsTypeAidon) { - l1current = l1current != 0 ? l1current / 10.0 : 0; - l2current = l2current != 0 ? l2current / 10.0 : 0; - l3current = l3current != 0 ? l3current / 10.0 : 0; - } else if(meterType == AmsTypeKamstrup) { - l1current = l1current != 0 ? l1current / 100.0 : 0; - l2current = l2current != 0 ? l2current / 100.0 : 0; - l3current = l3current != 0 ? l3current / 100.0 : 0; + int adiv = 1; + int watt = (l1voltage * l1current) + (l2voltage * l2current) + (l3voltage * l3current); + while(watt / activeImportPower > 2) { + adiv *= 10; + watt /= 10; + } + + l1current = l1current != 0 ? l1current / adiv : 0; + l2current = l2current != 0 ? l2current / adiv : 0; + l3current = l3current != 0 ? l3current / adiv : 0; } u32 = AMS_getUnsignedNumber(AMS_OBIS_ACTIVE_IMPORT_COUNT, ((char *) (d))); @@ -170,8 +173,8 @@ AmsData::AmsData(const char* d, bool substituteMissing) { twoPhase = (l1voltage > 0 && l2voltage > 0) || (l2voltage > 0 && l3voltage > 0) || (l3voltage > 0 && l1voltage > 0); if(threePhase) { - if(substituteMissing) { - l2current = (((activeImportPower - activeExportPower) * sqrt(3)) - (l1voltage * l1current) - (l3voltage * l3current)) / l2voltage; + if(substituteMissing && l2current == 0) { + l2current = (((activeImportPower - activeExportPower) * sqrt(3)) - (l1voltage * l1current) - (l3voltage * l3current)) / l2voltage; } } diff --git a/src/AmsData.h b/src/AmsData.h index daf93dad..4709d672 100644 --- a/src/AmsData.h +++ b/src/AmsData.h @@ -3,7 +3,6 @@ #include "Arduino.h" #include -#include "HanReader.h" #define METER_TYPE_KAIFA 1 #define METER_TYPE_AIDON 2 @@ -14,7 +13,6 @@ class AmsData { public: AmsData(); AmsData(const char* d, bool substituteMissing); - AmsData(uint8_t meterType, bool substituteMissing, HanReader& hanReader); void apply(AmsData& other); @@ -61,11 +59,6 @@ private: float l1voltage = 0, l2voltage = 0, l3voltage = 0, l1current = 0, l2current = 0, l3current = 0; float activeImportCounter = 0, reactiveImportCounter = 0, activeExportCounter = 0, reactiveExportCounter = 0; bool threePhase = false, twoPhase = false, counterEstimated = false; - - void extractFromKaifa(HanReader& hanReader, uint8_t listSize); - void extractFromAidon(HanReader& hanReader, uint8_t listSize); - void extractFromKamstrup(HanReader& hanReader, uint8_t listSize); - void extractFromOmnipower(HanReader& hanReader, uint8_t listSize); }; #endif diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index 527523c6..931b59c2 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -31,18 +31,12 @@ ADC_MODE(ADC_VCC); #include "web/AmsWebServer.h" #include "AmsConfiguration.h" -#include "HanReader.h" #include "mqtt/AmsMqttHandler.h" #include "mqtt/JsonMqttHandler.h" #include "mqtt/RawMqttHandler.h" #include "mqtt/DomoticzMqttHandler.h" -#include "Aidon.h" -#include "Kaifa.h" -#include "Kamstrup.h" -#include "Omnipower.h" - #include "Uptime.h" #include "RemoteDebug.h" @@ -67,8 +61,6 @@ AmsWebServer ws(&Debug, &hw); MQTTClient mqtt(512); AmsMqttHandler* mqttHandler = NULL; -HanReader hanReader; - Stream *hanSerial; GpioConfig gpioConfig; @@ -144,15 +136,16 @@ void setup() { config.getMeterConfig(meterConfig); if(gpioConfig.hanPin == 3) { shared = true; - switch(meterConfig.type) { - case METER_TYPE_KAMSTRUP: - case METER_TYPE_OMNIPOWER: - Serial.begin(2400, SERIAL_8N1); + SerialConfig serialConfig; + switch(meterConfig.parity) { + case 3: + serialConfig = SERIAL_8N1; break; default: - Serial.begin(2400, SERIAL_8E1); + serialConfig = SERIAL_8E1; break; } + Serial.begin(meterConfig.baud, serialConfig); } if(!shared) { @@ -449,7 +442,7 @@ void loop() { if(config.isMeterChanged()) { config.getMeterConfig(meterConfig); - setupHanPort(gpioConfig.hanPin, meterConfig.type); + setupHanPort(gpioConfig.hanPin, meterConfig.baud, meterConfig.parity, meterConfig.invert); config.ackMeterChanged(); } delay(1); @@ -458,8 +451,8 @@ void loop() { delay(1); // Needed for auto modem sleep } -void setupHanPort(int pin, int newMeterType) { - debugI("Setting up HAN on pin %d for meter type %d", pin, newMeterType); +void setupHanPort(uint8_t pin, uint32_t baud, uint8_t parityOrdinal, bool invert) { + debugI("Setting up HAN on pin %d with baud %d and parity %d", pin, baud, parityOrdinal); HardwareSerial *hwSerial = NULL; if(pin == 3) { @@ -482,42 +475,40 @@ void setupHanPort(int pin, int newMeterType) { if(hwSerial != NULL) { debugD("Hardware serial"); Serial.flush(); - switch(newMeterType) { - case METER_TYPE_KAMSTRUP: - case METER_TYPE_OMNIPOWER: - hwSerial->begin(2400, SERIAL_8N1); + + SerialConfig serialConfig; + switch(parityOrdinal) { + case 3: + serialConfig = SERIAL_8N1; break; default: - hwSerial->begin(2400, SERIAL_8E1); + serialConfig = SERIAL_8E1; break; } + + hwSerial->begin(baud, serialConfig, SERIAL_FULL, -1, invert); hanSerial = hwSerial; } else { debugD("Software serial"); Serial.flush(); - SoftwareSerial *swSerial = new SoftwareSerial(pin); - switch(newMeterType) { - case METER_TYPE_KAMSTRUP: - case METER_TYPE_OMNIPOWER: - swSerial->begin(2400, SWSERIAL_8N1); + SoftwareSerialConfig serialConfig; + switch(parityOrdinal) { + case 3: + serialConfig = SWSERIAL_8N1; break; default: - swSerial->begin(2400, SWSERIAL_8E1); + serialConfig = SWSERIAL_8E1; break; } + + SoftwareSerial *swSerial = new SoftwareSerial(pin, -1, invert); + swSerial->begin(baud, serialConfig); hanSerial = swSerial; Serial.begin(115200); } - hanReader.setup(hanSerial, &Debug); - hanReader.setEncryptionKey(meterConfig.encryptionKey); - hanReader.setAuthenticationKey(meterConfig.authenticationKey); - - // Compensate for the known Kaifa bug - hanReader.compensateFor09HeaderBug = (newMeterType == 1); - // Empty buffer before starting while (hanSerial->available() > 0) { hanSerial->read(); @@ -604,15 +595,16 @@ HDLCConfig* hc = NULL; int currentMeterType = 0; void readHanPort() { uint8_t buf[BUF_SIZE]; + if(!hanSerial->available()) return; size_t len = hanSerial->readBytes(buf, BUF_SIZE); // TODO: read one byte at the time. This blocks up the GUI if(len > 0) { - if(meterConfig.type == 4 && hc == NULL) { + int pos = HDLC_validate((uint8_t *) buf, len, hc); + if(pos == HDLC_ENCRYPTION_CONFIG_MISSING) { hc = new HDLCConfig(); memcpy(hc->encryption_key, meterConfig.encryptionKey, 16); memcpy(hc->authentication_key, meterConfig.authenticationKey, 16); } - int pos = HDLC_validate((uint8_t *) buf, len, hc); - if(Debug.isActive(RemoteDebug::INFO)) { + if(Debug.isActive(RemoteDebug::DEBUG)) { debugD("Frame dump:"); debugPrint(buf, 0, len); if(hc != NULL) { @@ -630,7 +622,7 @@ void readHanPort() { debugI("Valid HDLC, start at %d", pos); if(!hw.ledBlink(LED_GREEN, 1)) hw.ledBlink(LED_INTERNAL, 1); - AmsData data = AmsData(((char *) (buf)) + pos, meterConfig.substituteMissing); + AmsData data = AmsData(((char *) (buf)) + pos, true); if(data.getListType() > 0) { if(mqttEnabled && mqttHandler != NULL) { if(mqttHandler->publish(&data, &meterState)) { @@ -682,95 +674,6 @@ void debugPrint(byte *buffer, int start, int length) { Debug.println(""); } -void oldReadHanPort() { - if (hanReader.read()) { - lastSuccessfulRead = millis(); - delay(1); - - if(meterConfig.type > 0) { - if(!hw.ledBlink(LED_GREEN, 1)) - hw.ledBlink(LED_INTERNAL, 1); - - AmsData data(meterConfig.type, meterConfig.substituteMissing, hanReader); - if(data.getListType() > 0) { - if(mqttEnabled && mqttHandler != NULL) { - if(mqttHandler->publish(&data, &meterState)) { - if(data.getListType() == 3 && eapi != NULL) { - mqttHandler->publishPrices(eapi); - } - if(data.getListType() >= 2) { - mqttHandler->publishSystem(&hw); - } - time_t now = time(nullptr); - if(now < EPOCH_2021_01_01 || data.getListType() == 3) { - if(data.getMeterTimestamp() > EPOCH_2021_01_01 || !ntpEnabled) { - debugI("Using timestamp from meter"); - now = data.getMeterTimestamp(); - } else if(data.getPackageTimestamp() > EPOCH_2021_01_01) { - debugI("Using timestamp from meter (DLMS)"); - now = data.getPackageTimestamp(); - } - if(now > EPOCH_2021_01_01) { - timeval tv { now, 0}; - settimeofday(&tv, nullptr); - } - } - } - mqtt.loop(); - delay(10); - } - meterState.apply(data); - } - } else { - // Auto detect meter if not set - for(int i = 1; i <= 3; i++) { - String list; - switch(i) { - case 1: - list = hanReader.getString((int) Kaifa_List1Phase::ListVersionIdentifier); - break; - case 2: - list = hanReader.getString((int) Aidon_List1Phase::ListVersionIdentifier); - break; - case 3: - list = hanReader.getString((int) Kamstrup_List1Phase::ListVersionIdentifier); - break; - } - if(!list.isEmpty()) { - list.toLowerCase(); - if(list.startsWith("kfm")) { - meterConfig.type = 1; - config.setMeterConfig(meterConfig); - if(Debug.isActive(RemoteDebug::INFO)) debugI("Detected Kaifa meter"); - break; - } else if(list.startsWith("aidon")) { - meterConfig.type = 2; - config.setMeterConfig(meterConfig); - if(Debug.isActive(RemoteDebug::INFO)) debugI("Detected Aidon meter"); - break; - } else if(list.startsWith("kamstrup")) { - meterConfig.type = 3; - config.setMeterConfig(meterConfig); - if(Debug.isActive(RemoteDebug::INFO)) debugI("Detected Kamstrup meter"); - break; - } - } - } - hanReader.compensateFor09HeaderBug = (meterConfig.type == 1); - } - } - - // Switch parity if meter is still not detected - if(meterConfig.type == 0 && millis() - lastSuccessfulRead > 10000) { - lastSuccessfulRead = millis(); - debugD("No data for current setting, switching parity"); - Serial.flush(); - if(++currentMeterType == 4) currentMeterType = 1; - setupHanPort(gpioConfig.hanPin, currentMeterType); - } - delay(1); -} - unsigned long wifiTimeout = WIFI_CONNECTION_TIMEOUT; unsigned long lastWifiRetry = -WIFI_CONNECTION_TIMEOUT; void WiFi_connect() { diff --git a/src/ams/hdlc.cpp b/src/ams/hdlc.cpp index 4e3b8694..5a1a7058 100644 --- a/src/ams/hdlc.cpp +++ b/src/ams/hdlc.cpp @@ -90,7 +90,7 @@ int HDLC_validate(const uint8_t* d, int len, HDLCConfig* config) { // Encrypted APDU // http://www.weigu.lu/tutorials/sensors2bus/04_encryption/index.html if(config == NULL) - return -90; + return HDLC_ENCRYPTION_CONFIG_MISSING; memcpy(config->system_title, d + headersize + 2, 8); memcpy(config->initialization_vector, config->system_title, 8); diff --git a/src/ams/hdlc.h b/src/ams/hdlc.h index 9f618fe2..dc709951 100644 --- a/src/ams/hdlc.h +++ b/src/ams/hdlc.h @@ -5,6 +5,7 @@ #include #define HDLC_FLAG 0x7E +#define HDLC_ENCRYPTION_CONFIG_MISSING -90 struct HDLCConfig { uint8_t encryption_key[32]; diff --git a/src/web/AmsWebServer.cpp b/src/web/AmsWebServer.cpp index 37b5f2f2..b8af05a6 100644 --- a/src/web/AmsWebServer.cpp +++ b/src/web/AmsWebServer.cpp @@ -391,10 +391,13 @@ void AmsWebServer::configMeterHtml() { server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); - html.replace("{m}", String(meterConfig->mainFuse)); - for(int i = 0; i<5; i++) { - html.replace("{m" + String(i) + "}", meterConfig->type == i ? "selected" : ""); - } + html.replace("{b}", String(meterConfig->baud)); + html.replace("{b2400}", meterConfig->baud == 2400 ? "selected" : ""); + html.replace("{b115200}", meterConfig->baud == 115200 ? "selected" : ""); + html.replace("{c}", String(meterConfig->baud)); + html.replace("{c3}", meterConfig->parity == 3 ? "selected" : ""); + html.replace("{c11}", meterConfig->parity == 11 ? "selected" : ""); + html.replace("{i}", meterConfig->invert ? "checked" : ""); html.replace("{d}", String(meterConfig->distributionSystem)); for(int i = 0; i<3; i++) { html.replace("{d" + String(i) + "}", meterConfig->distributionSystem == i ? "selected" : ""); @@ -405,7 +408,7 @@ void AmsWebServer::configMeterHtml() { } html.replace("{p}", String(meterConfig->productionCapacity)); - if(meterConfig->type == METER_TYPE_OMNIPOWER) { + if(meterConfig->encryptionKey[0] != 0x00) { String encryptionKeyHex = "0x"; encryptionKeyHex += toHex(meterConfig->encryptionKey, 16); html.replace("{e}", encryptionKeyHex); @@ -418,8 +421,6 @@ void AmsWebServer::configMeterHtml() { html.replace("{a}", ""); } - html.replace("{s}", meterConfig->substituteMissing ? "checked" : ""); - server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); server.send_P(200, "text/html", HEAD_HTML); server.sendContent(html); @@ -665,7 +666,7 @@ void AmsWebServer::dataJson() { uint8_t hanStatus; - if(meterConfig->type == 0) { + if(meterConfig->baud == 0) { hanStatus = 0; } else if(now - meterState->getLastUpdateMillis() < 15000) { hanStatus = 1; @@ -910,7 +911,9 @@ void AmsWebServer::handleSave() { if(server.hasArg("mc") && server.arg("mc") == "true") { printD("Received meter config"); - meterConfig->type = server.arg("m").toInt(); + meterConfig->baud = server.arg("b").toInt(); + meterConfig->parity = server.arg("c").toInt(); + meterConfig->invert = server.hasArg("i") && server.arg("i") == "true"; meterConfig->distributionSystem = server.arg("d").toInt(); meterConfig->mainFuse = server.arg("f").toInt(); meterConfig->productionCapacity = server.arg("p").toInt(); @@ -926,7 +929,6 @@ void AmsWebServer::handleSave() { authenticationKeyHex.replace("0x", ""); fromHex(meterConfig->authenticationKey, authenticationKeyHex, 16); } - meterConfig->substituteMissing = server.hasArg("s") && server.arg("s") == "true"; config->setMeterConfig(*meterConfig); } diff --git a/web/application.js b/web/application.js index 35d3c7d1..88d0decb 100644 --- a/web/application.js +++ b/web/application.js @@ -74,25 +74,6 @@ $(function() { $('#m').trigger('change'); $('#f').trigger('change'); - // For meter - $('.sd').on('change', function() { - if(($('#mt').val() == 2 || $('#mt').val() == 3) && $('#d').val() == 1) { - $('#ss').show(); - } else { - $('#ss').hide(); - } - }); - - $('#mt').on('change', function() { - if($('#mt').val() == 4) { - $('.enc').show(); - } else { - $('.enc').hide(); - } - }); - - $('#mt').trigger('change'); - // For wifi $('#st').on('change', function() { if($(this).is(':checked')) { diff --git a/web/meter.html b/web/meter.html index 61ffb73d..6ea59565 100644 --- a/web/meter.html +++ b/web/meter.html @@ -3,26 +3,41 @@
Meter
-
+
- Meter type + Baud rate
- + +
+
+
+
+ Parity +
+ +
+
+
+
+ +
+
+
+
Distribution system
- @@ -56,25 +71,22 @@
-
+
+
+
Encryption key
- +
-
+
Authentication key
- -
-
-
-
- +