Alarm test work again.

pull/156/head
Fredrik Öhrström 2020-09-18 20:05:59 +02:00
rodzic 802e62cbbd
commit 891e3f4228
20 zmienionych plików z 264 dodań i 113 usunięć

26
CHANGES
Wyświetl plik

@ -1,6 +1,32 @@
IMPORTANT CHANGES THAT MIGHT AFFECT YOU!
** No udev rules
Wmbusmeters new default behaviour is to NOT exit if no wmbus
device is found. It stays running all the time even if no
wmbus device is detected. As soon as a device is inserted
it will detect/configure and start using the device.
When reading stdin and files, then wmbusmeters will exit
as soon as there is no more data.
This means that the udev rules no longer are needed and must be
removed. This will be done automatically by the install script.
** Use stderr for logging, stdout for data.
wmbusmeters now uses STDERR as default for info/verbose/debug/trace output.
This will not affect you if you run wmbusmeters as a daemon,
but if you start wmbusmeters yourself you should check where stderr is going.
To use the old style add --usestdoutforlogging.
** New features
To list the shell envs for a meter do --listenvs=multical21
To list the fields avilable for a meter do --listfields=multical21
To list all meters do --listmeters
To search for a meter do --listmeters=water or --listmeters=multi
Version 0.9.36: 2020-09-08

Wyświetl plik

