From addff11eb707b3110099bad3b18d4c4f4fbd4218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20=C3=96hrstr=C3=B6m?= Date: Thu, 24 Nov 2022 16:22:37 +0100 Subject: [PATCH] Pattern generated fields based on storage nr calculation now work. --- src/driver_evo868.cc | 23 +++++++++----- src/formula.cc | 5 ---- src/main.cc | 43 ++++++++++++++++++-------- src/meters.cc | 48 +++++++++++++++++++++++++----- src/meters.h | 4 ++- src/meters_common_implementation.h | 4 ++- tests/test_additional_json.sh | 16 +++++++--- tests/test_drivers.sh | 4 +++ tests/test_list_envs.sh | 12 +++++++- 9 files changed, 121 insertions(+), 38 deletions(-) diff --git a/src/driver_evo868.cc b/src/driver_evo868.cc index f6f74c4..0435f4d 100644 --- a/src/driver_evo868.cc +++ b/src/driver_evo868.cc @@ -27,7 +27,7 @@ namespace static bool ok = registerDriver([](DriverInfo&di) { di.setName("evo868"); - di.setDefaultFields("name,id,total_m3,set_date,consumption_at_set_date_m3,timestamp"); + di.setDefaultFields("name,id,total_m3,current_status,consumption_at_set_date_m3,set_date,timestamp"); di.setMeterType(MeterType::WaterMeter); di.addLinkMode(LinkMode::T1); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); @@ -59,7 +59,7 @@ namespace }, }); - addOptionalCommonFields("fabrication_no,meter_datetime"); + addOptionalCommonFields("fabrication_no"); addOptionalFlowRelatedFields("total_m3"); addNumericFieldWithExtractor( @@ -140,12 +140,21 @@ namespace .set(StorageNr(8),StorageNr(19)) ); + addStringFieldWithExtractor( + "device_date_time", + "Date and time when the meter sent the telegram.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::DateTime) + ); + } } -// est: Votchka evo868 79787776 NOKEY -// omment: Test Maddalena EVO 868 wmbus module on water meter -// elegram=|aa4424347677787950077ac10000202f2f041306070000046d1e31b12104fd17000000000e787880048120004413c9040000426c9f2c840113c904000082016c9f2cd3013b9a0200c4016d0534a7218104fd280182046c9f2c840413c9040000c404131b00000084051300000000c405130000000084061300000000c406130000000084071300000000c407130000000084081300000000c408130000000084091300000000c4091300000000ffff| -// "media":"water","meter":"evo868","name":"Votchka","id":"79787776","total_m3":1.798,"device_date_time":"2021-01-17 17:30","current_status":"OK","fabrication_no":"002081048078","consumption_at_set_date_m3":1.225,"set_date":"2020-12-31","consumption_at_set_date_2_m3":1.225,"set_date_2":"2020-12-31","max_flow_since_datetime_m3h":0.666,"max_flow_datetime":"2021-01-07 20:05","consumption_at_history_1_m3":1.225,"history_1_date":"2020-12-31","consumption_at_history_2_m3":0.027,"history_2_date":"2020-11-30","consumption_at_history_3_m3":0,"history_3_date":"2020-10-31","consumption_at_history_4_m3":0,"history_4_date":"2020-09-30","consumption_at_history_5_m3":0,"history_5_date":"2020-08-31","consumption_at_history_6_m3":0,"history_6_date":"2020-07-31","consumption_at_history_7_m3":0,"history_7_date":"2020-06-30","consumption_at_history_8_m3":0,"history_8_date":"2020-05-31","consumption_at_history_9_m3":0,"history_9_date":"2020-04-30","consumption_at_history_10_m3":0,"history_10_date":"2020-03-31","consumption_at_history_11_m3":0,"history_11_date":"2020-02-29","consumption_at_history_12_m3":0,"history_12_date":"2020-01-31","timestamp":"1111-11-11T11:11:11Z"} -// Votchka;79787776;1.798;OK;1.225;2020-12-31;1111-11-11 11:11.11 +// Test: Votchka evo868 79787776 NOKEY +// Comment: Test Maddalena EVO 868 wmbus module on water meter +// telegram=|aa4424347677787950077ac10000202f2f041306070000046d1e31b12104fd17000000000e787880048120004413c9040000426c9f2c840113c904000082016c9f2cd3013b9a0200c4016d0534a7218104fd280182046c9f2c840413c9040000c404131b00000084051300000000c405130000000084061300000000c406130000000084071300000000c407130000000084081300000000c408130000000084091300000000c4091300000000ffff| +// {"media":"water","meter":"evo868","name":"Votchka","id":"79787776","total_m3":1.798,"device_date_time":"2021-01-17 17:30","current_status":"OK","fabrication_no":"002081048078","consumption_at_set_date_m3":1.225,"set_date":"2020-12-31","consumption_at_set_date_2_m3":1.225,"set_date_2":"2020-12-31","max_flow_since_datetime_m3h":0.666,"max_flow_datetime":"2021-01-07 20:05","consumption_at_history_1_m3":1.225,"history_1_date":"2020-12-31","consumption_at_history_2_m3":0.027,"history_2_date":"2020-11-30","consumption_at_history_3_m3":0,"history_3_date":"2020-10-31","consumption_at_history_4_m3":0,"history_4_date":"2020-09-30","consumption_at_history_5_m3":0,"history_5_date":"2020-08-31","consumption_at_history_6_m3":0,"history_6_date":"2020-07-31","consumption_at_history_7_m3":0,"history_7_date":"2020-06-30","consumption_at_history_8_m3":0,"history_8_date":"2020-05-31","consumption_at_history_9_m3":0,"history_9_date":"2020-04-30","consumption_at_history_10_m3":0,"history_10_date":"2020-03-31","consumption_at_history_11_m3":0,"history_11_date":"2020-02-29","consumption_at_history_12_m3":0,"history_12_date":"2020-01-31","timestamp":"1111-11-11T11:11:11Z"} +// |Votchka;79787776;1.798;OK;1.225;2020-12-31;1111-11-11 11:11.11 diff --git a/src/formula.cc b/src/formula.cc index f6c31a1..76e4820 100644 --- a/src/formula.cc +++ b/src/formula.cc @@ -1030,8 +1030,6 @@ StringInterpolatorImplementation::~StringInterpolatorImplementation() bool StringInterpolatorImplementation::parse(const std::string &f) { - debug("(stringinterpolator) parsing \"%s\"\n", f.c_str()); - strings_.clear(); formulas_.clear(); @@ -1042,7 +1040,6 @@ bool StringInterpolatorImplementation::parse(const std::string &f) { // Push the string up to the brace. string part = f.substr(prev_string_start, next_start_brace - prev_string_start); - debug("(stringinterpolator) string \"%s\"\n", part.c_str()); strings_.push_back(part); // Find the end of the formula. @@ -1050,7 +1047,6 @@ bool StringInterpolatorImplementation::parse(const std::string &f) if (next_end_brace == string::npos) return false; // Oups, missing closing } string formula = f.substr(next_start_brace+1, next_end_brace - next_start_brace - 1); - debug("(stringinterpolator) formula \"%s\"\n", formula.c_str()); formulas_.push_back(unique_ptr(newFormula())); bool ok = formulas_.back()->parse(NULL, formula); @@ -1065,7 +1061,6 @@ bool StringInterpolatorImplementation::parse(const std::string &f) if (prev_string_start < f.length()) { string part = f.substr(prev_string_start); - debug("(stringinterpolator) last string \"%s\"\n", part.c_str()); strings_.push_back(part); } diff --git a/src/main.cc b/src/main.cc index 43fa296..8c19a4b 100644 --- a/src/main.cc +++ b/src/main.cc @@ -210,21 +210,40 @@ void list_shell_envs(Configuration *config, string meter_driver) meter = di.construct(mi); } - meter->printMeter(&t, - &ignore1, - &ignore2, config->separator, - &ignore3, - &envs, - &config->extra_constant_fields, - &config->selected_fields, - false); + printf("METER_DEVICE\n" + "METER_ID\n" + "METER_JSON\n" + "METER_MEDIA\n" + "METER_TYPE\n" + "METER_NAME\n" + "METER_RSSI_DBM\n" + "METER_TIMESTAMP\n" + "METER_TIMESTAMP_LT\n" + "METER_TIMESTAMP_UT\n" + "METER_TIMESTAMP_UTC\n"); - for (auto &e : envs) + for (auto &fi : meter->fieldInfos()) { - int p = e.find('='); - string key = e.substr(0,p); - printf("%s\n", key.c_str()); + if (fi.vname() == "") continue; + string name = fi.vname(); + std::transform(name.begin(), name.end(), name.begin(), ::toupper); + if (fi.xuantity() != Quantity::Text) + { + printf("METER_%s_%s\n",name.c_str(), unitToStringUpperCase(fi.defaultUnit()).c_str()); + } + else + { + printf("METER_%s\n",name.c_str()); + } } + + for (string &s : meter->extraConstantFields()) + { + string name = s; + std::transform(name.begin(), name.end(), name.begin(), ::toupper); + printf("METER_%s\n", name.c_str()); + } + } void list_fields(Configuration *config, string meter_driver) diff --git a/src/meters.cc b/src/meters.cc index 8440cc2..718118a 100644 --- a/src/meters.cc +++ b/src/meters.cc @@ -788,6 +788,11 @@ vector &MeterCommonImplementation::fieldInfos() return field_infos_; } +vector &MeterCommonImplementation::extraConstantFields() +{ + return extra_constant_fields_; +} + string MeterCommonImplementation::name() { return name_; @@ -1446,7 +1451,7 @@ void MeterCommonImplementation::processContent(Telegram *t) { } -void MeterCommonImplementation::setNumericValue(FieldInfo *fi, Unit u, double v) +void MeterCommonImplementation::setNumericValue(FieldInfo *fi, DVEntry *dve, Unit u, double v) { if (fi->hasSetNumericValueOverride()) { @@ -1456,8 +1461,18 @@ void MeterCommonImplementation::setNumericValue(FieldInfo *fi, Unit u, double v) } // Store value in default meter location for numeric values. - string field_name_no_unit = fi->vname(); - numeric_values_[pair(field_name_no_unit,fi->xuantity())] = NumericField(u, v, fi); + string field_name_no_unit; + + if (dve == NULL) + { + field_name_no_unit = fi->vname(); + } + else + { + field_name_no_unit = fi->generateFieldNameNoUnit(dve); + } + + numeric_values_[pair(field_name_no_unit, fi->xuantity())] = NumericField(u, v, fi); } void MeterCommonImplementation::setNumericValue(string vname, Unit u, double v) @@ -1470,7 +1485,7 @@ void MeterCommonImplementation::setNumericValue(string vname, Unit u, double v) warning("(meter) cannot set numeric value %g %s for non-existant field \"%s\" %s\n", v, unitToStringLowerCase(u).c_str(), vname.c_str(), toString(q)); return; } - setNumericValue(fi, u, v); + setNumericValue(fi, NULL, u, v); } bool MeterCommonImplementation::hasValue(FieldInfo *fi) @@ -1511,6 +1526,25 @@ double MeterCommonImplementation::getNumericValue(FieldInfo *fi, Unit to) return convert(nf.value, nf.unit, to); } +double MeterCommonImplementation::getNumericValue(string vname, Unit to) +{ + Quantity q = toQuantity(to); + FieldInfo *fi = findFieldInfo(vname, q); + + if (fi != NULL && fi->hasGetNumericValueOverride()) + { + return fi->getNumericValueOverride(to); + } + + pair key(vname,q); + if (numeric_values_.count(key) == 0) + { + return std::numeric_limits::quiet_NaN(); // This is translated into a null in the json. + } + NumericField &nf = numeric_values_[key]; + return convert(nf.value, nf.unit, to); +} + void MeterCommonImplementation::setStringValue(FieldInfo *fi, string v) { if (fi->hasSetStringValueOverride()) @@ -1718,7 +1752,7 @@ string FieldInfo::renderJson(Meter *m, DVEntry *dve) } else { - s += "\""+field_name+"_"+default_unit+"\":"+valueToString(m->getNumericValue(this, defaultUnit()), defaultUnit()); + s += "\""+field_name+"_"+default_unit+"\":"+valueToString(m->getNumericValue(field_name, defaultUnit()), defaultUnit()); } return s; @@ -2255,7 +2289,7 @@ void FieldInfo::performCalculation(Meter *m) assert(hasFormula()); double value = formula_->calculate(defaultUnit()); - m->setNumericValue(this, defaultUnit(), value); + m->setNumericValue(this, NULL, defaultUnit(), value); } bool FieldInfo::hasMatcher() @@ -2358,7 +2392,7 @@ bool FieldInfo::extractNumeric(Meter *m, Telegram *t, DVEntry *dve) unitToStringLowerCase(default_unit_).c_str(), extracted_double_value); } - m->setNumericValue(this, default_unit_, convert(extracted_double_value, decoded_unit, default_unit_)); + m->setNumericValue(this, dve, default_unit_, convert(extracted_double_value, decoded_unit, default_unit_)); t->addMoreExplanation(dve->offset, renderJson(m, dve)); found = true; } diff --git a/src/meters.h b/src/meters.h index b088ffe..d2ba239 100644 --- a/src/meters.h +++ b/src/meters.h @@ -411,6 +411,7 @@ struct Meter virtual string idsc() = 0; // This meter can report these fields, like total_m3, temp_c. virtual vector &fieldInfos() = 0; + virtual vector &extraConstantFields() = 0; // Either the default fields specified in the driver, or override fields in the meter configuration file. virtual vector &selectedFields() = 0; virtual void setSelectedFields(vector &f) = 0; @@ -428,7 +429,8 @@ struct Meter virtual bool usesPolling() = 0; virtual void setNumericValue(string vname, Unit u, double v) = 0; - virtual void setNumericValue(FieldInfo *fi, Unit u, double v) = 0; + virtual void setNumericValue(FieldInfo *fi, DVEntry *dve, Unit u, double v) = 0; + virtual double getNumericValue(string vname, Unit u) = 0; virtual double getNumericValue(FieldInfo *fi, Unit u) = 0; virtual void setStringValue(FieldInfo *fi, std::string v) = 0; virtual std::string getStringValue(FieldInfo *fi) = 0; diff --git a/src/meters_common_implementation.h b/src/meters_common_implementation.h index 30fa676..906d830 100644 --- a/src/meters_common_implementation.h +++ b/src/meters_common_implementation.h @@ -60,6 +60,7 @@ struct MeterCommonImplementation : public virtual Meter vector& ids(); string idsc(); vector &fieldInfos(); + vector &extraConstantFields(); string name(); MeterDriver driver(); DriverName driverName(); @@ -250,7 +251,8 @@ protected: virtual void processContent(Telegram *t); void setNumericValue(string vname, Unit u, double v); - void setNumericValue(FieldInfo *fi, Unit u, double v); + void setNumericValue(FieldInfo *fi, DVEntry *dve, Unit u, double v); + double getNumericValue(string vname, Unit u); double getNumericValue(FieldInfo *fi, Unit u); void setStringValue(FieldInfo *fi, std::string v); std::string getStringValue(FieldInfo *fi); diff --git a/tests/test_additional_json.sh b/tests/test_additional_json.sh index 602b617..1d912a1 100755 --- a/tests/test_additional_json.sh +++ b/tests/test_additional_json.sh @@ -20,6 +20,11 @@ then then echo "OK: $TESTNAME" TESTRESULT="OK" + else + if [ "$USE_MELD" = "true" ] + then + meld $TEST/test_expected.txt $TEST/test_response.txt + fi fi fi @@ -30,11 +35,11 @@ if [ "$TESTRESULT" = "ERROR" ]; then echo ERROR: $TESTNAME; exit 1; fi TESTNAME="Test additional shell envs from cmdline" TESTRESULT="ERROR" -$PROG --json_floor=5 --json_house="alfa beta" --listenvs=multical21 > $TEST/test_output.txt 2> $TEST/test_stderr.txt +$PROG --json_floor=5 --json_house="alfa beta" --listenvs=multical21 2> $TEST/test_stderr.txt | sort > $TEST/test_output.txt ENVS=$(cat $TEST/test_output.txt | tr '\n' ' ') -cat > $TEST/test_expected.txt < $TEST/test_expected.txt METER_JSON METER_ID METER_NAME @@ -58,8 +63,6 @@ METER_TIME_DRY METER_TIME_REVERSED METER_TIME_LEAKING METER_TIME_BURSTING -METER_floor -METER_house EOF diff $TEST/test_expected.txt $TEST/test_output.txt @@ -67,6 +70,11 @@ if [ "$?" = "0" ] then echo "OK: $TESTNAME" TESTRESULT="OK" +else + if [ "$USE_MELD" = "true" ] + then + meld $TEST/test_expected.txt $TEST/test_output.txt + fi fi if [ "$TESTRESULT" = "ERROR" ]; then echo ERROR: $TESTNAME; exit 1; fi diff --git a/tests/test_drivers.sh b/tests/test_drivers.sh index 7d21617..9ee1173 100755 --- a/tests/test_drivers.sh +++ b/tests/test_drivers.sh @@ -42,6 +42,10 @@ do TESTRESULT="OK" else TESTRESULT="ERROR" + if [ "$USE_MELD" = "true" ] + then + meld $TEST/test_expected_json.txt $TEST/test_response_json.txt + fi fi else echo "wmbusmeters returned error code: $?" diff --git a/tests/test_list_envs.sh b/tests/test_list_envs.sh index a8d4bba..16a90be 100755 --- a/tests/test_list_envs.sh +++ b/tests/test_list_envs.sh @@ -21,6 +21,7 @@ METER_TIMESTAMP_UTC METER_TIMESTAMP_UT METER_TIMESTAMP_LT METER_DEVICE +METER_DEVICE_DATE_TIME METER_RSSI_DBM METER_TOTAL_ENERGY_CONSUMPTION_KWH METER_CURRENT_POWER_CONSUMPTION_KW @@ -29,7 +30,6 @@ METER_CURRENT_POWER_PRODUCTION_KW METER_VOLTAGE_AT_PHASE_1_Volt METER_VOLTAGE_AT_PHASE_2_Volt METER_VOLTAGE_AT_PHASE_3_Volt -METER_DEVICE_DATE_TIME METER_TOTAL_ENERGY_CONSUMPTION_TARIFF_1_KWH METER_TOTAL_ENERGY_CONSUMPTION_TARIFF_2_KWH METER_TOTAL_ENERGY_CONSUMPTION_TARIFF_3_KWH @@ -45,6 +45,11 @@ then then echo OK: $TESTNAME TESTRESULT="OK" + else + if [ "$USE_MELD" = "true" ] + then + meld $TEST/test_expected.txt $TEST/test_output.txt + fi fi fi @@ -90,6 +95,11 @@ then then echo OK: $TESTNAME TESTRESULT="OK" + else + if [ "$USE_MELD" = "true" ] + then + meld $TEST/test_expected.txt $TEST/test_output.txt + fi fi fi