kopia lustrzana https://github.com/weetmuts/wmbusmeters
Add field_ prefix which is equivalent to json_ prefix.
rodzic
2c83c51db1
commit
e4d3ec1e7e
3
CHANGES
3
CHANGES
|
@ -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!
|
||||
|
||||
Mblnk added support for Qundis QWater5.5. Thanks Mblnk!
|
||||
|
|
|
@ -126,11 +126,11 @@ You can add the static json data `"address":"RoadenRd 456","city":"Stockholm"` t
|
|||
wmbusmeters.conf setting:
|
||||
|
||||
```ini
|
||||
json_address=RoadenRd 456
|
||||
json_city=Stockholm
|
||||
field_address=RoadenRd 456
|
||||
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
|
||||
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.
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
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"}
|
||||
|
|
|
@ -440,16 +440,22 @@ shared_ptr<Configuration> parseCommandLine(int argc, char **argv) {
|
|||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(argv[i], "--json_", 7))
|
||||
if (!strncmp(argv[i], "--json_", 7) ||
|
||||
!strncmp(argv[i], "--field_", 8))
|
||||
{
|
||||
// For example: --json_floor=42
|
||||
string json = string(argv[i]+7);
|
||||
if (json == "") {
|
||||
error("The json command cannot be empty.\n");
|
||||
// or --field_floor=42
|
||||
// they are equivalent.
|
||||
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.
|
||||
debug("Added json %s\n", json.c_str());
|
||||
c->jsons.push_back(json);
|
||||
debug("Added extra constant field %s\n", extra_constant_field.c_str());
|
||||
c->extra_constant_fields.push_back(extra_constant_field);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
|
|||
int bps {};
|
||||
vector<string> telegram_shells;
|
||||
vector<string> alarm_shells;
|
||||
vector<string> jsons;
|
||||
vector<string> extra_constant_fields;
|
||||
|
||||
debug("(config) loading meter file %s\n", file.c_str());
|
||||
for (;;) {
|
||||
|
@ -118,10 +118,13 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
|
|||
alarm_shells.push_back(p.second);
|
||||
}
|
||||
else
|
||||
if (startsWith(p.first, "json_"))
|
||||
if (startsWith(p.first, "json_") ||
|
||||
startsWith(p.first, "field_"))
|
||||
{
|
||||
string keyvalue = p.first.substr(5)+"="+p.second;
|
||||
jsons.push_back(keyvalue);
|
||||
int off = 5;
|
||||
if (startsWith(p.first, "field_")) { off = 6; }
|
||||
string keyvalue = p.first.substr(off)+"="+p.second;
|
||||
extra_constant_fields.push_back(keyvalue);
|
||||
}
|
||||
else
|
||||
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) {
|
||||
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;
|
||||
|
@ -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)
|
||||
{
|
||||
c->telegram_shells.push_back(cmdline);
|
||||
|
@ -572,9 +588,9 @@ void handleAlarmShell(Configuration *c, string 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)
|
||||
|
@ -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 == "logtimestamps") handleLogTimestamps(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 == "resetafter") handleResetAfter(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;
|
||||
handleJson(c, keyvalue);
|
||||
handleExtraConstantField(c, keyvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -110,8 +110,10 @@ struct Configuration
|
|||
bool no_init {};
|
||||
std::vector<Unit> conversions;
|
||||
std::vector<std::string> selected_fields;
|
||||
std::vector<std::string> added_fields;
|
||||
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;
|
||||
};
|
||||
|
@ -120,6 +122,7 @@ shared_ptr<Configuration> loadConfiguration(string root, string device_override,
|
|||
|
||||
void handleConversions(Configuration *c, string s);
|
||||
void handleSelectedFields(Configuration *c, string s);
|
||||
void handleAddedFields(Configuration *c, string s);
|
||||
bool handleDevice(Configuration *c, string devicefile);
|
||||
|
||||
enum class LinkModeCalculationResultType
|
||||
|
|
13
src/main.cc
13
src/main.cc
|
@ -187,8 +187,9 @@ void list_shell_envs(Configuration *config, string meter_driver)
|
|||
&ignore2, config->separator,
|
||||
&ignore3,
|
||||
&envs,
|
||||
&config->jsons,
|
||||
&config->selected_fields);
|
||||
&config->extra_constant_fields,
|
||||
&config->selected_fields,
|
||||
&config->added_fields);
|
||||
|
||||
for (auto &e : envs)
|
||||
{
|
||||
|
@ -219,7 +220,11 @@ void list_fields(Configuration *config, string meter_driver)
|
|||
string meterr = padLeft("meter", width);
|
||||
printf("%s Meter driver.\n", meterr.c_str());
|
||||
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);
|
||||
printf("%s The wmbus device that received the telegram.\n", device.c_str());
|
||||
string rssi = padLeft("rssi_dbm", width);
|
||||
|
@ -401,7 +406,7 @@ bool start(Configuration *config)
|
|||
meter_manager_->whenMeterUpdated(
|
||||
[&](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);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -404,7 +404,7 @@ string MeterCommonImplementation::unixTimestampOfUpdate()
|
|||
{
|
||||
char ut[40];
|
||||
memset(ut, 0, sizeof(ut));
|
||||
sprintf(ut, "%zu", datetime_of_update_);
|
||||
snprintf(ut, sizeof(ut)-1, "%zu", datetime_of_update_);
|
||||
return string(ut);
|
||||
}
|
||||
|
||||
|
@ -650,6 +650,16 @@ string concatFields(Meter *m, Telegram *t, char c, vector<Print> &prints, vector
|
|||
s += m->datetimeOfUpdateHumanReadable() + c;
|
||||
continue;
|
||||
}
|
||||
if (field == "timestamp_lt")
|
||||
{
|
||||
s += m->datetimeOfUpdateHumanReadable() + c;
|
||||
continue;
|
||||
}
|
||||
if (field == "timestamp_utc")
|
||||
{
|
||||
s += m->datetimeOfUpdateRobot() + c;
|
||||
continue;
|
||||
}
|
||||
if (field == "timestamp_ut")
|
||||
{
|
||||
s += m->unixTimestampOfUpdate() + c;
|
||||
|
@ -767,7 +777,8 @@ void MeterCommonImplementation::printMeter(Telegram *t,
|
|||
string *json,
|
||||
vector<string> *envs,
|
||||
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);
|
||||
*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_TYPE=")+meterDriver());
|
||||
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 != "")
|
||||
{
|
||||
envs->push_back(string("METER_DEVICE=")+t->about.device);
|
||||
|
|
|
@ -230,7 +230,8 @@ struct Meter
|
|||
string *json,
|
||||
vector<string> *envs,
|
||||
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.
|
||||
// Returns true of this meter handled this telegram!
|
||||
|
|
|
@ -89,7 +89,8 @@ protected:
|
|||
string *json,
|
||||
vector<string> *envs,
|
||||
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;
|
||||
|
||||
|
|
|
@ -42,13 +42,14 @@ Printer::Printer(bool json, bool fields, char separator,
|
|||
|
||||
void Printer::print(Telegram *t, Meter *meter,
|
||||
vector<string> *more_json,
|
||||
vector<string> *selected_fields)
|
||||
vector<string> *selected_fields,
|
||||
vector<string> *added_fields)
|
||||
{
|
||||
string human_readable, fields, json;
|
||||
vector<string> envs;
|
||||
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) {
|
||||
printShells(meter, envs);
|
||||
|
|
|
@ -32,7 +32,7 @@ struct Printer {
|
|||
MeterFileNaming naming,
|
||||
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:
|
||||
|
||||
|
|
|
@ -2,5 +2,7 @@ loglevel=debug
|
|||
device=must_be_overriden
|
||||
logtelegrams=false
|
||||
format=json
|
||||
shell=echo METER =="$METER_JSON"== =="$METER_address"== =="$METER_floor"== > /tmp/wmbusmeters_meter_additional_json_test
|
||||
json_address=RoodRd 42
|
||||
shell=echo METER =="$METER_JSON"== =="$METER_address"== =="$METER_city"== =="$METER_floor"== =="$METER_elevator"== > /tmp/wmbusmeters_meter_additional_json_test
|
||||
# The json_ prefix and field_ prefix are equivalent.
|
||||
json_address=RoodRd 42
|
||||
field_city=Stockholm
|
|
@ -3,3 +3,4 @@ type=supercom587
|
|||
id=12345678
|
||||
key=
|
||||
json_floor=5
|
||||
field_elevator=ABC
|
||||
|
|
|
@ -8,7 +8,7 @@ TESTNAME="Test additional json from cmdline"
|
|||
TESTRESULT="ERROR"
|
||||
|
||||
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 "" \
|
||||
> $TEST/test_output.txt 2> $TEST/test_stderr.txt
|
||||
|
||||
|
@ -41,6 +41,9 @@ METER_NAME
|
|||
METER_MEDIA
|
||||
METER_TYPE
|
||||
METER_TIMESTAMP
|
||||
METER_TIMESTAMP_UTC
|
||||
METER_TIMESTAMP_UT
|
||||
METER_TIMESTAMP_LT
|
||||
METER_DEVICE
|
||||
METER_RSSI_DBM
|
||||
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"
|
||||
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" ]
|
||||
then
|
||||
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" ]
|
||||
then
|
||||
echo "OK: $TESTNAME"
|
||||
TESTRESULT="OK"
|
||||
else
|
||||
echo "INFO =>$INFO<"
|
||||
echo "EXPECTED=>$EXPECTED<"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue