Wireless layout control with MQTT
After making a set of signal modules with shafts for light signals I needed a method to control these signals. Pulling cables and making switchboards was not attractive. Earlier experiments from 2013 with RF868 showed that this was a feasible approach, but anno 2023 the available hardware/software is much further developed and the boards from 2013 have long disappeared from market. Thus a new approach was taken using a Raspberry Pi as master and a selection of Arduino IOT boards as slaves with MQTT messaging as control method.
first order approach with 2 very short signal modules
Set-up of infrastructure
The Raspberry PI (RPI) is a small single board computer capable of complex tasks using Wifi, ethernet etc. Programmable in Python and other higher languages. MQTT is a lightweight protocol for messaging and for instance used in home control appliances. The RPI is set-up as wifi access point, runs the MQTT broker (Mosquitto) that functions as host server. It also runs JMRI as server for the WiFred cab controllers, connecting these via an USB loconet buffer to a DCC command station. The RPI is equiped with a small TFT touchscreen display as input device.
In principle JMRI is prepared for MQTT communication, but the set-up of the messaging command structure seems organically grown and looks a disaster from the point of control aspect to me. Signals can only be set indirectly by setting points and programming routes and don't have any feedback. Of course there is a way around this in JMRI by treating them as simple lights but a direct approach in python is much faster. Controlling my points other than by its current set of toggle switches requires further interfacing which takes far more time than available now. The JMRI manual states that it is possible to rewrite the MQTT interfaces in java, this might be an approach for the long run, but requires an in depth study in the workings of JMRI.
Full NMBS light signals can show 6 aspects (not counting the dark non lighted situation). The earlier experiments used a rotary solution to choose the aspects, but a point and click approach using the touchscreen avoids mechanical work and selecting cables and connectors etc. The light signals are from Mafen and are effectively nothing more than a stick with a set of leds with resistors and a common supply. Modern electronics have 3.3V supply and can of course directly control leds, only requiring smaller resistors on the Mafen signal. An Arduino 33 IOT was selected as controller, not the best choice as these don't come with battery charge unit, but they can be run from a USB power pack and thus function as stand alone device. Later it was decided that some form of optical feedback was helpful. For this option the boards were changed to Lolin TTGO T10 V2, based on ESP. These boards come with a small display which allows the loco crew to see the signal state in text form without bending over the layout, also time can be displayed. These boards also have a battery charger and micro USB input.
A bit of warning is that to get all of this working takes lots of effort. This is particularly caused by all rubbish on internet, consider anything on configuration of RPI older than 1.5 year as outdated, this also holds for the official site. Many pages of documentation on Python/Arduino libraries need to be consulted and much of it turns out to be badly documented, unclear or ambiguous and even examples often turn out not to work. But keep on and in the end you slowly get some grip on the matter and can fiddle around with some working items. Thus in terms of time it is not a cheap solution, but at least doesn't use outdated commercial protocols or no longer available boards thus probably can stand time at least 3 years before coming fully obsolete.
MQTT structure
The MQTT command structure can be straigthforward. Layouts can have lots of different devices, but these are mainly more of the same. You want to set things to a certain state, you require status feedbacks for control decisions and may be gather spurious info like time or alarms. Most items can be controlled by giving them an item address and send an ON/OFF command. For instance the case of my the light signals can be done with 5 individual ON/OFF commands, one for each led, but it seems more logical and certainly easier to interpret, to define all aspects and then send this as a state value. This same structure can be used for a servo controlled item which needs a value between 0 and 180. A turntable can be done with a selection of track name. A stepping motor with a signed value for steps in positive or negative direction.
Thus in my view at least 99% of devices can be covered with MQTT messages with topics in the form of:
- Module#/SET
- Module#/GET
- Module#/STATUS
- Module#/TIME
- Module#/ALARM
The Module# helps to discriminate between different parts of a larger layout, as it will be possible to receive (subscribe) only those messages that will be of interest for a particular control section. The alarm message is used to signal problems from a local board to the server, for instance due to an empty battery or Wifi connection problems (willTopic).
I currently don't have any use for the time message, but it looked useful for station clocks on models. Although it can be easily argued that a SET message with a number between 0 and 43200s / 86400s or UNIX coded timenumber can effectively do the same thing. The JMRI fast clock can be directly read over Wifi and thus doesn't need an MQTT alternative here. The advantage of that direct approach is that it also allows to send a message to stop the clock or alter its rate.
The GET message induces a STATUS report from an item and the SET is simply a steering message to an item, but completed with a STATUS feedback report makes it into a control command. Effectively all items can originate status reports either as feedback or as report on a detected change like track occupancy, wheel counters, RFID and any further spurious item that you can think of.
The messages are completed with a payload, the useful content comes in the form of an item address and a state. These can be anything, but for human interpretation it is easier to use understandable information in the form of strings and only use numbers where it concerns positions like degrees and similar.
Thus for payload the choice was made for a JSON structure:
- {"ItemNr":"SigJ742","State":"SLOW"}
This in the form of a JSON coded item for an entry signal J at km post 74.2 with an aspect for low speed calling into a station. Of course any indication either understandable or cryptic code can be used. Libraries for JSON are available and with these it is easy to unravel such a message for control action.
In order to keep closer to the JMRI structure to be able to produce an overlay later I made a diversion between points and signals as the points are likely to be controlled later by a dedicated board allowing discrimination in the MQTT subscriptions, thus for testing I actually programmed messages with payload as:
- Waimes/SET/Signal {"SigNr":"Zuid","State":"STOP"}
for points this could lead to:
- Waimes/SET/Point {"PntNr":"10","State":"OFF"}
A warning is that all this MQTT message stuff is case sensitive thus /SET/ is not equal to /set/ or /Set/ thus a sloppy approach leads to non-working attempts.
Python control interface for light signals
The control interface for the entry light signals was written in Python using Tkinter. This led to the above screen dump. Pressing one button of the row of radio buttons beneath the icon directly runs a lamdba command routine. This routine replaces the icon with a different png and sends off an MQTT /SET/ message with the required signal state. A Callback routine handles a /STATUS/ feedback message. The state is checked against the required state. Currently a screen message is dumped when a difference is detected but an audible warning signal with a buzzer will be more useful.