Wireless M-Bus

Receive data from Wireless Meter-Bus (wM-Bus) devices like gas or electricity meters

Current Release
0.13.0
Developer
Christian Landvogt
License
GPL-2.0-only

This adapter allows to receive wireless M-Bus data from supported receivers. The extent of device implementation varies, but wMBus modes can be configured for all listed devices.

  • Embit WMB modules
  • Amber Wireless AMB8465 (Beware: Command mode (UART_CMD_Out_Enable) is enabled!)
  • IMST iM871A
  • IMST iU891A-XL
  • CUL

The WMBUS stack has been "re-ported" from FHEM project and was extensively fixed and refactored. Testing was done with raw data picked up on the internet, OMS sample data and some test data from the jmbus library. Some edge cases are still untested.

The device creation, updating, etc is mostly based of Apollon77's M-Bus adapter (see below).

If the adapter receives encrypted telegrams the AES key configuration tab should list the device ID automatically.

If the parser fails the raw telegram data will be saved to the info.rawdata state.

Attention: The Amber receiver seems to crash after some time (or amount of received messages) in C mode? Hardware flaw?

IMST iM871A variant: There exists a "RWE Smart Home" USB receiver which is in principle a IMST iM871A, but the kernel will not automatically load the corresponding driver. This is a one-liner to create a udev rule to fix that:

sudo bash -c "echo \
    

ACTION==\"add\", ATTRS{idVendor}==\"10c4\", ATTRS{idProduct}==\"87ed\", RUN+=\"/sbin/modprobe cp210x\" RUN+=\"/bin/sh -c \\'echo 10c4 87ed > /sys/bus/usb-serial/drivers/cp210x/new_id\\'\"' > /etc/udev/rules.d/99-imst.rules"

Links:

Initial setup

The initial setup requires to configure the basics (hardware connection to the wmbus receiver) and to setup AES keys for all encrypted wmbus nodes to be collected. The most tricky part are the AES keys.

Basic setup

This requires to select the appropriate USB device and the correct baud rate (usually for IMST iM871A: 57600 baud; IMST iU891A-XL: 115200 baud; Amber: 9600 baud; Embit: 9600 baud, CUL: 38400 or 9600 baud). Most meters will send in "T Mode".

From version 0.9.0 on, the adapter also supports to connect to serial devices reachable via a TCP socket. However, the admin interface does not really reflect that (for now) and you have to select "custom port" and enter the host as tcp://host:port.

Other options

  • Update unchanged states: When a telegram arrives all states will be updated, even if their value did not change. (default: on)
  • Force energy units to kWh: All energy units (Wh and J) will be converted to kWh. (default: off)
  • Temporarily block device after consecutive failures: If 10 consecutive telegrams of the same device are not parsed successfully the device will be ignored until adapter restart (default: on)
  • Only handle devices that already have an object tree: Telegrams of devices that do not have an object tree yet are ignored, so no new devices are created - useful once every meter you care about has been set up. Telegrams that cannot be decoded at all are ignored just as well: they do not add a device to the AES key list and they are not written to info.rawdata. The automatic block list still counts them, so that an unwanted device stops costing a decoding attempt - it just does not say so in the log. The devices are looked up when the adapter starts, so a device you delete from the object tree is gone for good after the next restart, and a device that should be picked up again needs one as well. (default: off)

Compact telegrams (used by some Kamstrup devices) are supported automatically: the structure of a full telegram is remembered - with the device, so that it survives a restart of the adapter - and reused to decode the compact ones. Only the compact telegrams a device sends before it has sent a full one for the first time cannot be decoded and are silently skipped.

AES keys

The device identifier is a combination of the manufacturer code and the device ID (e.g. AAA-12345678). The key can be entered either as a plain-text key with 16 characters or as a hex string with 32 characters (16 bytes).

The easiest way to setup the keys is to start the adapter without any key setup and to wait for an encrypted telegram, after which an entry with "UNKNOWN" key is generated by the adapter. (With "only handle devices that already have an object tree" switched on, no device can be waiting for a key - the button is disabled then and says so.) Then you can fill in the corresponding key and save the settings. If you see devices you don't know or just want to get rid of (e.g. devices from neighbours), you can enter them in the blocked devices tab (see below).

Blocking unwanted devices

