Traintastic Homie v1 (MQTT, Homie 5.0) Draft

Protocol specifiction

Scope: Defines a Homie 5.0 device topology for model-railway control: vehicles, command stations, turnouts, signals, and feedback sensors.

Base topic: traintastic/5/ QoS: 1 for all $state, property values, and /set commands. Retained: yes, for every attribute and property value topic, so a client always sees last-known state on subscribe.

Out of scope: multiple unit operations, some things which unclear for me

Expected to hear: review and proposals


Design decision: two device tiers

Not every object in this domain has the same relationship to a controller, and the device topology should reflect that rather than flattening everything to “one object, one device.”

Tier 1 — complex, independently-owned entities. A vehicle and a command station are each managed as a single entity with their own identity, lifecycle, and non-trivial internal state (unit + functions for a vehicle; power + programming for a command station). Each gets its own top-level Homie device:

traintastic/5/vehicle-<id>/...
traintastic/5/cs-<id>/...        (the command station itself, id=1)

Tier 2 — simple accessory objects managed collectively by one controller. Turnouts, signals, and feedback sensors are typically all driven or read by a single physical accessory/feedback controller (an accessory decoder bus master, a detector bus interface). Modeling each one as its own top-level Homie device would multiply discovery overhead — $state, LWT, and full device metadata — far out of proportion to how simple each individual object is. Instead, the controller’s domain is represented as one zone device, with each accessory object as a node of that device:

traintastic/5/zone-<id>/turnout-<n>/...
traintastic/5/zone-<id>/signal-<n>/...
traintastic/5/zone-<id>/feedback-<n>/...

This keeps the topology proportional to complexity: a vehicle’s speed/direction/function set genuinely warrants full device status, while a turnout’s single settable value does not.


Vehicle device

Relevant properties: name, address, protocol, speed-step mode, speed, direction, per-function state, active/emergency-stop flag.

traintastic/5/vehicle-<id>/$homie          → 5.0
traintastic/5/vehicle-<id>/$name
traintastic/5/vehicle-<id>/$state          → init | ready | lost
traintastic/5/vehicle-<id>/$nodes          → unit,functions

traintastic/5/vehicle-<id>/unit/$name           → "Unit control"
traintastic/5/vehicle-<id>/unit/$properties     → speed,direction,speed-steps,active

traintastic/5/vehicle-<id>/unit/speed
  $datatype   integer
  $format     0:127          # normalized to a 128-step range regardless of configured speed-step mode
  $settable   true
  $retained   true

traintastic/5/vehicle-<id>/unit/direction
  $datatype   enum
  $format     forward,reverse
  $settable   true
  $retained   true

traintastic/5/vehicle-<id>/unit/speed-steps
  $datatype   enum
  $format     14,28,128
  $settable   false            # read-only mirror; changing this is a decoder config action, not a runtime command

traintastic/5/vehicle-<id>/unit/active
  $datatype   boolean
  $settable   true
  # false→true triggers vehicle-scoped emergency stop

traintastic/5/vehicle-<id>/functions/$name        → "Function outputs"
traintastic/5/vehicle-<id>/functions/$properties  → f-0,f-1,...,f-28   (only the range this vehicle reports)

traintastic/5/vehicle-<id>/functions/f-<n>
  $datatype   boolean
  $settable   true
  $retained   true

Speed, direction, and functions are independently settable properties, deliberately not bundled into one combined value, since the underlying decoder-level protocols on the market vary in whether they bundle these — a Homie device implementing this specification exposes them decomposed regardless of that variation.


Zone device

A zone device represents everything managed by one accessory/feedback controller: turnouts, signals, and feedback sensors, exposed as nodes.

traintastic/5/zone-<id>/$homie          → 5.0
traintastic/5/zone-<id>/$name
traintastic/5/zone-<id>/$state          → init | ready | lost
traintastic/5/zone-<id>/$nodes          → turnout-1,turnout-2,signal-1,feedback-1,feedback-2,...

$state here applies to the whole zone controller: if the physical controller goes offline, every node under this device loses currency together, which is exactly why these objects are grouped under one device rather than given independent device-level state each.

Degenerate case — a zone with a single node. A controller that happens to manage only one turnout, one signal, or one feedback input is not a different device kind — it is the same zone device with $nodes containing exactly one entry (e.g. $nodes → turnout-1). Nothing about the topic shape, $state semantics, or node structure changes; a one-node zone and a fifty-node zone are the same specification applied to different controller sizes. This also means a controller’s node count is free to grow over time (new turnouts added to an existing zone) without any structural change to how the zone device itself is addressed or discovered.

Turnout node — simple (two routes)

traintastic/5/zone-<id>/turnout-<n>/$type         → turnout
traintastic/5/zone-<id>/turnout-<n>/$properties   → position

traintastic/5/zone-<id>/turnout-<n>/position
  $datatype   enum
  $format     straight,thrown
  $settable   true
  $retained   true

Turnout node — three-way

traintastic/5/zone-<id>/turnout-<n>/$type         → turnout-3way
traintastic/5/zone-<id>/turnout-<n>/$properties   → route

traintastic/5/zone-<id>/turnout-<n>/route
  $datatype   enum
  $format     left,straight,right
  $settable   true
  $retained   true

Turnout node — double slip / single slip

traintastic/5/zone-<id>/turnout-<n>/$type         → slip-double   (or slip-single)
traintastic/5/zone-<id>/turnout-<n>/$properties   → route

traintastic/5/zone-<id>/turnout-<n>/route
  $datatype   enum
  $format     through-a,through-b,cross-a,cross-b     # single slip: drop one value
  $settable   true
  $retained   true

State-transition requirement (applies to all turnout node types): a node MUST NOT publish a new retained position/route value until the commanded position is fully set. If the transition is not atomic on the underlying hardware, the property MUST hold its prior retained value for the duration — a subscriber must never observe a value that does not correspond to an actual, settled track position.

Diagnostics (optional): a node MAY expose a read-only sub-outputs property with implementation-specific detail for troubleshooting a route that fails to settle. It carries no normative meaning — position/route alone is authoritative.

Signal node

Signal state is a normalized aspect, not the raw index used by any particular underlying accessory protocol, since aspect indexing is symbol/type-dependent and varies across regional signaling systems.

traintastic/5/zone-<id>/signal-<n>/$type          → signal
traintastic/5/zone-<id>/signal-<n>/$properties    → indication

traintastic/5/zone-<id>/signal-<n>/indication
  $datatype   enum
  $format     stop,proceed,proceed-restricted,expect-stop
  $settable   true
  $retained   true

Feedback node

Represents a single occupancy/detection input.

traintastic/5/zone-<id>/feedback-<n>/$type        → feedback
traintastic/5/zone-<id>/feedback-<n>/$properties  → occupied,vehicle-id

traintastic/5/zone-<id>/feedback-<n>/occupied
  $datatype   boolean
  $settable   false        # sensors are inputs only, never settable
  $retained   true

traintastic/5/zone-<id>/feedback-<n>/vehicle-id
  $datatype   integer
  $settable   false
  $retained   true
  # optional — only present if the underlying detector hardware reports per-input vehicle addresses


Lifecycle mapping ($state + LWT)

Situation Homie mechanism
Device (vehicle, command station, or zone) initializing $state → init while awaiting first confirmed values
First confirmed values available $state → ready; all property values published retained
A property changes Publish only the changed property topic (retained), not a full device re-publish
Zone’s physical controller goes offline Zone $state → lost; this applies to the zone as a whole, not per-node — individual turnout/signal/feedback nodes have no $state of their own
A vehicle or command station goes offline Its own $state → lost, independent of any zone
Loss of currency generally Retained property values are NOT cleared on lost — last-known-state stays visible until the device or zone returns to ready
MQTT client disconnect Standard Homie LWT on traintastic/5/<device-id>/$state → lost, set at connect time

Fast clock

Not addressed by any object type above. If a fast-clock node is wanted at all, it is a distinct device with its own identity (traintastic/5/clock-1/...), not an attribute of a vehicle, command station, or zone.


Programming-track CV read/write

Stateful, transactional, and slow (multiple retries typical) — a poor fit for the retained-property model used elsewhere in this specification. Modeled as a request/response pair on the command station device, using a dedicated non-retained command topic (traintastic/5/cs-1/programming/cv-request/set → result published to a non-retained cv-result topic) rather than forcing it into the property pattern.


Summary table

Object Homie device Node(s) Key properties
Vehicle vehicle-<id> unit, functions speed, direction, speed-steps, active, f-0..f-28
Command station cs-1 power, programming track-power, cv-request/cv-result
Zone (accessory/feedback controller) zone-<id> turnout-, signal-, feedback- —
— Turnout node, simple (within zone) turnout-<n> position
— Turnout node, three-way / slip (within zone) turnout-<n> route
— Signal node (within zone) signal-<n> indication
— Feedback node (within zone) feedback-<n> occupied, vehicle-id

Hi,

I did a quick read of the proposal. I don’t know much about Homie 5.0, but I do know a lot about Traintastic’s internals.

