Improve extraction of readble strings like fabricatio no and enhanced id.

pull/473/head
Fredrik Öhrström 2022-02-06 11:21:15 +01:00
rodzic 86b7163aa1
commit cb794cae42
19 zmienionych plików z 206 dodań i 58 usunięć

Wyświetl plik

@ -1,4 +1,6 @@
NOTE! Json slight json output change drivers esyswm and evo868 where fabrication now is now properly reversed.
You can now combine --useconfig=<dir> with --oneshot --exitafter=<time>
--silent --verbose --debug --normal --trace to override the config file settings.
(Already existing possible overrides was --device=<device> and --listento<mode>.)

Wyświetl plik

@ -163,13 +163,13 @@ telegram=|5B445A149922992202378C20F6900F002C25BC9E0000BF48954821BC508D7299229922
# Test electricity meter with ESYS-WM20
# static telegram
telegram=|7B4479169977997730378C208B900F002C25E4EF0A002EA98E7D58B3ADC57299779977991611028B005087102F2F|0DFD090F34302e3030562030303030303030300D790E31323334353637383839595345310DFD100AAAAAAAAAAAAAAAAAAAAA0D780E31323334353637383930594553312F2F2F2F2F2F2F2F2F2F2F|
{"media":"electricity","meter":"esyswm","name":"Elen2","id":"77997799","total_energy_consumption_kwh":0,"current_power_consumption_kw":0,"total_energy_production_kwh":0,"total_energy_consumption_tariff1_kwh":0,"total_energy_consumption_tariff2_kwh":0,"current_power_consumption_phase1_kw":0,"current_power_consumption_phase2_kw":0,"current_power_consumption_phase3_kw":0,"enhanced_id":"1ESY9887654321","version":"40.00V 00000000","location_hex":"AAAAAAAAAAAAAAAAAAAA","fabrication_no":"1SEY0987654321","timestamp":"1111-11-11T11:11:11Z"}
telegram=|7B4479169977997730378C208B900F002C25E4EF0A002EA98E7D58B3ADC57299779977991611028B005087102F2F#0DFD090F34302e3030562030303030303030300D790E31323334353637383839595345310DFD100AAAAAAAAAAAAAAAAAAAAA0D780E31323334353637383930594553312F2F2F2F2F2F2F2F2F2F2F|
{"media":"electricity","meter":"esyswm","name":"Elen2","id":"77997799","total_energy_consumption_kwh":0,"current_power_consumption_kw":0,"total_energy_production_kwh":0,"total_energy_consumption_tariff1_kwh":0,"total_energy_consumption_tariff2_kwh":0,"current_power_consumption_phase1_kw":0,"current_power_consumption_phase2_kw":0,"current_power_consumption_phase3_kw":0,"enhanced_id":"1ESY9887654321","version":"00000000 V00.04","location_hex":"AAAAAAAAAAAAAAAAAAAA","fabrication_no":"1SEY0987654321","timestamp":"1111-11-11T11:11:11Z"}
|Elen2;77997799;0.000000;0.000000;0.000000;0.000000;0.000000;0.000000;0.000000;0.000000;1ESY9887654321;1111-11-11 11:11.11
# dynamic telegram
telegram=|7B4479169977997730378C20F0900F002C2549EE0A0077C19D3D1A08ABCD729977997779161102F0005007102F2F|0702F5C3FA000000000007823C5407000000000000841004E081020084200415000000042938AB000004A9FF01FA0A000004A9FF02050A000004A9FF03389600002F2F2F2F2F2F2F2F2F2F2F2F2F|
{"media":"electricity","meter":"esyswm","name":"Elen2","id":"77997799","total_energy_consumption_kwh":1643.4165,"current_power_consumption_kw":0.43832,"total_energy_production_kwh":0.1876,"total_energy_consumption_tariff1_kwh":1643.2,"total_energy_consumption_tariff2_kwh":0.21,"current_power_consumption_phase1_kw":0.0281,"current_power_consumption_phase2_kw":0.02565,"current_power_consumption_phase3_kw":0.38456,"enhanced_id":"1ESY9887654321","version":"40.00V 00000000","location_hex":"AAAAAAAAAAAAAAAAAAAA","fabrication_no":"1SEY0987654321","timestamp":"1111-11-11T11:11:11Z"}
telegram=|7B4479169977997730378C20F0900F002C2549EE0A0077C19D3D1A08ABCD729977997779161102F0005007102F2F#0702F5C3FA000000000007823C5407000000000000841004E081020084200415000000042938AB000004A9FF01FA0A000004A9FF02050A000004A9FF03389600002F2F2F2F2F2F2F2F2F2F2F2F2F|
{"media":"electricity","meter":"esyswm","name":"Elen2","id":"77997799","total_energy_consumption_kwh":1643.4165,"current_power_consumption_kw":0.43832,"total_energy_production_kwh":0.1876,"total_energy_consumption_tariff1_kwh":1643.2,"total_energy_consumption_tariff2_kwh":0.21,"current_power_consumption_phase1_kw":0.0281,"current_power_consumption_phase2_kw":0.02565,"current_power_consumption_phase3_kw":0.38456,"enhanced_id":"1ESY9887654321","version":"00000000 V00.04","location_hex":"AAAAAAAAAAAAAAAAAAAA","fabrication_no":"1SEY0987654321","timestamp":"1111-11-11T11:11:11Z"}
|Elen2;77997799;1643.416500;0.438320;0.187600;1643.200000;0.210000;0.028100;0.025650;0.384560;1ESY9887654321;1111-11-11 11:11.11
# Test electricity meter eHZ-P
@ -234,7 +234,7 @@ telegram=|36446850626262624543A1|009F2777010060780000000A00000000000000000000000
# Test Maddalena EVO 868 wmbus module on water meter
telegram=|aa4424347677787950077ac10000202f2f041306070000046d1e31b12104fd17000000000e787880048120004413c9040000426c9f2c840113c904000082016c9f2cd3013b9a0200c4016d0534a7218104fd280182046c9f2c840413c9040000c404131b00000084051300000000c405130000000084061300000000c406130000000084071300000000c407130000000084081300000000c408130000000084091300000000c4091300000000ffff|
{"media":"water","meter":"evo868","name":"Votchka","id":"79787776","total_m3":1.798,"device_date_time":"2021-01-17 17:30","current_status":"OK","fabrication_no":"000218400887","consumption_at_set_date_m3":1.225,"set_date":"2020-12-31","consumption_at_set_date_2_m3":1.225,"set_date_2":"2020-12-31","max_flow_since_datetime_m3h":0.666,"max_flow_datetime":"2021-01-07 20:05","consumption_at_history_1_m3":1.225,"history_1_date":"2020-12-31","consumption_at_history_2_m3":0.027,"history_2_date":"2020-11-30","consumption_at_history_3_m3":0,"history_3_date":"2020-10-31","consumption_at_history_4_m3":0,"history_4_date":"2020-09-30","consumption_at_history_5_m3":0,"history_5_date":"2020-08-31","consumption_at_history_6_m3":0,"history_6_date":"2020-07-31","consumption_at_history_7_m3":0,"history_7_date":"2020-06-30","consumption_at_history_8_m3":0,"history_8_date":"2020-05-31","consumption_at_history_9_m3":0,"history_9_date":"2020-04-30","consumption_at_history_10_m3":0,"history_10_date":"2020-03-31","consumption_at_history_11_m3":0,"history_11_date":"2020-02-29","consumption_at_history_12_m3":0,"history_12_date":"2020-01-31","timestamp":"1111-11-11T11:11:11Z"}
{"media":"water","meter":"evo868","name":"Votchka","id":"79787776","total_m3":1.798,"device_date_time":"2021-01-17 17:30","current_status":"OK","fabrication_no":"002081048078","consumption_at_set_date_m3":1.225,"set_date":"2020-12-31","consumption_at_set_date_2_m3":1.225,"set_date_2":"2020-12-31","max_flow_since_datetime_m3h":0.666,"max_flow_datetime":"2021-01-07 20:05","consumption_at_history_1_m3":1.225,"history_1_date":"2020-12-31","consumption_at_history_2_m3":0.027,"history_2_date":"2020-11-30","consumption_at_history_3_m3":0,"history_3_date":"2020-10-31","consumption_at_history_4_m3":0,"history_4_date":"2020-09-30","consumption_at_history_5_m3":0,"history_5_date":"2020-08-31","consumption_at_history_6_m3":0,"history_6_date":"2020-07-31","consumption_at_history_7_m3":0,"history_7_date":"2020-06-30","consumption_at_history_8_m3":0,"history_8_date":"2020-05-31","consumption_at_history_9_m3":0,"history_9_date":"2020-04-30","consumption_at_history_10_m3":0,"history_10_date":"2020-03-31","consumption_at_history_11_m3":0,"history_11_date":"2020-02-29","consumption_at_history_12_m3":0,"history_12_date":"2020-01-31","timestamp":"1111-11-11T11:11:11Z"}
|Votchka;79787776;1.798000;OK;1.225000;2020-12-31;1111-11-11 11:11.11
# Test Gran-System-S electricity meter 101

