kopia lustrzana https://github.com/weetmuts/wmbusmeters
Initial work on config files and daemon mode.
rodzic
eceef17499
commit
05e33c32c3
8
CHANGES
8
CHANGES
|
@ -1,4 +1,12 @@
|
|||
|
||||
Version 0.8.4: 2019-02-23
|
||||
|
||||
Add config files support and daemon mode.
|
||||
|
||||
Version 0.8.3: 2019-02-17
|
||||
|
||||
Add experimental support for qcaloric.
|
||||
|
||||
Version 0.8.2: 2019-01-27
|
||||
|
||||
Properly supports short C1 frames after it has received a long frame.
|
||||
|
|
5
Makefile
5
Makefile
|
@ -44,7 +44,7 @@ endif
|
|||
|
||||
$(shell mkdir -p $(BUILD))
|
||||
|
||||
CXXFLAGS := $(DEBUG_FLAGS) -fPIC -fmessage-length=0 -std=c++11 -Wall -Wno-maybe-uninitialized -Wno-unused-function "-DWMBUSMETERS_VERSION=\"0.8.1\""
|
||||
CXXFLAGS := $(DEBUG_FLAGS) -fPIC -fmessage-length=0 -std=c++11 -Wall -Wno-maybe-uninitialized -Wno-unused-function "-DWMBUSMETERS_VERSION=\"0.8.4\""
|
||||
|
||||
$(BUILD)/%.o: %.cc $(wildcard %.h)
|
||||
$(CXX) $(CXXFLAGS) $< -c -o $@
|
||||
|
@ -52,6 +52,7 @@ $(BUILD)/%.o: %.cc $(wildcard %.h)
|
|||
METERS_OBJS:=\
|
||||
$(BUILD)/aes.o \
|
||||
$(BUILD)/cmdline.o \
|
||||
$(BUILD)/config.o \
|
||||
$(BUILD)/dvparser.o \
|
||||
$(BUILD)/meters.o \
|
||||
$(BUILD)/meter_multical21.o \
|
||||
|
@ -72,6 +73,8 @@ METERS_OBJS:=\
|
|||
|
||||
all: $(BUILD)/wmbusmeters $(BUILD)/testinternals
|
||||
@$(STRIP_BINARY)
|
||||
@rm -f $(BUILD)/wmbusmetersd
|
||||
@cp $(BUILD)/wmbusmeters $(BUILD)/wmbusmetersd
|
||||
|
||||
dist: wmbusmeters_0.8.1_$(DEBARCH).deb
|
||||
|
||||
|
|
37
cmdline.cc
37
cmdline.cc
|
@ -19,6 +19,8 @@
|
|||
#include"meters.h"
|
||||
#include"util.h"
|
||||
|
||||
#include<string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
unique_ptr<CommandLine> parseCommandLine(int argc, char **argv) {
|
||||
|
@ -26,6 +28,14 @@ unique_ptr<CommandLine> parseCommandLine(int argc, char **argv) {
|
|||
CommandLine * c = new CommandLine;
|
||||
|
||||
int i=1;
|
||||
const char *filename = strrchr(argv[0], '/')+1;
|
||||
if (!strcmp(filename, "wmbusmetersd")) {
|
||||
c->daemon = true;
|
||||
if (argc > 1) {
|
||||
error("Usage error: wmbusmetersd does not accept any arguments.\n");
|
||||
}
|
||||
return unique_ptr<CommandLine>(c);
|
||||
}
|
||||
if (argc < 2) {
|
||||
c->need_help = true;
|
||||
return unique_ptr<CommandLine>(c);
|
||||
|
@ -73,6 +83,13 @@ unique_ptr<CommandLine> parseCommandLine(int argc, char **argv) {
|
|||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "--useconfig")) {
|
||||
c->useconfig = true;
|
||||
if (i > 1 || argc > 2) {
|
||||
error("Usage error: --useconfig implies no other arguments on the command line.\n");
|
||||
}
|
||||
return unique_ptr<CommandLine>(c);
|
||||
}
|
||||
if (!strncmp(argv[i], "--robot", 7)) {
|
||||
if (strlen(argv[i]) == 7 ||
|
||||
(strlen(argv[i]) == 12 &&
|
||||
|
@ -109,7 +126,7 @@ unique_ptr<CommandLine> parseCommandLine(int argc, char **argv) {
|
|||
if (strlen(argv[i]) > 12 && argv[i][12] == '=') {
|
||||
size_t len = strlen(argv[i])-13;
|
||||
if (len > 0) {
|
||||
c->meterfiles_dir = argv[i]+13;
|
||||
c->meterfiles_dir = string(argv[i]+13, len);
|
||||
} else {
|
||||
c->meterfiles_dir = "/tmp";
|
||||
}
|
||||
|
@ -117,7 +134,7 @@ unique_ptr<CommandLine> parseCommandLine(int argc, char **argv) {
|
|||
c->meterfiles_dir = "/tmp";
|
||||
}
|
||||
if (!checkIfDirExists(c->meterfiles_dir.c_str())) {
|
||||
error("Directory does not exist \"%s\"\n", c->meterfiles_dir.c_str());
|
||||
error("Cannot write meter files into dir \"%s\"\n", c->meterfiles_dir);
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
|
@ -158,7 +175,7 @@ unique_ptr<CommandLine> parseCommandLine(int argc, char **argv) {
|
|||
|
||||
c->usb_device = argv[i];
|
||||
i++;
|
||||
if (!c->usb_device) error("You must supply the usb device to which the wmbus dongle is connected.\n");
|
||||
if (c->usb_device.length() == 0) error("You must supply the usb device to which the wmbus dongle is connected.\n");
|
||||
|
||||
if ((argc-i) % 4 != 0) {
|
||||
error("For each meter you must supply a: name,type,id and key.\n");
|
||||
|
@ -166,16 +183,16 @@ unique_ptr<CommandLine> parseCommandLine(int argc, char **argv) {
|
|||
int num_meters = (argc-i)/4;
|
||||
|
||||
for (int m=0; m<num_meters; ++m) {
|
||||
char *name = argv[m*4+i+0];
|
||||
char *type = argv[m*4+i+1];
|
||||
char *id = argv[m*4+i+2];
|
||||
char *key = argv[m*4+i+3];
|
||||
string name = argv[m*4+i+0];
|
||||
string type = argv[m*4+i+1];
|
||||
string id = argv[m*4+i+2];
|
||||
string key = argv[m*4+i+3];
|
||||
|
||||
MeterType mt = toMeterType(type);
|
||||
|
||||
if (mt == UNKNOWN_METER) error("Not a valid meter type \"%s\"\n", type);
|
||||
if (!isValidId(id)) error("Not a valid meter id \"%s\"\n", id);
|
||||
if (!isValidKey(key)) error("Not a valid meter key \"%s\"\n", key);
|
||||
if (mt == UNKNOWN_METER) error("Not a valid meter type \"%s\"\n", type.c_str());
|
||||
if (!isValidId(id)) error("Not a valid meter id \"%s\"\n", id.c_str());
|
||||
if (!isValidKey(key)) error("Not a valid meter key \"%s\"\n", key.c_str());
|
||||
c->meters.push_back(MeterInfo(name,type,id,key));
|
||||
}
|
||||
|
||||
|
|
39
cmdline.h
39
cmdline.h
|
@ -18,6 +18,7 @@
|
|||
#ifndef CMDLINE_H
|
||||
#define CMDLINE_H
|
||||
|
||||
#include"config.h"
|
||||
#include"meters.h"
|
||||
#include<memory>
|
||||
#include<string.h>
|
||||
|
@ -25,44 +26,6 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
struct MeterInfo {
|
||||
char *name;
|
||||
char *type;
|
||||
char *id;
|
||||
char *key;
|
||||
|
||||
MeterInfo(char *n, char *t, char *i, char *k) {
|
||||
name = n;
|
||||
type = t;
|
||||
id = i;
|
||||
key = k;
|
||||
}
|
||||
};
|
||||
|
||||
struct CommandLine {
|
||||
bool need_help {};
|
||||
bool silence {};
|
||||
bool verbose {};
|
||||
bool debug {};
|
||||
bool logtelegrams {};
|
||||
bool meterfiles {};
|
||||
string meterfiles_dir;
|
||||
bool json {};
|
||||
bool fields {};
|
||||
char separator { ';' };
|
||||
vector<string> shells;
|
||||
bool list_shell_envs {};
|
||||
bool oneshot {};
|
||||
int exitafter {}; // Seconds to exit.
|
||||
char *usb_device {};
|
||||
LinkMode link_mode {};
|
||||
bool link_mode_set {};
|
||||
bool no_init {};
|
||||
vector<MeterInfo> meters;
|
||||
|
||||
~CommandLine() = default;
|
||||
};
|
||||
|
||||
unique_ptr<CommandLine> parseCommandLine(int argc, char **argv);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
Copyright (C) 2019 Fredrik Öhrström
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include"config.h"
|
||||
#include"meters.h"
|
||||
|
||||
#include<vector>
|
||||
#include<string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
pair<string,string> getNextKeyValue(vector<char> &buf, vector<char>::iterator &i)
|
||||
{
|
||||
bool eof, err;
|
||||
string key, value;
|
||||
key = eatToSkipWhitespace(buf, i, '=', 64, &eof, &err);
|
||||
if (eof || err) goto nomore;
|
||||
value = eatToSkipWhitespace(buf, i, '\n', 4096, &eof, &err);
|
||||
if (err) goto nomore;
|
||||
|
||||
return { key, value };
|
||||
|
||||
nomore:
|
||||
|
||||
return { "", "" };
|
||||
}
|
||||
|
||||
void parseMeterConfig(CommandLine *c, vector<char> &buf, string file)
|
||||
{
|
||||
auto i = buf.begin();
|
||||
string name;
|
||||
string type;
|
||||
string id;
|
||||
string key;
|
||||
|
||||
for (;;) {
|
||||
auto p = getNextKeyValue(buf, i);
|
||||
|
||||
if (p.first == "") break;
|
||||
|
||||
if (p.first == "name") name = p.second;
|
||||
if (p.first == "type") type = p.second;
|
||||
if (p.first == "id") id = p.second;
|
||||
if (p.first == "key") key = p.second;
|
||||
}
|
||||
|
||||
MeterType mt = toMeterType(type);
|
||||
if (mt == UNKNOWN_METER) error("Not a valid meter type \"%s\"\n", type.c_str());
|
||||
if (!isValidId(id)) error("Not a valid meter id \"%s\"\n", id.c_str());
|
||||
if (!isValidKey(key)) error("Not a valid meter key \"%s\"\n", key.c_str());
|
||||
|
||||
c->meters.push_back(MeterInfo(name, type, id, key));
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
unique_ptr<CommandLine> loadConfiguration()
|
||||
{
|
||||
CommandLine *c = new CommandLine;
|
||||
|
||||
vector<char> global_conf;
|
||||
loadFile("/etc/wmbusmeters.conf", &global_conf);
|
||||
|
||||
auto i = global_conf.begin();
|
||||
string loglevel;
|
||||
string device;
|
||||
|
||||
for (;;) {
|
||||
auto p = getNextKeyValue(global_conf, i);
|
||||
|
||||
if (p.first == "") break;
|
||||
|
||||
if (p.first == "loglevel") loglevel = p.second;
|
||||
if (p.first == "device") device = p.second;
|
||||
}
|
||||
|
||||
if (loglevel == "verbose") {
|
||||
c->verbose = true;
|
||||
} else
|
||||
if (loglevel == "debug") {
|
||||
c->debug = true;
|
||||
} else
|
||||
if (loglevel == "silent") {
|
||||
c->silence = true;
|
||||
} else
|
||||
if (loglevel == "normal") {
|
||||
} else
|
||||
{
|
||||
warning("No such log level: \"%s\"\n", loglevel.c_str());
|
||||
}
|
||||
// cmdline->logtelegrams
|
||||
|
||||
c->usb_device = device;
|
||||
|
||||
vector<string> meter_files;
|
||||
listFiles("/etc/wmbusmeters.d", &meter_files);
|
||||
|
||||
for (auto& f : meter_files)
|
||||
{
|
||||
vector<char> meter_conf;
|
||||
string file = string("/etc/wmbusmeters.d/")+f;
|
||||
loadFile(file.c_str(), &meter_conf);
|
||||
parseMeterConfig(c, meter_conf, file);
|
||||
}
|
||||
|
||||
return unique_ptr<CommandLine>(c);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
Copyright (C) 2019 Fredrik Öhrström
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include"util.h"
|
||||
#include"wmbus.h"
|
||||
#include<vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct MeterInfo {
|
||||
string name;
|
||||
string type;
|
||||
string id;
|
||||
string key;
|
||||
|
||||
MeterInfo(string& n, string& t, string& i, string& k) {
|
||||
name = n;
|
||||
type = t;
|
||||
id = i;
|
||||
key = k;
|
||||
}
|
||||
};
|
||||
|
||||
struct CommandLine {
|
||||
bool daemon {};
|
||||
bool useconfig {};
|
||||
bool need_help {};
|
||||
bool silence {};
|
||||
bool verbose {};
|
||||
bool debug {};
|
||||
bool logtelegrams {};
|
||||
bool meterfiles {};
|
||||
std::string meterfiles_dir;
|
||||
bool json {};
|
||||
bool fields {};
|
||||
char separator { ';' };
|
||||
std::vector<std::string> shells;
|
||||
bool list_shell_envs {};
|
||||
bool oneshot {};
|
||||
int exitafter {}; // Seconds to exit.
|
||||
string usb_device;
|
||||
LinkMode link_mode {};
|
||||
bool link_mode_set {};
|
||||
bool no_init {};
|
||||
vector<MeterInfo> meters;
|
||||
|
||||
~CommandLine() = default;
|
||||
};
|
||||
|
||||
unique_ptr<CommandLine> loadConfiguration();
|
||||
|
||||
#endif
|
88
main.cc
88
main.cc
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include"cmdline.h"
|
||||
#include"config.h"
|
||||
#include"meters.h"
|
||||
#include"printer.h"
|
||||
#include"serial.h"
|
||||
|
@ -24,9 +25,22 @@
|
|||
|
||||
#include<string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void oneshotCheck(CommandLine *cmdline, SerialCommunicationManager *manager, Meter *meter, vector<unique_ptr<Meter>> &meters);
|
||||
void startUsingCommandline(CommandLine *cmdline);
|
||||
void startUsingConfigFiles();
|
||||
void startDaemon(); // Will use config files.
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
@ -47,7 +61,9 @@ int main(int argc, char **argv)
|
|||
printf(" --shellenvs list the env variables available for the meter.\n");
|
||||
printf(" --oneshot wait for an update from each meter, then quit.\n\n");
|
||||
printf(" --exitafter=20h program exits after running for twenty hoursh\n"
|
||||
" or 10m for ten minutes or 5s for five seconds.\n\n");
|
||||
" or 10m for ten minutes or 5s for five seconds.\n");
|
||||
printf(" --useconfig read from /etc/wmbusmeters.conf and /etc/wmbusmeters.d\n");
|
||||
printf(" check the man page for how to write the config files.\n\n");
|
||||
printf("Specifying auto as the device will automatically look for usb\n");
|
||||
printf("wmbus dongles on /dev/im871a and /dev/amb8465\n\n");
|
||||
printf("The meter types: multical21,flowiq3100,supercom587,iperl (water meters) are supported.\n"
|
||||
|
@ -56,9 +72,25 @@ int main(int argc, char **argv)
|
|||
exit(0);
|
||||
}
|
||||
|
||||
if (cmdline->daemon) {
|
||||
startDaemon();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (cmdline->useconfig) {
|
||||
startUsingConfigFiles();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// We want the data visible in the log file asap!
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
startUsingCommandline(cmdline.get());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void startUsingCommandline(CommandLine *cmdline)
|
||||
{
|
||||
warningSilenced(cmdline->silence);
|
||||
verboseEnabled(cmdline->verbose);
|
||||
logTelegramsEnabled(cmdline->logtelegrams);
|
||||
|
@ -71,7 +103,7 @@ int main(int argc, char **argv)
|
|||
if (cmdline->meterfiles) {
|
||||
verbose("(cmdline) store meter files in: \"%s\"\n", cmdline->meterfiles_dir.c_str());
|
||||
}
|
||||
verbose("(cmdline) using usb device: %s\n", cmdline->usb_device);
|
||||
verbose("(cmdline) using usb device: %s\n", cmdline->usb_device.c_str());
|
||||
verbose("(cmdline) number of meters: %d\n", cmdline->meters.size());
|
||||
|
||||
auto manager = createSerialCommunicationManager(cmdline->exitafter);
|
||||
|
@ -172,7 +204,7 @@ int main(int argc, char **argv)
|
|||
&ignore2, cmdline->separator,
|
||||
&ignore3,
|
||||
&envs);
|
||||
printf("Environment variables provided to shell for meter %s:\n", m.type);
|
||||
printf("Environment variables provided to shell for meter %s:\n", m.type.c_str());
|
||||
for (auto &e : envs) {
|
||||
int p = e.find('=');
|
||||
string key = e.substr(0,p);
|
||||
|
@ -181,7 +213,7 @@ int main(int argc, char **argv)
|
|||
exit(0);
|
||||
}
|
||||
meters.back()->onUpdate(calll(output.get(),print,Meter*));
|
||||
meters.back()->onUpdate([&](Meter*meter) { oneshotCheck(cmdline.get(), manager.get(), meter, meters); });
|
||||
meters.back()->onUpdate([&](Meter*meter) { oneshotCheck(cmdline, manager.get(), meter, meters); });
|
||||
}
|
||||
} else {
|
||||
printf("No meters configured. Printing id:s of all telegrams heard!\n\n");
|
||||
|
@ -206,3 +238,51 @@ void oneshotCheck(CommandLine *cmdline, SerialCommunicationManager *manager, Met
|
|||
// All meters have received at least one update! Stop!
|
||||
manager->stop();
|
||||
}
|
||||
|
||||
void startDaemon()
|
||||
{
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
error("Could not fork.\n");
|
||||
}
|
||||
if (pid > 0)
|
||||
{
|
||||
// Parent returns to exit nicely.
|
||||
return;
|
||||
}
|
||||
|
||||
// Change the file mode mask
|
||||
umask(0);
|
||||
|
||||
setlogmask(LOG_UPTO (LOG_NOTICE));
|
||||
openlog("wmbusmetersd", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
|
||||
|
||||
syslog(LOG_NOTICE, "wmbusmeters started by User %d", getuid ());
|
||||
|
||||
enableSyslog();
|
||||
|
||||
// Create a new SID for the daemon
|
||||
pid_t sid = setsid();
|
||||
if (sid < 0) {
|
||||
// log
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if ((chdir("/")) < 0) {
|
||||
error("Could not change to root as current working directory.");
|
||||
}
|
||||
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
|
||||
startUsingConfigFiles();
|
||||
}
|
||||
|
||||
void startUsingConfigFiles()
|
||||
{
|
||||
unique_ptr<CommandLine> cmdline = loadConfiguration();
|
||||
|
||||
startUsingCommandline(cmdline.get());
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
using namespace std;
|
||||
|
||||
struct MeterIperl : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterIperl(WMBus *bus, const char *name, const char *id, const char *key);
|
||||
MeterIperl(WMBus *bus, string& name, string& id, string& key);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption();
|
||||
|
@ -68,7 +68,7 @@ private:
|
|||
double total_water_consumption_ {};
|
||||
};
|
||||
|
||||
MeterIperl::MeterIperl(WMBus *bus, const char *name, const char *id, const char *key) :
|
||||
MeterIperl::MeterIperl(WMBus *bus, string& name, string& id, string& key) :
|
||||
MeterCommonImplementation(bus, name, id, key, IPERL_METER, MANUFACTURER_SEN, 0x16, LinkModeT1)
|
||||
{
|
||||
MeterCommonImplementation::bus()->onTelegram(calll(this,handleTelegram,Telegram*));
|
||||
|
@ -80,7 +80,7 @@ double MeterIperl::totalWaterConsumption()
|
|||
return total_water_consumption_;
|
||||
}
|
||||
|
||||
unique_ptr<WaterMeter> createIperl(WMBus *bus, const char *name, const char *id, const char *key)
|
||||
unique_ptr<WaterMeter> createIperl(WMBus *bus, string& name, string& id, string& key)
|
||||
{
|
||||
return unique_ptr<WaterMeter>(new MeterIperl(bus,name,id,key));
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ using namespace std;
|
|||
#define INFO_CODE_BURST_SHIFT (4+9)
|
||||
|
||||
struct MeterMultical21 : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterMultical21(WMBus *bus, const char *name, const char *id, const char *key, MeterType mt);
|
||||
MeterMultical21(WMBus *bus, string& name, string& id, string& key, MeterType mt);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption();
|
||||
|
@ -103,7 +103,7 @@ private:
|
|||
int expected_version_ {}; // 0x1b for Multical21 and 0x1d for FlowIQ3100
|
||||
};
|
||||
|
||||
MeterMultical21::MeterMultical21(WMBus *bus, const char *name, const char *id, const char *key, MeterType mt) :
|
||||
MeterMultical21::MeterMultical21(WMBus *bus, string& name, string& id, string& key, MeterType mt) :
|
||||
MeterCommonImplementation(bus, name, id, key, mt, MANUFACTURER_KAM, 0x16, LinkModeC1)
|
||||
{
|
||||
if (type() == MULTICAL21_METER) {
|
||||
|
@ -169,7 +169,7 @@ bool MeterMultical21::hasExternalTemperature()
|
|||
return has_external_temperature_;
|
||||
}
|
||||
|
||||
unique_ptr<WaterMeter> createMultical21(WMBus *bus, const char *name, const char *id, const char *key, MeterType mt)
|
||||
unique_ptr<WaterMeter> createMultical21(WMBus *bus, string& name, string& id, string& key, MeterType mt)
|
||||
{
|
||||
if (mt != MULTICAL21_METER && mt != FLOWIQ3100_METER) {
|
||||
error("Internal error! Not a proper meter type when creating a multical21 style meter.\n");
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include<vector>
|
||||
|
||||
struct MeterMultical302 : public virtual HeatMeter, public virtual MeterCommonImplementation {
|
||||
MeterMultical302(WMBus *bus, const char *name, const char *id, const char *key);
|
||||
MeterMultical302(WMBus *bus, string& name, string& id, string& key);
|
||||
|
||||
double totalEnergyConsumption();
|
||||
double currentPowerConsumption();
|
||||
|
@ -49,7 +49,7 @@ private:
|
|||
double total_volume_ {};
|
||||
};
|
||||
|
||||
MeterMultical302::MeterMultical302(WMBus *bus, const char *name, const char *id, const char *key) :
|
||||
MeterMultical302::MeterMultical302(WMBus *bus, string& name, string& id, string& key) :
|
||||
MeterCommonImplementation(bus, name, id, key, MULTICAL302_METER, MANUFACTURER_KAM, 0x04, LinkModeC1)
|
||||
{
|
||||
MeterCommonImplementation::bus()->onTelegram(calll(this,handleTelegram,Telegram*));
|
||||
|
@ -178,7 +178,7 @@ void MeterMultical302::processContent(Telegram *t) {
|
|||
}
|
||||
}
|
||||
|
||||
unique_ptr<HeatMeter> createMultical302(WMBus *bus, const char *name, const char *id, const char *key) {
|
||||
unique_ptr<HeatMeter> createMultical302(WMBus *bus, string& name, string& id, string& key) {
|
||||
return unique_ptr<HeatMeter>(new MeterMultical302(bus,name,id,key));
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include<vector>
|
||||
|
||||
struct MeterOmnipower : public virtual ElectricityMeter, public virtual MeterCommonImplementation {
|
||||
MeterOmnipower(WMBus *bus, const char *name, const char *id, const char *key);
|
||||
MeterOmnipower(WMBus *bus, string& name, string& id, string& key);
|
||||
|
||||
double totalEnergyConsumption();
|
||||
double currentPowerConsumption();
|
||||
|
@ -48,7 +48,7 @@ private:
|
|||
double current_power_ {};
|
||||
};
|
||||
|
||||
MeterOmnipower::MeterOmnipower(WMBus *bus, const char *name, const char *id, const char *key) :
|
||||
MeterOmnipower::MeterOmnipower(WMBus *bus, string& name, string& id, string& key) :
|
||||
MeterCommonImplementation(bus, name, id, key, OMNIPOWER_METER, MANUFACTURER_KAM, 0x04, LinkModeC1)
|
||||
{
|
||||
MeterCommonImplementation::bus()->onTelegram(calll(this,handleTelegram,Telegram*));
|
||||
|
@ -118,7 +118,7 @@ void MeterOmnipower::processContent(Telegram *t)
|
|||
t->addMoreExplanation(offset, " total power (%f kwh)", total_energy_);
|
||||
}
|
||||
|
||||
unique_ptr<ElectricityMeter> createOmnipower(WMBus *bus, const char *name, const char *id, const char *key)
|
||||
unique_ptr<ElectricityMeter> createOmnipower(WMBus *bus, string& name, string& id, string& key)
|
||||
{
|
||||
return unique_ptr<ElectricityMeter>(new MeterOmnipower(bus,name,id,key));
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include<vector>
|
||||
|
||||
struct MeterQCaloric : public virtual HeatCostMeter, public virtual MeterCommonImplementation {
|
||||
MeterQCaloric(WMBus *bus, const char *name, const char *id, const char *key);
|
||||
MeterQCaloric(WMBus *bus, string& name, string& id, string& key);
|
||||
|
||||
double totalEnergyConsumption();
|
||||
|
||||
|
@ -46,7 +46,7 @@ private:
|
|||
double total_energy_ {};
|
||||
};
|
||||
|
||||
MeterQCaloric::MeterQCaloric(WMBus *bus, const char *name, const char *id, const char *key) :
|
||||
MeterQCaloric::MeterQCaloric(WMBus *bus, string& name, string& id, string& key) :
|
||||
MeterCommonImplementation(bus, name, id, key, QCALORIC_METER, MANUFACTURER_QDS, 0x08, LinkModeC1)
|
||||
{
|
||||
MeterCommonImplementation::bus()->onTelegram(calll(this,handleTelegram,Telegram*));
|
||||
|
@ -101,7 +101,7 @@ void MeterQCaloric::processContent(Telegram *t)
|
|||
parseDV(t, t->content, t->content.begin(), t->content.size(), &values);
|
||||
}
|
||||
|
||||
unique_ptr<HeatCostMeter> createQCaloric(WMBus *bus, const char *name, const char *id, const char *key)
|
||||
unique_ptr<HeatCostMeter> createQCaloric(WMBus *bus, string& name, string& id, string& key)
|
||||
{
|
||||
return unique_ptr<HeatCostMeter>(new MeterQCaloric(bus,name,id,key));
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
using namespace std;
|
||||
|
||||
struct MeterSupercom587 : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterSupercom587(WMBus *bus, const char *name, const char *id, const char *key);
|
||||
MeterSupercom587(WMBus *bus, string& name, string& id, string& key);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption();
|
||||
|
@ -67,7 +67,7 @@ private:
|
|||
double total_water_consumption_ {};
|
||||
};
|
||||
|
||||
MeterSupercom587::MeterSupercom587(WMBus *bus, const char *name, const char *id, const char *key) :
|
||||
MeterSupercom587::MeterSupercom587(WMBus *bus, string& name, string& id, string& key) :
|
||||
MeterCommonImplementation(bus, name, id, key, SUPERCOM587_METER, MANUFACTURER_SON, 0x16, LinkModeT1)
|
||||
{
|
||||
MeterCommonImplementation::bus()->onTelegram(calll(this,handleTelegram,Telegram*));
|
||||
|
@ -79,7 +79,7 @@ double MeterSupercom587::totalWaterConsumption()
|
|||
return total_water_consumption_;
|
||||
}
|
||||
|
||||
unique_ptr<WaterMeter> createSupercom587(WMBus *bus, const char *name, const char *id, const char *key)
|
||||
unique_ptr<WaterMeter> createSupercom587(WMBus *bus, string& name, string& id, string& key)
|
||||
{
|
||||
return unique_ptr<WaterMeter>(new MeterSupercom587(bus,name,id,key));
|
||||
}
|
||||
|
|
34
meters.cc
34
meters.cc
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include<memory.h>
|
||||
|
||||
MeterCommonImplementation::MeterCommonImplementation(WMBus *bus, const char *name, const char *id, const char *key,
|
||||
MeterCommonImplementation::MeterCommonImplementation(WMBus *bus, string& name, string& id, string& key,
|
||||
MeterType type, int manufacturer, int media,
|
||||
LinkMode required_link_mode) :
|
||||
type_(type), manufacturer_(manufacturer), media_(media), name_(name), bus_(bus),
|
||||
|
@ -28,7 +28,7 @@ MeterCommonImplementation::MeterCommonImplementation(WMBus *bus, const char *nam
|
|||
{
|
||||
use_aes_ = true;
|
||||
hex2bin(id, &id_);
|
||||
if (strlen(key) == 0) {
|
||||
if (key.length() == 0) {
|
||||
use_aes_ = false;
|
||||
} else {
|
||||
hex2bin(key, &key_);
|
||||
|
@ -97,26 +97,26 @@ string MeterCommonImplementation::datetimeOfUpdateRobot()
|
|||
return string(datetime);
|
||||
}
|
||||
|
||||
MeterType toMeterType(const char *type)
|
||||
MeterType toMeterType(string& type)
|
||||
{
|
||||
if (!strcmp(type, "multical21")) return MULTICAL21_METER;
|
||||
if (!strcmp(type, "flowiq3100")) return FLOWIQ3100_METER;
|
||||
if (!strcmp(type, "multical302")) return MULTICAL302_METER;
|
||||
if (!strcmp(type, "omnipower")) return OMNIPOWER_METER;
|
||||
if (!strcmp(type, "supercom587")) return SUPERCOM587_METER;
|
||||
if (!strcmp(type, "iperl")) return IPERL_METER;
|
||||
if (!strcmp(type, "qcaloric")) return QCALORIC_METER;
|
||||
if (type == "multical21") return MULTICAL21_METER;
|
||||
if (type == "flowiq3100") return FLOWIQ3100_METER;
|
||||
if (type == "multical302") return MULTICAL302_METER;
|
||||
if (type == "omnipower") return OMNIPOWER_METER;
|
||||
if (type == "supercom587") return SUPERCOM587_METER;
|
||||
if (type == "iperl") return IPERL_METER;
|
||||
if (type == "qcaloric") return QCALORIC_METER;
|
||||
return UNKNOWN_METER;
|
||||
}
|
||||
|
||||
LinkMode toMeterLinkMode(const char *type)
|
||||
LinkMode toMeterLinkMode(string& type)
|
||||
{
|
||||
if (!strcmp(type, "multical21")) return LinkModeC1;
|
||||
if (!strcmp(type, "flowiq3100")) return LinkModeC1;
|
||||
if (!strcmp(type, "multical302")) return LinkModeC1;
|
||||
if (!strcmp(type, "omnipower")) return LinkModeC1;
|
||||
if (!strcmp(type, "supercom587")) return LinkModeT1;
|
||||
if (!strcmp(type, "iperl")) return LinkModeT1;
|
||||
if (type == "multical21") return LinkModeC1;
|
||||
if (type == "flowiq3100") return LinkModeC1;
|
||||
if (type == "multical302") return LinkModeC1;
|
||||
if (type == "omnipower") return LinkModeC1;
|
||||
if (type == "supercom587") return LinkModeT1;
|
||||
if (type == "iperl") return LinkModeT1;
|
||||
|
||||
return UNKNOWN_LINKMODE;
|
||||
}
|
||||
|
|
18
meters.h
18
meters.h
|
@ -106,14 +106,14 @@ struct HeatCostMeter : public virtual Meter {
|
|||
struct GenericMeter : public virtual Meter {
|
||||
};
|
||||
|
||||
MeterType toMeterType(const char *type);
|
||||
LinkMode toMeterLinkMode(const char *type);
|
||||
unique_ptr<WaterMeter> createMultical21(WMBus *bus, const char *name, const char *id, const char *key, MeterType mt);
|
||||
unique_ptr<HeatMeter> createMultical302(WMBus *bus, const char *name, const char *id, const char *key);
|
||||
unique_ptr<ElectricityMeter> createOmnipower(WMBus *bus, const char *name, const char *id, const char *key);
|
||||
unique_ptr<WaterMeter> createSupercom587(WMBus *bus, const char *name, const char *id, const char *key);
|
||||
unique_ptr<WaterMeter> createIperl(WMBus *bus, const char *name, const char *id, const char *key);
|
||||
unique_ptr<HeatCostMeter> createQCaloric(WMBus *bus, const char *name, const char *id, const char *key);
|
||||
GenericMeter *createGeneric(WMBus *bus, const char *name, const char *id, const char *key);
|
||||
MeterType toMeterType(string& type);
|
||||
LinkMode toMeterLinkMode(string& type);
|
||||
unique_ptr<WaterMeter> createMultical21(WMBus *bus, string& name, string& id, string& key, MeterType mt);
|
||||
unique_ptr<HeatMeter> createMultical302(WMBus *bus, string& name, string& id, string& key);
|
||||
unique_ptr<ElectricityMeter> createOmnipower(WMBus *bus, string& name, string& id, string& key);
|
||||
unique_ptr<WaterMeter> createSupercom587(WMBus *bus, string& name, string& id, string& key);
|
||||
unique_ptr<WaterMeter> createIperl(WMBus *bus, string& name, string& id, string& key);
|
||||
unique_ptr<HeatCostMeter> createQCaloric(WMBus *bus, string& name, string& id, string& key);
|
||||
GenericMeter *createGeneric(WMBus *bus, string& name, string& id, string& key);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -46,7 +46,7 @@ struct MeterCommonImplementation : public virtual Meter
|
|||
double getRecordAsDouble(std::string record);
|
||||
uint16_t getRecordAsUInt16(std::string record);
|
||||
|
||||
MeterCommonImplementation(WMBus *bus, const char *name, const char *id, const char *key,
|
||||
MeterCommonImplementation(WMBus *bus, string& name, string& id, string& key,
|
||||
MeterType type, int manufacturer, int media,
|
||||
LinkMode required_link_mode);
|
||||
|
||||
|
|
152
util.cc
152
util.cc
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include"util.h"
|
||||
#include<dirent.h>
|
||||
#include<functional>
|
||||
#include<signal.h>
|
||||
#include<stdarg.h>
|
||||
|
@ -23,6 +24,10 @@
|
|||
#include<string.h>
|
||||
#include<string>
|
||||
#include<sys/stat.h>
|
||||
#include<syslog.h>
|
||||
#include<unistd.h>
|
||||
#include<sys/types.h>
|
||||
#include<fcntl.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -141,6 +146,7 @@ void error(const char* fmt, ...) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
bool syslog_enabled_ = false;
|
||||
bool warning_enabled_ = true;
|
||||
bool verbose_enabled_ = false;
|
||||
bool debug_enabled_ = false;
|
||||
|
@ -150,6 +156,10 @@ void warningSilenced(bool b) {
|
|||
warning_enabled_ = !b;
|
||||
}
|
||||
|
||||
void enableSyslog() {
|
||||
syslog_enabled_ = true;
|
||||
}
|
||||
|
||||
void verboseEnabled(bool b) {
|
||||
verbose_enabled_ = b;
|
||||
}
|
||||
|
@ -185,7 +195,11 @@ void warning(const char* fmt, ...) {
|
|||
if (warning_enabled_) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
if (syslog_enabled_) {
|
||||
vsyslog(LOG_WARNING, fmt, args);
|
||||
} else {
|
||||
vprintf(fmt, args);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +208,11 @@ void verbose(const char* fmt, ...) {
|
|||
if (verbose_enabled_) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
if (syslog_enabled_) {
|
||||
vsyslog(LOG_INFO, fmt, args);
|
||||
} else {
|
||||
vprintf(fmt, args);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
@ -203,25 +221,28 @@ void debug(const char* fmt, ...) {
|
|||
if (debug_enabled_) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
if (syslog_enabled_) {
|
||||
vsyslog(LOG_INFO, fmt, args);
|
||||
} else {
|
||||
vprintf(fmt, args);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
bool isValidId(char *id)
|
||||
bool isValidId(string& id)
|
||||
{
|
||||
if (strlen(id) == 0) return true;
|
||||
if (strlen(id) != 8) return false;
|
||||
if (id.length() != 8) return false;
|
||||
for (int i=0; i<8; ++i) {
|
||||
if (id[i]<'0' || id[i]>'9') return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isValidKey(char *key)
|
||||
bool isValidKey(string& key)
|
||||
{
|
||||
if (strlen(key) == 0) return true;
|
||||
if (strlen(key) != 32) return false;
|
||||
if (key.length() == 0) return true;
|
||||
if (key.length() != 32) return false;
|
||||
vector<uchar> tmp;
|
||||
return hex2bin(key, &tmp);
|
||||
}
|
||||
|
@ -438,3 +459,116 @@ bool crc16_CCITT_check(uchar *data, uint16_t length)
|
|||
uint16_t crc = ~crc16_CCITT(data, length);
|
||||
return crc == CRC16_GOOD_VALUE;
|
||||
}
|
||||
|
||||
bool listFiles(const char *dir, vector<string> *files)
|
||||
{
|
||||
DIR *dp = NULL;
|
||||
struct dirent *dptr = NULL;
|
||||
|
||||
if (NULL == (dp = opendir(dir)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
while(NULL != (dptr = ::readdir(dp)))
|
||||
{
|
||||
if (!strcmp(dptr->d_name,".") ||
|
||||
!strcmp(dptr->d_name,".."))
|
||||
{
|
||||
// Ignore . .. dirs.
|
||||
continue;
|
||||
}
|
||||
|
||||
files->push_back(string(dptr->d_name));
|
||||
}
|
||||
closedir(dp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool loadFile(const char *file, vector<char> *buf)
|
||||
{
|
||||
int blocksize = 1024;
|
||||
char block[blocksize];
|
||||
|
||||
int fd = open(file, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
while (true) {
|
||||
ssize_t n = read(fd, block, sizeof(block));
|
||||
if (n == -1) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
warning("Could not read file %s errno=%d\n", file, errno);
|
||||
close(fd);
|
||||
|
||||
return false;
|
||||
}
|
||||
buf->insert(buf->end(), block, block+n);
|
||||
if (n < (ssize_t)sizeof(block)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
string eatToSkipWhitespace(vector<char> &v, vector<char>::iterator &i, int c, size_t max, bool *eof, bool *err)
|
||||
{
|
||||
eatWhitespace(v, i, eof);
|
||||
if (*eof) {
|
||||
if (c != -1) {
|
||||
*err = true;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
string s = eatTo(v,i,c,max,eof,err);
|
||||
trimWhitespace(&s);
|
||||
return s;
|
||||
}
|
||||
|
||||
string eatTo(vector<char> &v, vector<char>::iterator &i, int c, size_t max, bool *eof, bool *err)
|
||||
{
|
||||
string s;
|
||||
|
||||
*eof = false;
|
||||
*err = false;
|
||||
while (max > 0 && i != v.end() && (c == -1 || *i != c))
|
||||
{
|
||||
s += *i;
|
||||
i++;
|
||||
max--;
|
||||
}
|
||||
if (c != -1 && (i == v.end() || *i != c))
|
||||
{
|
||||
*err = true;
|
||||
}
|
||||
if (i != v.end())
|
||||
{
|
||||
i++;
|
||||
}
|
||||
if (i == v.end()) {
|
||||
*eof = true;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void eatWhitespace(vector<char> &v, vector<char>::iterator &i, bool *eof)
|
||||
{
|
||||
*eof = false;
|
||||
while (i != v.end() && (*i == ' ' || *i == '\t'))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
if (i == v.end()) {
|
||||
*eof = true;
|
||||
}
|
||||
}
|
||||
|
||||
void trimWhitespace(string *s)
|
||||
{
|
||||
const char *ws = " \t";
|
||||
s->erase(0, s->find_first_not_of(ws));
|
||||
s->erase(s->find_last_not_of(ws) + 1);
|
||||
}
|
||||
|
|
20
util.h
20
util.h
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include<signal.h>
|
||||
#include<stdint.h>
|
||||
#include<string>
|
||||
#include<functional>
|
||||
#include<vector>
|
||||
|
||||
|
@ -38,6 +39,7 @@ void strprintf(std::string &s, const char* fmt, ...);
|
|||
|
||||
void xorit(uchar *srca, uchar *srcb, uchar *dest, int len);
|
||||
|
||||
void enableSyslog();
|
||||
void error(const char* fmt, ...);
|
||||
void verbose(const char* fmt, ...);
|
||||
void debug(const char* fmt, ...);
|
||||
|
@ -55,14 +57,16 @@ bool isLogTelegramsEnabled();
|
|||
void debugPayload(std::string intro, std::vector<uchar> &payload);
|
||||
void logTelegram(std::string intro, std::vector<uchar> &header, std::vector<uchar> &content);
|
||||
|
||||
bool isValidId(char *id);
|
||||
bool isValidKey(char *key);
|
||||
bool isValidId(std::string& id);
|
||||
bool isValidKey(std::string& key);
|
||||
|
||||
void incrementIV(uchar *iv, size_t len);
|
||||
|
||||
bool checkCharacterDeviceExists(const char *tty, bool fail_if_not);
|
||||
bool checkIfSimulationFile(const char *file);
|
||||
bool checkIfDirExists(const char *dir);
|
||||
bool listFiles(const char *dir, std::vector<std::string> *files);
|
||||
bool loadFile(const char *file, std::vector<char> *buf);
|
||||
|
||||
std::string eatTo(std::vector<uchar> &v, std::vector<uchar>::iterator &i, int c, size_t max, bool *eof, bool *err);
|
||||
|
||||
|
@ -76,4 +80,16 @@ uint16_t crc16_EN13757(uchar *data, size_t len);
|
|||
uint16_t crc16_CCITT(uchar *data, uint16_t length);
|
||||
bool crc16_CCITT_check(uchar *data, uint16_t length);
|
||||
|
||||
// Eat characters from the vector v, iterating using i, until the end char c is found.
|
||||
// If end char == -1, then do not expect any end char, get all until eof.
|
||||
// If the end char is not found, return error.
|
||||
// If the maximum length is reached without finding the end char, return error.
|
||||
std::string eatTo(std::vector<char> &v, std::vector<char>::iterator &i, int c, size_t max, bool *eof, bool *err);
|
||||
// Eat whitespace (space and tab, not end of lines).
|
||||
void eatWhitespace(std::vector<char> &v, std::vector<char>::iterator &i, bool *eof);
|
||||
// First eat whitespace, then start eating until c is found or eof. The found string is trimmed from beginning and ending whitespace.
|
||||
std::string eatToSkipWhitespace(std::vector<char> &v, std::vector<char>::iterator &i, int c, size_t max, bool *eof, bool *err);
|
||||
// Remove leading and trailing white space
|
||||
void trimWhitespace(std::string *s);
|
||||
|
||||
#endif
|
||||
|
|
Ładowanie…
Reference in New Issue