Print OPTIONAL fields that have previously received a value, even if the field is not part of the current telegram. Merge driver whe5x into qcaloric.

pull/609/head
Fredrik Öhrström 2022-09-10 08:44:55 +02:00
rodzic 94683240ea
commit 79e1395fdc
13 zmienionych plików z 187 dodań i 151 usunięć

Wyświetl plik

@ -1,3 +1,10 @@
OPTIONAL fields were only printed in the json, if they appeared in the telegram,
even if the field had received a value before. Now a field will be printed
in the json whenever there is a value stored in the meter object.
I.e. an OPTIONAL field that has never received a value will not be printed.
A NON-OPTIONAL field that has never received a value will be printed with the value null.
Version: 1.9.0 2022-09-04 Version: 1.9.0 2022-09-04
ATTENTION! The multical21 and flowiq drivers have been refactored to the new driver style. ATTENTION! The multical21 and flowiq drivers have been refactored to the new driver style.

Wyświetl plik

@ -44,7 +44,7 @@ telegram=|314493441234567835087a740000200b6e2701004b6e450100426c5f2ccb086e790000
# Test another pair of QCalric C1 telegrams # Test another pair of QCalric C1 telegrams
telegram=|49449344939291903408780DFF5F350082180000800007B06EFFFF970000009F2C70020000BE26970000000000010018002E001F002E0023FF210008000500020000002F046D220FA227| telegram=|49449344939291903408780DFF5F350082180000800007B06EFFFF970000009F2C70020000BE26970000000000010018002E001F002E0023FF210008000500020000002F046D220FA227|
{"media":"heat cost allocation","meter":"qcaloric","name":"MyElement2","id":"90919293","status":"OK","current_consumption_hca":null,"set_date":null,"consumption_at_set_date_hca":null,"set_date_1":null,"consumption_at_set_date_1_hca":null,"set_date_17":null,"consumption_at_set_date_17_hca":null,"error_date":null,"device_date_time":"2021-07-02 15:34","timestamp":"1111-11-11T11:11:11Z"} {"media":"heat cost allocation","meter":"qcaloric","name":"MyElement2","id":"90919293","status":"OK","current_consumption_hca":null,"set_date":null,"consumption_at_set_date_hca":null,"set_date_1":null,"consumption_at_set_date_1_hca":null,"device_date_time":"2021-07-02 15:34","timestamp":"1111-11-11T11:11:11Z"}
telegram=|314493449392919034087a520000200b6e9700004b6e700200426c9f2ccb086e970000c2086cbe26326cffff046d2d16a227| telegram=|314493449392919034087a520000200b6e9700004b6e700200426c9f2ccb086e970000c2086cbe26326cffff046d2d16a227|
{"media":"heat cost allocation","meter":"qcaloric","name":"MyElement2","id":"90919293","status":"OK","current_consumption_hca":97,"set_date":"2020-12-31","consumption_at_set_date_hca":270,"set_date_1":"2020-12-31","consumption_at_set_date_1_hca":270,"set_date_17":"2021-06-30","consumption_at_set_date_17_hca":97,"error_date":"2127-15-31","device_date_time":"2021-07-02 22:45","timestamp":"1111-11-11T11:11:11Z"} {"media":"heat cost allocation","meter":"qcaloric","name":"MyElement2","id":"90919293","status":"OK","current_consumption_hca":97,"set_date":"2020-12-31","consumption_at_set_date_hca":270,"set_date_1":"2020-12-31","consumption_at_set_date_1_hca":270,"set_date_17":"2021-06-30","consumption_at_set_date_17_hca":97,"error_date":"2127-15-31","device_date_time":"2021-07-02 22:45","timestamp":"1111-11-11T11:11:11Z"}

Wyświetl plik

