From 1c987f3f0e1f019b838b03e5eb314b03da15dfff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20=C3=96hrstr=C3=B6m?= Date: Sun, 24 Nov 2024 18:37:36 +0100 Subject: [PATCH] Add metershell or --detailedfirst to print reference from value to field in driver. E.g. total_m3=3 and total_m3_field=1 --- src/cmdline.cc | 5 ++++ src/config.cc | 16 +++++++++++++ src/config.h | 1 + src/main.cc | 7 +++++- src/meters.cc | 28 +++++++++++++++++++--- src/printer.cc | 8 ++++--- src/wmbus.cc | 12 ++++++++++ src/wmbus.h | 2 ++ test.sh | 3 +++ tests/test_detailed_first.sh | 46 ++++++++++++++++++++++++++++++++++++ 10 files changed, 121 insertions(+), 7 deletions(-) create mode 100755 tests/test_detailed_first.sh diff --git a/src/cmdline.cc b/src/cmdline.cc index 1ff7383..c8b488f 100644 --- a/src/cmdline.cc +++ b/src/cmdline.cc @@ -504,6 +504,11 @@ static shared_ptr parseNormalCommandLine(Configuration *c, int ar i++; continue; } + if (!strcmp(argv[i], "--detailedfirst")) { + c->detailed_first = true; + i++; + continue; + } if (!strncmp(argv[i], "--shell=", 8)) { string cmd = string(argv[i]+8); if (cmd == "") { diff --git a/src/config.cc b/src/config.cc index d2e96cd..34801e3 100644 --- a/src/config.cc +++ b/src/config.cc @@ -293,6 +293,21 @@ void handleIgnoreDuplicateTelegrams(Configuration *c, string value) } } +void handleDetailedFirst(Configuration *c, string value) +{ + if (value == "true") + { + c->detailed_first = true; + } + else if (value == "false") + { + c->detailed_first = false; + } + else { + warning("detailedfirst should be either true or false, not \"%s\"\n", value.c_str()); + } +} + void handleResetAfter(Configuration *c, string s) { if (s.length() >= 1) @@ -709,6 +724,7 @@ shared_ptr loadConfiguration(string root, ConfigOverrides overrid if (p.first == "loglevel") handleLoglevel(c, p.second); else if (p.first == "internaltesting") handleInternalTesting(c, p.second); else if (p.first == "ignoreduplicates") handleIgnoreDuplicateTelegrams(c, p.second); + else if (p.first == "detailedfirst") handleDetailedFirst(c, p.second); else if (p.first == "device") handleDeviceOrHex(c, p.second); else if (p.first == "donotprobe") handleDoNotProbe(c, p.second); else if (p.first == "listento") handleListenTo(c, p.second); diff --git a/src/config.h b/src/config.h index 3e691f3..e981a13 100644 --- a/src/config.h +++ b/src/config.h @@ -95,6 +95,7 @@ struct Configuration bool use_logfile {}; bool use_stderr_for_log = true; // Default is to use stderr for logging. bool ignore_duplicate_telegrams = true; // Default is to ignore duplicates. + bool detailed_first = false; // Print additional lines in telegram mapping back to driver field. std::string logfile; bool json {}; bool pretty_print_json {}; diff --git a/src/main.cc b/src/main.cc index 9e2985f..d5e7d48 100644 --- a/src/main.cc +++ b/src/main.cc @@ -570,7 +570,12 @@ bool start(Configuration *config) stderrEnabled(config->use_stderr_for_log); setAlarmShells(config->alarm_shells); setIgnoreDuplicateTelegrams(config->ignore_duplicate_telegrams); - + setDetailedFirst(config->detailed_first); + if (config->new_meter_shells.size() > 0) + { + // We have metershells, force detailed first telegram. + setDetailedFirst(true); + } log_start_information(config); // Create the manager monitoring all filedescriptors and invoking callbacks. diff --git a/src/meters.cc b/src/meters.cc index fe42591..f9f07ce 100644 --- a/src/meters.cc +++ b/src/meters.cc @@ -1912,6 +1912,8 @@ void MeterCommonImplementation::printMeter(Telegram *t, vector *selected_fields, bool pretty_print_json) { + bool first = !t->meter->hasReceivedFirstTelegram(); + *human_readable = concatFields(this, t, '\t', field_infos_, true, selected_fields, extra_constant_fields); *fields = concatFields(this, t, separator, field_infos_, false, selected_fields, extra_constant_fields); @@ -1964,18 +1966,29 @@ void MeterCommonImplementation::printMeter(Telegram *t, string out = nf.field_info->renderJson(this, &nf.dv_entry); s += indent+out+","+newline; + + if (first && getDetailedFirst()) + { + size_t pos = out.find("\":"); + if (pos != string::npos) + { + string rule = out.substr(0, pos)+"_field\":"+to_string(nf.field_info->index()); + s += indent+rule+","+newline; + } + } } for (auto &p : string_values_) { string vname = p.first; StringField& sf = p.second; + string out; if (sf.field_info->printProperties().hasHIDE()) continue; if (sf.field_info->printProperties().hasSTATUS()) { string in = getStatusField(sf.field_info); - string out = tostrprintf("\"%s\":\"%s\"", vname.c_str(), in.c_str()); + out = tostrprintf("\"%s\":\"%s\"", vname.c_str(), in.c_str()); s += indent+out+","+newline; } else @@ -1983,15 +1996,24 @@ void MeterCommonImplementation::printMeter(Telegram *t, if (sf.value == "null") { // The string "null" translates to actual json null. - string out = tostrprintf("\"%s\":null", vname.c_str()); + out = tostrprintf("\"%s\":null", vname.c_str()); s += indent+out+","+newline; } else { - string out = tostrprintf("\"%s\":\"%s\"", vname.c_str(), sf.value.c_str()); + out = tostrprintf("\"%s\":\"%s\"", vname.c_str(), sf.value.c_str()); s += indent+out+","+newline; } } + if (first && getDetailedFirst()) + { + size_t pos = out.find("\":"); + if (pos != string::npos) + { + string rule = out.substr(0, pos)+"_field\":"+to_string(sf.field_info->index()); + s += indent+rule+","+newline; + } + } } s += indent+"\"timestamp\":\""+datetimeOfUpdateRobot()+"\""; diff --git a/src/printer.cc b/src/printer.cc index b171842..bfdc635 100644 --- a/src/printer.cc +++ b/src/printer.cc @@ -53,12 +53,14 @@ void Printer::print(Telegram *t, Meter *meter, meter->printMeter(t, &human_readable, &fields, separator_, &json, &envs, more_json, selected_fields, pretty_print_json_); - if (!meter->hasReceivedFirstTelegram() && - (new_meter_shell_cmdlines_.size() > 0 || meter->shellCmdlinesMeterAdded().size() > 0)) + if (!meter->hasReceivedFirstTelegram()) { meter->markFirstTelegramReceived(); envs.push_back("METER_FIRST_TELEGRAM=true"); - printNewMeterShells(meter, envs); + if (new_meter_shell_cmdlines_.size() > 0 || meter->shellCmdlinesMeterAdded().size() > 0) + { + printNewMeterShells(meter, envs); + } } else { diff --git a/src/wmbus.cc b/src/wmbus.cc index d807993..0879560 100644 --- a/src/wmbus.cc +++ b/src/wmbus.cc @@ -4135,6 +4135,18 @@ void setIgnoreDuplicateTelegrams(bool idt) ignore_duplicate_telegrams_ = idt; } +static bool detailed_first_ = false; + +void setDetailedFirst(bool df) +{ + detailed_first_ = df; +} + +bool getDetailedFirst() +{ + return detailed_first_; +} + bool BusDeviceCommonImplementation::handleTelegram(AboutTelegram &about, vector frame) { bool handled = false; diff --git a/src/wmbus.h b/src/wmbus.h index fb22c65..a39afd7 100644 --- a/src/wmbus.h +++ b/src/wmbus.h @@ -86,6 +86,8 @@ const char *toLowerCaseString(BusDeviceType t); BusDeviceType toBusDeviceType(string &t); void setIgnoreDuplicateTelegrams(bool idt); +void setDetailedFirst(bool df); +bool getDetailedFirst(); // In link mode S1, is used when both the transmitter and receiver are stationary. // It can be transmitted relatively seldom. diff --git a/test.sh b/test.sh index f83493d..9633342 100755 --- a/test.sh +++ b/test.sh @@ -45,6 +45,9 @@ if [ "$?" != "0" ]; then RC="1"; fi ./tests/test_list_envs.sh $PROG if [ "$?" != "0" ]; then RC="1"; fi +./tests/test_detailed_first.sh $PROG +if [ "$?" != "0" ]; then RC="1"; fi + #tests/test_unknown.sh $PROG #if [ "$?" != "0" ]; then RC="1"; fi diff --git a/tests/test_detailed_first.sh b/tests/test_detailed_first.sh new file mode 100755 index 0000000..7312f99 --- /dev/null +++ b/tests/test_detailed_first.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +PROG="$1" + +mkdir -p testoutput +TEST=testoutput + +TESTNAME="Test detailed first telegram" +TESTRESULT="ERROR" + +$PROG --detailedfirst --format=json 1844AE4C4455223368077A55000000_041389E20100023B0000 Gurka iperl 33225544 NOKEY | jq . --sort-keys | grep -v timestamp > $TEST/test_output.txt 2>&1 + +cat < $TEST/test_expected.txt +{ + "_": "telegram", + "id": "33225544", + "max_flow_m3h": 0, + "max_flow_m3h_field": 1, + "media": "water", + "meter": "iperl", + "name": "Gurka", + "total_m3": 123.529, + "total_m3_field": 0 +} +EOF + +if [ "$?" = "0" ] +then + diff $TEST/test_expected.txt $TEST/test_output.txt + 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 +fi + +if [ "$TESTRESULT" = "ERROR" ] +then + echo ERROR: $TESTNAME + exit 1 +fi