In Traintastic every object has a unique id, it must match regex [a-z][a-z0-9_]*, so to me it make much more sense to use that as device id, without the additional prefixes like cs- etc. What is your opinion?

In Traintastic all objects have properties, so naturally it would make sense to expose (a selection of) those to Homie/MQTT. For the Lua scripting engine this is used too, see e.g. Train object in Lua (some properties leak documentation, but you get the idea I think :slight_smile:)
How does that sound?

What would be typical use cases for Traintastic and Homie 5.0?

Greetings,
Reinder

p.s. was the spec written using AI assistance?

@reinder thanks for quick response.

main thing with mqtt is “device publish properties” so in this case each decoder announce itself in homie tree. so here we have situation when naming defined not by control station, but by device itself. Also if we adding prefixes, we can subscribe for group of topics if we want.

At the moment i’m working on implementation of mqtt homie in my forked repo. It something like similar to vibecoding approach, cause i’m python dev at first, so C++ is hard for me at the moment. But fortunately i’m known with design patterns and more less see, how you design things inside. It is late now BTW, so i’ll back soon with more explanations about your question about topic naming, etc

Kapture 2026-09-13 at 23.50.02

At screencast there is old topic structure, so it will highly depends on how we deal with requested in this topic specification.

Regarding to implementation for example i can design prototype of my loc, turnouts and signals using https://circuitpython.org/ firmware as base to build my own controlled build by traintastic. In theory there will easier to write something like bridge which can imitate hardware for existing protocol such like ESU ECoS family, but i think it will limited for any future development. So there is better to develop mqtt interface with homie as one of different protocols which possible run over mqtt.

Yes but with a lot of iterations. My english is not fine to describe everything in good terms.