Wyświetl plik

@ -29,6 +29,9 @@ private:
string meter_date_;
double target_water_consumption_m3_ {};
string target_date_;
string unknown_a_;
string unknown_b_;
string enhanced_id_;
};
static bool ok = registerDriver([](DriverInfo&di)
@ -107,10 +110,76 @@ MeterItron::MeterItron(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementatio
SET_STRING_FUNC(target_date_),
GET_STRING_FUNC(target_date_));
addStringFieldWithExtractor(
"enhanced_id",
Quantity::Text,
DifVifKey("0E79"),
MeasurementType::Unknown,
ValueInformation::EnhancedIdentification,
StorageNr(0),
TariffNr(0),
IndexNr(1),
PrintProperty::JSON,
"Enhanced meter id.",
SET_STRING_FUNC(enhanced_id_),
GET_STRING_FUNC(enhanced_id_));
addStringFieldWithExtractorAndLookup(
"unknown_a",
Quantity::Text,
DifVifKey("047F"),
MeasurementType::Unknown,
ValueInformation::Any,
AnyStorageNr,
AnyTariffNr,
IndexNr(1),
PrintProperty::JSON,
"Unknown flags.",
SET_STRING_FUNC(unknown_a_),
GET_STRING_FUNC(unknown_a_),
{
{
{
"",
Translate::Type::BitToString,
0xffffffff,
"",
{
}
},
},
});
addStringFieldWithExtractorAndLookup(
"unknown_b",
Quantity::Text,
DifVifKey("027F"),
MeasurementType::Unknown,
ValueInformation::Any,
AnyStorageNr,
AnyTariffNr,
IndexNr(1),
PrintProperty::JSON,
"Unknown flags.",
SET_STRING_FUNC(unknown_b_),
GET_STRING_FUNC(unknown_b_),
{
{
{
"",
Translate::Type::BitToString,
0xffff,
"",
{
}
},
},
});
}
// Test: SomeWater itron 12345698 NOKEY
// Comment: Test ITRON T1 telegram not encrypted, which has no 2f2f markers.
// telegram=|384497269856341203077AD90000A0#0413FD110000066D2C1AA1D521004413300F0000426CBF2C047F0000060C027F862A0E79678372082100|
// {"media":"water","meter":"itron","name":"SomeWater","id":"12345698","total_m3":4.605,"meter_date":"2022-01-21 01:26","target_m3":3.888,"target_date":"2021-12-31","timestamp":"1111-11-11T11:11:11Z"}
// {"media":"water","meter":"itron","name":"SomeWater","id":"12345698","total_m3":4.605,"meter_date":"2022-01-21 01:26","target_m3":3.888,"target_date":"2021-12-31","enhanced_id":"002108728367","unknown_a":"UNKNOWN_(0xc060000)","unknown_b":"UNKNOWN_(0x2a86)","timestamp":"1111-11-11T11:11:11Z"}
// |SomeWater;12345698;4.605000;3.888000;1111-11-11 11:11.11