@ -2,7 +2,7 @@
# Test a HCA WHE465 Qundis # Test a HCA WHE465 Qundis
telegram=|244465323251839134087a4f0000000b6e0403004b6e660300426c9e29326cffff046d1416b921dd2f| telegram=|244465323251839134087a4f0000000b6e0403004b6e660300426c9e29326cffff046d1416b921dd2f|
{"media":"heat cost allocation","meter":"whe5x","name":"HCA","id":"91835132","status":"OK","current_consumption_hca":304,"set_date":"2020-09-30","consumption_at_set_date_hca":366,"set_date_1":"2020-09-30","consumption_at_set_date_1_hca":366,"error_date":"2127-15-31","device_date_time":"2021-01-25 22:20","timestamp":"1111-11-11T11:11:11Z"} {"media":"heat cost allocation","meter":"qcaloric","name":"HCA","id":"91835132","status":"OK","current_consumption_hca":304,"set_date":"2020-09-30","consumption_at_set_date_hca":366,"set_date_1":"2020-09-30","consumption_at_set_date_1_hca":366,"error_date":"2127-15-31","device_date_time":"2021-01-25 22:20","timestamp":"1111-11-11T11:11:11Z"}
|HCA;91835132;304;2020-09-30;366;1111-11-11 11:11.11 |HCA;91835132;304;2020-09-30;366;1111-11-11 11:11.11
# Test another HCA from Qundis # Test another HCA from Qundis

Wyświetl plik