@ -142,6 +142,9 @@ Usage: wmbusmeters {options} <device>{:suffix} ( [meter_name] [meter_type]{:<mod
As <options> you can use:
--addconversions=<unit>+ add conversion to these units to json and meter env variables (GJ)
--alarmexpectedactivity=mon-fri(08-17) Specify when the timeout is tested, default is mon-sun(00-23)
--alarmshell=<cmdline> invokes cmdline when an alarm triggers
--alarmtimeout=<time> Expect a telegram to arrive within <time> seconds, eg 60s, 60m, 24h during expected activity.
--debug for a lot of information
--exitafter=<time> exit program after time, eg 20h, 10m 5s
--format=<hr/json/fields> for human readable, json or semicolon separated fields

Wyświetl plik

@ -74,8 +74,6 @@ echo man page: installed "$ROOT"/usr/share/man/man1/wmbusmeters.1.gz
## Create wmbusmeters user
##
ID=$(id -u wmbusmeters 2>/dev/null)
if [ -f "$ROOT"/usr/sbin/nologin ]
then
USERSHELL="$ROOT/usr/sbin/nologin"
@ -88,15 +86,17 @@ fi
if [ "$ADDUSER" = "true" ]
then
# Create the wmbusmeters group, if it does not already exist.
groupadd -f wmbusmeters
ID=$(id -u wmbusmeters 2>/dev/null)
if [ -z "$ID" ]
then
# Create the wmbusmeters group, if it does not already exist.
groupadd -f wmbusmeters
# Create the wmbusmeters user
useradd --system --shell $USERSHELL -g wmbusmeters --groups dialout wmbusmeters
useradd --system --shell $USERSHELL -g wmbusmeters wmbusmeters
echo user: added wmbusmeters
else
echo user: wmbusmeters unmodified
echo user: wmbusmeters already exists
fi
if [ "$(groups wmbusmeters | grep -o dialout)" = "" ]
@ -107,6 +107,16 @@ then
else
echo user: wmbusmeters already added to dialout
fi
if [ "$(groups wmbusmeters | grep -o plugdev)" = "" ]
then
# Add the wmbusmeters user to plugdev
usermod -a -G plugdev wmbusmeters
echo user: added wmbusmeters to plugdev group
else
echo user: wmbusmeters already added to plugdev
fi
if [ ! -z "$SUDO_USER" ]
then
if [ "$(groups $SUDO_USER | grep -o wmbusmeters)" = "" ]
@ -236,7 +246,7 @@ fi
# This means that wmbusmeters will rely on the conf file device setting.
cat <<'EOF' > $CURR_WMBS
[Unit]
Description="wmbusmeters service (no udev trigger)"
Description="wmbusmeters service"
Documentation=https://github.com/weetmuts/wmbusmeters
Documentation=man:wmbusmeters(1)
After=network.target

Wyświetl plik

@ -1,4 +1,4 @@
telegram=|2A442D2C998734761B168D2091D37CAC21576C78|02FF207100041308190000441308190000615B7F616713|+0
{"media":"cold water","meter":"multical21","name":"MyTapWater","id":"76348799","total_m3":6.408,"target_m3":6.408,"max_flow_m3h":0,"flow_temperature_c":127,"external_temperature_c":19,"current_status":"DRY","time_dry":"22-31 days","time_reversed":"","time_leaking":"","time_bursting":"","timestamp":"1111-11-11T11:11:11Z"}
telegram=|2A442D2C998734761B168D2091D37CAC21576C78|02FF207100041308190000441308190000615B7F616713|+3
telegram=|2A442D2C998734761B168D2091D37CAC21576C78|02FF207100041308190000441308190000615B7F616713|+5
{"media":"cold water","meter":"multical21","name":"MyTapWater","id":"76348799","total_m3":6.408,"target_m3":6.408,"max_flow_m3h":0,"flow_temperature_c":127,"external_temperature_c":19,"current_status":"DRY","time_dry":"22-31 days","time_reversed":"","time_leaking":"","time_bursting":"","timestamp":"1111-11-11T11:11:11Z"}

Wyświetl plik

@ -72,7 +72,6 @@ LIST_OF_WMBUS_RECEIVERS
bool detectIfRoot();
string userName();
bool detectIfMemberOfGroup(string group);
void detectProcesses(string cmd, vector<int> *pids);
void detectWMBUSReceiver();
void resetWMBUSReceiver();
void probeFor(string type, AccessCheck(*func)(string,Detected*,SerialCommunicationManager*));
@ -359,24 +358,6 @@ bool detectIfMemberOfGroup(string group)
return false;
}
void detectProcesses(string cmd, vector<int> *pids)
{
vector<string> args;
vector<string> envs;
args.push_back(cmd);
string out;
invokeShellCaptureOutput("/bin/pidof", args, envs, &out, true);
char buf[out.size()+1];
strcpy(buf, out.c_str());
char *pch;
pch = strtok (buf," \n");
while (pch != NULL)
{
pids->push_back(atoi(pch));
pch = strtok (NULL, " \n");
}
}
void stopDaemon()
{

Wyświetl plik

@ -20,6 +20,7 @@
#include"meters.h"
#include"printer.h"
#include"serial.h"
#include"shell.h"
#include"util.h"
#include"version.h"
#include"wmbus.h"
@ -49,6 +50,7 @@ void logStartInformation(Configuration *config);
bool start(Configuration *config);
void startUsingConfigFiles(string root, bool is_daemon, string device_override, string listento_override);
void startDaemon(string pid_file, string device_override, string listento_override); // Will use config files.
void checkIfMultipleWmbusmetersRunning();
void list_shell_envs(Configuration *config, string meter_type);
void list_fields(Configuration *config, string meter_type);
void list_meters(Configuration *config);
@ -81,6 +83,9 @@ set<string> not_swradio_wmbus_devices_;
// it has been read, do not open it again!
set<string> do_not_open_file_again_;
// Store simulation files here.
set<string> simulation_files_;
// Rendering the telegrams to json,fields or shell calls is
// done by the printer.
unique_ptr<Printer> printer_;
@ -150,14 +155,15 @@ provided you with this binary. Read the full license for all details.
const char *short_manual =
#include"short_manual.h"
puts(short_manual);
exit(0);
}
else
if (config->daemon)
{
startDaemon(config->pid_file, config->device_override, config->listento_override);
exit(0);
}
else
if (config->useconfig)
{
startUsingConfigFiles(config->config_root, false, config->device_override, config->listento_override);
@ -492,6 +498,20 @@ void remove_lost_swradio_devices_from_ignore_list(vector<string> &devices)
}
}
void check_statuses()
{
LOCK("(main)", "check_statuses", devices_lock_);
vector<WMBus*> not_working;
for (auto &w : wmbus_devices_)
{
if (w->isWorking())
{
w->checkStatus();
}
}
UNLOCK("(main)", "check_statuses", devices_lock_);
}
void check_for_dead_wmbus_devices(Configuration *config)
{
trace("[MAIN] checking for dead wmbus devices...\n");
@ -503,9 +523,9 @@ void check_for_dead_wmbus_devices(Configuration *config)
if (!w->isWorking())
{
not_working.push_back(w.get());
if (!config->use_auto_detect)
if (config->use_auto_detect)
{
notice("Lost %s closing %s\n", w->device().c_str(), toString(w->type()));
info("Lost %s closing %s\n", w->device().c_str(), toString(w->type()));
}
}
}
@ -529,7 +549,8 @@ void check_for_dead_wmbus_devices(Configuration *config)
{
if (!printed_warning_)
{
info("(main) no wmbus device detected, waiting for a device to be plugged in.\n");
info("No wmbus device detected, waiting for a device to be plugged in.\n");
checkIfMultipleWmbusmetersRunning();
printed_warning_ = true;
}
}
@ -546,7 +567,7 @@ void open_wmbus_device(Configuration *config, string how, string device, Detecte
// A newly plugged in device has been manually configured or automatically detected! Start using it!
if (config->use_auto_detect)
{
notice("Detected %s %s on %s\n", how.c_str(), toString(detected->type), device.c_str());
notice("Configure %s on %s\n", how.c_str(), toString(detected->type), device.c_str());
}
else
{
@ -562,6 +583,11 @@ void open_wmbus_device(Configuration *config, string how, string device, Detecte
bool simulated = detected->type == WMBusDeviceType::DEVICE_SIMULATOR;
wmbus->onTelegram([&, simulated](vector<uchar> data){return meter_manager_->handleTelegram(data, simulated);});
wmbus->setTimeout(config->alarm_timeout, config->alarm_expected_activity);
if (detected->type == DEVICE_SIMULATOR)
{
debug("(main) added %s to files\n", detected->device.file.c_str());
simulation_files_.insert(detected->device.file);
}
UNLOCK("(main)", "perform_auto_scan_of_devices", devices_lock_);
}
@ -593,11 +619,11 @@ void perform_auto_scan_of_serial_devices(Configuration *config)
// A modem, an android phone, a teletype Model 33, etc....
// Mark this serial device as unknown, to avoid repeated detection attempts.
not_serial_wmbus_devices_.insert(device);
info("(main) ignoring %s, it does not respond as any of the supported wmbus devices.\n", device.c_str());
verbose("(main) ignoring %s, it does not respond as any of the supported wmbus devices.\n", device.c_str());
}
else
{
open_wmbus_device(config, "auto scan detected", device, &detected);
open_wmbus_device(config, "during auto scan", device, &detected);
}
}
}
@ -630,12 +656,12 @@ void perform_auto_scan_of_swradio_devices(Configuration *config)
{
// We cannot access this swradio device.
not_swradio_wmbus_devices_.insert(device);
info("(main) ignoring swradio %s since it is unavailable.\n", device.c_str());
verbose("(main) ignoring swradio %s since it is unavailable.\n", device.c_str());
}
else
{
detected.device.file = device;
open_wmbus_device(config, "auto scan detected", device, &detected);
open_wmbus_device(config, "during auto scan", device, &detected);
}
}
}
@ -659,7 +685,11 @@ void detectAndConfigureWMBusDevices(Configuration *config)
trace("(main) %s already configured\n", sd->device().c_str());
continue;
}
if (simulation_files_.count(device.file) > 0)
{
debug("(main) %s already configured as simulation\n", device.file.c_str());
continue;
}
if (do_not_open_file_again_.count(device.file) == 0)
{
Detected detected = detectWMBusDeviceSetting(device.file,
@ -674,7 +704,7 @@ void detectAndConfigureWMBusDevices(Configuration *config)
// Only read stdin and files once!
do_not_open_file_again_.insert(device.file);
}
open_wmbus_device(config, "manual configuration", device.str(), &detected);
open_wmbus_device(config, "using manual setting", device.str(), &detected);
}
}
else
@ -745,6 +775,7 @@ bool start(Configuration *config)
// If our software unexpectedly exits, then stop the manager, to try
// to achive a nice shutdown.
onExit(call(serial_manager_.get(),stop));
serial_manager_->eachEventLooping([]() { check_statuses(); });
// Create the printer object that knows how to translate
// telegrams into json, fields that are written into log files
@ -778,10 +809,14 @@ bool start(Configuration *config)
if (!config->use_auto_detect)
{
serial_manager_->expectDevicesToWork();
if (simulation_files_.size() == 0)
{
serial_manager_->expectDevicesToWork();
}
if (wmbus_devices_.size() == 0)
{
notice("(main) no wmbus device configured! Exiting.\n");
notice("No wmbus device configured! Exiting.\n");
checkIfMultipleWmbusmetersRunning();
serial_manager_->stop();
}
}
@ -789,7 +824,8 @@ bool start(Configuration *config)
{
if (wmbus_devices_.size() == 0)
{
notice("(main) no wmbus device detected, waiting for a device to be plugged in.\n");
notice("No wmbus device detected, waiting for a device to be plugged in.\n");
checkIfMultipleWmbusmetersRunning();
}
}
@ -947,3 +983,29 @@ void startUsingConfigFiles(string root, bool is_daemon, string device_override,
}
while (restart);
}
void checkIfMultipleWmbusmetersRunning()
{
pid_t my_pid = getpid();
vector<int> daemons;
detectProcesses("wmbusmetersd", &daemons);
for (int i : daemons)
{
if (i != my_pid)
{
info("Notice! Wmbusmeters daemon (pid %d) is running and it might hog any wmbus devices.\n", i);
}
}
vector<int> processes;
detectProcesses("wmbusmeters", &processes);
for (int i : processes)
{
if (i != my_pid)
{
info("Notice! Other wmbusmeters (pid %d) is running and it might hog any wmbus devices.\n", i);
}
}
}

