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