kopia lustrzana https://github.com/weetmuts/wmbusmeters
Add bus alias to meter info.
rodzic
71c32c7852
commit
948064ae76
1
Makefile
1
Makefile
|
@ -114,6 +114,7 @@ $(BUILD)/%.o: src/%.cc $(wildcard src/%.h)
|
|||
METER_OBJS:=\
|
||||
$(BUILD)/aes.o \
|
||||
$(BUILD)/aescmac.o \
|
||||
$(BUILD)/bus.o \
|
||||
$(BUILD)/cmdline.o \
|
||||
$(BUILD)/config.o \
|
||||
$(BUILD)/dvparser.o \
|
||||
|
|
|
@ -0,0 +1,730 @@
|
|||
/*
|
||||
Copyright (C) 2017-2021 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"bus.h"
|
||||
#include"cmdline.h"
|
||||
#include"config.h"
|
||||
#include"meters.h"
|
||||
#include"printer.h"
|
||||
#include"rtlsdr.h"
|
||||
#include"serial.h"
|
||||
#include"shell.h"
|
||||
#include"threads.h"
|
||||
#include"util.h"
|
||||
#include"version.h"
|
||||
#include"wmbus.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <set>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
shared_ptr<BusManager> createBusManager(shared_ptr<SerialCommunicationManager> serial_manager,
|
||||
shared_ptr<MeterManager> meter_manager)
|
||||
{
|
||||
return shared_ptr<BusManager>(new BusManager(serial_manager, meter_manager));
|
||||
}
|
||||
|
||||
BusManager::BusManager(shared_ptr<SerialCommunicationManager> serial_manager,
|
||||
shared_ptr<MeterManager> meter_manager)
|
||||
: serial_manager_(serial_manager),
|
||||
meter_manager_(meter_manager),
|
||||
bus_devices_mutex_("bus_devices_mutex"),
|
||||
printed_warning_(true)
|
||||
{
|
||||
}
|
||||
|
||||
void BusManager::removeAllBusDevices()
|
||||
{
|
||||
bus_devices_.clear();
|
||||
}
|
||||
|
||||
void BusManager::openBusDeviceAndPotentiallySetLinkmodes(Configuration *config, string how, Detected *detected)
|
||||
{
|
||||
if (detected->found_type == WMBusDeviceType::DEVICE_UNKNOWN)
|
||||
{
|
||||
debug("(verbose) ignoring device %s\n", detected->specified_device.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
LOCK_BUS_DEVICES(open_bus_device);
|
||||
|
||||
debug("(main) opening %s\n", detected->specified_device.str().c_str());
|
||||
|
||||
LinkModeSet lms = detected->specified_device.linkmodes;
|
||||
if (lms.empty())
|
||||
{
|
||||
if (config->use_auto_device_detect)
|
||||
{
|
||||
lms = config->auto_device_linkmodes;
|
||||
}
|
||||
if (lms.empty())
|
||||
{
|
||||
lms = config->default_device_linkmodes;
|
||||
}
|
||||
}
|
||||
string using_link_modes = lms.hr();
|
||||
|
||||
string id = detected->found_device_id.c_str();
|
||||
if (id != "") id = "["+id+"]";
|
||||
string extras = detected->specified_device.extras.c_str();
|
||||
if (extras != "") extras = "("+extras+")";
|
||||
string fq = detected->specified_device.fq;
|
||||
if (fq != "") fq = " using fq "+fq;
|
||||
string file = detected->found_file.c_str();
|
||||
if (file != "") file = " on "+file;
|
||||
string cmd = detected->specified_device.command.c_str();
|
||||
if (cmd != "")
|
||||
{
|
||||
cmd = " using CMD("+cmd+")";
|
||||
}
|
||||
|
||||
string listening = "";
|
||||
if (detected->found_type != WMBusDeviceType::DEVICE_MBUS)
|
||||
{
|
||||
listening = tostrprintf(" listening on %s%s%s",
|
||||
using_link_modes.c_str(),
|
||||
fq.c_str(),
|
||||
cmd.c_str());
|
||||
}
|
||||
string started = tostrprintf("Started %s %s%s%s%s%s\n",
|
||||
how.c_str(),
|
||||
toLowerCaseString(detected->found_type),
|
||||
id.c_str(),
|
||||
extras.c_str(),
|
||||
file.c_str(),
|
||||
listening.c_str());
|
||||
|
||||
// A newly plugged in device has been manually configured or automatically detected! Start using it!
|
||||
if (config->use_auto_device_detect || detected->found_type != DEVICE_SIMULATION)
|
||||
{
|
||||
notice("%s", started.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hide the started when running simulations.
|
||||
verbose("%s", started.c_str());
|
||||
}
|
||||
|
||||
shared_ptr<WMBus> wmbus = createWmbusObject(detected, config);
|
||||
if (wmbus == NULL) return;
|
||||
bus_devices_.push_back(wmbus);
|
||||
|
||||
// By default, reset your dongle once every 23 hours,
|
||||
// so that the reset is not at the exact same time every day.
|
||||
int regular_reset = 23*3600;
|
||||
if (config->resetafter != 0) regular_reset = config->resetafter;
|
||||
wmbus->setResetInterval(regular_reset);
|
||||
verbose("(main) regular reset of %s %s%s will happen every %d seconds\n",
|
||||
toString(detected->found_type), file.c_str(), cmd.c_str(), regular_reset);
|
||||
|
||||
if (wmbus->canSetLinkModes(lms))
|
||||
{
|
||||
wmbus->setLinkModes(lms);
|
||||
}
|
||||
else
|
||||
{
|
||||
warning("Warning! Desired link modes %s cannot be set for device %s\n",
|
||||
lms.hr().c_str(), wmbus->hr().c_str());
|
||||
}
|
||||
bool simulated = false;
|
||||
if (detected->found_type == DEVICE_SIMULATION)
|
||||
{
|
||||
simulated = true;
|
||||
debug("(main) added %s to files\n", detected->found_file.c_str());
|
||||
simulation_files_.insert(detected->specified_device.file);
|
||||
}
|
||||
wmbus->onTelegram([&, simulated](AboutTelegram &about,vector<uchar> data){return meter_manager_->handleTelegram(about, data, simulated);});
|
||||
wmbus->setTimeout(config->alarm_timeout, config->alarm_expected_activity);
|
||||
}
|
||||
|
||||
shared_ptr<WMBus> BusManager::createWmbusObject(Detected *detected, Configuration *config)
|
||||
{
|
||||
shared_ptr<WMBus> wmbus;
|
||||
|
||||
shared_ptr<SerialDevice> serial_override;
|
||||
|
||||
if (detected->found_tty_override)
|
||||
{
|
||||
serial_override = serial_manager_->createSerialDeviceFile(detected->specified_device.file,
|
||||
string("override ")+detected->specified_device.file.c_str());
|
||||
verbose("(serial) override with devicefile: %s\n", detected->specified_device.file.c_str());
|
||||
}
|
||||
|
||||
switch (detected->found_type)
|
||||
{
|
||||
case DEVICE_AUTO:
|
||||
assert(0);
|
||||
error("Internal error DEVICE_AUTO should not be used here!\n");
|
||||
break;
|
||||
case DEVICE_MBUS:
|
||||
verbose("(mbus) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openMBUS(*detected, serial_manager_, serial_override);
|
||||
break;
|
||||
case DEVICE_IM871A:
|
||||
verbose("(im871a) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openIM871A(*detected, serial_manager_, serial_override);
|
||||
break;
|
||||
case DEVICE_AMB8465:
|
||||
verbose("(amb8465) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openAMB8465(*detected, serial_manager_, serial_override);
|
||||
break;
|
||||
case DEVICE_SIMULATION:
|
||||
verbose("(simulation) in %s\n", detected->found_file.c_str());
|
||||
wmbus = openSimulator(detected->found_file, serial_manager_, serial_override);
|
||||
break;
|
||||
case DEVICE_RAWTTY:
|
||||
verbose("(rawtty) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openRawTTY(detected->found_file, detected->found_bps, serial_manager_, serial_override);
|
||||
break;
|
||||
case DEVICE_RTLWMBUS:
|
||||
wmbus = openRTLWMBUS(*detected, config->bin_dir, config->daemon, serial_manager_, serial_override);
|
||||
break;
|
||||
case DEVICE_RTL433:
|
||||
wmbus = openRTL433(*detected, config->bin_dir, config->daemon, serial_manager_, serial_override);
|
||||
break;
|
||||
case DEVICE_CUL:
|
||||
{
|
||||
verbose("(cul) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openCUL(detected->found_file, serial_manager_, serial_override);
|
||||
break;
|
||||
}
|
||||
case DEVICE_RC1180:
|
||||
{
|
||||
verbose("(rc1180) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openRC1180(detected->found_file, serial_manager_, serial_override);
|
||||
break;
|
||||
}
|
||||
case DEVICE_UNKNOWN:
|
||||
warning("(main) internal error! cannot create an unknown device! exiting!\n");
|
||||
if (config->daemon) {
|
||||
// If starting as a daemon, wait a bit so that systemd have time to catch up.
|
||||
sleep(1);
|
||||
}
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (detected->found_device_id != "" && !detected->found_tty_override)
|
||||
{
|
||||
string did = wmbus->getDeviceId();
|
||||
if (did != detected->found_device_id && detected->found_type != DEVICE_RTLWMBUS)
|
||||
{
|
||||
warning("Not the expected dongle (dongle said %s, you said %s!\n", did.c_str(), detected->found_device_id.c_str());
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
wmbus->setDetected(*detected);
|
||||
return wmbus;
|
||||
}
|
||||
|
||||
void BusManager::checkForDeadWmbusDevices(Configuration *config)
|
||||
{
|
||||
LOCK_BUS_DEVICES(check_for_bus_devices);
|
||||
|
||||
trace("[MAIN] checking for dead wmbus devices...\n");
|
||||
|
||||
vector<WMBus*> not_working;
|
||||
for (auto &w : bus_devices_)
|
||||
{
|
||||
if (!w->isWorking())
|
||||
{
|
||||
not_working.push_back(w.get());
|
||||
|
||||
string id = w->getDeviceId();
|
||||
if (id != "") id = "["+id+"]";
|
||||
|
||||
notice("Lost %s closing %s%s\n",
|
||||
w->device().c_str(),
|
||||
toLowerCaseString(w->type()),
|
||||
id.c_str());
|
||||
|
||||
w->close();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto w : not_working)
|
||||
{
|
||||
auto i = bus_devices_.begin();
|
||||
while (i != bus_devices_.end())
|
||||
{
|
||||
if (w == (*i).get())
|
||||
{
|
||||
// The erased shared_ptr will delete the WMBus object.
|
||||
bus_devices_.erase(i);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (bus_devices_.size() == 0)
|
||||
{
|
||||
if (config->single_device_override)
|
||||
{
|
||||
if (!config->simulation_found)
|
||||
{
|
||||
// Expect stdin/file to work.
|
||||
// Simulation is special since it will self stop the serial manager.
|
||||
serial_manager_->expectDevicesToWork();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (config->nodeviceexit)
|
||||
{
|
||||
if (!printed_warning_)
|
||||
{
|
||||
notice("No wmbus device detected. Exiting!\n");
|
||||
serial_manager_->stop();
|
||||
printed_warning_ = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!printed_warning_)
|
||||
{
|
||||
info("No wmbus device detected, waiting for a device to be plugged in.\n");
|
||||
checkIfMultipleWmbusMetersRunning();
|
||||
printed_warning_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printed_warning_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void BusManager::runAnySimulations()
|
||||
{
|
||||
for (auto &w : bus_devices_)
|
||||
{
|
||||
// Real devices do nothing, but the simulator device will simulate.
|
||||
w->simulate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BusManager::regularCheckup()
|
||||
{
|
||||
LOCK_BUS_DEVICES(regular_checkup);
|
||||
|
||||
for (auto &w : bus_devices_)
|
||||
{
|
||||
if (w->isWorking())
|
||||
{
|
||||
w->checkStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BusManager::detectAndConfigureWmbusDevices(Configuration *config, DetectionType dt)
|
||||
{
|
||||
checkForDeadWmbusDevices(config);
|
||||
|
||||
bool must_auto_find_ttys = false;
|
||||
bool must_auto_find_rtlsdrs = false;
|
||||
|
||||
// The device=auto has been specified....
|
||||
if (config->use_auto_device_detect && dt == DetectionType::ALL)
|
||||
{
|
||||
must_auto_find_ttys = true;
|
||||
must_auto_find_rtlsdrs = true;
|
||||
}
|
||||
|
||||
for (SpecifiedDevice &specified_device : config->supplied_bus_devices)
|
||||
{
|
||||
specified_device.handled = false;
|
||||
if (dt != DetectionType::ALL)
|
||||
{
|
||||
if (specified_device.is_tty || (!specified_device.is_stdin && !specified_device.is_file && !specified_device.is_simulation))
|
||||
{
|
||||
// The event loop has not yet started and this is not stdin nor a file, nor a simulation file.
|
||||
// Therefore, do not try to detect it yet!
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (specified_device.file == "" && specified_device.command == "")
|
||||
{
|
||||
// File/tty/command not specified, use auto scan later to find actual device file/tty.
|
||||
must_auto_find_ttys |= usesTTY(specified_device.type);
|
||||
must_auto_find_rtlsdrs |= usesRTLSDR(specified_device.type);
|
||||
continue;
|
||||
}
|
||||
if (specified_device.command != "")
|
||||
{
|
||||
string identifier = "cmd_"+to_string(specified_device.index);
|
||||
shared_ptr<SerialDevice> sd = serial_manager_->lookup(identifier);
|
||||
if (sd != NULL)
|
||||
{
|
||||
trace("(main) command %s already configured\n", identifier.c_str());
|
||||
specified_device.handled = true;
|
||||
continue;
|
||||
}
|
||||
Detected detected = detectWMBusDeviceWithCommand(specified_device, config->default_device_linkmodes, serial_manager_);
|
||||
specified_device.handled = true;
|
||||
openBusDeviceAndPotentiallySetLinkmodes(config, "config", &detected);
|
||||
}
|
||||
if (specified_device.file != "")
|
||||
{
|
||||
shared_ptr<SerialDevice> sd = serial_manager_->lookup(specified_device.file);
|
||||
if (sd != NULL)
|
||||
{
|
||||
trace("(main) %s already configured\n", sd->device().c_str());
|
||||
specified_device.handled = true;
|
||||
continue;
|
||||
}
|
||||
if (simulation_files_.count(specified_device.file) > 0)
|
||||
{
|
||||
debug("(main) %s already configured as simulation\n", specified_device.file.c_str());
|
||||
specified_device.handled = true;
|
||||
continue;
|
||||
}
|
||||
if (do_not_open_file_again_.count(specified_device.file) > 0)
|
||||
{
|
||||
// This was stdin/file, it should only be opened once.
|
||||
trace("[MAIN] ignoring handled file %s\n", specified_device.file.c_str());
|
||||
specified_device.handled = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (not_serial_wmbus_devices_.count(specified_device.file) > 0)
|
||||
{
|
||||
// Enumerate all serial devices that might connect to a wmbus device.
|
||||
vector<string> ttys = serial_manager_->listSerialTTYs();
|
||||
// Did a non-wmbus-device get unplugged? Then remove it from the known-not-wmbus-device set.
|
||||
remove_lost_serial_devices_from_ignore_list(ttys);
|
||||
if (not_serial_wmbus_devices_.count(specified_device.file) > 0)
|
||||
{
|
||||
trace("[MAIN] ignoring failed file %s\n", specified_device.file.c_str());
|
||||
specified_device.handled = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!checkCharacterDeviceExists(specified_device.file.c_str(), false) &&
|
||||
!checkFileExists(specified_device.file.c_str()) &&
|
||||
specified_device.file != "stdin")
|
||||
{
|
||||
trace("Cannot open %s, no such device.\n", specified_device.file.c_str(),
|
||||
specified_device.str().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
Detected detected = detectWMBusDeviceWithFile(specified_device, config->default_device_linkmodes, serial_manager_);
|
||||
|
||||
if (detected.found_type == DEVICE_UNKNOWN)
|
||||
{
|
||||
if (checkCharacterDeviceExists(specified_device.file.c_str(), false))
|
||||
{
|
||||
// Yes, this device actually exists, there is a need to ignore it.
|
||||
not_serial_wmbus_devices_.insert(specified_device.file);
|
||||
}
|
||||
}
|
||||
|
||||
if (detected.specified_device.is_stdin || detected.specified_device.is_file || detected.specified_device.is_simulation)
|
||||
{
|
||||
// Only read stdin and files once!
|
||||
do_not_open_file_again_.insert(specified_device.file);
|
||||
}
|
||||
openBusDeviceAndPotentiallySetLinkmodes(config, "config", &detected);
|
||||
}
|
||||
|
||||
specified_device.handled = true;
|
||||
}
|
||||
|
||||
if (must_auto_find_ttys)
|
||||
{
|
||||
perform_auto_scan_of_serial_devices(config);
|
||||
}
|
||||
|
||||
if (must_auto_find_rtlsdrs)
|
||||
{
|
||||
perform_auto_scan_of_swradio_devices(config);
|
||||
}
|
||||
|
||||
for (shared_ptr<WMBus> &wmbus : bus_devices_)
|
||||
{
|
||||
assert(wmbus->getDetected() != NULL);
|
||||
find_specified_device_and_mark_as_handled(config, wmbus->getDetected());
|
||||
}
|
||||
|
||||
for (SpecifiedDevice &specified_device : config->supplied_bus_devices)
|
||||
{
|
||||
if (dt == DetectionType::ALL && !specified_device.handled)
|
||||
{
|
||||
time_t last_alarm = specified_device.last_alarm;
|
||||
time_t now = time(NULL);
|
||||
|
||||
// If the device is missing, warn once per minute.
|
||||
if (now - last_alarm > 60)
|
||||
{
|
||||
specified_device.last_alarm = now;
|
||||
string device = specified_device.str();
|
||||
string info = tostrprintf("the device %s is not working", device.c_str());
|
||||
logAlarm(Alarm::SpecifiedDeviceNotFound, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BusManager::remove_lost_serial_devices_from_ignore_list(vector<string> &devices)
|
||||
{
|
||||
vector<string> to_be_removed;
|
||||
|
||||
// Iterate over the devices known to NOT be wmbus devices.
|
||||
for (const string& nots : not_serial_wmbus_devices_)
|
||||
{
|
||||
auto i = std::find(devices.begin(), devices.end(), nots);
|
||||
if (i == devices.end())
|
||||
{
|
||||
// The device has been removed, therefore
|
||||
// we have to forget that the device was not a wmbus device.
|
||||
// Since next time someone plugs in a device, it might be a different
|
||||
// one getting the same /dev/ttyUSBxx
|
||||
to_be_removed.push_back(nots);
|
||||
}
|
||||
}
|
||||
|
||||
for (string& r : to_be_removed)
|
||||
{
|
||||
not_serial_wmbus_devices_.erase(r);
|
||||
}
|
||||
}
|
||||
|
||||
void BusManager::perform_auto_scan_of_serial_devices(Configuration *config)
|
||||
{
|
||||
// Enumerate all serial devices that might connect to a wmbus device.
|
||||
vector<string> ttys = serial_manager_->listSerialTTYs();
|
||||
|
||||
// Did a non-wmbus-device get unplugged? Then remove it from the known-not-wmbus-device set.
|
||||
remove_lost_serial_devices_from_ignore_list(ttys);
|
||||
|
||||
for (string& tty : ttys)
|
||||
{
|
||||
trace("[MAIN] serial device %s\n", tty.c_str());
|
||||
if (not_serial_wmbus_devices_.count(tty) > 0)
|
||||
{
|
||||
trace("[MAIN] skipping already probed not wmbus serial device %s\n", tty.c_str());
|
||||
continue;
|
||||
}
|
||||
if (config->do_not_probe_ttys.count("all") > 0 ||
|
||||
config->do_not_probe_ttys.count(tty) > 0)
|
||||
{
|
||||
trace("[MAIN] not probing forbidden tty %s\n", tty.c_str());
|
||||
continue;
|
||||
}
|
||||
shared_ptr<SerialDevice> sd = serial_manager_->lookup(tty);
|
||||
if (!sd)
|
||||
{
|
||||
// This serial device is not in use, but is there a device on it?
|
||||
debug("(main) device %s not currently used, detect contents...\n", tty.c_str());
|
||||
|
||||
// What should the desired linkmodes be? We have no specified device since this an auto detect.
|
||||
// But we might have an auto linkmodes?
|
||||
LinkModeSet desired_linkmodes = config->auto_device_linkmodes;
|
||||
if (desired_linkmodes.empty())
|
||||
{
|
||||
// Nope, lets fall back on the default_linkmodes.
|
||||
desired_linkmodes = config->default_device_linkmodes;
|
||||
}
|
||||
Detected detected = detectWMBusDeviceOnTTY(tty, desired_linkmodes, serial_manager_);
|
||||
if (detected.found_type != DEVICE_UNKNOWN)
|
||||
{
|
||||
// See if we had a specified device without a file,
|
||||
// that matches this detected device.
|
||||
bool found = find_specified_device_and_update_detected(config, &detected);
|
||||
if (config->use_auto_device_detect || found)
|
||||
{
|
||||
// Open the device, only if auto is enabled, or if the device was specified.
|
||||
openBusDeviceAndPotentiallySetLinkmodes(config, found?"config":"auto", &detected);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This serial device was something that we could not recognize.
|
||||
// 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(tty);
|
||||
verbose("(main) ignoring %s, it does not respond as any of the supported wmbus devices.\n", tty.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BusManager::perform_auto_scan_of_swradio_devices(Configuration *config)
|
||||
{
|
||||
// Enumerate all swradio devices, that can be used.
|
||||
vector<string> serialnrs = listRtlSdrDevices();
|
||||
|
||||
if (serialnrs.size() > 0)
|
||||
{
|
||||
if (!rtlsdr_found_ || !rtlwmbus_found_)
|
||||
{
|
||||
rtlsdr_found_ = check_if_rtlsdr_exists_in_path();
|
||||
rtlwmbus_found_ = check_if_rtlwmbus_exists_in_path();
|
||||
// rtl433_found_ = check_if_rtl433_exists_in_path();
|
||||
}
|
||||
if (!rtlsdr_found_)
|
||||
{
|
||||
warning("Warning! Auto scan has found an rtl_sdr dongle, but you have no rtl_sdr in the path!\n");
|
||||
}
|
||||
if (!rtlwmbus_found_)
|
||||
{
|
||||
warning("Warning! Auto scan has found an rtl_sdr dongle, but you have no rtl_wmbus in the path!\n");
|
||||
}
|
||||
}
|
||||
|
||||
// We are missing rtl_sdr and/or rtl_wmbus, stop here.
|
||||
if (!rtlsdr_found_ || !rtlwmbus_found_) return;
|
||||
|
||||
// Did an unavailable swradio-device get unplugged? Then remove it from the known-not-swradio-device set.
|
||||
remove_lost_swradio_devices_from_ignore_list(serialnrs);
|
||||
|
||||
for (string& serialnr : serialnrs)
|
||||
{
|
||||
trace("[MAIN] rtlsdr device %s\n", serialnr.c_str());
|
||||
if (not_swradio_wmbus_devices_.count(serialnr) > 0)
|
||||
{
|
||||
trace("[MAIN] skipping already probed rtlsdr %s\n", serialnr.c_str());
|
||||
continue;
|
||||
}
|
||||
shared_ptr<SerialDevice> sd = serial_manager_->lookup(serialnr);
|
||||
if (!sd)
|
||||
{
|
||||
debug("(main) rtlsdr device %s not currently used.\n", serialnr.c_str());
|
||||
Detected detected;
|
||||
detected.specified_device.type = WMBusDeviceType::DEVICE_RTLWMBUS;
|
||||
AccessCheck ac = detectRTLSDR(serialnr, &detected);
|
||||
if (ac != AccessCheck::AccessOK)
|
||||
{
|
||||
// We cannot access this swradio device.
|
||||
not_swradio_wmbus_devices_.insert(serialnr);
|
||||
verbose("(main) ignoring rtlsdr %s since it is unavailable.\n", serialnr.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the serialnr as the id.
|
||||
detected.found_device_id = serialnr;
|
||||
bool found = find_specified_device_and_update_detected(config, &detected);
|
||||
if (config->use_auto_device_detect || found)
|
||||
{
|
||||
// Open the device, only if auto is enabled, or if the device was specified.
|
||||
openBusDeviceAndPotentiallySetLinkmodes(config, found?"config":"auto", &detected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BusManager::find_specified_device_and_mark_as_handled(Configuration *c, Detected *d)
|
||||
{
|
||||
SpecifiedDevice *sd = find_specified_device_from_detected(c, d);
|
||||
|
||||
if (sd)
|
||||
{
|
||||
sd->handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool BusManager::find_specified_device_and_update_detected(Configuration *c, Detected *d)
|
||||
{
|
||||
SpecifiedDevice *sd = find_specified_device_from_detected(c, d);
|
||||
|
||||
if (sd)
|
||||
{
|
||||
if (sd->type == DEVICE_RTL433 && d->found_type == DEVICE_RTLWMBUS)
|
||||
{
|
||||
d->found_type = DEVICE_RTL433;
|
||||
}
|
||||
|
||||
d->specified_device = *sd;
|
||||
debug("(main) found specified device (%s) that matches detected device (%s)\n",
|
||||
sd->str().c_str(),
|
||||
d->str().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void BusManager::remove_lost_swradio_devices_from_ignore_list(vector<string> &devices)
|
||||
{
|
||||
vector<string> to_be_removed;
|
||||
|
||||
// Iterate over the devices known to NOT be wmbus devices.
|
||||
for (const string& nots : not_swradio_wmbus_devices_)
|
||||
{
|
||||
auto i = std::find(devices.begin(), devices.end(), nots);
|
||||
if (i == devices.end())
|
||||
{
|
||||
// The device has been removed, therefore
|
||||
// we have to forget that the device was not a wmbus device.
|
||||
// Since next time someone plugs in a device, it might be a different
|
||||
// one getting the same /dev/ttyUSBxx
|
||||
to_be_removed.push_back(nots);
|
||||
}
|
||||
}
|
||||
|
||||
for (string& r : to_be_removed)
|
||||
{
|
||||
not_swradio_wmbus_devices_.erase(r);
|
||||
}
|
||||
}
|
||||
|
||||
SpecifiedDevice *BusManager::find_specified_device_from_detected(Configuration *c, Detected *d)
|
||||
{
|
||||
// Iterate over the supplied devices and look for an exact type+id match.
|
||||
// This will find specified devices like: im871a[12345678]
|
||||
for (SpecifiedDevice & sd : c->supplied_bus_devices)
|
||||
{
|
||||
if (sd.file == "" && sd.id != "" && sd.id == d->found_device_id &&
|
||||
(sd.type == d->found_type ||
|
||||
(sd.type == DEVICE_RTL433 && d->found_type == DEVICE_RTLWMBUS)))
|
||||
{
|
||||
return &sd;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over the supplied devices and look for a type match.
|
||||
// This will find specified devices like: im871a, rtlwmbus
|
||||
for (SpecifiedDevice & sd : c->supplied_bus_devices)
|
||||
{
|
||||
if (sd.file == "" && sd.id == "" &&
|
||||
(sd.type == d->found_type ||
|
||||
(sd.type == DEVICE_RTL433 && d->found_type == DEVICE_RTLWMBUS)))
|
||||
{
|
||||
return &sd;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Copyright (C) 2021 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 BUS_H_
|
||||
#define BUS_H_
|
||||
|
||||
#include"config.h"
|
||||
#include"threads.h"
|
||||
#include"util.h"
|
||||
#include"units.h"
|
||||
#include"wmbus.h"
|
||||
|
||||
enum class DetectionType { STDIN_FILE_SIMULATION, ALL };
|
||||
|
||||
struct BusManager
|
||||
{
|
||||
BusManager(shared_ptr<SerialCommunicationManager> serial_manager,
|
||||
shared_ptr<MeterManager> meter_manager);
|
||||
|
||||
void detectAndConfigureWmbusDevices(Configuration *config, DetectionType dt);
|
||||
void removeAllBusDevices();
|
||||
void checkForDeadWmbusDevices(Configuration *config);
|
||||
void openBusDeviceAndPotentiallySetLinkmodes(Configuration *config, string how, Detected *detected);
|
||||
shared_ptr<WMBus> createWmbusObject(Detected *detected, Configuration *config);
|
||||
|
||||
void runAnySimulations();
|
||||
void regularCheckup();
|
||||
|
||||
int numBusDevices() { return bus_devices_.size(); }
|
||||
|
||||
private:
|
||||
|
||||
void remove_lost_serial_devices_from_ignore_list(vector<string> &devices);
|
||||
void perform_auto_scan_of_serial_devices(Configuration *config);
|
||||
void perform_auto_scan_of_swradio_devices(Configuration *config);
|
||||
void find_specified_device_and_mark_as_handled(Configuration *c, Detected *d);
|
||||
bool find_specified_device_and_update_detected(Configuration *c, Detected *d);
|
||||
void remove_lost_swradio_devices_from_ignore_list(vector<string> &devices);
|
||||
SpecifiedDevice *find_specified_device_from_detected(Configuration *c, Detected *d);
|
||||
|
||||
|
||||
shared_ptr<SerialCommunicationManager> serial_manager_;
|
||||
shared_ptr<MeterManager> meter_manager_;
|
||||
|
||||
// Current active set of wmbus devices that can receive telegrams.
|
||||
// This can change during runtime, plugging/unplugging wmbus dongles.
|
||||
vector<shared_ptr<WMBus>> bus_devices_;
|
||||
RecursiveMutex bus_devices_mutex_;
|
||||
#define LOCK_BUS_DEVICES(where) WITH(bus_devices_mutex_, bus_devices_mutex, where)
|
||||
|
||||
// Then check if the rtl_sdr and/or rtl_wmbus and/or rtl_433 is available.
|
||||
bool rtlsdr_found_ = false;
|
||||
bool rtlwmbus_found_ = false;
|
||||
bool rtl433_found_ = false;
|
||||
|
||||
// Remember devices that were not detected as wmbus devices.
|
||||
// To avoid probing them again and again.
|
||||
set<string> not_serial_wmbus_devices_;
|
||||
|
||||
// The software radio devices are always swradio devices
|
||||
// but they might not be available for wmbusmeters.
|
||||
set<string> not_swradio_wmbus_devices_;
|
||||
|
||||
// When manually supplying stdin or a file, then, after
|
||||
// it has been read, do not open it again!
|
||||
set<string> do_not_open_file_again_;
|
||||
|
||||
// Store simulation files here.
|
||||
set<string> simulation_files_;
|
||||
|
||||
// Set as true when the warning for no detected wmbus devices has been printed.
|
||||
bool printed_warning_ = false;
|
||||
};
|
||||
|
||||
shared_ptr<BusManager> createBusManager(shared_ptr<SerialCommunicationManager> serial_manager,
|
||||
shared_ptr<MeterManager> meter_manager);
|
||||
|
||||
#endif
|
777
src/main.cc
777
src/main.cc
|
@ -15,6 +15,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include"bus.h"
|
||||
#include"cmdline.h"
|
||||
#include"config.h"
|
||||
#include"meters.h"
|
||||
|
@ -44,26 +45,14 @@
|
|||
using namespace std;
|
||||
|
||||
int main(int argc, char **argv);
|
||||
void check_if_multiple_wmbus_meters_running();
|
||||
void check_for_dead_wmbus_devices(Configuration *config);
|
||||
shared_ptr<Printer> create_printer(Configuration *config);
|
||||
shared_ptr<WMBus> create_wmbus_object(Detected *detected, Configuration *config, shared_ptr<SerialCommunicationManager> manager);
|
||||
enum class DetectionType { STDIN_FILE_SIMULATION, ALL };
|
||||
void detect_and_configure_wmbus_devices(Configuration *config, DetectionType dt);
|
||||
SpecifiedDevice *find_specified_device_from_detected(Configuration *c, Detected *d);
|
||||
bool find_specified_device_and_update_detected(Configuration *c, Detected *d);
|
||||
void find_specified_device_and_mark_as_handled(Configuration *c, Detected *d);
|
||||
void list_fields(Configuration *config, string meter_type);
|
||||
void list_shell_envs(Configuration *config, string meter_type);
|
||||
void list_meters(Configuration *config);
|
||||
void log_start_information(Configuration *config);
|
||||
void oneshot_check(Configuration *config, Telegram *t, Meter *meter);
|
||||
void open_bus_device_and_potentially_set_linkmodes(Configuration *config, string how, Detected *detected);
|
||||
void perform_auto_scan_of_serial_devices(Configuration *config);
|
||||
void perform_auto_scan_of_swradio_devices(Configuration *config);
|
||||
void regular_checkup(Configuration *config);
|
||||
void remove_lost_serial_devices_from_ignore_list(vector<string> &devices);
|
||||
void remove_lost_swradio_devices_from_ignore_list(vector<string> &devices);
|
||||
bool start(Configuration *config);
|
||||
void start_using_config_files(string root, bool is_daemon, string device_override, string listento_override);
|
||||
void start_daemon(string pid_file, string device_override, string listento_override); // Will use config files.
|
||||
|
@ -78,49 +67,15 @@ void write_pid(string pid_file, int pid);
|
|||
// detecting new devices.
|
||||
shared_ptr<SerialCommunicationManager> serial_manager_;
|
||||
|
||||
// Manage registered meters to decode and relay.
|
||||
// Manage registered meters.
|
||||
shared_ptr<MeterManager> meter_manager_;
|
||||
|
||||
struct BusManager
|
||||
{
|
||||
BusManager() : bus_devices_mutex_("bus_devices_mutex") {}
|
||||
// Current active set of wmbus devices that can receive telegrams.
|
||||
// This can change during runtime, plugging/unplugging wmbus dongles.
|
||||
vector<shared_ptr<WMBus>> bus_devices_;
|
||||
RecursiveMutex bus_devices_mutex_;
|
||||
#define LOCK_BUS_DEVICES(where) WITH(bus_manager_->bus_devices_mutex_, bus_devices_mutex, where)
|
||||
|
||||
// Remember devices that were not detected as wmbus devices.
|
||||
// To avoid probing them again and again.
|
||||
set<string> not_serial_wmbus_devices_;
|
||||
|
||||
// The software radio devices are always swradio devices
|
||||
// but they might not be available for wmbusmeters.
|
||||
set<string> not_swradio_wmbus_devices_;
|
||||
|
||||
// When manually supplying stdin or a file, then, after
|
||||
// it has been read, do not open it again!
|
||||
set<string> do_not_open_file_again_;
|
||||
|
||||
// Store simulation files here.
|
||||
set<string> simulation_files_;
|
||||
};
|
||||
|
||||
// Manage bus devices wmbus, mbus, HAN etc.
|
||||
// Manage bus devices that receive telegrams or send commands to meters.
|
||||
shared_ptr<BusManager> bus_manager_;
|
||||
|
||||
// Rendering the telegrams to json,fields or shell calls is
|
||||
// done by the printer.
|
||||
// The printer renders the telegrams to: json, fields or shell calls.
|
||||
shared_ptr<Printer> printer_;
|
||||
|
||||
// Set as true when the warning for no detected wmbus devices has been printed.
|
||||
bool printed_warning_ = false;
|
||||
|
||||
// Then check if the rtl_sdr and/or rtl_wmbus and/or rtl_433 is available.
|
||||
bool rtlsdr_found_ = false;
|
||||
bool rtlwmbus_found_ = false;
|
||||
bool rtl433_found_ = false;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
auto config = parseCommandLine(argc, argv);
|
||||
|
@ -207,191 +162,6 @@ provided you with this binary. Read the full license for all details.
|
|||
error("(main) internal error\n");
|
||||
}
|
||||
|
||||
void check_if_multiple_wmbus_meters_running()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void check_for_dead_wmbus_devices(Configuration *config)
|
||||
{
|
||||
LOCK_BUS_DEVICES(check_for_bus_devices);
|
||||
|
||||
trace("[MAIN] checking for dead wmbus devices...\n");
|
||||
|
||||
vector<WMBus*> not_working;
|
||||
for (auto &w : bus_manager_->bus_devices_)
|
||||
{
|
||||
if (!w->isWorking())
|
||||
{
|
||||
not_working.push_back(w.get());
|
||||
|
||||
string id = w->getDeviceId();
|
||||
if (id != "") id = "["+id+"]";
|
||||
|
||||
notice("Lost %s closing %s%s\n",
|
||||
w->device().c_str(),
|
||||
toLowerCaseString(w->type()),
|
||||
id.c_str());
|
||||
|
||||
w->close();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto w : not_working)
|
||||
{
|
||||
auto i = bus_manager_->bus_devices_.begin();
|
||||
while (i != bus_manager_->bus_devices_.end())
|
||||
{
|
||||
if (w == (*i).get())
|
||||
{
|
||||
// The erased shared_ptr will delete the WMBus object.
|
||||
bus_manager_->bus_devices_.erase(i);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (bus_manager_->bus_devices_.size() == 0)
|
||||
{
|
||||
if (config->single_device_override)
|
||||
{
|
||||
if (!config->simulation_found)
|
||||
{
|
||||
// Expect stdin/file to work.
|
||||
// Simulation is special since it will self stop the serial manager.
|
||||
serial_manager_->expectDevicesToWork();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (config->nodeviceexit)
|
||||
{
|
||||
if (!printed_warning_)
|
||||
{
|
||||
notice("No wmbus device detected. Exiting!\n");
|
||||
serial_manager_->stop();
|
||||
printed_warning_ = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!printed_warning_)
|
||||
{
|
||||
info("No wmbus device detected, waiting for a device to be plugged in.\n");
|
||||
check_if_multiple_wmbus_meters_running();
|
||||
printed_warning_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printed_warning_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<WMBus> create_wmbus_object(Detected *detected, Configuration *config,
|
||||
shared_ptr<SerialCommunicationManager> manager)
|
||||
{
|
||||
shared_ptr<WMBus> wmbus;
|
||||
|
||||
shared_ptr<SerialDevice> serial_override;
|
||||
|
||||
if (detected->found_tty_override)
|
||||
{
|
||||
serial_override = manager->createSerialDeviceFile(detected->specified_device.file,
|
||||
string("override ")+detected->specified_device.file.c_str());
|
||||
verbose("(serial) override with devicefile: %s\n", detected->specified_device.file.c_str());
|
||||
}
|
||||
|
||||
switch (detected->found_type)
|
||||
{
|
||||
case DEVICE_AUTO:
|
||||
assert(0);
|
||||
error("Internal error DEVICE_AUTO should not be used here!\n");
|
||||
break;
|
||||
case DEVICE_MBUS:
|
||||
verbose("(mbus) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openMBUS(*detected, manager, serial_override);
|
||||
break;
|
||||
case DEVICE_IM871A:
|
||||
verbose("(im871a) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openIM871A(*detected, manager, serial_override);
|
||||
break;
|
||||
case DEVICE_AMB8465:
|
||||
verbose("(amb8465) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openAMB8465(*detected, manager, serial_override);
|
||||
break;
|
||||
case DEVICE_SIMULATION:
|
||||
verbose("(simulation) in %s\n", detected->found_file.c_str());
|
||||
wmbus = openSimulator(detected->found_file, manager, serial_override);
|
||||
break;
|
||||
case DEVICE_RAWTTY:
|
||||
verbose("(rawtty) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openRawTTY(detected->found_file, detected->found_bps, manager, serial_override);
|
||||
break;
|
||||
case DEVICE_RTLWMBUS:
|
||||
wmbus = openRTLWMBUS(*detected, config->bin_dir, config->daemon, manager, serial_override);
|
||||
break;
|
||||
case DEVICE_RTL433:
|
||||
wmbus = openRTL433(*detected, config->bin_dir, config->daemon, manager, serial_override);
|
||||
break;
|
||||
case DEVICE_CUL:
|
||||
{
|
||||
verbose("(cul) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openCUL(detected->found_file, manager, serial_override);
|
||||
break;
|
||||
}
|
||||
case DEVICE_RC1180:
|
||||
{
|
||||
verbose("(rc1180) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openRC1180(detected->found_file, manager, serial_override);
|
||||
break;
|
||||
}
|
||||
case DEVICE_UNKNOWN:
|
||||
warning("(main) internal error! cannot create an unknown device! exiting!\n");
|
||||
if (config->daemon) {
|
||||
// If starting as a daemon, wait a bit so that systemd have time to catch up.
|
||||
sleep(1);
|
||||
}
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (detected->found_device_id != "" && !detected->found_tty_override)
|
||||
{
|
||||
string did = wmbus->getDeviceId();
|
||||
if (did != detected->found_device_id && detected->found_type != DEVICE_RTLWMBUS)
|
||||
{
|
||||
warning("Not the expected dongle (dongle said %s, you said %s!\n", did.c_str(), detected->found_device_id.c_str());
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
wmbus->setDetected(*detected);
|
||||
return wmbus;
|
||||
}
|
||||
|
||||
shared_ptr<Printer> create_printer(Configuration *config)
|
||||
{
|
||||
return shared_ptr<Printer>(new Printer(config->json, config->fields,
|
||||
|
@ -403,216 +173,6 @@ shared_ptr<Printer> create_printer(Configuration *config)
|
|||
config->meterfiles_timestamp));
|
||||
}
|
||||
|
||||
void detect_and_configure_wmbus_devices(Configuration *config, DetectionType dt)
|
||||
{
|
||||
check_for_dead_wmbus_devices(config);
|
||||
|
||||
bool must_auto_find_ttys = false;
|
||||
bool must_auto_find_rtlsdrs = false;
|
||||
|
||||
// The device=auto has been specified....
|
||||
if (config->use_auto_device_detect && dt == DetectionType::ALL)
|
||||
{
|
||||
must_auto_find_ttys = true;
|
||||
must_auto_find_rtlsdrs = true;
|
||||
}
|
||||
|
||||
for (SpecifiedDevice &specified_device : config->supplied_bus_devices)
|
||||
{
|
||||
specified_device.handled = false;
|
||||
if (dt != DetectionType::ALL)
|
||||
{
|
||||
if (specified_device.is_tty || (!specified_device.is_stdin && !specified_device.is_file && !specified_device.is_simulation))
|
||||
{
|
||||
// The event loop has not yet started and this is not stdin nor a file, nor a simulation file.
|
||||
// Therefore, do not try to detect it yet!
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (specified_device.file == "" && specified_device.command == "")
|
||||
{
|
||||
// File/tty/command not specified, use auto scan later to find actual device file/tty.
|
||||
must_auto_find_ttys |= usesTTY(specified_device.type);
|
||||
must_auto_find_rtlsdrs |= usesRTLSDR(specified_device.type);
|
||||
continue;
|
||||
}
|
||||
if (specified_device.command != "")
|
||||
{
|
||||
string identifier = "cmd_"+to_string(specified_device.index);
|
||||
shared_ptr<SerialDevice> sd = serial_manager_->lookup(identifier);
|
||||
if (sd != NULL)
|
||||
{
|
||||
trace("(main) command %s already configured\n", identifier.c_str());
|
||||
specified_device.handled = true;
|
||||
continue;
|
||||
}
|
||||
Detected detected = detectWMBusDeviceWithCommand(specified_device, config->default_device_linkmodes, serial_manager_);
|
||||
specified_device.handled = true;
|
||||
open_bus_device_and_potentially_set_linkmodes(config, "config", &detected);
|
||||
}
|
||||
if (specified_device.file != "")
|
||||
{
|
||||
shared_ptr<SerialDevice> sd = serial_manager_->lookup(specified_device.file);
|
||||
if (sd != NULL)
|
||||
{
|
||||
trace("(main) %s already configured\n", sd->device().c_str());
|
||||
specified_device.handled = true;
|
||||
continue;
|
||||
}
|
||||
if (bus_manager_->simulation_files_.count(specified_device.file) > 0)
|
||||
{
|
||||
debug("(main) %s already configured as simulation\n", specified_device.file.c_str());
|
||||
specified_device.handled = true;
|
||||
continue;
|
||||
}
|
||||
if (bus_manager_->do_not_open_file_again_.count(specified_device.file) > 0)
|
||||
{
|
||||
// This was stdin/file, it should only be opened once.
|
||||
trace("[MAIN] ignoring handled file %s\n", specified_device.file.c_str());
|
||||
specified_device.handled = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bus_manager_->not_serial_wmbus_devices_.count(specified_device.file) > 0)
|
||||
{
|
||||
// Enumerate all serial devices that might connect to a wmbus device.
|
||||
vector<string> ttys = serial_manager_->listSerialTTYs();
|
||||
// Did a non-wmbus-device get unplugged? Then remove it from the known-not-wmbus-device set.
|
||||
remove_lost_serial_devices_from_ignore_list(ttys);
|
||||
if (bus_manager_->not_serial_wmbus_devices_.count(specified_device.file) > 0)
|
||||
{
|
||||
trace("[MAIN] ignoring failed file %s\n", specified_device.file.c_str());
|
||||
specified_device.handled = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!checkCharacterDeviceExists(specified_device.file.c_str(), false) &&
|
||||
!checkFileExists(specified_device.file.c_str()) &&
|
||||
specified_device.file != "stdin")
|
||||
{
|
||||
trace("Cannot open %s, no such device.\n", specified_device.file.c_str(),
|
||||
specified_device.str().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
Detected detected = detectWMBusDeviceWithFile(specified_device, config->default_device_linkmodes, serial_manager_);
|
||||
|
||||
if (detected.found_type == DEVICE_UNKNOWN)
|
||||
{
|
||||
if (checkCharacterDeviceExists(specified_device.file.c_str(), false))
|
||||
{
|
||||
// Yes, this device actually exists, there is a need to ignore it.
|
||||
bus_manager_->not_serial_wmbus_devices_.insert(specified_device.file);
|
||||
}
|
||||
}
|
||||
|
||||
if (detected.specified_device.is_stdin || detected.specified_device.is_file || detected.specified_device.is_simulation)
|
||||
{
|
||||
// Only read stdin and files once!
|
||||
bus_manager_->do_not_open_file_again_.insert(specified_device.file);
|
||||
}
|
||||
open_bus_device_and_potentially_set_linkmodes(config, "config", &detected);
|
||||
}
|
||||
|
||||
specified_device.handled = true;
|
||||
}
|
||||
|
||||
if (must_auto_find_ttys)
|
||||
{
|
||||
perform_auto_scan_of_serial_devices(config);
|
||||
}
|
||||
|
||||
if (must_auto_find_rtlsdrs)
|
||||
{
|
||||
perform_auto_scan_of_swradio_devices(config);
|
||||
}
|
||||
|
||||
for (shared_ptr<WMBus> &wmbus : bus_manager_->bus_devices_)
|
||||
{
|
||||
assert(wmbus->getDetected() != NULL);
|
||||
find_specified_device_and_mark_as_handled(config, wmbus->getDetected());
|
||||
}
|
||||
|
||||
for (SpecifiedDevice &specified_device : config->supplied_bus_devices)
|
||||
{
|
||||
if (dt == DetectionType::ALL && !specified_device.handled)
|
||||
{
|
||||
time_t last_alarm = specified_device.last_alarm;
|
||||
time_t now = time(NULL);
|
||||
|
||||
// If the device is missing, warn once per minute.
|
||||
if (now - last_alarm > 60)
|
||||
{
|
||||
specified_device.last_alarm = now;
|
||||
string device = specified_device.str();
|
||||
string info = tostrprintf("the device %s is not working", device.c_str());
|
||||
logAlarm(Alarm::SpecifiedDeviceNotFound, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SpecifiedDevice *find_specified_device_from_detected(Configuration *c, Detected *d)
|
||||
{
|
||||
// Iterate over the supplied devices and look for an exact type+id match.
|
||||
// This will find specified devices like: im871a[12345678]
|
||||
for (SpecifiedDevice & sd : c->supplied_bus_devices)
|
||||
{
|
||||
if (sd.file == "" && sd.id != "" && sd.id == d->found_device_id &&
|
||||
(sd.type == d->found_type ||
|
||||
(sd.type == DEVICE_RTL433 && d->found_type == DEVICE_RTLWMBUS)))
|
||||
{
|
||||
return &sd;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over the supplied devices and look for a type match.
|
||||
// This will find specified devices like: im871a, rtlwmbus
|
||||
for (SpecifiedDevice & sd : c->supplied_bus_devices)
|
||||
{
|
||||
if (sd.file == "" && sd.id == "" &&
|
||||
(sd.type == d->found_type ||
|
||||
(sd.type == DEVICE_RTL433 && d->found_type == DEVICE_RTLWMBUS)))
|
||||
{
|
||||
return &sd;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool find_specified_device_and_update_detected(Configuration *c, Detected *d)
|
||||
{
|
||||
SpecifiedDevice *sd = find_specified_device_from_detected(c, d);
|
||||
|
||||
if (sd)
|
||||
{
|
||||
if (sd->type == DEVICE_RTL433 && d->found_type == DEVICE_RTLWMBUS)
|
||||
{
|
||||
d->found_type = DEVICE_RTL433;
|
||||
}
|
||||
|
||||
d->specified_device = *sd;
|
||||
debug("(main) found specified device (%s) that matches detected device (%s)\n",
|
||||
sd->str().c_str(),
|
||||
d->str().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void find_specified_device_and_mark_as_handled(Configuration *c, Detected *d)
|
||||
{
|
||||
SpecifiedDevice *sd = find_specified_device_from_detected(c, d);
|
||||
|
||||
if (sd)
|
||||
{
|
||||
sd->handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void list_shell_envs(Configuration *config, string meter_driver)
|
||||
{
|
||||
string ignore1, ignore2, ignore3;
|
||||
|
@ -714,230 +274,6 @@ void oneshot_check(Configuration *config, Telegram *t, Meter *meter)
|
|||
}
|
||||
}
|
||||
|
||||
void open_bus_device_and_potentially_set_linkmodes(Configuration *config, string how, Detected *detected)
|
||||
{
|
||||
if (detected->found_type == WMBusDeviceType::DEVICE_UNKNOWN)
|
||||
{
|
||||
debug("(verbose) ignoring device %s\n", detected->specified_device.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
LOCK_BUS_DEVICES(open_bus_device);
|
||||
|
||||
debug("(main) opening %s\n", detected->specified_device.str().c_str());
|
||||
|
||||
LinkModeSet lms = detected->specified_device.linkmodes;
|
||||
if (lms.empty())
|
||||
{
|
||||
if (config->use_auto_device_detect)
|
||||
{
|
||||
lms = config->auto_device_linkmodes;
|
||||
}
|
||||
if (lms.empty())
|
||||
{
|
||||
lms = config->default_device_linkmodes;
|
||||
}
|
||||
}
|
||||
string using_link_modes = lms.hr();
|
||||
|
||||
string id = detected->found_device_id.c_str();
|
||||
if (id != "") id = "["+id+"]";
|
||||
string extras = detected->specified_device.extras.c_str();
|
||||
if (extras != "") extras = "("+extras+")";
|
||||
string fq = detected->specified_device.fq;
|
||||
if (fq != "") fq = " using fq "+fq;
|
||||
string file = detected->found_file.c_str();
|
||||
if (file != "") file = " on "+file;
|
||||
string cmd = detected->specified_device.command.c_str();
|
||||
if (cmd != "")
|
||||
{
|
||||
cmd = " using CMD("+cmd+")";
|
||||
}
|
||||
|
||||
string listening = "";
|
||||
if (detected->found_type != WMBusDeviceType::DEVICE_MBUS)
|
||||
{
|
||||
listening = tostrprintf(" listening on %s%s%s",
|
||||
using_link_modes.c_str(),
|
||||
fq.c_str(),
|
||||
cmd.c_str());
|
||||
}
|
||||
string started = tostrprintf("Started %s %s%s%s%s%s\n",
|
||||
how.c_str(),
|
||||
toLowerCaseString(detected->found_type),
|
||||
id.c_str(),
|
||||
extras.c_str(),
|
||||
file.c_str(),
|
||||
listening.c_str());
|
||||
|
||||
// A newly plugged in device has been manually configured or automatically detected! Start using it!
|
||||
if (config->use_auto_device_detect || detected->found_type != DEVICE_SIMULATION)
|
||||
{
|
||||
notice("%s", started.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hide the started when running simulations.
|
||||
verbose("%s", started.c_str());
|
||||
}
|
||||
|
||||
shared_ptr<WMBus> wmbus = create_wmbus_object(detected, config, serial_manager_);
|
||||
if (wmbus == NULL) return;
|
||||
bus_manager_->bus_devices_.push_back(wmbus);
|
||||
|
||||
// By default, reset your dongle once every 23 hours,
|
||||
// so that the reset is not at the exact same time every day.
|
||||
int regular_reset = 23*3600;
|
||||
if (config->resetafter != 0) regular_reset = config->resetafter;
|
||||
wmbus->setResetInterval(regular_reset);
|
||||
verbose("(main) regular reset of %s %s%s will happen every %d seconds\n",
|
||||
toString(detected->found_type), file.c_str(), cmd.c_str(), regular_reset);
|
||||
|
||||
if (wmbus->canSetLinkModes(lms))
|
||||
{
|
||||
wmbus->setLinkModes(lms);
|
||||
}
|
||||
else
|
||||
{
|
||||
warning("Warning! Desired link modes %s cannot be set for device %s\n",
|
||||
lms.hr().c_str(), wmbus->hr().c_str());
|
||||
}
|
||||
bool simulated = false;
|
||||
if (detected->found_type == DEVICE_SIMULATION)
|
||||
{
|
||||
simulated = true;
|
||||
debug("(main) added %s to files\n", detected->found_file.c_str());
|
||||
bus_manager_->simulation_files_.insert(detected->specified_device.file);
|
||||
}
|
||||
wmbus->onTelegram([&, simulated](AboutTelegram &about,vector<uchar> data){return meter_manager_->handleTelegram(about, data, simulated);});
|
||||
wmbus->setTimeout(config->alarm_timeout, config->alarm_expected_activity);
|
||||
}
|
||||
|
||||
void perform_auto_scan_of_serial_devices(Configuration *config)
|
||||
{
|
||||
// Enumerate all serial devices that might connect to a wmbus device.
|
||||
vector<string> ttys = serial_manager_->listSerialTTYs();
|
||||
|
||||
// Did a non-wmbus-device get unplugged? Then remove it from the known-not-wmbus-device set.
|
||||
remove_lost_serial_devices_from_ignore_list(ttys);
|
||||
|
||||
for (string& tty : ttys)
|
||||
{
|
||||
trace("[MAIN] serial device %s\n", tty.c_str());
|
||||
if (bus_manager_->not_serial_wmbus_devices_.count(tty) > 0)
|
||||
{
|
||||
trace("[MAIN] skipping already probed not wmbus serial device %s\n", tty.c_str());
|
||||
continue;
|
||||
}
|
||||
if (config->do_not_probe_ttys.count("all") > 0 ||
|
||||
config->do_not_probe_ttys.count(tty) > 0)
|
||||
{
|
||||
trace("[MAIN] not probing forbidden tty %s\n", tty.c_str());
|
||||
continue;
|
||||
}
|
||||
shared_ptr<SerialDevice> sd = serial_manager_->lookup(tty);
|
||||
if (!sd)
|
||||
{
|
||||
// This serial device is not in use, but is there a device on it?
|
||||
debug("(main) device %s not currently used, detect contents...\n", tty.c_str());
|
||||
|
||||
// What should the desired linkmodes be? We have no specified device since this an auto detect.
|
||||
// But we might have an auto linkmodes?
|
||||
LinkModeSet desired_linkmodes = config->auto_device_linkmodes;
|
||||
if (desired_linkmodes.empty())
|
||||
{
|
||||
// Nope, lets fall back on the default_linkmodes.
|
||||
desired_linkmodes = config->default_device_linkmodes;
|
||||
}
|
||||
Detected detected = detectWMBusDeviceOnTTY(tty, desired_linkmodes, serial_manager_);
|
||||
if (detected.found_type != DEVICE_UNKNOWN)
|
||||
{
|
||||
// See if we had a specified device without a file,
|
||||
// that matches this detected device.
|
||||
bool found = find_specified_device_and_update_detected(config, &detected);
|
||||
if (config->use_auto_device_detect || found)
|
||||
{
|
||||
// Open the device, only if auto is enabled, or if the device was specified.
|
||||
open_bus_device_and_potentially_set_linkmodes(config, found?"config":"auto", &detected);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This serial device was something that we could not recognize.
|
||||
// A modem, an android phone, a teletype Model 33, etc....
|
||||
// Mark this serial device as unknown, to avoid repeated detection attempts.
|
||||
bus_manager_->not_serial_wmbus_devices_.insert(tty);
|
||||
verbose("(main) ignoring %s, it does not respond as any of the supported wmbus devices.\n", tty.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void perform_auto_scan_of_swradio_devices(Configuration *config)
|
||||
{
|
||||
// Enumerate all swradio devices, that can be used.
|
||||
vector<string> serialnrs = listRtlSdrDevices();
|
||||
|
||||
if (serialnrs.size() > 0)
|
||||
{
|
||||
if (!rtlsdr_found_ || !rtlwmbus_found_)
|
||||
{
|
||||
rtlsdr_found_ = check_if_rtlsdr_exists_in_path();
|
||||
rtlwmbus_found_ = check_if_rtlwmbus_exists_in_path();
|
||||
// rtl433_found_ = check_if_rtl433_exists_in_path();
|
||||
}
|
||||
if (!rtlsdr_found_)
|
||||
{
|
||||
warning("Warning! Auto scan has found an rtl_sdr dongle, but you have no rtl_sdr in the path!\n");
|
||||
}
|
||||
if (!rtlwmbus_found_)
|
||||
{
|
||||
warning("Warning! Auto scan has found an rtl_sdr dongle, but you have no rtl_wmbus in the path!\n");
|
||||
}
|
||||
}
|
||||
|
||||
// We are missing rtl_sdr and/or rtl_wmbus, stop here.
|
||||
if (!rtlsdr_found_ || !rtlwmbus_found_) return;
|
||||
|
||||
// Did an unavailable swradio-device get unplugged? Then remove it from the known-not-swradio-device set.
|
||||
remove_lost_swradio_devices_from_ignore_list(serialnrs);
|
||||
|
||||
for (string& serialnr : serialnrs)
|
||||
{
|
||||
trace("[MAIN] rtlsdr device %s\n", serialnr.c_str());
|
||||
if (bus_manager_->not_swradio_wmbus_devices_.count(serialnr) > 0)
|
||||
{
|
||||
trace("[MAIN] skipping already probed rtlsdr %s\n", serialnr.c_str());
|
||||
continue;
|
||||
}
|
||||
shared_ptr<SerialDevice> sd = serial_manager_->lookup(serialnr);
|
||||
if (!sd)
|
||||
{
|
||||
debug("(main) rtlsdr device %s not currently used.\n", serialnr.c_str());
|
||||
Detected detected;
|
||||
detected.specified_device.type = WMBusDeviceType::DEVICE_RTLWMBUS;
|
||||
AccessCheck ac = detectRTLSDR(serialnr, &detected);
|
||||
if (ac != AccessCheck::AccessOK)
|
||||
{
|
||||
// We cannot access this swradio device.
|
||||
bus_manager_->not_swradio_wmbus_devices_.insert(serialnr);
|
||||
verbose("(main) ignoring rtlsdr %s since it is unavailable.\n", serialnr.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the serialnr as the id.
|
||||
detected.found_device_id = serialnr;
|
||||
bool found = find_specified_device_and_update_detected(config, &detected);
|
||||
if (config->use_auto_device_detect || found)
|
||||
{
|
||||
// Open the device, only if auto is enabled, or if the device was specified.
|
||||
open_bus_device_and_potentially_set_linkmodes(config, found?"config":"auto", &detected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
time_t last_info_print_ = 0;
|
||||
|
||||
void regular_checkup(Configuration *config)
|
||||
|
@ -961,68 +297,10 @@ void regular_checkup(Configuration *config)
|
|||
|
||||
if (serial_manager_ && config)
|
||||
{
|
||||
detect_and_configure_wmbus_devices(config, DetectionType::ALL);
|
||||
bus_manager_->detectAndConfigureWmbusDevices(config, DetectionType::ALL);
|
||||
}
|
||||
|
||||
{
|
||||
LOCK_BUS_DEVICES(regular_checkup);
|
||||
|
||||
for (auto &w : bus_manager_->bus_devices_)
|
||||
{
|
||||
if (w->isWorking())
|
||||
{
|
||||
w->checkStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void remove_lost_serial_devices_from_ignore_list(vector<string> &devices)
|
||||
{
|
||||
vector<string> to_be_removed;
|
||||
|
||||
// Iterate over the devices known to NOT be wmbus devices.
|
||||
for (const string& nots : bus_manager_->not_serial_wmbus_devices_)
|
||||
{
|
||||
auto i = std::find(devices.begin(), devices.end(), nots);
|
||||
if (i == devices.end())
|
||||
{
|
||||
// The device has been removed, therefore
|
||||
// we have to forget that the device was not a wmbus device.
|
||||
// Since next time someone plugs in a device, it might be a different
|
||||
// one getting the same /dev/ttyUSBxx
|
||||
to_be_removed.push_back(nots);
|
||||
}
|
||||
}
|
||||
|
||||
for (string& r : to_be_removed)
|
||||
{
|
||||
bus_manager_->not_serial_wmbus_devices_.erase(r);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_lost_swradio_devices_from_ignore_list(vector<string> &devices)
|
||||
{
|
||||
vector<string> to_be_removed;
|
||||
|
||||
// Iterate over the devices known to NOT be wmbus devices.
|
||||
for (const string& nots : bus_manager_->not_swradio_wmbus_devices_)
|
||||
{
|
||||
auto i = std::find(devices.begin(), devices.end(), nots);
|
||||
if (i == devices.end())
|
||||
{
|
||||
// The device has been removed, therefore
|
||||
// we have to forget that the device was not a wmbus device.
|
||||
// Since next time someone plugs in a device, it might be a different
|
||||
// one getting the same /dev/ttyUSBxx
|
||||
to_be_removed.push_back(nots);
|
||||
}
|
||||
}
|
||||
|
||||
for (string& r : to_be_removed)
|
||||
{
|
||||
bus_manager_->not_swradio_wmbus_devices_.erase(r);
|
||||
}
|
||||
bus_manager_->regularCheckup();
|
||||
}
|
||||
|
||||
void setup_log_file(Configuration *config)
|
||||
|
@ -1104,9 +382,15 @@ bool start(Configuration *config)
|
|||
// or sent to shell invocations.
|
||||
printer_ = create_printer(config);
|
||||
|
||||
bus_manager_ = shared_ptr<BusManager>(new BusManager());
|
||||
// The meter manager knows about specified device templates
|
||||
// and creates meters on demand when the telegram arrives
|
||||
// or on startup for 2-way communication meters like mbus or T2.
|
||||
meter_manager_ = createMeterManager(config->daemon);
|
||||
|
||||
// The bus manager detects new/lost wmbus devices and
|
||||
// configures the devices according to the specification.
|
||||
bus_manager_ = createBusManager(serial_manager_, meter_manager_);
|
||||
|
||||
// When a meter is updated, print it, shell it, log it, etc.
|
||||
meter_manager_->whenMeterUpdated(
|
||||
[&](Telegram *t,Meter *meter)
|
||||
|
@ -1116,19 +400,15 @@ bool start(Configuration *config)
|
|||
}
|
||||
);
|
||||
|
||||
// Create the Meter objects from the configuration.
|
||||
setup_meters(config, meter_manager_.get());
|
||||
|
||||
// Detect and initialize any devices.
|
||||
// Future changes are triggered through this callback.
|
||||
printed_warning_ = true;
|
||||
|
||||
detect_and_configure_wmbus_devices(config, DetectionType::STDIN_FILE_SIMULATION);
|
||||
bus_manager_->detectAndConfigureWmbusDevices(config, DetectionType::STDIN_FILE_SIMULATION);
|
||||
|
||||
serial_manager_->startEventLoop();
|
||||
detect_and_configure_wmbus_devices(config, DetectionType::ALL);
|
||||
|
||||
if (bus_manager_->bus_devices_.size() == 0)
|
||||
bus_manager_->detectAndConfigureWmbusDevices(config, DetectionType::ALL);
|
||||
|
||||
if (bus_manager_->numBusDevices() == 0)
|
||||
{
|
||||
if (config->nodeviceexit)
|
||||
{
|
||||
|
@ -1138,7 +418,7 @@ bool start(Configuration *config)
|
|||
else
|
||||
{
|
||||
notice("No wmbus device detected, waiting for a device to be plugged in.\n");
|
||||
check_if_multiple_wmbus_meters_running();
|
||||
checkIfMultipleWmbusMetersRunning();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1180,6 +460,7 @@ bool start(Configuration *config)
|
|||
});
|
||||
}
|
||||
|
||||
/*
|
||||
for (auto &w : bus_manager_->bus_devices_)
|
||||
{
|
||||
if (w->type() == WMBusDeviceType::DEVICE_MBUS)
|
||||
|
@ -1210,19 +491,16 @@ bool start(Configuration *config)
|
|||
|
||||
}
|
||||
}
|
||||
*/
|
||||
bus_manager_->runAnySimulations();
|
||||
|
||||
|
||||
for (auto &w : bus_manager_->bus_devices_)
|
||||
{
|
||||
// Real devices do nothing, but the simulator device will simulate.
|
||||
w->simulate();
|
||||
}
|
||||
|
||||
// This thread now sleeps waiting for the serial communication manager to stop.
|
||||
// This main thread now sleeps and waits for the serial communication manager to stop.
|
||||
// The manager has already started one thread that performs select and then callbacks
|
||||
// to decoding the telegrams, finally invoking the printer.
|
||||
// The regular callback invoked to detect changes in the wmbus devices and
|
||||
// the alarm checks, is started in a separate thread.
|
||||
// The regular callback invoked to detect changes in the wmbus devices and perform the alarm checks,
|
||||
// is started in a separate thread.
|
||||
//
|
||||
// Totalling 3 threads: main (sleeping here), serial manager (telegram handling), regular checks (check lost devices and alarms)
|
||||
serial_manager_->waitForStop();
|
||||
|
||||
if (config->daemon)
|
||||
|
@ -1230,8 +508,7 @@ bool start(Configuration *config)
|
|||
notice("(wmbusmeters) shutting down\n");
|
||||
}
|
||||
|
||||
// Destroy any remaining allocated objects.
|
||||
bus_manager_->bus_devices_.clear();
|
||||
bus_manager_->removeAllBusDevices();
|
||||
meter_manager_->removeAllMeters();
|
||||
printer_.reset();
|
||||
serial_manager_.reset();
|
||||
|
|
25
src/util.cc
25
src/util.cc
|
@ -1865,3 +1865,28 @@ bool parseExtras(string s, map<string,string> *extras)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -205,5 +205,6 @@ std::string lookForExecutable(std::string prog, std::string bin_dir, std::string
|
|||
|
||||
// Extract from "ppm=5 radix=7" and put key values into map.
|
||||
bool parseExtras(std::string s, std::map<std::string,std::string> *extras);
|
||||
void checkIfMultipleWmbusMetersRunning();
|
||||
|
||||
#endif
|
||||
|
|
Ładowanie…
Reference in New Issue