From 4f1790a464aa55b3a43b95bc584b21dbd9857051 Mon Sep 17 00:00:00 2001 From: Gunnar Skjold Date: Tue, 30 Dec 2025 10:12:31 +0100 Subject: [PATCH] Added support for Iskraemeco IE.5 in Croatia (#1107) * Added support for Croation Iskra * Temp removed meterid * Fixed HDLC block decoding * Fixed context length * Changing some stuff back * Change some stuff back * Final test * Added debugging * Updated selector for iskra dataformat * Added fake test frame --- frames/iskra_croatia.txt | 48 ++++++ lib/AmsDecoder/src/HdlcParser.cpp | 14 +- lib/MeterCommunicators/src/IEC6205675.cpp | 177 +++++++++++++++++----- 3 files changed, 200 insertions(+), 39 deletions(-) create mode 100644 frames/iskra_croatia.txt diff --git a/frames/iskra_croatia.txt b/frames/iskra_croatia.txt new file mode 100644 index 00000000..cbcc3a72 --- /dev/null +++ b/frames/iskra_croatia.txt @@ -0,0 +1,48 @@ +They actually use multiple frames, so this is a "fake" frame combining the two into one, but without checksum fields. + +7E +A0 BD +CF 02 23 03 00 00 +E6 E7 00 +0F 00 03 46 3B +0C 07 E9 0C 13 05 17 37 28 00 FF C4 00 + +02 21 +09 08 39 32 30 32 39 36 39 31 +09 04 17 37 28 00 +09 05 07 E9 0C 13 05 +06 00 6C 28 5A +06 00 4B 76 1A +06 00 20 B2 40 +06 00 58 68 AA +06 00 57 A1 62 +06 00 00 C7 48 +06 00 17 EE D7 +06 00 12 F5 5C +06 00 00 D9 6A +06 00 15 36 84 +06 00 00 01 7E +06 00 00 00 00 +12 03 79 +06 00 00 00 7F +06 00 00 00 BD +06 00 00 00 41 +06 00 00 00 00 +06 00 00 00 00 +06 00 00 00 00 +12 09 54 +12 09 35 +12 09 49 +12 00 37 +12 00 59 +12 00 4D +06 00 00 43 62 +01 01 + 12 24 B8 +01 01 + 12 24 B8 +01 01 + 12 24 B8 +03 01 + +00 00 7E diff --git a/lib/AmsDecoder/src/HdlcParser.cpp b/lib/AmsDecoder/src/HdlcParser.cpp index 685fe005..7bb5d418 100644 --- a/lib/AmsDecoder/src/HdlcParser.cpp +++ b/lib/AmsDecoder/src/HdlcParser.cpp @@ -69,7 +69,12 @@ int8_t HDLCParser::parse(uint8_t *d, DataParserContext &ctx) { if(buf == NULL) return DATA_PARSE_FAIL; - memcpy(buf + pos, ptr+3, ctx.length); // +3 to skip LLC + if((*ptr) == DATA_TAG_LLC) { + ptr += 3; // Skip LLC + ctx.length -= 3; + } + + memcpy(buf + pos, ptr, ctx.length); pos += ctx.length; lastSequenceNumber++; @@ -78,7 +83,12 @@ int8_t HDLCParser::parse(uint8_t *d, DataParserContext &ctx) { lastSequenceNumber = 0; if(buf == NULL) return DATA_PARSE_FAIL; - memcpy(buf + pos, ptr+3, ctx.length); // +3 to skip LLC + if((*ptr) == DATA_TAG_LLC) { + ptr += 3; // Skip LLC + ctx.length -= 3; + } + + memcpy(buf + pos, ptr, ctx.length); pos += ctx.length; memcpy((uint8_t *) d, buf, pos); diff --git a/lib/MeterCommunicators/src/IEC6205675.cpp b/lib/MeterCommunicators/src/IEC6205675.cpp index a03fa2c1..1de4c52d 100644 --- a/lib/MeterCommunicators/src/IEC6205675.cpp +++ b/lib/MeterCommunicators/src/IEC6205675.cpp @@ -39,7 +39,7 @@ IEC6205675::IEC6205675(const char* d, Timezone* tz, uint8_t useMeterType, MeterC this->listId = listId; meterType = AmsTypeKaifa; - int idx = 0; + uint8_t idx = 0; data = getCosemDataAt(idx, ((char *) (d))); idx+=2; if(data->base.length == 0x0D || data->base.length == 0x12) { @@ -141,7 +141,7 @@ IEC6205675::IEC6205675(const char* d, Timezone* tz, uint8_t useMeterType, MeterC this->listId = listId; meterType = AmsTypeIskra; - int idx = 0; + uint8_t idx = 0; data = getCosemDataAt(idx++, ((char *) (d))); if(data->base.length == 0x12) { apply(state); @@ -558,54 +558,157 @@ IEC6205675::IEC6205675(const char* d, Timezone* tz, uint8_t useMeterType, MeterC } } else if(useMeterType == AmsTypeIskra && data->base.type == CosemTypeOctetString) { // Iskra special case meterType = AmsTypeIskra; - uint8_t idx = 5; - data = getCosemDataAt(idx++, ((char *) (d))); - if(data != NULL) { + uint8_t idx = 0; + data = getCosemDataAt(idx, ((char *) (d))); + if(data->base.length == 0x21) { + idx = 4; + + // 1.8.0 + data = getCosemDataAt(idx++, ((char *) (d))); activeImportCounter = ntohl(data->dlu.data) / 1000.0; - } - - data = getCosemDataAt(idx++, ((char *) (d))); - if(data != NULL) { + + // 1.8.1 + // 1.8.2 + idx += 2; + + // 2.8.0 + data = getCosemDataAt(idx++, ((char *) (d))); activeExportCounter = ntohl(data->dlu.data) / 1000.0; - } - - data = getCosemDataAt(idx++, ((char *) (d))); - if(data != NULL) { - reactiveImportCounter = ntohl(data->dlu.data) / 1000.0; - } - - data = getCosemDataAt(idx++, ((char *) (d))); - if(data != NULL) { - reactiveExportCounter = ntohl(data->dlu.data) / 1000.0; - } - data = getCosemDataAt(idx++, ((char *) (d))); - if(data != NULL) { + // 2.8.1 + // 2.8.2 + idx += 2; + + // 5.8.0 + // 6.8.0 + // 7.8.0 + // 8.8.0 + idx += 4; + + // 1.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); activeImportPower = ntohl(data->dlu.data); - } - data = getCosemDataAt(idx++, ((char *) (d))); - if(data != NULL) { + // 2.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); activeExportPower = ntohl(data->dlu.data); - } - uint8_t str_len = 0; - str_len = getString(AMS_OBIS_UNKNOWN_1, sizeof(AMS_OBIS_UNKNOWN_1), ((char *) (d)), str); - if(str_len > 0) { - meterId = String(str); - } + // 13.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); + powerFactor= ntohl(data->dlu.data) / 1000.0; - listType = 3; - lastUpdateMillis = millis64(); + // 21.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); + l1activeImportPower = ntohl(data->dlu.data); + + // 41.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); + l2activeImportPower = ntohl(data->dlu.data); + + // 61.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); + l3activeImportPower = ntohl(data->dlu.data); + + // 22.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); + l1activeExportPower = ntohl(data->dlu.data); + + // 42.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); + l2activeExportPower = ntohl(data->dlu.data); + + // 62.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); + l3activeExportPower = ntohl(data->dlu.data); + + // 32.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); + l1voltage = ntohs(data->lu.data) / 10.0; + + // 52.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); + l2voltage = ntohs(data->lu.data) / 10.0; + + // 72.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); + l3voltage = ntohs(data->lu.data) / 10.0; + + // 31.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); + l1current = ntohs(data->lu.data) / 100.0; + + // 51.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); + l2current = ntohs(data->lu.data) / 100.0; + + // 71.7.0 + data = getCosemDataAt(idx++, ((char *) (d))); + l3current = ntohs(data->lu.data) / 100.0; + + listType = 4; + lastUpdateMillis = millis64(); + } else { + idx = 5; + + data = getCosemDataAt(idx++, ((char *) (d))); + if(data != NULL) { + activeImportCounter = ntohl(data->dlu.data) / 1000.0; + } + + data = getCosemDataAt(idx++, ((char *) (d))); + if(data != NULL) { + activeExportCounter = ntohl(data->dlu.data) / 1000.0; + } + + data = getCosemDataAt(idx++, ((char *) (d))); + if(data != NULL) { + reactiveImportCounter = ntohl(data->dlu.data) / 1000.0; + } + + data = getCosemDataAt(idx++, ((char *) (d))); + if(data != NULL) { + reactiveExportCounter = ntohl(data->dlu.data) / 1000.0; + } + + data = getCosemDataAt(idx++, ((char *) (d))); + if(data != NULL) { + activeImportPower = ntohl(data->dlu.data); + } + + data = getCosemDataAt(idx++, ((char *) (d))); + if(data != NULL) { + activeExportPower = ntohl(data->dlu.data); + } + + uint8_t str_len = 0; + str_len = getString(AMS_OBIS_UNKNOWN_1, sizeof(AMS_OBIS_UNKNOWN_1), ((char *) (d)), str); + if(str_len > 0) { + meterId = String(str); + } + + listType = 4; + lastUpdateMillis = millis64(); + } } else if(useMeterType == AmsTypeUnknown) { - uint8_t str_len = 0; - str_len = getString(AMS_OBIS_UNKNOWN_1, sizeof(AMS_OBIS_UNKNOWN_1), ((char *) (d)), str); - if(str_len > 0) { + uint8_t idx = 1; + CosemData* d1 = getCosemDataAt(idx++, ((char *) (d))); + CosemData* d2 = getCosemDataAt(idx++, ((char *) (d))); + CosemData* d3 = getCosemDataAt(idx++, ((char *) (d))); + + if(d1->base.type == CosemTypeOctetString && d2->base.type == CosemTypeOctetString && d3->base.type == CosemTypeOctetString) { meterType = AmsTypeIskra; - meterId = String(str); lastUpdateMillis = millis64(); listType = 3; + } else { + uint8_t str_len = 0; + str_len = getString(AMS_OBIS_UNKNOWN_1, sizeof(AMS_OBIS_UNKNOWN_1), ((char *) (d)), str); + if(str_len > 0) { + meterType = AmsTypeIskra; + meterId = String(str); + lastUpdateMillis = millis64(); + listType = 3; + } } } }