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
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
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|
{"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
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
# Test another HCA from Qundis

Wyświetl plik

@ -288,12 +288,12 @@ namespace
// Type T1A2 telegram:
// 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
// Type T1B telegram:
// 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
// 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
// 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

Wyświetl plik

@ -66,7 +66,7 @@ namespace
.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(
"target",
"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)
{
di.setName("qcaloric");
di.addNameAlias("whe5x");
di.setDefaultFields("name,id,current_consumption_hca,set_date,consumption_at_set_date_hca,timestamp");
di.setMeterType(MeterType::HeatCostAllocationMeter);
di.addLinkMode(LinkMode::C1);
di.addLinkMode(LinkMode::T1);
di.addLinkMode(LinkMode::S1);
di.addDetection(MANUFACTURER_LSE, 0x08, 0x34);
di.addDetection(MANUFACTURER_LSE, 0x08, 0x35);
di.addDetection(MANUFACTURER_QDS, 0x08, 0x35);
di.addDetection(MANUFACTURER_QDS, 0x08, 0x34);
@ -104,7 +107,7 @@ namespace
addStringFieldWithExtractor(
"set_date_17",
"The 17 billing period date.",
PrintProperty::JSON | PrintProperty::FIELD,
PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::OPTIONAL,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Date)
@ -114,7 +117,7 @@ namespace
addNumericFieldWithExtractor(
"consumption_at_set_date_17",
"Heat cost allocation at the 17 billing period date.",
PrintProperty::JSON | PrintProperty::FIELD,
PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::OPTIONAL,
Quantity::HCA,
VifScaling::Auto,
FieldMatcher::build()
@ -126,7 +129,7 @@ namespace
addStringFieldWithExtractor(
"error_date",
"Date when the meter entered an error state.",
PrintProperty::JSON,
PrintProperty::JSON | PrintProperty::OPTIONAL,
FieldMatcher::build()
.set(MeasurementType::AtError)
.set(VIFRange::Date)
@ -153,7 +156,7 @@ namespace
// Test: MyElement2 qcaloric 90919293 NOKEY
// Comment: Test mostly proprietary telegram without values
// 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
// Comment: Normal telegram that fills in values.
@ -165,3 +168,10 @@ namespace
// 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"}
// |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 "?";
}
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; }
bool matches(DVEntry &dv_entry);
std::string str();
};
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);
}
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)
{
if (fi->hasGetNumericValueOverride())
@ -2033,12 +2054,14 @@ void MeterCommonImplementation::printMeter(Telegram *t,
}
// Iterate over the meter field infos...
map<FieldInfo*,DVEntry*> found; // Found from the telegram
set<string> found_vnames;
for (FieldInfo& fi : field_infos_)
{
if (fi.printProperties().hasJSON())
{
// The field should be printed in the json. (Most usually should.)
bool found = false;
for (auto& i : t->dv_entries)
{
// 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.
if (dve->hasFieldInfo(&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());
assert(found.count(&fi) == 0);
found[&fi] = dve;
found_vnames.insert(fi.vname());
}
}
}
}
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());
debug("(meters) %s\n", out.c_str());
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);
}
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()
{
if (driver_name.str() == "")
@ -2923,6 +2985,17 @@ void MeterCommonImplementation::addOptionalFlowRelatedFields()
.set(MeasurementType::Instantaneous)
.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.
};
const char* toString(VifScaling s);
enum PrintProperty
{
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
// total_at_month_2 (for the dventry with storage nr 34.)
string generateFieldName(DVEntry *dve);
// Check if the meter object stores a value for this field.
bool hasValue(Meter *m);
Translate::Lookup& lookup() { return lookup_; }
string str();
private:
int index_; // The field infos for a meter are ordered.

Wyświetl plik

@ -231,6 +231,12 @@ protected:
double getNumericValue(FieldInfo *fi, Unit u);
void setStringValue(FieldInfo *fi, std::string v);
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);
void addOptionalCommonFields();