JMRI: WiFi Throttle Communications Protocol

This page describes the protocol provided by the jmri.jmrit.withrottle package for controlling trains, turnouts, and more through JMRI via a TCP/IP socket.

JMRI uses a fairly simple text-based client-server protocol over TCP/IP sockets. Throttles (or other applications) can locate JMRI by sending a multi-cast DNS request, using ZeroConf/Bonjour, for the address "_withrottle._tcp.local". JMRI won't always reply (it depends on your operating system, firewall settings, and network environment), so your application should also allow entering an IP address and port.

When you first open the connection, JMRI responds with a number of lines of text that provide information about the JMRI instance to which you've connected. Your application then sends comands to JMRI. Each of these commands is plain text, with a newline character at the end (0A hex). Likewise, lines sent back from JMRI are newline terminated.

Because the Java code calls the println method, you will actually get two newline characters at the end of each line returned.

String Parsing

JMRI commands and results are very often arrays of values, and sometimes arrays of arrays. The array elements are separated by three-character delimiters. For example, the following roster entry contains two engines, and each engine has three values:

RL2]\[RGS 41}|{41}|{L]\[Test Loco}|{1234}|{L

Here the delimiters are color-coded to make it easier to see the two different delimiters. The ]\[ delimiter is used to divide the different roster entries (there are two), while the }|{ delimiter is used to divide the parts of each roster entry. The details are described in sections below for each command and response.

Initial Connection

When you first open a socket to JMRI, you'll get a response that will look something like the following:

RL1]\[SP 2101}|{2102}|{L

Each line is actually followed by two newline characters. For brevity, the extra blank line is not shown.

Each line contains information for part of JMRI, as described below, so your application can show things like engines, turnouts, etc.

WiThrottle Version

The first string, VN2.0, provides the version number of the WiThrottle protocol. In this case the version number is 2.0.

Roster List

The roster string always begins with RL (Roster List) followed by the number of entries in the roster. Here are three different examples of roster strings that might be returned by JMRI:

RL2]\[RGS 41}|{41}|{L]\[Test Loco}|{1234}|{L
RL3]\[D&RGW 341}|{3}|{S]\[RGS 41}|{41}|{L]\[Test Loco}|{1234}|{L

with zero, two, and three roster entries, repsectively. Each roster entry contains three pieces of information, always in the same order:

Segment Example Description
Name RGS 41 The name to show in your application
Address 41 The DCC address of the locomotive
Length L S or L to indicate if this is a Short or Long DCC address

Track Power

Returns information about the curent state of track power. This can be one of the following:

PPA0 Off
PPA2 Unknown

Turnout List

JMRI returns either zero, one, or two strings for this section. The first string provides the labels for the different turnout states. For example:


This string contains an array with two elements, which provide the labels to use for each turnout state (except for Unknown):

Segment Example Description
Caption Closed The string to show for the state of turnout
Value 2 The corresponding value for the turnout state

There is also a third value, Unknown, represented with the value 1, that is not explicitly given a caption in the reply.

The second string appears when you have turnouts defined in JMRI, and contains an array of turnouts, and will look something like this:

PTL]\[LT12}|{Rico Station N}|{1]\[LT324}|{Rico Station S}|{2

Each turnout contains the following segments:

Segment Example Description
System Name LT12 The internal name used for this turnout
User Name Rico Station N The name entered into JMRI for this turnout
State 1 The current state of the turnout (see above)

Route List

Like for turnouts, JMRI will reply with zero, one or two strings. The first string is likewise a list of labels for the route values. Again, Unknown (1) is not explicitly listed. For example:


The second string contains an array of routes. For example:

PRL]\[IR:AUTO:0001}|{Rico Main}|{
Segment Example Description
System Name IR:AUTO:0001 The internal name used for this route. The name in this example was auto-generated
User Name Rico Main The name entered into JMRI for this turnout

JMRI Web Port

The final string from the initial reply provides the port set for the JMRI web server. For example:


indicates that the web server port is set to 12080.


Once you've established a connection as outlined above, you can start sending commands to JMRI. The first letter of each command is interpreted by the DeviceServer class to determine where to send the rest of the command. Here are the letters currently supported:

'N' Device Name

Sets the name that will appear in the WiThrottle window. In Engine Driver, this is the throttle name that you can set. The syntax is Nname, where name can be any text, except for a newline, as the newline terminates the command. For example:

NJohn's Throttle

Reply: *StopSeconds


The number after '*' indicates how often your throttle will need to send a command or heartbeat (0 means a heartbeat is not required). JMRI will send an EStop to the locomotive if it hasn't received a command or heartbeat within the number of seconds provided.

'*' Heartbeat

There are three versions of this command:

Command Description
* Send heartbeat
*+ Turn heartbeat monitoring on
*- Turn heartbeat monitoring off

The idea of the heartbeat is that JMRI will issue an emergency stop if it has not received any commands from your throttle within the heartbeat period. When you set your throttle name, using the N command, JMRI returns the emergency stop delay, in seconds, but it doesn't turn heartbeat monitoring on until you explicitly tell it to do so. Once you've turned it on, your throttle will need to ensure it sends periodic heartbeat commands (or any other command) to keep your engine(s) alive.

T, S, M - Throttle Controller

The three throttle commands are somewhat similiar. The 'T' and 'S' commands support a primary and secondary throttle, which allows controlling two locomotives independently. The 'M' command is for a "multi" throttle (more details below). All 'T' and 'S', and most 'M' commands are handled by the ThrottleController class.

Unlike the 'T' and 'S' throttles, the 'M' multi throttle can handle more than one locomotive. Engine Driver uses this feature, for example, to make it super easy to create a consist on the fly with any set of engines (without using DCC consisting). You can have one or more multi throttle, and each multi throttle can have more than one locomotive attached to it. The first character after the 'M' is used as a key for the instance of MultiThrottle to use. Engine Driver always uses 'MT' and therefore the key 'T' for it's multi throttle instance. However, you can use other characters for the key.

MultiThrottle Elements

The command string after the first two characters is passed to the MultiThrottle for further processing. As in other cases, the commands are arrays, where the "<;>" string is used as the delimiter. For example:

MT+L341<;>ED&RGW 341

Contains the array elements "+L341" and "ED&RGW 341" (after removing the first two letters of the command).

The first character of the first element describes the MultiThrottle command, and is one of the following:

3rd Char Description
A Action. The following characters provide more details
+ Add a locomotive to the throttle
- Remove a locomotive from the throttle

Each of these operations is described in sections below.

The second element will be passed onto the ThrottleController instance for further processing, and the details are described below in the Throttle Controller section.

'+' -- Add Locomotive
The following command is a request to add a new locomotive to the multi throttle:
MT+S3<;>ED&RGW 341

The first element is "+S3" has the '+' to indicate that this is a request to add a locomotive to the multi throttle. The rest of the string looks like an address, but it's actually a key used to identify the engine within the multi throttle. Engine Driver uses the DCC address as the key.

The reply from this command is quite verbose, and contains details about this locomotive as known by JMRI. If the engine number is in JMRI's roster, it will return information like the following:

MTLL41<;>]\[Headlight]\[Bell]\[Whistle]\[Short Whistle]\[Steam Release]\[FX5 Light]\[FX6 Light]\[Dimmer]\[Mute]\[Water Stop]\[Injectors]\[Brake Squeal]\[Coupler]\[]\[]\[]\[]\[]\[]\[]\[]\[]\[]\[]\[]\[]\[]\[]\[

If, on the other hand, JMRI does not have the engine number in it's roster, it returns information like the following:


the examples above are all replies from the multi throttle.

The reply consists of the following sections:

For all except the function lables, see the appropriate throttle commands, such as 'V' below, for details.

The function labels are an array of strings, with ]\[ used as the array delimiter. So in the example above, F0 is called Headlight, F1 Bell, etc. Note that, unlike with other arrays, the array delimiter appears at the start and end of the array, as well as between elements.

'-' -- Remove Locomotive

The '-' command removes an engine from a multi throttle. Engine Driver, for example, sends the following command when you release a locomotive:


The first element after the '-' character is the key of the locomotive to remove, or '*' to remove all locomotives from the multi throttle instance. The multi throttle instance will loop through all of it's throttle instances and send the 'r' command to each one. The 'r' command is a release command.

'A' -- Locomotive Action

This command passes the second element in the array to either a specific throttle (if you specify a key), or to all of the throttles in the multi-throttle instance if you provide '*' as the key. For example:


The characters after the 'A' in the first elemnet are the key to a locomotive in the multi throttle, or '*' to send the command to all of the locomotives. In the example above, Engine Driver is sending a "qR" command to all of the locomotives in the multi throttle.

Throttle Controller Commands

This section describes throttle commands, which are commands that start with 'T' or 'S', or the second element of 'MT' commands (as described above). After the command prefix, the next letter is one of the following:

All of the examples above use the simpler 'T' command. If you're using the multi throttle, you'll need to send an array with the text after the "T" in the second part of the array. The descriptions below all use examples based on the multi throttle. Here is an example of the difference in the full command format for a multi throttle vs a normal throttle ('T' or 'S'). Here is an example of one command in both formats:


Each of the commands is described in a section below when it takes additional information. Some commands, such as 'X' require no additional information.

'd' Dispatch and 'r' Release

For most DCC systems, these are the same thing; if in doubt, use release. Device server will then send "Not Set" to the mobile device.

'F' Function

Function keys have two states. Either they're pushed down (when you're pushing with your finger), or they're up (when you release them). Therefore, when you send function commands, you'll send a pair--first when the button is pushed down and second when the button is released. Here is an example of a pair of messages (usually with some time in between them):


The first command is when you push F12, and the second is when you release the F12 button. Although this example sends to all of the 'T' throttles, you can send a function to just one by providing the key you used when you added an engine.

Some functions, such as whistle, remain active only while you have the button down, while others, like lights, are toggle. In both cases, your code should send both the push (1) and release (0) and JMRI will map that into the correct DCC command or commands, as appropriate.

'R' Set Direction

Used to change between forward and reverse:

R0 Reverse
R1 Forward. Actually, any value other than 0 after the R is considered forward

'V' Set Speed

Set the speed to a value between 0 and 126. The format looks something like this:


This is the package/jmri/jmrit/withrottle/Protocol help page