mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-01-15 16:25:43 +00:00
Merge pull request #5 from vegarwe/develop
Stott modul kort (ESP8266 NodeMCU og ESP32 Feather)
This commit is contained in:
commit
d0118c1dc0
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@
|
||||
[Rr]elease/
|
||||
**/__vm/
|
||||
.DS_Store
|
||||
*.sw[op]
|
||||
.vscode
|
||||
.pio
|
||||
platformio.ini
|
||||
|
||||
@ -5,27 +5,48 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <DallasTemperature.h>
|
||||
#include <OneWire.h>
|
||||
#define HAS_DALLAS_TEMP_SENSOR 1 // Set to zero if Dallas one wire temp sensor is not present
|
||||
#define IS_CUSTOM_AMS_BOARD 1 // Set to zero if using NodeMCU or board not designed by Roar Fredriksen
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <MQTT.h>
|
||||
#include <HanReader.h>
|
||||
#include <Aidon.h>
|
||||
#include <Kaifa.h>
|
||||
#include <Kamstrup.h>
|
||||
#include "configuration.h"
|
||||
#include "accesspoint.h"
|
||||
|
||||
#if HAS_DALLAS_TEMP_SENSOR
|
||||
#include <DallasTemperature.h>
|
||||
#include <OneWire.h>
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#elif defined(ESP32)
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
#include "HanConfigAp.h"
|
||||
#include "HanReader.h"
|
||||
#include "HanToJson.h"
|
||||
|
||||
#define WIFI_CONNECTION_TIMEOUT 30000;
|
||||
|
||||
#if IS_CUSTOM_AMS_BOARD
|
||||
#define LED_PIN 2 // The blue on-board LED of the ESP8266 custom AMS board
|
||||
#define LED_ACTIVE_HIGH 0
|
||||
#define AP_BUTTON_PIN 0
|
||||
#else
|
||||
#define LED_PIN LED_BUILTIN
|
||||
#define LED_ACTIVE_HIGH 1
|
||||
#define AP_BUTTON_PIN INVALID_BUTTON_PIN
|
||||
#endif
|
||||
|
||||
#if HAS_DALLAS_TEMP_SENSOR
|
||||
#define TEMP_SENSOR_PIN 5 // Temperature sensor connected to GPIO5
|
||||
#define LED_PIN 2 // The blue on-board LED of the ESP
|
||||
|
||||
OneWire oneWire(TEMP_SENSOR_PIN);
|
||||
DallasTemperature tempSensor(&oneWire);
|
||||
long lastTempDebug = 0;
|
||||
#endif
|
||||
|
||||
// Object used to boot as Access Point
|
||||
accesspoint ap;
|
||||
HanConfigAp ap;
|
||||
|
||||
// WiFi client and MQTT client
|
||||
WiFiClient *client;
|
||||
@ -38,37 +59,40 @@ HardwareSerial* debugger = NULL;
|
||||
HanReader hanReader;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
void setup()
|
||||
{
|
||||
// Uncomment to debug over the same port as used for HAN communication
|
||||
debugger = &Serial;
|
||||
|
||||
//debugger = &Serial;
|
||||
|
||||
if (debugger) {
|
||||
// Setup serial port for debugging
|
||||
debugger->begin(2400, SERIAL_8E1);
|
||||
while (!&debugger);
|
||||
//debugger->begin(115200);
|
||||
while (!debugger);
|
||||
debugger->println("");
|
||||
debugger->println("Started...");
|
||||
}
|
||||
|
||||
// Assign pin for boot as AP
|
||||
delay(1000);
|
||||
pinMode(0, INPUT_PULLUP);
|
||||
|
||||
// Flash the blue LED, to indicate we can boot as AP now
|
||||
// Flash the LED, to indicate we can boot as AP now
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
|
||||
led_on();
|
||||
|
||||
delay(1000);
|
||||
|
||||
// Initialize the AP
|
||||
ap.setup(0, Serial);
|
||||
|
||||
// Turn off the blue LED
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
ap.setup(AP_BUTTON_PIN, debugger);
|
||||
|
||||
led_off();
|
||||
|
||||
if (!ap.isActivated)
|
||||
{
|
||||
setupWiFi();
|
||||
hanReader.setup(&Serial, 2400, SERIAL_8E1, 0);
|
||||
|
||||
// Configure uart for AMS data
|
||||
Serial.begin(2400, SERIAL_8E1);
|
||||
while (!Serial);
|
||||
|
||||
hanReader.setup(&Serial, debugger);
|
||||
|
||||
// Compensate for the known Kaifa bug
|
||||
hanReader.compensateFor09HeaderBug = (ap.config.meterType == 1);
|
||||
}
|
||||
@ -80,8 +104,8 @@ void loop()
|
||||
// Only do normal stuff if we're not booted as AP
|
||||
if (!ap.loop())
|
||||
{
|
||||
// turn off the blue LED
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
// Turn off the LED
|
||||
led_off();
|
||||
|
||||
// allow the MQTT client some resources
|
||||
mqtt.loop();
|
||||
@ -99,34 +123,57 @@ void loop()
|
||||
}
|
||||
else
|
||||
{
|
||||
// Continously flash the blue LED when AP mode
|
||||
if (millis() / 1000 % 2 == 0)
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
else
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
// Continously flash the LED when AP mode
|
||||
if (millis() / 1000 % 2 == 0) led_on();
|
||||
else led_off();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void led_on()
|
||||
{
|
||||
#if LED_ACTIVE_HIGH
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
#else
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void led_off()
|
||||
{
|
||||
#if LED_ACTIVE_HIGH
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
#else
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void setupWiFi()
|
||||
{
|
||||
// Turn off AP
|
||||
WiFi.enableAP(false);
|
||||
|
||||
|
||||
// Connect to WiFi
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ap.config.ssid, ap.config.ssidPassword);
|
||||
|
||||
|
||||
// Wait for WiFi connection
|
||||
if (debugger) debugger->print("\nWaiting for WiFi to connect...");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
if (debugger) debugger->print(".");
|
||||
delay(500);
|
||||
}
|
||||
|
||||
client = new WiFiClient();
|
||||
if (debugger) debugger->println(" connected");
|
||||
|
||||
client = new WiFiClient();
|
||||
mqtt.begin(ap.config.mqtt, *client);
|
||||
|
||||
// Direct incoming MQTT messages
|
||||
if (ap.config.mqttSubscribeTopic != 0 && strlen(ap.config.mqttSubscribeTopic) > 0) {
|
||||
mqtt.subscribe(ap.config.mqttSubscribeTopic);
|
||||
mqtt.onMessage(mqttMessageReceived);
|
||||
mqtt.subscribe(ap.config.mqttSubscribeTopic);
|
||||
mqtt.onMessage(mqttMessageReceived);
|
||||
}
|
||||
|
||||
// Notify everyone we're here!
|
||||
@ -153,333 +200,65 @@ void readHanPort()
|
||||
if (hanReader.read())
|
||||
{
|
||||
// Flash LED on, this shows us that data is received
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
led_on();
|
||||
|
||||
// Get the list identifier
|
||||
int listSize = hanReader.getListSize();
|
||||
// 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);
|
||||
|
||||
switch (ap.config.meterType)
|
||||
// Define a json object to keep the data
|
||||
StaticJsonDocument<500> json;
|
||||
|
||||
// Any generic useful info here
|
||||
json["id"] = WiFi.macAddress();
|
||||
json["up"] = millis();
|
||||
json["t"] = time;
|
||||
|
||||
// Add a sub-structure to the json object,
|
||||
// to keep the data from the meter itself
|
||||
JsonObject data = json.createNestedObject("data");
|
||||
|
||||
#if HAS_DALLAS_TEMP_SENSOR
|
||||
// Get the temperature too
|
||||
tempSensor.requestTemperatures();
|
||||
data["temp"] = tempSensor.getTempCByIndex(0);
|
||||
#endif
|
||||
|
||||
hanToJson(data, ap.config.meterType, hanReader);
|
||||
|
||||
// Write the json to the debug port
|
||||
if (debugger) {
|
||||
debugger->print("Sending data to MQTT: ");
|
||||
serializeJsonPretty(json, *debugger);
|
||||
debugger->println();
|
||||
}
|
||||
|
||||
// Make sure we have configured a publish topic
|
||||
if (! ap.config.mqttPublishTopic == 0 || strlen(ap.config.mqttPublishTopic) == 0)
|
||||
{
|
||||
case 1: // Kaifa
|
||||
readHanPort_Kaifa(listSize);
|
||||
break;
|
||||
case 2: // Aidon
|
||||
readHanPort_Aidon(listSize);
|
||||
break;
|
||||
case 3: // Kamstrup
|
||||
readHanPort_Kamstrup(listSize);
|
||||
break;
|
||||
default:
|
||||
debugger->print("Meter type ");
|
||||
debugger->print(ap.config.meterType, HEX);
|
||||
debugger->println(" is unknown");
|
||||
delay(10000);
|
||||
break;
|
||||
// Publish the json to the MQTT server
|
||||
String msg;
|
||||
serializeJson(json, msg);
|
||||
|
||||
mqtt.publish(ap.config.mqttPublishTopic, msg.c_str());
|
||||
mqtt.loop();
|
||||
}
|
||||
|
||||
// Flash LED off
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
led_off();
|
||||
}
|
||||
}
|
||||
|
||||
void readHanPort_Aidon(int listSize)
|
||||
{
|
||||
if (listSize == (int)Aidon::List1 || listSize == (int)Aidon::List2 || listSize == (int)Aidon::List3 || listSize == (int)Aidon::List2_1p)
|
||||
{
|
||||
if (listSize == (int)Aidon::List2)
|
||||
{
|
||||
String id = hanReader.getString((int)Aidon_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
|
||||
StaticJsonBuffer<500> jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.createObject();
|
||||
|
||||
// Any generic useful info here
|
||||
root["id"] = WiFi.macAddress();
|
||||
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");
|
||||
|
||||
// Get the temperature too
|
||||
tempSensor.requestTemperatures();
|
||||
float temperature = tempSensor.getTempCByIndex(0);
|
||||
data["temp"] = temperature;
|
||||
|
||||
// Based on the list number, get all details
|
||||
// according to OBIS specifications for the meter
|
||||
if (listSize == (int)Aidon::List1)
|
||||
{
|
||||
data["P"] = hanReader.getInt((int)Aidon_List1::ActiveImportPower);
|
||||
}
|
||||
else if (listSize == (int)Aidon::List2)
|
||||
{
|
||||
data["lv"] = hanReader.getString((int)Aidon_List2::ListVersionIdentifier);
|
||||
data["id"] = hanReader.getString((int)Aidon_List2::MeterID);
|
||||
data["type"] = hanReader.getString((int)Aidon_List2::MeterType);
|
||||
data["P"] = hanReader.getInt((int)Aidon_List2::ActiveImportPower);
|
||||
data["Q"] = hanReader.getInt((int)Aidon_List2::ReactiveExportPower);
|
||||
data["I1"] = ((double) hanReader.getInt((int)Aidon_List2::CurrentL1)) / 10;
|
||||
data["I2"] = ((double) hanReader.getInt((int)Aidon_List2::CurrentL2)) / 10;
|
||||
data["I3"] = ((double) hanReader.getInt((int)Aidon_List2::CurrentL3)) / 10;
|
||||
data["U1"] = ((double) hanReader.getInt((int)Aidon_List2::VoltageL1)) / 10;
|
||||
data["U2"] = ((double) hanReader.getInt((int)Aidon_List2::VoltageL2)) / 10;
|
||||
data["U3"] = ((double) hanReader.getInt((int)Aidon_List2::VoltageL3)) / 10;
|
||||
}
|
||||
else if (listSize == (int)Aidon::List2_1p)
|
||||
{
|
||||
data["lv"] = hanReader.getString((int)Aidon_List2_1p::ListVersionIdentifier);
|
||||
data["id"] = hanReader.getString((int)Aidon_List2_1p::MeterID);
|
||||
data["type"] = hanReader.getString((int)Aidon_List2_1p::MeterType);
|
||||
data["P"] = hanReader.getInt((int)Aidon_List2_1p::ActiveImportPower);
|
||||
data["Q"] = hanReader.getInt((int)Aidon_List2_1p::ReactiveExportPower);
|
||||
data["I1"] = ((double) hanReader.getInt((int)Aidon_List2_1p::Current)) / 10;
|
||||
data["U1"] = ((double) hanReader.getInt((int)Aidon_List2_1p::Voltage)) / 10;
|
||||
}
|
||||
else if (listSize == (int)Aidon::List3)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
// Write the json to the debug port
|
||||
if (debugger) {
|
||||
debugger->print("Sending data to MQTT: ");
|
||||
root.printTo(*debugger);
|
||||
debugger->println();
|
||||
}
|
||||
|
||||
// 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];
|
||||
root.printTo(msg, 1024);
|
||||
mqtt.publish(ap.config.mqttPublishTopic, msg);
|
||||
mqtt.loop();
|
||||
}
|
||||
}
|
||||
|
||||
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: ");
|
||||
if (debugger) debugger->println(time);
|
||||
|
||||
// Define a json object to keep the data
|
||||
StaticJsonBuffer<500> jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.createObject();
|
||||
|
||||
// Any generic useful info here
|
||||
root["id"] = WiFi.macAddress();
|
||||
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");
|
||||
|
||||
// Get the temperature too
|
||||
tempSensor.requestTemperatures();
|
||||
float temperature = tempSensor.getTempCByIndex(0);
|
||||
data["temp"] = temperature;
|
||||
|
||||
// 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: ");
|
||||
root.printTo(*debugger);
|
||||
debugger->println();
|
||||
}
|
||||
|
||||
// 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];
|
||||
root.printTo(msg, 1024);
|
||||
mqtt.publish(ap.config.mqttPublishTopic, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
//StaticJsonBuffer<500> jsonBuffer;
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.createObject();
|
||||
|
||||
// Any generic useful info here
|
||||
root["id"] = WiFi.macAddress();
|
||||
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");
|
||||
|
||||
// Get the temperature too
|
||||
tempSensor.requestTemperatures();
|
||||
float temperature = tempSensor.getTempCByIndex(0);
|
||||
data["temp"] = String(temperature);
|
||||
|
||||
// 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
|
||||
if (debugger) {
|
||||
debugger->print("Sending data to MQTT: ");
|
||||
root.printTo(*debugger);
|
||||
debugger->println();
|
||||
}
|
||||
|
||||
// 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];
|
||||
root.printTo(msg, 1024);
|
||||
mqtt.publish(ap.config.mqttPublishTopic, msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to connect and reconnect as necessary to the MQTT server.
|
||||
// Should be called in the loop function and it will take care if connecting.
|
||||
void MQTT_connect()
|
||||
void MQTT_connect()
|
||||
{
|
||||
// Connect to WiFi access point.
|
||||
if (debugger)
|
||||
{
|
||||
debugger->println();
|
||||
debugger->println();
|
||||
debugger->println();
|
||||
debugger->print("Connecting to WiFi network ");
|
||||
debugger->println(ap.config.ssid);
|
||||
@ -498,7 +277,7 @@ void MQTT_connect()
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(50);
|
||||
if (debugger) debugger->print(".");
|
||||
|
||||
|
||||
// If we timed out, disconnect and try again
|
||||
if (vTimeout < millis())
|
||||
{
|
||||
@ -528,9 +307,8 @@ void MQTT_connect()
|
||||
|
||||
// Wait for the MQTT connection to complete
|
||||
while (!mqtt.connected()) {
|
||||
|
||||
// Connect to a unsecure or secure MQTT server
|
||||
if ((ap.config.mqttUser == 0 && mqtt.connect(ap.config.mqttClientID)) ||
|
||||
if ((ap.config.mqttUser == 0 && mqtt.connect(ap.config.mqttClientID)) ||
|
||||
(ap.config.mqttUser != 0 && mqtt.connect(ap.config.mqttClientID, ap.config.mqttUser, ap.config.mqttPass)))
|
||||
{
|
||||
if (debugger) debugger->println("\nSuccessfully connected to MQTT!");
|
||||
@ -559,7 +337,7 @@ void MQTT_connect()
|
||||
|
||||
// Allow some resources for the WiFi connection
|
||||
yield();
|
||||
delay(2000);
|
||||
delay(2000);
|
||||
}
|
||||
}
|
||||
|
||||
@ -576,16 +354,18 @@ void sendMqttData(String data)
|
||||
}
|
||||
|
||||
// Build a json with the message in a "data" attribute
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonObject& json = jsonBuffer.createObject();
|
||||
StaticJsonDocument<500> json;
|
||||
json["id"] = WiFi.macAddress();
|
||||
json["up"] = millis();
|
||||
json["data"] = data;
|
||||
|
||||
// Stringify the json
|
||||
String msg;
|
||||
json.printTo(msg);
|
||||
serializeJson(json, msg);
|
||||
|
||||
// Send the json over MQTT
|
||||
mqtt.publish(ap.config.mqttPublishTopic, msg.c_str());
|
||||
|
||||
if (debugger) debugger->print("sendMqttData: ");
|
||||
if (debugger) debugger->println(data);
|
||||
}
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
name=HanConfigAp
|
||||
version=1.0.0
|
||||
author=roarfred
|
||||
maintainer=roarfred <not@important.com>
|
||||
sentence=HAN Configuraiton accesspoint
|
||||
paragraph=HAN Configuraiton accesspoint
|
||||
category=Sensors
|
||||
url=https://github.com/roarfred/AmsToMqttBridge
|
||||
architectures=*
|
||||
@ -1,19 +1,19 @@
|
||||
//
|
||||
//
|
||||
//
|
||||
#include "HanConfigAp.h"
|
||||
|
||||
#include "accesspoint.h"
|
||||
#if defined(ESP8266)
|
||||
ESP8266WebServer HanConfigAp::server(80);
|
||||
#elif defined(ESP32) // ARDUINO_ARCH_ESP32
|
||||
WebServer HanConfigAp::server(80);
|
||||
#endif
|
||||
Stream* HanConfigAp::debugger;
|
||||
|
||||
ESP8266WebServer accesspoint::server(80);
|
||||
Stream* accesspoint::debugger;
|
||||
|
||||
bool accesspoint::hasConfig() {
|
||||
bool HanConfigAp::hasConfig() {
|
||||
return config.hasConfig();
|
||||
}
|
||||
|
||||
void accesspoint::setup(int accessPointButtonPin, Stream& debugger)
|
||||
void HanConfigAp::setup(int accessPointButtonPin, Stream* debugger)
|
||||
{
|
||||
this->debugger = &debugger;
|
||||
this->debugger = debugger;
|
||||
|
||||
// Test if we're missing configuration
|
||||
if (!config.hasConfig())
|
||||
@ -26,23 +26,29 @@ void accesspoint::setup(int accessPointButtonPin, Stream& debugger)
|
||||
{
|
||||
// Load the configuration
|
||||
config.load();
|
||||
if (this->debugger) config.print(debugger);
|
||||
if (this->debugger) config.print(this->debugger);
|
||||
|
||||
// Test if we're holding down the AP pin, over 5 seconds
|
||||
int time = millis() + 5000;
|
||||
print("Press the AP button now to boot as access point");
|
||||
while (millis() < time)
|
||||
if (accessPointButtonPin != INVALID_BUTTON_PIN)
|
||||
{
|
||||
print(".");
|
||||
if (digitalRead(accessPointButtonPin) == LOW)
|
||||
// Assign pin for boot as AP
|
||||
pinMode(accessPointButtonPin, INPUT_PULLUP);
|
||||
|
||||
// Test if we're holding down the AP pin, over 5 seconds
|
||||
int time = millis() + 5000;
|
||||
print("Press the AP button now to boot as access point");
|
||||
while (millis() < time)
|
||||
{
|
||||
println("");
|
||||
print("AP button was pressed. Booting as access point now. Look for SSID ");
|
||||
println(this->AP_SSID);
|
||||
isActivated = true;
|
||||
break;
|
||||
print(".");
|
||||
if (digitalRead(accessPointButtonPin) == LOW)
|
||||
{
|
||||
print("AP button was pressed. Booting as access point now. Look for SSID ");
|
||||
println(this->AP_SSID);
|
||||
isActivated = true;
|
||||
break;
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
delay(100);
|
||||
println("");
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,7 +77,7 @@ void accesspoint::setup(int accessPointButtonPin, Stream& debugger)
|
||||
}
|
||||
}
|
||||
|
||||
bool accesspoint::loop() {
|
||||
bool HanConfigAp::loop() {
|
||||
if (isActivated)
|
||||
{
|
||||
//DNS
|
||||
@ -87,7 +93,7 @@ bool accesspoint::loop() {
|
||||
}
|
||||
|
||||
/** Handle root or redirect to captive portal */
|
||||
void accesspoint::handleRoot() {
|
||||
void HanConfigAp::handleRoot() {
|
||||
println("Serving / over http...");
|
||||
|
||||
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
@ -102,7 +108,7 @@ void accesspoint::handleRoot() {
|
||||
}
|
||||
|
||||
|
||||
void accesspoint::handleSave() {
|
||||
void HanConfigAp::handleSave() {
|
||||
configuration *config = new configuration();
|
||||
|
||||
String temp;
|
||||
@ -145,13 +151,17 @@ void accesspoint::handleSave() {
|
||||
|
||||
println("Saving configuration now...");
|
||||
|
||||
if (accesspoint::debugger) config->print(*accesspoint::debugger);
|
||||
if (HanConfigAp::debugger) config->print(HanConfigAp::debugger);
|
||||
if (config->save())
|
||||
{
|
||||
println("Successfully saved. Will roboot now.");
|
||||
String html = "<html><body><h1>Successfully Saved!</h1><h3>Device is restarting now...</h3></form>";
|
||||
server.send(200, "text/html", html);
|
||||
#if defined(ESP8266)
|
||||
ESP.reset();
|
||||
#elif defined(ESP32)
|
||||
ESP.restart();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -161,19 +171,19 @@ void accesspoint::handleSave() {
|
||||
}
|
||||
}
|
||||
|
||||
size_t accesspoint::print(const char* text)
|
||||
size_t HanConfigAp::print(const char* text)
|
||||
{
|
||||
if (debugger) debugger->print(text);
|
||||
}
|
||||
size_t accesspoint::println(const char* text)
|
||||
size_t HanConfigAp::println(const char* text)
|
||||
{
|
||||
if (debugger) debugger->println(text);
|
||||
}
|
||||
size_t accesspoint::print(const Printable& data)
|
||||
size_t HanConfigAp::print(const Printable& data)
|
||||
{
|
||||
if (debugger) debugger->print(data);
|
||||
}
|
||||
size_t accesspoint::println(const Printable& data)
|
||||
size_t HanConfigAp::println(const Printable& data)
|
||||
{
|
||||
if (debugger) debugger->println(data);
|
||||
}
|
||||
@ -9,14 +9,24 @@
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#elif defined(ESP32) // ARDUINO_ARCH_ESP32
|
||||
#include <WiFi.h>
|
||||
#include <WebServer.h>
|
||||
#else
|
||||
#warning "Unsupported board type"
|
||||
#endif
|
||||
|
||||
#include <DNSServer.h>
|
||||
#include "configuration.h"
|
||||
|
||||
class accesspoint {
|
||||
#define INVALID_BUTTON_PIN 0xFFFFFFFF
|
||||
|
||||
class HanConfigAp {
|
||||
public:
|
||||
void setup(int accessPointButtonPin, Stream& debugger);
|
||||
void setup(int accessPointButtonPin, Stream* debugger);
|
||||
bool loop();
|
||||
bool hasConfig();
|
||||
configuration config;
|
||||
@ -37,7 +47,11 @@ private:
|
||||
// Web server
|
||||
static void handleRoot();
|
||||
static void handleSave();
|
||||
#if defined(ESP8266)
|
||||
static ESP8266WebServer server;
|
||||
#elif defined(ESP32) // ARDUINO_ARCH_ESP32
|
||||
static WebServer server;
|
||||
#endif
|
||||
|
||||
static Stream* debugger;
|
||||
};
|
||||
@ -145,7 +145,7 @@ int configuration::saveByte(int address, byte value)
|
||||
EEPROM.write(address, value);
|
||||
return 1;
|
||||
}
|
||||
void configuration::print(Stream& serial)
|
||||
void configuration::print(Stream* debugger)
|
||||
{
|
||||
/*
|
||||
char* ssid;
|
||||
@ -161,24 +161,24 @@ void configuration::print(Stream& serial)
|
||||
char* mqttPass;
|
||||
*/
|
||||
|
||||
serial.println("Configuration:");
|
||||
serial.println("-----------------------------------------------");
|
||||
serial.printf("ssid: %s\r\n", this->ssid);
|
||||
serial.printf("ssidPassword: %s\r\n", this->ssidPassword);
|
||||
serial.printf("meterType: %i\r\n", this->meterType);
|
||||
serial.printf("mqtt: %s\r\n", this->mqtt);
|
||||
serial.printf("mqttPort: %i\r\n", this->mqttPort);
|
||||
serial.printf("mqttClientID: %s\r\n", this->mqttClientID);
|
||||
serial.printf("mqttPublishTopic: %s\r\n", this->mqttPublishTopic);
|
||||
serial.printf("mqttSubscribeTopic: %s\r\n", this->mqttSubscribeTopic);
|
||||
debugger->println("Configuration:");
|
||||
debugger->println("-----------------------------------------------");
|
||||
debugger->printf("ssid: %s\r\n", this->ssid);
|
||||
debugger->printf("ssidPassword: %s\r\n", this->ssidPassword);
|
||||
debugger->printf("meterType: %i\r\n", this->meterType);
|
||||
debugger->printf("mqtt: %s\r\n", this->mqtt);
|
||||
debugger->printf("mqttPort: %i\r\n", this->mqttPort);
|
||||
debugger->printf("mqttClientID: %s\r\n", this->mqttClientID);
|
||||
debugger->printf("mqttPublishTopic: %s\r\n", this->mqttPublishTopic);
|
||||
debugger->printf("mqttSubscribeTopic: %s\r\n", this->mqttSubscribeTopic);
|
||||
|
||||
if (this->isSecure())
|
||||
{
|
||||
serial.printf("SECURE MQTT CONNECTION:\r\n");
|
||||
serial.printf("mqttUser: %s\r\n", this->mqttUser);
|
||||
serial.printf("mqttPass: %s\r\n", this->mqttPass);
|
||||
debugger->printf("SECURE MQTT CONNECTION:\r\n");
|
||||
debugger->printf("mqttUser: %s\r\n", this->mqttUser);
|
||||
debugger->printf("mqttPass: %s\r\n", this->mqttPass);
|
||||
}
|
||||
serial.println("-----------------------------------------------");
|
||||
debugger->println("-----------------------------------------------");
|
||||
}
|
||||
|
||||
template <class T> int configuration::writeAnything(int ee, const T& value)
|
||||
@ -30,7 +30,7 @@ public:
|
||||
bool save();
|
||||
bool load();
|
||||
|
||||
void print(Stream& serial);
|
||||
void print(Stream* debugger);
|
||||
protected:
|
||||
|
||||
private:
|
||||
@ -6,10 +6,11 @@
|
||||
|
||||
enum class Aidon
|
||||
{
|
||||
List1 = 0x01,
|
||||
List2 = 0x0D,
|
||||
List2_1p = 0x09,
|
||||
List3 = 0x12
|
||||
List1 = 0x01,
|
||||
List1PhaseShort = 0x09,
|
||||
List1PhaseLong = 0xff, // TODO: Need sample
|
||||
List3PhaseShort = 0x0D,
|
||||
List3PhaseLong = 0x12
|
||||
};
|
||||
|
||||
enum class Aidon_List1
|
||||
@ -24,7 +25,7 @@ enum class Aidon_List1
|
||||
};
|
||||
|
||||
|
||||
enum class Aidon_List2
|
||||
enum class Aidon_List1Phase
|
||||
{
|
||||
ListSize,
|
||||
IGN_0,
|
||||
@ -67,88 +68,14 @@ enum class Aidon_List2
|
||||
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,
|
||||
IGN_14,
|
||||
VoltageL1Int8,
|
||||
VoltageL1Enum,
|
||||
IGN_19,
|
||||
VoltageL2_OBIS,
|
||||
VoltageL2,
|
||||
IGN_20,
|
||||
VoltageL2Int8,
|
||||
VoltageL2Enum,
|
||||
IGN_21,
|
||||
VoltageL3_OBIS,
|
||||
VoltageL3,
|
||||
IGN_22,
|
||||
VoltageL3Int8,
|
||||
VoltageL3Enum
|
||||
};
|
||||
|
||||
enum class Aidon_List2_1p
|
||||
{
|
||||
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,
|
||||
Current_OBIS,
|
||||
Current,
|
||||
IGN_12,
|
||||
CurrentInt8,
|
||||
CurrentEnum,
|
||||
IGN_13,
|
||||
Voltage_OBIS,
|
||||
Voltage,
|
||||
IGN_14,
|
||||
VoltageInt8,
|
||||
VoltageEnum
|
||||
};
|
||||
|
||||
enum class Aidon_List3
|
||||
enum class Aidon_List3Phase
|
||||
{
|
||||
ListSize,
|
||||
IGN_0,
|
||||
|
||||
@ -5,15 +5,8 @@ HanReader::HanReader()
|
||||
|
||||
}
|
||||
|
||||
void HanReader::setup(HardwareSerial *hanPort, unsigned long baudrate, SerialConfig config, Stream *debugPort)
|
||||
void HanReader::setup(HardwareSerial *hanPort, Stream *debugPort)
|
||||
{
|
||||
// Initialize H/W serial port for MBus communication
|
||||
if (hanPort != NULL)
|
||||
{
|
||||
hanPort->begin(baudrate, config);
|
||||
while (!hanPort) {}
|
||||
}
|
||||
|
||||
han = hanPort;
|
||||
bytesRead = 0;
|
||||
debug = debugPort;
|
||||
@ -22,12 +15,7 @@ void HanReader::setup(HardwareSerial *hanPort, unsigned long baudrate, SerialCon
|
||||
|
||||
void HanReader::setup(HardwareSerial *hanPort)
|
||||
{
|
||||
setup(hanPort, 2400, SERIAL_8E1, NULL);
|
||||
}
|
||||
|
||||
void HanReader::setup(HardwareSerial *hanPort, Stream *debugPort)
|
||||
{
|
||||
setup(hanPort, 2400, SERIAL_8E1, debugPort);
|
||||
setup(hanPort, NULL);
|
||||
}
|
||||
|
||||
bool HanReader::read(byte data)
|
||||
@ -63,10 +51,13 @@ bool HanReader::read(byte data)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (debug) debug->println("HAN data is valid");
|
||||
listSize = getInt(0, buffer, 0, bytesRead);
|
||||
if (debug) debug->print("HAN data is valid, listSize: ");
|
||||
if (debug) debug->println(listSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void HanReader::debugPrint(byte *buffer, int start, int length)
|
||||
@ -81,7 +72,7 @@ void HanReader::debugPrint(byte *buffer, int start, int length)
|
||||
debug->println("");
|
||||
else if ((i - start + 1) % 4 == 0)
|
||||
debug->print(" ");
|
||||
|
||||
|
||||
yield(); // Let other get some resources too
|
||||
}
|
||||
debug->println("");
|
||||
@ -294,4 +285,4 @@ time_t HanReader::toUnixTime(int year, int month, int day, int hour, int minute,
|
||||
time += second;
|
||||
|
||||
return (time_t)time;
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,6 @@ public:
|
||||
HanReader();
|
||||
void setup(HardwareSerial *hanPort);
|
||||
void setup(HardwareSerial *hanPort, Stream *debugPort);
|
||||
void setup(HardwareSerial *hanPort, unsigned long baudrate, SerialConfig config, Stream *debugPort);
|
||||
bool read();
|
||||
bool read(byte data);
|
||||
int getListSize();
|
||||
|
||||
@ -2,9 +2,11 @@
|
||||
#define _KAIFA_h
|
||||
|
||||
enum class Kaifa : byte {
|
||||
List1 = 0x01,
|
||||
List2 = 0x0D,
|
||||
List3 = 0x12
|
||||
List1 = 0x01,
|
||||
List1PhaseShort = 0x09,
|
||||
List3PhaseShort = 0x0D,
|
||||
List1PhaseLong = 0x0E,
|
||||
List3PhaseLong = 0x12
|
||||
};
|
||||
|
||||
enum class Kaifa_List1 {
|
||||
@ -12,24 +14,7 @@ enum class Kaifa_List1 {
|
||||
ActivePowerImported
|
||||
};
|
||||
|
||||
enum class Kaifa_List2 {
|
||||
ListSize,
|
||||
ListVersionIdentifier,
|
||||
MeterID,
|
||||
MeterType,
|
||||
ActiveImportPower,
|
||||
ActiveExportPower,
|
||||
ReactiveImportPower,
|
||||
ReactiveExportPower,
|
||||
CurrentL1,
|
||||
CurrentL2,
|
||||
CurrentL3,
|
||||
VoltageL1,
|
||||
VoltageL2,
|
||||
VoltageL3
|
||||
};
|
||||
|
||||
enum class Kaifa_List3 {
|
||||
enum class Kaifa_List3Phase {
|
||||
ListSize,
|
||||
ListVersionIdentifier,
|
||||
MeterID,
|
||||
@ -51,4 +36,22 @@ enum class Kaifa_List3 {
|
||||
CumulativeReactiveExportEnergy
|
||||
};
|
||||
|
||||
enum class Kaifa_List1Phase {
|
||||
ListSize,
|
||||
ListVersionIdentifier,
|
||||
MeterID,
|
||||
MeterType,
|
||||
ActiveImportPower,
|
||||
ActiveExportPower,
|
||||
ReactiveImportPower,
|
||||
ReactiveExportPower,
|
||||
CurrentL1,
|
||||
VoltageL1,
|
||||
MeterClock,
|
||||
CumulativeActiveImportEnergy,
|
||||
CumulativeActiveExportEnergy,
|
||||
CumulativeReactiveImportEnergy,
|
||||
CumulativeReactiveExportEnergy
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -6,42 +6,13 @@
|
||||
|
||||
enum class Kamstrup
|
||||
{
|
||||
List1 = 0x19,
|
||||
List2 = 0x23
|
||||
List3PhaseShort = 0x19,
|
||||
List3PhaseLong = 0x23,
|
||||
List1PhaseShort = 0x11,
|
||||
List1PhaseLong = 0x1B
|
||||
};
|
||||
|
||||
enum class Kamstrup_List1
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
enum class Kamstrup_List2
|
||||
enum class Kamstrup_List3Phase
|
||||
{
|
||||
ListSize,
|
||||
ListVersionIdentifier,
|
||||
@ -81,6 +52,37 @@ enum class Kamstrup_List2
|
||||
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
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
name=HanToJson
|
||||
version=1.0.0
|
||||
author=roarfred
|
||||
maintainer=roarfred <not@important.com>
|
||||
sentence=HAN reader data to Json
|
||||
paragraph=HAN reader data to Json
|
||||
category=Sensors
|
||||
url=https://github.com/roarfred/AmsToMqttBridge
|
||||
architectures=*
|
||||
240
Arduino Code/Arduino Libraries/HanToJson/src/HanToJson.cpp
Normal file
240
Arduino Code/Arduino Libraries/HanToJson/src/HanToJson.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
#include "HanToJson.h"
|
||||
#include "Aidon.h"
|
||||
#include "Kaifa.h"
|
||||
#include "Kamstrup.h"
|
||||
|
||||
|
||||
static void hanToJsonKaifa3phase(int listSize, JsonObject& data, HanReader& hanReader, Stream *debugger)
|
||||
{
|
||||
if (listSize >= (int)Kaifa::List3PhaseShort)
|
||||
{
|
||||
data["lv"] = hanReader.getString( (int)Kaifa_List3Phase::ListVersionIdentifier);
|
||||
data["id"] = hanReader.getString( (int)Kaifa_List3Phase::MeterID);
|
||||
data["type"] = hanReader.getString( (int)Kaifa_List3Phase::MeterType);
|
||||
data["P"] = hanReader.getInt( (int)Kaifa_List3Phase::ActiveImportPower);
|
||||
data["Q"] = hanReader.getInt( (int)Kaifa_List3Phase::ReactiveImportPower);
|
||||
data["I1"] = hanReader.getInt( (int)Kaifa_List3Phase::CurrentL1);
|
||||
data["I2"] = hanReader.getInt( (int)Kaifa_List3Phase::CurrentL2);
|
||||
data["I3"] = hanReader.getInt( (int)Kaifa_List3Phase::CurrentL3);
|
||||
data["U1"] = hanReader.getInt( (int)Kaifa_List3Phase::VoltageL1);
|
||||
data["U2"] = hanReader.getInt( (int)Kaifa_List3Phase::VoltageL2);
|
||||
data["U3"] = hanReader.getInt( (int)Kaifa_List3Phase::VoltageL3);
|
||||
}
|
||||
|
||||
if (listSize >= (int)Kaifa::List3PhaseLong)
|
||||
{
|
||||
data["tPI"] = hanReader.getInt( (int)Kaifa_List3Phase::CumulativeActiveImportEnergy);
|
||||
data["tPO"] = hanReader.getInt( (int)Kaifa_List3Phase::CumulativeActiveExportEnergy);
|
||||
data["tQI"] = hanReader.getInt( (int)Kaifa_List3Phase::CumulativeReactiveImportEnergy);
|
||||
data["tQO"] = hanReader.getInt( (int)Kaifa_List3Phase::CumulativeReactiveExportEnergy);
|
||||
}
|
||||
}
|
||||
|
||||
static void hanToJsonKaifa1phase(int listSize, JsonObject& data, HanReader& hanReader, Stream *debugger)
|
||||
{
|
||||
if (listSize >= (int)Kaifa::List1PhaseShort)
|
||||
{
|
||||
data["lv"] = hanReader.getString( (int)Kaifa_List1Phase::ListVersionIdentifier);
|
||||
data["id"] = hanReader.getString( (int)Kaifa_List1Phase::MeterID);
|
||||
data["type"] = hanReader.getString( (int)Kaifa_List1Phase::MeterType);
|
||||
data["P"] = hanReader.getInt( (int)Kaifa_List1Phase::ActiveImportPower);
|
||||
data["Q"] = hanReader.getInt( (int)Kaifa_List1Phase::ReactiveImportPower);
|
||||
data["I1"] = hanReader.getInt( (int)Kaifa_List1Phase::CurrentL1);
|
||||
data["U1"] = hanReader.getInt( (int)Kaifa_List1Phase::VoltageL1);
|
||||
}
|
||||
|
||||
if (listSize >= (int)Kaifa::List1PhaseLong)
|
||||
{
|
||||
data["tPI"] = hanReader.getInt( (int)Kaifa_List1Phase::CumulativeActiveImportEnergy);
|
||||
data["tPO"] = hanReader.getInt( (int)Kaifa_List1Phase::CumulativeActiveExportEnergy);
|
||||
data["tQI"] = hanReader.getInt( (int)Kaifa_List1Phase::CumulativeReactiveImportEnergy);
|
||||
data["tQO"] = hanReader.getInt( (int)Kaifa_List1Phase::CumulativeReactiveExportEnergy);
|
||||
}
|
||||
}
|
||||
|
||||
static void hanToJsonKaifa(JsonObject& data, HanReader& hanReader, Stream *debugger)
|
||||
{
|
||||
int listSize = hanReader.getListSize();
|
||||
|
||||
if (listSize == (int)Kaifa::List1)
|
||||
{
|
||||
// Handle listSize == 1 specially
|
||||
data["P"] = hanReader.getInt( (int)Kaifa_List1::ActivePowerImported);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (listSize) {
|
||||
case (int)Kaifa::List3PhaseShort:
|
||||
case (int)Kaifa::List3PhaseLong:
|
||||
return hanToJsonKaifa3phase(listSize, data, hanReader, debugger);
|
||||
case (int)Kaifa::List1PhaseShort:
|
||||
case (int)Kaifa::List1PhaseLong:
|
||||
return hanToJsonKaifa1phase(listSize, data, hanReader, debugger);
|
||||
default:
|
||||
if (debugger) debugger->printf("Warning: Unknown listSize %d\n", listSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hanToJsonAidon3phase(int listSize, JsonObject& data, HanReader& hanReader, Stream *debugger)
|
||||
{
|
||||
if (listSize >= (int)Aidon::List3PhaseShort)
|
||||
{
|
||||
data["lv"] = hanReader.getString( (int)Aidon_List3Phase::ListVersionIdentifier);
|
||||
data["id"] = hanReader.getString( (int)Aidon_List3Phase::MeterID);
|
||||
data["type"] = hanReader.getString( (int)Aidon_List3Phase::MeterType);
|
||||
data["P"] = hanReader.getInt( (int)Aidon_List3Phase::ActiveImportPower);
|
||||
data["Q"] = hanReader.getInt( (int)Aidon_List3Phase::ReactiveExportPower);
|
||||
data["I1"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::CurrentL1)) / 10;
|
||||
data["I2"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::CurrentL2)) / 10;
|
||||
data["I3"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::CurrentL3)) / 10;
|
||||
data["U1"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::VoltageL1)) / 10;
|
||||
data["U2"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::VoltageL2)) / 10;
|
||||
data["U3"] = ((double) hanReader.getInt( (int)Aidon_List3Phase::VoltageL3)) / 10;
|
||||
}
|
||||
|
||||
if (listSize >= (int)Aidon::List3PhaseLong)
|
||||
{
|
||||
data["tPI"] = hanReader.getInt( (int)Aidon_List3Phase::CumulativeActiveImportEnergy);
|
||||
data["tPO"] = hanReader.getInt( (int)Aidon_List3Phase::CumulativeActiveExportEnergy);
|
||||
data["tQI"] = hanReader.getInt( (int)Aidon_List3Phase::CumulativeReactiveImportEnergy);
|
||||
data["tQO"] = hanReader.getInt( (int)Aidon_List3Phase::CumulativeReactiveExportEnergy);
|
||||
}
|
||||
|
||||
// TODO: Do not divide Aidon values by 10!?
|
||||
}
|
||||
|
||||
static void hanToJsonAidon1phase(int listSize, JsonObject& data, HanReader& hanReader, Stream *debugger)
|
||||
{
|
||||
if (listSize >= (int)Aidon::List1PhaseShort)
|
||||
{
|
||||
data["lv"] = hanReader.getString( (int)Aidon_List1Phase::ListVersionIdentifier);
|
||||
data["id"] = hanReader.getString( (int)Aidon_List1Phase::MeterID);
|
||||
data["type"] = hanReader.getString( (int)Aidon_List1Phase::MeterType);
|
||||
data["P"] = hanReader.getInt( (int)Aidon_List1Phase::ActiveImportPower);
|
||||
data["Q"] = hanReader.getInt( (int)Aidon_List1Phase::ReactiveExportPower);
|
||||
data["I1"] = ((double) hanReader.getInt( (int)Aidon_List1Phase::CurrentL1)) / 10;
|
||||
data["U1"] = ((double) hanReader.getInt( (int)Aidon_List1Phase::VoltageL1)) / 10;
|
||||
}
|
||||
|
||||
// TODO Aidon::List1PhaseLong
|
||||
}
|
||||
|
||||
static void hanToJsonAidon(JsonObject& data, HanReader& hanReader, Stream *debugger)
|
||||
{
|
||||
int listSize = hanReader.getListSize();
|
||||
|
||||
// Based on the list number, get all details
|
||||
// according to OBIS specifications for the meter
|
||||
if (listSize == (int)Aidon::List1)
|
||||
{
|
||||
// Handle listSize == 1 specially
|
||||
data["P"] = hanReader.getInt((int)Aidon_List1::ActiveImportPower);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (listSize) {
|
||||
case (int)Aidon::List3PhaseShort:
|
||||
case (int)Aidon::List3PhaseLong:
|
||||
return hanToJsonAidon3phase(listSize, data, hanReader, debugger);
|
||||
case (int)Aidon::List1PhaseShort:
|
||||
case (int)Aidon::List1PhaseLong:
|
||||
return hanToJsonAidon1phase(listSize, data, hanReader, debugger);
|
||||
default:
|
||||
if (debugger) debugger->printf("Warning: Unknown listSize %d\n", listSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void hanToJsonKamstrup3phase(int listSize, JsonObject& data, HanReader& hanReader, Stream *debugger)
|
||||
{
|
||||
if (listSize >= (int)Kamstrup::List3PhaseShort)
|
||||
{
|
||||
data["lv"] = hanReader.getString( (int)Kamstrup_List3Phase::ListVersionIdentifier);
|
||||
data["id"] = hanReader.getString( (int)Kamstrup_List3Phase::MeterID);
|
||||
data["type"] = hanReader.getString( (int)Kamstrup_List3Phase::MeterType);
|
||||
data["P"] = hanReader.getInt( (int)Kamstrup_List3Phase::ActiveImportPower);
|
||||
data["Q"] = hanReader.getInt( (int)Kamstrup_List3Phase::ReactiveImportPower);
|
||||
data["I1"] = hanReader.getInt( (int)Kamstrup_List3Phase::CurrentL1);
|
||||
data["I2"] = hanReader.getInt( (int)Kamstrup_List3Phase::CurrentL2);
|
||||
data["I3"] = hanReader.getInt( (int)Kamstrup_List3Phase::CurrentL3);
|
||||
data["U1"] = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL1);
|
||||
data["U2"] = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL2);
|
||||
data["U3"] = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL3);
|
||||
}
|
||||
|
||||
if (listSize >= (int)Kamstrup::List3PhaseLong)
|
||||
{
|
||||
data["tPI"] = hanReader.getInt( (int)Kamstrup_List3Phase::CumulativeActiveImportEnergy);
|
||||
data["tPO"] = hanReader.getInt( (int)Kamstrup_List3Phase::CumulativeActiveExportEnergy);
|
||||
data["tQI"] = hanReader.getInt( (int)Kamstrup_List3Phase::CumulativeReactiveImportEnergy);
|
||||
data["tQO"] = hanReader.getInt( (int)Kamstrup_List3Phase::CumulativeReactiveExportEnergy);
|
||||
}
|
||||
}
|
||||
|
||||
static void hanToJsonKamstrup1phase(int listSize, JsonObject& data, HanReader& hanReader, Stream *debugger)
|
||||
{
|
||||
if (listSize >= (int)Kamstrup::List1PhaseShort)
|
||||
{
|
||||
data["lv"] = hanReader.getString( (int)Kamstrup_List1Phase::ListVersionIdentifier);
|
||||
data["id"] = hanReader.getString( (int)Kamstrup_List1Phase::MeterID);
|
||||
data["type"] = hanReader.getString( (int)Kamstrup_List1Phase::MeterType);
|
||||
data["P"] = hanReader.getInt( (int)Kamstrup_List1Phase::ActiveImportPower);
|
||||
data["Q"] = hanReader.getInt( (int)Kamstrup_List1Phase::ReactiveImportPower);
|
||||
data["I1"] = hanReader.getInt( (int)Kamstrup_List1Phase::CurrentL1);
|
||||
data["U1"] = hanReader.getInt( (int)Kamstrup_List1Phase::VoltageL1);
|
||||
}
|
||||
|
||||
if (listSize >= (int)Kamstrup::List1PhaseLong)
|
||||
{
|
||||
data["tPI"] = hanReader.getInt( (int)Kamstrup_List1Phase::CumulativeActiveImportEnergy);
|
||||
data["tPO"] = hanReader.getInt( (int)Kamstrup_List1Phase::CumulativeActiveExportEnergy);
|
||||
data["tQI"] = hanReader.getInt( (int)Kamstrup_List1Phase::CumulativeReactiveImportEnergy);
|
||||
data["tQO"] = hanReader.getInt( (int)Kamstrup_List1Phase::CumulativeReactiveExportEnergy);
|
||||
}
|
||||
}
|
||||
|
||||
static void hanToJsonKamstrup(JsonObject& data, HanReader& hanReader, Stream *debugger)
|
||||
{
|
||||
int listSize = hanReader.getListSize();
|
||||
|
||||
switch (listSize) {
|
||||
case (int)Kamstrup::List3PhaseShort:
|
||||
case (int)Kamstrup::List3PhaseLong:
|
||||
return hanToJsonKamstrup3phase(listSize, data, hanReader, debugger);
|
||||
case (int)Kamstrup::List1PhaseShort:
|
||||
case (int)Kamstrup::List1PhaseLong:
|
||||
return hanToJsonKamstrup1phase(listSize, data, hanReader, debugger);
|
||||
default:
|
||||
if (debugger) debugger->printf("Warning: Unknown listSize %d\n", listSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void hanToJson(JsonObject& data, byte meterType, HanReader& hanReader, Stream *debugger)
|
||||
{
|
||||
// Based on the list number, get all details
|
||||
// according to OBIS specifications for the meter
|
||||
switch (meterType)
|
||||
{
|
||||
case 1: // Kaifa
|
||||
return hanToJsonKaifa(data, hanReader, debugger);
|
||||
case 2: // Aidon
|
||||
return hanToJsonAidon(data, hanReader, debugger);
|
||||
case 3: // Kamstrup
|
||||
return hanToJsonKamstrup(data, hanReader, debugger);
|
||||
default:
|
||||
if (debugger) {
|
||||
debugger->print("Meter type ");
|
||||
debugger->print(meterType, HEX);
|
||||
debugger->println(" is unknown");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void hanToJson(JsonObject& data, byte meterType, HanReader& hanReader)
|
||||
{
|
||||
return hanToJson(data, meterType, hanReader, NULL);
|
||||
}
|
||||
17
Arduino Code/Arduino Libraries/HanToJson/src/HanToJson.h
Normal file
17
Arduino Code/Arduino Libraries/HanToJson/src/HanToJson.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef _HANTOJSON_h
|
||||
#define _HANTOJSON_h
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include "HanReader.h"
|
||||
|
||||
void hanToJson(JsonObject& data, byte meterType, HanReader& hanReader);
|
||||
void hanToJson(JsonObject& root, byte meterType, HanReader& hanReader, Stream *debugPort);
|
||||
|
||||
|
||||
#endif
|
||||
27
Arduino Code/README.md
Normal file
27
Arduino Code/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
## Arduino Code
|
||||
|
||||
FW and libraries for running on various HW
|
||||
|
||||
### AmsToMqttBridge
|
||||
|
||||
The original FW by roarfred, runs a Wifi access point until configured. Uploads data as json to a MQTT server.
|
||||
|
||||
### WifiFeatherRestBridge
|
||||
|
||||
_Note: This project is still under development._
|
||||
|
||||
Firmware for runninw AMS decoding with off-the-shelf components, so no PCB etching or soldering necessary. Specifially,
|
||||
the sketch runs on the [Adafruit Feather M0 WiFi w/ATWINC1500](https://www.adafruit.com/product/3010) card and uses the
|
||||
[TSS721 M-BUS module board](https://www.aliexpress.com/item/TSS721/32751482255.html) available from Aliexpress.
|
||||
|
||||

|
||||
|
||||
|
||||
### Arduino Libraries/HanReader
|
||||
|
||||
The shared library to read from a serial port and decode the data into packets.
|
||||
|
||||
### Arduino Libraries/HanToJson
|
||||
|
||||
Shared library to create a json structure from the read HAN packets (for the different meter types).
|
||||
|
||||
283
Debugging/Code/Arduino/HanToJsonTest/HanToJsonTest.ino
Normal file
283
Debugging/Code/Arduino/HanToJsonTest/HanToJsonTest.ino
Normal file
@ -0,0 +1,283 @@
|
||||
/**
|
||||
* Simple sketch to simulate reading data from different meters.
|
||||
*
|
||||
* Created 24. October 2017 by Roar Fredriksen
|
||||
*/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
//#include "Kaifa.h"
|
||||
//#include "Kamstrup.h"
|
||||
//#include "Aidon.h"
|
||||
#include "HanReader.h"
|
||||
#include "HanToJson.h"
|
||||
|
||||
// The HAN Port reader
|
||||
HanReader hanReader;
|
||||
|
||||
HardwareSerial* debugger = NULL;
|
||||
|
||||
byte meterType = 1; // Start with Kaifa
|
||||
int sampleIndex = 0;
|
||||
int expectIndex = 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,
|
||||
};
|
||||
String kaifa_expect[] = {
|
||||
String("{\"t\":1505417462,\"data\":{\"P\":920}}"),
|
||||
String("{\"t\":1505417470,\"data\":{\"lv\":\"KFM_001\",\"id\":\"6970631401753985\",\"type\":\"MA304H3E\",\"P\":918,\"Q\":0,\"I1\":1380,\"I2\":3218,\"I3\":3145,\"U1\":2374,\"U2\":0,\"U3\":2382}}"),
|
||||
String("{\"t\":1505419210,\"data\":{\"lv\":\"KFM_001\",\"id\":\"6970631401753985\",\"type\":\"MA304H3E\",\"P\":1022,\"Q\":0,\"I1\":1937,\"I2\":3229,\"I3\":3430,\"U1\":2369,\"U2\":0,\"U3\":2380,\"tPI\":180073,\"tPO\":0,\"tQI\":247,\"tQO\":16380}}"),
|
||||
String("{\"t\":1557354760,\"data\":{\"lv\":\"KFM_001\",\"id\":\"6970631401991684\",\"type\":\"MA105H2E\",\"P\":933,\"Q\":33,\"I1\":4110,\"U1\":2314}}")
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
String aidon_expect[] = {
|
||||
String("{\"t\":0,\"data\":{\"lv\":\"AIDON_V0001\",\"id\":\"7359992890941742\",\"type\":\"6515\",\"P\":1362,\"Q\":0,\"I1\":9.3,\"U1\":250}}")
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
String kamstrup_expect[] = {
|
||||
String("{\"t\":1520197190,\"data\":{\"lv\":\"Kamstrup_V0001\",\"id\":\"5706567274389702\",\"type\":\"6841121BN243101040\",\"P\":4392,\"Q\":132,\"I1\":1382,\"I2\":780,\"I3\":1370,\"U1\":224,\"U2\":223,\"U3\":223}}"),
|
||||
String("{\"t\":1520197205,\"data\":{\"lv\":\"Kamstrup_V0001\",\"id\":\"5706567274389702\",\"type\":\"6841121BN243101040\",\"P\":3643,\"Q\":134,\"I1\":1057,\"I2\":780,\"I3\":1052,\"U1\":226,\"U2\":224,\"U3\":223,\"tPI\":1720393,\"tPO\":0,\"tQI\":1380,\"tQO\":162593}}")
|
||||
};
|
||||
|
||||
|
||||
void assert_equal(DynamicJsonDocument& doc, const String& expected)
|
||||
{
|
||||
String jsonActual;
|
||||
serializeJson(doc, jsonActual);
|
||||
if (jsonActual != expected)
|
||||
{
|
||||
debugger->printf("Test assert failed:\n %s\n !=\n %s\n", jsonActual.c_str(), expected.c_str());
|
||||
while (true) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial1.begin(115200);
|
||||
//while (!Serial) {}
|
||||
Serial1.println("Serial1 debugging port initialized");
|
||||
|
||||
// initialize the HanReader
|
||||
// (passing no han port, as we are feeding data manually, but provide Serial for debugging)
|
||||
hanReader.setup(NULL, &Serial1);
|
||||
hanReader.compensateFor09HeaderBug = true; // Starting with Kaifa
|
||||
|
||||
debugger = &Serial1;
|
||||
}
|
||||
|
||||
void loopKaifa()
|
||||
{
|
||||
if (sampleIndex >= sizeof(kaifa_samples))
|
||||
{
|
||||
meterType++;
|
||||
sampleIndex = 0;
|
||||
expectIndex = 0;
|
||||
hanReader.setup(NULL, debugger);
|
||||
hanReader.compensateFor09HeaderBug = false;
|
||||
Serial1.println("Done with Kaifa");
|
||||
}
|
||||
|
||||
// Read one byte from the "port", and see if we got a full package
|
||||
if (hanReader.read(kaifa_samples[sampleIndex++]))
|
||||
{
|
||||
DynamicJsonDocument doc(500);
|
||||
|
||||
doc["t"] = hanReader.getPackageTime();
|
||||
|
||||
JsonObject data = doc.createNestedObject("data");
|
||||
|
||||
hanToJson(data, meterType, hanReader);
|
||||
|
||||
debugger->println("Kaifa JsonData: ");
|
||||
serializeJsonPretty(doc, Serial1);
|
||||
debugger->println();
|
||||
|
||||
if (expectIndex < sizeof(kaifa_expect) / sizeof(kaifa_expect[0]))
|
||||
{
|
||||
assert_equal(doc, kaifa_expect[expectIndex++]);
|
||||
} else {
|
||||
debugger->println("Not enough expected results spesified");
|
||||
while (true) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loopAidon()
|
||||
{
|
||||
if (sampleIndex >= sizeof(aidon_samples))
|
||||
{
|
||||
meterType++;
|
||||
sampleIndex = 0;
|
||||
expectIndex = 0;
|
||||
hanReader.setup(NULL, &Serial1);
|
||||
debugger->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);
|
||||
|
||||
doc["t"] = hanReader.getPackageTime();
|
||||
|
||||
JsonObject data = doc.createNestedObject("data");
|
||||
|
||||
hanToJson(data, meterType, hanReader);
|
||||
|
||||
debugger->println("Aidon JsonData: ");
|
||||
serializeJsonPretty(doc, Serial1);
|
||||
debugger->println();
|
||||
|
||||
if (expectIndex < sizeof(aidon_expect) / sizeof(aidon_expect[0]))
|
||||
{
|
||||
assert_equal(doc, aidon_expect[expectIndex++]);
|
||||
} else {
|
||||
debugger->println("Not enough expected results spesified");
|
||||
while (true) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loopKamstrup()
|
||||
{
|
||||
if (sampleIndex >= sizeof(kamstrup_samples))
|
||||
{
|
||||
meterType++;
|
||||
sampleIndex = 0;
|
||||
hanReader.setup(NULL, &Serial1);
|
||||
debugger->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);
|
||||
|
||||
doc["t"] = hanReader.getPackageTime();
|
||||
|
||||
JsonObject data = doc.createNestedObject("data");
|
||||
|
||||
hanToJson(data, meterType, hanReader);
|
||||
|
||||
debugger->println("Kamstrup JsonData: ");
|
||||
serializeJsonPretty(doc, Serial1);
|
||||
debugger->println();
|
||||
|
||||
if (expectIndex < sizeof(kamstrup_expect) / sizeof(kamstrup_expect[0]))
|
||||
{
|
||||
assert_equal(doc, kamstrup_expect[expectIndex++]);
|
||||
} else {
|
||||
debugger->println("Not enough expected results spesified");
|
||||
while (true) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
switch (meterType)
|
||||
{
|
||||
case 1: // Kaifa
|
||||
return loopKaifa();
|
||||
case 2: // Aidon
|
||||
return loopAidon();
|
||||
case 3: // Kamstrup
|
||||
return loopKamstrup();
|
||||
default:
|
||||
debugger->println("Done");
|
||||
while (true) ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,3 +18,9 @@ Very similar to the HanDebugger, simply reading the HAN data and outputting the
|
||||
This code outputs a changing serial test pattern.
|
||||
|
||||

|
||||
|
||||
### SerialSimulator (Python code to send sample HAN data over serial port)
|
||||
|
||||
Use this Python3 script (e.g. running on a desktop computer using a USB to serial dongle) to simulate the data sent over the HAN port (after being translate from Mbus to uart signals).
|
||||
|
||||

|
||||
|
||||
BIN
Debugging/Code/SerialSimulator/ams_serial_simulator.jpg
Normal file
BIN
Debugging/Code/SerialSimulator/ams_serial_simulator.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 234 KiB |
19
Debugging/Code/SerialSimulator/ams_serial_simulator.py
Normal file
19
Debugging/Code/SerialSimulator/ams_serial_simulator.py
Normal file
@ -0,0 +1,19 @@
|
||||
import serial
|
||||
import time
|
||||
import sys
|
||||
|
||||
import sample_data
|
||||
|
||||
serial_port = sys.argv[1]
|
||||
|
||||
with serial.Serial(port=serial_port, baudrate=2400, bytesize=8, parity='E', stopbits=1) as ser:
|
||||
print(ser)
|
||||
print('sleeping')
|
||||
time.sleep(1)
|
||||
while True:
|
||||
for packet in sample_data.kaifa_20190508_packets[:]:
|
||||
sys.stdout.flush()
|
||||
ser.write(packet)
|
||||
print('sleeping')
|
||||
time.sleep(2)
|
||||
break
|
||||
27
Debugging/Code/SerialSimulator/sample_data.py
Normal file
27
Debugging/Code/SerialSimulator/sample_data.py
Normal file
@ -0,0 +1,27 @@
|
||||
# From Samples/Kaifa/HAN 20170912-3.txt:
|
||||
kaifa_han_20170912_3_packets = [
|
||||
# [2017-09-13 00.00.07.776 - Received 41 (0x29) bytes]
|
||||
b'\x7E\xA0\x27\x01\x02\x01\x10\x5A\x87\xE6\xE7\x00\x0F\x40\x00\x00\x00\x09\x0C\x07\xE1\x09\x0D\x02\x00\x00\x06\xFF\x80\x00\x00\x02\x01\x06\x00\x00\x11\xAC\x85\x61\x7E',
|
||||
# [2017-09-13 00.00.09.784 - Received 41 (0x29) bytes]
|
||||
b'\x7E\xA0\x27\x01\x02\x01\x10\x5A\x87\xE6\xE7\x00\x0F\x40\x00\x00\x00\x09\x0C\x07\xE1\x09\x0D\x02\x00\x00\x08\xFF\x80\x00\x00\x02\x01\x06\x00\x00\x11\xB4\x6D\xF0\x7E',
|
||||
# [2017-09-13 00.00.11.761 - Received 157 (0x9D) bytes]
|
||||
b'\x7E\xA0\x9B\x01\x02\x01\x10\xEE\xAE\xE6\xE7\x00\x0F\x40\x00\x00\x00\x09\x0C\x07\xE1\x09\x0D\x02\x00\x00\x0A\xFF\x80\x00\x00\x02\x12\x09\x07\x4B\x46\x4D\x5F\x30\x30\x31\x09\x10\x36\x39\x37\x30\x36\x33\x31\x34\x30\x31\x37\x35\x33\x39\x38\x35\x09\x08\x4D\x41\x33\x30\x34\x48\x33\x45\x06\x00\x00\x11\xB5\x06\x00\x00\x00\x00\x06\x00\x00\x00\x00\x06\x00\x00\x00\x80\x06\x00\x00\x38\x48\x06\x00\x00\x3C\x76\x06\x00\x00\x14\x5B\x06\x00\x00\x09\x4D\x06\x00\x00\x00\x00\x06\x00\x00\x09\x5A\x09\x0C\x07\xE1\x09\x0D\x02\x00\x00\x0A\xFF\x80\x00\x00\x06\x00\x01\xB8\x57\x06\x00\x00\x00\x00\x06\x00\x00\x00\x65\x06\x00\x00\x33\xA4\x54\x83\x7E',
|
||||
# [2017-09-13 00.00.13.769 - Received 41 (0x29) bytes]
|
||||
b'\x7E\xA0\x27\x01\x02\x01\x10\x5A\x87\xE6\xE7\x00\x0F\x40\x00\x00\x00\x09\x0C\x07\xE1\x09\x0D\x02\x00\x00\x0C\xFF\x80\x00\x00\x02\x01\x06\x00\x00\x11\xB9\xFE\x2E\x7E',
|
||||
# [2017-09-13 00.00.15.778 - Received 41 (0x29) bytes]
|
||||
b'\x7E\xA0\x27\x01\x02\x01\x10\x5A\x87\xE6\xE7\x00\x0F\x40\x00\x00\x00\x09\x0C\x07\xE1\x09\x0D\x02\x00\x00\x0E\xFF\x80\x00\x00\x02\x01\x06\x00\x00\x11\xBA\xDE\x1E\x7E',
|
||||
# [2017-09-13 00.00.17.786 - Received 41 (0x29) bytes]
|
||||
b'\x7E\xA0\x27\x01\x02\x01\x10\x5A\x87\xE6\xE7\x00\x0F\x40\x00\x00\x00\x09\x0C\x07\xE1\x09\x0D\x02\x00\x00\x10\xFF\x80\x00\x00\x02\x01\x06\x00\x00\x11\xBB\xAE\x17\x7E',
|
||||
# [2017-09-13 00.00.19.762 - Received 41 (0x29) bytes]
|
||||
b'\x7E\xA0\x27\x01\x02\x01\x10\x5A\x87\xE6\xE7\x00\x0F\x40\x00\x00\x00\x09\x0C\x07\xE1\x09\x0D\x02\x00\x00\x12\xFF\x80\x00\x00\x02\x01\x06\x00\x00\x11\xB7\x79\xDF\x7E',
|
||||
# [2017-09-13 00.00.21.771 - Received 123 (0x7B) bytes]
|
||||
b'\x7E\xA0\x79\x01\x02\x01\x10\x80\x93\xE6\xE7\x00\x0F\x40\x00\x00\x00\x09\x0C\x07\xE1\x09\x0D\x02\x00\x00\x14\xFF\x80\x00\x00\x02\x0D\x09\x07\x4B\x46\x4D\x5F\x30\x30\x31\x09\x10\x36\x39\x37\x30\x36\x33\x31\x34\x30\x31\x37\x35\x33\x39\x38\x35\x09\x08\x4D\x41\x33\x30\x34\x48\x33\x45\x06\x00\x00\x11\xBB\x06\x00\x00\x00\x00\x06\x00\x00\x00\x00\x06\x00\x00\x00\x7F\x06\x00\x00\x38\x4D\x06\x00\x00\x3C\x86\x06\x00\x00\x14\x5B\x06\x00\x00\x09\x4F\x06\x00\x00\x00\x00\x06\x00\x00\x09\x5C\xC1\x54\x7E',
|
||||
]
|
||||
|
||||
# From Kaifa MA105H2E 2019-05-08
|
||||
kaifa_20190508_packets = [
|
||||
b'~\xa0\'\x01\x02\x01\x10Z\x87\xe6\xe7\x00\x0f@\x00\x00\x00\t\x0c\x07\xe3\x05\x08\x03\x16 "\xff\x80\x00\x00\x02\x01\x06\x00\x00\x03\xa3L\xab~',
|
||||
b'~\xa0e\x01\x02\x01\x10\xf0P\xe6\xe7\x00\x0f@\x00\x00\x00\t\x0c\x07\xe3\x05\x08\x03\x16 (\xff\x80\x00\x00\x02\t\t\x07KFM_001\t\x106970631401991684\t\x08MA105H2E\x06\x00\x00\x03\xa5\x06\x00\x00\x00\x00\x06\x00\x00\x00!\x06\x00\x00\x00\x00\x06\x00\x00\x10\x0e\x06\x00\x00\t\n\x98v~',
|
||||
b'~\xa0\'\x01\x02\x01\x10Z\x87\xe6\xe7\x00\x0f@\x00\x00\x00\t\x0c\x07\xe3\x05\x08\x03\x16 "\xff\x80\x00\x00\x02\x01\x06\x00\x00\x03\xa3L\xab~',
|
||||
]
|
||||
|
||||
Binary file not shown.
BIN
Debugging/Documentation/feather_3010-00_mbus_slave.jpg
Normal file
BIN
Debugging/Documentation/feather_3010-00_mbus_slave.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 202 KiB |
Loading…
x
Reference in New Issue
Block a user