diff --git a/Arduino Code/Arduino Libraries/HanReader/src/Aidon.h b/Arduino Code/Arduino Libraries/HanReader/src/Aidon.h index c00e905f..2c536284 100644 --- a/Arduino Code/Arduino Libraries/HanReader/src/Aidon.h +++ b/Arduino Code/Arduino Libraries/HanReader/src/Aidon.h @@ -7,6 +7,7 @@ enum class Aidon { List1 = 0x01, + List21 = 0x09, List2 = 0x0D, List3 = 0x12 }; diff --git a/Arduino Code/Arduino Libraries/HanReader/src/Kaifa.h b/Arduino Code/Arduino Libraries/HanReader/src/Kaifa.h index 87e5370c..dd5fea5a 100644 --- a/Arduino Code/Arduino Libraries/HanReader/src/Kaifa.h +++ b/Arduino Code/Arduino Libraries/HanReader/src/Kaifa.h @@ -3,9 +3,9 @@ enum class Kaifa : byte { List1 = 0x01, + List21 = 0x09, List2 = 0x0D, - List3 = 0x12, - List4 = 0x09 + List3 = 0x12 }; enum class Kaifa_List1 { @@ -52,7 +52,7 @@ enum class Kaifa_List3 { CumulativeReactiveExportEnergy }; -enum class Kaifa_List4 { // TODO: Stop using list size like this? +enum class Kaifa_List4 { // TODO: Stop using list size like this? Only really need a single long list. ListSize, ListVersionIdentifier, MeterID, diff --git a/Arduino Code/Arduino Libraries/HanToJson/library.properties b/Arduino Code/Arduino Libraries/HanToJson/library.properties new file mode 100644 index 00000000..946c0272 --- /dev/null +++ b/Arduino Code/Arduino Libraries/HanToJson/library.properties @@ -0,0 +1,9 @@ +name=HANtoJson +version=1.0.0 +author=roarfred +maintainer=roarfred +sentence=HAN support +paragraph=HAN support +category=Sensors +url=https://github.com/roarfred/AmsToMqttBridge +architectures=* diff --git a/Arduino Code/Arduino Libraries/HanToJson/src/HanToJson.cpp b/Arduino Code/Arduino Libraries/HanToJson/src/HanToJson.cpp new file mode 100644 index 00000000..7dd6afb2 --- /dev/null +++ b/Arduino Code/Arduino Libraries/HanToJson/src/HanToJson.cpp @@ -0,0 +1,140 @@ +#include "HanToJson.h" +#include "Aidon.h" +#include "Kaifa.h" +#include "Kamstrup.h" + + +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; + } + + if (listSize >= (int)Kaifa::List21) + { + 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); + } + + if (listSize >= (int)Kaifa::List2) + { + 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); + } + + if (listSize > (int)Kaifa::List3) // Note: Bug in Kaifa? (Should have been '>=') + { + 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); + } +} + +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; + } + + if (listSize >= (int)Aidon::List21) + { + data["lv"] = hanReader.getString( (int)Aidon_List3::ListVersionIdentifier); + data["id"] = hanReader.getString( (int)Aidon_List3::MeterID); + data["type"] = hanReader.getString( (int)Aidon_List3::MeterType); + data["P"] = hanReader.getInt( (int)Aidon_List3::ActiveImportPower); + data["Q"] = hanReader.getInt( (int)Aidon_List3::ReactiveExportPower); + data["I1"] = ((double) hanReader.getInt( (int)Aidon_List3::CurrentL1)) / 10; + data["I2"] = ((double) hanReader.getInt( (int)Aidon_List3::CurrentL2)) / 10; + } + + if (listSize >= (int)Aidon::List2) + { + data["I3"] = ((double) hanReader.getInt( (int)Aidon_List3::CurrentL3)) / 10; + data["U1"] = ((double) hanReader.getInt( (int)Aidon_List3::VoltageL1)) / 10; + data["U2"] = ((double) hanReader.getInt( (int)Aidon_List3::VoltageL2)) / 10; + data["U3"] = ((double) hanReader.getInt( (int)Aidon_List3::VoltageL3)) / 10; + } + + if (listSize >= (int)Aidon::List3) + { + data["tPI"] = hanReader.getInt( (int)Aidon_List3::CumulativeActiveImportEnergy); + data["tPO"] = hanReader.getInt( (int)Aidon_List3::CumulativeActiveExportEnergy); + data["tQI"] = hanReader.getInt( (int)Aidon_List3::CumulativeReactiveImportEnergy); + data["tQO"] = hanReader.getInt( (int)Aidon_List3::CumulativeReactiveExportEnergy); + } +} + +static void hanToJsonKamstrup(JsonObject& data, HanReader& hanReader, Stream *debugger) +{ + int listSize = hanReader.getListSize(); + + if (listSize >= (int)Kamstrup::List1) + { + data["lv"] = hanReader.getString( (int)Kamstrup_List2::ListVersionIdentifier); + data["id"] = hanReader.getString( (int)Kamstrup_List2::MeterID); + data["type"] = hanReader.getString( (int)Kamstrup_List2::MeterType); + data["P"] = hanReader.getInt( (int)Kamstrup_List2::ActiveImportPower); + data["Q"] = hanReader.getInt( (int)Kamstrup_List2::ReactiveImportPower); + data["I1"] = hanReader.getInt( (int)Kamstrup_List2::CurrentL1); + data["I2"] = hanReader.getInt( (int)Kamstrup_List2::CurrentL2); + data["I3"] = hanReader.getInt( (int)Kamstrup_List2::CurrentL3); + data["U1"] = hanReader.getInt( (int)Kamstrup_List2::VoltageL1); + data["U2"] = hanReader.getInt( (int)Kamstrup_List2::VoltageL2); + data["U3"] = hanReader.getInt( (int)Kamstrup_List2::VoltageL3); + } + + if (listSize >= (int)Kamstrup::List2) + { + data["tPI"] = hanReader.getInt( (int)Kamstrup_List2::CumulativeActiveImportEnergy); + data["tPO"] = hanReader.getInt( (int)Kamstrup_List2::CumulativeActiveExportEnergy); + data["tQI"] = hanReader.getInt( (int)Kamstrup_List2::CumulativeReactiveImportEnergy); + data["tQO"] = hanReader.getInt( (int)Kamstrup_List2::CumulativeReactiveExportEnergy); + } +} + +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/Arduino Code/Arduino Libraries/HanToJson/src/HanToJson.h b/Arduino Code/Arduino Libraries/HanToJson/src/HanToJson.h new file mode 100644 index 00000000..a06f4caf --- /dev/null +++ b/Arduino Code/Arduino Libraries/HanToJson/src/HanToJson.h @@ -0,0 +1,17 @@ +#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/Arduino Code/WifiFeatherRestBridge/WifiFeatherRestBridge.ino b/Arduino Code/WifiFeatherRestBridge/WifiFeatherRestBridge.ino index 19ae071f..0ec37bc5 100644 --- a/Arduino Code/WifiFeatherRestBridge/WifiFeatherRestBridge.ino +++ b/Arduino Code/WifiFeatherRestBridge/WifiFeatherRestBridge.ino @@ -1,9 +1,8 @@ #include #include #include -#include "Kaifa.h" -#include "Kamstrup.h" #include "HanReader.h" +#include "HanToJson.h" #include "wifi_client.h" @@ -102,57 +101,6 @@ void readHanPort() // Flash LED on, this shows us that data is received digitalWrite(LED_PIN, HIGH); - // Get the list identifier - int listSize = hanReader.getListSize(); - - switch (meterType) - { - case 1: // Kaifa - readHanPort_Kaifa(listSize); - break; - case 2: // Aidon - readHanPort_Aidon(listSize); - break; - case 3: // Kamstrup - readHanPort_Kamstrup(listSize); - break; - default: - if (debugger) { - debugger->print("Meter type "); - debugger->print(meterType, HEX); - debugger->println(" is unknown"); - } - delay(10000); // TODO: Why sleep? - break; - } - - // Flash LED off - digitalWrite(LED_PIN, LOW); - } -} - -void readHanPort_Aidon(int listSize) -{ - if (debugger) debugger->println("Meter type Aidon is not yet implemented"); - delay(1000); -} - -void readHanPort_Kamstrup(int listSize) -{ - // Only care for the ACtive Power Imported, which is found in the first list - if (listSize == (int)Kamstrup::List1 || listSize == (int)Kamstrup::List2) - { - if (listSize == (int)Kamstrup::List1) - { - String id = hanReader.getString((int)Kamstrup_List1::ListVersionIdentifier); - if (debugger) debugger->println(id); - } - else if (listSize == (int)Kamstrup::List2) - { - String id = hanReader.getString((int)Kamstrup_List2::ListVersionIdentifier); - if (debugger) debugger->println(id); - } - // Get the timestamp (as unix time) from the package time_t time = hanReader.getPackageTime(); if (debugger) debugger->print("Time of the package is: "); @@ -166,150 +114,11 @@ void readHanPort_Kamstrup(int listSize) doc["up"] = millis(); doc["t"] = time; - // Add a sub-structure to the json object, - // to keep the data from the meter itself - JsonObject data = doc.createNestedObject("data"); - - // Based on the list number, get all details - // according to OBIS specifications for the meter - if (listSize == (int)Kamstrup::List1) - { - data["lv"] = hanReader.getString((int)Kamstrup_List1::ListVersionIdentifier); - data["id"] = hanReader.getString((int)Kamstrup_List1::MeterID); - data["type"] = hanReader.getString((int)Kamstrup_List1::MeterType); - data["P"] = hanReader.getInt((int)Kamstrup_List1::ActiveImportPower); - data["Q"] = hanReader.getInt((int)Kamstrup_List1::ReactiveImportPower); - data["I1"] = hanReader.getInt((int)Kamstrup_List1::CurrentL1); - data["I2"] = hanReader.getInt((int)Kamstrup_List1::CurrentL2); - data["I3"] = hanReader.getInt((int)Kamstrup_List1::CurrentL3); - data["U1"] = hanReader.getInt((int)Kamstrup_List1::VoltageL1); - data["U2"] = hanReader.getInt((int)Kamstrup_List1::VoltageL2); - data["U3"] = hanReader.getInt((int)Kamstrup_List1::VoltageL3); - } - else if (listSize == (int)Kamstrup::List2) - { - data["lv"] = hanReader.getString((int)Kamstrup_List2::ListVersionIdentifier);; - data["id"] = hanReader.getString((int)Kamstrup_List2::MeterID); - data["type"] = hanReader.getString((int)Kamstrup_List2::MeterType); - data["P"] = hanReader.getInt((int)Kamstrup_List2::ActiveImportPower); - data["Q"] = hanReader.getInt((int)Kamstrup_List2::ReactiveImportPower); - data["I1"] = hanReader.getInt((int)Kamstrup_List2::CurrentL1); - data["I2"] = hanReader.getInt((int)Kamstrup_List2::CurrentL2); - data["I3"] = hanReader.getInt((int)Kamstrup_List2::CurrentL3); - data["U1"] = hanReader.getInt((int)Kamstrup_List2::VoltageL1); - data["U2"] = hanReader.getInt((int)Kamstrup_List2::VoltageL2); - data["U3"] = hanReader.getInt((int)Kamstrup_List2::VoltageL3); - data["tPI"] = hanReader.getInt((int)Kamstrup_List2::CumulativeActiveImportEnergy); - data["tPO"] = hanReader.getInt((int)Kamstrup_List2::CumulativeActiveExportEnergy); - data["tQI"] = hanReader.getInt((int)Kamstrup_List2::CumulativeReactiveImportEnergy); - data["tQO"] = hanReader.getInt((int)Kamstrup_List2::CumulativeReactiveExportEnergy); - } - - // Write the json to the debug port - if (debugger) { - debugger->print("Sending data to MQTT: "); - serializeJsonPretty(doc, *debugger); - debugger->println(); - } - - // TODO: Post data - //// Make sure we have configured a publish topic - //if (ap.config.mqttPublishTopic == 0 || strlen(ap.config.mqttPublishTopic) == 0) - // return; - - //// Publish the json to the MQTT server - //char msg[1024]; - //serializeJsonPretty(doc, msg, 1024); - //mqtt.publish(ap.config.mqttPublishTopic, msg); - - //if (send_data(&client)) { - // state = 1; - //} - } -} - - -void readHanPort_Kaifa(int listSize) -{ - // 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 || listSize == (int)Kaifa::List4) - { - if (listSize == (int)Kaifa::List1) - { - if (debugger) debugger->println(" (list #1 has no ID)"); - } - else - { - String id = hanReader.getString((int)Kaifa_List2::ListVersionIdentifier); - if (debugger) debugger->println(id); - } - - // 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<500> doc; - DynamicJsonDocument doc(500); // TODO: Too small? - - // Any generic useful info here - //doc["id"] = WiFi.macAddress(); // TODO: Fix? - doc["up"] = millis(); - doc["t"] = time; - // Add a sub-structure to the json object, // to keep the data from the meter itself JsonObject data = doc.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); - } - else if (listSize == (int)Kaifa::List4) - { - 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); - } + hanToJson(data, meterType, hanReader); // Write the json to the debug port if (debugger) { @@ -333,6 +142,9 @@ void readHanPort_Kaifa(int listSize) if (send_data(&client, msg)) { state = 1; } + + // Flash LED off + digitalWrite(LED_PIN, LOW); } } diff --git a/Debugging/Code/Arduino/HanToJsonTest/HanToJsonTest.ino b/Debugging/Code/Arduino/HanToJsonTest/HanToJsonTest.ino new file mode 100644 index 00000000..c7c117dc --- /dev/null +++ b/Debugging/Code/Arduino/HanToJsonTest/HanToJsonTest.ino @@ -0,0 +1,217 @@ +/* + * Simple sketch to simulate reading data from a Kamstrup + * AMS Meter. + * + * Created 24. October 2017 by Roar Fredriksen + */ + +#include +#include "Kaifa.h" +#include "HanReader.h" +#include "HanToJson.h" + +// The HAN Port reader +HanReader hanReader; + +byte meterType = 1; // Start with Kaifa +int sampleIndex = 0; +byte kaifa_samples[] = +{ + // List #1 + 0x7E, 0xA0, 0x27, 0x01, 0x02, 0x01, 0x10, 0x5A, 0x87, 0xE6, 0xE7, 0x00, 0x0F, 0x40, 0x00, 0x00, + 0x00, 0x09, 0x0C, 0x07, 0xE1, 0x09, 0x0E, 0x04, 0x13, 0x1F, 0x02, 0xFF, 0x80, 0x00, 0x00, 0x02, + 0x01, 0x06, 0x00, 0x00, 0x03, 0x98, 0xAB, 0xAD, 0x7E, + + // List#2 + 0x7E, 0xA0, 0x79, 0x01, 0x02, 0x01, 0x10, 0x80, 0x93, 0xE6, 0xE7, 0x00, 0x0F, 0x40, 0x00, 0x00, + 0x00, 0x09, 0x0C, 0x07, 0xE1, 0x09, 0x0E, 0x04, 0x13, 0x1F, 0x0A, 0xFF, 0x80, 0x00, 0x00, 0x02, + 0x0D, 0x09, 0x07, 0x4B, 0x46, 0x4D, 0x5F, 0x30, 0x30, 0x31, 0x09, 0x10, 0x36, 0x39, 0x37, 0x30, + 0x36, 0x33, 0x31, 0x34, 0x30, 0x31, 0x37, 0x35, 0x33, 0x39, 0x38, 0x35, 0x09, 0x08, 0x4D, 0x41, + 0x33, 0x30, 0x34, 0x48, 0x33, 0x45, 0x06, 0x00, 0x00, 0x03, 0x96, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x05, 0x64, 0x06, + 0x00, 0x00, 0x0C, 0x92, 0x06, 0x00, 0x00, 0x0C, 0x49, 0x06, 0x00, 0x00, 0x09, 0x46, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x09, 0x4E, 0x1F, 0x85, 0x7E, + + // List#3 + 0x7E, 0xA0, 0x9B, 0x01, 0x02, 0x01, 0x10, 0xEE, 0xAE, 0xE6, 0xE7, 0x00, 0x0F, 0x40, 0x00, 0x00, + 0x00, 0x09, 0x0C, 0x07, 0xE1, 0x09, 0x0E, 0x04, 0x14, 0x00, 0x0A, 0xFF, 0x80, 0x00, 0x00, 0x02, + 0x12, 0x09, 0x07, 0x4B, 0x46, 0x4D, 0x5F, 0x30, 0x30, 0x31, 0x09, 0x10, 0x36, 0x39, 0x37, 0x30, + 0x36, 0x33, 0x31, 0x34, 0x30, 0x31, 0x37, 0x35, 0x33, 0x39, 0x38, 0x35, 0x09, 0x08, 0x4D, 0x41, + 0x33, 0x30, 0x34, 0x48, 0x33, 0x45, 0x06, 0x00, 0x00, 0x03, 0xFE, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x00, 0x07, 0x91, 0x06, + 0x00, 0x00, 0x0C, 0x9D, 0x06, 0x00, 0x00, 0x0D, 0x66, 0x06, 0x00, 0x00, 0x09, 0x41, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x09, 0x4C, 0x09, 0x0C, 0x07, 0xE1, 0x09, 0x0E, 0x04, 0x14, + 0x00, 0x0A, 0xFF, 0x80, 0x00, 0x00, 0x06, 0x00, 0x02, 0xBF, 0x69, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0xF7, 0x06, 0x00, 0x00, 0x3F, 0xFC, 0x71, 0x71, 0x7E, + + // List#2.1 + 0x7e, 0xa0, 0x65, 0x01, 0x02, 0x01, 0x10, 0xf0, 0x50, 0xe6, 0xe7, 0x00, 0x0f, 0x40, 0x00, 0x00, + 0x00, 0x09, 0x0c, 0x07, 0xe3, 0x05, 0x08, 0x03, 0x16, 0x20, 0x28, 0xff, 0x80, 0x00, 0x00, 0x02, + 0x09, 0x09, 0x07, 0x4b, 0x46, 0x4d, 0x5f, 0x30, 0x30, 0x31, 0x09, 0x10, 0x36, 0x39, 0x37, 0x30, + 0x36, 0x33, 0x31, 0x34, 0x30, 0x31, 0x39, 0x39, 0x31, 0x36, 0x38, 0x34, 0x09, 0x08, 0x4d, 0x41, + 0x31, 0x30, 0x35, 0x48, 0x32, 0x45, 0x06, 0x00, 0x00, 0x03, 0xa5, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x21, 0x06, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x10, 0x0e, 0x06, + 0x00, 0x00, 0x09, 0x0a, 0x98, 0x76, 0x7e, +}; + +byte aidon_samples[] = +{ // From Aidon-HAN-Interface-Description-v10A-ID-34331.pdf + // List 2 sending (1-phase) + 0x7e, 0xa0, 0xd2, 0x41, 0x08, 0x83, 0x13, 0x82, 0xd6, 0xe6, 0xe7, 0x00, 0x0f, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x09, 0x02, 0x02, 0x09, 0x06, 0x01, 0x01, 0x00, 0x02, 0x81, 0xff, 0x0a, 0x0b, + 0x41, 0x49, 0x44, 0x4f, 0x4e, 0x5f, 0x56, 0x30, 0x30, 0x30, 0x31, 0x02, 0x02, 0x09, 0x06, 0x00, + 0x00, 0x60, 0x01, 0x00, 0xff, 0x0a, 0x10, 0x37, 0x33, 0x35, 0x39, 0x39, 0x39, 0x32, 0x38, 0x39, + 0x30, 0x39, 0x34, 0x31, 0x37, 0x34, 0x32, 0x02, 0x02, 0x09, 0x06, 0x00, 0x00, 0x60, 0x01, 0x07, + 0xff, 0x0a, 0x04, 0x36, 0x35, 0x31, 0x35, 0x02, 0x03, 0x09, 0x06, 0x01, 0x00, 0x01, 0x07, 0x00, + 0xff, 0x06, 0x00, 0x00, 0x05, 0x52, 0x02, 0x02, 0x0f, 0x00, 0x16, 0x1b, 0x02, 0x03, 0x09, 0x06, + 0x01, 0x00, 0x02, 0x07, 0x00, 0xff, 0x06, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x0f, 0x00, 0x16, + 0x1b, 0x02, 0x03, 0x09, 0x06, 0x01, 0x00, 0x03, 0x07, 0x00, 0xff, 0x06, 0x00, 0x00, 0x03, 0xe4, + 0x02, 0x02, 0x0f, 0x00, 0x16, 0x1d, 0x02, 0x03, 0x09, 0x06, 0x01, 0x00, 0x04, 0x07, 0x00, 0xff, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x0f, 0x00, 0x16, 0x1d, 0x02, 0x03, 0x09, 0x06, 0x01, + 0x00, 0x1f, 0x07, 0x00, 0xff, 0x10, 0x00, 0x5d, 0x02, 0x02, 0x0f, 0xff, 0x16, 0x21, 0x02, 0x03, + 0x09, 0x06, 0x01, 0x00, 0x20, 0x07, 0x00, 0xff, 0x12, 0x09, 0xc4, 0x02, 0x02, 0x0f, 0xff, 0x16, + 0x23, 0xe0, 0xc4, 0x7e +}; + +byte kamstrup_samples[] = +{ // [2017-10-20 04.43.32.368 - Received 229 (0xE5) bytes] + // List #1 + 0x7E, 0xA0, 0xE2, 0x2B, 0x21, 0x13, 0x23, 0x9A, 0xE6, 0xE7, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x07, 0xE2, 0x03, 0x04, 0x07, 0x14, 0x3B, 0x32, 0xFF, 0x80, 0x00, 0x00, 0x02, 0x19, 0x0A, + 0x0E, 0x4B, 0x61, 0x6D, 0x73, 0x74, 0x72, 0x75, 0x70, 0x5F, 0x56, 0x30, 0x30, 0x30, 0x31, 0x09, + 0x06, 0x01, 0x01, 0x00, 0x00, 0x05, 0xFF, 0x0A, 0x10, 0x35, 0x37, 0x30, 0x36, 0x35, 0x36, 0x37, + 0x32, 0x37, 0x34, 0x33, 0x38, 0x39, 0x37, 0x30, 0x32, 0x09, 0x06, 0x01, 0x01, 0x60, 0x01, 0x01, + 0xFF, 0x0A, 0x12, 0x36, 0x38, 0x34, 0x31, 0x31, 0x32, 0x31, 0x42, 0x4E, 0x32, 0x34, 0x33, 0x31, + 0x30, 0x31, 0x30, 0x34, 0x30, 0x09, 0x06, 0x01, 0x01, 0x01, 0x07, 0x00, 0xFF, 0x06, 0x00, 0x00, + 0x11, 0x28, 0x09, 0x06, 0x01, 0x01, 0x02, 0x07, 0x00, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x06, 0x01, 0x01, 0x03, 0x07, 0x00, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x84, 0x09, 0x06, 0x01, 0x01, + 0x04, 0x07, 0x00, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x00, 0x09, 0x06, 0x01, 0x01, 0x1F, 0x07, 0x00, + 0xFF, 0x06, 0x00, 0x00, 0x05, 0x66, 0x09, 0x06, 0x01, 0x01, 0x33, 0x07, 0x00, 0xFF, 0x06, 0x00, + 0x00, 0x03, 0x0C, 0x09, 0x06, 0x01, 0x01, 0x47, 0x07, 0x00, 0xFF, 0x06, 0x00, 0x00, 0x05, 0x5A, + 0x09, 0x06, 0x01, 0x01, 0x20, 0x07, 0x00, 0xFF, 0x12, 0x00, 0xE0, 0x09, 0x06, 0x01, 0x01, 0x34, + 0x07, 0x00, 0xFF, 0x12, 0x00, 0xDF, 0x09, 0x06, 0x01, 0x01, 0x48, 0x07, 0x00, 0xFF, 0x12, 0x00, + 0xDF, 0xA1, 0xD8, 0x7E, + + // List #2 + 0x7E, 0xA1, 0x2C, 0x2B, 0x21, 0x13, 0xFC, 0x04, 0xE6, 0xE7, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x07, 0xE2, 0x03, 0x04, 0x07, 0x15, 0x00, 0x05, 0xFF, 0x80, 0x00, 0x00, 0x02, 0x23, 0x0A, + 0x0E, 0x4B, 0x61, 0x6D, 0x73, 0x74, 0x72, 0x75, 0x70, 0x5F, 0x56, 0x30, 0x30, 0x30, 0x31, 0x09, + 0x06, 0x01, 0x01, 0x00, 0x00, 0x05, 0xFF, 0x0A, 0x10, 0x35, 0x37, 0x30, 0x36, 0x35, 0x36, 0x37, + 0x32, 0x37, 0x34, 0x33, 0x38, 0x39, 0x37, 0x30, 0x32, 0x09, 0x06, 0x01, 0x01, 0x60, 0x01, 0x01, + 0xFF, 0x0A, 0x12, 0x36, 0x38, 0x34, 0x31, 0x31, 0x32, 0x31, 0x42, 0x4E, 0x32, 0x34, 0x33, 0x31, + 0x30, 0x31, 0x30, 0x34, 0x30, 0x09, 0x06, 0x01, 0x01, 0x01, 0x07, 0x00, 0xFF, 0x06, 0x00, 0x00, + 0x0E, 0x3B, 0x09, 0x06, 0x01, 0x01, 0x02, 0x07, 0x00, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x06, 0x01, 0x01, 0x03, 0x07, 0x00, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x86, 0x09, 0x06, 0x01, 0x01, + 0x04, 0x07, 0x00, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x00, 0x09, 0x06, 0x01, 0x01, 0x1F, 0x07, 0x00, + 0xFF, 0x06, 0x00, 0x00, 0x04, 0x21, 0x09, 0x06, 0x01, 0x01, 0x33, 0x07, 0x00, 0xFF, 0x06, 0x00, + 0x00, 0x03, 0x0C, 0x09, 0x06, 0x01, 0x01, 0x47, 0x07, 0x00, 0xFF, 0x06, 0x00, 0x00, 0x04, 0x1C, + 0x09, 0x06, 0x01, 0x01, 0x20, 0x07, 0x00, 0xFF, 0x12, 0x00, 0xE2, 0x09, 0x06, 0x01, 0x01, 0x34, + 0x07, 0x00, 0xFF, 0x12, 0x00, 0xE0, 0x09, 0x06, 0x01, 0x01, 0x48, 0x07, 0x00, 0xFF, 0x12, 0x00, + 0xDF, 0x09, 0x06, 0x00, 0x01, 0x01, 0x00, 0x00, 0xFF, 0x09, 0x0C, 0x07, 0xE2, 0x03, 0x04, 0x07, + 0x15, 0x00, 0x05, 0xFF, 0x80, 0x00, 0x00, 0x09, 0x06, 0x01, 0x01, 0x01, 0x08, 0x00, 0xFF, 0x06, + 0x00, 0x1A, 0x40, 0x49, 0x09, 0x06, 0x01, 0x01, 0x02, 0x08, 0x00, 0xFF, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x09, 0x06, 0x01, 0x01, 0x03, 0x08, 0x00, 0xFF, 0x06, 0x00, 0x00, 0x05, 0x64, 0x09, 0x06, + 0x01, 0x01, 0x04, 0x08, 0x00, 0xFF, 0x06, 0x00, 0x02, 0x7B, 0x21, 0x20, 0x92, 0x7E +}; + +void setup() { + Serial.begin(115200); + while (!Serial) {} + Serial.println("Serial debugging port initialized"); + + // initialize the HanReader + // (passing no han port, as we are feeding data manually, but provide Serial for debugging) + hanReader.setup(NULL, &Serial); + hanReader.compensateFor09HeaderBug = true; // Starting with Kaifa +} + +void loopKaifa() +{ + if (sampleIndex >= sizeof(kaifa_samples)) + { + meterType++; + sampleIndex = 0; + hanReader.setup(NULL, &Serial); + hanReader.compensateFor09HeaderBug = false; + Serial.println("Done with Kaifa"); + } + + // Read one byte from the "port", and see if we got a full package + if (hanReader.read(kaifa_samples[sampleIndex++])) + { + StaticJsonDocument<500> doc; + JsonObject data = doc.createNestedObject("data"); + + hanToJson(data, meterType, hanReader); + + Serial.println("Kaifa JsonData: "); + serializeJsonPretty(doc, Serial); + Serial.println(); + } +} + +void loopAidon() +{ + if (sampleIndex >= sizeof(aidon_samples)) + { + meterType++; + sampleIndex = 0; + hanReader.setup(NULL, &Serial); + Serial.println("Done with Aidon"); + } + + // Read one byte from the "port", and see if we got a full package + if (hanReader.read(aidon_samples[sampleIndex++])) + { + DynamicJsonDocument doc(500); + JsonObject data = doc.createNestedObject("data"); + + hanToJson(data, meterType, hanReader); + + Serial.println("Aidon JsonData: "); + serializeJsonPretty(doc, Serial); + Serial.println(); + } +} + +void loopKamstrup() +{ + if (sampleIndex >= sizeof(kamstrup_samples)) + { + meterType++; + sampleIndex = 0; + hanReader.setup(NULL, &Serial); + Serial.println("Done with Kamstrup"); + } + + // Read one byte from the "port", and see if we got a full package + if (hanReader.read(kamstrup_samples[sampleIndex++])) + { + DynamicJsonDocument doc(500); + JsonObject data = doc.createNestedObject("data"); + + hanToJson(data, meterType, hanReader); + + Serial.println("Kamstrup JsonData: "); + serializeJsonPretty(doc, Serial); + Serial.println(); + } +} + +void loop() { + delay(2); + + switch (meterType) + { + case 1: // Kaifa + return loopKaifa(); + case 2: // Aidon + return loopAidon(); + case 3: // Kamstrup + return loopKamstrup(); + default: + Serial.println("Done"); + while (true) ; + break; + } +} diff --git a/Debugging/Documentation/Aidon-HAN-Interface-Description-v10A-ID-34331.pdf b/Debugging/Documentation/Aidon-HAN-Interface-Description-v10A-ID-34331.pdf new file mode 100644 index 00000000..c579c142 Binary files /dev/null and b/Debugging/Documentation/Aidon-HAN-Interface-Description-v10A-ID-34331.pdf differ