Add field_ prefix which is equivalent to json_ prefix.

pull/324/head
Fredrik Öhrström 2021-08-01 23:12:52 +02:00
rodzic 2c83c51db1
commit e4d3ec1e7e
15 zmienionych plików z 100 dodań i 37 usunięć

Wyświetl plik

@ -1,4 +1,7 @@
Added the field timestamp_ut to print the existing timestamp field
using unix timestamp seconds since 1970-01-01.
Daniel Glaser added support for the Aventies water meter! Thanks Daniel! Daniel Glaser added support for the Aventies water meter! Thanks Daniel!
Mblnk added support for Qundis QWater5.5. Thanks Mblnk! Mblnk added support for Qundis QWater5.5. Thanks Mblnk!

Wyświetl plik

@ -126,11 +126,11 @@ You can add the static json data `"address":"RoadenRd 456","city":"Stockholm"` t
wmbusmeters.conf setting: wmbusmeters.conf setting:
```ini ```ini
json_address=RoadenRd 456 field_address=RoadenRd 456
json_city=Stockholm field_city=Stockholm
``` ```
If you add `json_floor=5` to the meter file `MyTapWater`, then you can have the meter tailored static json `"floor":"5"` added to telegrams handled by that particular meter. If you add `field_floor=5` to the meter file `MyTapWater`, then you can have the meter tailored static json `"floor":"5"` added to telegrams handled by that particular meter. (The old prefix json_ still works.)
If you are running on a Raspberry PI with flash storage and you relay the data to If you are running on a Raspberry PI with flash storage and you relay the data to
another computer using a shell command (`mosquitto_pub` or `curl` or similar) then you might want to remove `meterfiles` and `meterfilesaction` to minimize the writes to the local flash file system. another computer using a shell command (`mosquitto_pub` or `curl` or similar) then you might want to remove `meterfiles` and `meterfilesaction` to minimize the writes to the local flash file system.

Wyświetl plik

@ -1,2 +1,2 @@
telegram=|2A442D2C998734761B168D2091D37CAC21576C78|02FF207100041308190000441308190000615B7F616713| telegram=|2A442D2C998734761B168D2091D37CAC21576C78|02FF207100041308190000441308190000615B7F616713|
{"media":"cold water","meter":"multical21","name":"MyTapWater","id":"76348799","total_m3":6.408,"target_m3":6.408,"max_flow_m3h":0,"flow_temperature_c":127,"external_temperature_c":19,"current_status":"DRY","time_dry":"22-31 days","time_reversed":"","time_leaking":"","time_bursting":"","timestamp":"1111-11-11T11:11:11Z","floor":"5","address":"RoodRd 42"} {"media":"cold water","meter":"multical21","name":"MyTapWater","id":"76348799","total_m3":6.408,"target_m3":6.408,"max_flow_m3h":0,"flow_temperature_c":127,"external_temperature_c":19,"current_status":"DRY","time_dry":"22-31 days","time_reversed":"","time_leaking":"","time_bursting":"","timestamp":"1111-11-11T11:11:11Z","floor":"5","address":"RoodRd 42","city":"Stockholm"}

Wyświetl plik

@ -440,16 +440,22 @@ shared_ptr<Configuration> parseCommandLine(int argc, char **argv) {
i++; i++;
continue; continue;
} }
if (!strncmp(argv[i], "--json_", 7)) if (!strncmp(argv[i], "--json_", 7) ||
!strncmp(argv[i], "--field_", 8))
{ {
// For example: --json_floor=42 // For example: --json_floor=42
string json = string(argv[i]+7); // or --field_floor=42
if (json == "") { // they are equivalent.
error("The json command cannot be empty.\n"); int off = 7;
if (!strncmp(argv[i], "--field_", 8)) { off = 8; }
string extra_constant_field = string(argv[i]+off);
if (extra_constant_field == "") {
error("The extra constant field command cannot be empty.\n");
} }
// The extra "floor"="42" will be pushed to the json. // The extra "floor"="42" will be pushed to the json.
debug("Added json %s\n", json.c_str()); debug("Added extra constant field %s\n", extra_constant_field.c_str());
c->jsons.push_back(json); c->extra_constant_fields.push_back(extra_constant_field);
i++; i++;
continue; continue;
} }

Wyświetl plik

