Welcome on Henk's website

find all about fiNe-scale modelling
in a scale of 1 : 160


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

control interface

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.

Sub board interface

On the subscription side I experimented with Arduino Nano 33 IOT, RP2040 and ESP32 boards and all these are functional with only small differences due to different processors. For testing, boards programmed in micropython look to be more effective, all mentioned processors can be setup with micropython instead of Arduino C++.
The code is based on the Arduino Wifi advanced callback example and needs some further extension in case of loosing Wifi contact. Basically the board first connects to the Wlan network of the RPI, then it connects to the MQTT broker on the RPI and subscribes and publishes messages. The callback routine executes the command to set the signal. The main program sends regular status messages. For the entry signals there is only a single signal to the board, because these will be positioned at least 7 m apart. In order to make the approach universal applicable a layer of indirection would be necessary. But at the moment I can live with a dedicated version per signal, identical except for the messages, easily solvable with preprocessor instructions.

Nano 33 IOT with interface for form signals

Image of a provisional print with Nano 33 IOT with a ULN 2803 interface for controlling formsignals and points. It carries a 5V 7805 power regulator for the servos and is also prepared for control of the tortoise point motors. Power feed is 12V for the tortoise point motors. The 7805 regulator is now equipped with passive cooling, on the first meeting it became very hot on the 4th day and stopped functioning. This probably because the peak current is rather large when a servo doesn't reach its endpoint and the regulator became too hot. Lucky the Arduino survived, it can withstand a high voltage on its Vin input pin. Actually these used cheap SG90 servos are a disaster on various fronts, prefer better ones.

ESP32 with light signal

Image of clamp on box with battery (only connector visible) and ESP D32 board in USB charging mode (red led). This is the early version without feedback

Extension with formsignals

control interface2

A new version of the control interface is now extended with the formsignals for the southern side. Next step will be the testing of the electronic hardware, the steering electronics do work, but this needs tying up with a processor plus programming and testing. All is more of the same, just time and patience. After that there are still 2 formsignals B_T1 + C_T3 left, needing motors plus an interface. But all of the installation works for E_T3 and D_T2 are still on the To_Do list, although the signals already exist.

Version with optical feedback

It is good practice to give an optical feedback to the train crew when waiting for the signal to clear to avoid having to bend over and staring at the signal along the line. Therefore I tested a version with display using a Lilygo TTGO T10 V2.0 board. This is a board from 2020 with an early ESP32 module and TFT display. The advantage is that the display has lower resolution and thus bigger fonts than the T4 models. These can be read by most people, this contrary to the newer displays where you need magnifying glasses to be able to read the small 8 pixel fronts, clearly newer isn't better here.

Display with signal state and clock

Apart from the signal state this also allows to display the fast clock and some other info such as the IP address and functions of the buttons. Maybe the clock font is a bit too large here with respect to the signal status, but fiddling around to create a better GUI is easy.
The latest version has a deep sleep mode for switching off to safe battery power when not in use. Over a 4 day meeting only a single charging action by USB connection was necessary.

Station clock

Offspin of the above is a version for station clocks. This uses a newer board with a larger 2.4" display in the form of a Lilygo TTGO T4 V1.3. These directly connect to JMRI to read the time set with the fastclock. The JMRI fast clock interface itself is a disaster, programmed in Java, but it doesn't observe the display size. On small displays you cannot reach the save/done button and save its settings. Basically the JMRI time can be read with a browser at "HTTP://" where the IP address is of course that from your JMRI server. The output is the fast clock time in JSON format albeit with an offset due to GMT + winter/summer time. The time is synchronised every 30s, a ticker function generates the update of the display every few seconds. These units worked reliable over a 4 day meeting although some error checking needs to be incorporated. One out of 5 items seems to have a small problem and was switching off early on battery use, reason unknown as yet, could be a bad battery or misfunctioning in the measurement circuit, operating over micro USB was satisfactory however

Station clock module

These boards have 3 buttons, the top one is used for ON/OFF function. The second could be used for stopping the clock. The third can be used to switch to analog clock display. The display shows further information such as IP address, battery voltage and fast clock setting in seconds per minute. The next step will be to integrate these into a more permanent 3D printed housing, there are some examples on Thingiverse. An dedicated time control box with large display for the train crew is necessary, for this it is probably easier to use the earlier defined time message and use MQTT protocol.

Below the provisional code as used for the Magdeburg FREMO meeting, a minor error has however crept into the stop function here.

Station clock module

Dedicated box with 3 buttons, painted red. The print is screwed to the front and the battery fits below. There is an opening for the USB connector in one side. These are resin printed, I don't think that it is strong enough, but the FDM printer is still out of order due to a burned out connector.

Apart from fine-tuning the software part one is now completed. Next phase is testing other uses such as relaying messages over WiFi for traffic control between stations, think of announcing train numbers, accepting and signing off trains to replace telephones. That's why the boxes get different colours and where the card interface might come useful.

to be followed-up.

copyright: Henk Oversloot
date: 10 Sep 2023