Added support for meterfilestimestamp

pull/60/head 0.9.20
weetmuts 2019-12-11 18:56:34 +01:00
rodzic bf233da26c
commit cf7efb8127
11 zmienionych plików z 203 dodań i 4 usunięć

Wyświetl plik

@ -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!

Wyświetl plik

@ -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

Wyświetl plik

@ -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 &&

Wyświetl plik

@ -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);

Wyświetl plik

@ -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 {};

Wyświetl plik

@ -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)

Wyświetl plik

@ -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) {

Wyświetl plik

@ -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);

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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