Home

Awesome

spicierModbus2mqtt

Written and (C) 2018 Max Brueggemann mail@maxbrueggemann.de

Contains code from modbus2mqtt, written and (C) 2015 Oliver Wagner owagner@tellerulam.com

Provided under the terms of the MIT license.

Overview

spicierModbus2mqtt is a Modbus master which continuously polls slaves and publishes values via MQTT.

It is intended as a building block in heterogeneous smart home environments where an MQTT message broker is used as the centralized message bus.

Changelog

Spicier?

Main improvements over modbus2mqtt by Oliver Wagner:

Feel free to contribute!

Installation

run sudo pip3 install modbus2mqtt

Without installation

Requirements:

Installation of requirements:

Usage

If you've installed using pip:

If you haven't installed modbus2mqtt you can run modbus2mqtt.py from the root directory of this repo directly:

For docker support see below.

Configuration file

THE FIRST LINE OF THE CONFIG FILE HAS TO BE:

"type","topic","col2","col3","col4","col5","col6"

The Modbus data which is to be polled is defined in a CSV file. There are two types of rows, each with different columns; a "Poller" object and a "Reference" object. In the "Poller" object we define the type of the modbus data and how the request to the device should look like (which modbus references are to be read, for example: holding registers at references 0 to 10). With the reference object we define (among other things) to which topic the data of a certain data point (registers, coil..) is going to be published. Modbus references are as transmitted on the wire. In the traditional numbering scheme these would have been called offsets. E. g. to read 400020 you would use reference 20. Refer to the example.csv for more details.

Reference objects link to the modbus reference address and define specific details about that register or bit. Pollers and references are used together like this:

poll,kitchen,7,0,5,coil,1.0
ref,light0,0,rw
ref,light1,1,rw
ref,light2,2,rw
ref,light3,3,rw
ref,light4,4,rw

This will poll from Modbus slave id 7, starting at coil offset 0, for 5 coils, 1.0 times a second.

The first coil 0 will then be sent as an MQTT message with topic modbus/kitchen/state/light0.

The second coil 1 will then be sent as an MQTT message with topic modbus/kitchen/state/light1 and so on.

Note that the reference addresses are absolute addresses and are NOT related to the start address of the poller! If you define a reference that is not within the pollers range you will get an error message. So another example:

poll,someTopic,1,2,11,coil,1.0
ref,light9,9,rw

This will poll states of 11 coils from slave device 1 once a second, starting at coil 2. The state of coil 9 will be published to mqtt with the topic modbus/someTopic/state/light0 if column 3 contains an 'r'.

If you publish a value (in case of a coil: True or False) to modbus/someTopic/set/light0 and column 3 contains a 'w', the new state will be written to coil 9 of the slave device.

Some other "interpretations" of register contents are also supported:

poll,garage,1,0,10,holding_register,2
ref,counter1,0,rw,float32BE 
ref,counter2,2,rw,uint16
ref,somestring,3,rw,string6

This will poll 10 consecutive registers from Modbus slave id 1, starting at holding register 0.

The last row now contains the data format. Supported values: float32BE, float32LE, uint32BE, uint32LE, uint16 (default), stringXXX with XXX being the string length in bytes.

Note that a float32BE will of course span over two registers (0 and 1 in the above example) and that you can still define another reference object occupying the same registers. This might come in handy if you want to modify a small part of a string separately.

Topics

Values are published as strings to topic:

"prefix/poller topic/state/reference topic"

A value will only be published if it's raw data has changed, e.g. before any formatting has been applied. The published MQTT messages have the retain flag set.

A special topic "prefix/connected" is maintained. It states whether the module is currently running and connected to the broker (1) and to the Modbus interface (2).

We also maintain a "connected"-Topic for each poller (prefix/poller_topic/connected). This is useful when using Modbus RTU with multiple slave devices because a non-responsive device can be detected.

For diagnostic purposes (mainly for Modbus via serial) the topics prefix/poller_topic/state/diagnostics_errors_percent and prefix/poller_topic/state/diagnostics_errors_total are available. This feature can be enabled by passing the argument "--diagnostics-rate X" with x being the amount of seconds between each recalculation and publishing of the error rate in percent and the amount of errors within the time frame X. Set X to something like 600 to get diagnostic messages every 10 minutes.

Writing to Modbus coils and registers

spiciermodbus2mqtt subscribes to:

"prefix/poller topic/set/reference topic"

If you want to write to a coil:

mosquitto_pub -h <mqtt broker> -t modbus/somePoller/set/someReference -m "True"

to a register:

mosquitto_pub -h <mqtt broker> -t modbus/somePoller/set/someReference -m "12346"

Scripts addToHomeAssistant.py and create-openhab-conf.py

These scripts are not really part of this project, but I decided to include them anyway. They were written because I grew more and more frustrated with the Modbus capabilities of OpenHAB and Home Assistant.

So what exactly do they do? Completely different things actually.

Docker

spicierModbus2mqtt can be run as a docker container, using the included Dockerfile. It allows all usual configuration options, with the expectation that it's configuration is at /app/conf/modbus2mqtt.csv. For example:

docker build -t modbus2mqtt . && docker run -v $(pwd)/example.csv:/app/conf/modbus2mqtt.csv modbus2mqtt --tcp <modbus-tcp-host> --mqtt-host <mqtt-host>