Wyświetl plik

@ -77,6 +77,8 @@ struct SerialCommunicationManagerImp : public SerialCommunicationManager
void listenTo(SerialDevice *sd, function<void()> cb);
void onDisappear(SerialDevice *sd, function<void()> cb);
void eachEventLooping(function<void()> cb);
void expectDevicesToWork();
void stop();
void startEventLoop();
@ -121,17 +123,18 @@ private:
pthread_mutex_t devices_lock_ = PTHREAD_MUTEX_INITIALIZER;
vector<SerialDeviceImp*> devices_;
vector<Timer> timers_;
pthread_mutex_t timers_lock_ = PTHREAD_MUTEX_INITIALIZER;
// pthread_mutex_t timers_lock_ = PTHREAD_MUTEX_INITIALIZER;
bool calling_timers_ {};
pthread_mutex_t timer_thread_lock_ = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t timer_thread_lock_ = PTHREAD_MUTEX_INITIALIZER; // Only have one regular callback thread running.
function<void()> on_event_looping_;
};
SerialCommunicationManagerImp::~SerialCommunicationManagerImp()
{
// Stop the loop.
stop();
// Close all managed devices (not yet closed)
closeAll();
// Stop the event loop.
stop();
// Grab the event_loop_lock. This can only be done when the eventLoop has stopped running.
LOCK("(serial)", "destructor", event_loop_lock_);
// Now we can be sure the eventLoop has stopped and it is safe to
@ -723,6 +726,11 @@ void SerialCommunicationManagerImp::onDisappear(SerialDevice *sd, function<void(
si->on_disappear_ = cb;
}
void SerialCommunicationManagerImp::eachEventLooping(function<void()> cb)
{
on_event_looping_ = cb;
}
void SerialCommunicationManagerImp::expectDevicesToWork()
{
debug("(serial) expecting devices to work\n");
@ -770,14 +778,15 @@ void SerialCommunicationManagerImp::waitForStop()
}
usleep(1000*1000);
}
debug("(serial) closing %d devices\n", devices_.size());
closeAll();
if (signalsInstalled())
{
if (select_thread_) pthread_kill(select_thread_, SIGUSR1);
}
pthread_join(select_thread_, NULL);
debug("(serial) closing %d devices\n", devices_.size());
closeAll();
}
bool SerialCommunicationManagerImp::isRunning()
@ -848,19 +857,28 @@ void SerialCommunicationManagerImp::closeAll()
void SerialCommunicationManagerImp::executeTimerCallbacks()
{
time_t curr = time(NULL);
LOCK("(serial)", "executeTimerCallbacks", timers_lock_);
vector<Timer> timers_copy = timers_;
UNLOCK("(serial)", "executeTimerCallbacks", timers_lock_);
vector<Timer> to_be_called;
for (Timer &t : timers_copy)
LOCK("(serial)", "executeTimerCallbacks", devices_lock_);
for (Timer &t : timers_)
{
if (t.isTime(curr))
{
trace("[SERIAL] invoking callback %d %s\n", t.id, t.name.c_str());
trace("[SERIAL] timer isTime! %d %s\n", t.id, t.name.c_str());
t.last_call = curr;
t.callback();
to_be_called.push_back(t);
}
}
UNLOCK("(serial)", "executeTimerCallbacks", devices_lock_);
for (Timer &t : to_be_called)
{
trace("[SERIAL] invoking callback %s(%d)\n", t.name.c_str(), t.id);
t.callback();
}
}
time_t SerialCommunicationManagerImp::calculateTimeToNearestTimerCallback(time_t now)
@ -1006,10 +1024,13 @@ void *SerialCommunicationManagerImp::eventLoop()
}
else
{
debug("(serial) not starting timer thread since it is already running.\n");
trace("(serial) not starting timer thread since it is already running.\n");
}
}
// Invoke callback every event looping....
if (on_event_looping_) on_event_looping_();
if (non_working.size() > 0 && expect_devices_to_work_ && resetting_ == false)
{
debug("(serial) non working devices found, exiting.\n");
@ -1121,17 +1142,17 @@ SerialCommunicationManager::~SerialCommunicationManager()
int SerialCommunicationManagerImp::startRegularCallback(string name, int seconds, function<void()> callback)
{
Timer t = { (int)timers_.size(), seconds, time(NULL), callback, name };
LOCK("(serial)", "startRegularCallback", timers_lock_);
LOCK("(serial)", "startRegularCallback", devices_lock_);
timers_.push_back(t);
UNLOCK("(serial)", "startRegularCallback", timers_lock_);
debug("(serial) registered regular callback %d %s every %d seconds\n", t.id, name.c_str(), seconds);
UNLOCK("(serial)", "startRegularCallback", devices_lock_);
debug("(serial) registered regular callback %s(%d) every %d seconds\n", name.c_str(), t.id, seconds);
return t.id;
}
void SerialCommunicationManagerImp::stopRegularCallback(int id)
{
debug("(serial) stopping regular callback %d\n", id);
LOCK("(serial)", "stopRegularCallback", timers_lock_);
LOCK("(serial)", "stopRegularCallback", devices_lock_);
for (auto i = timers_.begin(); i != timers_.end(); ++i)
{
if ((*i).id == id)
@ -1140,7 +1161,7 @@ void SerialCommunicationManagerImp::stopRegularCallback(int id)
break;
}
}
UNLOCK("(serial)", "startRegularCallback", timers_lock_);
UNLOCK("(serial)", "stopRegularCallback", devices_lock_);
}