The "blocked devices" tab allows you to complete stop the adapter from handling telegrams from unwanted devices.

You only need to enter the device ID (e.g. AAA-12345678), which you can get from the object tree after a telegram has been received and parsed or from the (debug) log.

Afterwards, when you delete the device from the object tree, the adapter will not recreate it again.

Manufacturer specific data

Some meters put values the standard does not describe into a manufacturer specific data record: a blob of a few bytes with several values packed into it. The parser knows a few of them already (an Itron smoke detector, for instance) and writes their values as states of their own. For every other meter the blob is one state holding a large number - and the "Manufacturer specific data" tab is where you describe what is in it.

A description is JSON, one entry per manufacturer code - the three letters of the device address:

{
    "ACM": [
        { "byte": 0, "bit": 0, "description": "Backflow detected" },
        { "byte": 1, "description": "Battery", "unit": "%", "legacyName": "VIF_BATTERY_PERCENT" },
        { "byte": 2, "bytes": 3, "description": "Volume", "unit": "l" },
        { "byte": 5, "flags": ["Leakage", "Burst", null, "Removal"] },
        { "byte": 6, "bits": [0, 1], "description": "Network mode", "values": ["Off", "Walk-by", "Fixed"] }
    ]
}
keywhat it does
bytewhere the value starts in the blob, counted from zero (required)
byteshow many bytes it is (default 1)
bit / bitsa single bit, or an inclusive range like [0, 1], of that byte
descriptionwhat the value is - it becomes the name of the state (required unless flags is given)
flagsone name per bit of the byte, null for a bit to skip - each name becomes a state of its own
valuesnames for the numbers a field can hold, as a list or as an object like { "4": "Water" }
unitthe unit of the state
legacyNamethe VIF_… part of the state id, see below
storageNo, tariffoverride what the record they came from says

The table above is a summary. Every field a description can hold, with what each one does to the value, is documented with the parser itself: wireless-mbus-parser, "Describing a blob instead of decoding it"

  • the same link sits under the editor in the tab. Insert an example puts a description of a meter that does not exist into the editor, with one of every kind of field in it, which is the quickest way to start: replace its XXX with the manufacturer code of your meter.

If a manufacturer uses more than one kind of blob, describe each one as a layout with the device types and the VIF it belongs to - the first one that matches decodes the blob:

{ "ACM": [{ "deviceType": 7, "fields": [ ... ] }, { "deviceType": [4, 12], "fields": [ ... ] }] }

The descriptions are edited in the tab's JSON editor, which highlights them and marks a syntax error while you type. Two buttons belong to it. Check the descriptions hands them to the parser and reports what it makes of them, with the exact complaint for one it rejects ("bit 9 is outside of the field at byte 0"). Decode it with the descriptions takes a telegram as hex - from the debug log, for instance - and lists every state it would write in a table, so a description can be tried before it is saved. Neither button writes anything.

The telegram and the decoded table are part of the instance configuration, so they are still there when you come back to the tab. The adapter never reads them - they are a scratch pad.

Two things are worth knowing:

  • The state id is derived from the description of its field, so "description": "Battery" becomes …-VIF_BATTERY. Fixing a typo in a description therefore renames the state. legacyName sets that part of the id directly and keeps it stable, which is worth doing for every value you intend to keep.
  • A description replaces the one the parser ships for that manufacturer, rather than adding to it. Describing one value of an Itron smoke detector means its other 25 are no longer written.

Updating from 0.11.x

Version 0.12.0 replaces the built-in telegram parser with the wireless-mbus-parser library. Object IDs stay as they are, but four things change:

  • Measured values are numbers now, not preformatted text - "474.240" became 474.24. The states have always been of type mixed, so ioBroker itself does not mind, but a history back end that has stored them as text does: InfluxDB refuses numbers for a field that holds strings, and the SQL adapter keeps one type per datapoint, so those series start over. Look at the log of your history adapter after the update and decide per series whether to drop the old data or to keep it beside the new one.
  • Scripts and visualisations that compare or format that text need a look: state.val === '474.240' no longer matches, and a widget that relied on the fixed number of decimals now shows a plain number.
  • Tariff and device unit were read from the wrong bits and are correct now, so the names of the states of a meter with more than one tariff change. Their IDs do not.
  • Reserved and unknown VIFs can be named differently by the library, so a few states of unusual meters appear under a new ID. The old ones stay behind and can be deleted - everything else is written on as before.

