Skip to content

Commit

Permalink
Merge branch 'volkszaehler:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
maxberger authored May 22, 2022
2 parents 9431a37 + 76e868f commit 95b3e2f
Show file tree
Hide file tree
Showing 12 changed files with 84 additions and 135 deletions.
15 changes: 11 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
ARG DEBIAN_VERSION=buster
ARG DEBIAN_VERSION=buster-slim

############################
# STEP 1 build executable binary
############################

FROM debian:$DEBIAN_VERSION as builder

RUN apt-get update && apt-get install -y \
Expand Down Expand Up @@ -38,6 +43,11 @@ RUN cmake -DBUILD_TEST=off \
&& make \
&& make install


#############################
## STEP 2 build a small image
#############################

FROM debian:$DEBIAN_VERSION

LABEL Description="vzlogger"
Expand Down Expand Up @@ -66,7 +76,4 @@ COPY --from=builder /usr/local/lib/libmbus.so* /usr/local/lib/
RUN useradd -M -G dialout vz
USER vz

# Setup volume
VOLUME ["/cfg"]

CMD ["vzlogger", "--foreground"]
21 changes: 1 addition & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,11 @@ Installation
---------------
To install, follow the detailed installation instructions at http://wiki.volkszaehler.org/software/controller/vzlogger/installation_cpp-version

If you're impatient you can quickstart using (Debian Wheezy):
If you're impatient you can quickstart using (Debian Bullseye or Ubuntu 18.04 LTS):

sudo apt-get install build-essential git-core cmake pkg-config subversion libcurl3-dev \
libgnutls-dev libsasl2-dev uuid-dev uuid-runtime libtool dh-autoreconf libunistring-dev

For Debian Jessie, be sure to add:

sudo apt-get install libgcrypt20-dev

For Debian Stretch, use:

sudo apt-get install git cmake autoconf libtool uuid-dev libcurl4-openssl-dev libssl-dev \
libgnutls28-dev libgcrypt20-dev libmicrohttpd-dev libsasl2-dev libunistring-dev
For Debian Buster, use:

sudo apt-get install git cmake autoconf libtool uuid-dev libcurl4-openssl-dev libssl-dev \
libgnutls28-dev libgcrypt20-dev libmicrohttpd-dev libsasl2-dev libunistring-dev build-essential

Ubuntu 18.04 LTS (bionic) needs an additional:

sudo apt-get install libunistring-dev
(this might be needed on others now as well as we link unconditionally against libunistring)

If you want to use MQTT support:

sudo apt-get install libmosquitto-dev
Expand Down
1 change: 0 additions & 1 deletion debian/vzlogger.manpages

This file was deleted.

79 changes: 0 additions & 79 deletions docs/vzlogger.1

This file was deleted.

1 change: 0 additions & 1 deletion etc/vzlogger.conf
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
"timestamp": false // optional whether to include a timestamp in the payload
},


