Merge remote-tracking branch 'origin/master' into enhanced_device

This commit is contained in:
john
2019-11-24 15:37:10 +01:00
18 changed files with 232 additions and 89 deletions
+3 -1
View File
@@ -1,4 +1,4 @@
# 3.4 (2019-10-?) # 3.4 (2019-10-27)
## Bug Fixes ## Bug Fixes
* fix for always enabled "--mqttchanges" option * fix for always enabled "--mqttchanges" option
@@ -10,6 +10,7 @@
* fix for compilation and running on FreeBSD and MacOS with low latency setting for FTDI device (thanks to samm-git) * fix for compilation and running on FreeBSD and MacOS with low latency setting for FTDI device (thanks to samm-git)
* fix for switching to daemon mode when log file was not opened * fix for switching to daemon mode when log file was not opened
* fix for checking required arguments of "write" command with "-h" * fix for checking required arguments of "write" command with "-h"
* fix for potential MQTT reconnect issue after lost connection
## Features ## Features
* added option to set poll priority with MQTT get topic * added option to set poll priority with MQTT get topic
@@ -17,6 +18,7 @@
* added MQTT /list topic for retrieval of all known messages * added MQTT /list topic for retrieval of all known messages
* added support for init scripts on non-LSB distributions (thanks to andr2000) * added support for init scripts on non-LSB distributions (thanks to andr2000)
* added support for logging to syslog instead of file (thanks to samm-git) * added support for logging to syslog instead of file (thanks to samm-git)
* added adjustable verbosity and option to include unknown messages to "listen" command
# 3.3 (2018-12-26) # 3.3 (2018-12-26)
+1 -1
View File
@@ -1 +1 @@
3.3 3.4
+2 -2
View File
@@ -2,7 +2,7 @@
# Contributor: Milan Knizek <knizek volny cz> # Contributor: Milan Knizek <knizek volny cz>
# Usage: makepkg # Usage: makepkg
pkgname=ebusd pkgname=ebusd
pkgver=3.3 pkgver=3.4
pkgrel=1 pkgrel=1
pkgdesc="ebusd, the daemon for communication with eBUS heating systems." pkgdesc="ebusd, the daemon for communication with eBUS heating systems."
arch=('i686' 'x86_64' 'armv6h' 'armv7h' 'aarch64') arch=('i686' 'x86_64' 'armv6h' 'armv7h' 'aarch64')
@@ -37,4 +37,4 @@ package() {
install -m 0644 contrib/archlinux/conf.d/ebusd "${pkgdir}/etc/conf.d/ebusd" install -m 0644 contrib/archlinux/conf.d/ebusd "${pkgdir}/etc/conf.d/ebusd"
} }
# update md5sums: updpkgsums # update md5sums: updpkgsums
md5sums=('f65252d59ccce4c244d3c4c5597a6b8e') md5sums=('0ce4e4646445612373d5114bb2f99fa8')
+1 -1
View File
@@ -3,7 +3,7 @@
# Usage: makepkg -p PKGBUILD.git # Usage: makepkg -p PKGBUILD.git
pkgname=ebusd-git pkgname=ebusd-git
_gitname=ebusd _gitname=ebusd
pkgver=3.3 pkgver=3.4
pkgrel=1 pkgrel=1
pkgdesc="ebusd, the daemon for communication with eBUS heating systems." pkgdesc="ebusd, the daemon for communication with eBUS heating systems."
arch=('i686' 'x86_64' 'armv6h' 'armv7h' 'aarch64') arch=('i686' 'x86_64' 'armv6h' 'armv7h' 'aarch64')
+1 -1
View File
@@ -12,7 +12,7 @@ RUN apt-get update && apt-get install -y \
LABEL maintainer "ebusd@ebusd.eu" LABEL maintainer "ebusd@ebusd.eu"
ENV EBUSD_VERSION 3.3 ENV EBUSD_VERSION 3.4
ENV EBUSD_ARCH amd64 ENV EBUSD_ARCH amd64
LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}-devel" LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}-devel"
+1 -1
View File
@@ -7,7 +7,7 @@ RUN apt-get update && apt-get install -y \
LABEL maintainer "ebusd@ebusd.eu" LABEL maintainer "ebusd@ebusd.eu"
ENV EBUSD_VERSION 3.3 ENV EBUSD_VERSION 3.4
ENV EBUSD_ARCH amd64 ENV EBUSD_ARCH amd64
LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}" LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}"
+25
View File
@@ -0,0 +1,25 @@
FROM balenalib/raspberrypi3
RUN apt-get update && apt-get install -y \
logrotate libmosquitto1 libstdc++6 libc6 libgcc1 \
curl \
&& rm -rf /var/lib/apt/lists/*
LABEL maintainer "ebusd@ebusd.eu"
ENV EBUSD_VERSION 3.4
ENV EBUSD_ARCH armhf
LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}"
RUN curl -SL https://github.com/john30/ebusd/releases/download/v${EBUSD_VERSION}/ebusd-${EBUSD_VERSION}_${EBUSD_ARCH}-stretch_mqtt1.deb > ebusd.deb
RUN dpkg -i ebusd.deb
RUN rm ebusd.deb
EXPOSE 8888
COPY docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["-f", "--scanconfig"]
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
set -e
if [ "${1#-}" != "$1" ]; then
set -- ebusd "$@"
fi
exec "$@"
Executable → Regular
+1 -1
View File
@@ -2,5 +2,5 @@
set -e set -e
export EBUSD_VERSION=`cat ../../VERSION` export EBUSD_VERSION=`cat ../../VERSION`
export EBUSD_ARCH=`docker version|grep -i "Arch[^:]*:"|tail -n 1|sed -e 's#^.*/##'` export EBUSD_ARCH=`docker version|grep -i "Arch[^:]*:"|tail -n 1|sed -e 's#^.*/##'`
sed -i -e "s#^ENV EBUSD_VERSION .*\$#ENV EBUSD_VERSION ${EBUSD_VERSION}#" -e "s#^ENV EBUSD_ARCH .*\$#ENV EBUSD_ARCH ${EBUSD_ARCH}#" Dockerfile release/Dockerfile runtime/Dockerfile sed -i -e "s#^ENV EBUSD_VERSION .*\$#ENV EBUSD_VERSION ${EBUSD_VERSION}#" -e "s#^ENV EBUSD_ARCH .*\$#ENV EBUSD_ARCH ${EBUSD_ARCH}#" Dockerfile release/Dockerfile rpirelease/Dockerfile
+10 -2
View File
@@ -1,12 +1,20 @@
<?php <?php
$agent = $_SERVER['HTTP_USER_AGENT']; $agent = $_SERVER['HTTP_USER_AGENT'];
require_once('prepend.inc');
if (substr($agent, 0, 5)==='ebusd') { if (substr($agent, 0, 5)==='ebusd') {
require_once('prepend.inc');
$r = @file_get_contents('php://input'); $r = @file_get_contents('php://input');
header('Content-Type: text/plain'); header('Content-Type: text/plain');
$r = @json_decode($r, true); $r = @json_decode($r, true);
echo checkUpdate(@$r['v'], @$r['r'], @$r['a'], @$r['l']); echo checkUpdate(@$r['v'], @$r['r'], @$r['a'], @$r['l']);
exit; exit;
} }
header('HTTP/1.1 404 Not Found'); readVersions();
?> ?>
<html>
<head>
<title>ebusd update check service</title>
</head>
<body>
<p>latest ebusd version: <?=$versions['ebusd'][0]?></p>
<p>last update: <?=date('c', @filemtime('versions.txt'))?></p>
</body>
Executable → Regular
+25 -11
View File
@@ -223,11 +223,12 @@ static const struct argp_option argpoptions[] = {
{"updatecheck", O_UPDCHK, "MODE", 0, "Set automatic update check to MODE (on|off) [on]", 0 }, {"updatecheck", O_UPDCHK, "MODE", 0, "Set automatic update check to MODE (on|off) [on]", 0 },
{nullptr, 0, nullptr, 0, "Log options:", 5 }, {nullptr, 0, nullptr, 0, "Log options:", 5 },
{"logfile", 'l', "FILE", 0, "Write log to FILE (only for daemon, empty string for using syslog) [" PACKAGE_LOGFILE "]", 0 }, {"logfile", 'l', "FILE", 0, "Write log to FILE (only for daemon, empty string for using syslog) ["
PACKAGE_LOGFILE "]", 0 },
{"log", O_LOG, "AREAS LEVEL", 0, "Only write log for matching AREA(S) below or equal to LEVEL" {"log", O_LOG, "AREAS LEVEL", 0, "Only write log for matching AREA(S) below or equal to LEVEL"
" (alternative to --logareas/--logevel, may be used multiple times) [all notice]", 0 }, " (alternative to --logareas/--logevel, may be used multiple times) [all notice]", 0 },
{"logareas", O_LOGARE, "AREAS", 0, "Only write log for matching AREA(S): main|network|bus|update|all" {"logareas", O_LOGARE, "AREAS", 0, "Only write log for matching AREA(S): main|network|bus|update|other"
" [all]", 0 }, "|all [all]", 0 },
{"loglevel", O_LOGLEV, "LEVEL", 0, "Only write log below or equal to LEVEL: error|notice|info|debug" {"loglevel", O_LOGLEV, "LEVEL", 0, "Only write log below or equal to LEVEL: error|notice|info|debug"
" [notice]", 0 }, " [notice]", 0 },
@@ -661,7 +662,7 @@ void closePidFile() {
/** /**
* Helper method performing shutdown. * Helper method performing shutdown.
*/ */
void shutdown() { void shutdown(bool error = false) {
// stop main loop and all dependent components // stop main loop and all dependent components
if (s_mainLoop) { if (s_mainLoop) {
delete s_mainLoop; delete s_mainLoop;
@@ -690,7 +691,7 @@ void shutdown() {
logNotice(lf_main, "ebusd stopped"); logNotice(lf_main, "ebusd stopped");
closeLogFile(); closeLogFile();
exit(EXIT_SUCCESS); exit(error ? EXIT_FAILURE : EXIT_SUCCESS);
} }
/** /**
@@ -701,7 +702,7 @@ void signalHandler(int sig) {
switch (sig) { switch (sig) {
case SIGHUP: case SIGHUP:
logNotice(lf_main, "SIGHUP received"); logNotice(lf_main, "SIGHUP received");
if (!opt.foreground && opt.logFile && opt.logFile[0] != 0) { // for log file rotation if (!opt.foreground && opt.logFile && opt.logFile[0] != 0) { // for log file rotation
closeLogFile(); closeLogFile();
setLogFile(opt.logFile); setLogFile(opt.logFile);
} }
@@ -928,7 +929,7 @@ void readMessage(Message* message) {
} }
} }
void executeInstructions(MessageMap* messages, bool verbose) { result_t executeInstructions(MessageMap* messages, bool verbose) {
string errorDescription; string errorDescription;
result_t result = messages->resolveConditions(verbose, &errorDescription); result_t result = messages->resolveConditions(verbose, &errorDescription);
if (result != RESULT_OK) { if (result != RESULT_OK) {
@@ -945,6 +946,7 @@ void executeInstructions(MessageMap* messages, bool verbose) {
} }
logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(), logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(),
messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive()); messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive());
return result;
} }
result_t loadDefinitionsFromConfigPath(FileReader* reader, const string& filename, bool verbose, result_t loadDefinitionsFromConfigPath(FileReader* reader, const string& filename, bool verbose,
@@ -992,7 +994,7 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive)
getResultCode(result), errorDescription.c_str()); getResultCode(result), errorDescription.c_str());
} }
messages->unlock(); messages->unlock();
return RESULT_OK; return opt.checkConfig ? result : RESULT_OK;
} }
result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose, string* relativeFile) { result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose, string* relativeFile) {
@@ -1255,7 +1257,7 @@ int main(int argc, char* argv[]) {
logNotice(lf_main, PACKAGE_STRING "." REVISION " performing configuration check..."); logNotice(lf_main, PACKAGE_STRING "." REVISION " performing configuration check...");
result_t result = loadConfigFiles(s_messageMap, true, opt.scanConfig && arg_index < argc); result_t result = loadConfigFiles(s_messageMap, true, opt.scanConfig && arg_index < argc);
executeInstructions(s_messageMap, true); result_t overallResult = executeInstructions(s_messageMap, true);
MasterSymbolString master; MasterSymbolString master;
SlaveSymbolString slave; SlaveSymbolString slave;
while (result == RESULT_OK && opt.scanConfig && arg_index < argc) { while (result == RESULT_OK && opt.scanConfig && arg_index < argc) {
@@ -1267,21 +1269,33 @@ int main(int argc, char* argv[]) {
Message* message = s_messageMap->getScanMessage(address); Message* message = s_messageMap->getScanMessage(address);
if (!message) { if (!message) {
logError(lf_main, "invalid scan address %2.2x", address); logError(lf_main, "invalid scan address %2.2x", address);
if (overallResult == RESULT_OK) {
overallResult = RESULT_ERR_INVALID_ADDR;
}
} else { } else {
message->storeLastData(master, slave); message->storeLastData(master, slave);
string file; string file;
result_t res = loadScanConfigFile(s_messageMap, address, true, &file); result_t res = loadScanConfigFile(s_messageMap, address, true, &file);
executeInstructions(s_messageMap, true); result_t instrRes = executeInstructions(s_messageMap, true);
if (res == RESULT_OK) { if (res == RESULT_OK) {
logInfo(lf_main, "scan config %2.2x: file %s loaded", address, file.c_str()); logInfo(lf_main, "scan config %2.2x: file %s loaded", address, file.c_str());
} else if (overallResult == RESULT_OK) {
overallResult = res;
}
if (overallResult == RESULT_OK && instrRes != RESULT_OK) {
overallResult = instrRes;
} }
} }
} }
if (result != RESULT_OK) {
overallResult = result;
}
if (result == RESULT_OK && opt.dumpConfig) { if (result == RESULT_OK && opt.dumpConfig) {
logNotice(lf_main, "configuration dump:"); logNotice(lf_main, "configuration dump:");
s_messageMap->dump(true, &cout); s_messageMap->dump(true, &cout);
} }
shutdown();
shutdown(overallResult != RESULT_OK);
return 0; return 0;
} }
Executable → Regular
+2 -1
View File
@@ -120,8 +120,9 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose
* Helper method for executing all loaded and resolvable instructions. * Helper method for executing all loaded and resolvable instructions.
* @param messages the @a MessageMap instance. * @param messages the @a MessageMap instance.
* @param verbose whether to verbosely log all problems. * @param verbose whether to verbosely log all problems.
* @return the result code.
*/ */
void executeInstructions(MessageMap* messages, bool verbose = false); result_t executeInstructions(MessageMap* messages, bool verbose = false);
/** /**
* Helper method for loading definitions from a relative file from the config path/URL. * Helper method for loading definitions from a relative file from the config path/URL.
Executable → Regular
+100 -45
View File
@@ -371,12 +371,12 @@ void MainLoop::run() {
continue; continue;
} }
if (m_shutdown) { if (m_shutdown) {
netMessage->setResult("ERR: shutdown", "", cm_normal, now, true); netMessage->setResult("ERR: shutdown", "", nullptr, now, true);
break; break;
} }
string request = netMessage->getRequest(); string request = netMessage->getRequest();
string user = netMessage->getUser(); string user = netMessage->getUser();
ClientMode mode = netMessage->getMode(&since); ClientSettings settings = netMessage->getSettings(&since);
if (!netMessage->isListeningMode()) { if (!netMessage->isListeningMode()) {
since = now; since = now;
} }
@@ -384,9 +384,9 @@ void MainLoop::run() {
bool connected = true; bool connected = true;
if (request.length() > 0) { if (request.length() > 0) {
logDebug(lf_main, ">>> %s", request.c_str()); logDebug(lf_main, ">>> %s", request.c_str());
result_t result = decodeMessage(request, netMessage->isHttp(), &connected, &mode, &user, &reload, &ostream); result_t result = decodeMessage(request, netMessage->isHttp(), &connected, &settings, &user, &reload, &ostream);
if (!netMessage->isHttp() && (ostream.tellp() == 0 || result != RESULT_OK)) { if (!netMessage->isHttp() && (ostream.tellp() == 0 || result != RESULT_OK)) {
if (mode != cm_direct) { if (settings.mode != cm_direct) {
ostream.str(""); ostream.str("");
} }
ostream << getResultCode(result); ostream << getResultCode(result);
@@ -399,25 +399,34 @@ void MainLoop::run() {
if (ostream.tellp() == 0) { if (ostream.tellp() == 0) {
ostream << "\n"; // only for HTTP ostream << "\n"; // only for HTTP
} else if (!netMessage->isHttp()) { } else if (!netMessage->isHttp()) {
ostream << (mode == cm_direct ? "\n" : "\n\n"); ostream << (settings.mode == cm_direct ? "\n" : "\n\n");
} }
} }
if (mode == cm_listen) { if (settings.mode == cm_listen) {
string levels = getUserLevels(user); if (!settings.listenOnlyUnknown) {
messages.clear(); string levels = getUserLevels(user);
m_messages->findAll("", "", levels, false, true, true, true, true, true, since, now, true, &messages); messages.clear();
for (const auto message : messages) { m_messages->findAll("", "", levels, false, true, true, true, true, true, since, now, true, &messages);
ostream << message->getCircuit() << " " << message->getName() << " = " << dec; for (const auto message : messages) {
message->decodeLastData(false, nullptr, -1, 0, &ostream); ostream << message->getCircuit() << " " << message->getName() << " = " << dec;
ostream << endl; message->decodeLastData(false, nullptr, -1, settings.format, &ostream);
ostream << endl;
}
} }
} else if (mode == cm_direct) { if (settings.listenWithUnknown || settings.listenOnlyUnknown) {
if (m_busHandler->isGrabEnabled()) {
m_busHandler->formatGrabResult(true, false, &ostream, true, since, now);
} else {
m_busHandler->enableGrab(true); // needed for listening to all messages
}
}
} else if (settings.mode == cm_direct) {
if (m_busHandler->isGrabEnabled()) { if (m_busHandler->isGrabEnabled()) {
m_busHandler->formatGrabResult(false, false, &ostream, true, since, now); m_busHandler->formatGrabResult(false, false, &ostream, true, since, now);
} }
} }
// send result to client // send result to client
netMessage->setResult(ostream.str(), user, mode, now, !connected); netMessage->setResult(ostream.str(), user, &settings, now, !connected);
} }
} }
@@ -462,7 +471,7 @@ void MainLoop::notifyDeviceData(symbol_t symbol, bool received) {
} }
} }
result_t MainLoop::decodeMessage(const string &data, bool isHttp, bool* connected, ClientMode* mode, result_t MainLoop::decodeMessage(const string &data, bool isHttp, bool* connected, ClientSettings* settings,
string* user, bool* reload, ostringstream* ostream) { string* user, bool* reload, ostringstream* ostream) {
string token, previous; string token, previous;
istringstream stream(data); istringstream stream(data);
@@ -520,8 +529,8 @@ result_t MainLoop::decodeMessage(const string &data, bool isHttp, bool* connecte
transform(cmd.begin(), cmd.end(), cmd.begin(), ::toupper); transform(cmd.begin(), cmd.end(), cmd.begin(), ::toupper);
args.clear(); // empty args is used as command help indicator args.clear(); // empty args is used as command help indicator
} }
if (*mode == cm_direct) { if (settings->mode == cm_direct) {
return executeDirect(args, mode, ostream); return executeDirect(args, &settings->mode, ostream);
} }
if (cmd.empty() && args.size() == 0) { if (cmd.empty() && args.size() == 0) {
return executeHelp(ostream); return executeHelp(ostream);
@@ -553,10 +562,10 @@ result_t MainLoop::decodeMessage(const string &data, bool isHttp, bool* connecte
return executeFind(args, getUserLevels(*user), ostream); return executeFind(args, getUserLevels(*user), ostream);
} }
if (cmd == "L" || cmd == "LISTEN") { if (cmd == "L" || cmd == "LISTEN") {
return executeListen(args, mode, ostream); return executeListen(args, settings, ostream);
} }
if (cmd == "DIRECT") { if (cmd == "DIRECT") {
return executeDirect(args, mode, ostream); return executeDirect(args, &settings->mode, ostream);
} }
if (cmd == "S" || cmd == "STATE") { if (cmd == "S" || cmd == "STATE") {
return executeState(args, ostream); return executeState(args, ostream);
@@ -652,7 +661,7 @@ result_t MainLoop::executeAuth(const vector<string>& args, string* user, ostring
result_t MainLoop::executeRead(const vector<string>& args, const string& levels, ostringstream* ostream) { result_t MainLoop::executeRead(const vector<string>& args, const string& levels, ostringstream* ostream) {
size_t argPos = 1; size_t argPos = 1;
bool hex = false, newDefinition = false, numeric = false, valueName = false; bool hex = false, newDefinition = false;
OutputFormat verbosity = 0; OutputFormat verbosity = 0;
time_t maxAge = 5*60; time_t maxAge = 5*60;
string circuit, params; string circuit, params;
@@ -699,10 +708,9 @@ result_t MainLoop::executeRead(const vector<string>& args, const string& levels,
} else if (args[argPos] == "-vvv" || args[argPos] == "-V") { } else if (args[argPos] == "-vvv" || args[argPos] == "-V") {
verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS; verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS;
} else if (args[argPos] == "-n") { } else if (args[argPos] == "-n") {
numeric = true; verbosity = (verbosity & ~OF_VALUENAME) | OF_NUMERIC;
} else if (args[argPos] == "-N") { } else if (args[argPos] == "-N") {
numeric = true; verbosity = (verbosity & ~OF_NUMERIC) | OF_VALUENAME;
valueName = true;
} else if (args[argPos] == "-c") { } else if (args[argPos] == "-c") {
argPos++; argPos++;
if (argPos >= args.size()) { if (argPos >= args.size()) {
@@ -751,7 +759,7 @@ result_t MainLoop::executeRead(const vector<string>& args, const string& levels,
} }
argPos++; argPos++;
} }
if ((hex && (newDefinition || numeric || verbosity != 0 || !circuit.empty() || !params.empty() || dstAddress != SYN if ((hex && (newDefinition || verbosity != 0 || !circuit.empty() || !params.empty() || dstAddress != SYN
|| pollPriority > 0 || args.size() < argPos + 1)) || pollPriority > 0 || args.size() < argPos + 1))
|| (newDefinition && (hex || !circuit.empty() || pollPriority > 0 || args.size() != argPos + 1))) { || (newDefinition && (hex || !circuit.empty() || pollPriority > 0 || args.size() != argPos + 1))) {
argPos = 0; // print usage argPos = 0; // print usage
@@ -895,7 +903,6 @@ result_t MainLoop::executeRead(const vector<string>& args, const string& levels,
if (!newDefinition && message != nullptr && pollPriority > 0 && message->setPollPriority(pollPriority)) { if (!newDefinition && message != nullptr && pollPriority > 0 && message->setPollPriority(pollPriority)) {
m_messages->addPollMessage(false, message); m_messages->addPollMessage(false, message);
} }
verbosity |= valueName ? OF_VALUENAME : numeric ? OF_NUMERIC : 0;
bool allowCache = !newDefinition && srcAddress == SYN && dstAddress == SYN && maxAge > 0 && params.length() == 0; bool allowCache = !newDefinition && srcAddress == SYN && dstAddress == SYN && maxAge > 0 && params.length() == 0;
Message* cacheMessage = allowCache ? m_messages->find(circuit, name, levels, false, true) : nullptr; Message* cacheMessage = allowCache ? m_messages->find(circuit, name, levels, false, true) : nullptr;
bool hasCache = cacheMessage != nullptr; bool hasCache = cacheMessage != nullptr;
@@ -1479,23 +1486,71 @@ result_t MainLoop::executeFind(const vector<string>& args, const string& levels,
return RESULT_OK; return RESULT_OK;
} }
result_t MainLoop::executeListen(const vector<string>& args, ClientMode* mode, ostringstream* ostream) { result_t MainLoop::executeListen(const vector<string>& args, ClientSettings* settings, ostringstream* ostream) {
if (args.size() == 1) { size_t argPos = 1;
if (*mode == cm_listen) { OutputFormat verbosity = 0;
bool listenWithUnknown = false;
bool listenOnlyUnknown = false;
while (args.size() > argPos && args[argPos][0] == '-') {
if (args[argPos] == "-v") {
switch (verbosity) {
case 0:
verbosity = OF_NAMES;
break;
case OF_NAMES:
verbosity |= OF_UNITS;
break;
case OF_NAMES|OF_UNITS:
verbosity |= OF_COMMENTS;
break;
}
} else if (args[argPos] == "-vv") {
verbosity |= OF_NAMES|OF_UNITS;
} else if (args[argPos] == "-vvv" || args[argPos] == "-V") {
verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS;
} else if (args[argPos] == "-n") {
verbosity = (verbosity & ~OF_VALUENAME) | OF_NUMERIC;
} else if (args[argPos] == "-N") {
verbosity = (verbosity & ~OF_NUMERIC) | OF_VALUENAME;
} else if (args[argPos] == "-u") {
listenWithUnknown = true;
listenOnlyUnknown = false;
} else if (args[argPos] == "-U") {
listenOnlyUnknown = true;
} else {
argPos = 0; // print usage
break;
}
argPos++;
}
if (argPos > 0 && args.size() == argPos) {
settings->format = verbosity;
settings->listenWithUnknown = listenWithUnknown;
settings->listenOnlyUnknown = listenOnlyUnknown;
if (listenWithUnknown || listenOnlyUnknown) {
m_busHandler->enableGrab(true); // needed for listening to all messages
}
if (settings->mode == cm_listen) {
*ostream << "listen continued"; *ostream << "listen continued";
return RESULT_OK; return RESULT_OK;
} }
*mode = cm_listen; settings->mode = cm_listen;
*ostream << "listen started"; *ostream << "listen started";
return RESULT_OK; return RESULT_OK;
} }
if (args.size() != 2 || args[1] != "stop") { if (argPos == 0 || args.size() != argPos + 1 || args[argPos] != "stop") {
*ostream << "usage: listen [stop]\n" *ostream << "usage: listen [-v|-V] [-n|-N] [-u|-U] [stop]\n"
" Listen for updates or stop it."; " Listen for updates or stop it.\n"
" -v increase verbosity (include names/units/comments)\n"
" -V be very verbose (include names, units, and comments)\n"
" -n use numeric value of value=name pairs\n"
" -N use numeric and named value of value=name pairs\n"
" -u include unknown messages\n"
" -U only show unknown messages";
return RESULT_OK; return RESULT_OK;
} }
*mode = cm_normal; settings->mode = cm_normal;
*ostream << "listen stopped"; *ostream << "listen stopped";
return RESULT_OK; return RESULT_OK;
} }
@@ -1573,7 +1628,6 @@ result_t MainLoop::executeDefine(const vector<string>& args, ostringstream* ostr
result_t MainLoop::executeDecode(const vector<string>& args, ostringstream* ostream) { result_t MainLoop::executeDecode(const vector<string>& args, ostringstream* ostream) {
size_t argPos = 1; size_t argPos = 1;
bool numeric = false, valueName = false;
OutputFormat verbosity = 0; OutputFormat verbosity = 0;
while (args.size() > argPos && args[argPos][0] == '-') { while (args.size() > argPos && args[argPos][0] == '-') {
if (args[argPos] == "-v") { if (args[argPos] == "-v") {
@@ -1593,10 +1647,9 @@ result_t MainLoop::executeDecode(const vector<string>& args, ostringstream* ostr
} else if (args[argPos] == "-vvv" || args[argPos] == "-V") { } else if (args[argPos] == "-vvv" || args[argPos] == "-V") {
verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS; verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS;
} else if (args[argPos] == "-n") { } else if (args[argPos] == "-n") {
numeric = true; verbosity = (verbosity & ~OF_VALUENAME) | OF_NUMERIC;
} else if (args[argPos] == "-N") { } else if (args[argPos] == "-N") {
numeric = true; verbosity = (verbosity & ~OF_NUMERIC) | OF_VALUENAME;
valueName = true;
} else { } else {
argPos = 0; // print usage argPos = 0; // print usage
break; break;
@@ -1622,7 +1675,6 @@ result_t MainLoop::executeDecode(const vector<string>& args, ostringstream* ostr
time_t now; time_t now;
time(&now); time(&now);
verbosity |= valueName ? OF_VALUENAME : numeric ? OF_NUMERIC : 0;
istringstream defstr("#\n" + args[argPos]); // ensure first line is not used for determining col names istringstream defstr("#\n" + args[argPos]); // ensure first line is not used for determining col names
string errorDescription; string errorDescription;
DataFieldTemplates* templates = getTemplates("*"); DataFieldTemplates* templates = getTemplates("*");
@@ -1865,7 +1917,7 @@ result_t MainLoop::executeHelp(ostringstream* ostream) {
" hex Send hex data: hex [-s QQ] ZZPBSBNN[DD]* (if enabled)\n" " hex Send hex data: hex [-s QQ] ZZPBSBNN[DD]* (if enabled)\n"
" find|f Find message(s): find [-v|-V] [-r] [-w] [-p] [-a] [-d] [-h] [-i ID] [-f] [-F COL[,COL]*] [-e]" " find|f Find message(s): find [-v|-V] [-r] [-w] [-p] [-a] [-d] [-h] [-i ID] [-f] [-F COL[,COL]*] [-e]"
" [-c CIRCUIT] [-l LEVEL] [NAME]\n" " [-c CIRCUIT] [-l LEVEL] [NAME]\n"
" listen|l Listen for updates: listen [stop]\n" " listen|l Listen for updates: listen [-v|-V] [-n|-N] [-u|-U] [stop]\n"
" direct Enter direct mode\n" " direct Enter direct mode\n"
" state|s Report bus state\n" " state|s Report bus state\n"
" info|i Report information about the daemon, the configuration, and seen devices.\n" " info|i Report information about the daemon, the configuration, and seen devices.\n"
@@ -1895,7 +1947,7 @@ bool parseBoolQuery(const string& value) {
} }
result_t MainLoop::executeGet(const vector<string>& args, bool* connected, ostringstream* ostream) { result_t MainLoop::executeGet(const vector<string>& args, bool* connected, ostringstream* ostream) {
bool numeric = false, valueName = false, required = false, full = false, withWrite = false, raw = false; bool required = false, full = false, withWrite = false, raw = false;
bool withDefinition = false; bool withDefinition = false;
OutputFormat verbosity = OF_NAMES; OutputFormat verbosity = OF_NAMES;
time_t maxAge = -1; time_t maxAge = -1;
@@ -1945,9 +1997,13 @@ result_t MainLoop::executeGet(const vector<string>& args, bool* connected, ostri
verbosity &= ~OF_NAMES; verbosity &= ~OF_NAMES;
} }
} else if (qname == "numeric") { } else if (qname == "numeric") {
numeric = parseBoolQuery(value); if (parseBoolQuery(value)) {
verbosity = (verbosity & ~OF_VALUENAME) | OF_NUMERIC;
}
} else if (qname == "valuename") { } else if (qname == "valuename") {
valueName = parseBoolQuery(value); if (parseBoolQuery(value)) {
verbosity = (verbosity & ~OF_NUMERIC) | OF_VALUENAME;
}
} else if (qname == "full") { } else if (qname == "full") {
full = parseBoolQuery(value); full = parseBoolQuery(value);
} else if (qname == "required") { } else if (qname == "required") {
@@ -1982,8 +2038,7 @@ result_t MainLoop::executeGet(const vector<string>& args, bool* connected, ostri
time_t maxLastUp = 0; time_t maxLastUp = 0;
if (ret == RESULT_OK) { if (ret == RESULT_OK) {
bool first = true; bool first = true;
verbosity |= (valueName ? OF_VALUENAME : numeric ? OF_NUMERIC : 0) | OF_JSON | (full ? OF_ALL_ATTRS : 0) verbosity |= OF_JSON | (full ? OF_ALL_ATTRS : 0) | (withDefinition ? OF_DEFINTION : 0);
| (withDefinition ? OF_DEFINTION : 0);
deque<Message*> messages; deque<Message*> messages;
m_messages->findAll(circuit, name, getUserLevels(user), exact, true, withWrite, true, true, true, 0, 0, false, m_messages->findAll(circuit, name, getUserLevels(user), exact, true, withWrite, true, true, true, 0, 0, false,
&messages); &messages);
Executable → Regular
+4 -4
View File
@@ -144,13 +144,13 @@ class MainLoop : public Thread, DeviceListener {
* @param data the data string to decode (may be empty). * @param data the data string to decode (may be empty).
* @param connected set to false when the client connection shall be closed. * @param connected set to false when the client connection shall be closed.
* @param isHttp true for HTTP message. * @param isHttp true for HTTP message.
* @param mode set to the new client mode. * @param settings set to the new client settings.
* @param user set to the new user name when changed by authentication. * @param user set to the new user name when changed by authentication.
* @param reload set to true when the configuration files were reloaded. * @param reload set to true when the configuration files were reloaded.
* @param ostream the @a ostringstream to format the result string to. * @param ostream the @a ostringstream to format the result string to.
* @return the result code. * @return the result code.
*/ */
result_t decodeMessage(const string& data, bool isHttp, bool* connected, ClientMode* mode, result_t decodeMessage(const string& data, bool isHttp, bool* connected, ClientSettings* settings,
string* user, bool* reload, ostringstream* ostream); string* user, bool* reload, ostringstream* ostream);
/** /**
@@ -238,11 +238,11 @@ class MainLoop : public Thread, DeviceListener {
/** /**
* Execute the listen command. * Execute the listen command.
* @param args the arguments passed to the command (starting with the command itself), or empty for help. * @param args the arguments passed to the command (starting with the command itself), or empty for help.
* @param mode set to the new client mode. * @param settings set to the new client settings.
* @param ostream the @a ostringstream to format the result string to. * @param ostream the @a ostringstream to format the result string to.
* @return the result code. * @return the result code.
*/ */
result_t executeListen(const vector<string>& args, ClientMode* mode, ostringstream* ostream); result_t executeListen(const vector<string>& args, ClientSettings* settings, ostringstream* ostream);
/** /**
* Execute the state command. * Execute the state command.
+15 -6
View File
@@ -109,6 +109,15 @@ static const char* g_keypass = nullptr; //!< client key file password for TLS
bool parseTopic(const string& topic, vector<string>* strs, vector<string>* fields); bool parseTopic(const string& topic, vector<string>* strs, vector<string>* fields);
static char* replaceSecret(char *arg) {
char* ret = strdup(arg);
int cnt = 0;
while (*arg && cnt++ < 256) {
*arg++ = ' ';
}
return ret;
}
/** /**
* The MQTT argument parsing function. * The MQTT argument parsing function.
* @param key the key from @a g_mqtt_argp_options. * @param key the key from @a g_mqtt_argp_options.
@@ -156,7 +165,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
argp_error(state, "invalid mqttpass"); argp_error(state, "invalid mqttpass");
return EINVAL; return EINVAL;
} }
g_password = arg; g_password = replaceSecret(arg);
break; break;
case O_TOPI: // --mqtttopic=ebusd case O_TOPI: // --mqtttopic=ebusd
@@ -237,7 +246,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
argp_error(state, "invalid mqttkeypass"); argp_error(state, "invalid mqttkeypass");
return EINVAL; return EINVAL;
} }
g_keypass = arg; g_keypass = replaceSecret(arg);
break; break;
#endif #endif
@@ -743,12 +752,12 @@ void MqttHandler::run() {
for (auto it = m_updatedMessages.begin(); it != m_updatedMessages.end(); ) { for (auto it = m_updatedMessages.begin(); it != m_updatedMessages.end(); ) {
const vector<Message*>* messages = m_messages->getByKey(it->first); const vector<Message*>* messages = m_messages->getByKey(it->first);
if (messages) { if (messages) {
updates.str("");
updates.clear();
updates << dec;
for (auto message : *messages) { for (auto message : *messages) {
if (message->getLastChangeTime() > 0 && message->isAvailable() if (message->getLastChangeTime() > 0 && message->isAvailable()
&& (!g_onlyChanges || message->getLastChangeTime() > lastUpdates)) { && (!g_onlyChanges || message->getLastChangeTime() > lastUpdates)) {
updates.str("");
updates.clear();
updates << dec;
publishMessage(message, &updates); publishMessage(message, &updates);
} }
} }
@@ -778,7 +787,7 @@ bool MqttHandler::handleTraffic(bool allowReconnect) {
#else #else
ret = mosquitto_loop(m_mosquitto, -1); // waits up to 1 second for network traffic ret = mosquitto_loop(m_mosquitto, -1); // waits up to 1 second for network traffic
#endif #endif
if (!m_connected && ret == MOSQ_ERR_NO_CONN && allowReconnect) { if (!m_connected && (ret == MOSQ_ERR_NO_CONN || ret == MOSQ_ERR_CONN_LOST) && allowReconnect) {
if (m_initialConnectFailed) { if (m_initialConnectFailed) {
#if (LIBMOSQUITTO_MAJOR >= 1) #if (LIBMOSQUITTO_MAJOR >= 1)
ret = mosquitto_connect(m_mosquitto, g_host, g_port, 60); ret = mosquitto_connect(m_mosquitto, g_host, g_port, 60);
Executable → Regular
+1 -1
View File
@@ -208,7 +208,7 @@ Network::~Network() {
stop(); stop();
NetMessage* netMsg; NetMessage* netMsg;
while ((netMsg = m_netQueue->pop()) != nullptr) { while ((netMsg = m_netQueue->pop()) != nullptr) {
netMsg->setResult("ERR: shutdown", "", cm_normal, 0, true); netMsg->setResult("ERR: shutdown", "", nullptr, 0, true);
} }
while (!m_connections.empty()) { while (!m_connections.empty()) {
Connection* connection = m_connections.back(); Connection* connection = m_connections.back();
Executable → Regular
+29 -11
View File
@@ -23,6 +23,7 @@
#include <cstdio> #include <cstdio>
#include <algorithm> #include <algorithm>
#include <list> #include <list>
#include "lib/ebus/datatype.h"
#include "lib/utils/tcpsocket.h" #include "lib/utils/tcpsocket.h"
#include "lib/utils/queue.h" #include "lib/utils/queue.h"
#include "lib/utils/notify.h" #include "lib/utils/notify.h"
@@ -44,6 +45,16 @@ enum ClientMode {
cm_direct, //!< direct mode cm_direct, //!< direct mode
}; };
/**
* Combination of client settings.
*/
struct ClientSettings {
ClientMode mode; //!< the current client mode
OutputFormat format; //!< the output format settings for listen mode
bool listenWithUnknown; //!< include unknown messages in listen mode
bool listenOnlyUnknown; //!< only print unknown messages in listen mode
};
/** /**
* Class for data/message transfer between @a Connection and @a MainLoop. * Class for data/message transfer between @a Connection and @a MainLoop.
*/ */
@@ -54,7 +65,11 @@ class NetMessage {
* @param isHttp whether this is a HTTP message. * @param isHttp whether this is a HTTP message.
*/ */
explicit NetMessage(bool isHttp) explicit NetMessage(bool isHttp)
: m_isHttp(isHttp), m_resultSet(false), m_disconnect(false), m_mode(cm_normal), m_listenSince(0) { : m_isHttp(isHttp), m_resultSet(false), m_disconnect(false), m_listenSince(0) {
m_settings.mode = cm_normal;
m_settings.format = 0;
m_settings.listenWithUnknown = false;
m_settings.listenOnlyUnknown = false;
pthread_mutex_init(&m_mutex, nullptr); pthread_mutex_init(&m_mutex, nullptr);
pthread_cond_init(&m_cond, nullptr); pthread_cond_init(&m_cond, nullptr);
} }
@@ -124,16 +139,19 @@ class NetMessage {
* Set the result string and notify the waiting thread. * Set the result string and notify the waiting thread.
* @param result the result string. * @param result the result string.
* @param user the new user name. * @param user the new user name.
* @param mode the new client mode. * @param settings the new client settings.
* @param listenUntil the end time to which to updates were added (exclusive). * @param listenUntil the end time to which to updates were added (exclusive).
* @param disconnect true when the client shall be disconnected. * @param disconnect true when the client shall be disconnected.
*/ */
void setResult(const string& result, const string& user, ClientMode mode, time_t listenUntil, bool disconnect) { void setResult(const string& result, const string& user, ClientSettings* settings, time_t listenUntil,
bool disconnect) {
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
m_result = result; m_result = result;
m_user = user; m_user = user;
m_disconnect = disconnect; m_disconnect = disconnect;
m_mode = mode; if (settings) {
m_settings = *settings;
}
m_listenSince = listenUntil; m_listenSince = listenUntil;
m_resultSet = true; m_resultSet = true;
pthread_cond_signal(&m_cond); pthread_cond_signal(&m_cond);
@@ -141,22 +159,22 @@ class NetMessage {
} }
/** /**
* Return the client mode. * Return the client settings.
* @param listenSince set listening to the specified start time from which to add updates (inclusive). * @param listenSince set listening to the specified start time from which to add updates (inclusive).
* @return the client mode. * @return the client settings.
*/ */
ClientMode getMode(time_t* listenSince = nullptr) { ClientSettings getSettings(time_t* listenSince = nullptr) {
if (listenSince) { if (listenSince) {
*listenSince = m_listenSince; *listenSince = m_listenSince;
} }
return m_mode; return m_settings;
} }
/** /**
* Return whether this instance is in one of the listening modes. * Return whether this instance is in one of the listening modes.
* @return whether this instance is in one of the listening modes. * @return whether this instance is in one of the listening modes.
*/ */
bool isListeningMode() { return m_mode == cm_listen || m_mode == cm_direct; } bool isListeningMode() { return m_settings.mode == cm_listen || m_settings.mode == cm_direct; }
/** /**
* Return whether the client shall be disconnected. * Return whether the client shall be disconnected.
@@ -190,8 +208,8 @@ class NetMessage {
/** condition variable for exclusive lock. */ /** condition variable for exclusive lock. */
pthread_cond_t m_cond; pthread_cond_t m_cond;
/** the client mode. */ /** the client settings. */
ClientMode m_mode; ClientSettings m_settings;
/** start timestamp of listening update. */ /** start timestamp of listening update. */
time_t m_listenSince; time_t m_listenSince;
+3
View File
@@ -227,6 +227,9 @@ string fetchData(ebusd::TCPSocket* socket, bool listening) {
} }
} else if (newInput) { } else if (newInput) {
getline(cin, message); getline(cin, message);
if (message.length()==0) {
continue;
}
sendmessage = message+'\n'; sendmessage = message+'\n';
socket->send(sendmessage.c_str(), sendmessage.size()); socket->send(sendmessage.c_str(), sendmessage.size());