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
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
@ -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
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.
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 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
@./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_readme || echo CODE_VS_README
@diff /tmp/options_in_code /tmp/options_in_binary || echo CODE_VS_BINARY
@echo "OK docs"
install: $(BUILD)/wmbusmeters check_docs
echo "Installing $(BUILD)/wmbusmeters"
@./install.sh $(BUILD)/wmbusmeters $(DESTDIR) $(EXTRA_INSTALL_OPTIONS)
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
```
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
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.
# But do not use auto here since it will cause unnecessary and slow probing of the serial ports.
device=/dev/ttyUSB0:im871a:c1,t1
# And mbus
device=MAIN=/dev/ttyUSB1:mbus:2400
# But do not probe this serial tty.
donotprobe=/dev/ttyACM2
logtelegrams=false
@ -154,10 +155,19 @@ key=00112233445566778899AABBCCDDEEFF
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.
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`.
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
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.
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.
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
change in an incompatible way. (The only allowed changes are: adding new fields
and changing the ordering.)
Now plugin your wmbus dongle.
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
`/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
--oneshot wait for an update from each meter, then quit
--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
--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

Wyświetl plik

@ -55,6 +55,7 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
string id;
string key = "";
string linkmodes;
int poll_interval = 0;
vector<string> telegram_shells;
vector<string> alarm_shells;
vector<string> extra_constant_fields;
@ -109,6 +110,19 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
debug("(config) key=<notprinted>\n");
}
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") {
telegram_shells.push_back(p.second);
}
@ -136,6 +150,7 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
MeterInfo mi;
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.

Wyświetl plik

@ -96,7 +96,7 @@ struct Configuration
std::string logfile;
bool 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 {};
char separator { ';' };
std::vector<std::string> telegram_shells;

Wyświetl plik

@ -447,7 +447,7 @@ void setup_meters(Configuration *config, MeterManager *manager)
{
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.
auto meter = createMeter(&m);

Wyświetl plik

@ -1015,8 +1015,11 @@ void MeterCommonImplementation::addStringFieldWithExtractorAndLookup(string vnam
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 next_poll_time = timestampLastUpdate()+pollInterval();
if (now < next_poll_time)
@ -1029,7 +1032,7 @@ void MeterCommonImplementation::poll(shared_ptr<BusManager> bus_manager)
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;
}
@ -1061,7 +1064,10 @@ void MeterCommonImplementation::poll(shared_ptr<BusManager> bus_manager)
buf[3] = cs; // checksum
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);
}
@ -1118,7 +1124,10 @@ void MeterCommonImplementation::poll(shared_ptr<BusManager> bus_manager)
buf[3] = cs; // checksum
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);
}
}
@ -1187,6 +1196,10 @@ time_t MeterCommonImplementation::timestampLastUpdate()
void MeterCommonImplementation::setPollInterval(time_t 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()
@ -1194,7 +1207,15 @@ time_t MeterCommonImplementation::pollInterval()
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)
{
@ -1209,7 +1230,10 @@ LIST_OF_METERS
DriverInfo& di = all_registered_drivers_[dn.str()];
// 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)
@ -2091,6 +2115,7 @@ shared_ptr<Meter> createMeter(MeterInfo *mi)
DriverInfo& di = all_registered_drivers_[mi->driver_name.str()];
shared_ptr<Meter> newm = di.construct(*mi);
newm->addConversions(mi->conversions);
newm->setPollInterval(mi->poll_interval);
verbose("(meter) constructed \"%s\" \"%s\" \"%s\" %s\n",
mi->name.c_str(),
di.name().str().c_str(),
@ -2106,6 +2131,7 @@ shared_ptr<Meter> createMeter(MeterInfo *mi)
{ \
newm = create##cname(*mi); \
newm->addConversions(mi->conversions); \
newm->setPollInterval(mi->poll_interval); \
verbose("(meter) created \"%s\" \"" #mname "\" \"%s\" %s\n", \
mi->name.c_str(), mi->idsc.c_str(), keymsg); \
return newm; \
@ -2253,6 +2279,14 @@ bool MeterInfo::parse(string n, string d, string i, string k)
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)
{
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 needsPolling();
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -277,8 +278,8 @@ bool registerDriver(function<void(DriverInfo&di)> setup);
bool lookupDriverInfo(string& driver, DriverInfo *di);
// Return the best driver match for a telegram.
DriverInfo pickMeterDriver(Telegram *t);
// Return true for mbus and S2/C2/T2 meters.
bool needsPolling(MeterDriver driver, DriverName& dn);
// Return true for mbus and S2/C2/T2 drivers.
bool driverNeedsPolling(MeterDriver driver, DriverName& dn);
vector<DriverInfo>& allRegisteredDrivers();
@ -433,6 +434,7 @@ struct Meter
virtual time_t timestampLastUpdate() = 0;
virtual void setPollInterval(time_t interval) = 0;
virtual time_t pollInterval() = 0;
virtual bool needsPolling() = 0;
virtual void setNumericValue(FieldInfo *fi, Unit u, double v) = 0;
virtual double getNumericValue(FieldInfo *fi, Unit u) = 0;

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -81,18 +81,21 @@ void setIgnoreDuplicateTelegrams(bool idt);
#define LIST_OF_LINK_MODES \
X(Any,any,--anylinkmode,0xffff) \
X(C1,c1,--c1,0x1) \
X(S1,s1,--s1,0x2) \
X(S1m,s1m,--s1m,0x4) \
X(T1,t1,--t1,0x8) \
X(N1a,n1a,--n1a,0x10) \
X(N1b,n1b,--n1b,0x20) \
X(N1c,n1c,--n1c,0x40) \
X(N1d,n1d,--n1d,0x80) \
X(N1e,n1e,--n1e,0x100) \
X(N1f,n1f,--n1f,0x200) \
X(MBUS,mbus,--mbus,0x400) \
X(LORA,lora,--lora,0x800) \
X(MBUS,mbus,--mbus,0x1) \
X(C1,c1,--c1,0x2) \
X(S1,s1,--s1,0x4) \
X(S1m,s1m,--s1m,0x8) \
X(T1,t1,--t1,0x10) \
X(C2,c2,--c2,0x20) \
X(S2,s2,--s2,0x40) \
X(T2,t2,--t2,0x80) \
X(N1a,n1a,--n1a,0x100) \
X(N1b,n1b,--n1b,0x200) \
X(N1c,n1c,--n1c,0x400) \
X(N1d,n1d,--n1d,0x800) \
X(N1e,n1e,--n1e,0x1000) \
X(N1f,n1f,--n1f,0x2000) \
X(LORA,lora,--lora,0x400) \
X(UNKNOWN,unknown,----,0x0)
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\--pollinterval=\fR<interval> poll mbus meters every <interval>, default is 10m.
\fB\--ppjson\fR pretty print the json output
\fB\--resetafter=\fR<time> reset the wmbus dongle regularly, default is 23h