Add option pollinterval=10m to meter files.

pull/540/head
Fredrik Öhrström 2022-05-01 17:05:30 +02:00
rodzic 4c6fefa089
commit 8d164b7753
12 zmienionych plików z 106 dodań i 34 usunięć

Wyświetl plik

@ -1,4 +1,8 @@
ATTENTION! When a field is not optional in the driver description,
but alas, no data has arrived in the telegram, then the json now
contains a null for the value! Previousy 0 was used, which is misleading.
ATTENTION! The default location of the meter_readings directory has changed ATTENTION! The default location of the meter_readings directory has changed
from /var/log/wmbusmeters/meter_readings to /var/lib/wmbusmeters/meter_readings from /var/log/wmbusmeters/meter_readings to /var/lib/wmbusmeters/meter_readings
This only affects new installations. Existing conf files will use the old location This only affects new installations. Existing conf files will use the old location
@ -9,7 +13,7 @@ Add detection of bad CUL firmware.
Using :mbus as suffix to the meter driver now works to poll a meter of mbus instead of Using :mbus as suffix to the meter driver now works to poll a meter of mbus instead of
listening to wmbus telegrams. listening to wmbus telegrams.
wmbusmeters --pollinterval=1h --format=json MAIN=/dev/ttyUSB0:mbus MyTemp piigth:MAIN:2400:mbus 12301234 NOKEY wmbusmeters --pollinterval=1h --format=json MAIN=/dev/ttyUSB0:mbus:2400 MyTemp piigth:MAIN:mbus 12301234 NOKEY
Added --pollinterval=<time> to set the poll interval for all meters to 10 minutes. Added --pollinterval=<time> to set the poll interval for all meters to 10 minutes.
As <time> you can say 5s 10m 11h etc. As <time> you can say 5s 10m 11h etc.

Wyświetl plik

@ -184,13 +184,14 @@ check_docs:
@cat src/cmdline.cc | grep -o -- '--[a-z][a-z]*' | sort | uniq | grep -v internaltesting > /tmp/options_in_code @cat src/cmdline.cc | grep -o -- '--[a-z][a-z]*' | sort | uniq | grep -v internaltesting > /tmp/options_in_code
@cat wmbusmeters.1 | grep -o -- '--[a-z][a-z]*' | sort | uniq | grep -v internaltesting > /tmp/options_in_man @cat wmbusmeters.1 | grep -o -- '--[a-z][a-z]*' | sort | uniq | grep -v internaltesting > /tmp/options_in_man
@cat README.md | grep -o -- '--[a-z][a-z]*' | sort | uniq | grep -v internaltesting > /tmp/options_in_readme @cat README.md | grep -o -- '--[a-z][a-z]*' | sort | uniq | grep -v internaltesting > /tmp/options_in_readme
@./build/wmbusmeters --help | grep -o -- '--[a-z][a-z]*' | sort | uniq | grep -v internaltesting > /tmp/options_in_binary @$(BUILD)/wmbusmeters --help | grep -o -- '--[a-z][a-z]*' | sort | uniq | grep -v internaltesting > /tmp/options_in_binary
@diff /tmp/options_in_code /tmp/options_in_man || echo CODE_VS_MAN @diff /tmp/options_in_code /tmp/options_in_man || echo CODE_VS_MAN
@diff /tmp/options_in_code /tmp/options_in_readme || echo CODE_VS_README @diff /tmp/options_in_code /tmp/options_in_readme || echo CODE_VS_README
@diff /tmp/options_in_code /tmp/options_in_binary || echo CODE_VS_BINARY @diff /tmp/options_in_code /tmp/options_in_binary || echo CODE_VS_BINARY
@echo "OK docs" @echo "OK docs"
install: $(BUILD)/wmbusmeters check_docs install: $(BUILD)/wmbusmeters check_docs
echo "Installing $(BUILD)/wmbusmeters"
@./install.sh $(BUILD)/wmbusmeters $(DESTDIR) $(EXTRA_INSTALL_OPTIONS) @./install.sh $(BUILD)/wmbusmeters $(DESTDIR) $(EXTRA_INSTALL_OPTIONS)
uninstall: uninstall:

Wyświetl plik

@ -110,11 +110,10 @@ here we pick the bus alias MAIN for the mbus using 2400 bps for all meters on th
``` ```
MAIN=/dev/ttyUSB0:mbus:2400 MAIN=/dev/ttyUSB0:mbus:2400
``` ```
and here we pick the bus alias WIRELESS2 for an im871a dongle: and here we pick the bus alias OUT for an im871a dongle:
``` ```
WIRELESS2=/dev/ttyUSB1:im871a:c2 OUT=/dev/ttyUSB1:im871a:c2
``` ```
(This is not yet fully functional.)
The bus alias is then used in the meter driver specification to specify which The bus alias is then used in the meter driver specification to specify which
bus the mbus poll request should be sent to. bus the mbus poll request should be sent to.
@ -129,6 +128,8 @@ loglevel=normal
# You can use auto:t1 to find the device you have connected to your system. # You can use auto:t1 to find the device you have connected to your system.
# But do not use auto here since it will cause unnecessary and slow probing of the serial ports. # But do not use auto here since it will cause unnecessary and slow probing of the serial ports.
device=/dev/ttyUSB0:im871a:c1,t1 device=/dev/ttyUSB0:im871a:c1,t1
# And mbus
device=MAIN=/dev/ttyUSB1:mbus:2400
# But do not probe this serial tty. # But do not probe this serial tty.
donotprobe=/dev/ttyACM2 donotprobe=/dev/ttyACM2
logtelegrams=false logtelegrams=false
@ -154,10 +155,19 @@ key=00112233445566778899AABBCCDDEEFF
driver=multical21 driver=multical21
``` ```
And an mbus meter file in /etc/wmbusmeters.d/MyTempHygro
```ini
name=MyTempHygro
id=11223344
driver=piigth:mbus
pollinterval=60s
```
# Important information about meter drivers and their names. # Important information about meter drivers and their names.
You can use `driver=auto` to have wmbusmeters automatically detect You can use `driver=auto` to have wmbusmeters automatically detect
and use the best driver for your meter, but you should not use auto in production. and use the best driver for your meter, but you should >not< use auto in production.
You can find out which driver is recommended by running `wmbusmeters im871a:t1`. You can find out which driver is recommended by running `wmbusmeters im871a:t1`.
This will print information like: This will print information like:
@ -172,15 +182,16 @@ Received telegram from: 71727374
For production use it is very much recommended that you specify the exact driver For production use it is very much recommended that you specify the exact driver
in the meter file. The reason is that new and better drivers might be developed in the meter file. The reason is that new and better drivers might be developed
for your meter, where the keys and the content of the json might change. for your meter, where the keys and the content of the json might change.
Such new drivers are guaranteed to have a different driver name! Such new drivers are guaranteed to have a different driver name.
The auto look up will change to the new driver, but the old driver will still work. The auto look up will change to the new driver, but the old driver will still work.
So wmbusmeters makes a guarantee that if you have specified the driver name, So wmbusmeters strives to guarantee that if you have specified the driver name,
then wmbusmeters can be safely upgraded at any time. The json will not then wmbusmeters can be safely upgraded at any time. The json will not
change in an incompatible way. (The only allowed changes are: adding new fields change in an incompatible way. (The only allowed changes are: adding new fields
and changing the ordering.) and changing the ordering.)
Now plugin your wmbus dongle. Now plugin your wmbus dongle.
Wmbusmeters should start automatically, check with `tail -f /var/log/syslog` and `tail -f /var/log/wmbusmeters/wmbusmeters.log` Wmbusmeters should start automatically, check with `tail -f /var/log/syslog` and `tail -f /var/log/wmbusmeters/wmbusmeters.log`
(If you are using an rtlsdr dongle, then make sure that either the binaries `/usr/bin/rtl_sdr` and (If you are using an rtlsdr dongle, then make sure that either the binaries `/usr/bin/rtl_sdr` and
`/usr/bin/rtl_wmbus` exists and are executable. Or that the executable `rtl_sdr/rtl_wmbus` binaries `/usr/bin/rtl_wmbus` exists and are executable. Or that the executable `rtl_sdr/rtl_wmbus` binaries
@ -307,7 +318,7 @@ As {options} you can use:
--normal for normal logging --normal for normal logging
--oneshot wait for an update from each meter, then quit --oneshot wait for an update from each meter, then quit
--ppjson pretty print the json --ppjson pretty print the json
--pollinterval=<time> time between polling of meters, default is 10m --pollinterval=<time> time between polling of meters, must be set to get polling.
--resetafter=<time> reset the wmbus dongle regularly, default is 23h --resetafter=<time> reset the wmbus dongle regularly, default is 23h
--selectfields=id,timestamp,total_m3 select only these fields to be printed (--listfields=<meter> to list available fields) --selectfields=id,timestamp,total_m3 select only these fields to be printed (--listfields=<meter> to list available fields)
--separator=<c> change field separator to c --separator=<c> change field separator to c

Wyświetl plik

@ -55,6 +55,7 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
string id; string id;
string key = ""; string key = "";
string linkmodes; string linkmodes;
int poll_interval = 0;
vector<string> telegram_shells; vector<string> telegram_shells;
vector<string> alarm_shells; vector<string> alarm_shells;
vector<string> extra_constant_fields; vector<string> extra_constant_fields;
@ -109,6 +110,19 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
debug("(config) key=<notprinted>\n"); debug("(config) key=<notprinted>\n");
} }
else else
if (p.first == "pollinterval") {
if (poll_interval != 0)
{
error("You have already specified a poll interval for this meter!\n");
}
poll_interval = parseTime(p.second);
if (poll_interval == 0)
{
error("Poll interval must be non-zero \"%s\"!\n", p.second.c_str());
}
}
else
if (p.first == "shell") { if (p.first == "shell") {
telegram_shells.push_back(p.second); telegram_shells.push_back(p.second);
} }
@ -136,6 +150,7 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
MeterInfo mi; MeterInfo mi;
mi.parse(name, driver, id, key); // sets driver, extras, name, bus, bps, link_modes, ids, name, key mi.parse(name, driver, id, key); // sets driver, extras, name, bus, bps, link_modes, ids, name, key
mi.poll_interval = poll_interval;
/* /*
Ignore link mode checking until all drivers have been refactored. Ignore link mode checking until all drivers have been refactored.

Wyświetl plik

@ -96,7 +96,7 @@ struct Configuration
std::string logfile; std::string logfile;
bool json {}; bool json {};
bool pretty_print_json {}; bool pretty_print_json {};
int pollinterval = 60*10; // Time between polling, default 10 minutes. int pollinterval {}; // Time between polling of mbus meters.
bool fields {}; bool fields {};
char separator { ';' }; char separator { ';' };
std::vector<std::string> telegram_shells; std::vector<std::string> telegram_shells;

Wyświetl plik

@ -447,7 +447,7 @@ void setup_meters(Configuration *config, MeterManager *manager)
{ {
m.conversions = config->conversions; m.conversions = config->conversions;
if (m.link_modes.has(LinkMode::MBUS) || needsPolling(m.driver, m.driver_name)) if (m.needsPolling() || driverNeedsPolling(m.driver, m.driver_name))
{ {
// A polling meter must be defined from the start. // A polling meter must be defined from the start.
auto meter = createMeter(&m); auto meter = createMeter(&m);

Wyświetl plik

@ -1015,8 +1015,11 @@ void MeterCommonImplementation::addStringFieldWithExtractorAndLookup(string vnam
void MeterCommonImplementation::poll(shared_ptr<BusManager> bus_manager) void MeterCommonImplementation::poll(shared_ptr<BusManager> bus_manager)
{ {
if (link_modes_.has(LinkMode::MBUS)) if (needsPolling())
{ {
// An valid poll interval must have been set!
if (pollInterval() <= 0) return;
time_t now = time(NULL); time_t now = time(NULL);
time_t next_poll_time = timestampLastUpdate()+pollInterval(); time_t next_poll_time = timestampLastUpdate()+pollInterval();
if (now < next_poll_time) if (now < next_poll_time)
@ -1029,7 +1032,7 @@ void MeterCommonImplementation::poll(shared_ptr<BusManager> bus_manager)
if (!bus_device) if (!bus_device)
{ {
debug("(meter) Could not find bus from name \"%s\"\n", bus().c_str()); warning("(meter) warning! no bus specified for meter %s %s\n", name().c_str(), idsc().c_str());
return; return;
} }
@ -1061,7 +1064,10 @@ void MeterCommonImplementation::poll(shared_ptr<BusManager> bus_manager)
buf[3] = cs; // checksum buf[3] = cs; // checksum
buf[4] = 0x16; // Stop buf[4] = 0x16; // Stop
verbose("(meter) req ud2 bus %s address %s\n", bus_device->busAlias().c_str(),id.c_str()); verbose("(meter) polling %s %s (primary) with req ud2 on bus %s\n",
name().c_str(),
id.c_str(),
bus_device->busAlias().c_str(),id.c_str());
bus_device->serial()->send(buf); bus_device->serial()->send(buf);
} }
@ -1118,7 +1124,10 @@ void MeterCommonImplementation::poll(shared_ptr<BusManager> bus_manager)
buf[3] = cs; // checksum buf[3] = cs; // checksum
buf[4] = 0x16; // Stop buf[4] = 0x16; // Stop
verbose("(meter) req ud2 bus %s address %s\n", bus_device->busAlias().c_str(),id.c_str()); verbose("(meter) polling %s %s (secondary) with req ud2 bus %s\n",
name().c_str(),
id.c_str(),
bus_device->busAlias().c_str());
bus_device->serial()->send(buf); bus_device->serial()->send(buf);
} }
} }
@ -1187,6 +1196,10 @@ time_t MeterCommonImplementation::timestampLastUpdate()
void MeterCommonImplementation::setPollInterval(time_t interval) void MeterCommonImplementation::setPollInterval(time_t interval)
{ {
poll_interval_ = interval; poll_interval_ = interval;
if (needsPolling() && poll_interval_ == 0)
{
warning("(meter) %s %s needs polling but has no pollinterval set!\n", name().c_str(), idsc().c_str());
}
} }
time_t MeterCommonImplementation::pollInterval() time_t MeterCommonImplementation::pollInterval()
@ -1194,7 +1207,15 @@ time_t MeterCommonImplementation::pollInterval()
return poll_interval_; return poll_interval_;
} }
bool needsPolling(MeterDriver d, DriverName& dn) bool MeterCommonImplementation::needsPolling()
{
return link_modes_.has(LinkMode::MBUS) ||
link_modes_.has(LinkMode::C2) ||
link_modes_.has(LinkMode::T2) ||
link_modes_.has(LinkMode::S2);
}
bool driverNeedsPolling(MeterDriver d, DriverName& dn)
{ {
if (d != MeterDriver::UNKNOWN && d != MeterDriver::AUTO) if (d != MeterDriver::UNKNOWN && d != MeterDriver::AUTO)
{ {
@ -1209,7 +1230,10 @@ LIST_OF_METERS
DriverInfo& di = all_registered_drivers_[dn.str()]; DriverInfo& di = all_registered_drivers_[dn.str()];
// Return true for MBUS,S2,C2,T2 meters. Currently only mbus is implemented. // Return true for MBUS,S2,C2,T2 meters. Currently only mbus is implemented.
return di.linkModes().has(LinkMode::MBUS); return di.linkModes().has(LinkMode::MBUS) ||
di.linkModes().has(LinkMode::C2) ||
di.linkModes().has(LinkMode::T2) ||
di.linkModes().has(LinkMode::S2);
} }
const char *toString(MeterType type) const char *toString(MeterType type)
@ -2091,6 +2115,7 @@ shared_ptr<Meter> createMeter(MeterInfo *mi)
DriverInfo& di = all_registered_drivers_[mi->driver_name.str()]; DriverInfo& di = all_registered_drivers_[mi->driver_name.str()];
shared_ptr<Meter> newm = di.construct(*mi); shared_ptr<Meter> newm = di.construct(*mi);
newm->addConversions(mi->conversions); newm->addConversions(mi->conversions);
newm->setPollInterval(mi->poll_interval);
verbose("(meter) constructed \"%s\" \"%s\" \"%s\" %s\n", verbose("(meter) constructed \"%s\" \"%s\" \"%s\" %s\n",
mi->name.c_str(), mi->name.c_str(),
di.name().str().c_str(), di.name().str().c_str(),
@ -2106,6 +2131,7 @@ shared_ptr<Meter> createMeter(MeterInfo *mi)
{ \ { \
newm = create##cname(*mi); \ newm = create##cname(*mi); \
newm->addConversions(mi->conversions); \ newm->addConversions(mi->conversions); \
newm->setPollInterval(mi->poll_interval); \
verbose("(meter) created \"%s\" \"" #mname "\" \"%s\" %s\n", \ verbose("(meter) created \"%s\" \"" #mname "\" \"%s\" %s\n", \
mi->name.c_str(), mi->idsc.c_str(), keymsg); \ mi->name.c_str(), mi->idsc.c_str(), keymsg); \
return newm; \ return newm; \
@ -2253,6 +2279,14 @@ bool MeterInfo::parse(string n, string d, string i, string k)
return true; return true;
} }
bool MeterInfo::needsPolling()
{
return link_modes.has(LinkMode::MBUS) ||
link_modes.has(LinkMode::C2) ||
link_modes.has(LinkMode::T2) ||
link_modes.has(LinkMode::S2);
}
bool isValidKey(string& key, MeterDriver mt) bool isValidKey(string& key, MeterDriver mt)
{ {
if (key.length() == 0) return true; if (key.length() == 0) return true;

Wyświetl plik

@ -226,6 +226,7 @@ struct MeterInfo
} }
bool parse(string name, string driver, string id, string key); bool parse(string name, string driver, string id, string key);
bool needsPolling();
}; };
///////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -277,8 +278,8 @@ bool registerDriver(function<void(DriverInfo&di)> setup);
bool lookupDriverInfo(string& driver, DriverInfo *di); bool lookupDriverInfo(string& driver, DriverInfo *di);
// Return the best driver match for a telegram. // Return the best driver match for a telegram.
DriverInfo pickMeterDriver(Telegram *t); DriverInfo pickMeterDriver(Telegram *t);
// Return true for mbus and S2/C2/T2 meters. // Return true for mbus and S2/C2/T2 drivers.
bool needsPolling(MeterDriver driver, DriverName& dn); bool driverNeedsPolling(MeterDriver driver, DriverName& dn);
vector<DriverInfo>& allRegisteredDrivers(); vector<DriverInfo>& allRegisteredDrivers();
@ -433,6 +434,7 @@ struct Meter
virtual time_t timestampLastUpdate() = 0; virtual time_t timestampLastUpdate() = 0;
virtual void setPollInterval(time_t interval) = 0; virtual void setPollInterval(time_t interval) = 0;
virtual time_t pollInterval() = 0; virtual time_t pollInterval() = 0;
virtual bool needsPolling() = 0;
virtual void setNumericValue(FieldInfo *fi, Unit u, double v) = 0; virtual void setNumericValue(FieldInfo *fi, Unit u, double v) = 0;
virtual double getNumericValue(FieldInfo *fi, Unit u) = 0; virtual double getNumericValue(FieldInfo *fi, Unit u) = 0;

Wyświetl plik

@ -65,7 +65,7 @@ struct MeterCommonImplementation : public virtual Meter
time_t timestampLastUpdate(); time_t timestampLastUpdate();
void setPollInterval(time_t interval); void setPollInterval(time_t interval);
time_t pollInterval(); time_t pollInterval();
bool needsPolling();
void onUpdate(function<void(Telegram*,Meter*)> cb); void onUpdate(function<void(Telegram*,Meter*)> cb);
int numUpdates(); int numUpdates();

Wyświetl plik

@ -72,7 +72,7 @@ int main(int argc, char **argv)
/* /*
test_linkmodes();*/ test_linkmodes();*/
test_ids(); test_ids();
test_addresses(); // test_addresses();
test_kdf(); test_kdf();
test_periods(); test_periods();
test_months(); test_months();
@ -924,7 +924,7 @@ void test_meters()
"", // extras "", // extras
"", // bus "", // bus
"0", // bps "0", // bps
"c1,t1,mbus"); // linkmodes "mbus,c1,t1"); // linkmodes
/* /*
config_content = config_content =

Wyświetl plik

@ -81,18 +81,21 @@ void setIgnoreDuplicateTelegrams(bool idt);
#define LIST_OF_LINK_MODES \ #define LIST_OF_LINK_MODES \
X(Any,any,--anylinkmode,0xffff) \ X(Any,any,--anylinkmode,0xffff) \
X(C1,c1,--c1,0x1) \ X(MBUS,mbus,--mbus,0x1) \
X(S1,s1,--s1,0x2) \ X(C1,c1,--c1,0x2) \
X(S1m,s1m,--s1m,0x4) \ X(S1,s1,--s1,0x4) \
X(T1,t1,--t1,0x8) \ X(S1m,s1m,--s1m,0x8) \
X(N1a,n1a,--n1a,0x10) \ X(T1,t1,--t1,0x10) \
X(N1b,n1b,--n1b,0x20) \ X(C2,c2,--c2,0x20) \
X(N1c,n1c,--n1c,0x40) \ X(S2,s2,--s2,0x40) \
X(N1d,n1d,--n1d,0x80) \ X(T2,t2,--t2,0x80) \
X(N1e,n1e,--n1e,0x100) \ X(N1a,n1a,--n1a,0x100) \
X(N1f,n1f,--n1f,0x200) \ X(N1b,n1b,--n1b,0x200) \
X(MBUS,mbus,--mbus,0x400) \ X(N1c,n1c,--n1c,0x400) \
X(LORA,lora,--lora,0x800) \ X(N1d,n1d,--n1d,0x800) \
X(N1e,n1e,--n1e,0x1000) \
X(N1f,n1f,--n1f,0x2000) \
X(LORA,lora,--lora,0x400) \
X(UNKNOWN,unknown,----,0x0) X(UNKNOWN,unknown,----,0x0)
enum class LinkMode { enum class LinkMode {

Wyświetl plik

@ -93,6 +93,8 @@ Add :verbose to any analyze to get more verbose analyze output.
\fB\--oneshot\fR wait for an update from each meter, then quit \fB\--oneshot\fR wait for an update from each meter, then quit
\fB\--pollinterval=\fR<interval> poll mbus meters every <interval>, default is 10m.
\fB\--ppjson\fR pretty print the json output \fB\--ppjson\fR pretty print the json output
\fB\--resetafter=\fR<time> reset the wmbus dongle regularly, default is 23h \fB\--resetafter=\fR<time> reset the wmbus dongle regularly, default is 23h