Wyświetl plik

@ -79,6 +79,8 @@ struct SerialCommunicationManager
virtual void listenTo(SerialDevice *sd, function<void()> cb) = 0;
// Invoke cb callback when the serial device has disappeared!
virtual void onDisappear(SerialDevice *sd, function<void()> cb) = 0;
// Invoke once every select loop, typically once per second.
virtual void eachEventLooping(function<void()> cb) = 0;
// Normally the communication mananager runs for ever.
// But if you expect configured devices to work, then
// the manager will exit when there are no working devices.

Wyświetl plik

@ -325,3 +325,22 @@ bool invokeShellCaptureOutput(string program, vector<string> args, vector<string
return true;
}
void detectProcesses(string cmd, vector<int> *pids)
{
vector<string> args;
vector<string> envs;
args.push_back(cmd);
string out;
invokeShellCaptureOutput("/bin/pidof", args, envs, &out, true);
char buf[out.size()+1];
strcpy(buf, out.c_str());
char *pch;
pch = strtok (buf," \n");
while (pch != NULL)
{
pids->push_back(atoi(pch));
pch = strtok (NULL, " \n");
}
}

Wyświetl plik

@ -25,3 +25,4 @@ bool invokeShellCaptureOutput(string program, vector<string> args, vector<string
bool invokeBackgroundShell(string program, vector<string> args, vector<string> envs, int *out, int *pid);
bool stillRunning(int pid);
void stopBackgroundShell(int pid);
void detectProcesses(string cmd, vector<int> *pids);

Wyświetl plik

@ -333,6 +333,7 @@ int test_linkmodes()
}
debug("test7 OK\n\n");
manager->stop();
return 0;
}

Wyświetl plik

@ -21,9 +21,7 @@
// Default select timeout one second.
#define SELECT_TIMEOUT 1
// Default checkStatus callback frequency every 60 seconds, when an alarmtimeout has been set.
#define CHECKSTATUS_TIMER 60
// When running internal tests on timeouts use 2 seconds instead.
#define CHECKSTATUS_TIMER_INTERNAL_TESTING 2
// Default checkStatus callback frequency every 2 seconds, when an alarmtimeout has been set.
#define CHECKSTATUS_TIMER 2
#endif

Wyświetl plik

@ -3262,7 +3262,6 @@ bool Telegram::findFormatBytesFromKnownMeterSignatures(vector<uchar> *format_byt
WMBusCommonImplementation::~WMBusCommonImplementation()
{
manager_->stopRegularCallback(regular_cb_id_);
debug("(wmbus) deleted %s\n", toString(type()));
}
@ -3277,12 +3276,14 @@ WMBusCommonImplementation::WMBusCommonImplementation(WMBusDeviceType t,
// Initialize timeout from now.
last_received_ = time(NULL);
/*
// Invoke the check status once per minute. Unless internal testing, then it is every 2 seconds.
int default_timer = isInternalTestingEnabled() ? CHECKSTATUS_TIMER_INTERNAL_TESTING : CHECKSTATUS_TIMER;
int default_timer = CHECKSTATUS_TIMER;
string info = "simulator";
if (serial != NULL) info = serial_->device();
string alarm_id = "CHECK_STATUS "+string(toString(t))+":"+info;
regular_cb_id_ = manager_->startRegularCallback(alarm_id, default_timer, call(this,checkStatus));
*/
}
WMBusDeviceType WMBusCommonImplementation::type()
@ -3394,6 +3395,7 @@ bool WMBusCommonImplementation::isWorking()
void WMBusCommonImplementation::checkStatus()
{
trace("[ALARM] check status\n");
if (protocol_error_count_ >= 20)
{
string msg;
@ -3416,58 +3418,73 @@ void WMBusCommonImplementation::checkStatus()
time_t now = time(NULL);
time_t then = now - timeout_;
time_t since = now-last_received_;
if (timeout_ > 0 && since < timeout_)
// If no timeout set, just return.
if (timeout_ == 0) return;
if (since < timeout_)
{
trace("[WMBUS] No timeout. All ok. (%d s) Now %d seconds since last telegram was received.\n", since);
trace("[WMBUS] No timeout since=%d timeout=%d. All ok.\n", since, timeout_);
return;
}
last_received_ = time(NULL);
// The timeout has expired! But is the timeout expected because there should be no activity now?
// Also, do not sound the alarm unless we actually have a possible timeout within the expected activity,
// otherwise we will always get an alarm when we enter the expected activity period.
if (isInsideTimePeriod(now, expected_activity_) &&
isInsideTimePeriod(then, expected_activity_))
if (!(isInsideTimePeriod(now, expected_activity_) &&
isInsideTimePeriod(then, expected_activity_)))
{
trace("[WMBUS] hit timeout(%d s) but this is ok, since there is no expected activity.\n", timeout_);
return;
}
time_t nowt = time(NULL);
struct tm nowtm;
localtime_r(&nowt, &nowtm);
// Ok, timeout has triggered for real! Deal with it!
struct tm nowtm;
localtime_r(&now, &nowtm);
string now = strdatetime(&nowtm);
string nowtxt = strdatetime(&nowtm);
string msg;
strprintf(msg, "%d seconds of inactivity resetting %s %s "
"(timeout %ds expected %s now %s)",
since, device().c_str(), toString(type()),
timeout_, expected_activity_.c_str(), now.c_str());
string msg;
strprintf(msg, "%d seconds of inactivity resetting %s %s "
"(timeout %ds expected %s now %s)",
since, device().c_str(), toString(type()),
timeout_, expected_activity_.c_str(), nowtxt.c_str());
logAlarm("inactivity", msg);
logAlarm("inactivity", msg);
bool ok = reset();
if (ok)
{
warning("(wmbus) successfully reset wmbus device\n");
}
else
{
strprintf(msg, "failed to reset wmbus device %s %s exiting wmbusmeters", device().c_str(), toString(type()));
logAlarm("device_failure", msg);
manager_->stop();
}
bool ok = reset();
if (ok)
{
warning("(wmbus) successfully reset wmbus device\n");
}
else
{
debug("(wmbus) Hit timeout(%d s) but no expected activity!\n", timeout_);
strprintf(msg, "failed to reset wmbus device %s %s exiting wmbusmeters", device().c_str(), toString(type()));
logAlarm("device_failure", msg);
manager_->stop();
}
// Fake last received to restart the timeout.
last_received_ = time(NULL);
}
void WMBusCommonImplementation::setTimeout(int seconds, string expected_activity)
{
assert(seconds >= 0);
timeout_ = seconds;
if (expected_activity == "")
{
expected_activity = "mon-sun(00-23)";
}
expected_activity_ = expected_activity;
debug("(wmbus) set timeout %s to \"%d\" with expected activity \"%s\"\n", toString(type_), timeout_, expected_activity_.c_str());
if (seconds > 0)
{
debug("(wmbus) set timeout %s to \"%d\" with expected activity \"%s\"\n", toString(type_), timeout_, expected_activity_.c_str());
}
else
{
debug("(wmbus) no alarm (expected activity) for %s\n", toString(type_));
}
}
int toInt(TPLSecurityMode tsm)

Wyświetl plik

@ -61,7 +61,9 @@ struct WMBusIM871A : public virtual WMBusCommonImplementation
void simulate() { }
WMBusIM871A(unique_ptr<SerialDevice> serial, SerialCommunicationManager *manager);
~WMBusIM871A() { }
~WMBusIM871A() {
manager_->onDisappear(this->serial(), NULL);
}
private:

Wyświetl plik

@ -56,6 +56,11 @@ struct WMBusRTLWMBUS : public virtual WMBusCommonImplementation
void simulate();
WMBusRTLWMBUS(unique_ptr<SerialDevice> serial, SerialCommunicationManager *manager);
~WMBusRTLWMBUS()
{
manager_->listenTo(this->serial(), NULL);
manager_->onDisappear(this->serial(), NULL);
}
private:

Wyświetl plik

@ -177,7 +177,11 @@ void WMBusSimulator::simulate()
curr = time(NULL);
if (curr > start_time + rel_time) break;
usleep(1000*1000);
if (!manager_->isRunning()) break;
if (!manager_->isRunning())
{
debug("(simulator) exiting early\n");
break;
}
}
}
}

Wyświetl plik

@ -70,8 +70,6 @@ struct WMBusCommonImplementation : public virtual WMBus
bool link_modes_configured_ {};
LinkModeSet link_modes_ {};
int regular_cb_id_;
unique_ptr<SerialDevice> serial_;
};

11
test.sh
Wyświetl plik

@ -78,11 +78,10 @@ if [ "$?" != "0" ]; then RC="1"; fi
tests/test_serial_bads.sh $PROG
if [ "$?" != "0" ]; then RC="1"; fi
#if [ "$(uname)" = "Linux" ]
#then
# tests/test_alarm.sh $PROG
# if [ "$?" != "0" ]; then RC="1"; fi
#fi
if [ "$(uname)" = "Linux" ]
then
tests/test_alarm.sh $PROG
if [ "$?" != "0" ]; then RC="1"; fi
fi
exit $RC

Wyświetl plik

@ -1,4 +1,4 @@
loglevel=debug
loglevel=normal
# Set internaltesting=true to shorten times for test to finish in reasonable time.
internaltesting=true
device=must_be_overriden
@ -9,7 +9,7 @@ shell=echo METER =="$METER_JSON"== >> /tmp/wmbusmeters_telegram_test
# The alarm will always be logged in the log file.
alarmshell=echo ALARM_SHELL "$ALARM_TYPE" "$ALARM_MESSAGE" >> /tmp/wmbusmeters_alarm_test
# Expect a received telegram no longer than 1 second since the last telegram!
alarmtimeout=1s
alarmtimeout=4s
# Only sound the alarm if the timeout is reached when the radio is actually
# expected to be transmitting. Some meters disable transmissions during nights
# and weekends. Change this to mon-fri(08-19)

