# wmbusmeters
The program acquires utility meter readings from wired m-bus or
wireless wm-bus meters. The readings can then be published using
MQTT, curled to a REST api, inserted into a database or stored in a
log file.
# What does it do?
Wmbusmeters converts incoming telegrams from (w)mbus/OMS compatible meters like:
`1844AE4C4455223368077A55000000_041389E20100023B0000`
into human readable:
`MyTapWater 33225544 123.529 m³ 0 m³/h 2024-03-03 19:36:22`
or into csv:
`MyTapWater;33225544;123.529;0;2024-03-03 19:36:45`
or into json:
{
"_":"telegram",
"media":"water",
"meter":"iperl",
"name":"MyTapWater",
"id":"33225544",
"max_flow_m3h":0,
"total_m3":123.529,
"timestamp":"2024-03-03T18:37:00Z"
}
Wmbusmeters can collect telegrams from radio using hardware dongles or
rtl-sdr software radio dongles, or from m-bus meters using serial
ports, or from files/pipes.
Wmbusmeters uses drivers to translate the measurement values from a
meter to understandable key-value pairs.
You can automatically decode a 32 bit signed binary word
representing a volume in m3 stored in storage slot 1 but what does this
measurement mean? Is it last months final measurement that will be
used for water billing? Is it the amount of gas delivered last year?
The [drivers](https://github.com/wmbusmeters/wmbusmeters/tree/master/drivers/src)
adds this knowledge, here is an example:
field {
name = target
info = 'Water consumption at the end of last month.'
quantity = Volume
match {
measurement_type = Instantaneous
vif_range = Volume
storage_nr = 20
}
}
All native drivers are going to be rewritten in this form.
If you want to create a new driver, write it directly in xmq form.
I am not accepting new drivers as C++ code.
[FAQ/WIKI/MANUAL pages](https://wmbusmeters.github.io/wmbusmeters-wiki/)
The program runs on GNU/Linux, MacOSX, FreeBSD, and Raspberry Pi.
| System | Status |
| ------------ |:-------------:|
| Ubuntu | [](https://github.com/wmbusmeters/wmbusmeters/actions)|
| MacOSX | [](https://github.com/wmbusmeters/wmbusmeters/actions)|
| Docker | [](https://hub.docker.com/r/wmbusmeters/wmbusmeters/)|
| Snap | [](https://snapcraft.io/wmbusmeters)|
# Distributions
**wmbusmeters** package is available on [Fedora](https://src.fedoraproject.org/rpms/wmbusmeters) _(version 31 or newer)_ and can be simply installed by using:
dnf install wmbusmeters
**wmbusmeters** for [Debian](https://tracker.debian.org/pkg/wmbusmeters) is currently available through Experimental repositories. Availability for other Linux distributions can be checked on [release-monitoring](https://release-monitoring.org/project/88654/) project page.
# Docker
Experimental docker containers are available here: https://hub.docker.com/r/wmbusmeters/wmbusmeters
# Snap
Experimental snaps are available here: https://snapcraft.io/wmbusmeters
Read the wiki for more info on how to use the snap: https://wmbusmeters.github.io/wmbusmeters-wiki/SNAP.html
# Build from source and run as a daemon
Building and installing from source is easy and recommended since the
development progresses quickly. First remove the wmbus dongle
(im871a,iu891a,amb8465(metis),amb3665,cul,rc1180) or the generic rtlsdr dongle (RTL2832U)
from your computer. Then do:
`./configure; make; sudo make install` will install wmbusmeters as a daemon.
# Usage
Check the contents of your `/etc/wmbusmeters.conf` file, assuming it
has `device=auto:t1` and you are using a im871a,iu891a,amb8465(metis),amb3665,rc1180,cul or rtlsdr device,
then you can now start the daemon with `sudo systemctl start wmbusmeters`
or you can try it from the command line `wmbusmeters auto:t1`
Wmbusmeters will scan for wmbus devices every few seconds and detect whenever
a device is plugged in or removed. However since wmbusmeters now supports
several dongle types, the scan can take some time!
Use `auto` for testing and to find your dongle. For production it is very much
recommended that you change `auto:t1` to the device name with the full device path
(eg `/dev/ttyAMA0:iu891a:c1,t1`). This will skip the slow probing for all possible
wmbus dongles when wmbusmeters startup.
If the serial device (ttyUSB0) might change you can also use `device=iu891a:c1,t1`
which will probe all serial devices but only scans for im891a which also speeds it up.
Note that the rtl-sdr devices are not found under the tty devices (e.g. `/dev/tty...`).
Instead the rtl-sdr devices are accessed through character device special files named `/dev/swradio0` to `/dev/swradio255`[^kernel_docs_sdr]. Wmbusmeters uses librtsldr to probe these devices.
If you have to scan serial devices, then remember that some Raspberry PIs are upset when
random data is sent to `/dev/ttyAMA0` when it is configured in bluetooth mode.
To solve this, add `donotprobe=/dev/ttyAMA0`
To have the wmbusmeters daemon start automatically when the computer boots do:
`sudo systemctl enable wmbusmeters`
You can trigger a reload of the config files with `sudo killall -HUP wmbusmetersd`
(Note! make install only works for GNU/Linux. For MacOSX try to start
`wmbusmetersd /tmp/thepidfile` from a script instead.)
You can also start the daemon with another set of config files:
`wmbusmetersd --useconfig=/home/me/.config/wmbusmeters /tmp/thepidfile`
When using useconfig, the files/dir should be:
`/home/me/.config/wmbusmeters/wmbusmeters.conf` and the meters dir:
`/home/me/.config/wmbusmeters/wmbusmeters.d`
Check the config file /etc/wmbusmeters.conf and edit the device. For example:
`/dev/ttyUSB1:amb8465:c1,t1` or `iu891a:c1,t1` or `iu891a[457200101056]:t1`.
Adding a device like auto or iu891a will trigger an automatic probe of all serial ttys
to auto find or to find on which tty the iu891a resides.
If you specify a full device path like `/dev/ttyUSB0:iu891a:c1` or `rtlwmbus` or `rtl433`
then it will not probe the serial devices. If you must be really sure that it will not probe something
you can add `donotprobe=/dev/ttyUSB0` or `donotprobe=all`.
You can specify combinations like: `device=rc1180:t1` `device=auto:c1`
to set the rc1180 dongle to t1 but any other auto-detected dongle to c1.
Some dongles have identifiers (im871a,iu891a,amb8465(metis),amb3665 and rtlsdrs) (for example: rtlsdr can be set with `rtl_eeprom -s myname`)
You might have two rtlsdr dongles, one attached to an antenna tuned to 433MHz and the other
attached to an antenna tuned for 868.95MHz, then a more complicated setup could look like this:
device=rtlwmbus[555555]:433M
device=rtlwmbus[112233]
device=/dev/ttyUSB0:iu891a[00102759]:c1,t1
device=/dev/ttyUSB1:rc1180:t1
# Bus aliases and polling
To poll an C2/T2/S2 wireless meter or an wired m-bus meter you need to give the (w)mbus device a bus-alias, for example
here we pick the bus alias MAIN for the mbus using 2400 bps for all meters on this bus.
MAIN=/dev/ttyUSB0:mbus:2400
and here we pick the bus alias RADIOMAIN for an iu891a dongle:
RADIOMAIN=/dev/ttyUSB1:iu891a:c2
The bus alias is then used in the meter driver specification to specify which
bus the mbus poll request should be sent to.
wmbusmeters --pollinterval=60s MAIN=/dev/ttyUSB0:mbus:2400 MyTempMeter piigth:MAIN:mbus 12001932 NOKEY
If you want to poll an mbus meter using the primary address, use p0 to p250 (deciman numbers)
instead of the full 8 digit secondary address.
wmbusmeters --pollinterval=60s MAIN=/dev/ttyUSB0:mbus:2400 MyTempMeter piigth:MAIN:mbus p0 NOKEY
# Example wmbusmeter.conf file
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:iu891a:c1,t1
# And mbus
device=MAIN=/dev/ttyUSB1:mbus:2400
# But do not probe this serial tty.
donotprobe=/dev/ttyACM2
logtelegrams=false
format=json
meterfiles=/var/lib/wmbusmeters/meter_readings
meterfilesaction=overwrite
meterfilesnaming=name
meterfilestimestamp=day
logfile=/var/log/wmbusmeters/wmbusmeters.log
shell=/usr/bin/mosquitto_pub -h localhost -t wmbusmeters/$METER_ID -m "$METER_JSON"
alarmshell=/usr/bin/mosquitto_pub -h localhost -t wmbusmeters_alarm -m "$ALARM_TYPE $ALARM_MESSAGE"
alarmtimeout=1h
alarmexpectedactivity=mon-sun(00-23)
ignoreduplicates=true
Then add a meter file in /etc/wmbusmeters.d/MyTapWater
name=MyTapWater
id=12345678
key=00112233445566778899AABBCCDDEEFF
driver=multical21
And an mbus meter file in /etc/wmbusmeters.d/MyTempHygro
name=MyTempHygro
id=11223344
driver=piigth:MAIN: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.
You can find out which driver is recommended by running `wmbusmeters iu891a:t1`.
This will print information like:
Received telegram from: 71727374
manufacturer: (BMT) BMETERS, Italy (0x9b4)
type: Heat/Cooling load meter (0x0d) encrypted
ver: 0x0b
driver: hydrocalm3
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.
The auto look up will change to the new driver, but the old driver will still work.
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
exists inside the same directory as the wmbusmeters executable. If not you will see the
error message `(rtlwmbus) error: when starting as daemon, wmbusmeters looked for .../rtl_wmbus and /usr/bin/rtl_wmbus, but found neither!`
and the daemon will refuse to start.)
The latest reading of the meter can also be found here: `/var/lib/wmbusmeters/meter_readings/MyTapWater`
You can use several ids using `id=1111111,2222222,3333333` or you can listen to all
meters of a certain type `id=*` or you can suffix with star `id=8765*` to match
all meters with a given prefix. If you supply at least one positive match rule, then you
can add filter out rules as well. For example `id=*,!2222*`
which will match all meter ids, except those that begin with 2222.
You can also specify the exact manufacturer, version and type: `id=11111111.M=KAM.V=1b.T=16`
or a subset: `id=11111111.T=16` or all telegrams from 22222222 except those with version 77:
`id=22222222,!22222222.V=77` You can also use the fully specified secondary address that is
printed by libmbus after doing a bus scan, ie `100002842941011B` which is equivalent to
`10000284.M=PII.V=01.T=1B`
When matching all meters from the command line you can use `ANYID` instead of `*` to avoid shell quotes.
# Add static and calculated fields to the output
You can add the static json data `"address":"RoadenRd 456","city":"Stockholm"` to every json message with the
wmbusmeters.conf setting:
field_address=RoadenRd 456
field_city=Stockholm
If you add `field_floor=5` to the meter file `MyTapWater`, then you can have the meter tailored static json `"floor":"5"` added to telegrams handled by that particular meter. (The old prefix json_ still works.)
You can add unit conversions and calculated values to the meter files using
`calculate_...`. The formulas track units. If the unit do not match
up, then the formula will generate a null value. When two units are compatible
it will automatically convert the value between two units.
The formula
calculate_sum_mj=5 kwh + 8 gj + (7 kw * 3 h)
will add the field:
"sum_mj":8093.6
Units inside the formula calculation are tracked as arbitrary SI unit
exponents (ie Volt is `1kgm²s⁻³a⁻¹`) however the final result must be
a named unit (ie the calculated field must end with `_v`). The
existing named units can be found with `wmbusmeters --listunits`.
If you make a mistake in the formula you will get a warning:
Warning! Ignoring calculated field sum because parse failed:
Cannot add [kw|Power|1000kgm²s⁻³] to [gj|Energy|1×10⁹kgm²s⁻²]!
5 kw + 8 gj + (7 kw * 3 h)
^~~~~
You need parentheses in the formulas since operator precedence is not yet implemented.
calculate_total_l=total_m3
calculate_approx_power_m3ch=(t1_temperature_c-t2_temperature_c)*volume_flow_m3h
calculate_total_mj=total_energy_consumption_kwh
wmbusmeters --format=json --ppjson
--field_collector=cm57829
--calculate_total_l=total_volume_m3
--calculate_approx_power_m3ch='(t1_temperature_c-t2_temperature_c)*volume_flow_m3h'
--calculate_total_mj=total_energy_consumption_kwh
5e442d2c1155775540047a7d0050252f2f0406c50e000004147B86000004ff074254000004ff086047000002594117025d9a14023Bed0302ff220000026cca2c4406750B00004414ad680000426cc12c2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f
Heato kamheat 55775511 NOKEY
which will output:
{
"media":"heat",
"meter":"kamheat",
"name":"Heato",
"id":"55775511",
"status":"OK",
"total_energy_consumption_kwh":3781,
"total_volume_m3":344.27,
"volume_flow_m3h":1.005,
"t1_temperature_c":59.53,
"t2_temperature_c":52.74,
"forward_energy_m3c":21570,
"return_energy_m3c":18272,
"meter_date":"2022-12-10",
"target_energy_kwh":2933,
"target_volume_m3":267.97,
"target_date":"2022-12-01",
"total_l":344270,
"approx_power_m3ch":6.82395,
"total_mj":13611.6,
"timestamp":"2023-01-14T07:20:22Z",
"collector":"cm57829"
}
If you have connected your Lansen pulse counting meter to an
electricity meter triggering a pulse per 0.1 kwh, then you can
directly calculate a value based on the counters:
wmbusmeters --format=json --ppjson
--calculate_total_kwh='1000 kwh + (a_counter * 0.1 kwh)'
234433300602010014007a8e0400002f2f0efd3a1147000000008e40fd3a341200000000
Electricity lansenpu 00010206 NOKEY
{
"media":"other",
"meter":"lansenpu",
"name":"Electricity",
"id":"00010206",
"status":"POWER_LOW",
"a_counter":4711,
"b_counter":1234,
"total_kwh":1471.1,
"timestamp":"2023-01-14T07:25:34Z"
}
# Miscellaneous
If you are running on a Raspberry PI with flash storage and you relay
the data to another computer using a shell command (`mosquitto_pub` or
`curl` or similar) then you might want to remove `meterfiles` and
`meterfilesaction` to minimize the writes to the local flash file
system.
Also when using the Raspberry PI it can get confused by the serial ports, in particular the bluetooth port might come and
go as a serial tty depending on the config. Therefore it can be advantageous to use the auto device to find the proper tty
(eg /dev/ttyUSB0) and then specify this tty device explicitly in the config file, instead of using auto. This assumes that
you only have a single usb dongle otherwise the USB tty names can change depending on how and when the devices are
unplugged/replugged and the pi restarted. If you have multiple devies with different antennas, then you should instead
use donotprobe to avoid the ttys that can never have a wmbus dongle.
If you specify `--meterfilesaction=append --meterfilestimestamp=day` then wmbusmeters will append all todays received telegrams in for example the file `Water_2019-12-11`, the day after the telegrams will be recorded in `Water_2019-12-12`. You can change the resolution to day,hour,minute and micros. Micros means that every telegram gets their own file.
The purpose of the alarm shell and timeout is to notify you about
problems within wmbusmeters and the wmbus dongles, not the meters
themselves. Thus the timeout is for a dongle to receive some telegram
at all. It does not matter from which meter.
# Run using config files
If you cannot install as a daemon, then you can also start
wmbusmeters in your terminal using the config files in `/etc/wmbusmeters`.
wmbusmeters --useconfig=/etc
Or you can start wmbusmeters with your own config files:
wmbusmeters --useconfig=/home/me/.config/wmbusmeters
If you already have config with a device specified, and you want to use
the config with another device. You might have multiple meters in the config
that you want to listen to. Then you can add `--overridedevice` to override the settings
in the config. Like this:
wmbusmeters --useconfig=/home/me/.config/wmbusmeters --overridedevice=rtlwmbus
You must have both `--useconfig=` and `--overridedevice=` for it to work.
The files/dir should then be located here:
`/home/me/.config/wmbusmeters/wmbusmeters.conf` and
`/home/me/.config/wmbusmeters/wmbusmeters.d`
The option `--useconfig=` can only be combined with a few other options: `--overridedevice= --listento= --exitafter= --oneshot= --silent --normal --verbose --debug --trace`
When running using config files then you can trigger a reload of the config files
using `sudo killall -HUP wmbusmetersd` or `killall -HUP wmbusmeters`
depending on if you are running as a daemon or not.
# Running without config files, good for experimentation and test.
wmbusmeters version: 2.0.0
Usage: wmbusmeters {options} [device] { [meter_name] [meter_driver] [meter_id] [meter_key] }*
wmbusmeters {options} [hex] { [meter_name] [meter_driver] [meter_id] [meter_key] }*
wmbusmetersd {options} [pid_file]
As {options} you can use:
--alarmexpectedactivity=mon-fri(08-17),sat-sun(09-12) Specify when the timeout is tested, default is mon-sun(00-23)
--alarmshell= invokes cmdline when an alarm triggers
--alarmtimeout=