@ -288,12 +288,12 @@ namespace
// Type T1A2 telegram: // Type T1A2 telegram:
// telegram=|DA44496A5555445588077A320200002F2F_04140000000084800114000000008280016C2124C480011400000080C280016CFFFF84810114000000808281016CFFFFC481011400000080C281016CFFFF84820114000000808282016CFFFFC482011400000080C282016CFFFF84830114000000808283016CFFFFC483011400000080C283016CFFFF84840114000000808284016CFFFFC484011400000080C284016CFFFF84850114000000808285016CFFFFC485011400000080C285016CFFFF84860114000000808286016CFFFFC486011400000080C286016CFFFF| // telegram=|DA44496A5555445588077A320200002F2F_04140000000084800114000000008280016C2124C480011400000080C280016CFFFF84810114000000808281016CFFFFC481011400000080C281016CFFFF84820114000000808282016CFFFFC482011400000080C282016CFFFF84830114000000808283016CFFFFC483011400000080C283016CFFFF84840114000000808284016CFFFFC484011400000080C284016CFFFF84850114000000808285016CFFFFC485011400000080C285016CFFFF84860114000000808286016CFFFFC486011400000080C286016CFFFF|
// {"media":"water","meter":"c5isf","name":"Heat","id":"55445555","total_energy_consumption_kwh":0,"total_volume_m3":0,"status":"ERROR REVERSE_FLOW SUPPLY_SENSOR_INTERRUPTED","prev_1_month":"2017-04-01","prev_2_month":"2127-15-31","prev_3_month":"2127-15-31","prev_4_month":"2127-15-31","prev_5_month":"2127-15-31","prev_6_month":"2127-15-31","prev_7_month":"2127-15-31","prev_8_month":"2127-15-31","prev_9_month":"2127-15-31","prev_10_month":"2127-15-31","prev_11_month":"2127-15-31","prev_12_month":"2127-15-31","prev_13_month":"2127-15-31","prev_14_month":"2127-15-31","prev_1_month_m3":0,"prev_2_month_m3":21474836.48,"prev_3_month_m3":21474836.48,"prev_4_month_m3":21474836.48,"prev_5_month_m3":21474836.48,"prev_6_month_m3":21474836.48,"prev_7_month_m3":21474836.48,"prev_8_month_m3":21474836.48,"prev_9_month_m3":21474836.48,"prev_10_month_m3":21474836.48,"prev_11_month_m3":21474836.48,"prev_12_month_m3":21474836.48,"prev_13_month_m3":21474836.48,"prev_14_month_m3":21474836.48,"timestamp":"1111-11-11T11:11:11Z"} // {"media":"water","meter":"c5isf","name":"Heat","id":"55445555","total_energy_consumption_kwh":0,"total_volume_m3":0,"status":"ERROR REVERSE_FLOW SUPPLY_SENSOR_INTERRUPTED","prev_1_month":"2017-04-01","prev_2_month":"2127-15-31","prev_3_month":"2127-15-31","prev_4_month":"2127-15-31","prev_5_month":"2127-15-31","prev_6_month":"2127-15-31","prev_7_month":"2127-15-31","prev_8_month":"2127-15-31","prev_9_month":"2127-15-31","prev_10_month":"2127-15-31","prev_11_month":"2127-15-31","prev_12_month":"2127-15-31","prev_13_month":"2127-15-31","prev_14_month":"2127-15-31","prev_1_month_m3":0,"prev_2_month_m3":21474836.48,"prev_3_month_m3":21474836.48,"prev_4_month_m3":21474836.48,"prev_5_month_m3":21474836.48,"prev_6_month_m3":21474836.48,"prev_7_month_m3":21474836.48,"prev_8_month_m3":21474836.48,"prev_9_month_m3":21474836.48,"prev_10_month_m3":21474836.48,"prev_11_month_m3":21474836.48,"prev_12_month_m3":21474836.48,"prev_13_month_m3":21474836.48,"prev_14_month_m3":21474836.48,"total_energy_consumption_last_month_kwh":0,"timestamp":"1111-11-11T11:11:11Z"}
// |Heat;55445555;0.000000;0.000000;ERROR REVERSE_FLOW SUPPLY_SENSOR_INTERRUPTED;1111-11-11 11:11.11 // |Heat;55445555;0.000000;0.000000;ERROR REVERSE_FLOW SUPPLY_SENSOR_INTERRUPTED;1111-11-11 11:11.11
// Type T1B telegram: // Type T1B telegram:
// telegram=|5E44496A5555445588047A0A0050052F2F_04061A0000000413C20800008404060000000082046CC121043BA4000000042D1900000002591216025DE21002FD17000084800106000000008280016CC121948001AE25000000002F2F2F2F2F2F| // telegram=|5E44496A5555445588047A0A0050052F2F_04061A0000000413C20800008404060000000082046CC121043BA4000000042D1900000002591216025DE21002FD17000084800106000000008280016CC121948001AE25000000002F2F2F2F2F2F|
// {"media":"heat","meter":"c5isf","name":"Heat","id":"55445555","total_energy_consumption_kwh":26,"total_volume_m3":2.242,"status":"OK","prev_1_month":"2022-01-01","prev_1_month_kwh":0,"due_energy_consumption_kwh":0,"due_date":"2022-01-01","volume_flow_m3h":0.164,"power_kw":2.5,"total_energy_consumption_last_month_kwh":0,"max_power_last_month_kw":0,"flow_temperature_c":56.5,"return_temperature_c":43.22,"timestamp":"1111-11-11T11:11:11Z"} // {"media":"heat","meter":"c5isf","name":"Heat","id":"55445555","total_energy_consumption_kwh":26,"total_volume_m3":2.242,"status":"OK","prev_1_month":"2022-01-01","prev_2_month":"2127-15-31","prev_3_month":"2127-15-31","prev_4_month":"2127-15-31","prev_5_month":"2127-15-31","prev_6_month":"2127-15-31","prev_7_month":"2127-15-31","prev_8_month":"2127-15-31","prev_9_month":"2127-15-31","prev_10_month":"2127-15-31","prev_11_month":"2127-15-31","prev_12_month":"2127-15-31","prev_13_month":"2127-15-31","prev_14_month":"2127-15-31","prev_1_month_kwh":0,"prev_2_month_kwh":2147483648,"prev_3_month_kwh":2147483648,"prev_4_month_kwh":2147483648,"prev_5_month_kwh":2147483648,"prev_6_month_kwh":2147483648,"prev_7_month_kwh":2147483648,"prev_8_month_kwh":2147483648,"prev_9_month_kwh":2147483648,"prev_10_month_kwh":2147483648,"prev_11_month_kwh":2147483648,"prev_12_month_kwh":2147483648,"prev_13_month_kwh":2147483648,"prev_14_month_kwh":2147483648,"prev_2_month_m3":21474836.48,"prev_3_month_m3":21474836.48,"prev_4_month_m3":21474836.48,"prev_5_month_m3":21474836.48,"prev_6_month_m3":21474836.48,"prev_7_month_m3":21474836.48,"prev_8_month_m3":21474836.48,"prev_9_month_m3":21474836.48,"prev_10_month_m3":21474836.48,"prev_11_month_m3":21474836.48,"prev_12_month_m3":21474836.48,"prev_13_month_m3":21474836.48,"prev_14_month_m3":21474836.48,"due_energy_consumption_kwh":0,"due_date":"2022-01-01","volume_flow_m3h":0.164,"power_kw":2.5,"total_energy_consumption_last_month_kwh":0,"max_power_last_month_kw":0,"flow_temperature_c":56.5,"return_temperature_c":43.22,"timestamp":"1111-11-11T11:11:11Z"}
// |Heat;55445555;26.000000;2.242000;OK;1111-11-11 11:11.11 // |Heat;55445555;26.000000;2.242000;OK;1111-11-11 11:11.11
// Test: Heat c5isf 32002044 NOKEY // Test: Heat c5isf 32002044 NOKEY

