Added resetafter, regular reset.

pull/156/head
Fredrik Öhrström 2020-09-25 23:56:50 +02:00
rodzic 7c361ce9ac
commit 7e07af03e7
11 zmienionych plików z 74 dodań i 38 usunięć

Wyświetl plik

@ -166,6 +166,7 @@ As <options> you can use:
--meterfilestimestamp=(never|day|hour|minute|micros) the meter file is suffixed with a
timestamp (localtime) with the given resolution.
--oneshot wait for an update from each meter, then quit
--resetafter=<time> reset the wmbus dongle regularly, default is 24h
--selectfields=id,timestamp,total_m3 select fields to be printed
--separator=<c> change field separator to c
--shell=<cmdline> invokes cmdline with env variables containing the latest reading

Wyświetl plik

@ -429,6 +429,14 @@ shared_ptr<Configuration> parseCommandLine(int argc, char **argv) {
i++;
continue;
}
if (!strncmp(argv[i], "--resetafter=", 13) && strlen(argv[i]) > 13) {
c->resetafter = parseTime(argv[i]+13);
if (c->resetafter <= 0) {
error("Not a valid time to regularly reset after. \"%s\"\n", argv[i]+13);
}
i++;
continue;
}
if (!strncmp(argv[i], "--alarmtimeout=", 15)) {
c->alarm_timeout = parseTime(argv[i]+15);
if (c->alarm_timeout <= 0) {

Wyświetl plik

@ -189,6 +189,22 @@ void handleInternalTesting(Configuration *c, string value)
}
}
void handleResetAfter(Configuration *c, string s)
{
if (s.length() >= 1)
{
c->resetafter = parseTime(s.c_str());
if (c->resetafter <= 0)
{
warning("Not a valid time to reset wmbus devices after. \"%s\"\n", s.c_str());
}
}
else
{
warning("Reset after must be a valid number of seconds.\n");
}
}
bool handleDevice(Configuration *c, string devicefile)
{
Device device;
@ -456,6 +472,7 @@ shared_ptr<Configuration> loadConfiguration(string root, string device_override,
else if (p.first == "addconversions") handleConversions(c, p.second);
else if (p.first == "selectfields") handleSelectedFields(c, p.second);
else if (p.first == "shell") handleShell(c, p.second);
else if (p.first == "resetafter") handleResetAfter(c, p.second);
else if (p.first == "alarmshell") handleAlarmShell(c, p.second);
else if (startsWith(p.first, "json_"))
{

Wyświetl plik

@ -82,6 +82,7 @@ struct Configuration
std::string list_meter;
bool oneshot {};
int exitafter {}; // Seconds to exit.
int resetafter {}; // Reset the wmbus devices regularly.
std::vector<Device> supplied_wmbus_devices; // /dev/ttyUSB0, simulation.txt, rtlwmbus, /dev/ttyUSB1:9600
bool use_auto_detect {}; // Set to true if auto was supplied as device.
std::vector<Device> supplied_mbus_devices; // /dev/ttyACM0

Wyświetl plik

@ -563,8 +563,14 @@ void open_wmbus_device(Configuration *config, string how, string device, Detecte
wmbus_devices_.push_back(w);
WMBus *wmbus = wmbus_devices_.back().get();
wmbus->setLinkModes(config->listen_to_link_modes);
//string using_link_modes = wmbus->getLinkModes().hr();
//verbose("(config) listen to link modes: %s\n", using_link_modes.c_str());
// By default, reset your dongle once every day.
int regular_reset = 24*3600;
if (config->resetafter != 0) regular_reset = config->resetafter;
wmbus->setResetInterval(regular_reset);
string using_link_modes = wmbus->getLinkModes().hr();
verbose("(config) listen to link modes: %s\n", using_link_modes.c_str());
bool simulated = false;
if (detected->type == DEVICE_SIMULATOR)
{

Wyświetl plik

@ -154,6 +154,14 @@ struct SerialDeviceImp : public SerialDevice
SerialCommunicationManager *manager() { return manager_; }
void resetInitiated() { debug("(serial) initiate reset\n"); resetting_ = true; }
void resetCompleted() { debug("(serial) reset completed\n"); resetting_ = false; }
bool checkIfDataIsPending()
{
if (!opened() || !working()) return false; // No data can be pending if device is not opened nor working.
int available = -1;
int rc = ioctl(fd_, FIONREAD, &available);
if (rc == -1) return false;
return available > 0;
}
SerialDeviceImp(SerialCommunicationManagerImp *manager)
{
@ -249,7 +257,6 @@ struct SerialDeviceTTY : public SerialDeviceImp
AccessCheck open(bool fail_if_not_ok);
void close();
void checkIfShouldReopen();
bool send(vector<uchar> &data);
bool working();
string device() { return device_; }
@ -321,32 +328,6 @@ void SerialDeviceTTY::close()
verbose("(serialtty) closed %s\n", device_.c_str());
}
void SerialDeviceTTY::checkIfShouldReopen()
{
assert(0);
/* if (fd_ != -1 && reopen_after_ > 0)
{
time_t curr = time(NULL);
time_t diff = curr-start_since_reopen_;
int available = 0;
ioctl(fd_, FIONREAD, &available);
// Is it time to reopen AND there is no data available for reading?
if (diff > reopen_after_ && !available)
{
start_since_reopen_ = curr;
debug("(serialtty) reopened after %ld seconds\n", diff);
::flock(fd_, LOCK_UN);
::close(fd_);
fd_ = openSerialTTY(device_.c_str(), baud_rate_);
if (fd_ == -1) {
error("Could not re-open %s with %d baud N81\n", device_.c_str(), baud_rate_);
}
}
}*/
}
bool SerialDeviceTTY::send(vector<uchar> &data)
{
LOCK_WRITE_SERIAL(send);
@ -400,7 +381,6 @@ struct SerialDeviceCommand : public SerialDeviceImp
AccessCheck open(bool fail_if_not_ok);
void close();
void checkIfShouldReopen() {}
bool send(vector<uchar> &data);
int available();
bool working();
@ -528,7 +508,6 @@ struct SerialDeviceFile : public SerialDeviceImp
AccessCheck open(bool fail_if_not_ok);
void close();
bool working();
void checkIfShouldReopen();
bool send(vector<uchar> &data);
int available();
string device() { return file_; }
@ -615,10 +594,6 @@ bool SerialDeviceFile::working()
return true;
}
void SerialDeviceFile::checkIfShouldReopen()
{
}
bool SerialDeviceFile::send(vector<uchar> &data)
{
return true;
@ -635,7 +610,6 @@ struct SerialDeviceSimulator : public SerialDeviceImp
AccessCheck open(bool fail_if_not_ok) { return AccessCheck::AccessOK; };
void close() { };
void checkIfShouldReopen() { }
bool readonly() { return true; }
bool send(vector<uchar> &data) { return true; };
void fill(vector<uchar> &data) { data_ = data; on_data_(); }; // Fill buffer and trigger callback.

Wyświetl plik

@ -55,7 +55,7 @@ struct SerialDevice
// Return underlying device as string.
virtual std::string device() = 0;
virtual void checkIfShouldReopen() = 0;
virtual bool checkIfDataIsPending() = 0;
virtual void fill(std::vector<uchar> &data) = 0; // Fill buffer with raw data.
virtual SerialCommunicationManager *manager() = 0;
virtual void resetInitiated() = 0;

Wyświetl plik

@ -3278,6 +3278,7 @@ WMBusCommonImplementation::WMBusCommonImplementation(WMBusDeviceType t,
{
// Initialize timeout from now.
last_received_ = time(NULL);
last_reset_ = time(NULL);
sem_init(&command_wait_, 0, 0);
manager_->listenTo(this->serial(),call(this,processSerialData));
manager_->onDisappear(this->serial(),call(this,disconnectedFromDevice));
@ -3339,6 +3340,7 @@ LinkModeSet WMBusCommonImplementation::protectedGetLinkModes()
bool WMBusCommonImplementation::reset()
{
last_reset_ = time(NULL);
bool resetting = false;
if (serial())
{
@ -3393,6 +3395,22 @@ bool WMBusCommonImplementation::isWorking()
void WMBusCommonImplementation::checkStatus()
{
trace("[ALARM] check status\n");
time_t since_last_reset = time(NULL) - last_reset_;
if (reset_timeout_ > 1 &&
since_last_reset > reset_timeout_ &&
!serial()->checkIfDataIsPending() &&
!serial()->readonly())
{
verbose("(wmbus) regular reset of %s %s\n", device().c_str(), toString(type()));
bool ok = reset();
if (ok) return;
string msg;
strprintf(msg, "failed regular reset of %s %s", device().c_str(), toString(type()));
logAlarm("regular_reset", msg);
return;
}
if (protocol_error_count_ >= 20)
{
string msg;
@ -3465,6 +3483,11 @@ void WMBusCommonImplementation::checkStatus()
}
}
void WMBusCommonImplementation::setResetInterval(int seconds)
{
reset_timeout_ = seconds;
}
void WMBusCommonImplementation::setTimeout(int seconds, string expected_activity)
{
assert(seconds >= 0);

Wyświetl plik

@ -495,6 +495,9 @@ struct WMBus
// within seconds, then invoke reset(). However do not reset
// when no activity is expected.
virtual void setTimeout(int seconds, std::string expected_activity) = 0;
// Set a regular interval for resetting the wmbus device.
// Default is once ever 24 hours.
virtual void setResetInterval(int seconds) = 0;
virtual ~WMBus() = 0;
};

Wyświetl plik

@ -39,6 +39,7 @@ struct WMBusCommonImplementation : public virtual WMBus
void checkStatus();
bool isWorking();
void setTimeout(int seconds, std::string expected_activity);
void setResetInterval(int seconds);
void setLinkModes(LinkModeSet lms);
virtual void processSerialData() = 0;
void disconnectedFromDevice();
@ -69,7 +70,7 @@ struct WMBusCommonImplementation : public virtual WMBus
string expected_activity_ {}; // During which times should we care about timeouts?
time_t last_received_ {}; // When as the last telegram reception?
time_t last_reset_ {}; // When did we last attempt a reset of the dongle?
int reset_timeout_ {}; // When set to 24*3600 reset the device once every 24 hours.
bool link_modes_configured_ {};
LinkModeSet link_modes_ {};

Wyświetl plik

@ -65,6 +65,8 @@ mqtt_publish) sent to a REST API (eg curl) or store it in a database
\fB\--oneshot\fR wait for an update from each meter, then quit
\fB\--resetafter=\fR<time> reset the wmbus dongle regularly, default is 24h
\fB\--separator=\fR<c> change field separator to c
\fB\--selectfields=\fRid,timestamp,total_m3 select fields to be printed (--listfields=<meter> to list available fields)