The option "Cache for compact frames support" is gone as well: compact telegrams are always supported now, and the first one of a meter no longer counts towards the automatic block list.

Techem and Diehl (PRIOS) meters

Version 0.12.0 got these two wrong: a Techem heat cost allocator reported nonsense under names like VIF_RETURN_TEMP, a Techem heat meter could not be read at all and ended up on the automatic block list, and a PRIOS water meter reported its volume as a heat cost unit. 0.12.1 reads them correctly again - the states 0.12.0 created for them stay behind and can be deleted, the right ones are written with the next telegram.

Two of their states are named differently than in 0.11.x, because the values of the previous period now carry the storage number they belong to (1-1-… rather than 1-0-…), and the remaining battery life of a PRIOS meter is reported in months rather than in years.

ToDo

  • sending telegrams for S mode receivers?
  • handling meters with "multiple telegrams"

Changelog

0.13.0 (2026-09-09)

  • (ChL) Describe the manufacturer specific data records of a meter in the admin UI, the result become states of their own
  • (ChL) Update wireless-mbus-parser to 1.5.0: support for decoding manufacturer specific blobs - description for Itron smoke detector included.

0.12.3 (2026-09-07)

  • (ChL) Fix the CUL initialisation on the receivers that lose the first byte written after the line has been idle: every command is now sent with a separator in front of it, which is what gets lost instead of the command letter, and setting the mode waits for its confirmation rather than failing on a line that crossed it (#312)

0.12.2 (2026-09-05)

  • (ChL) Add an option to only handle devices that already have an object tree, so that no new devices are created and no telegram of a device without one is reported
  • (ChL) Remember the record layout of a device, so that its compact telegrams are decoded right after a restart of the adapter
  • (ChL) Update wireless-mbus-parser to 1.3.1, which fixes the date of the current reading of a Techem meter - it used to be stamped with the year it was decoded in rather than with the year of the meter
  • (ChL) Report at the log level the message deserves: a receiver that stays away no longer writes an error with every attempt, what the hardware says about itself is a warning, and the noise of the air is debug

0.12.1 (2026-09-05)

  • (ChL) Fix Techem and Diehl (PRIOS) meters, which 0.12.0 decoded wrongly or not at all - the states it wrote for them carry wrong names and values and can be deleted
  • (ChL) Fix the adapter stopping instead of blocking a device whose telegrams keep failing to decode
  • (ChL) A 64 bit measured value with a scaling factor is a number now, like every other measured value

0.12.0 (2026-09-03)

  • (ChL) Replace the built-in telegram parser with the wireless-mbus-parser library
  • (ChL) New admin configuration UI (JSON config); a serial port can now simply be typed in, the separate "custom port" field is gone
  • (ChL) Fix shutdown of the adapter: a serial connection over TCP was not closed properly and could reconnect itself while the adapter was stopping
  • (ChL) Measured values are now stored as numbers instead of preformatted strings - a history adapter that stored them as text starts a new series
  • (ChL) Fix decoding of the tariff and device unit of a data record
  • (ChL) Compact telegrams are now supported without a separate option; the option "Cache for compact frames support" was removed
  • (ChL) Follow further ioBroker repository recommendations: move the test code below test/, use the short admin/i18n/<lang>.json layout and clean up the keywords
  • (ChL) Run the adapter tests only after linting and type checking succeeded
  • (ChL) Use the adapter's own timer functions, so pending timers are cleared when the adapter is unloaded
  • (ChL) Fix receivers getting stuck after disturbed reception: a damaged telegram no longer takes the following ones with it, and no longer leaves the adapter yellow until it is restarted by hand (#308, #309)
  • (ChL) The adapter reconnects to the receiver instead of staying idle or stopping when the connection fails
  • (ChL) Fix telegrams getting lost when several meters transmit at once, and damaged data being reported as readings of devices that do not exist
  • (ChL) Declare the state that holds the raw data of an unreadable telegram as text rather than as a numeric value

License

Copyright (c) 2019 ISFH - Institute for Solar Energy Research www.isfh.de
Copyright (c) 2021 - 2026 Christian Landvogt

Licensed under GPLv2. See LICENSE and NOTICE