kopia lustrzana https://github.com/weetmuts/wmbusmeters
rodzic
bf233da26c
commit
cf7efb8127
5
CHANGES
5
CHANGES
|
|
@ -1,3 +1,8 @@
|
|||
Version 0.9.20: 2019-12-11
|
||||
|
||||
Added support for meterfilestimestamp
|
||||
to get the effect of log rotation of the meter files.
|
||||
|
||||
Version 0.9.19: 2019-11-26
|
||||
|
||||
Chester4444 added support for the nanoCUL usb stick. Thanks chester4444!
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ format=json
|
|||
meterfiles=/var/log/wmbusmeters/meter_readings
|
||||
meterfilesaction=overwrite
|
||||
meterfilesnaming=name
|
||||
meterfilestimestamp=daily
|
||||
logfile=/var/log/wmbusmeters/wmbusmeters.log
|
||||
shell=/usr/bin/mosquitto_pub -h localhost -t wmbusmeters/$METER_ID -m "$METER_JSON"
|
||||
```
|
||||
|
|
@ -74,6 +75,11 @@ If you are running on a Raspberry PI with flash storage and you relay the data t
|
|||
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.
|
||||
|
||||
If you specify --metefilesaction=append --meterfilestimestamp=day then wmbusmeters will
|
||||
append all todays received telegrams in for example the file Water_2019-12-11, the day
|
||||
after the telegrams will be recorded in Water_2019-12-12. You can change the resolution
|
||||
to day,hour,minute and micros. Micros means that every telegram gets their own file.
|
||||
|
||||
# Run using config files
|
||||
|
||||
If you cannot install as a daemon, then you can also start
|
||||
|
|
@ -117,6 +123,8 @@ As <options> you can use:
|
|||
--meterfiles=<dir> store meter readings in dir
|
||||
--meterfilesaction=(overwrite|append) overwrite or append to the meter readings file
|
||||
--meterfilesnaming=(name|id|name-id) the meter file is the meter's: name, id or name-id
|
||||
--meterfilestimestamp=(never|day|hour|minute|micros) the meter file is suffixed with a
|
||||
timestamp (localtime) with the given resolution.
|
||||
--oneshot wait for an update from each meter, then quit
|
||||
--reopenafter=<time> close/reopen dongle connection repeatedly every <time> seconds, eg 60s, 60m, 24h
|
||||
--separator=<c> change field separator to c
|
||||
|
|
|
|||
|
|
@ -218,6 +218,37 @@ unique_ptr<Configuration> parseCommandLine(int argc, char **argv) {
|
|||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(argv[i], "--meterfilestimestamp", 21)) {
|
||||
if (strlen(argv[i]) > 22 && argv[i][21] == '=') {
|
||||
if (!strncmp(argv[i]+22, "day", 3))
|
||||
{
|
||||
c->meterfiles_timestamp = MeterFileTimestamp::Day;
|
||||
}
|
||||
else if (!strncmp(argv[i]+22, "hour", 4))
|
||||
{
|
||||
c->meterfiles_timestamp = MeterFileTimestamp::Hour;
|
||||
}
|
||||
else if (!strncmp(argv[i]+22, "minute", 6))
|
||||
{
|
||||
c->meterfiles_timestamp = MeterFileTimestamp::Minute;
|
||||
}
|
||||
else if (!strncmp(argv[i]+22, "micros", 5))
|
||||
{
|
||||
c->meterfiles_timestamp = MeterFileTimestamp::Micros;
|
||||
}
|
||||
else if (!strncmp(argv[i]+22, "never", 5))
|
||||
{
|
||||
c->meterfiles_timestamp = MeterFileTimestamp::Never;
|
||||
} else
|
||||
{
|
||||
error("No such meter file timestamp \"%s\"\n", argv[i]+22);
|
||||
}
|
||||
} else {
|
||||
error("Incorrect option %s\n", argv[i]);
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "--meterfiles") ||
|
||||
(!strncmp(argv[i], "--meterfiles", 12) &&
|
||||
strlen(argv[i]) > 12 &&
|
||||
|
|
|
|||
|
|
@ -239,6 +239,34 @@ void handleMeterfilesNaming(Configuration *c, string type)
|
|||
}
|
||||
}
|
||||
|
||||
void handleMeterfilesTimestamp(Configuration *c, string type)
|
||||
{
|
||||
if (type == "day")
|
||||
{
|
||||
c->meterfiles_timestamp = MeterFileTimestamp::Day;
|
||||
}
|
||||
else if (type == "hour")
|
||||
{
|
||||
c->meterfiles_timestamp = MeterFileTimestamp::Hour;
|
||||
}
|
||||
else if (type == "minute")
|
||||
{
|
||||
c->meterfiles_timestamp = MeterFileTimestamp::Minute;
|
||||
}
|
||||
else if (type == "micros")
|
||||
{
|
||||
c->meterfiles_timestamp = MeterFileTimestamp::Micros;
|
||||
}
|
||||
else if (type == "never")
|
||||
{
|
||||
c->meterfiles_timestamp = MeterFileTimestamp::Never;
|
||||
}
|
||||
else
|
||||
{
|
||||
warning("No such meter file timestamp \"%s\"\n", type.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void handleLogfile(Configuration *c, string logfile)
|
||||
{
|
||||
if (logfile.length() > 0)
|
||||
|
|
@ -347,6 +375,7 @@ unique_ptr<Configuration> loadConfiguration(string root)
|
|||
else if (p.first == "meterfiles") handleMeterfiles(c, p.second);
|
||||
else if (p.first == "meterfilesaction") handleMeterfilesAction(c, p.second);
|
||||
else if (p.first == "meterfilesnaming") handleMeterfilesNaming(c, p.second);
|
||||
else if (p.first == "meterfilestimestamp") handleMeterfilesTimestamp(c, p.second);
|
||||
else if (p.first == "logfile") handleLogfile(c, p.second);
|
||||
else if (p.first == "format") handleFormat(c, p.second);
|
||||
else if (p.first == "reopenafter") handleReopenAfter(c, p.second);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,11 @@ enum class MeterFileNaming
|
|||
Name, Id, NameId
|
||||
};
|
||||
|
||||
enum class MeterFileTimestamp
|
||||
{
|
||||
Never, Day, Hour, Minute, Micros
|
||||
};
|
||||
|
||||
struct Configuration
|
||||
{
|
||||
bool daemon {};
|
||||
|
|
@ -54,6 +59,7 @@ struct Configuration
|
|||
std::string meterfiles_dir;
|
||||
MeterFileType meterfiles_action {};
|
||||
MeterFileNaming meterfiles_naming {};
|
||||
MeterFileTimestamp meterfiles_timestamp {}; // Default is never.
|
||||
bool use_logfile {};
|
||||
std::string logfile;
|
||||
bool json {};
|
||||
|
|
|
|||
|
|
@ -238,7 +238,8 @@ bool startUsingCommandline(Configuration *config)
|
|||
config->use_logfile, config->logfile,
|
||||
config->shells,
|
||||
config->meterfiles_action == MeterFileType::Overwrite,
|
||||
config->meterfiles_naming));
|
||||
config->meterfiles_naming,
|
||||
config->meterfiles_timestamp));
|
||||
vector<unique_ptr<Meter>> meters;
|
||||
|
||||
if (config->meters.size() > 0)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@ Printer::Printer(bool json, bool fields, char separator,
|
|||
bool use_meterfiles, string &meterfiles_dir,
|
||||
bool use_logfile, string &logfile,
|
||||
vector<string> shell_cmdlines, bool overwrite,
|
||||
MeterFileNaming naming)
|
||||
MeterFileNaming naming,
|
||||
MeterFileTimestamp timestamp)
|
||||
{
|
||||
json_ = json;
|
||||
fields_ = fields;
|
||||
|
|
@ -36,6 +37,7 @@ Printer::Printer(bool json, bool fields, char separator,
|
|||
shell_cmdlines_ = shell_cmdlines;
|
||||
overwrite_ = overwrite;
|
||||
naming_ = naming;
|
||||
timestamp_ = timestamp;
|
||||
}
|
||||
|
||||
void Printer::print(Telegram *t, Meter *meter, vector<string> *more_json)
|
||||
|
|
@ -80,7 +82,7 @@ void Printer::printFiles(Meter *meter, Telegram *t, string &human_readable, stri
|
|||
FILE *output = stdout;
|
||||
|
||||
if (use_meterfiles_) {
|
||||
char filename[128];
|
||||
char filename[256];
|
||||
memset(filename, 0, sizeof(filename));
|
||||
switch (naming_) {
|
||||
case MeterFileNaming::Name:
|
||||
|
|
@ -93,6 +95,33 @@ void Printer::printFiles(Meter *meter, Telegram *t, string &human_readable, stri
|
|||
snprintf(filename, 127, "%s/%s-%s", meterfiles_dir_.c_str(), meter->name().c_str(), t->id.c_str());
|
||||
break;
|
||||
}
|
||||
string stamp;
|
||||
|
||||
switch (timestamp_) {
|
||||
case MeterFileTimestamp::Never:
|
||||
// Append nothing.
|
||||
break;
|
||||
case MeterFileTimestamp::Day:
|
||||
stamp = currentDay();
|
||||
break;
|
||||
case MeterFileTimestamp::Hour:
|
||||
stamp = currentHour();
|
||||
break;
|
||||
case MeterFileTimestamp::Minute:
|
||||
stamp = currentMinute();
|
||||
break;
|
||||
case MeterFileTimestamp::Micros:
|
||||
stamp = currentMicros();
|
||||
break;
|
||||
}
|
||||
|
||||
if (stamp.length() > 0)
|
||||
{
|
||||
// There is a timestamp, lets append it.
|
||||
strcat(filename, "_");
|
||||
strcat(filename, stamp.c_str());
|
||||
}
|
||||
|
||||
const char *mode = overwrite_ ? "w" : "a";
|
||||
output = fopen(filename, mode);
|
||||
if (!output) {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ struct Printer {
|
|||
bool use_logfile, string &logfile,
|
||||
vector<string> shell_cmdlines,
|
||||
bool overwrite,
|
||||
MeterFileNaming naming);
|
||||
MeterFileNaming naming,
|
||||
MeterFileTimestamp timestamp);
|
||||
|
||||
void print(Telegram *t, Meter *meter, vector<string> *more_json);
|
||||
|
||||
|
|
@ -44,6 +45,7 @@ struct Printer {
|
|||
vector<string> shell_cmdlines_;
|
||||
bool overwrite_;
|
||||
MeterFileNaming naming_;
|
||||
MeterFileTimestamp timestamp_;
|
||||
|
||||
void printShells(Meter *meter, vector<string> &envs);
|
||||
void printFiles(Meter *meter, Telegram *t, string &human_readable, string &fields, string &json);
|
||||
|
|
|
|||
49
src/util.cc
49
src/util.cc
|
|
@ -28,6 +28,7 @@
|
|||
#include<string>
|
||||
#include<sys/errno.h>
|
||||
#include<sys/stat.h>
|
||||
#include<sys/time.h>
|
||||
#include<syslog.h>
|
||||
#include<unistd.h>
|
||||
#include<sys/types.h>
|
||||
|
|
@ -1019,3 +1020,51 @@ string makeQuotedJson(string &s)
|
|||
|
||||
return string("\"")+key+"\":\""+value+"\"";
|
||||
}
|
||||
|
||||
string currentDay()
|
||||
{
|
||||
char datetime[40];
|
||||
memset(datetime, 0, sizeof(datetime));
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
strftime(datetime, 20, "%Y-%m-%d", localtime(&tv.tv_sec));
|
||||
return string(datetime);
|
||||
}
|
||||
|
||||
string currentHour()
|
||||
{
|
||||
char datetime[40];
|
||||
memset(datetime, 0, sizeof(datetime));
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
strftime(datetime, 20, "%Y-%m-%d_%H", localtime(&tv.tv_sec));
|
||||
return string(datetime);
|
||||
}
|
||||
|
||||
string currentMinute()
|
||||
{
|
||||
char datetime[40];
|
||||
memset(datetime, 0, sizeof(datetime));
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
strftime(datetime, 20, "%Y-%m-%d_%H:%M", localtime(&tv.tv_sec));
|
||||
return string(datetime);
|
||||
}
|
||||
|
||||
string currentMicros()
|
||||
{
|
||||
char datetime[40];
|
||||
memset(datetime, 0, sizeof(datetime));
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
strftime(datetime, 20, "%Y-%m-%d_%H:%M:%S", localtime(&tv.tv_sec));
|
||||
return string(datetime)+"."+to_string(tv.tv_usec);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,4 +128,9 @@ bool startsWith(std::string &s, const char *prefix);
|
|||
// Given alfa=beta it returns "alfa":"beta"
|
||||
std::string makeQuotedJson(std::string &s);
|
||||
|
||||
std::string currentDay();
|
||||
std::string currentHour();
|
||||
std::string currentMinute();
|
||||
std::string currentMicros();
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -57,3 +57,37 @@ then
|
|||
fi
|
||||
|
||||
if [ "$TESTRESULT" = "ERROR" ]; then echo ERROR: $TESTNAME; exit 1; fi
|
||||
|
||||
|
||||
TESTNAME="Test that meterfiles with timestamps are written"
|
||||
TESTRESULT="ERROR"
|
||||
|
||||
rm -rf /tmp/testmeters
|
||||
mkdir /tmp/testmeters
|
||||
cat simulations/simulation_c1.txt | grep '^{' | grep 76348799 | tail -n 1 > $TEST/test_expected.txt
|
||||
$PROG --meterfiles=/tmp/testmeters --meterfilesnaming=id --meterfilestimestamp=day --format=json simulations/simulation_c1.txt MyTapWater multical21 76348799 ""
|
||||
cat /tmp/testmeters/76348799_$(date +%Y-%m-%d) | sed 's/"timestamp":"....-..-..T..:..:..Z"/"timestamp":"1111-11-11T11:11:11Z"/' > $TEST/test_response.txt
|
||||
diff $TEST/test_expected.txt $TEST/test_response.txt
|
||||
if [ "$?" == "0" ]
|
||||
then
|
||||
echo OK: $TESTNAME
|
||||
TESTRESULT="OK"
|
||||
rm -rf /tmp/testmeters
|
||||
fi
|
||||
|
||||
if [ "$TESTRESULT" = "ERROR" ]; then echo ERROR: $TESTNAME; exit 1; fi
|
||||
|
||||
rm -rf /tmp/testmeters
|
||||
mkdir /tmp/testmeters
|
||||
cat simulations/simulation_c1.txt | grep '^{' | grep 76348799 | tail -n 1 > $TEST/test_expected.txt
|
||||
$PROG --meterfiles=/tmp/testmeters --meterfilesnaming=id --meterfilestimestamp=minute --format=json simulations/simulation_c1.txt MyTapWater multical21 76348799 ""
|
||||
cat /tmp/testmeters/76348799_$(date +%Y-%m-%d_%H:%M) | sed 's/"timestamp":"....-..-..T..:..:..Z"/"timestamp":"1111-11-11T11:11:11Z"/' > $TEST/test_response.txt
|
||||
diff $TEST/test_expected.txt $TEST/test_response.txt
|
||||
if [ "$?" == "0" ]
|
||||
then
|
||||
echo OK: $TESTNAME
|
||||
TESTRESULT="OK"
|
||||
rm -rf /tmp/testmeters
|
||||
fi
|
||||
|
||||
if [ "$TESTRESULT" = "ERROR" ]; then echo ERROR: $TESTNAME; exit 1; fi
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue