From eb479f8216bcbd99d61517ee219c731ca4c4a25f Mon Sep 17 00:00:00 2001 From: Gunnar Skjold Date: Tue, 7 Dec 2021 19:07:43 +0100 Subject: [PATCH] More adaptations for Austian meters --- frames/Aidon-TN-3p.raw | 29 +++++++++++++++++++++++++++-- src/AmsDataStorage.cpp | 13 ++++++++++--- src/AmsToMqttBridge.ino | 20 ++++++++++++-------- src/IEC6205675.cpp | 2 +- src/ams/hdlc.cpp | 39 +++++++++++++++++++-------------------- src/ams/hdlc.h | 4 ++++ 6 files changed, 73 insertions(+), 34 deletions(-) diff --git a/frames/Aidon-TN-3p.raw b/frames/Aidon-TN-3p.raw index 0296e2cb..203f832d 100644 --- a/frames/Aidon-TN-3p.raw +++ b/frames/Aidon-TN-3p.raw @@ -2,5 +2,30 @@ 7E A0 2A 41 08 83 13 04 13 E6 E7 00 0F 40 00 00 00 00 01 01 02 03 09 06 01 00 01 07 00 FF 06 00 00 08 64 02 02 0F 00 16 1B E1 7E A1 1E 41 08 83 13 EE EE E6 E7 00 0F 40 00 00 00 00 01 0D 02 02 09 06 01 01 00 02 81 FF 0A 0B 41 49 44 4F 4E 5F 56 30 30 30 31 02 02 09 06 00 00 60 01 00 FF 0A 10 37 33 35 39 39 39 32 38 39 30 34 39 37 39 39 37 02 02 09 06 00 00 60 01 07 FF 0A 04 36 35 33 34 02 03 09 06 01 00 01 07 00 FF 06 00 00 08 6C 02 02 0F 00 16 1B 02 03 09 06 01 00 02 07 00 FF 06 00 00 00 00 02 02 0F 00 16 1B 02 03 09 06 01 00 03 07 00 FF 06 00 00 00 00 02 02 0F 00 16 1D 02 03 09 06 01 00 04 07 00 FF 06 00 00 02 09 02 02 0F 00 16 1D 02 03 09 06 01 00 1F 07 00 FF 10 00 41 02 02 0F FF 16 21 02 03 09 06 01 00 33 07 00 FF 10 00 13 02 02 0F FF 16 21 02 03 09 06 01 00 47 07 00 FF 10 00 0E 02 02 0F FF 16 21 02 03 09 06 01 00 20 07 00 FF 12 08 F2 02 02 0F FF 16 23 02 03 09 06 01 00 34 07 00 FF 12 08 D1 02 02 0F FF 16 23 02 03 09 06 01 00 48 07 00 FF 12 08 E8 02 02 0F FF 16 23 8B 7E A1 8A 41 08 83 13 EB FD E6 E7 00 0F 40 00 00 00 00 01 12 02 02 09 06 01 01 00 02 81 FF 0A 0B 41 49 44 4F 4E 5F 56 30 30 30 31 02 02 09 06 00 00 60 01 00 FF 0A 10 37 33 35 39 39 39 32 38 39 30 34 39 37 39 39 37 02 02 09 06 00 00 60 01 07 FF 0A 04 36 35 33 34 02 03 09 06 01 00 01 07 00 FF 06 00 00 03 9A 02 02 0F 00 16 1B 02 03 09 06 01 00 02 07 00 FF 06 00 00 00 00 02 02 0F 00 16 1B 02 03 09 06 01 00 03 07 00 FF 06 00 00 00 00 02 02 0F 00 16 1D 02 03 09 06 01 00 04 07 00 FF 06 00 00 02 0E 02 02 0F 00 16 1D 02 03 09 06 01 00 1F 07 00 FF 10 00 11 02 02 0F FF 16 21 02 03 09 06 01 00 33 07 00 FF 10 00 10 02 02 0F FF 16 21 02 03 09 06 01 00 47 07 00 FF 10 00 0E 02 02 0F FF 16 21 02 03 09 06 01 00 20 07 00 FF 12 08 F4 02 02 0F FF 16 23 02 03 09 06 01 00 34 07 00 FF 12 08 CD 02 02 0F FF 16 23 02 03 09 06 01 00 48 07 00 FF 12 08 DC 02 02 0F FF 16 23 02 02 09 06 00 00 01 00 00 FF 09 0C 07 E5 03 18 03 08 00 00 FF 00 00 00 02 03 09 06 01 00 01 08 00 FF 06 00 47 F0 34 02 02 0F 01 16 1E 02 03 09 06 01 00 02 08 00 FF 06 00 00 00 00 02 02 0F 01 16 1E 02 03 09 06 01 00 03 08 00 FF 06 00 00 21 9E 02 02 0F 01 16 20 02 03 09 06 01 00 04 08 00 FF 06 00 08 E0 21 02 02 0F 01 16 20 57 -7E A1 8A 41 08 83 13 EB FD E6 E7 00 0F 40 00 00 00 00 01 12 02 02 09 06 01 01 00 02 81 FF 0A 0B 41 49 44 4F 4E 5F 56 30 30 30 31 02 02 09 06 00 00 60 01 00 FF 0A 10 37 33 35 39 39 39 32 38 39 30 34 39 37 39 39 37 02 02 09 06 00 00 60 01 07 FF 0A 04 36 35 33 34 02 03 09 06 01 00 01 07 00 FF 06 00 00 09 6D 02 02 0F 00 16 1B 02 03 09 06 01 00 02 07 00 FF 06 00 00 00 00 02 02 0F 00 16 1B 02 03 09 06 01 00 03 07 00 FF 06 00 00 00 00 02 02 0F 00 16 1D 02 03 09 06 01 00 04 07 00 FF 06 00 00 02 5B 02 02 0F 00 16 1D 02 03 09 06 01 00 1F 07 00 FF 10 00 11 02 02 0F FF 16 21 02 03 09 06 01 00 33 07 00 FF 10 00 03 02 02 0F FF 16 21 02 03 09 06 01 00 47 07 00 FF 10 00 5A 02 02 0F FF 16 21 02 03 09 06 01 00 20 07 00 FF 12 09 04 02 02 0F FF 16 23 02 03 09 06 01 00 34 07 00 FF 12 09 02 02 02 0F FF 16 23 02 03 09 06 01 00 48 07 00 FF 12 08 EC 02 02 0F FF 16 23 02 02 09 06 00 00 01 00 00 FF 09 0C 07 E5 0A 1F 00 14 00 00 FF 00 00 00 02 03 09 06 01 00 01 08 00 FF 06 00 56 9F 52 02 02 0F 01 16 1E 02 03 09 06 01 00 02 08 00 FF 06 00 00 00 00 02 02 0F 01 16 1E 02 03 09 06 01 00 03 08 00 FF 06 00 00 22 D0 02 02 0F 01 16 20 02 03 09 06 01 00 04 08 00 FF 06 00 0A F5 EC 02 02 0F 01 16 20 51 D7 7E -7E A0 2A 41 08 83 13 04 13 E6 E7 00 0F 40 00 00 00 00 01 01 02 03 09 06 01 00 01 07 00 FF 06 00 00 09 56 02 02 0F 00 16 1B AF A1 7E + +7E A1 8A 41 08 83 13 EB FD E6 E7 00 0F 40 00 00 00 00 +01 12 +02 02 09 06 01 01 00 02 81 FF 0A 0B 41 49 44 4F 4E 5F 56 30 30 30 31 +02 02 09 06 00 00 60 01 00 FF 0A 10 37 33 35 39 39 39 32 38 39 30 34 39 37 39 39 37 +02 02 09 06 00 00 60 01 07 FF 0A 04 36 35 33 34 +02 03 09 06 01 00 01 07 00 FF 06 00 00 09 6D 02 02 0F 00 16 1B +02 03 09 06 01 00 02 07 00 FF 06 00 00 00 00 02 02 0F 00 16 1B +02 03 09 06 01 00 03 07 00 FF 06 00 00 00 00 02 02 0F 00 16 1D +02 03 09 06 01 00 04 07 00 FF 06 00 00 02 5B 02 02 0F 00 16 1D + +Object with three values Value Object with two values +| Obis code | | Scaling +| | | | | Unit +02 03 09 06 01 00 1F 07 00 FF 10 00 11 02 02 0F FF 16 21 +02 03 09 06 01 00 33 07 00 FF 10 00 03 02 02 0F FF 16 21 +02 03 09 06 01 00 47 07 00 FF 10 00 5A 02 02 0F FF 16 21 +02 03 09 06 01 00 20 07 00 FF 12 09 04 02 02 0F FF 16 23 +02 03 09 06 01 00 34 07 00 FF 12 09 02 02 02 0F FF 16 23 +02 03 09 06 01 00 48 07 00 FF 12 08 EC 02 02 0F FF 16 23 +02 02 09 06 00 00 01 00 00 FF 09 0C 07 E5 0A 1F 00 14 00 00 FF 00 00 00 +02 03 09 06 01 00 01 08 00 FF 06 00 56 9F 52 02 02 0F 01 16 1E +02 03 09 06 01 00 02 08 00 FF 06 00 00 00 00 02 02 0F 01 16 1E +02 03 09 06 01 00 03 08 00 FF 06 00 00 22 D0 02 02 0F 01 16 20 +02 03 09 06 01 00 04 08 00 FF 06 00 0A F5 EC 02 02 0F 01 16 20 +51 D7 +7E diff --git a/src/AmsDataStorage.cpp b/src/AmsDataStorage.cpp index 6b21f4ee..09c83ce8 100644 --- a/src/AmsDataStorage.cpp +++ b/src/AmsDataStorage.cpp @@ -21,9 +21,16 @@ bool AmsDataStorage::update(AmsData* data) { debugger->printf("(AmsDataStorage) Time is: %d\n", now); } if(now < EPOCH_2021_01_01) { - now = data->getMeterTimestamp(); - if(debugger->isActive(RemoteDebug::DEBUG)) { - debugger->printf("(AmsDataStorage) Using meter timestamp, which is: %d\n", now); + if(data->getMeterTimestamp() > 0) { + now = data->getMeterTimestamp(); + if(debugger->isActive(RemoteDebug::DEBUG)) { + debugger->printf("(AmsDataStorage) Using meter timestamp, which is: %d\n", now); + } + } else if(data->getPackageTimestamp() > 0) { + now = data->getPackageTimestamp(); + if(debugger->isActive(RemoteDebug::DEBUG)) { + debugger->printf("(AmsDataStorage) Using package timestamp, which is: %d\n", now); + } } } if(now-day.lastMeterReadTime < 3595) { diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index fe25b5f0..d252e61c 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -429,7 +429,7 @@ void loop() { errorBlink(); } - if (mqttEnabled) { + if (mqttEnabled || config.isMqttChanged()) { if(mqtt == NULL || !mqtt->connected() || config.isMqttChanged()) { MQTT_connect(); } @@ -670,7 +670,7 @@ void readHanPort() { } if(currentMeterType == 0) { uint8_t flag = hanSerial->read(); - if(flag == 0x7E) currentMeterType = 1; + if(flag == 0x7E || flag == 0x68) currentMeterType = 1; else currentMeterType = 2; hanSerial->readBytes(buf, BUF_SIZE); return; @@ -716,7 +716,8 @@ void readHanPort() { } } len = 0; - if(pos >= 0) { + if(pos > 0) { + while(hanSerial->available()) hanSerial->read(); debugI("Valid HDLC, start at %d", pos); data = IEC6205675(((char *) (buf)) + pos, meterState.getMeterType(), timestamp); } else { @@ -774,11 +775,9 @@ void readHanPort() { meterState.apply(data); - if(ds.update(&meterState)) { + if(ds.update(&data)) { debugI("Saving day plot"); ds.save(); - } else if(data.getListType() == 3) { - debugE("Unable to update day plot"); } } delay(1); @@ -963,7 +962,8 @@ void MQTT_connect() { debugI("Found MQTT CA file"); file = LittleFS.open(FILE_MQTT_CA, "r"); #if defined(ESP8266) - // Disabled for ESP8266 + BearSSL::X509List *serverTrustedCA = new BearSSL::X509List(file); + mqttSecureClient->setTrustAnchors(serverTrustedCA); #elif defined(ESP32) mqttSecureClient->loadCACert(file, file.size()); #endif @@ -971,7 +971,11 @@ void MQTT_connect() { if(LittleFS.exists(FILE_MQTT_CERT) && LittleFS.exists(FILE_MQTT_KEY)) { #if defined(ESP8266) - // Disabled for ESP8266 + file = LittleFS.open(FILE_MQTT_CERT, "r"); + BearSSL::X509List *serverCertList = new BearSSL::X509List(file); + file = LittleFS.open(FILE_MQTT_KEY, "r"); + BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(file); + mqttSecureClient->setClientRSACert(serverCertList, serverPrivKey); #elif defined(ESP32) debugI("Found MQTT certificate file"); file = LittleFS.open(FILE_MQTT_CERT, "r"); diff --git a/src/IEC6205675.cpp b/src/IEC6205675.cpp index 18a3d869..536f6c4f 100644 --- a/src/IEC6205675.cpp +++ b/src/IEC6205675.cpp @@ -217,7 +217,7 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, CosemDateTime packag int adiv = 1; int watt = (l1voltage * l1current) + (l2voltage * l2current) + (l3voltage * l3current); - while(watt / activeImportPower > 2) { + while(activeImportPower > 0 && watt / activeImportPower > 2) { adiv *= 10; watt /= 10; } diff --git a/src/ams/hdlc.cpp b/src/ams/hdlc.cpp index b7e2e316..ca1c1d6a 100644 --- a/src/ams/hdlc.cpp +++ b/src/ams/hdlc.cpp @@ -25,7 +25,7 @@ int HDLC_validate(const uint8_t* d, int length, HDLCConfig* config, CosemDateTim HDLCHeader* h = (HDLCHeader*) d; uint8_t* ptr = (uint8_t*) &h[1]; // Frame format type 3 - if((h->format & 0xF0) == 0xA0) { + if(h->flag == HDLC_FLAG && (h->format & 0xF0) == 0xA0) { // Length field (11 lsb of format) len = (ntohs(h->format) & 0x7FF) + 2; if(len > length) @@ -66,16 +66,13 @@ int HDLC_validate(const uint8_t* d, int length, HDLCConfig* config, CosemDateTim return HDLC_HCS_ERROR; ptr += sizeof *t3; - } else if((h->format & 0xF0) == 0x00) { - // First byte should be start byte - if(h->flag != MBUS_START) - return HDLC_BOUNDRY_FLAG_MISSING; - + } else if(h->flag == MBUS_START) { // TODO: Check that the two next bytes are identical - // Ignore: Flag + Control field + Address + // Ignore: Control field + Address + Flag ptr += 3; headersize += 3; + footersize++; } // Extract LLC @@ -113,8 +110,6 @@ int HDLC_validate(const uint8_t* d, int length, HDLCConfig* config, CosemDateTim if(length < headersize + 18) return HDLC_FRAME_INCOMPLETE; - uint8_t preheadersize = headersize; - ptr++; // Encrypted APDU // http://www.weigu.lu/tutorials/sensors2bus/04_encryption/index.html @@ -133,6 +128,7 @@ int HDLC_validate(const uint8_t* d, int length, HDLCConfig* config, CosemDateTim len = *ptr; // 1-byte payload length ptr++; + headersize += 2; } else if(((*ptr) & 0xFF) == 0x82) { HDLCHeader* h = (HDLCHeader*) ptr; @@ -142,10 +138,11 @@ int HDLC_validate(const uint8_t* d, int length, HDLCConfig* config, CosemDateTim ptr += 3; headersize += 3; } - if(len + preheadersize > length) + len = ceil(len/16.0) * 16; + if(len + headersize + footersize > length) return HDLC_FRAME_INCOMPLETE; - //Serial.printf("\nL: %d : %d, %d : %d\n", length, len, preheadersize, headersize); + //Serial.printf("\nL: %d : %d, %d : %d\n", length, len, headersize, footersize); // TODO: FCS @@ -181,25 +178,27 @@ int HDLC_validate(const uint8_t* d, int length, HDLCConfig* config, CosemDateTim br_gcm_aad_inject(&gcmCtx, config->additional_authenticated_data, aadlen); } br_gcm_flip(&gcmCtx); - br_gcm_run(&gcmCtx, 0, (void*) (ptr), len - footersize - 2); + br_gcm_run(&gcmCtx, 0, (void*) (ptr), len - authkeylen - 5); // 5 == security tag and frame counter if(authkeylen > 0 && br_gcm_check_tag_trunc(&gcmCtx, config->authentication_tag, authkeylen) != 1) { - return -91; + return HDLC_ENCRYPTION_AUTH_FAILED; } #elif defined(ESP32) - uint8_t cipher_text[len - authkeylen - footersize - 2]; - memcpy(cipher_text, ptr, len - authkeylen - footersize - 2); + uint8_t cipher_text[len - authkeylen - 5]; + memcpy(cipher_text, ptr, len - authkeylen - 5); mbedtls_gcm_context m_ctx; mbedtls_gcm_init(&m_ctx); int success = mbedtls_gcm_setkey(&m_ctx, MBEDTLS_CIPHER_ID_AES, config->encryption_key, 128); - if (0 != success ) { - return -92; + if (0 != success) { + return HDLC_ENCRYPTION_KEY_FAILED; } success = mbedtls_gcm_auth_decrypt(&m_ctx, sizeof(cipher_text), config->initialization_vector, sizeof(config->initialization_vector), config->additional_authenticated_data, aadlen, config->authentication_tag, authkeylen, cipher_text, (unsigned char*)(ptr)); - if (0 != success) { - return -91; + if (authkeylen > 0 && success == MBEDTLS_ERR_GCM_AUTH_FAILED) { + return HDLC_ENCRYPTION_AUTH_FAILED; + } else if(success == MBEDTLS_ERR_GCM_BAD_INPUT) { + return HDLC_ENCRYPTION_DECRYPT_FAILED; } mbedtls_gcm_free(&m_ctx); #endif @@ -229,5 +228,5 @@ int HDLC_validate(const uint8_t* d, int length, HDLCConfig* config, CosemDateTim } // Unknown payload - return 0; + return HDLC_UNKNOWN_DATA; } diff --git a/src/ams/hdlc.h b/src/ams/hdlc.h index 8be687c8..5e5a0983 100644 --- a/src/ams/hdlc.h +++ b/src/ams/hdlc.h @@ -9,7 +9,11 @@ #define HDLC_FCS_ERROR -2 #define HDLC_HCS_ERROR -3 #define HDLC_FRAME_INCOMPLETE -4 +#define HDLC_UNKNOWN_DATA -9 #define HDLC_ENCRYPTION_CONFIG_MISSING -90 +#define HDLC_ENCRYPTION_AUTH_FAILED -91 +#define HDLC_ENCRYPTION_KEY_FAILED -92 +#define HDLC_ENCRYPTION_DECRYPT_FAILED -93 #define MBUS_START 0x68 #define MBUS_END 0x16