@@ -73,6 +73,41 @@ namespace dsmr
73
73
}
74
74
};
75
75
76
+ // A hexstring field is essencially a string filled with hex digits. If the
77
+ // string does not consist of an even number of hex digits, the original
78
+ // string is returned, otherwise the decoded hex string is returned.
79
+ template <typename T, size_t minlen, size_t maxlen>
80
+ struct HexStringField : ParsedField<T>
81
+ {
82
+ ParseResult<void > parse (const char *str, const char *end)
83
+ {
84
+ ParseResult<String> res = StringParser::parse_string (minlen, maxlen, str, end);
85
+ if (!res.err ) {
86
+ static_cast <T *>(this )->val () = res.result ;
87
+
88
+ if (res.result .length () & 1 ) {
89
+ // Odd number of chars, can't be a hex coded string.
90
+ return res;
91
+ }
92
+ if (!std::all_of (res.result .begin (), res.result .end (), [](const char ch){ return isxdigit (ch); })) {
93
+ // Not all chars are hex digits.
94
+ return res;
95
+ }
96
+ String hexStr;
97
+ hexStr.reserve (res.result .length ()/2 );
98
+ for (auto it = res.result .begin (); it != res.result .end (); ++it) {
99
+ const unsigned char ch1 = static_cast <unsigned const char >(*it++);
100
+ const unsigned char ch2 = static_cast <unsigned const char >(*it);
101
+ uint8_t val = (isdigit (ch1) ? ch1 - ' 0' : toupper (ch1) - ' A' + 10 ) * 16 +
102
+ (isdigit (ch2) ? ch2 - ' 0' : toupper (ch2) - ' A' + 10 );
103
+ hexStr.concat (static_cast <char >(val));
104
+ }
105
+ static_cast <T *>(this )->val () = hexStr;
106
+ }
107
+ return res;
108
+ }
109
+ };
110
+
76
111
// A timestamp is essentially a string using YYMMDDhhmmssX format (where
77
112
// X is W or S for wintertime or summertime). Parsing this into a proper
78
113
// (UNIX) timestamp is hard to do generically. Parsing it into a
@@ -268,7 +303,7 @@ namespace dsmr
268
303
DEFINE_FIELD (timestamp, String, ObisId(0 , 0 , 1 , 0 , 0 ), TimestampField);
269
304
270
305
/* Equipment identifier */
271
- DEFINE_FIELD (equipment_id, String, ObisId(0 , 0 , 96 , 1 , 1 ), StringField , 0, 96);
306
+ DEFINE_FIELD (equipment_id, String, ObisId(0 , 0 , 96 , 1 , 1 ), HexStringField , 0, 96);
272
307
273
308
/* Meter Reading electricity delivered to client (Special for Lux) in 0,001 kWh */
274
309
DEFINE_FIELD (energy_delivered_lux, FixedValue, ObisId(1 , 0 , 1 , 8 , 0 ), FixedField, units::kWh, units::Wh);
@@ -398,9 +433,9 @@ namespace dsmr
398
433
DEFINE_FIELD (gas_device_type, uint16_t , ObisId(0 , GAS_MBUS_ID, 24 , 1 , 0 ), IntField, units::none);
399
434
400
435
/* Equipment identifier (Gas) */
401
- DEFINE_FIELD (gas_equipment_id, String, ObisId(0 , GAS_MBUS_ID, 96 , 1 , 0 ), StringField , 0, 96);
436
+ DEFINE_FIELD (gas_equipment_id, String, ObisId(0 , GAS_MBUS_ID, 96 , 1 , 0 ), HexStringField , 0, 96);
402
437
/* Equipment identifier (Gas) BE */
403
- DEFINE_FIELD (gas_equipment_id_be, String, ObisId(0 , GAS_MBUS_ID, 96 , 1 , 1 ), StringField , 0, 96);
438
+ DEFINE_FIELD (gas_equipment_id_be, String, ObisId(0 , GAS_MBUS_ID, 96 , 1 , 1 ), HexStringField , 0, 96);
404
439
405
440
/* Valve position Gas (on/off/released) (Note: Removed in 4.0.7 / 4.2.2 / 5.0). */
406
441
DEFINE_FIELD (gas_valve_position, uint8_t , ObisId(0 , GAS_MBUS_ID, 24 , 4 , 0 ), IntField, units::none);
@@ -419,7 +454,7 @@ namespace dsmr
419
454
DEFINE_FIELD (thermal_device_type, uint16_t , ObisId(0 , THERMAL_MBUS_ID, 24 , 1 , 0 ), IntField, units::none);
420
455
421
456
/* Equipment identifier (Thermal: heat or cold) */
422
- DEFINE_FIELD (thermal_equipment_id, String, ObisId(0 , THERMAL_MBUS_ID, 96 , 1 , 0 ), StringField , 0, 96);
457
+ DEFINE_FIELD (thermal_equipment_id, String, ObisId(0 , THERMAL_MBUS_ID, 96 , 1 , 0 ), HexStringField , 0, 96);
423
458
424
459
/* Valve position (on/off/released) (Note: Removed in 4.0.7 / 4.2.2 / 5.0). */
425
460
DEFINE_FIELD (thermal_valve_position, uint8_t , ObisId(0 , THERMAL_MBUS_ID, 24 , 4 , 0 ), IntField, units::none);
@@ -433,7 +468,7 @@ namespace dsmr
433
468
DEFINE_FIELD (water_device_type, uint16_t , ObisId(0 , WATER_MBUS_ID, 24 , 1 , 0 ), IntField, units::none);
434
469
435
470
/* Equipment identifier (Thermal: heat or cold) */
436
- DEFINE_FIELD (water_equipment_id, String, ObisId(0 , WATER_MBUS_ID, 96 , 1 , 0 ), StringField , 0, 96);
471
+ DEFINE_FIELD (water_equipment_id, String, ObisId(0 , WATER_MBUS_ID, 96 , 1 , 0 ), HexStringField , 0, 96);
437
472
438
473
/* Valve position (on/off/released) (Note: Removed in 4.0.7 / 4.2.2 / 5.0). */
439
474
DEFINE_FIELD (water_valve_position, uint8_t , ObisId(0 , WATER_MBUS_ID, 24 , 4 , 0 ), IntField, units::none);
@@ -447,7 +482,7 @@ namespace dsmr
447
482
DEFINE_FIELD (sub_device_type, uint16_t , ObisId(0 , SUB_MBUS_ID, 24 , 1 , 0 ), IntField, units::none);
448
483
449
484
/* Equipment identifier (Thermal: heat or cold) */
450
- DEFINE_FIELD (sub_equipment_id, String, ObisId(0 , SUB_MBUS_ID, 96 , 1 , 0 ), StringField , 0, 96);
485
+ DEFINE_FIELD (sub_equipment_id, String, ObisId(0 , SUB_MBUS_ID, 96 , 1 , 0 ), HexStringField , 0, 96);
451
486
452
487
/* Valve position (on/off/released) (Note: Removed in 4.0.7 / 4.2.2 / 5.0). */
453
488
DEFINE_FIELD (sub_valve_position, uint8_t , ObisId(0 , SUB_MBUS_ID, 24 , 4 , 0 ), IntField, units::none);
0 commit comments