Wyświetl plik

@ -204,5 +204,5 @@ namespace
// |Water;13963399;nan;nan;null;null;null;2021-12-01 00:24;1111-11-11 11:11.11 // |Water;13963399;nan;nan;null;null;null;2021-12-01 00:24;1111-11-11 11:11.11
// telegram=|2D4465329933961318067ADA000000_0C13567100004C1300000000426CFFFF02BB560000326CFFFF046D2307A12C| // telegram=|2D4465329933961318067ADA000000_0C13567100004C1300000000426CFFFF02BB560000326CFFFF046D2307A12C|
// {"media":"warm water","meter":"lse_07_17","name":"Water","id":"13963399","total_m3":7.156,"due_date_m3":0,"due_date":"2127-15-31","error_code":"OK","error_date":"2127-15-31","device_date_time":"2021-12-01 07:35","timestamp":"1111-11-11T11:11:11Z"} // {"media":"warm water","meter":"lse_07_17","name":"Water","id":"13963399","total_m3":7.156,"due_date_m3":0,"due_date":"2127-15-31","what_date_m3":7,"what_date":"2021-11-30","error_code":"OK","error_date":"2127-15-31","device_date_time":"2021-12-01 07:35","meter_version":"11","timestamp":"1111-11-11T11:11:11Z"}
// |Water;13963399;7.156000;0.000000;2127-15-31;OK;2127-15-31;2021-12-01 07:35;1111-11-11 11:11.11 // |Water;13963399;7.156000;0.000000;2127-15-31;OK;2127-15-31;2021-12-01 07:35;1111-11-11 11:11.11

Wyświetl plik

