Merge branch 'lng-parser'

This commit is contained in:
Gunnar Skjold
2022-10-01 11:56:08 +02:00
6 changed files with 182 additions and 1 deletions

View File

@@ -12,6 +12,7 @@ enum AmsType {
AmsTypeIskra = 0x08,
AmsTypeLandis = 0x09,
AmsTypeSagemcom = 0x0A,
AmsTypeLng = 0x0B,
AmsTypeCustom = 0x88,
AmsTypeUnknown = 0xFF
};

View File

@@ -69,6 +69,7 @@ ADC_MODE(ADC_VCC);
#include "IEC6205621.h"
#include "IEC6205675.h"
#include "LNG.h"
#include "ams/DataParsers.h"
@@ -860,7 +861,8 @@ bool readHanPort() {
if(Debug.isActive(RemoteDebug::VERBOSE)) debugPrint(hanBuffer+pos, 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);
//data = IEC6205675(((char *) (hanBuffer)) + pos, meterState.getMeterType(), &meterConfig, ctx);
data = LNG(((char *) (hanBuffer)) + pos, meterState.getMeterType(), &meterConfig, ctx, &Debug);
} else if(ctx.type == DATA_TAG_DSMR) {
data = IEC6205621(((char *) (hanBuffer)) + pos);
}

111
src/LNG.cpp Normal file
View 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 %d (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 %d (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 %d (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 %d (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 %d (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 %d (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 %d (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 %d (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
View 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

View File

@@ -336,6 +336,9 @@ void AmsWebServer::configMeterHtml() {
case AmsTypeSagemcom:
manufacturer = "Sagemcom";
break;
case AmsTypeLng:
manufacturer = "L&G";
break;
default:
manufacturer = "Unknown";
break;