@ -58,7 +58,7 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
int bps {}; int bps {};
vector<string> telegram_shells; vector<string> telegram_shells;
vector<string> alarm_shells; vector<string> alarm_shells;
vector<string> jsons; vector<string> extra_constant_fields;
debug("(config) loading meter file %s\n", file.c_str()); debug("(config) loading meter file %s\n", file.c_str());
for (;;) { for (;;) {
@ -118,10 +118,13 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
alarm_shells.push_back(p.second); alarm_shells.push_back(p.second);
} }
else else
if (startsWith(p.first, "json_")) if (startsWith(p.first, "json_") ||
startsWith(p.first, "field_"))
{ {
string keyvalue = p.first.substr(5)+"="+p.second; int off = 5;
jsons.push_back(keyvalue); if (startsWith(p.first, "field_")) { off = 6; }
string keyvalue = p.first.substr(off)+"="+p.second;
extra_constant_fields.push_back(keyvalue);
} }
else else
warning("Found invalid key \"%s\" in meter config file\n", p.first.c_str()); warning("Found invalid key \"%s\" in meter config file\n", p.first.c_str());
@ -182,7 +185,7 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
} }
if (use) { if (use) {
vector<string> ids = splitMatchExpressions(id); vector<string> ids = splitMatchExpressions(id);
c->meters.push_back(MeterInfo(bus, name, mt, "", ids, key, modes, bps, telegram_shells, jsons)); c->meters.push_back(MeterInfo(bus, name, mt, "", ids, key, modes, bps, telegram_shells, extra_constant_fields));
} }
return; return;
@ -562,6 +565,19 @@ void handleSelectedFields(Configuration *c, string s)
} }
} }
void handleAddedFields(Configuration *c, string s)
{
char buf[s.length()+1];
strcpy(buf, s.c_str());
char *saveptr {};
const char *tok = strtok_r(buf, ",", &saveptr);
while (tok != NULL)
{
c->added_fields.push_back(tok);
tok = strtok_r(NULL, ",", &saveptr);
}
}
void handleShell(Configuration *c, string cmdline) void handleShell(Configuration *c, string cmdline)
{ {
c->telegram_shells.push_back(cmdline); c->telegram_shells.push_back(cmdline);
@ -572,9 +588,9 @@ void handleAlarmShell(Configuration *c, string cmdline)
c->alarm_shells.push_back(cmdline); c->alarm_shells.push_back(cmdline);
} }
void handleJson(Configuration *c, string json) void handleExtraConstantField(Configuration *c, string field)
{ {
c->jsons.push_back(json); c->extra_constant_fields.push_back(field);
} }
shared_ptr<Configuration> loadConfiguration(string root, string device_override, string listento_override) shared_ptr<Configuration> loadConfiguration(string root, string device_override, string listento_override)
@ -620,14 +636,18 @@ shared_ptr<Configuration> loadConfiguration(string root, string device_override,
else if (p.first == "addconversions") handleConversions(c, p.second); else if (p.first == "addconversions") handleConversions(c, p.second);
else if (p.first == "logtimestamps") handleLogTimestamps(c, p.second); else if (p.first == "logtimestamps") handleLogTimestamps(c, p.second);
else if (p.first == "selectfields") handleSelectedFields(c, p.second); else if (p.first == "selectfields") handleSelectedFields(c, p.second);
else if (p.first == "addfields") handleAddedFields(c, p.second);
else if (p.first == "shell") handleShell(c, p.second); else if (p.first == "shell") handleShell(c, p.second);
else if (p.first == "resetafter") handleResetAfter(c, p.second); else if (p.first == "resetafter") handleResetAfter(c, p.second);
else if (p.first == "alarmshell") handleAlarmShell(c, p.second); else if (p.first == "alarmshell") handleAlarmShell(c, p.second);
else if (startsWith(p.first, "json_")) else if (startsWith(p.first, "json_") ||
startsWith(p.first, "field_"))
{ {
string s = p.first.substr(5); int off = 5;
if (startsWith(p.first, "field_")) { off = 6; }
string s = p.first.substr(off);
string keyvalue = s+"="+p.second; string keyvalue = s+"="+p.second;
handleJson(c, keyvalue); handleExtraConstantField(c, keyvalue);
} }
else else
{ {

Wyświetl plik

@ -110,8 +110,10 @@ struct Configuration
bool no_init {}; bool no_init {};
std::vector<Unit> conversions; std::vector<Unit> conversions;
std::vector<std::string> selected_fields; std::vector<std::string> selected_fields;
std::vector<std::string> added_fields;
std::vector<MeterInfo> meters; std::vector<MeterInfo> meters;
std::vector<std::string> jsons; // Additional jsons to always add. std::vector<std::string> extra_constant_fields; // Additional constant fields to always add to json.
// These extra constant fields can also be part of selected with selectfields or added with addfields.
~Configuration() = default; ~Configuration() = default;
}; };
@ -120,6 +122,7 @@ shared_ptr<Configuration> loadConfiguration(string root, string device_override,
void handleConversions(Configuration *c, string s); void handleConversions(Configuration *c, string s);
void handleSelectedFields(Configuration *c, string s); void handleSelectedFields(Configuration *c, string s);
void handleAddedFields(Configuration *c, string s);
bool handleDevice(Configuration *c, string devicefile); bool handleDevice(Configuration *c, string devicefile);
enum class LinkModeCalculationResultType enum class LinkModeCalculationResultType

Wyświetl plik

@ -187,8 +187,9 @@ void list_shell_envs(Configuration *config, string meter_driver)
&ignore2, config->separator, &ignore2, config->separator,
&ignore3, &ignore3,
&envs, &envs,
&config->jsons, &config->extra_constant_fields,
&config->selected_fields); &config->selected_fields,
&config->added_fields);
for (auto &e : envs) for (auto &e : envs)
{ {
@ -219,7 +220,11 @@ void list_fields(Configuration *config, string meter_driver)
string meterr = padLeft("meter", width); string meterr = padLeft("meter", width);
printf("%s Meter driver.\n", meterr.c_str()); printf("%s Meter driver.\n", meterr.c_str());
string timestamp = padLeft("timestamp", width); string timestamp = padLeft("timestamp", width);
printf("%s Timestamp when wmbusmeters received the telegram.\n", timestamp.c_str()); printf("%s Timestamp when wmbusmeters received the telegram. Local time for hr/fields UTC for json.\n", timestamp.c_str());
string timestamp_ut = padLeft("timestamp_ut", width);
printf("%s Unix timestamp when wmbusmeters received the telegram.\n", timestamp_ut.c_str());
string timestamp_lt = padLeft("timestamp_l", width);
printf("%s Unix timestamp when wmbusmeters received the telegram.\n", timestamp_ut.c_str());
string device = padLeft("device", width); string device = padLeft("device", width);
printf("%s The wmbus device that received the telegram.\n", device.c_str()); printf("%s The wmbus device that received the telegram.\n", device.c_str());
string rssi = padLeft("rssi_dbm", width); string rssi = padLeft("rssi_dbm", width);
@ -401,7 +406,7 @@ bool start(Configuration *config)
meter_manager_->whenMeterUpdated( meter_manager_->whenMeterUpdated(
[&](Telegram *t,Meter *meter) [&](Telegram *t,Meter *meter)
{ {
printer_->print(t, meter, &config->jsons, &config->selected_fields); printer_->print(t, meter, &config->extra_constant_fields, &config->selected_fields, &config->added_fields);
oneshot_check(config, t, meter); oneshot_check(config, t, meter);
} }
); );

Wyświetl plik

@ -404,7 +404,7 @@ string MeterCommonImplementation::unixTimestampOfUpdate()
{ {
char ut[40]; char ut[40];
memset(ut, 0, sizeof(ut)); memset(ut, 0, sizeof(ut));
sprintf(ut, "%zu", datetime_of_update_); snprintf(ut, sizeof(ut)-1, "%zu", datetime_of_update_);
return string(ut); return string(ut);
} }
@ -650,6 +650,16 @@ string concatFields(Meter *m, Telegram *t, char c, vector<Print> &prints, vector
s += m->datetimeOfUpdateHumanReadable() + c; s += m->datetimeOfUpdateHumanReadable() + c;
continue; continue;
} }
if (field == "timestamp_lt")
{
s += m->datetimeOfUpdateHumanReadable() + c;
continue;
}
if (field == "timestamp_utc")
{
s += m->datetimeOfUpdateRobot() + c;
continue;
}
if (field == "timestamp_ut") if (field == "timestamp_ut")
{ {
s += m->unixTimestampOfUpdate() + c; s += m->unixTimestampOfUpdate() + c;
@ -767,7 +777,8 @@ void MeterCommonImplementation::printMeter(Telegram *t,
string *json, string *json,
vector<string> *envs, vector<string> *envs,
vector<string> *more_json, vector<string> *more_json,
vector<string> *selected_fields) vector<string> *selected_fields,
vector<string> *added_fields)
{ {
*human_readable = concatFields(this, t, '\t', prints_, conversions_, true, selected_fields); *human_readable = concatFields(this, t, '\t', prints_, conversions_, true, selected_fields);
*fields = concatFields(this, t, separator, prints_, conversions_, false, selected_fields); *fields = concatFields(this, t, separator, prints_, conversions_, false, selected_fields);
@ -853,6 +864,9 @@ void MeterCommonImplementation::printMeter(Telegram *t,
envs->push_back(string("METER_MEDIA=")+media); envs->push_back(string("METER_MEDIA=")+media);
envs->push_back(string("METER_TYPE=")+meterDriver()); envs->push_back(string("METER_TYPE=")+meterDriver());
envs->push_back(string("METER_TIMESTAMP=")+datetimeOfUpdateRobot()); envs->push_back(string("METER_TIMESTAMP=")+datetimeOfUpdateRobot());
envs->push_back(string("METER_TIMESTAMP_UTC=")+datetimeOfUpdateRobot());
envs->push_back(string("METER_TIMESTAMP_UT=")+unixTimestampOfUpdate());
envs->push_back(string("METER_TIMESTAMP_LT=")+datetimeOfUpdateHumanReadable());
if (t->about.device != "") if (t->about.device != "")
{ {
envs->push_back(string("METER_DEVICE=")+t->about.device); envs->push_back(string("METER_DEVICE=")+t->about.device);

Wyświetl plik

@ -230,7 +230,8 @@ struct Meter
string *json, string *json,
vector<string> *envs, vector<string> *envs,
vector<string> *more_json, vector<string> *more_json,
vector<string> *selected_fields) = 0; vector<string> *selected_fields,
vector<string> *added_fields) = 0;
// The handleTelegram expects an input_frame where the DLL crcs have been removed. // The handleTelegram expects an input_frame where the DLL crcs have been removed.
// Returns true of this meter handled this telegram! // Returns true of this meter handled this telegram!

Wyświetl plik

@ -89,7 +89,8 @@ protected:
string *json, string *json,
vector<string> *envs, vector<string> *envs,
vector<string> *more_json, // Add this json "key"="value" strings. vector<string> *more_json, // Add this json "key"="value" strings.
vector<string> *selected_fields); // Only print these fields. Json always everything. vector<string> *selected_fields, // Only print these fields. Json always everything.
vector<string> *added_fields); // Added these fields for printing.
virtual void processContent(Telegram *t) = 0; virtual void processContent(Telegram *t) = 0;

Wyświetl plik

@ -42,13 +42,14 @@ Printer::Printer(bool json, bool fields, char separator,
void Printer::print(Telegram *t, Meter *meter, void Printer::print(Telegram *t, Meter *meter,
vector<string> *more_json, vector<string> *more_json,
vector<string> *selected_fields) vector<string> *selected_fields,
vector<string> *added_fields)
{ {
string human_readable, fields, json; string human_readable, fields, json;
vector<string> envs; vector<string> envs;
bool printed = false; bool printed = false;
meter->printMeter(t, &human_readable, &fields, separator_, &json, &envs, more_json, selected_fields); meter->printMeter(t, &human_readable, &fields, separator_, &json, &envs, more_json, selected_fields, added_fields);
if (shell_cmdlines_.size() > 0 || meter->shellCmdlines().size() > 0) { if (shell_cmdlines_.size() > 0 || meter->shellCmdlines().size() > 0) {
printShells(meter, envs); printShells(meter, envs);

Wyświetl plik

@ -32,7 +32,7 @@ struct Printer {
MeterFileNaming naming, MeterFileNaming naming,
MeterFileTimestamp timestamp); MeterFileTimestamp timestamp);
void print(Telegram *t, Meter *meter, vector<string> *more_json, vector<string> *selected_fields); void print(Telegram *t, Meter *meter, vector<string> *more_json, vector<string> *selected_fields, vector<string> *added_fields);
private: private:

Wyświetl plik

@ -2,5 +2,7 @@ loglevel=debug
device=must_be_overriden device=must_be_overriden
logtelegrams=false logtelegrams=false
format=json format=json
shell=echo METER =="$METER_JSON"== =="$METER_address"== =="$METER_floor"== > /tmp/wmbusmeters_meter_additional_json_test shell=echo METER =="$METER_JSON"== =="$METER_address"== =="$METER_city"== =="$METER_floor"== =="$METER_elevator"== > /tmp/wmbusmeters_meter_additional_json_test
json_address=RoodRd 42 # The json_ prefix and field_ prefix are equivalent.
json_address=RoodRd 42
field_city=Stockholm

Wyświetl plik

@ -3,3 +3,4 @@ type=supercom587
id=12345678 id=12345678
key= key=
json_floor=5 json_floor=5
field_elevator=ABC

Wyświetl plik

@ -8,7 +8,7 @@ TESTNAME="Test additional json from cmdline"
TESTRESULT="ERROR" TESTRESULT="ERROR"
cat simulations/simulation_additional_json.txt | grep '^{' > $TEST/test_expected.txt cat simulations/simulation_additional_json.txt | grep '^{' > $TEST/test_expected.txt
$PROG --format=json --json_floor=5 --json_address="RoodRd 42" simulations/simulation_additional_json.txt \ $PROG --format=json --json_floor=5 --json_address="RoodRd 42" --field_city="Stockholm" simulations/simulation_additional_json.txt \
MyTapWater multical21 76348799 "" \ MyTapWater multical21 76348799 "" \
> $TEST/test_output.txt 2> $TEST/test_stderr.txt > $TEST/test_output.txt 2> $TEST/test_stderr.txt
@ -41,6 +41,9 @@ METER_NAME
METER_MEDIA METER_MEDIA
METER_TYPE METER_TYPE
METER_TIMESTAMP METER_TIMESTAMP
METER_TIMESTAMP_UTC
METER_TIMESTAMP_UT
METER_TIMESTAMP_LT
METER_DEVICE METER_DEVICE
METER_RSSI_DBM METER_RSSI_DBM
METER_TOTAL_M3 METER_TOTAL_M3
@ -69,16 +72,19 @@ if [ "$TESTRESULT" = "ERROR" ]; then echo ERROR: $TESTNAME; exit 1; fi
TESTNAME="Test additional json from wmbusmeters.conf and from meter file" TESTNAME="Test additional json from wmbusmeters.conf and from meter file"
TESTRESULT="ERROR" TESTRESULT="ERROR"
$PROG --useconfig=tests/config6 --device=simulations/simulation_shell.txt > $TEST/test_output.txt 2> $TEST/test_stderr.txt $PROG --debug --useconfig=tests/config6 --device=simulations/simulation_shell.txt > $TEST/test_output.txt 2> $TEST/test_stderr.txt
if [ "$?" = "0" ] if [ "$?" = "0" ]
then then
INFO=$(cat /tmp/wmbusmeters_meter_additional_json_test | sed 's/"timestamp":"....-..-..T..:..:..Z"/"timestamp":"1111-11-11T11:11:11Z"/') INFO=$(cat /tmp/wmbusmeters_meter_additional_json_test | sed 's/"timestamp":"....-..-..T..:..:..Z"/"timestamp":"1111-11-11T11:11:11Z"/')
EXPECTED=$(echo 'METER =={"media":"warm water","meter":"supercom587","name":"Water","id":"12345678","total_m3":5.548,"timestamp":"1111-11-11T11:11:11Z","floor":"5","address":"RoodRd 42"}== ==RoodRd 42== ==5==') EXPECTED=$(echo 'METER =={"media":"warm water","meter":"supercom587","name":"Water","id":"12345678","total_m3":5.548,"timestamp":"1111-11-11T11:11:11Z","floor":"5","elevator":"ABC","address":"RoodRd 42","city":"Stockholm"}== ==RoodRd 42== ==Stockholm== ==5== ==ABC==')
if [ "$INFO" = "$EXPECTED" ] if [ "$INFO" = "$EXPECTED" ]
then then
echo "OK: $TESTNAME" echo "OK: $TESTNAME"
TESTRESULT="OK" TESTRESULT="OK"
else
echo "INFO =>$INFO<"
echo "EXPECTED=>$EXPECTED<"
fi fi
fi fi