@ -66,7 +66,7 @@ namespace
.set(StorageNr(8)) .set(StorageNr(8))
); );
/* The wire mbus telegram contains 4 totals and dates. For the moment we only print nr 1 which is the latest. */ // The wire mbus telegram contains 4 totals and dates. For the moment we only print nr 1 which is the latest.
addNumericFieldWithExtractor( addNumericFieldWithExtractor(
"target", "target",
"The total water consumption recorded at the beginning of this month.", "The total water consumption recorded at the beginning of this month.",

Wyświetl plik

@ -27,10 +27,13 @@ namespace
static bool ok = registerDriver([](DriverInfo&di) static bool ok = registerDriver([](DriverInfo&di)
{ {
di.setName("qcaloric"); di.setName("qcaloric");
di.addNameAlias("whe5x");
di.setDefaultFields("name,id,current_consumption_hca,set_date,consumption_at_set_date_hca,timestamp"); di.setDefaultFields("name,id,current_consumption_hca,set_date,consumption_at_set_date_hca,timestamp");
di.setMeterType(MeterType::HeatCostAllocationMeter); di.setMeterType(MeterType::HeatCostAllocationMeter);
di.addLinkMode(LinkMode::C1); di.addLinkMode(LinkMode::C1);
di.addLinkMode(LinkMode::T1); di.addLinkMode(LinkMode::T1);
di.addLinkMode(LinkMode::S1);
di.addDetection(MANUFACTURER_LSE, 0x08, 0x34);
di.addDetection(MANUFACTURER_LSE, 0x08, 0x35); di.addDetection(MANUFACTURER_LSE, 0x08, 0x35);
di.addDetection(MANUFACTURER_QDS, 0x08, 0x35); di.addDetection(MANUFACTURER_QDS, 0x08, 0x35);
di.addDetection(MANUFACTURER_QDS, 0x08, 0x34); di.addDetection(MANUFACTURER_QDS, 0x08, 0x34);
@ -104,7 +107,7 @@ namespace
addStringFieldWithExtractor( addStringFieldWithExtractor(
"set_date_17", "set_date_17",
"The 17 billing period date.", "The 17 billing period date.",
PrintProperty::JSON | PrintProperty::FIELD, PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::OPTIONAL,
FieldMatcher::build() FieldMatcher::build()
.set(MeasurementType::Instantaneous) .set(MeasurementType::Instantaneous)
.set(VIFRange::Date) .set(VIFRange::Date)
@ -114,7 +117,7 @@ namespace
addNumericFieldWithExtractor( addNumericFieldWithExtractor(
"consumption_at_set_date_17", "consumption_at_set_date_17",
"Heat cost allocation at the 17 billing period date.", "Heat cost allocation at the 17 billing period date.",
PrintProperty::JSON | PrintProperty::FIELD, PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::OPTIONAL,
Quantity::HCA, Quantity::HCA,
VifScaling::Auto, VifScaling::Auto,
FieldMatcher::build() FieldMatcher::build()
@ -126,7 +129,7 @@ namespace
addStringFieldWithExtractor( addStringFieldWithExtractor(
"error_date", "error_date",
"Date when the meter entered an error state.", "Date when the meter entered an error state.",
PrintProperty::JSON, PrintProperty::JSON | PrintProperty::OPTIONAL,
FieldMatcher::build() FieldMatcher::build()
.set(MeasurementType::AtError) .set(MeasurementType::AtError)
.set(VIFRange::Date) .set(VIFRange::Date)
@ -153,7 +156,7 @@ namespace
// Test: MyElement2 qcaloric 90919293 NOKEY // Test: MyElement2 qcaloric 90919293 NOKEY
// Comment: Test mostly proprietary telegram without values // Comment: Test mostly proprietary telegram without values
// telegram=|49449344939291903408780DFF5F350082180000800007B06EFFFF970000009F2C70020000BE26970000000000010018002E001F002E0023FF210008000500020000002F046D220FA227| // telegram=|49449344939291903408780DFF5F350082180000800007B06EFFFF970000009F2C70020000BE26970000000000010018002E001F002E0023FF210008000500020000002F046D220FA227|
// {"media":"heat cost allocation","meter":"qcaloric","name":"MyElement2","id":"90919293","status":"OK","current_consumption_hca":null,"set_date":null,"consumption_at_set_date_hca":null,"set_date_1":null,"consumption_at_set_date_1_hca":null,"set_date_17":null,"consumption_at_set_date_17_hca":null,"error_date":null,"device_date_time":"2021-07-02 15:34","timestamp":"1111-11-11T11:11:11Z"} // {"media":"heat cost allocation","meter":"qcaloric","name":"MyElement2","id":"90919293","status":"OK","current_consumption_hca":null,"set_date":null,"consumption_at_set_date_hca":null,"set_date_1":null,"consumption_at_set_date_1_hca":null,"device_date_time":"2021-07-02 15:34","timestamp":"1111-11-11T11:11:11Z"}
// |MyElement2;90919293;null;null;null;1111-11-11 11:11.11 // |MyElement2;90919293;null;null;null;1111-11-11 11:11.11
// Comment: Normal telegram that fills in values. // Comment: Normal telegram that fills in values.
@ -165,3 +168,10 @@ namespace
// telegram=|49449344939291903408780DFF5F350082180000800007B06EFFFF970000009F2C70020000BE26970000000000010018002E001F002E0023FF210008000500020000002F046D220FA228| // telegram=|49449344939291903408780DFF5F350082180000800007B06EFFFF970000009F2C70020000BE26970000000000010018002E001F002E0023FF210008000500020000002F046D220FA228|
// {"media":"heat cost allocation","meter":"qcaloric","name":"MyElement2","id":"90919293","status":"OK","current_consumption_hca":97,"set_date":"2020-12-31","consumption_at_set_date_hca":270,"set_date_1":"2020-12-31","consumption_at_set_date_1_hca":270,"set_date_17":"2021-06-30","consumption_at_set_date_17_hca":97,"error_date":"2127-15-31","device_date_time":"2021-08-02 15:34","timestamp":"1111-11-11T11:11:11Z"} // {"media":"heat cost allocation","meter":"qcaloric","name":"MyElement2","id":"90919293","status":"OK","current_consumption_hca":97,"set_date":"2020-12-31","consumption_at_set_date_hca":270,"set_date_1":"2020-12-31","consumption_at_set_date_1_hca":270,"set_date_17":"2021-06-30","consumption_at_set_date_17_hca":97,"error_date":"2127-15-31","device_date_time":"2021-08-02 15:34","timestamp":"1111-11-11T11:11:11Z"}
// |MyElement2;90919293;97;2020-12-31;270;1111-11-11 11:11.11 // |MyElement2;90919293;97;2020-12-31;270;1111-11-11 11:11.11
// Comment: Another version of the heat cost allocator. But for historical reasons got its
// own driver name, which is now aliased to qcaloric.
// Test: HCA whe5x 91835132 NOKEY
// telegram=|244465323251839134087a4f0000000b6e0403004b6e660300426c9e29326cffff046d1416b921dd2f|
// {"media":"heat cost allocation","meter":"qcaloric","name":"HCA","id":"91835132","status":"OK","current_consumption_hca":304,"set_date":"2020-09-30","consumption_at_set_date_hca":366,"set_date_1":"2020-09-30","consumption_at_set_date_1_hca":366,"error_date":"2127-15-31","device_date_time":"2021-01-25 22:20","timestamp":"1111-11-11T11:11:11Z"}
// |HCA;91835132;304;2020-09-30;366;1111-11-11 11:11.11

Wyświetl plik

@ -1,126 +0,0 @@
/*
Copyright (C) 2019-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("whe5x");
di.setDefaultFields("name,id,current_consumption_hca,set_date,consumption_at_set_date_hca,timestamp");
di.setMeterType(MeterType::HeatCostAllocationMeter);
di.addLinkMode(LinkMode::S1);
di.addDetection(MANUFACTURER_LSE, 0x08, 0x34);
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
});
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
{
addStringField(
"status",
"Meter status from tpl status field.",
PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT |
PrintProperty::STATUS | PrintProperty::JOIN_TPL_STATUS);
addNumericFieldWithExtractor(
"current_consumption",
"The current temperature.",
PrintProperty::JSON | PrintProperty::FIELD,
Quantity::HCA,
VifScaling::Auto,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::HeatCostAllocation)
);
addStringFieldWithExtractor(
"set_date",
"The most recent billing period date.",
PrintProperty::JSON | PrintProperty::FIELD,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Date)
.set(StorageNr(1))
);
addNumericFieldWithExtractor(
"consumption_at_set_date",
"Heat cost allocation at the most recent billing period date.",
PrintProperty::JSON | PrintProperty::FIELD,
Quantity::HCA,
VifScaling::Auto,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::HeatCostAllocation)
.set(StorageNr(1))
);
addStringFieldWithExtractor(
"set_date_1",
"The most recent billing period date.",
PrintProperty::JSON | PrintProperty::FIELD,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Date)
.set(StorageNr(1))
);
addNumericFieldWithExtractor(
"consumption_at_set_date_1",
"Heat cost allocation at the most recent billing period date.",
PrintProperty::JSON | PrintProperty::FIELD,
Quantity::HCA,
VifScaling::Auto,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::HeatCostAllocation)
.set(StorageNr(1))
);
addStringFieldWithExtractor(
"error_date",
"Date when the meter entered an error state.",
PrintProperty::JSON,
FieldMatcher::build()
.set(MeasurementType::AtError)
.set(VIFRange::Date)
);
addStringFieldWithExtractor(
"device_date_time",
"Date and time when the meter sent the telegram.",
PrintProperty::JSON,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::DateTime)
);
}
}
// Test: HCA whe5x 91835132 NOKEY
// telegram=|244465323251839134087a4f0000000b6e0403004b6e660300426c9e29326cffff046d1416b921dd2f|
// {"media":"heat cost allocation","meter":"whe5x","name":"HCA","id":"91835132","status":"OK","current_consumption_hca":304,"set_date":"2020-09-30","consumption_at_set_date_hca":366,"set_date_1":"2020-09-30","consumption_at_set_date_1_hca":366,"error_date":"2127-15-31","device_date_time":"2021-01-25 22:20","timestamp":"1111-11-11T11:11:11Z"}
// |HCA;91835132;304;2020-09-30;366;1111-11-11 11:11.11

Wyświetl plik

@ -1225,3 +1225,63 @@ const char *toString(MeasurementType mt)
} }
return "?"; return "?";
} }
string FieldMatcher::str()
{
string s = "";
if (match_dif_vif_key)
{
s = s+"DVK("+dif_vif_key.str()+") ";
}
if (match_measurement_type)
{
s = s+"MT("+toString(measurement_type)+") ";
}
if (match_vif_range)
{
s = s+"VR("+toString(vif_range)+") ";
}
if (vif_combinables.size() > 0)
{
s += "Comb(";
for (auto vc : vif_combinables)
{
s = s+toString(vc)+" ";
}
s.pop_back();
s += ")";
}
if (match_storage_nr)
{
s = s+"S("+to_string(storage_nr_from.intValue())+"-"+to_string(storage_nr_to.intValue())+") ";
}
if (match_tariff_nr)
{
s = s+"T("+to_string(tariff_nr_from.intValue())+"-"+to_string(tariff_nr_to.intValue())+") ";
}
if (match_subunit_nr)
{
s += "U("+to_string(subunit_nr_from.intValue())+"-"+to_string(subunit_nr_to.intValue())+") ";
}
if (index_nr.intValue() != 1)
{
s += "I("+to_string(index_nr.intValue())+")";
}
if (s.size() > 0)
{
s.pop_back();
}
return s;
}

Wyświetl plik

@ -430,6 +430,7 @@ struct FieldMatcher
FieldMatcher &set(IndexNr i) { index_nr = i; return *this; } FieldMatcher &set(IndexNr i) { index_nr = i; return *this; }
bool matches(DVEntry &dv_entry); bool matches(DVEntry &dv_entry);
std::string str();
}; };
bool loadFormatBytesFromSignature(uint16_t format_signature, std::vector<uchar> *format_bytes); bool loadFormatBytesFromSignature(uint16_t format_signature, std::vector<uchar> *format_bytes);

Wyświetl plik

@ -1820,6 +1820,27 @@ void MeterCommonImplementation::setNumericValue(FieldInfo *fi, Unit u, double v)
numeric_values_[pair<string,Quantity>(field_name_no_unit,fi->xuantity())] = NumericField(u, v, fi); numeric_values_[pair<string,Quantity>(field_name_no_unit,fi->xuantity())] = NumericField(u, v, fi);
} }
bool MeterCommonImplementation::hasValue(FieldInfo *fi)
{
return hasStringValue(fi) || hasNumericValue(fi);
}
bool MeterCommonImplementation::hasNumericValue(FieldInfo *fi)
{
if (fi->hasGetNumericValueOverride()) return true;
pair<string,Quantity> key(fi->vname(),fi->xuantity());
return numeric_values_.count(key) != 0;
}
bool MeterCommonImplementation::hasStringValue(FieldInfo *fi)
{
if (fi->hasGetStringValueOverride()) return true;
return string_values_.count(fi->vname()) != 0;
}
double MeterCommonImplementation::getNumericValue(FieldInfo *fi, Unit to) double MeterCommonImplementation::getNumericValue(FieldInfo *fi, Unit to)
{ {
if (fi->hasGetNumericValueOverride()) if (fi->hasGetNumericValueOverride())
@ -2033,12 +2054,14 @@ void MeterCommonImplementation::printMeter(Telegram *t,
} }
// Iterate over the meter field infos... // Iterate over the meter field infos...
map<FieldInfo*,DVEntry*> found; // Found from the telegram
set<string> found_vnames;
for (FieldInfo& fi : field_infos_) for (FieldInfo& fi : field_infos_)
{ {
if (fi.printProperties().hasJSON()) if (fi.printProperties().hasJSON())
{ {
// The field should be printed in the json. (Most usually should.) // The field should be printed in the json. (Most usually should.)
bool found = false;
for (auto& i : t->dv_entries) for (auto& i : t->dv_entries)
{ {
// Check each telegram dv entry. // Check each telegram dv entry.
@ -2046,24 +2069,50 @@ void MeterCommonImplementation::printMeter(Telegram *t,
// Has the entry been matches to this field, then print it as json. // Has the entry been matches to this field, then print it as json.
if (dve->hasFieldInfo(&fi)) if (dve->hasFieldInfo(&fi))
{ {
debug("(meters) render field %s(%s)[%d] with dventry @%d key %s data %s\n", assert(found.count(&fi) == 0);
fi.vname().c_str(), toString(fi.xuantity()), fi.index(), found[&fi] = dve;
dve->offset, found_vnames.insert(fi.vname());
dve->dif_vif_key.str().c_str(), }
dve->value.c_str()); }
}
}
for (FieldInfo& fi : field_infos_)
{
if (fi.printProperties().hasJSON())
{
if (found.count(&fi) != 0)
{
DVEntry *dve = found[&fi];
debug("(meters) render field %s(%s)[%d] with dventry @%d key %s data %s\n",
fi.vname().c_str(), toString(fi.xuantity()), fi.index(),
dve->offset,
dve->dif_vif_key.str().c_str(),
dve->value.c_str());
string out = fi.renderJson(this, &conversions());
debug("(meters) %s\n", out.c_str());
s += indent+out+","+newline;
}
else
{
// Ok, no value found in received telegram.
// Print field anyway, if it is not OPTIONAL
// or if a value has been received before and this field has not been received using a different rule.
// Why this complicated rule?
// E.g. the minmoess mbus seems to use storage 1 for target_m3 but the wmbus version uses storage 8.
// I.e. we have two rules that store into target_m3, this check will prevent target_m3 from being printed twice.
if (!fi.printProperties().hasOPTIONAL() || (found_vnames.count(fi.vname()) == 0 && hasValue(&fi)))
{
// No telegram entries found, but this field should be printed anyway.
// It will be printed with any value received from a previous telegram.
// Or if no value has been received, null.
debug("(meters) render field %s(%s)[%d] without dventry\n",
fi.vname().c_str(), toString(fi.xuantity()), fi.index());
string out = fi.renderJson(this, &conversions()); string out = fi.renderJson(this, &conversions());
debug("(meters) %s\n", out.c_str()); debug("(meters) %s\n", out.c_str());
s += indent+out+","+newline; s += indent+out+","+newline;
found = true;
} }
} }
if (!found && !fi.printProperties().hasOPTIONAL())
{
// No telegram entries found, but this field should be printed anyway.
// It will be printed with any value received from a previous telegram.
// Or if no value has been received, null.
s += indent+fi.renderJson(this, &conversions())+","+newline;
}
} }
} }
@ -2492,6 +2541,19 @@ bool FieldInfo::matches(DVEntry *dve)
return matcher_.matches(*dve); return matcher_.matches(*dve);
} }
string FieldInfo::str()
{
// 15 target Volume x<> :<3A> Auto XUZ "The total water consumption recorded at the beginning of this month."
return tostrprintf("%d %s_%s (%s) %s [%s] \"%s\"",
index_,
vname_.c_str(),
unitToStringLowerCase(default_unit_).c_str(),
toString(xuantity_),
toString(vif_scaling_),
matcher_.str().c_str(),
help_.c_str());
}
DriverName MeterInfo::driverName() DriverName MeterInfo::driverName()
{ {
if (driver_name.str() == "") if (driver_name.str() == "")
@ -2923,6 +2985,17 @@ void MeterCommonImplementation::addOptionalFlowRelatedFields()
.set(MeasurementType::Instantaneous) .set(MeasurementType::Instantaneous)
.set(VIFRange::VolumeFlow) .set(VIFRange::VolumeFlow)
); );
}
const char *toString(VifScaling s)
{
switch (s)
{
case VifScaling::None: return "None";
case VifScaling::Auto: return "Auto";
case VifScaling::NoneSigned: return "NoneSigned";
case VifScaling::AutoSigned: return "AutoSigned";
} }
return "?";
}

Wyświetl plik

@ -288,6 +288,8 @@ enum class VifScaling
AutoSigned // Scale and assume the value is signed. AutoSigned // Scale and assume the value is signed.
}; };
const char* toString(VifScaling s);
enum PrintProperty enum PrintProperty
{ {
JSON = 1, // This field should be printed when using --format=json JSON = 1, // This field should be printed when using --format=json
@ -382,10 +384,13 @@ struct FieldInfo
// The vname is then a pattern total_at_month_{storagenr-32} that gets translated into // The vname is then a pattern total_at_month_{storagenr-32} that gets translated into
// total_at_month_2 (for the dventry with storage nr 34.) // total_at_month_2 (for the dventry with storage nr 34.)
string generateFieldName(DVEntry *dve); string generateFieldName(DVEntry *dve);
// Check if the meter object stores a value for this field.
bool hasValue(Meter *m);
Translate::Lookup& lookup() { return lookup_; } Translate::Lookup& lookup() { return lookup_; }
string str();
private: private:
int index_; // The field infos for a meter are ordered. int index_; // The field infos for a meter are ordered.

Wyświetl plik

@ -231,6 +231,12 @@ protected:
double getNumericValue(FieldInfo *fi, Unit u); double getNumericValue(FieldInfo *fi, Unit u);
void setStringValue(FieldInfo *fi, std::string v); void setStringValue(FieldInfo *fi, std::string v);
std::string getStringValue(FieldInfo *fi); std::string getStringValue(FieldInfo *fi);
// Check if the meter has received a value for this field.
bool hasValue(FieldInfo *fi);
bool hasNumericValue(FieldInfo *fi);
bool hasStringValue(FieldInfo *fi);
std::string decodeTPLStatusByte(uchar sts); std::string decodeTPLStatusByte(uchar sts);
void addOptionalCommonFields(); void addOptionalCommonFields();