// Meter configuration
"meters": [
{
Expand Down
5 changes: 5 additions & 0 deletions include/Config_Options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ class Config_Options {

bool doRegistration() const { return _doRegistration; }

bool haveTimeMachine() const { return _time_machine; }

// setter
void config(const std::string &v) { _config = v; }
void log(const std::string &v) { _log = v; }
Expand All @@ -95,6 +97,8 @@ class Config_Options {

void doRegistration(const bool v) { _doRegistration = v; }

void haveTimeMachine(const bool v) { _time_machine = v; }

PushDataServer *pushDataServer() const { return _pds; }

private:
Expand All @@ -114,6 +118,7 @@ class Config_Options {
int _local : 1; // enable local interface
int _foreground : 1; // don't daemonize
int _doRegistration : 1; // FIXME
int _time_machine : 1; // accept readings from before smart-metering existed
};

/**
Expand Down
1 change: 1 addition & 0 deletions include/api/InfluxDB.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class InfluxDB : public ApiIF {
std::string _host;
std::string _username;
std::string _token;
struct curl_slist *_token_header;
std::string _organization;
std::string _password;
std::string _database;
Expand Down
10 changes: 7 additions & 3 deletions src/Config_Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ static const char *option_type_str[] = {"null", "boolean", "double", "int",

Config_Options::Config_Options()
: _config("/etc/vzlogger.conf"), _log(""), _pds(0), _port(8080), _verbosity(0),
_comet_timeout(30), _buffer_length(-1), _retry_pause(15), _local(false), _foreground(false) {
_comet_timeout(30), _buffer_length(-1), _retry_pause(15), _local(false), _foreground(false),
_time_machine(false) {
_logfd = NULL;
}

Config_Options::Config_Options(const std::string filename)
: _config(filename), _log(""), _pds(0), _port(8080), _verbosity(0), _comet_timeout(30),
_buffer_length(-1), _retry_pause(15), _local(false), _foreground(false) {
_buffer_length(-1), _retry_pause(15), _local(false), _foreground(false),
_time_machine(false) {
_logfd = NULL;
}

Expand Down Expand Up @@ -178,7 +180,9 @@ void Config_Options::config_parse(MapContainer &mappings) {
"mqtt");
}
#endif
else {
else if ((strcmp(key, "i_have_a_time_machine") == 0) && type == json_type_boolean) {
_time_machine = json_object_get_boolean(value);
} else {
print(log_alert, "Ignoring invalid field or type: %s=%s (%s)", NULL, key,
json_object_get_string(value), option_type_str[type]);
}
Expand Down
14 changes: 7 additions & 7 deletions src/api/InfluxDB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,12 @@ vz::api::InfluxDB::InfluxDB(const Channel::Ptr &ch, const std::list<Option> &pOp
throw;
}

_token_header = NULL;
try {
_token = optlist.lookup_string(pOptions, "token");
print(log_finest, "api InfluxDB using login Token: %s", ch->name(), _token.c_str());
_token = "Authorization: Token " + _token;
_token_header = curl_slist_append(_token_header, _token.c_str());
} catch (vz::OptionNotFoundException &e) {
print(log_finest, "api InfluxDB no Token set", ch->name());
_token = "";
Expand Down Expand Up @@ -233,12 +236,11 @@ vz::api::InfluxDB::InfluxDB(const Channel::Ptr &ch, const std::list<Option> &pOp
curl_free(database_urlencoded);
}

vz::api::InfluxDB::~InfluxDB() // destructor
{}
// destructor
vz::api::InfluxDB::~InfluxDB() { curl_slist_free_all(_token_header); }

void vz::api::InfluxDB::send() {
long int http_code;
struct curl_slist *list = NULL;
CURLcode curl_code;
int request_body_lines = 0;
std::string request_body;
Expand Down Expand Up @@ -317,10 +319,8 @@ void vz::api::InfluxDB::send() {
curl_easy_setopt(_api.curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_easy_setopt(_api.curl, CURLOPT_USERNAME, _username.c_str());
curl_easy_setopt(_api.curl, CURLOPT_PASSWORD, _password.c_str());
} else if (!_token.empty()) {
std::string authtoken = "Authorization: Token " + _token;
list = curl_slist_append(list, authtoken.c_str());
curl_easy_setopt(_api.curl, CURLOPT_HTTPHEADER, list);
} else if (_token_header) {
curl_easy_setopt(_api.curl, CURLOPT_HTTPHEADER, _token_header);
}
curl_easy_setopt(_api.curl, CURLOPT_URL, _url.c_str());
curl_easy_setopt(_api.curl, CURLOPT_VERBOSE, options.verbosity() > 0);
Expand Down
42 changes: 26 additions & 16 deletions src/mqtt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ MqttClient::MqttClient(struct json_object *option) : _enabled(false) {
// tell mosquitto that it should be thread safe:
int res = mosquitto_threaded_set(_mcs, true);
if (res != MOSQ_ERR_SUCCESS) {
print(log_warning, "mosquitto_threaded_set returned %d!", "mqtt", res);
print(log_warning, "mosquitto_threaded_set failed: %s", "mqtt",
mosquitto_strerror(res));
}
// set username&pwd
if ((_user.length() or _pwd.length()) and
Expand Down Expand Up @@ -144,10 +145,17 @@ MqttClient::MqttClient(struct json_object *option) : _enabled(false) {
return len;
});
if (res != MOSQ_ERR_SUCCESS) {
print(log_warning, "mosquitto_tls_set returned error %d!", "mqtt", res);
print(log_warning, "mosquitto_tls_set failed: %s", "mqtt",
mosquitto_strerror(res));
}
}

int protocol = MQTT_PROTOCOL_V311;
res = mosquitto_opts_set(_mcs, MOSQ_OPT_PROTOCOL_VERSION, &protocol);
if (res != MOSQ_ERR_SUCCESS) {
print(log_warning, "unable to set MQTT protocol version (error %d)", "mqtt", res);
}

mosquitto_connect_callback_set(_mcs, [](struct mosquitto *mosq, void *obj, int res) {
static_cast<MqttClient *>(obj)->connect_callback(mosq, res);
});
Expand All @@ -165,23 +173,23 @@ MqttClient::MqttClient(struct json_object *option) : _enabled(false) {
if (res != MOSQ_ERR_SUCCESS) {
switch (res) {
case MOSQ_ERR_CONN_REFUSED: // mqtt might accept us later only.
print(log_warning, "mosquitto_connect failed. res=%d (%s)! Trying anyhow.",
"mqtt", res, strerror(errno));
print(log_warning, "mosquitto_connect failed (but trying anyhow): %s", "mqtt",
mosquitto_strerror(res));
break;
case MOSQ_ERR_ERRNO:
if (errno == 111) // con refused:
{
print(log_warning,
"mosquitto_connect failed. res=%d (%d %s)! Trying anyhow.", "mqtt",
res, errno, strerror(errno));
print(log_warning, "mosquitto_connect failed (but trying anyhow): %s",
"mqtt", mosquitto_strerror(res));
} else {
print(log_alert, "mosquitto_connect failed. res=%d (%d %s)! Stopped!",
"mqtt", res, errno, strerror(errno));
print(log_alert, "mosquitto_connect failed, giving up: %s", "mqtt",
mosquitto_strerror(res));
_enabled = false;
}
break;
default:
print(log_alert, "mosquitto_connect failed. res=%d! Stopped!", "mqtt", res);
print(log_alert, "mosquitto_connect failed, stopped: %s", "mqtt",
mosquitto_strerror(res));
_enabled = false;
break;
}
Expand Down Expand Up @@ -211,7 +219,7 @@ MqttClient::~MqttClient() {
// we call mosquitto_loop at least once here as the thread should be stopped already:
int res = mosquitto_loop(_mcs, 50, 1);
if (res != MOSQ_ERR_SUCCESS and res != MOSQ_ERR_NO_CONN) {
print(log_warning, "mosquitto_loop returned %d", "mqtt", res);
print(log_warning, "mosquitto_loop returned: %s", "mqtt", mosquitto_strerror(res));
}
mosquitto_destroy(_mcs);
}
Expand Down Expand Up @@ -275,8 +283,8 @@ void MqttClient::publish(Channel::Ptr ch, Reading &rds, bool aggregate) {
int res = mosquitto_publish(_mcs, 0, name.c_str(), v.second.length(), v.second.c_str(),
_qos, _retain);
if (res != MOSQ_ERR_SUCCESS) {
print(log_finest, "mosquitto_publish announce %s returned %d", "mqtt", name.c_str(),
res);
print(log_finest, "mosquitto_publish announce \"%s\" failed: %s", "mqtt",
name.c_str(), mosquitto_strerror(res));
} else {
entry._announced = true; // if one can be announced we treat it successfull
}
Expand All @@ -303,7 +311,7 @@ void MqttClient::publish(Channel::Ptr ch, Reading &rds, bool aggregate) {
int res = mosquitto_publish(_mcs, 0, topic.c_str(), payload.length(), payload.c_str(), _qos,
_retain);
if (res != MOSQ_ERR_SUCCESS) {
print(log_finest, "mosquitto_publish returned %d", "mqtt", res);
print(log_finest, "mosquitto_publish failed: %s", "mqtt", mosquitto_strerror(res));
}
if (payload_obj != NULL) {
json_object_put(payload_obj);
Expand Down Expand Up @@ -339,11 +347,13 @@ void *mqtt_client_thread(void *arg) {
while (!endMqttClientThread) {
int res = mosquitto_loop(mqttClient->_mcs, 1000, 1);
if (res != MOSQ_ERR_SUCCESS) {
print(log_warning, "mosquitto_loop returned %d. trying reconnect", "mqtt", res);
print(log_warning, "mosquitto_loop failed (trying to reconnect): %s", "mqtt",
mosquitto_strerror(res));
sleep(1);
res = mosquitto_reconnect(mqttClient->_mcs);
if (res != MOSQ_ERR_SUCCESS) {
print(log_warning, "mosquitto_reconnect returned %d", "mqtt", res);
print(log_warning, "mosquitto_reconnect failed: %s", "mqtt",
mosquitto_strerror(res));
// todo investigate: will next loop return same != SUCCESS and trigger recon?
} else {
print(log_finest, "mosquitto_reconnect succeeded", "mqtt");
Expand Down
21 changes: 21 additions & 0 deletions src/threads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,27 @@ void *reading_thread(void *arg) {
rds[i].time_ms());
}
}
if (n > 0 && !options.haveTimeMachine())
for (size_t i = 0; i < n; i++)
if (rds[i].time_s() < 631152000) { // 1990-01-01 00:00:00
print(log_error,
"meter returned readings with a timestamp before 1990, IGNORING.",
mtr->name());
print(log_error, "most likely your meter is misconfigured,",
mtr->name());
print(log_error,
"for sml meters, set `\"use_local_time\": true` in vzlogger.conf"
" (meter section),",
mtr->name());
print(log_error,
"to override this check, set `\"i_have_a_time_machine\": true`"
" in vzlogger.conf.",
mtr->name());
// note: we do NOT throw an exception or such,
// because this might be a spurious error,
// the next reading might be valid again.
n = 0;
}

/* insert readings into channel queues */
if (n > 0)
Expand Down
Loading

0 comments on commit 95b3e2f

Please sign in to comment.