mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-02-14 12:05:25 +00:00
Merge branch 'master' into dev-v2.2
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#ifndef _AMSTOMQTTBRIDGE_H
|
||||
#define _AMSTOMQTTBRIDGE_H
|
||||
|
||||
#define WIFI_CONNECTION_TIMEOUT 30000;
|
||||
#define WIFI_CONNECTION_TIMEOUT 30000
|
||||
|
||||
#define INVALID_BUTTON_PIN 0xFFFFFFFF
|
||||
|
||||
|
||||
@@ -65,10 +65,11 @@ ADC_MODE(ADC_VCC);
|
||||
#include "RemoteDebug.h"
|
||||
|
||||
#define BUF_SIZE_COMMON (2048)
|
||||
#define BUF_SIZE_HAN (1024)
|
||||
#define BUF_SIZE_HAN (1280)
|
||||
|
||||
#include "IEC6205621.h"
|
||||
#include "IEC6205675.h"
|
||||
#include "LNG.h"
|
||||
|
||||
#include "ams/DataParsers.h"
|
||||
|
||||
@@ -118,7 +119,6 @@ DLMSParser *dlmsParser = NULL;
|
||||
DSMRParser *dsmrParser = NULL;
|
||||
|
||||
void setup() {
|
||||
WiFiConfig wifi;
|
||||
Serial.begin(115200);
|
||||
|
||||
if(!config.getGpioConfig(gpioConfig)) {
|
||||
@@ -245,7 +245,6 @@ void setup() {
|
||||
}
|
||||
|
||||
Debug.setSerialEnabled(true);
|
||||
DebugConfig debug;
|
||||
delay(1);
|
||||
|
||||
float vcc = hw.getVcc();
|
||||
@@ -435,6 +434,10 @@ void loop() {
|
||||
}
|
||||
}
|
||||
|
||||
if(now > 10000 && now - lastErrorBlink > 3000) {
|
||||
errorBlink();
|
||||
}
|
||||
|
||||
// Only do normal stuff if we're not booted as AP
|
||||
if (WiFi.getMode() != WIFI_AP) {
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
@@ -505,13 +508,10 @@ void loop() {
|
||||
MDNS.update();
|
||||
#endif
|
||||
|
||||
if(now > 10000 && now - lastErrorBlink > 3000) {
|
||||
errorBlink();
|
||||
}
|
||||
|
||||
if (mqttEnabled || config.isMqttChanged()) {
|
||||
if(mqtt == NULL || !mqtt->connected() || config.isMqttChanged()) {
|
||||
MQTT_connect();
|
||||
config.ackMqttChange();
|
||||
}
|
||||
} else if(mqtt != NULL && mqtt->connected()) {
|
||||
mqttClient->stop();
|
||||
@@ -589,11 +589,11 @@ void loop() {
|
||||
if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) {
|
||||
mqttHandler->publishTemperatures(&config, &hw);
|
||||
}
|
||||
debugD("Used %d ms to update temperature", millis()-start);
|
||||
debugD("Used %ld ms to update temperature", millis()-start);
|
||||
}
|
||||
if(now - lastSysupdate > 10000) {
|
||||
if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) {
|
||||
mqttHandler->publishSystem(&hw);
|
||||
mqttHandler->publishSystem(&hw, eapi, &ea);
|
||||
}
|
||||
lastSysupdate = now;
|
||||
}
|
||||
@@ -723,22 +723,25 @@ void errorBlink() {
|
||||
if(lastError == 3)
|
||||
lastError = 0;
|
||||
lastErrorBlink = millis();
|
||||
for(;lastError < 3;lastError++) {
|
||||
switch(lastError) {
|
||||
while(lastError < 3) {
|
||||
switch(lastError++) {
|
||||
case 0:
|
||||
if(lastErrorBlink - meterState.getLastUpdateMillis() > 30000) {
|
||||
debugW("No HAN data received last 30s, single blink");
|
||||
hw.ledBlink(LED_RED, 1); // If no message received from AMS in 30 sec, blink once
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if(mqttEnabled && mqtt != NULL && mqtt->lastError() != 0) {
|
||||
debugW("MQTT connection not available, double blink");
|
||||
hw.ledBlink(LED_RED, 2); // If MQTT error, blink twice
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if(WiFi.getMode() != WIFI_AP && WiFi.status() != WL_CONNECTED) {
|
||||
debugW("WiFi not connected, tripe blink");
|
||||
hw.ledBlink(LED_RED, 3); // If WiFi not connected, blink three times
|
||||
return;
|
||||
}
|
||||
@@ -825,6 +828,11 @@ bool readHanPort() {
|
||||
}
|
||||
if(pos == DATA_PARSE_INCOMPLETE) {
|
||||
return false;
|
||||
} else if(pos == DATA_PARSE_UNKNOWN_DATA) {
|
||||
len = len + hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len);
|
||||
debugPrint(hanBuffer, 0, len);
|
||||
len = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pos == DATA_PARSE_INTERMEDIATE_SEGMENT) {
|
||||
@@ -848,20 +856,26 @@ bool readHanPort() {
|
||||
}
|
||||
|
||||
AmsData data;
|
||||
char* payload = ((char *) (hanBuffer)) + pos;
|
||||
if(ctx.type == DATA_TAG_DLMS) {
|
||||
// If MQTT bytestream payload is selected (mqttHandler == NULL), send the payload to MQTT
|
||||
if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) {
|
||||
mqtt->publish(topic.c_str(), toHex(hanBuffer+pos, ctx.length));
|
||||
mqtt->publish(topic.c_str(), toHex((byte*) payload, ctx.length));
|
||||
mqtt->loop();
|
||||
}
|
||||
|
||||
debugV("Using application data:");
|
||||
if(Debug.isActive(RemoteDebug::VERBOSE)) debugPrint(hanBuffer+pos, 0, ctx.length);
|
||||
if(Debug.isActive(RemoteDebug::VERBOSE)) debugPrint((byte*) payload, 0, ctx.length);
|
||||
|
||||
// TODO: Split IEC6205675 into DataParserKaifa and DataParserObis. This way we can add other means of parsing, for those other proprietary formats
|
||||
data = IEC6205675(((char *) (hanBuffer)) + pos, meterState.getMeterType(), &meterConfig, ctx);
|
||||
// Rudimentary detector for L&G proprietary format
|
||||
if(payload[0] == CosemTypeStructure && payload[2] == CosemTypeArray && payload[1] == payload[3]) {
|
||||
data = LNG(payload, meterState.getMeterType(), &meterConfig, ctx, &Debug);
|
||||
} else {
|
||||
// TODO: Split IEC6205675 into DataParserKaifa and DataParserObis. This way we can add other means of parsing, for those other proprietary formats
|
||||
data = IEC6205675(payload, meterState.getMeterType(), &meterConfig, ctx);
|
||||
}
|
||||
} else if(ctx.type == DATA_TAG_DSMR) {
|
||||
data = IEC6205621(((char *) (hanBuffer)) + pos);
|
||||
data = IEC6205621(payload);
|
||||
}
|
||||
len = 0;
|
||||
|
||||
@@ -977,17 +991,34 @@ void debugPrint(byte *buffer, int start, int length) {
|
||||
Debug.println("");
|
||||
}
|
||||
|
||||
unsigned long wifiTimeout = WIFI_CONNECTION_TIMEOUT;
|
||||
unsigned long lastWifiRetry = -WIFI_CONNECTION_TIMEOUT;
|
||||
void WiFi_connect() {
|
||||
if(millis() - lastWifiRetry < wifiTimeout) {
|
||||
delay(50);
|
||||
return;
|
||||
}
|
||||
lastWifiRetry = millis();
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if(WiFi.status() == WL_DISCONNECTED) {
|
||||
if(millis() - lastWifiRetry < WIFI_CONNECTION_TIMEOUT) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(WiFi.getMode() != WIFI_OFF) {
|
||||
switch(WiFi.status()) {
|
||||
case WL_NO_SSID_AVAIL:
|
||||
debugE("WiFi error, no SSID available");
|
||||
break;
|
||||
case WL_CONNECT_FAILED:
|
||||
debugE("WiFi error, connection failed");
|
||||
break;
|
||||
case WL_CONNECTION_LOST:
|
||||
debugE("WiFi error, connection lost");
|
||||
break;
|
||||
#if defined(ESP8266)
|
||||
case WL_WRONG_PASSWORD:
|
||||
debugE("WiFi error, wrong password");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
debugE("WiFi error, %d", WiFi.status());
|
||||
break;
|
||||
}
|
||||
if(wifiReconnectCount > 3) {
|
||||
ESP.restart();
|
||||
return;
|
||||
@@ -1021,11 +1052,13 @@ void WiFi_connect() {
|
||||
WiFi.softAPdisconnect(true);
|
||||
WiFi.enableAP(false);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
#if defined(ESP8266)
|
||||
WiFi.forceSleepBegin();
|
||||
#endif
|
||||
yield();
|
||||
wifiTimeout = 5000;
|
||||
return;
|
||||
}
|
||||
wifiTimeout = WIFI_CONNECTION_TIMEOUT;
|
||||
lastWifiRetry = millis();
|
||||
|
||||
WiFiConfig wifi;
|
||||
if(!config.getWiFiConfig(wifi) || strlen(wifi.ssid) == 0) {
|
||||
@@ -1043,7 +1076,7 @@ void WiFi_connect() {
|
||||
}
|
||||
#endif
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.setSleep(WIFI_PS_MIN_MODEM);
|
||||
WiFi.setSleep(WIFI_PS_MAX_MODEM);
|
||||
#if defined(ESP32)
|
||||
if(wifi.power >= 195)
|
||||
WiFi.setTxPower(WIFI_POWER_19_5dBm);
|
||||
@@ -1113,16 +1146,16 @@ void WiFi_connect() {
|
||||
|
||||
void mqttMessageReceived(String &topic, String &payload) {
|
||||
debugI("Received message for topic %s", topic.c_str() );
|
||||
if(meterConfig.source == METER_SOURCE_MQTT) {
|
||||
DataParserContext ctx = {payload.length()/2};
|
||||
fromHex(hanBuffer, payload, ctx.length);
|
||||
uint16_t pos = unwrapData(hanBuffer, ctx);
|
||||
//if(meterConfig.source == METER_SOURCE_MQTT) {
|
||||
//DataParserContext ctx = {static_cast<uint8_t>(payload.length()/2)};
|
||||
//fromHex(hanBuffer, payload, ctx.length);
|
||||
//uint16_t pos = unwrapData(hanBuffer, ctx);
|
||||
// TODO: Run through DLMS/DMSR parser and apply AmsData
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
int16_t unwrapData(uint8_t *buf, DataParserContext &context) {
|
||||
int16_t ret;
|
||||
int16_t ret = 0;
|
||||
bool doRet = false;
|
||||
uint16_t end = BUF_SIZE_HAN;
|
||||
uint8_t tag = (*buf);
|
||||
@@ -1243,7 +1276,6 @@ void MQTT_connect() {
|
||||
if(Debug.isActive(RemoteDebug::WARNING)) debugW("No MQTT config");
|
||||
mqttEnabled = false;
|
||||
ws.setMqttEnabled(false);
|
||||
config.ackMqttChange();
|
||||
return;
|
||||
}
|
||||
if(mqtt != NULL) {
|
||||
@@ -1258,20 +1290,19 @@ void MQTT_connect() {
|
||||
}
|
||||
|
||||
mqtt->disconnect();
|
||||
if(config.isMqttChanged()) {
|
||||
if(mqttSecureClient != NULL) {
|
||||
mqttSecureClient->stop();
|
||||
delete mqttSecureClient;
|
||||
mqttSecureClient = NULL;
|
||||
} else {
|
||||
mqttClient->stop();
|
||||
}
|
||||
mqttClient = NULL;
|
||||
}
|
||||
yield();
|
||||
} else {
|
||||
uint16_t size = 256;
|
||||
switch(mqttConfig.payloadFormat) {
|
||||
case 0: // JSON
|
||||
case 4: // Home Assistant
|
||||
size = 768;
|
||||
break;
|
||||
case 255: // Raw frame
|
||||
size = 1024;
|
||||
break;
|
||||
}
|
||||
|
||||
mqtt = new MQTTClient(size);
|
||||
mqtt = new MQTTClient(1024);
|
||||
ws.setMqtt(mqtt);
|
||||
}
|
||||
|
||||
@@ -1306,54 +1337,54 @@ void MQTT_connect() {
|
||||
debugI("MQTT SSL is configured (%dkb free heap)", ESP.getFreeHeap());
|
||||
if(mqttSecureClient == NULL) {
|
||||
mqttSecureClient = new WiFiClientSecure();
|
||||
}
|
||||
#if defined(ESP8266)
|
||||
mqttSecureClient->setBufferSizes(512, 512);
|
||||
#endif
|
||||
|
||||
if(LittleFS.begin()) {
|
||||
File file;
|
||||
#if defined(ESP8266)
|
||||
mqttSecureClient->setBufferSizes(512, 512);
|
||||
#endif
|
||||
|
||||
if(LittleFS.begin()) {
|
||||
File file;
|
||||
|
||||
if(LittleFS.exists(FILE_MQTT_CA)) {
|
||||
debugI("Found MQTT CA file (%dkb free heap)", ESP.getFreeHeap());
|
||||
file = LittleFS.open(FILE_MQTT_CA, "r");
|
||||
#if defined(ESP8266)
|
||||
BearSSL::X509List *serverTrustedCA = new BearSSL::X509List(file);
|
||||
mqttSecureClient->setTrustAnchors(serverTrustedCA);
|
||||
#elif defined(ESP32)
|
||||
mqttSecureClient->loadCACert(file, file.size());
|
||||
#endif
|
||||
file.close();
|
||||
if(LittleFS.exists(FILE_MQTT_CA)) {
|
||||
debugI("Found MQTT CA file (%dkb free heap)", ESP.getFreeHeap());
|
||||
file = LittleFS.open(FILE_MQTT_CA, "r");
|
||||
#if defined(ESP8266)
|
||||
BearSSL::X509List *serverTrustedCA = new BearSSL::X509List(file);
|
||||
mqttSecureClient->setTrustAnchors(serverTrustedCA);
|
||||
#elif defined(ESP32)
|
||||
mqttSecureClient->loadCACert(file, file.size());
|
||||
#endif
|
||||
file.close();
|
||||
}
|
||||
|
||||
if(LittleFS.exists(FILE_MQTT_CERT) && LittleFS.exists(FILE_MQTT_KEY)) {
|
||||
#if defined(ESP8266)
|
||||
debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap());
|
||||
file = LittleFS.open(FILE_MQTT_CERT, "r");
|
||||
BearSSL::X509List *serverCertList = new BearSSL::X509List(file);
|
||||
file.close();
|
||||
|
||||
debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap());
|
||||
file = LittleFS.open(FILE_MQTT_KEY, "r");
|
||||
BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(file);
|
||||
file.close();
|
||||
|
||||
debugD("Setting client certificates (%dkb free heap)", ESP.getFreeHeap());
|
||||
mqttSecureClient->setClientRSACert(serverCertList, serverPrivKey);
|
||||
#elif defined(ESP32)
|
||||
debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap());
|
||||
file = LittleFS.open(FILE_MQTT_CERT, "r");
|
||||
mqttSecureClient->loadCertificate(file, file.size());
|
||||
file.close();
|
||||
|
||||
debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap());
|
||||
file = LittleFS.open(FILE_MQTT_KEY, "r");
|
||||
mqttSecureClient->loadPrivateKey(file, file.size());
|
||||
file.close();
|
||||
#endif
|
||||
}
|
||||
LittleFS.end();
|
||||
debugD("MQTT SSL setup complete (%dkb free heap)", ESP.getFreeHeap());
|
||||
}
|
||||
|
||||
if(LittleFS.exists(FILE_MQTT_CERT) && LittleFS.exists(FILE_MQTT_KEY)) {
|
||||
#if defined(ESP8266)
|
||||
debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap());
|
||||
file = LittleFS.open(FILE_MQTT_CERT, "r");
|
||||
BearSSL::X509List *serverCertList = new BearSSL::X509List(file);
|
||||
file.close();
|
||||
|
||||
debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap());
|
||||
file = LittleFS.open(FILE_MQTT_KEY, "r");
|
||||
BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(file);
|
||||
file.close();
|
||||
|
||||
debugD("Setting client certificates (%dkb free heap)", ESP.getFreeHeap());
|
||||
mqttSecureClient->setClientRSACert(serverCertList, serverPrivKey);
|
||||
#elif defined(ESP32)
|
||||
debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap());
|
||||
file = LittleFS.open(FILE_MQTT_CERT, "r");
|
||||
mqttSecureClient->loadCertificate(file, file.size());
|
||||
file.close();
|
||||
|
||||
debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap());
|
||||
file = LittleFS.open(FILE_MQTT_KEY, "r");
|
||||
mqttSecureClient->loadPrivateKey(file, file.size());
|
||||
file.close();
|
||||
#endif
|
||||
}
|
||||
LittleFS.end();
|
||||
debugD("MQTT SSL setup complete (%dkb free heap)", ESP.getFreeHeap());
|
||||
}
|
||||
mqttClient = mqttSecureClient;
|
||||
} else if(mqttClient == NULL) {
|
||||
@@ -1369,7 +1400,7 @@ void MQTT_connect() {
|
||||
#if defined(ESP8266)
|
||||
if(mqttSecureClient) {
|
||||
time_t epoch = time(nullptr);
|
||||
debugD("Setting NTP time %i for secure MQTT connection", epoch);
|
||||
debugD("Setting NTP time %lld for secure MQTT connection", epoch);
|
||||
mqttSecureClient->setX509Time(epoch);
|
||||
}
|
||||
#endif
|
||||
@@ -1378,10 +1409,9 @@ void MQTT_connect() {
|
||||
if ((strlen(mqttConfig.username) == 0 && mqtt->connect(mqttConfig.clientId)) ||
|
||||
(strlen(mqttConfig.username) > 0 && mqtt->connect(mqttConfig.clientId, mqttConfig.username, mqttConfig.password))) {
|
||||
if (Debug.isActive(RemoteDebug::INFO)) debugI("Successfully connected to MQTT!");
|
||||
config.ackMqttChange();
|
||||
|
||||
if(mqttHandler != NULL) {
|
||||
mqttHandler->publishSystem(&hw);
|
||||
mqttHandler->publishSystem(&hw, eapi, &ea);
|
||||
}
|
||||
|
||||
// Subscribe to the chosen MQTT topic, if set in configuration
|
||||
|
||||
@@ -296,6 +296,38 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo
|
||||
l3PowerFactor = val;
|
||||
}
|
||||
|
||||
val = getNumber(AMS_OBIS_ACTIVE_IMPORT_L1, sizeof(AMS_OBIS_ACTIVE_IMPORT_L1), ((char *) (d)));
|
||||
if (val != NOVALUE) {
|
||||
listType = 4;
|
||||
l1activeImportPower = val;
|
||||
}
|
||||
val = getNumber(AMS_OBIS_ACTIVE_IMPORT_L2, sizeof(AMS_OBIS_ACTIVE_IMPORT_L2), ((char *) (d)));
|
||||
if (val != NOVALUE) {
|
||||
listType = 4;
|
||||
l2activeImportPower = val;
|
||||
}
|
||||
val = getNumber(AMS_OBIS_ACTIVE_IMPORT_L3, sizeof(AMS_OBIS_ACTIVE_IMPORT_L3), ((char *) (d)));
|
||||
if (val != NOVALUE) {
|
||||
listType = 4;
|
||||
l3activeImportPower = val;
|
||||
}
|
||||
|
||||
val = getNumber(AMS_OBIS_ACTIVE_EXPORT_L1, sizeof(AMS_OBIS_ACTIVE_EXPORT_L1), ((char *) (d)));
|
||||
if (val != NOVALUE) {
|
||||
listType = 4;
|
||||
l1activeExportPower = val;
|
||||
}
|
||||
val = getNumber(AMS_OBIS_ACTIVE_EXPORT_L2, sizeof(AMS_OBIS_ACTIVE_EXPORT_L2), ((char *) (d)));
|
||||
if (val != NOVALUE) {
|
||||
listType = 4;
|
||||
l2activeExportPower = val;
|
||||
}
|
||||
val = getNumber(AMS_OBIS_ACTIVE_EXPORT_L3, sizeof(AMS_OBIS_ACTIVE_EXPORT_L3), ((char *) (d)));
|
||||
if (val != NOVALUE) {
|
||||
listType = 4;
|
||||
l3activeExportPower = val;
|
||||
}
|
||||
|
||||
if(meterType == AmsTypeKamstrup) {
|
||||
if(listType >= 3) {
|
||||
activeImportCounter *= 10;
|
||||
@@ -336,12 +368,16 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo
|
||||
if(mid != NULL) {
|
||||
switch(mid->base.type) {
|
||||
case CosemTypeString:
|
||||
memcpy(&meterId, mid->str.data, mid->str.length);
|
||||
memcpy(str, mid->oct.data, mid->oct.length);
|
||||
str[mid->oct.length] = 0x00;
|
||||
meterId = String(str);
|
||||
meterId[mid->str.length] = 0;
|
||||
break;
|
||||
case CosemTypeOctetString:
|
||||
memcpy(&meterId, mid->oct.data, mid->oct.length);
|
||||
meterId[mid->oct.length] = 0;
|
||||
memcpy(str, mid->str.data, mid->str.length);
|
||||
str[mid->str.length] = 0x00;
|
||||
meterId = String(str);
|
||||
meterId[mid->str.length] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,12 @@ private:
|
||||
uint8_t AMS_OBIS_POWER_FACTOR_L1[4] = { 33, 7, 0, 255 };
|
||||
uint8_t AMS_OBIS_POWER_FACTOR_L2[4] = { 53, 7, 0, 255 };
|
||||
uint8_t AMS_OBIS_POWER_FACTOR_L3[4] = { 73, 7, 0, 255 };
|
||||
uint8_t AMS_OBIS_ACTIVE_IMPORT_L1[4] = { 21, 7, 0, 255 };
|
||||
uint8_t AMS_OBIS_ACTIVE_IMPORT_L2[4] = { 41, 7, 0, 255 };
|
||||
uint8_t AMS_OBIS_ACTIVE_IMPORT_L3[4] = { 61, 7, 0, 255 };
|
||||
uint8_t AMS_OBIS_ACTIVE_EXPORT_L1[4] = { 22, 7, 0, 255 };
|
||||
uint8_t AMS_OBIS_ACTIVE_EXPORT_L2[4] = { 42, 7, 0, 255 };
|
||||
uint8_t AMS_OBIS_ACTIVE_EXPORT_L3[4] = { 62, 7, 0, 255 };
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
111
src/LNG.cpp
Normal file
111
src/LNG.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
#include "LNG.h"
|
||||
#include "lwip/def.h"
|
||||
#include "ams/Cosem.h"
|
||||
|
||||
LNG::LNG(const char* payload, uint8_t useMeterType, MeterConfig* meterConfig, DataParserContext &ctx, RemoteDebug* debugger) {
|
||||
LngHeader* h = (LngHeader*) payload;
|
||||
if(h->tag == CosemTypeStructure && h->arrayTag == CosemTypeArray) {
|
||||
meterType = AmsTypeLng;
|
||||
this->packageTimestamp = ctx.timestamp;
|
||||
|
||||
uint8_t* ptr = (uint8_t*) &h[1];
|
||||
uint8_t* data = ptr + (18*h->arrayLength); // Skip descriptors
|
||||
|
||||
uint16_t o170 = 0, o270 = 0;
|
||||
uint16_t o181 = 0, o182 = 0;
|
||||
uint16_t o281 = 0, o282 = 0;
|
||||
LngObisDescriptor* descriptor = (LngObisDescriptor*) ptr;
|
||||
for(uint8_t x = 0; x < h->arrayLength-1; x++) {
|
||||
ptr = (uint8_t*) &descriptor[1];
|
||||
descriptor = (LngObisDescriptor*) ptr;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(L&G) OBIS %d.%d.%d with type 0x%02X", descriptor->obis[2], descriptor->obis[3], descriptor->obis[4], *data);
|
||||
|
||||
CosemData* item = (CosemData*) data;
|
||||
if(descriptor->obis[2] == 1) {
|
||||
if(descriptor->obis[3] == 7) {
|
||||
if(descriptor->obis[4] == 0) {
|
||||
o170 = ntohl(item->dlu.data);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data));
|
||||
}
|
||||
} else if(descriptor->obis[3] == 8) {
|
||||
if(descriptor->obis[4] == 0) {
|
||||
activeImportCounter = ntohl(item->dlu.data) / 1000.0;
|
||||
listType = listType >= 3 ? listType : 3;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data));
|
||||
} else if(descriptor->obis[4] == 1) {
|
||||
o181 = ntohl(item->dlu.data);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data));
|
||||
} else if(descriptor->obis[4] == 2) {
|
||||
o182 = ntohl(item->dlu.data);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data));
|
||||
}
|
||||
}
|
||||
} else if(descriptor->obis[2] == 2) {
|
||||
if(descriptor->obis[3] == 7) {
|
||||
if(descriptor->obis[4] == 0) {
|
||||
o270 = ntohl(item->dlu.data);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data));
|
||||
}
|
||||
} else if(descriptor->obis[3] == 8) {
|
||||
if(descriptor->obis[4] == 0) {
|
||||
activeExportCounter = ntohl(item->dlu.data) / 1000.0;
|
||||
listType = listType >= 3 ? listType : 3;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data));
|
||||
} else if(descriptor->obis[4] == 1) {
|
||||
o281 = ntohl(item->dlu.data);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data));
|
||||
} else if(descriptor->obis[4] == 2) {
|
||||
o282 = ntohl(item->dlu.data);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data));
|
||||
}
|
||||
}
|
||||
} else if(descriptor->obis[2] == 96) {
|
||||
if(descriptor->obis[3] == 1) {
|
||||
if(descriptor->obis[4] == 0) {
|
||||
char str[item->oct.length+1];
|
||||
memcpy(str, item->oct.data, item->oct.length);
|
||||
str[item->oct.length] = '\0';
|
||||
meterId = String(str);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %s (oct)", str);
|
||||
} else if(descriptor->obis[4] == 1) {
|
||||
char str[item->oct.length+1];
|
||||
memcpy(str, item->oct.data, item->oct.length);
|
||||
str[item->oct.length] = '\0';
|
||||
meterModel = String(str);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %s (oct)", str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("\n");
|
||||
|
||||
if(o170 > 0 || o270 > 0) {
|
||||
int32_t sum = o170-o270;
|
||||
if(sum > 0) {
|
||||
listType = listType >= 1 ? listType : 1;
|
||||
activeImportPower = sum;
|
||||
} else {
|
||||
listType = listType >= 2 ? listType : 2;
|
||||
activeExportPower = sum * -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(o181 > 0 || o182 > 0) {
|
||||
activeImportCounter = (o181 + o182) / 1000.0;
|
||||
listType = listType >= 3 ? listType : 3;
|
||||
}
|
||||
if(o281 > 0 || o282 > 0) {
|
||||
activeExportCounter = (o281 + o282) / 1000.0;
|
||||
listType = listType >= 3 ? listType : 3;
|
||||
}
|
||||
|
||||
if((*data) == 0x09) {
|
||||
data += (*(data+1))+2;
|
||||
} else {
|
||||
data += 5;
|
||||
}
|
||||
|
||||
lastUpdateMillis = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
30
src/LNG.h
Normal file
30
src/LNG.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef _LNG_H
|
||||
#define _LNG_H
|
||||
|
||||
#include "AmsData.h"
|
||||
#include "AmsConfiguration.h"
|
||||
#include "ams/DataParser.h"
|
||||
#include "RemoteDebug.h"
|
||||
|
||||
struct LngHeader {
|
||||
uint8_t tag;
|
||||
uint8_t values;
|
||||
uint8_t arrayTag;
|
||||
uint8_t arrayLength;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct LngObisDescriptor {
|
||||
uint8_t ignore1[5];
|
||||
uint8_t octetTag;
|
||||
uint8_t octetLength;
|
||||
uint8_t obis[6];
|
||||
uint8_t ignore2[5];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
class LNG : public AmsData {
|
||||
public:
|
||||
LNG(const char* payload, uint8_t useMeterType, MeterConfig* meterConfig, DataParserContext &ctx, RemoteDebug* debugger);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -4,7 +4,6 @@ int8_t DSMRParser::parse(uint8_t *buf, DataParserContext &ctx, bool verified) {
|
||||
uint16_t crcPos = 0;
|
||||
bool reachedEnd = verified;
|
||||
uint8_t lastByte = 0x00;
|
||||
int c = 0;
|
||||
for(int pos = 0; pos < ctx.length; pos++) {
|
||||
uint8_t b = *(buf+pos);
|
||||
if(pos == 0 && b != '/') return DATA_PARSE_BOUNDRY_FLAG_MISSING;
|
||||
|
||||
@@ -27,7 +27,7 @@ int8_t GCMParser::parse(uint8_t *d, DataParserContext &ctx) {
|
||||
memcpy(ctx.system_title, ptr, systemTitleLength);
|
||||
memcpy(initialization_vector, ctx.system_title, systemTitleLength);
|
||||
|
||||
int len;
|
||||
int len = 0;
|
||||
int headersize = 2 + systemTitleLength;
|
||||
ptr += systemTitleLength;
|
||||
if(((*ptr) & 0xFF) == 0x81) {
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
int8_t HDLCParser::parse(uint8_t *d, DataParserContext &ctx) {
|
||||
int len;
|
||||
|
||||
uint8_t flag = *d;
|
||||
|
||||
uint8_t* ptr;
|
||||
if(ctx.length < 3)
|
||||
return DATA_PARSE_INCOMPLETE;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "LlcParser.h"
|
||||
|
||||
int8_t LLCParser::parse(uint8_t *buf, DataParserContext &ctx) {
|
||||
LLCHeader* llc = (LLCHeader*) buf;
|
||||
ctx.length -= 3;
|
||||
return 3;
|
||||
}
|
||||
@@ -5,8 +5,6 @@ int8_t MBUSParser::parse(uint8_t *d, DataParserContext &ctx) {
|
||||
int headersize = 3;
|
||||
int footersize = 1;
|
||||
|
||||
uint8_t flag = *d;
|
||||
|
||||
uint8_t* ptr;
|
||||
|
||||
// https://m-bus.com/documentation-wired/06-application-layer
|
||||
|
||||
Reference in New Issue
Block a user