If I may add a thought?
I have used jmris Mqtt protocol for a bit, and I kinda like their distinct main hives
Plus configurable root hive where my entry was jmri/testlayout/* ( sub hives for everything jmri knows about )

Transposed to Traintastic:

Eg:
Traintastic/layout1/signals/signal1/ [ signal state ]
Traintastic/layout1/rurnout/turnout2/[ thrown / closed ]
Traintastic/layout1/sensor/sensor3/ [ on/ off )

This would allow for a modular buildout too.
Perhaps generic hive based on your object class?

Think future classes like lights or rfid sensors?

Thought: publish all relevant objects/ids/states so Mqtt is close-coupled to any other source?

Two way working might be hard ( locking of turnouts in active routes vs free to use otherwise) but at least having read access could be desirable. As well as turnouts or lights since you theoretically could see it as another station to control things?

Apologies I have been offline for a bit…
Dccex seems to have burnt out, awaiting new merg kits ( roast my decisions :grinning_face: )

But if homie is easier? Pick the route that suits best

Thanks for your interest for this topic. But in case of discussion you are describing different approach to reach data exchange. In homie specification device is first. Homie describe topics as 3 nested levels /device/node/property where:

device - always is hardware board which operate with connection.

node - such like group of properties and sensors

property - there is no secret here it is spped, light, voltage on rails for example, etc

and what is more important device propagate own structure itself so we need to develop own structure to be sure DIY devices follow our convention. beauty of Homie specification - it is already fine described and used in IoT widely

so first chunk in topics path {device} is a biggest limitation for multiple units operations using homie. if we have 2 units for example with decoder on each one. so they are different devices with their own nested nodes and properties. as result due network and client processing delays we got situation when two motors got command to increase speed win different timing. result: they will shake while speed changing. Another thing in homie specification we can’t publish nodes into one structure from different real devices because it is brutal specification violation. Sure we can add description how devices runned as MU could make negotiations and sunchronize speed but this is require a lot of time it think. So regarding case of MUing your approach looks more attractive, but it would be nice if you provide vision how to operate with vehicles with your variant.

I do not push horses to accept homie as source of truth for mqtt integration cause it have a lot of blocker which could make some things not possible.

so now we have two major choices with different approach:

  • use Homie where device announce itself(source of truth) with predefined structure and control station is consumer of all devices in layout topology and in theory control station can use autodiscovery for devices in this case to know about each device or search them on-demand. in this case we require something like mapping between homie structure and traintastic internal objects.
  • use own specification where source source of truth is command station and each device should be configured regarding station setup.. so in this case mqtt is pure reflection of object inside traintastic server

I’m already have unfinished changes for server and need to complete few things before push to my fork repo. but.. i make codebase where homie is just one protocol of mqtt interface so i think there is possible to realize few protocols in parallel.

Anyway i think our choice is between truth sources at the moment. Yeah, a lot of words :slight_smile:

1 Like

@TamiasSibiricus
Homie looks very interesting ( but a relative small number of Mcu supported by the library is a distraction for me, Esp32 / esp8266 are there but not much else )
I still have a slew of arduino mega with lan around :rofl:

Ingesting input from multiple sources will become an interesting one if ever possible
( and responding appropriately if possible )

Curious to see your implementation and see if I could use it with my existing arduino mega code base with some appropriate hacks

Agree. Mqtt + Homie are very resource expensive for chips with low memory value. But take a look here Loco.Engineering DCC/WCC Train Sound/Multifunction Decoder - WCC and Loco.Engineering Docs This guy from Poland did nice try to make locomotive decoder with geometry which fits into scale model. There is enough resources even to play sound while control app run on circuitpython(tested by me, incredible but it works if app designed to use async) sure i use little bit different chips but my idea wery close to this finding. so this solution allow to make loc as independed wifi client. sure there is cost of this - power consumption starting from 400mA per each decoder + motors and sound chips

My use case is more like driving leds ( signals ) & potentially leds for static lights

Easy secondary: servos for signals and/or turnouts

Work in progress/ stalled rfid since jmri rfid via Mqtt support has somewhat reduced → Mqtt less valuable in that specific scenario
Have solutions but that is for a later discussion :rofl:

Rest of decoders are a smattering of Esu / Hornby hm7000

1 Like

I chose Traintastic (software) and CBUS/VLCB (hardware) for my model railway because the system is simple and serves just one purpose: controlling the layout in a straightforward way, without a lot of complex computer technology.

Maybe it’s down to my day job in IT and infrastructure; right now, I’m undergoing a massive digital detox - both in terms of hardware and software - following the KISS principle.

For me, model railroading is really about crafting with various materials - not so much about complex IT architectures. Computers and software are just tools, like a hammer.

I don’t want to be a killjoy, but looking at these plans I do wonder: is this becoming a “hobby within a hobby”?

What are your thoughts on building such a complicated control system?

Greetings, Tom

Hi @DL7BJ at first we need to define terms “simplicity” and “complexity”. For different people things, which could defined by this term, are different and usually based on personal experience. As i said usually: “there’s no accounting for taste”

As i understand you are not software developer and very familiar with hardware protocols such like CAN, RS485, i2S, i2C, etc. So personally for you they are simple and well known. They allow you to reach result and got satisfaction in your comfortable way. So any different approaches which are not well known for you seems complex. Right?

Good. For me, as software developer, there is comfortable to work with high level protocols such like MQTT and JSON(for example) as data payloads. Sure this approach require more powerful chips and as result of power conssumption, but it is simple for me to write firmwares easily. Also i do not like idea to use rails as data transfer layer and prefer network over radio(wifi). In this case i see your approach as complex way to reach my goals.

So as result we see solution under different angles and want realize our own. Thankfully Traintastic have possibility to connect with different types of interfaces and protocols. So mqtt and Homie is just interface of data exchange, same as CBUS/VLCB but on different level.

Personally i do not understand where you see complexity for yourself. Interface and protocol for your hardware will stay as is cause it already part of traintastic. With any new release you will get same things as was, but with some improvements of course. So you do not loose anything.. In theory, following your logic ideal situation is just remove all interfaces such like DCC-EX, ECoS, etc and just left only one which you find simple. But in design Traintastic built as multiprotocol solution, so i do not see any breaks to introduce another one which allow people such like me got results in comfortable and simple(for us) way.

In my design mqtt is interface homie is protocol work in same principles as BUS/VLCB - interface + protocol. So if you find MQTT complex just do not activate it and do not use it. :slight_smile:

@DL7BJ And regarding KISS pattern. If there is 8 protocols supported already, is it violation to add another one? Especially if software is multiprotocol in design.

Hi,

nope, that’s not what I mean. I was already developing production control software in the early 1990s using C in a client-server environment with SCO, DEC Ultrix, and Novell NetWare (running on ArcNet and Ethernet) though the actual hardware control of the PLCs always relied on RS-485 networks (using Digi hardware). Also I developed since more than 25 years firmware for microcontroller in an agricultur environment.

Ethernet (TCP/IP or UDP) and Wi-Fi are not inherently suited for systems requiring strict real-time timing because they are non-deterministic. Packet collisions, network traffic, operating system schedulers, and (in the case of Wi-Fi) wireless interference cause unpredictable delays (jitter). If you need a real-time timing you should use Industrial Ethernet or if you need a wireless solution you could use 5G, iPCF or Wireless HART.

If you build a system in Europe with WLAN, you always face severe limitations due to channel congestion: while 2.4 GHz offers a maximum of 11 channels, the 5 GHz band quickly bottlenecks as well - making reliable, interference-free operation nearly impossible in densely populated urban areas or large apartment blocks. You could have round-trip times from serveral hundred ms.

Your approach requires complex controllers and a complex network where you cannot guarantee specific timing characteristics for communication. That might work for switching, but not for running trains. DCC signals on the track are continuously repeated; if a data packet is lost, it’s not an issue - it will arrive again within the required timeframe, as a single packet takes about 10 ms.

By “complex,” I am referring to the effort required to manage latency, jitter, protocol overhead, address management and the power needs of Wi-Fi controllers (in N-scale locos?), rather than my own level of knowledge - which is certainly more than adequate, especially given my 35+ years of experience in infrastructure and professional control technology.

I chose CAN-based VLCB/CBUS, DCC and Traintastic for a simple reason: it’s already there, it’s non-complex, and it works deterministically.

I’m sorry to have to disagree, but CAN is not even remotely comparable to MQTT over LAN and WLAN when it comes to control systems. CAN is OSI Layer 2, with MQTT you are using OSI Layer 7 with the complex stack of software. CAN is CSMA/CR, LAN and WLAN is CSMA/CA.

But my question “hobby within a hobby” was actually something else entirely; let me put it this way:

Do you want to build and operate a model railway or an alternative control system that won’t work flawlessly? I don’t want to stop you from trying :wink:

Greetings, Tom

@DL7BJ Ok, i agree that radio have a lot of bad things but there is simple question: do we build space rocket where timing is everything or just try to play for fun where 0.5 sec is not a problem? Sure it does not about signal lost or reconnects cause it is another kind of problem.

For example: Roco release Multimaus a lot of years ago. Personally i do not have any experience with Multimaus and can’t tell how good it works in real life. But, it 99% have same networking problem as you describe cause WiFi. Anyway this product still alive.

BTW, MQTT can partially resolve network gaps using topic retention. Even if disconnect happened there is possible to restore/republish actual values.

I known about OCI layers and as i remember never told that discussed protocols work same or relate to same layer. And yes, mqtt more complex if we take a look from OCI layering angle, but much simpler in development and debug in case of DIY programing.

Yes, i’m working on my own controlled railway models and very close to design decoder, which designed to work over wifi radio and play mixed sounds for locs. And main idea was to introduce native mqtt support in Traintastic server to avoid +1 bridge as point of deny which will translate existing protocols such like ECoS or similar to mqtt topics. if idea will declined i always can build my own lunar module with blackjack and hot girls bridge :slight_smile:

Hi,

and the Z21 App also works with Wi-Fi. But, these are different things! You wrote, you don’t like the DCC signal on tracks and you would design a decoder with WiFi. But the Roco Multimaus and the Z21 App only controls a central station (or Traintastic) which repeats always the DCC command on the track. If you send a stop command to a locomotive in front of a signal, the locomotive will travel roughly 20 cm past the signal, given a 0.5 second delay. Do you know how long the ESP’s poor Wi-Fi stack takes to reconnect? You could find articles about other Wi-Fi controls, like the WLANMaus - it has these problems too with bad Wi-Fi connections and high latency.

Some hints for your tests:

  • You have to implement some security function, what happens, if no control data are received over time.
  • DCC is good enough for 40-60 locos at same time - you should test how many WiFi decoders you could talk to at the same time
  • check how many Wi-Fi sockets a standard $HOME router could handle at same time, normally nothing more as 20-30 connections. For example, in cafeterias within an Alcatel-Lucent Enterprise network, we use special access points capable of handling 150 simultaneous connections (or more), ensuring that all smartphones function without issues during the lunch break.

Nope, a complex protocol could never be simpler as some data on a serial port and nothing else is DCC, CAN and LocoNet. Debugging is no problem with CubeIDE (STM32) or MPLAB (PIC and AVR). Programming is only simpler for you because you use many existing libraries - for networking, MQTT, and so on - isn’t that right?

Don’t get me wrong - your idea isn’t bad, for instance for a garden railway with just a few trains. But for an HO layout with a Wi-Fi decoder in every locomotive? You’re going to run into a lot of communication issues that you don’t even realize exist right now.

“For every complex problem there is an answer that is clear, simple, and wrong” (H.L. Mencken) :wink:

Greetings, Tom

@DL7BJ Thanks for hints.. will include them in my plans.