Wyświetl plik

@ -12,10 +12,10 @@ echo "RUNNING $TESTNAME ..."
> /tmp/wmbusmeters_telegram_test
> /tmp/wmbusmeters_alarm_test
$PROG --useconfig=tests/config7 --device=simulations/simulation_alarm.txt | sed 's/....-..-.. ..:../1111-11-11 11:11/' > $TEST/test_output.txt
$PROG --useconfig=tests/config7 --device=simulations/simulation_alarm.txt 2> $TEST/test_stderr.txt | sed 's/....-..-..T..:..:..Z/1111-11-11T11:11:11Z/' > $TEST/test_output.txt
cat > $TEST/test_expected.txt <<EOF
(alarm) inactivity: 2 seconds of inactivity resetting simulations/simulation_alarm.txt DEVICE_SIMULATOR (timeout 1s expected mon-sun(00-23) now 1111-11-11 11:11)
(alarm) inactivity: 4 seconds of inactivity resetting simulations/simulation_alarm.txt DEVICE_SIMULATOR (timeout 4s expected mon-sun(00-23) now 1111-11-11 11:11)
(wmbus) successfully reset wmbus device
EOF
@ -25,16 +25,18 @@ METER =={"media":"cold water","meter":"multical21","name":"Water","id":"76348799
EOF
cat > /tmp/wmbusmeters_alarm_expected <<EOF
ALARM_SHELL inactivity 2 seconds of inactivity resetting simulations/simulation_alarm.txt DEVICE_SIMULATOR (timeout 1s expected mon-sun(00-23) now 1111-11-11 11:11)
ALARM_SHELL inactivity 4 seconds of inactivity resetting simulations/simulation_alarm.txt DEVICE_SIMULATOR (timeout 4s expected mon-sun(00-23) now 1111-11-11 11:11)
EOF
REST=$(diff $TEST/test_output.txt $TEST/test_expected.txt)
cat $TEST/test_stderr.txt | sed 's/now ....-..-.. ..:../now 1111-11-11 11:11/' > $TEST/test_responses.txt
REST=$(diff $TEST/test_responses.txt $TEST/test_expected.txt)
if [ ! -z "$REST" ]
then
echo ERROR STDOUT: $TESTNAME
echo ERROR STDERR: $TESTNAME
echo -----------------
diff $TEST/test_output.txt $TEST/test_expected.txt
diff $TEST/test_responses.txt $TEST/test_expected.txt
echo -----------------
TESTRESULT="ERROR"
fi