Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 1 addition & 5 deletions build-linux.sh
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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

Expand Down
2 changes: 1 addition & 1 deletion idf_component.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
14 changes: 10 additions & 4 deletions src/dlms_parser/dlms_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 5 additions & 3 deletions tests/expected/hdlc_lgz_e450_2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string, std::string> hdlc_lgz_e450_2_expected_strings = {};
const std::map<std::string, std::string> hdlc_lgz_e450_2_expected_strings = {
{"0.0.0.0.0.0", "2023-11-10 10:58:50"}, // DateTime
};

const std::map<std::string, float> hdlc_lgz_e450_2_expected_floats = {
{"1.0.1.8.0.255", 12048950.0f}, // Active energy+ total
Expand Down
3 changes: 2 additions & 1 deletion tests/expected/mbus_netz_noe_p1.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string, std::string> 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)
Comment thread
PolarGoose marked this conversation as resolved.
};

Expand Down
5 changes: 3 additions & 2 deletions tests/expected/raw_energomera.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string, std::string> raw_energomera_expected_strings = {};

Expand All @@ -44,6 +44,7 @@ const std::map<std::string, float> 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
40 changes: 8 additions & 32 deletions tests/test_meter_dumps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
}

Expand All @@ -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
);
}

Expand All @@ -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
);
}

Expand All @@ -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
);
}

Expand All @@ -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
);
}

Expand All @@ -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");
}
);
}
Expand All @@ -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");
}
);
}
Expand All @@ -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");
}
);
}
Expand All @@ -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");
}
);
}
Expand All @@ -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");
}
);
}
Expand All @@ -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");
}
);
}
Expand All @@ -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");
}
);
}
Expand All @@ -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");
}
);
}
Expand All @@ -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");
}
);
}
Expand Down Expand Up @@ -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");
}
);
}
Expand All @@ -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");
}
);
}
Expand Down
Loading