Wyświetl plik

@ -761,20 +761,68 @@ bool extractDVlong(map<string,pair<int,DVEntry>> *values,
return true;
}
bool extractDVstring(map<string,pair<int,DVEntry>> *values,
string key,
int *offset,
string *value)
bool extractDVHexString(map<string,pair<int,DVEntry>> *values,
string key,
int *offset,
string *value)
{
if ((*values).count(key) == 0) {
verbose("(dvparser) warning: cannot extract string from non-existant key \"%s\"\n", key.c_str());
*offset = -1;
*value = "";
return false;
}
pair<int,DVEntry>& p = (*values)[key];
*offset = p.first;
*value = p.second.value;
return true;
}
bool extractDVReadableString(map<string,pair<int,DVEntry>> *values,
string key,
int *offset,
string *value)
{
if ((*values).count(key) == 0) {
verbose("(dvparser) warning: cannot extract string from non-existant key \"%s\"\n", key.c_str());
*offset = -1;
return false;
}
uchar dif, vif;
extractDV(key, &dif, &vif);
int t = dif&0xf;
pair<int,DVEntry>& p = (*values)[key];
*offset = p.first;
string v = p.second.value;
if (t == 0x1 || // 8 Bit Integer/Binary
t == 0x2 || // 16 Bit Integer/Binary
t == 0x3 || // 24 Bit Integer/Binary
t == 0x4 || // 32 Bit Integer/Binary
t == 0x6 || // 48 Bit Integer/Binary
t == 0x7 || // 64 Bit Integer/Binary
t == 0xD) // Variable length
{
// For example an enhanced id 32 bits binary looks like:
// 44434241 and will be reversed to: 41424344 and translated using ascii
// to ABCD
v = reverseBinaryAsciiSafeToString(v);
}
if (t == 0x9 || // 2 digit BCD
t == 0xA || // 4 digit BCD
t == 0xB || // 6 digit BCD
t == 0xC || // 8 digit BCD
t == 0xE) // 12 digit BCD
{
// For example an enhanced id 12 digit bcd looks like:
// 618171183100 and will be reversed to: 003118718161
v = reverseBCD(v);
}
*value = v;
return true;
}

