kopia lustrzana https://github.com/weetmuts/wmbusmeters
Change nan:s to null:s in fields. Fix problem with irrelevant fields listed for --listfields for some meters. Refactor unismart driver.
rodzic
b999952fb5
commit
5675716286
12
CHANGES
12
CHANGES
|
@ -1,3 +1,15 @@
|
|||
ATTENTION! When values are missing in the fields output, they were previously
|
||||
reported as "nan" but they are now reported as "null".
|
||||
|
||||
ATTENTION! The unismart driver has been refactored to the new driver format.
|
||||
Several fields were unknown before and are still unknown and their content
|
||||
have slightly changed: status and version.
|
||||
|
||||
The field "other_counter" is replaced with just "other" and its content changed.
|
||||
The field "suppler_info" is replaced with "supplier_info".
|
||||
The field "device_date_time" is replaced with "device_timestamp" and now contains seconds
|
||||
and a timezone.
|
||||
|
||||
ATTENTION! A bug was fixed where the on_time_h and operating_time_h
|
||||
(and related error times) were wrong.
|
||||
|
||||
|
|
|
@ -29,14 +29,14 @@ telegram=|1844AE4C4455223368077A55000000_041389E20100023B0000|
|
|||
# Test amiplus/apator electricity meter
|
||||
|
||||
telegram=|4E4401061010101002027A00004005_2F2F0E035040691500000B2B300300066D00790C7423400C78371204860BABC8FC100000000E833C8074000000000BAB3C0000000AFDC9FC0136022F2F2F2F2F|
|
||||
{"media":"electricity","meter":"amiplus","name":"MyElectricity1","id":"10101010","total_energy_consumption_kwh":15694.05,"current_power_consumption_kw":0.33,"total_energy_production_kwh":7.48,"current_power_production_kw":0,"voltage_at_phase_1_v":236,"voltage_at_phase_2_v":null,"voltage_at_phase_3_v":null,"device_date_time":"2019-03-20 12:57","total_energy_consumption_tariff_1_kwh":null,"total_energy_consumption_tariff_2_kwh":null,"total_energy_consumption_tariff_3_kwh":null,"total_energy_production_tariff_1_kwh":null,"total_energy_production_tariff_2_kwh":null,"total_energy_production_tariff_3_kwh":null,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|MyElectricity1;10101010;15694.050000;0.330000;7.480000;0.000000;236.000000;nan;nan;nan;nan;nan;nan;nan;nan;1111-11-11 11:11.11
|
||||
{"media":"electricity","meter":"amiplus","name":"MyElectricity1","id":"10101010","total_energy_consumption_kwh":15694.05,"current_power_consumption_kw":0.33,"total_energy_production_kwh":7.48,"current_power_production_kw":0,"voltage_at_phase_1_v":236,"voltage_at_phase_2_v":null,"voltage_at_phase_3_v":null,"device_date_time":"2019-03-20 12:57:00","total_energy_consumption_tariff_1_kwh":null,"total_energy_consumption_tariff_2_kwh":null,"total_energy_consumption_tariff_3_kwh":null,"total_energy_production_tariff_1_kwh":null,"total_energy_production_tariff_2_kwh":null,"total_energy_production_tariff_3_kwh":null,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|MyElectricity1;10101010;15694.05;0.33;7.48;0;236;null;null;null;null;null;null;null;null;1111-11-11 11:11.11
|
||||
|
||||
# Test amiplus/apator electricity meter with three phase voltages
|
||||
|
||||
telegram=|5E44B6105843250000027A2A005005_2F2F0C7835221400066D404708AC2A400E032022650900000E833C0000000000001B2B9647000B2B5510000BAB3C0000000AFDC9FC0135020AFDC9FC0245020AFDC9FC0339020BABC8FC100000002F2F|
|
||||
{"media":"electricity","meter":"amiplus","name":"MyElectricity2","id":"00254358","total_energy_consumption_kwh":9652.22,"current_power_consumption_kw":1.055,"total_energy_production_kwh":0,"current_power_production_kw":0,"voltage_at_phase_1_v":235,"voltage_at_phase_2_v":245,"voltage_at_phase_3_v":239,"device_date_time":"2021-10-12 08:07","total_energy_consumption_tariff_1_kwh":null,"total_energy_consumption_tariff_2_kwh":null,"total_energy_consumption_tariff_3_kwh":null,"total_energy_production_tariff_1_kwh":null,"total_energy_production_tariff_2_kwh":null,"total_energy_production_tariff_3_kwh":null,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|MyElectricity2;00254358;9652.220000;1.055000;0.000000;0.000000;235.000000;245.000000;239.000000;nan;nan;nan;nan;nan;nan;1111-11-11 11:11.11
|
||||
{"media":"electricity","meter":"amiplus","name":"MyElectricity2","id":"00254358","total_energy_consumption_kwh":9652.22,"current_power_consumption_kw":1.055,"total_energy_production_kwh":0,"current_power_production_kw":0,"voltage_at_phase_1_v":235,"voltage_at_phase_2_v":245,"voltage_at_phase_3_v":239,"device_date_time":"2021-10-12 08:07:00","total_energy_consumption_tariff_1_kwh":null,"total_energy_consumption_tariff_2_kwh":null,"total_energy_consumption_tariff_3_kwh":null,"total_energy_production_tariff_1_kwh":null,"total_energy_production_tariff_2_kwh":null,"total_energy_production_tariff_3_kwh":null,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|MyElectricity2;00254358;9652.22;1.055;0;0;235;245;239;null;null;null;null;null;null;1111-11-11 11:11.11
|
||||
|
||||
|
||||
# Test MKRadio3 T1 telegrams
|
||||
|
@ -294,8 +294,8 @@ telegram=76442104710007612507727100076121042507B5006005E2E95A3C2A1279A5415E67326
|
|||
|
||||
# Test Unismart Gas Meter
|
||||
telegram=|6044B8059430040001037A1D005085E2B670BCF1A5C87E0C1A51DA18924EF984613DA2A9CD39D8F4C7208326C76D42DBEADF80D574192B71BD7C4F56A7F1513151768A9DB804883B28CB085CA2D0F7438C361CB9E2734712ED9BFBB2A14EF55208|
|
||||
{"media":"gas","meter":"unismart","name":"GasMeter","id":"00043094","fabrication_no":"3162296","total_date_time":"2021-09-15 13:18","total_m3":917,"target_date_time":"2021-09-01 06:00","target_m3":911.32,"version":"UGG4","device_date_time":"2021-09-15 13:18","suppler_info":"00","status":"F00C","parameter_set":"02","other_counter":20,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|GasMeter;00043094;917.000000;911.320000;1111-11-11 11:11.11
|
||||
{"media":"gas","meter":"unismart","name":"GasMeter","id":"00043094","fabrication_no":"03162296","status":"STATUS_FLAGS_CF0","other":"OTHER_FLAGS_14","total_date_time":"2021-09-15 13:18","total_m3":917,"target_date_time":"2021-09-01 06:00","target_m3":911.32,"version":" 4GGU","supplier_info":"00","parameter_set":"02","meter_timestamp":"2021-09-15 13:18:30","timestamp":"1111-11-11T11:11:11Z"}
|
||||
|GasMeter;00043094;917;911.32;1111-11-11 11:11.11
|
||||
|
||||
# Test Hydrocal M3 heat/cooling meter
|
||||
telegram=|8E44B409747372710B0D7A798080052F2F_0C0E59600100046D1D36B9290C13679947000C0E000000000C13590000000C13000000000C13000000000A5A18020A5E11020F823D06003D06003D06003D0600140600620500480400E402001601000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002F2F|
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace
|
|||
static bool ok = registerDriver([](DriverInfo&di)
|
||||
{
|
||||
di.setName("amiplus");
|
||||
di.setDefaultFields("name,id,total_energy_consumption_kwh,current_power_consumption_kw,total_energy_production_kwh,current_power_production_kw,voltage_at_phase_1_v,voltage_at_phase_2_v,voltage_at_phase_3_v,total_energy_consumption_tariff_1_kwh,total_energy_consumption_tariff_2_kwh,total_energy_consumption_tariff_3_kwh,total_energy_production_tariff_1_kwh,total_energy_production_tariff_2_kwh,total_energy_production_tariff_3_kwh,timestamp");
|
||||
di.setMeterType(MeterType::ElectricityMeter);
|
||||
di.addLinkMode(LinkMode::T1);
|
||||
di.addDetection(MANUFACTURER_APA, 0x02, 0x02);
|
||||
|
@ -188,19 +189,19 @@ namespace
|
|||
|
||||
// Test: MyElectricity1 amiplus 10101010 NOKEY
|
||||
// telegram=|4E4401061010101002027A00004005_2F2F0E035040691500000B2B300300066D00790C7423400C78371204860BABC8FC100000000E833C8074000000000BAB3C0000000AFDC9FC0136022F2F2F2F2F|
|
||||
// {"media":"electricity","meter":"amiplus","name":"MyElectricity1","id":"10101010","total_energy_consumption_kwh":15694.05,"current_power_consumption_kw":0.33,"total_energy_production_kwh":7.48,"current_power_production_kw":0,"voltage_at_phase_1_v":236,"voltage_at_phase_2_v":null,"voltage_at_phase_3_v":null,"device_date_time":"2019-03-20 12:57","total_energy_consumption_tariff_1_kwh":null,"total_energy_consumption_tariff_2_kwh":null,"total_energy_consumption_tariff_3_kwh":null,"total_energy_production_tariff_1_kwh":null,"total_energy_production_tariff_2_kwh":null,"total_energy_production_tariff_3_kwh":null,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |MyElectricity1;10101010;15694.050000;0.330000;7.480000;0.000000;236.000000;nan;nan;nan;nan;nan;nan;nan;nan;1111-11-11 11:11.11
|
||||
// {"media":"electricity","meter":"amiplus","name":"MyElectricity1","id":"10101010","total_energy_consumption_kwh":15694.05,"current_power_consumption_kw":0.33,"total_energy_production_kwh":7.48,"current_power_production_kw":0,"voltage_at_phase_1_v":236,"voltage_at_phase_2_v":null,"voltage_at_phase_3_v":null,"device_date_time":"2019-03-20 12:57:00","total_energy_consumption_tariff_1_kwh":null,"total_energy_consumption_tariff_2_kwh":null,"total_energy_consumption_tariff_3_kwh":null,"total_energy_production_tariff_1_kwh":null,"total_energy_production_tariff_2_kwh":null,"total_energy_production_tariff_3_kwh":null,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |MyElectricity1;10101010;15694.05;0.33;7.48;0;236;null;null;null;null;null;null;null;null;1111-11-11 11:11.11
|
||||
|
||||
// Test: MyElectricity2 amiplus 00254358 NOKEY
|
||||
// amiplus/apator electricity meter with three phase voltages
|
||||
|
||||
// telegram=|5E44B6105843250000027A2A005005_2F2F0C7835221400066D404708AC2A400E032022650900000E833C0000000000001B2B9647000B2B5510000BAB3C0000000AFDC9FC0135020AFDC9FC0245020AFDC9FC0339020BABC8FC100000002F2F|
|
||||
// {"media":"electricity","meter":"amiplus","name":"MyElectricity2","id":"00254358","total_energy_consumption_kwh":9652.22,"current_power_consumption_kw":1.055,"total_energy_production_kwh":0,"current_power_production_kw":0,"voltage_at_phase_1_v":235,"voltage_at_phase_2_v":245,"voltage_at_phase_3_v":239,"device_date_time":"2021-10-12 08:07","total_energy_consumption_tariff_1_kwh":null,"total_energy_consumption_tariff_2_kwh":null,"total_energy_consumption_tariff_3_kwh":null,"total_energy_production_tariff_1_kwh":null,"total_energy_production_tariff_2_kwh":null,"total_energy_production_tariff_3_kwh":null,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |MyElectricity2;00254358;9652.220000;1.055000;0.000000;0.000000;235.000000;245.000000;239.000000;nan;nan;nan;nan;nan;nan;1111-11-11 11:11.11
|
||||
// {"media":"electricity","meter":"amiplus","name":"MyElectricity2","id":"00254358","total_energy_consumption_kwh":9652.22,"current_power_consumption_kw":1.055,"total_energy_production_kwh":0,"current_power_production_kw":0,"voltage_at_phase_1_v":235,"voltage_at_phase_2_v":245,"voltage_at_phase_3_v":239,"device_date_time":"2021-10-12 08:07:00","total_energy_consumption_tariff_1_kwh":null,"total_energy_consumption_tariff_2_kwh":null,"total_energy_consumption_tariff_3_kwh":null,"total_energy_production_tariff_1_kwh":null,"total_energy_production_tariff_2_kwh":null,"total_energy_production_tariff_3_kwh":null,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |MyElectricity2;00254358;9652.22;1.055;0;0;235;245;239;null;null;null;null;null;null;1111-11-11 11:11.11
|
||||
|
||||
// Test: MyElectricity3 amiplus 86064864 NOKEY
|
||||
// amiplus/apator electricity meter with three phase voltages and 2 tariffs
|
||||
|
||||
// telegram=|804401066448068602027A000070052F2F_066D1E5C11DA21400C78644806868E10036110012500008E20038106531800008E10833C9949000000008E20833C8606000000001B2B5228020B2B3217000BAB3C0000000AFDC9FC0131020AFDC9FC0225020AFDC9FC0331020BABC8FC100000002F2F2F2F2F2F2F2F2F2F2F2F2FDE47|
|
||||
// {"media":"electricity","meter":"amiplus","name":"MyElectricity3","id":"86064864","total_energy_consumption_kwh":null,"current_power_consumption_kw":1.732,"total_energy_production_kwh":null,"current_power_production_kw":0,"voltage_at_phase_1_v":231,"voltage_at_phase_2_v":225,"voltage_at_phase_3_v":231,"device_date_time":"2022-01-26 17:28","total_energy_consumption_tariff_1_kwh":25011.061,"total_energy_consumption_tariff_2_kwh":18530.681,"total_energy_consumption_tariff_3_kwh":null,"total_energy_production_tariff_1_kwh":4.999,"total_energy_production_tariff_2_kwh":0.686,"total_energy_production_tariff_3_kwh":null,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |MyElectricity3;86064864;nan;1.732000;nan;0.000000;231.000000;225.000000;231.000000;25011.061000;18530.681000;nan;4.999000;0.686000;nan;1111-11-11 11:11.11
|
||||
// {"media":"electricity","meter":"amiplus","name":"MyElectricity3","id":"86064864","total_energy_consumption_kwh":null,"current_power_consumption_kw":1.732,"total_energy_production_kwh":null,"current_power_production_kw":0,"voltage_at_phase_1_v":231,"voltage_at_phase_2_v":225,"voltage_at_phase_3_v":231,"device_date_time":"2022-01-26 17:28:30","total_energy_consumption_tariff_1_kwh":25011.061,"total_energy_consumption_tariff_2_kwh":18530.681,"total_energy_consumption_tariff_3_kwh":null,"total_energy_production_tariff_1_kwh":4.999,"total_energy_production_tariff_2_kwh":0.686,"total_energy_production_tariff_3_kwh":null,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |MyElectricity3;86064864;null;1.732;null;0;231;225;231;25011.061;18530.681;null;4.999;0.686;null;1111-11-11 11:11.11
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields();
|
||||
addOptionalCommonFields("software_version");
|
||||
|
||||
addStringField(
|
||||
"status",
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace
|
|||
PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT |
|
||||
PrintProperty::STATUS | PrintProperty::JOIN_TPL_STATUS);
|
||||
|
||||
addOptionalCommonFields();
|
||||
addOptionalCommonFields("on_time_h");
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"total_energy_consumption",
|
||||
|
|
|
@ -237,7 +237,7 @@ namespace
|
|||
.set(StorageNr(1))
|
||||
);
|
||||
|
||||
addOptionalCommonFields();
|
||||
addOptionalCommonFields("operating_time_h,on_time_h,meter_datetime");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields();
|
||||
addOptionalCommonFields("fabrication_no,enhanced_id,location");
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"location_hex",
|
||||
|
|
|
@ -43,8 +43,8 @@ namespace
|
|||
|
||||
addLinkMode(LinkMode::T1);
|
||||
|
||||
addOptionalCommonFields();
|
||||
addOptionalFlowRelatedFields();
|
||||
addOptionalCommonFields("enhanced_id,meter_datetime");
|
||||
addOptionalFlowRelatedFields("total_m3,total_backward_m3,volume_flow_m3h");
|
||||
|
||||
addStringFieldWithExtractorAndLookup(
|
||||
"status",
|
||||
|
@ -136,10 +136,10 @@ namespace
|
|||
// 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","enhanced_id":"002108728367","meter_datetime":"2022-01-21 01:26","total_m3":4.605,"status":"OK","target_m3":3.888,"target_date":"2021-12-31","unknown_a":"WOOTA_C060000","unknown_b":"WOOTB_2A86","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// {"media":"water","meter":"itron","name":"SomeWater","id":"12345698","enhanced_id":"002108728367","meter_datetime":"2022-01-21 01:26:44","total_m3":4.605,"status":"OK","target_m3":3.888,"target_date":"2021-12-31","unknown_a":"WOOTA_C060000","unknown_b":"WOOTB_2A86","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |SomeWater;12345698;4.605;3.888;1111-11-11 11:11.11
|
||||
|
||||
// Test: MoreWater itron 18000056 NOKEY
|
||||
// telegram=|46449726560000183307725600001897263307AF0030052F2F_066D0E1015C82A000C13771252000C933C000000000B3B0400004C1361045200426CC12A03FD971C0000002F2F2F|
|
||||
// {"media":"water","meter":"itron","name":"MoreWater","id":"18000056","meter_datetime":"2022-10-08 21:16","total_m3":521.277,"total_backward_m3":0,"volume_flow_m3h":0.004,"status":"OK","target_m3":520.461,"target_date":"2022-10-01","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// {"media":"water","meter":"itron","name":"MoreWater","id":"18000056","meter_datetime":"2022-10-08 21:16:14","total_m3":521.277,"total_backward_m3":0,"volume_flow_m3h":0.004,"status":"OK","target_m3":520.461,"target_date":"2022-10-01","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |MoreWater;18000056;521.277;520.461;1111-11-11 11:11.11
|
||||
|
|
|
@ -37,8 +37,8 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields();
|
||||
addOptionalFlowRelatedFields();
|
||||
addOptionalCommonFields("meter_date,fabrication_no,operating_time_h,on_time_h,on_time_at_error_h,meter_datetime");
|
||||
addOptionalFlowRelatedFields("total_m3,total_backward_m3,volume_flow_m3h");
|
||||
|
||||
/* If the meter is recently commissioned, the target water consumption value is bogus.
|
||||
The bits store 0xffffffff. Should we deal with this? Now a very large value is printed in the json.
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields();
|
||||
addOptionalCommonFields("on_time_h");
|
||||
|
||||
// Technical Description Multical 603 page 116 section 7.7.2 Information code types on serial communication.
|
||||
addStringFieldWithExtractorAndLookup(
|
||||
|
|
|
@ -36,8 +36,6 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields();
|
||||
|
||||
addStringFieldWithExtractorAndLookup(
|
||||
"status",
|
||||
"Meter status. Reports OK if neither tpl sts nor error flags have bits set.",
|
||||
|
@ -59,11 +57,6 @@ namespace
|
|||
},
|
||||
}));
|
||||
|
||||
/*
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ErrorFlags)
|
||||
.add(VIFCombinable::StandardConformantDataContent)
|
||||
*/
|
||||
addNumericFieldWithExtractor(
|
||||
"current_temperature",
|
||||
"The current temperature.",
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields();
|
||||
addOptionalCommonFields("fabrication_no,software_version");
|
||||
|
||||
addStringField(
|
||||
"status",
|
||||
|
|
|
@ -36,8 +36,8 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields();
|
||||
addOptionalFlowRelatedFields();
|
||||
addOptionalCommonFields("meter_datetime");
|
||||
addOptionalFlowRelatedFields("total_m3,total_forward_m3,total_backward_m3,flow_temperature_c,volume_flow_m3h");
|
||||
|
||||
addStringField(
|
||||
"status",
|
||||
|
|
|
@ -35,8 +35,8 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields();
|
||||
addOptionalFlowRelatedFields();
|
||||
addOptionalCommonFields("fabrication_no,operating_time_h,on_time_h,meter_datetime,meter_datetime_at_error");
|
||||
addOptionalFlowRelatedFields("total_m3,flow_temperature_c,return_temperature_c,flow_return_temperature_difference_c,volume_flow_m3h");
|
||||
|
||||
addStringFieldWithExtractorAndLookup(
|
||||
"status",
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
Copyright (C) 2021-2022 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include"meters_common_implementation.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Driver : public virtual MeterCommonImplementation
|
||||
{
|
||||
Driver(MeterInfo &mi, DriverInfo &di);
|
||||
};
|
||||
|
||||
static bool ok = registerDriver([](DriverInfo&di)
|
||||
{
|
||||
di.setName("unismart");
|
||||
di.setDefaultFields("name,id,total_m3,target_m3,timestamp");
|
||||
di.setMeterType(MeterType::GasMeter);
|
||||
di.addLinkMode(LinkMode::T1);
|
||||
di.addDetection(MANUFACTURER_AMX, 0x03, 0x01);
|
||||
|
||||
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
|
||||
});
|
||||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields("fabrication_no");
|
||||
|
||||
addStringFieldWithExtractorAndLookup(
|
||||
"status",
|
||||
"Status of meter?",
|
||||
PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT | PrintProperty::STATUS,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("02FD74")),
|
||||
{
|
||||
{
|
||||
{
|
||||
"STATUS_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
0xffff,
|
||||
"OK",
|
||||
{
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
addStringFieldWithExtractorAndLookup(
|
||||
"other",
|
||||
"Other status of meter?",
|
||||
PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT | PrintProperty::STATUS,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("017F")),
|
||||
{
|
||||
{
|
||||
{
|
||||
"OTHER_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
0xff,
|
||||
"",
|
||||
{
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"total_date_time",
|
||||
"Timestamp for this total measurement.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime)
|
||||
.set(IndexNr(1))
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"total",
|
||||
"The total gas consumption recorded by this meter.",
|
||||
PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
.add(VIFCombinable::UncorrectedMeterUnit)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"target_date_time",
|
||||
"Timestamp for gas consumption recorded at the beginning of this month.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime)
|
||||
.set(StorageNr(1))
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"target",
|
||||
"The total gas consumption recorded by this meter at the beginning of this month.",
|
||||
PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
.set(StorageNr(1))
|
||||
.add(VIFCombinable::UncorrectedMeterUnit)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"version",
|
||||
"Model version.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ModelVersion)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"supplier_info",
|
||||
"Supplier info?",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::SpecialSupplierInformation)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"parameter_set",
|
||||
"Meter configued with this parameter set?",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ParameterSet)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"meter_timestamp",
|
||||
"Timestamp when this measurement was sent.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime)
|
||||
.set(IndexNr(2))
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Test: GasMeter unismart 00043094 00000000000000000000000000000000
|
||||
// telegram=|6044B8059430040001037A1D005085E2B670BCF1A5C87E0C1A51DA18924EF984613DA2A9CD39D8F4C7208326C76D42DBEADF80D574192B71BD7C4F56A7F1513151768A9DB804883B28CB085CA2D0F7438C361CB9E2734712ED9BFBB2A14EF55208|
|
||||
// {"media":"gas","meter":"unismart","name":"GasMeter","id":"00043094","fabrication_no":"03162296","status":"STATUS_FLAGS_CF0","other":"OTHER_FLAGS_14","total_date_time":"2021-09-15 13:18","total_m3":917,"target_date_time":"2021-09-01 06:00","target_m3":911.32,"version":" 4GGU","supplier_info":"00","parameter_set":"02","meter_timestamp":"2021-09-15 13:18:30","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |GasMeter;00043094;917;911.32;1111-11-11 11:11.11
|
|
@ -1168,7 +1168,10 @@ bool DVEntry::extractDate(struct tm *out)
|
|||
// ..ss ssss
|
||||
int sec = (0x3f) & v[0];
|
||||
out->tm_sec = sec;
|
||||
// some daylight saving time decoding needed here....
|
||||
// There are also bits for day of week, week of year.
|
||||
// A bit for if daylight saving is in use or not and its offset.
|
||||
// A bit if it is a leap year.
|
||||
// I am unsure how to deal with this here..... TODO
|
||||
}
|
||||
|
||||
return ok;
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
X(Current,0x7D50,0x7D5F, Quantity::Current, Unit::Ampere) \
|
||||
X(ResetCounter,0x7D60,0x7D60, Quantity::Counter, Unit::COUNTER) \
|
||||
X(CumulationCounter,0x7D61,0x7D61, Quantity::Counter, Unit::COUNTER) \
|
||||
X(SpecialSupplierInformation,0x7D67,0x7D67, Quantity::Text, Unit::TXT) \
|
||||
X(RemainingBattery,0x7D74,0x7D74, Quantity::Time, Unit::Day) \
|
||||
X(DurationSinceReadout,0x7DAC,0x7DAC, Quantity::Time, Unit::Hour) \
|
||||
X(AnyVolumeVIF,0x00,0x00, Quantity::Volume, Unit::Unknown) \
|
||||
|
@ -280,6 +281,7 @@ struct IndexNr
|
|||
IndexNr(int n) : nr_(n) {}
|
||||
int intValue() { return nr_; }
|
||||
bool operator==(IndexNr s) { return nr_ == s.nr_; }
|
||||
bool operator!=(IndexNr s) { return nr_ != s.nr_; }
|
||||
|
||||
private:
|
||||
int nr_;
|
||||
|
@ -381,8 +383,9 @@ struct FieldMatcher
|
|||
SubUnitNr subunit_nr_from { 0 };
|
||||
SubUnitNr subunit_nr_to { 0 };
|
||||
|
||||
// If the telegram has multiple identical difvif entries, use entry with this index nr.
|
||||
// First entry has nr 1, which is the default value.
|
||||
// If the telegram has multiple identical difvif entries matching this field
|
||||
// and you want to catch the second matching entry, then set the index nr to 2.
|
||||
// The default is 1.
|
||||
IndexNr index_nr { 1 };
|
||||
|
||||
FieldMatcher() : active(false) { }
|
||||
|
|
|
@ -75,7 +75,6 @@
|
|||
X(SONTEX868, MANUFACTURER_SON, 0x08, 0x16) \
|
||||
X(TOPASESKR, MANUFACTURER_AMT, 0x06, 0xf1) \
|
||||
X(TOPASESKR, MANUFACTURER_AMT, 0x07, 0xf1) \
|
||||
X(UNISMART, MANUFACTURER_AMX, 0x03, 0x01) \
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,272 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2021 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include"dvparser.h"
|
||||
#include"meters.h"
|
||||
#include"meters_common_implementation.h"
|
||||
#include"wmbus.h"
|
||||
#include"wmbus_utils.h"
|
||||
#include"util.h"
|
||||
|
||||
#include<algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct MeterUnismart : public virtual MeterCommonImplementation {
|
||||
MeterUnismart(MeterInfo &mi);
|
||||
|
||||
// Total gas counted through the meter
|
||||
double totalGasConsumption(Unit u);
|
||||
bool hasTotalGasConsumption();
|
||||
// Consumption at the beginning of this month.
|
||||
double targetGasConsumption(Unit u);
|
||||
|
||||
private:
|
||||
void processContent(Telegram *t);
|
||||
|
||||
string fabrication_no_;
|
||||
string total_date_time_;
|
||||
double total_gas_consumption_m3_ {};
|
||||
string target_date_time_;
|
||||
double target_gas_consumption_m3_ {};
|
||||
string version_;
|
||||
string device_date_time_;
|
||||
|
||||
string supplier_info_;
|
||||
string status_;
|
||||
string parameter_set_;
|
||||
uint8_t other_;
|
||||
};
|
||||
|
||||
shared_ptr<Meter> createUnismart(MeterInfo &mi)
|
||||
{
|
||||
return shared_ptr<Meter>(new MeterUnismart(mi));
|
||||
}
|
||||
|
||||
MeterUnismart::MeterUnismart(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, "unismart")
|
||||
{
|
||||
setMeterType(MeterType::GasMeter);
|
||||
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
addLinkMode(LinkMode::T1);
|
||||
|
||||
addPrint("fabrication_no", Quantity::Text,
|
||||
[&](){ return fabrication_no_; },
|
||||
"Static fabrication no information.",
|
||||
PrintProperty::JSON);
|
||||
|
||||
addPrint("total_date_time", Quantity::Text,
|
||||
[&](){ return total_date_time_; },
|
||||
"Timestamp for this total measurement.",
|
||||
PrintProperty::JSON);
|
||||
|
||||
addPrint("total", Quantity::Volume,
|
||||
[&](Unit u){ return totalGasConsumption(u); },
|
||||
"The total gas consumption recorded by this meter.",
|
||||
PrintProperty::FIELD | PrintProperty::JSON);
|
||||
|
||||
addPrint("target_date_time", Quantity::Text,
|
||||
[&](){ return target_date_time_; },
|
||||
"Timestamp for gas consumption recorded at the beginning of this month.",
|
||||
PrintProperty::JSON);
|
||||
|
||||
addPrint("target", Quantity::Volume,
|
||||
[&](Unit u){ return targetGasConsumption(u); },
|
||||
"The total gas consumption recorded by this meter at the beginning of this month.",
|
||||
PrintProperty::FIELD | PrintProperty::JSON);
|
||||
|
||||
addPrint("version", Quantity::Text,
|
||||
[&](){ return version_; },
|
||||
"Model/version a reported by meter.",
|
||||
PrintProperty::JSON);
|
||||
|
||||
addPrint("device_date_time", Quantity::Text,
|
||||
[&](){ return device_date_time_; },
|
||||
"Device date time? Seems to be the same as total date time.",
|
||||
PrintProperty::JSON);
|
||||
|
||||
addPrint("suppler_info", Quantity::Text,
|
||||
[&](){ return supplier_info_; },
|
||||
"?",
|
||||
PrintProperty::JSON);
|
||||
|
||||
addPrint("status", Quantity::Text,
|
||||
[&](){ return status_; },
|
||||
"?",
|
||||
PrintProperty::JSON);
|
||||
|
||||
addPrint("parameter_set", Quantity::Text,
|
||||
[&](){ return parameter_set_; },
|
||||
"?",
|
||||
PrintProperty::JSON);
|
||||
|
||||
addPrint("other", Quantity::Counter,
|
||||
[&](Unit u){ return other_; },
|
||||
"?",
|
||||
PrintProperty::JSON);
|
||||
|
||||
}
|
||||
|
||||
void MeterUnismart::processContent(Telegram *t)
|
||||
{
|
||||
/*
|
||||
(unismart) 11: 0C dif (8 digit BCD Instantaneous value)
|
||||
(unismart) 12: 78 vif (Fabrication no)
|
||||
(unismart) 13: 96221603
|
||||
(unismart) 17: 04 dif (32 Bit Integer/Binary Instantaneous value)
|
||||
(unismart) 18: 6D vif (Date and time type)
|
||||
(unismart) 19: 122DAF29
|
||||
(unismart) 1d: 0C dif (8 digit BCD Instantaneous value)
|
||||
(unismart) 1e: 94 vif (Volume 10⁻² m³)
|
||||
(unismart) 1f: 3A vife (uncorrected meter unit)
|
||||
(unismart) 20: * 00170900 total consumption (917.000000 m3)
|
||||
(unismart) 24: 44 dif (32 Bit Integer/Binary Instantaneous value storagenr=1)
|
||||
(unismart) 25: 6D vif (Date and time type)
|
||||
(unismart) 26: 0026A129
|
||||
(unismart) 2a: 4C dif (8 digit BCD Instantaneous value storagenr=1)
|
||||
(unismart) 2b: 94 vif (Volume 10⁻² m³)
|
||||
(unismart) 2c: 3A vife (uncorrected meter unit)
|
||||
(unismart) 2d: 32110900
|
||||
(unismart) 31: 01 dif (8 Bit Integer/Binary Instantaneous value)
|
||||
(unismart) 32: FD vif (Second extension FD of VIF-codes)
|
||||
(unismart) 33: 67 vife (Special supplier information)
|
||||
(unismart) 34: 00
|
||||
(unismart) 35: 02 dif (16 Bit Integer/Binary Instantaneous value)
|
||||
(unismart) 36: FD vif (Second extension FD of VIF-codes)
|
||||
(unismart) 37: 74 vife (Reserved)
|
||||
(unismart) 38: F00C
|
||||
(unismart) 3a: 0D dif (variable length Instantaneous value)
|
||||
(unismart) 3b: FD vif (Second extension FD of VIF-codes)
|
||||
(unismart) 3c: 0C vife (Model/Version)
|
||||
(unismart) 3d: 06 varlen=6
|
||||
(unismart) 3e: 554747342020
|
||||
(unismart) 44: 01 dif (8 Bit Integer/Binary Instantaneous value)
|
||||
(unismart) 45: FD vif (Second extension FD of VIF-codes)
|
||||
(unismart) 46: 0B vife (Parameter set identification)
|
||||
(unismart) 47: 02
|
||||
(unismart) 48: 01 dif (8 Bit Integer/Binary Instantaneous value)
|
||||
(unismart) 49: 7F vif (Manufacturer specific)
|
||||
(unismart) 4a: 14
|
||||
(unismart) 4b: 06 dif (48 Bit Integer/Binary Instantaneous value)
|
||||
(unismart) 4c: 6D vif (Date and time type)
|
||||
(unismart) 4d: 1E120DAF296D
|
||||
(unismart) 53: 2F skip
|
||||
(unismart) 54: 2F skip
|
||||
(unismart) 55: 2F skip
|
||||
(unismart) 56: 2F skip
|
||||
(unismart) 57: 2F skip
|
||||
(unismart) 58: 2F skip
|
||||
(unismart) 59: 2F skip
|
||||
(unismart) 5a: 2F skip
|
||||
(unismart) 5b: 2F skip
|
||||
(unismart) 5c: 2F skip
|
||||
(unismart) 5d: 2F skip
|
||||
(unismart) 5e: 2F skip
|
||||
|
||||
*/
|
||||
int offset;
|
||||
string key;
|
||||
|
||||
uint64_t v {};
|
||||
if (extractDVlong(&t->dv_entries, "0C78", &offset, &v))
|
||||
{
|
||||
fabrication_no_ = to_string(v);
|
||||
t->addMoreExplanation(offset, " fabrication no (%zu)", v);
|
||||
}
|
||||
|
||||
if (findKey(MeasurementType::Instantaneous, VIFRange::DateTime, 0, 0, &key, &t->dv_entries)) {
|
||||
struct tm datetime;
|
||||
extractDVdate(&t->dv_entries, key, &offset, &datetime);
|
||||
total_date_time_ = strdatetime(&datetime);
|
||||
t->addMoreExplanation(offset, " total datetime (%s)", total_date_time_.c_str());
|
||||
}
|
||||
|
||||
if (findKey(MeasurementType::Instantaneous, VIFRange::Volume, 0, 0, &key, &t->dv_entries))
|
||||
{
|
||||
extractDVdouble(&t->dv_entries, key, &offset, &total_gas_consumption_m3_);
|
||||
t->addMoreExplanation(offset, " total consumption (%f m3)", total_gas_consumption_m3_);
|
||||
}
|
||||
|
||||
if (findKey(MeasurementType::Instantaneous, VIFRange::DateTime, 1, 0, &key, &t->dv_entries)) {
|
||||
struct tm datetime;
|
||||
extractDVdate(&t->dv_entries, key, &offset, &datetime);
|
||||
target_date_time_ = strdatetime(&datetime);
|
||||
t->addMoreExplanation(offset, " target datetime (%s)", target_date_time_.c_str());
|
||||
}
|
||||
|
||||
if (findKey(MeasurementType::Instantaneous, VIFRange::Volume, 1, 0, &key, &t->dv_entries))
|
||||
{
|
||||
extractDVdouble(&t->dv_entries, key, &offset, &target_gas_consumption_m3_);
|
||||
t->addMoreExplanation(offset, " target consumption (%f m3)", target_gas_consumption_m3_);
|
||||
}
|
||||
|
||||
string tmp;
|
||||
if (extractDVHexString(&t->dv_entries, "0DFD0C", &offset, &tmp))
|
||||
{
|
||||
vector<uchar> bin;
|
||||
hex2bin(tmp, &bin);
|
||||
version_ = safeString(bin);
|
||||
trimWhitespace(&version_);
|
||||
t->addMoreExplanation(offset, " version (%s)", version_.c_str());
|
||||
}
|
||||
|
||||
struct tm datetime;
|
||||
if (extractDVdate(&t->dv_entries, "066D", &offset, &datetime))
|
||||
{
|
||||
device_date_time_ = strdatetime(&datetime);
|
||||
t->addMoreExplanation(offset, " device datetime (%s)", device_date_time_.c_str());
|
||||
}
|
||||
|
||||
if (extractDVHexString(&t->dv_entries, "01FD67", &offset, &supplier_info_))
|
||||
{
|
||||
t->addMoreExplanation(offset, " suppler info (%s)", supplier_info_.c_str());
|
||||
}
|
||||
|
||||
if (extractDVHexString(&t->dv_entries, "02FD74", &offset, &status_))
|
||||
{
|
||||
t->addMoreExplanation(offset, " status (%s)", status_.c_str());
|
||||
}
|
||||
|
||||
if (extractDVHexString(&t->dv_entries, "01FD0B", &offset, ¶meter_set_))
|
||||
{
|
||||
t->addMoreExplanation(offset, " parameter set (%s)", parameter_set_.c_str());
|
||||
}
|
||||
|
||||
if (extractDVuint8(&t->dv_entries, "017F", &offset, &other_))
|
||||
{
|
||||
t->addMoreExplanation(offset, " status2 (%d)", other_);
|
||||
}
|
||||
}
|
||||
|
||||
double MeterUnismart::totalGasConsumption(Unit u)
|
||||
{
|
||||
assertQuantity(u, Quantity::Volume);
|
||||
return convert(total_gas_consumption_m3_, Unit::M3, u);
|
||||
}
|
||||
|
||||
bool MeterUnismart::hasTotalGasConsumption()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
double MeterUnismart::targetGasConsumption(Unit u)
|
||||
{
|
||||
assertQuantity(u, Quantity::Volume);
|
||||
return convert(target_gas_consumption_m3_, Unit::M3, u);
|
||||
}
|
541
src/meters.cc
541
src/meters.cc
|
@ -1873,6 +1873,8 @@ void MeterCommonImplementation::processFieldExtractors(Telegram *t)
|
|||
{
|
||||
map<FieldInfo*,DVEntry*> found;
|
||||
|
||||
// Sort the dv_entries based on their offset in the telegram.
|
||||
// I.e. restore the ordering that was implicit in the telegram.
|
||||
vector<DVEntry*> sorted_entries;
|
||||
|
||||
for (auto &p : t->dv_entries)
|
||||
|
@ -1882,30 +1884,32 @@ void MeterCommonImplementation::processFieldExtractors(Telegram *t)
|
|||
sort(sorted_entries.begin(), sorted_entries.end(),
|
||||
[](const DVEntry* a, const DVEntry *b) -> bool { return a->offset < b->offset; });
|
||||
|
||||
// Iterate through the data content (dv_entries) in the telegram.
|
||||
for (DVEntry *dve : sorted_entries)
|
||||
// Now go through each field_info defined by the driver.
|
||||
for (FieldInfo &fi : field_infos_)
|
||||
{
|
||||
// We have telegram content, a dif-vif-value entry.
|
||||
// Now check for a field info that wants to handle this telegram content entry.
|
||||
for (FieldInfo &fi : field_infos_)
|
||||
int current_match_nr = 0;
|
||||
|
||||
// This field_info has not been matched to a dv_entry before!
|
||||
debug("(meters) trying field info %s(%s)[%d]...\n",
|
||||
fi.vname().c_str(),
|
||||
toString(fi.xuantity()),
|
||||
fi.index());
|
||||
|
||||
// Iterate through dv_entries in the telegram in the same order the telegram presented them.
|
||||
for (DVEntry *dve : sorted_entries)
|
||||
{
|
||||
if (fi.hasMatcher() && fi.matches(dve))
|
||||
{
|
||||
if (found.count(&fi) != 0)
|
||||
{
|
||||
DVEntry *old = found[&fi];
|
||||
current_match_nr++;
|
||||
|
||||
verbose("(meter) while processing field extractors ignoring dventry %s at offset %d matching since "
|
||||
"field %s was already matched against dventry %s at offset %d !\n",
|
||||
dve->dif_vif_key.str().c_str(),
|
||||
dve->offset,
|
||||
fi.vname().c_str(),
|
||||
old->dif_vif_key.str().c_str(),
|
||||
old->offset);
|
||||
}
|
||||
else
|
||||
if (fi.matcher().index_nr != IndexNr(current_match_nr))
|
||||
{
|
||||
// We have field that wants to handle this entry!
|
||||
// This field info did match, but requires another index nr!
|
||||
// Increment the current index nr and look for the next match.
|
||||
}
|
||||
else if (found.count(&fi) == 0)
|
||||
{
|
||||
// This field_info has not been matched to a dv_entry before!
|
||||
debug("(meters) using field info %s(%s)[%d] to extract %s at offset %d\n",
|
||||
fi.vname().c_str(),
|
||||
toString(fi.xuantity()),
|
||||
|
@ -1917,6 +1921,18 @@ void MeterCommonImplementation::processFieldExtractors(Telegram *t)
|
|||
fi.performExtraction(this, t, dve);
|
||||
found[&fi] = dve;
|
||||
}
|
||||
else
|
||||
{
|
||||
DVEntry *old = found[&fi];
|
||||
|
||||
verbose("(meter) while processing field extractors ignoring dventry %s at offset %d matching since "
|
||||
"field %s was already matched against dventry %s at offset %d !\n",
|
||||
dve->dif_vif_key.str().c_str(),
|
||||
dve->offset,
|
||||
fi.vname().c_str(),
|
||||
old->dif_vif_key.str().c_str(),
|
||||
old->offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2912,7 +2928,17 @@ bool FieldInfo::extractString(Meter *m, Telegram *t, DVEntry *dve)
|
|||
{
|
||||
struct tm datetime;
|
||||
dve->extractDate(&datetime);
|
||||
string extracted_device_date_time = strdatetime(&datetime);
|
||||
string extracted_device_date_time;
|
||||
|
||||
if (dve->value.size() == 12)
|
||||
{
|
||||
// A long date time sec + timezone field. TODO add timezone data.
|
||||
extracted_device_date_time = strdatetimesec(&datetime);
|
||||
}
|
||||
else
|
||||
{
|
||||
extracted_device_date_time = strdatetime(&datetime);
|
||||
}
|
||||
m->setStringValue(this, extracted_device_date_time);
|
||||
t->addMoreExplanation(dve->offset, renderJsonText(m));
|
||||
found = true;
|
||||
|
@ -2926,13 +2952,14 @@ bool FieldInfo::extractString(Meter *m, Telegram *t, DVEntry *dve)
|
|||
t->addMoreExplanation(dve->offset, renderJsonText(m));
|
||||
found = true;
|
||||
}
|
||||
else if (matcher_.vif_range == VIFRange::EnhancedIdentification ||
|
||||
else if (matcher_.vif_range == VIFRange::Any ||
|
||||
matcher_.vif_range == VIFRange::EnhancedIdentification ||
|
||||
matcher_.vif_range == VIFRange::FabricationNo ||
|
||||
matcher_.vif_range == VIFRange::ModelVersion ||
|
||||
matcher_.vif_range == VIFRange::SoftwareVersion ||
|
||||
matcher_.vif_range == VIFRange::Customer ||
|
||||
matcher_.vif_range == VIFRange::Location ||
|
||||
matcher_.vif_range == VIFRange::Any ||
|
||||
matcher_.vif_range == VIFRange::SpecialSupplierInformation ||
|
||||
matcher_.vif_range == VIFRange::ParameterSet)
|
||||
{
|
||||
string extracted_id;
|
||||
|
@ -3030,204 +3057,302 @@ bool Address::parse(string &s)
|
|||
return true;
|
||||
}
|
||||
|
||||
void MeterCommonImplementation::addOptionalCommonFields()
|
||||
bool checkIf(set<string> &fields, const char *s)
|
||||
{
|
||||
addStringFieldWithExtractor(
|
||||
"fabrication_no",
|
||||
"Fabrication number.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FabricationNo)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"enhanced_id",
|
||||
"Enhanced identification number.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::EnhancedIdentification)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"software_version",
|
||||
"Software version.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::SoftwareVersion)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"customer",
|
||||
"Customer name.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Customer)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"location",
|
||||
"Meter installed at this customer location.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Location)
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"operating_time",
|
||||
"How long the meter has been collecting data.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::OperatingTime)
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"on_time",
|
||||
"How long the meter has been powered up.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::OnTime)
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"on_time_at_error",
|
||||
"How long the meter has been in an error state while powered up.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::AtError)
|
||||
.set(VIFRange::OnTime)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"meter_date",
|
||||
"Date when the meter sent the telegram.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Date)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"meter_date_at_error",
|
||||
"Date when the meter was in error.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::AtError)
|
||||
.set(VIFRange::Date)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"meter_datetime",
|
||||
"Date and time when the meter sent the telegram.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"meter_datetime_at_error",
|
||||
"Date and time when the meter was in error.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::AtError)
|
||||
.set(VIFRange::DateTime)
|
||||
);
|
||||
if (fields.count(s) > 0)
|
||||
{
|
||||
fields.erase(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MeterCommonImplementation::addOptionalFlowRelatedFields()
|
||||
void checkFieldsEmpty(set<string> &fields, string name)
|
||||
{
|
||||
addNumericFieldWithExtractor(
|
||||
"total",
|
||||
"The total media volume consumption recorded by this meter.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
);
|
||||
if (fields.size() > 0)
|
||||
{
|
||||
string info;
|
||||
for (auto &s : fields) { info += s+" "; }
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"total_forward",
|
||||
"The total media volume flowing forward.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
.add(VIFCombinable::ForwardFlow)
|
||||
);
|
||||
warning("(meter) when adding common fields to driver %s, these fields were not found: %s\n",
|
||||
name.c_str(),
|
||||
info.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"total_backward",
|
||||
"The total media volume flowing backward.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
.add(VIFCombinable::BackwardFlow)
|
||||
);
|
||||
void MeterCommonImplementation::addOptionalCommonFields(string field_names)
|
||||
{
|
||||
set<string> fields = splitStringIntoSet(field_names, ',');
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"flow_temperature",
|
||||
"Forward media temperature.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
);
|
||||
if (checkIf(fields, "fabrication_no"))
|
||||
{
|
||||
addStringFieldWithExtractor(
|
||||
"fabrication_no",
|
||||
"Fabrication number.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FabricationNo)
|
||||
);
|
||||
}
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"return_temperature",
|
||||
"Return media temperature.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ReturnTemperature)
|
||||
);
|
||||
if (checkIf(fields,"enhanced_id"))
|
||||
{
|
||||
addStringFieldWithExtractor(
|
||||
"enhanced_id",
|
||||
"Enhanced identification number.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::EnhancedIdentification)
|
||||
);
|
||||
}
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"flow_return_temperature_difference",
|
||||
"The difference between flow and return media temperatures.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Temperature,
|
||||
VifScaling::AutoSigned,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::TemperatureDifference)
|
||||
);
|
||||
if (checkIf(fields,"software_version"))
|
||||
{
|
||||
addStringFieldWithExtractor(
|
||||
"software_version",
|
||||
"Software version.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::SoftwareVersion)
|
||||
);
|
||||
}
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"volume_flow",
|
||||
"Media volume flow.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
);
|
||||
if (checkIf(fields,"model_version"))
|
||||
{
|
||||
addStringFieldWithExtractor(
|
||||
"model_version",
|
||||
"Meter model version.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ModelVersion)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"customer"))
|
||||
{
|
||||
addStringFieldWithExtractor(
|
||||
"customer",
|
||||
"Customer name.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Customer)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"location"))
|
||||
{
|
||||
addStringFieldWithExtractor(
|
||||
"location",
|
||||
"Meter installed at this customer location.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Location)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"operating_time_h"))
|
||||
{
|
||||
addNumericFieldWithExtractor(
|
||||
"operating_time",
|
||||
"How long the meter has been collecting data.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::OperatingTime)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"on_time_h"))
|
||||
{
|
||||
addNumericFieldWithExtractor(
|
||||
"on_time",
|
||||
"How long the meter has been powered up.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::OnTime)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"on_time_at_error_h"))
|
||||
{
|
||||
addNumericFieldWithExtractor(
|
||||
"on_time_at_error",
|
||||
"How long the meter has been in an error state while powered up.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::AtError)
|
||||
.set(VIFRange::OnTime)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"meter_date"))
|
||||
{
|
||||
addStringFieldWithExtractor(
|
||||
"meter_date",
|
||||
"Date when the meter sent the telegram.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Date)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"meter_date_at_error"))
|
||||
{
|
||||
addStringFieldWithExtractor(
|
||||
"meter_date_at_error",
|
||||
"Date when the meter was in error.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::AtError)
|
||||
.set(VIFRange::Date)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"meter_datetime"))
|
||||
{
|
||||
addStringFieldWithExtractor(
|
||||
"meter_datetime",
|
||||
"Date and time when the meter sent the telegram.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"meter_datetime_at_error"))
|
||||
{
|
||||
addStringFieldWithExtractor(
|
||||
"meter_datetime_at_error",
|
||||
"Date and time when the meter was in error.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::AtError)
|
||||
.set(VIFRange::DateTime)
|
||||
);
|
||||
}
|
||||
|
||||
checkFieldsEmpty(fields, name());
|
||||
}
|
||||
|
||||
void MeterCommonImplementation::addOptionalFlowRelatedFields(string field_names)
|
||||
{
|
||||
set<string> fields = splitStringIntoSet(field_names, ',');
|
||||
|
||||
if (checkIf(fields,"total_m3"))
|
||||
{
|
||||
addNumericFieldWithExtractor(
|
||||
"total",
|
||||
"The total media volume consumption recorded by this meter.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"total_forward_m3"))
|
||||
{
|
||||
addNumericFieldWithExtractor(
|
||||
"total_forward",
|
||||
"The total media volume flowing forward.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
.add(VIFCombinable::ForwardFlow)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"total_backward_m3"))
|
||||
{
|
||||
addNumericFieldWithExtractor(
|
||||
"total_backward",
|
||||
"The total media volume flowing backward.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
.add(VIFCombinable::BackwardFlow)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"flow_temperature_c"))
|
||||
{
|
||||
addNumericFieldWithExtractor(
|
||||
"flow_temperature",
|
||||
"Forward media temperature.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"return_temperature_c"))
|
||||
{
|
||||
addNumericFieldWithExtractor(
|
||||
"return_temperature",
|
||||
"Return media temperature.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ReturnTemperature)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"flow_return_temperature_difference_c"))
|
||||
{
|
||||
addNumericFieldWithExtractor(
|
||||
"flow_return_temperature_difference",
|
||||
"The difference between flow and return media temperatures.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Temperature,
|
||||
VifScaling::AutoSigned,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::TemperatureDifference)
|
||||
);
|
||||
}
|
||||
|
||||
if (checkIf(fields,"volume_flow_m3h"))
|
||||
{
|
||||
addNumericFieldWithExtractor(
|
||||
"volume_flow",
|
||||
"Media volume flow.",
|
||||
PrintProperty::JSON | PrintProperty::OPTIONAL,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -83,7 +83,6 @@ LIST_OF_METER_TYPES
|
|||
X(sontex868, T1_bit, HeatCostAllocationMeter, SONTEX868, Sontex868) \
|
||||
X(topaseskr, T1_bit, WaterMeter, TOPASESKR, TopasEsKr) \
|
||||
X(lse_08, S1_bit|C1_bit, HeatCostAllocationMeter, LSE_08, LSE_08) \
|
||||
X(unismart, T1_bit, GasMeter, UNISMART, Unismart) \
|
||||
|
||||
|
||||
enum class MeterDriver {
|
||||
|
@ -292,7 +291,8 @@ enum PrintProperty
|
|||
DEPRECATED = 32, // This field is about to be removed or changed in a newer driver, which will have a new name.
|
||||
STATUS = 64, // This is >the< status field and it should read OK of not error flags are set.
|
||||
JOIN_TPL_STATUS = 128, // This text field also includes the tpl status decoding. multiple OK:s collapse to a single OK.
|
||||
JOIN_INTO_STATUS = 256 // This text field is injected into the already defined status field. multiple OK:s collapse.
|
||||
JOIN_INTO_STATUS = 256, // This text field is injected into the already defined status field. multiple OK:s collapse.
|
||||
OFFICIAL = 512 // This field is listed as an official field for the driver.
|
||||
};
|
||||
|
||||
struct PrintProperties
|
||||
|
|
|
@ -103,7 +103,6 @@ protected:
|
|||
void setMeterType(MeterType mt);
|
||||
void addLinkMode(LinkMode lm);
|
||||
void addMfctTPLStatusBits(Translate::Lookup lookup);
|
||||
void setDefaultFields(string f);
|
||||
|
||||
// Print with the default unit for this quantity.
|
||||
void addPrint(string vname, Quantity vquantity,
|
||||
|
@ -257,8 +256,8 @@ protected:
|
|||
|
||||
std::string decodeTPLStatusByte(uchar sts);
|
||||
|
||||
void addOptionalCommonFields();
|
||||
void addOptionalFlowRelatedFields();
|
||||
void addOptionalCommonFields(string fields);
|
||||
void addOptionalFlowRelatedFields(string fields);
|
||||
|
||||
vector<string> &selectedFields() { return selected_fields_; }
|
||||
void setSelectedFields(vector<string> &f) { selected_fields_ = f; }
|
||||
|
|
|
@ -1884,6 +1884,13 @@ vector<string> splitString(const string &s, char c)
|
|||
return v;
|
||||
}
|
||||
|
||||
set<string> splitStringIntoSet(const string &s, char c)
|
||||
{
|
||||
vector<string> v = splitString(s, c);
|
||||
set<string> words(v.begin(), v.end());
|
||||
return words;
|
||||
}
|
||||
|
||||
vector<string> splitDeviceString(const string& ds)
|
||||
{
|
||||
string s = ds;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include<string>
|
||||
#include<functional>
|
||||
#include<map>
|
||||
#include<set>
|
||||
#include<vector>
|
||||
|
||||
void onExit(std::function<void()> cb);
|
||||
|
@ -152,6 +153,8 @@ bool isNumber(const std::string& fq);
|
|||
std::vector<std::string> splitMatchExpressions(const std::string& mes);
|
||||
// Split s into strings separated by c.
|
||||
std::vector<std::string> splitString(const std::string &s, char c);
|
||||
// Split s into strings separated by c and store inte set.
|
||||
std::set<std::string> splitStringIntoSet(const std::string &s, char c);
|
||||
// Split device string cul:c1:CMD(bar 1:2) into cul c1 CMD(bar 1:2)
|
||||
// I.e. the : colon inside CMD is not used for splitting.
|
||||
std::vector<std::string> splitDeviceString(const std::string &s);
|
||||
|
|
|
@ -13,11 +13,7 @@ cat > $TEST/test_expected.txt <<EOF
|
|||
(dvparser) warning: unexpected end of data
|
||||
(dvparser) warning: unexpected end of data
|
||||
(dvparser) found new format "046D0406041301FD17426C4406840106840206840306840406840506840606840706840806840906C1337F47A64E0C062364" with hash b934, remembering!
|
||||
(meter) while processing field extractors ignoring dventry 0C06 at offset 129 matching since field total was already matched against dventry 0406 at offset 25 !
|
||||
(dvparser) found new format "046D0406041301FD17426C4406840106840206840306840406840506840606840706840806840906585D65E6958F6B5E93DBA60CD99D06EB27D97106000000840F060003620501" with hash 6c76, remembering!
|
||||
(meter) while processing field extractors ignoring dventry 0000 at offset 146 matching since field total was already matched against dventry 0406 at offset 25 !
|
||||
(meter) while processing field extractors ignoring dventry 0600 at offset 151 matching since field total was already matched against dventry 0406 at offset 25 !
|
||||
(meter) while processing field extractors ignoring dventry 0501 at offset 166 matching since field total was already matched against dventry 0406 at offset 25 !
|
||||
EOF
|
||||
|
||||
$PROG --format=fields --selectfields=id,current_consumption_hca,device_date_time --debug simulations/simulation_broken.txt \
|
||||
|
@ -35,5 +31,11 @@ then
|
|||
fi
|
||||
else
|
||||
echo "wmbusmeters returned error code: $?"
|
||||
echo "EXPECTED----------------------------------------------"
|
||||
cat $TEST/test_expected.txt
|
||||
echo "----------------------------------------------"
|
||||
echo "GOT----------------------------------------------"
|
||||
cat $TEST/test_output.txt
|
||||
echo "----------------------------------------------"
|
||||
|
||||
fi
|
||||
|
|
|
@ -41,6 +41,8 @@ do
|
|||
echo OK json: $TESTNAME
|
||||
TESTRESULT="OK"
|
||||
else
|
||||
jq --sort-keys . $TEST/test_expected_json.txt
|
||||
jq --sort-keys . $TEST/test_response_json.txt
|
||||
TESTRESULT="ERROR"
|
||||
fi
|
||||
else
|
||||
|
|
Ładowanie…
Reference in New Issue