diff --git a/README.md b/README.md index 6a00a80..f490e65 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,17 @@ parser.load_default_patterns(); Built-in patterns -| Name | Priority | Typical use | -|-------|---------:|-------------------------------------------| -| `T1` | 10 | class ID, tagged OBIS, scaler, value | -| `T2` | 20 | tagged OBIS, value, scaler-unit structure | -| `T3` | 30 | value first, class ID, scaler-unit, OBIS | -| `ADV` | 40 | untagged ZPA/Aidon-style layouts | +| Name | Pattern | Priority | Typical use | +|------------------------------------------|------------------|---------:|-------------------------------------------| +| `classId-taggedObis-scaler-value` | `TC,TO,TS,TV` | 10 | class ID, tagged OBIS, scaler, value | +| `taggedObis-value-scalerUnit` | `TO,TV,TSU` | 20 | tagged OBIS, value, scaler-unit structure | +| `value-classId-scalerUnit-taggedObis` | `TV,TC,TSU,TO` | 30 | value first, class ID, scaler-unit, OBIS | +| `zpaAidon-untaggedLayout` | `ADV` | 40 | untagged ZPA/Aidon-style layouts | +| `structuredObis-value-scalerUnit` | `S(TO, TV, TSU)` | 50 | OBIS, value, scaler-unit structure | +| `structuredObis-value` | `S(TO, TV)` | 60 | OBIS and value structure | +| `flatObis-valuePair` | `TO, TV` | 70 | flat OBIS + value pairs | +| `firstElement-dateTime` | `F, S(TO, TDTM)` | 80 | first-element date-time structure | +| `swappedTagObis-value-scalerUnit` | `TOW, TV, TSU` | 90 | swapped-tag OBIS, value, scaler-unit | Register a custom pattern when your meter emits a different structure diff --git a/build-linux.sh b/build-linux.sh index caa59d1..5fc93fc 100755 --- a/build-linux.sh +++ b/build-linux.sh @@ -1,8 +1,6 @@ #!/usr/bin/env bash -# This script requires clang and g++-13 to be installed: +# This script requires clang to be installed: # sudo apt-get update && sudo apt-get install -y clang -# sudo add-apt-repository ppa:ubuntu-toolchain-r/test -# sudo apt-get install -y g++-13 set -o xtrace -o errexit -o nounset -o pipefail @@ -23,8 +21,6 @@ build_and_test() { ctest --test-dir "$buildDir/${target}-$build_type" } -export CC=gcc-13 -export CXX=g++-13 build_and_test Debug linux-gcc build_and_test Release linux-gcc diff --git a/idf_component.yml b/idf_component.yml index 4eead53..d9c89f8 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "1.0.0" +version: "1.1.0" description: "A C++20 library for parsing DLMS/COSEM push telegrams from electricity meters. It is designed for embedded and integration-heavy environments such as ESPHome" url: "https://github.com/esphome-libs/dlms_parser" files: diff --git a/library.json b/library.json index ab7a000..b23a933 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "dlms_parser", - "version": "1.0.2", + "version": "1.1.0", "description": "A C++20 library for parsing DLMS/COSEM push telegrams from electricity meters. It is designed for embedded and integration-heavy environments such as ESPHome", "keywords": [ "dlms", diff --git a/src/dlms_parser/dlms_parser.cpp b/src/dlms_parser/dlms_parser.cpp index dcf128d..a0b8a86 100644 --- a/src/dlms_parser/dlms_parser.cpp +++ b/src/dlms_parser/dlms_parser.cpp @@ -37,10 +37,16 @@ void DlmsParser::set_authentication_key(const Aes128GcmAuthenticationKey& key) c } void DlmsParser::load_default_patterns() { - axdr_parser_.register_pattern("T1", "TC,TO,TS,TV", 10); - axdr_parser_.register_pattern("T2", "TO,TV,TSU", 20); - axdr_parser_.register_pattern("T3", "TV,TC,TSU,TO", 30); - axdr_parser_.register_pattern("ADV", "ADV", 40); + axdr_parser_.clear_patterns(); + axdr_parser_.register_pattern("classId-taggedObis-scaler-value", "TC,TO,TS,TV", 10); + axdr_parser_.register_pattern("taggedObis-value-scalerUnit", "TO,TV,TSU", 20); + axdr_parser_.register_pattern("value-classId-scalerUnit-taggedObis", "TV,TC,TSU,TO", 30); + axdr_parser_.register_pattern("zpaAidon-untaggedLayout", "ADV", 40); + axdr_parser_.register_pattern("structuredObis-value-scalerUnit", "S(TO, TV, TSU)", 50); + axdr_parser_.register_pattern("structuredObis-value", "S(TO, TV)", 60); + axdr_parser_.register_pattern("flatObis-valuePair", "TO, TV", 70); + axdr_parser_.register_pattern("firstElement-dateTime", "F, S(TO, TDTM)", 80); + axdr_parser_.register_pattern("swappedTagObis-value-scalerUnit", "TOW, TV, TSU", 90); } void DlmsParser::register_pattern(const char* dsl) { diff --git a/tests/expected/hdlc_lgz_e450_2.h b/tests/expected/hdlc_lgz_e450_2.h index c548ef1..9e6e8fd 100644 --- a/tests/expected/hdlc_lgz_e450_2.h +++ b/tests/expected/hdlc_lgz_e450_2.h @@ -46,10 +46,12 @@ const auto hdlc_lgz_e450_2_key = dlms_parser::Aes128GcmDecryptionKey::from_bytes 0xE1, 0xC0, 0xBA, 0x04, 0x8F, 0xA9, 0xA0, 0x23, }).value(); -// 16 flat TO,TV pairs -constexpr size_t hdlc_lgz_e450_2_expected_count = 16; +// 16 flat TO,TV pairs and 1 datetime +constexpr size_t hdlc_lgz_e450_2_expected_count = 17; -const std::map hdlc_lgz_e450_2_expected_strings = {}; +const std::map hdlc_lgz_e450_2_expected_strings = { + {"0.0.0.0.0.0", "2023-11-10 10:58:50"}, // DateTime +}; const std::map hdlc_lgz_e450_2_expected_floats = { {"1.0.1.8.0.255", 12048950.0f}, // Active energy+ total diff --git a/tests/expected/mbus_netz_noe_p1.h b/tests/expected/mbus_netz_noe_p1.h index 24d9a49..a44071e 100644 --- a/tests/expected/mbus_netz_noe_p1.h +++ b/tests/expected/mbus_netz_noe_p1.h @@ -42,9 +42,10 @@ const auto mbus_netz_noe_p1_key = dlms_parser::Aes128GcmDecryptionKey::from_byte }).value(); // 11 T2 objects + 1 meter number (L, TSTR) = 12 total -constexpr size_t mbus_netz_noe_p1_expected_count = 12; +constexpr size_t mbus_netz_noe_p1_expected_count = 13; const std::map mbus_netz_noe_p1_expected_strings = { + {"0.0.0.0.0.0", "2021-09-27 09:47:15.00 -02:00"}, // DateTime {"0.0.96.1.0.255", "181220000009"}, // Meter number (last element, default OBIS from pattern) }; diff --git a/tests/expected/raw_energomera.h b/tests/expected/raw_energomera.h index cd25fbb..00c0ed6 100644 --- a/tests/expected/raw_energomera.h +++ b/tests/expected/raw_energomera.h @@ -31,8 +31,8 @@ const uint8_t raw_energomera_frame[] = { 0x00, 0x03, }; -// 7 objects matched by T1 pattern inside ARRAY(7) of STRUCTURE(6) elements -constexpr size_t raw_energomera_expected_count = 7; +// 7 objects matched by T1 pattern inside ARRAY(7) of STRUCTURE(6) elements and 1 object matched by "Obis-Value" +constexpr size_t raw_energomera_expected_count = 8; const std::map raw_energomera_expected_strings = {}; @@ -44,6 +44,7 @@ const std::map raw_energomera_expected_floats = { {"0.0.97.98.0.255", 0.0f}, // class=1, scaler=2 {"0.0.97.98.10.255", 0.0f}, // class=1, scaler=2 {"0.0.96.5.135.255", 0.0f}, // class=1, scaler=2 + {"0.0.99.98.4.255", 3.0f} }; } // namespace dlms::test_data diff --git a/tests/test_meter_dumps.cpp b/tests/test_meter_dumps.cpp index d25b5aa..68d038a 100644 --- a/tests/test_meter_dumps.cpp +++ b/tests/test_meter_dumps.cpp @@ -159,11 +159,7 @@ TEST_CASE("Integration: RAW APDU") { dlms::test_data::raw_salzburg_netz_frame, dlms::test_data::raw_salzburg_netz_expected_count, dlms::test_data::raw_salzburg_netz_expected_strings, - dlms::test_data::raw_salzburg_netz_expected_floats, - [](dlms_parser::DlmsParser& p) { - p.register_pattern("TO, TDTM"); - p.register_pattern("S(TO, TV)"); - } + dlms::test_data::raw_salzburg_netz_expected_floats ); } @@ -188,8 +184,7 @@ TEST_CASE("Integration: HDLC") { dlms::test_data::iskra550_raw_frame, dlms::test_data::iskra550_expected_count, dlms::test_data::iskra550_expected_strings, - dlms::test_data::iskra550_expected_floats, - [](dlms_parser::DlmsParser& p) { p.register_pattern("S(TO, TV)"); } + dlms::test_data::iskra550_expected_floats ); } @@ -200,8 +195,7 @@ TEST_CASE("Integration: HDLC") { duplicated_frame, dlms::test_data::iskra550_expected_count, dlms::test_data::iskra550_expected_strings, - dlms::test_data::iskra550_expected_floats, - [](dlms_parser::DlmsParser& p) { p.register_pattern("S(TO, TV)"); } + dlms::test_data::iskra550_expected_floats ); } @@ -220,11 +214,7 @@ TEST_CASE("Integration: HDLC") { dlms::test_data::norway_han_1phase_raw_frame, dlms::test_data::norway_han_1phase_expected_count, dlms::test_data::norway_han_1phase_expected_strings, - dlms::test_data::norway_han_1phase_expected_floats, - [](dlms_parser::DlmsParser& p) { - p.register_pattern("S(TO, TV, TSU)"); - p.register_pattern("S(TO, TV)"); - } + dlms::test_data::norway_han_1phase_expected_floats ); } @@ -233,11 +223,7 @@ TEST_CASE("Integration: HDLC") { dlms::test_data::norway_han_3phase_raw_frame, dlms::test_data::norway_han_3phase_expected_count, dlms::test_data::norway_han_3phase_expected_strings, - dlms::test_data::norway_han_3phase_expected_floats, - [](dlms_parser::DlmsParser& p) { - p.register_pattern("DateTime", "F, S(TO, TDTM)"); - p.register_pattern("Obis-Value-Scaler-Unit", "S(TO, TV, TSU)"); - } + dlms::test_data::norway_han_3phase_expected_floats ); } @@ -249,9 +235,6 @@ TEST_CASE("Integration: HDLC") { dlms::test_data::hdlc_landis_gyr_zmf100_expected_floats, [](dlms_parser::DlmsParser& p) { p.set_skip_crc_check(true); - p.register_pattern("S(TO, TDTM)"); - p.register_pattern("S(TO, TV)"); - p.register_pattern("TOW, TV, TSU"); } ); } @@ -274,7 +257,6 @@ TEST_CASE("Integration: HDLC") { [](dlms_parser::DlmsParser& p) { p.set_decryption_key(dlms::test_data::hdlc_landis_gyr_e450_key); p.register_pattern("DateTime", "F, TDTM"); - p.register_pattern("Obis-Value Pair","TO, TV"); } ); } @@ -288,7 +270,6 @@ TEST_CASE("Integration: HDLC") { [](dlms_parser::DlmsParser& p) { p.set_decryption_key(dlms::test_data::hdlc_landis_gyr_e450_key); p.register_pattern("DateTime", "F, TDTM"); - p.register_pattern("Obis-Value Pair", "TO, TV"); } ); } @@ -302,7 +283,6 @@ TEST_CASE("Integration: HDLC") { [](dlms_parser::DlmsParser& p) { p.set_decryption_key(dlms::test_data::hdlc_landis_gyr_e450_key); p.register_pattern("DateTime", "F, TDTM"); - p.register_pattern("Obis-Value Pair", "TO, TV"); } ); } @@ -315,7 +295,7 @@ TEST_CASE("Integration: HDLC") { dlms::test_data::hdlc_lgz_e450_2_expected_floats, [](dlms_parser::DlmsParser& p) { p.set_decryption_key(dlms::test_data::hdlc_lgz_e450_2_key); - p.register_pattern("TO, TV"); + p.register_pattern("DateTime", "F, TDTM"); } ); } @@ -329,7 +309,6 @@ TEST_CASE("Integration: HDLC") { [](dlms_parser::DlmsParser& p) { p.set_decryption_key(dlms::test_data::hdlc_kamstrup_omnipower_key); p.register_pattern("Obis List Ver", "F, TSTR"); - p.register_pattern("Code-Value Pair", "TO, TV"); } ); } @@ -344,7 +323,6 @@ TEST_CASE("Integration: HDLC") { p.set_decryption_key(dlms::test_data::hdlc_kamstrup_omnipower_key); p.set_authentication_key(dlms::test_data::hdlc_kamstrup_omnipower_auth_key); p.register_pattern("Obis List Ver", "F, TSTR"); - p.register_pattern("Code-Value Pair", "TO, TV"); } ); } @@ -359,7 +337,6 @@ TEST_CASE("Integration: HDLC") { p.set_decryption_key(dlms::test_data::hdlc_kamstrup_omnipower_key); p.set_authentication_key(dlms::test_data::hdlc_kamstrup_omnipower_auth_key); p.register_pattern("Obis List Ver", "F, TSTR"); - p.register_pattern("Code-Value Pair", "TO, TV"); } ); } @@ -374,7 +351,6 @@ TEST_CASE("Integration: HDLC") { p.set_decryption_key(dlms::test_data::hdlc_kamstrup_omnipower_key); p.set_authentication_key(dlms::test_data::hdlc_kamstrup_omnipower_auth_key); p.register_pattern("Obis List Ver", "F, TSTR"); - p.register_pattern("Code-Value Pair", "TO, TV"); } ); } @@ -418,7 +394,7 @@ TEST_CASE("Integration: MBus") { p.set_decryption_key(dlms::test_data::mbus_netz_noe_p1_key); const uint8_t meter_obis[] = {0, 0, 96, 1, 0, 255}; // 0.0.96.1.0.255 p.register_pattern("MeterID", "L, TSTR", 0, meter_obis); - p.register_pattern("Obis-Value-Scaler-Unit", "S(TO, TV, TSU)"); + p.register_pattern("DateTime", "F, TDTM"); } ); } @@ -435,7 +411,7 @@ TEST_CASE("Integration: MBus") { p.set_decryption_key(dlms::test_data::mbus_netz_noe_p1_key); const uint8_t meter_obis[] = { 0, 0, 96, 1, 0, 255 }; // 0.0.96.1.0.255 p.register_pattern("MeterID", "L, TSTR", 0, meter_obis); - p.register_pattern("Obis-Value-Scaler-Unit", "S(TO, TV, TSU)"); + p.register_pattern("DateTime", "F, TDTM"); } ); }