Wyświetl plik

@ -43,6 +43,7 @@
X(EnergyWh,0x00,0x07, Quantity::Energy, Unit::KWH) \
X(PowerW,0x28,0x2f, Quantity::Power, Unit::KW) \
X(ActualityDuration,0x74,0x77, Quantity::Time, Unit::Second) \
X(EnhancedIdentification,0x79,0x79, Quantity::Text, Unit::TXT) \
enum class ValueInformation
{
@ -165,10 +166,18 @@ bool extractDVlong(map<string,pair<int,DVEntry>> *values,
int *offset,
uint64_t *value);
bool extractDVstring(std::map<std::string,std::pair<int,DVEntry>> *values,
std::string key,
int *offset,
string *value);
// Just copy the raw hex data into the string, not reversed or anything.
bool extractDVHexString(std::map<std::string,std::pair<int,DVEntry>> *values,
std::string key,
int *offset,
string *value);
// Read the content and attempt to reverse and transform it into a readble string
// based on the dif information.
bool extractDVReadableString(std::map<std::string,std::pair<int,DVEntry>> *values,
std::string key,
int *offset,
string *value);
bool extractDVdate(std::map<std::string,std::pair<int,DVEntry>> *values,
std::string key,

Wyświetl plik

@ -170,7 +170,7 @@ void MeterEBZWMBE::processContent(Telegram *t)
t->addMoreExplanation(offset, " current power (%f kw)", current_power_kw_);
string tmp;
extractDVstring(&t->values, "0DFD11", &offset, &tmp);
extractDVHexString(&t->values, "0DFD11", &offset, &tmp);
if (tmp.length() > 0) {
vector<uchar> bin;
hex2bin(tmp, &bin);

Wyświetl plik

@ -286,37 +286,15 @@ void MeterESYSWM::processContent(Telegram *t)
extractDVdouble(&t->values, "04A9FF03", &offset, &current_power_phase3_kw_);
t->addMoreExplanation(offset, " current power phase 3 (%f kwh)", current_power_phase3_kw_);
string tmp;
extractDVstring(&t->values, "0DFD09", &offset, &tmp);
if (tmp.length() > 0) {
vector<uchar> bin;
hex2bin(tmp, &bin);
version_ = safeString(bin);
}
extractDVReadableString(&t->values, "0DFD09", &offset, &version_);
t->addMoreExplanation(offset, " version (%s)", version_.c_str());
extractDVstring(&t->values, "0D79", &offset, &tmp);
if (tmp.length() > 0) {
vector<uchar> bin;
hex2bin(tmp, &bin);
reverse(bin.begin(), bin.end());
enhanced_id_ = safeString(bin);
}
extractDVReadableString(&t->values, "0D79", &offset, &enhanced_id_);
t->addMoreExplanation(offset, " enhanced id (%s)", enhanced_id_.c_str());
extractDVstring(&t->values, "0DFD10", &offset, &tmp);
if (tmp.length() > 0) {
location_hex_ = tmp;
}
extractDVHexString(&t->values, "0DFD10", &offset, &location_hex_);
t->addMoreExplanation(offset, " location (%s)", location_hex_.c_str());
extractDVstring(&t->values, "0D78", &offset, &tmp);
if (tmp.length() > 0) {
vector<uchar> bin;
hex2bin(tmp, &bin);
reverse(bin.begin(), bin.end());
fabrication_no_ = safeString(bin);
}
extractDVReadableString(&t->values, "0D78", &offset, &fabrication_no_);
t->addMoreExplanation(offset, " fabrication no (%s)", fabrication_no_.c_str());
}

Wyświetl plik

@ -274,8 +274,7 @@ void MeterEvo868::processContent(Telegram *t)
extractDVuint32(&t->values, "04FD17", &offset, &error_flags_);
t->addMoreExplanation(offset, " error flags (%s)", status().c_str());
extractDVstring(&t->values, "0E78", &offset, &fabrication_no_);
reverse(fabrication_no_.begin(), fabrication_no_.end());
extractDVReadableString(&t->values, "0E78", &offset, &fabrication_no_);
t->addMoreExplanation(offset, " fabrication no (%s)", fabrication_no_.c_str());
if(findKey(MeasurementType::Instantaneous, ValueInformation::Volume, 1, 0, &key, &t->values)) {

Wyświetl plik

@ -201,7 +201,7 @@ void MeterFHKVDataIV::processContent(Telegram *t)
key = "0DFF5F";
if (hasKey(&t->values, key)) {
string hex;
extractDVstring(&t->values, key, &offset, &hex);
extractDVHexString(&t->values, key, &offset, &hex);
t->addMoreExplanation(offset, " vendor extension data");
// This is not stored anywhere yet, we need to understand it, if necessary.
}

Wyświetl plik

@ -214,7 +214,7 @@ void MeterQCaloric::processContent(Telegram *t)
key = "0DFF5F";
if (hasKey(&t->values, key)) {
string hex;
extractDVstring(&t->values, key, &offset, &hex);
extractDVHexString(&t->values, key, &offset, &hex);
t->addMoreExplanation(offset, " vendor extension data");
// This is not stored anywhere yet, we need to understand it, if necessary.
}

Wyświetl plik

@ -282,7 +282,7 @@ void MeterSontex868::processContent(Telegram *t)
key = "0DFF5F";
if (hasKey(&t->values, key)) {
string hex;
extractDVstring(&t->values, key, &offset, &hex);
extractDVHexString(&t->values, key, &offset, &hex);
t->addMoreExplanation(offset, " vendor extension data");
// This is not stored anywhere yet, we need to understand it, if necessary.
}

Wyświetl plik

@ -217,7 +217,7 @@ void MeterUnismart::processContent(Telegram *t)
}
string tmp;
if (extractDVstring(&t->values, "0DFD0C", &offset, &tmp))
if (extractDVHexString(&t->values, "0DFD0C", &offset, &tmp))
{
vector<uchar> bin;
hex2bin(tmp, &bin);
@ -233,17 +233,17 @@ void MeterUnismart::processContent(Telegram *t)
t->addMoreExplanation(offset, " device datetime (%s)", device_date_time_.c_str());
}
if (extractDVstring(&t->values, "01FD67", &offset, &supplier_info_))
if (extractDVHexString(&t->values, "01FD67", &offset, &supplier_info_))
{
t->addMoreExplanation(offset, " suppler info (%s)", supplier_info_.c_str());
}
if (extractDVstring(&t->values, "02FD74", &offset, &status_))
if (extractDVHexString(&t->values, "02FD74", &offset, &status_))
{
t->addMoreExplanation(offset, " status (%s)", status_.c_str());
}
if (extractDVstring(&t->values, "01FD0B", &offset, &parameter_set_))
if (extractDVHexString(&t->values, "01FD0B", &offset, &parameter_set_))
{
t->addMoreExplanation(offset, " parameter set (%s)", parameter_set_.c_str());
}

Wyświetl plik

@ -215,7 +215,7 @@ void MeterWhe46x::processContent(Telegram *t)
key = "0DFF5F";
if (hasKey(&t->values, key)) {
extractDVstring(&t->values, key, &offset, &vendor_data_);
extractDVHexString(&t->values, key, &offset, &vendor_data_);
t->addMoreExplanation(offset, " vendor extension data");
}

Wyświetl plik

@ -147,7 +147,7 @@ void MeterWhe5x::processContent(Telegram *t)
key = "0DFF5F";
if (hasKey(&t->values, key)) {
string hex;
extractDVstring(&t->values, key, &offset, &hex);
extractDVHexString(&t->values, key, &offset, &hex);
t->addMoreExplanation(offset, " vendor extension data");
// This is not stored anywhere yet, we need to understand it, if necessary.
}

Wyświetl plik

@ -864,9 +864,20 @@ void MeterCommonImplementation::addStringFieldWithExtractor(
t->addMoreExplanation(offset, fi->renderJsonText());
found = true;
}
else if (fi->valueInformation() == ValueInformation::EnhancedIdentification)
{
string extracted_id;
extractDVReadableString(&t->values, key, &offset, &extracted_id);
fi->setValueString(extracted_id);
t->addMoreExplanation(offset, fi->renderJsonText());
found = true;
}
else
{
assert(0);
error("Internal error: Cannot extract text string from vif %s in %s:%d\n",
toString(fi->valueInformation()),
__FILE__, __LINE__);
}
return found;
};

Wyświetl plik

@ -173,10 +173,10 @@ void test_string(map<string,pair<int,DVEntry>> &values, const char *key, const c
{
int offset;
string value;
bool b = extractDVstring(&values,
key,
&offset,
&value);
bool b = extractDVHexString(&values,
key,
&offset,
&value);
if (!b || value != v) {
fprintf(stderr, "Error in dvparser testnr %d: got \"%s\" but expected value \"%s\" for key %s\n", testnr, value.c_str(), v, key);
}

Wyświetl plik

@ -2056,3 +2056,29 @@ size_t findBytes(vector<uchar> &v, uchar a, uchar b, uchar c)
}
return (size_t)-1;
}
string reverseBCD(string v)
{
int vlen = v.length();
if (vlen % 2 != 0)
{
return "BADHEX:"+v;
}
string n = "";
for (int i=0; i<vlen; i+=2)
{
n += v[vlen-2-i];
n += v[vlen-1-i];
}
return n;
}
string reverseBinaryAsciiSafeToString(string v)
{
vector<uchar> bytes;
bool ok = hex2bin(v, &bytes);
if (!ok) return "BADHEX:"+v;
reverse(bytes.begin(), bytes.end());
return safeString(bytes);
}

Wyświetl plik

@ -39,6 +39,10 @@ typedef unsigned char uchar;
uchar bcd2bin(uchar c);
uchar revbcd2bin(uchar c);
uchar reverse(uchar c);
// A BCD string 102030405060 is reversed to 605040302010
std::string reverseBCD(std::string v);
// A hex string encoding ascii chars is reversed and safely translated into a readble string.
std::string reverseBinaryAsciiSafeToString(std::string v);
bool isHexChar(uchar c);

Wyświetl plik

@ -81,6 +81,7 @@ then
TESTRESULT="OK"
else
TESTRESULT="ERROR"
exit 1
fi
else
echo "wmbusmeters returned error code: $?"
@ -100,6 +101,7 @@ then
TESTRESULT="OK"
else
TESTRESULT="ERROR"
exit 1
fi
else
echo "wmbusmeters returned error code: $?"