JMRI JSON Protocol
The JMRI JSON Protocol provides access for a number of JMRI-defined entities, and is accessible through multiple methods:
- The JMRI JSON servlet, providing both HTTP and WebSocket access
- The JMRI JSON server, providing a standard network socket for streamed access
- jquery.jmri, A jQuery-based JavaScript library that chooses the best method to communicate with a JMRI server using the JMRI JSON protocol
JMRI JSON Servlet
The JMRI JSON Servlet provides web access to lists and values for numerous JMRI-defined entities, in the modern JSON format. It also provides a WebSocket interface for making changes to the state of those entities, and listening for external changes.
Setting up the JSON Servlet
The JMRI JSON Servlet is a feature that is part of the Web Server. In order to use this service, you'll need to do the following:
- Ensure the web server's port is unique:
-
- Click Edit and then Preferences to open the Preferences dialog
- Click Web Server on the left side
- Ensure the port number is unique (for example 12080). Other ports are used by WiThrottle, JSON Server, etc.
- Click Save
- Click Actions and Start Web Server to ensure the web server is running
- If you want the web server to run each time you start JMRI:
-
- Open the Preferences dialog
- Select Start Up
- Click Add ▾
- Select Perform action...
- Select Start Web Server
- Click OK
Using HTTP JSON
The HTTP feature of the servlet responds to the following URL patterns:
- /json/<listName> -- used with HTTP GET to retrieve a list from JMRI, or with PUT to add an item to a list
- /json/<typeName>/<itemName> -- used with HTTP GET to retrieve a single item from a list, or with POST to update an existing item
There are a number of lists, and not all operations are supported on these lists and/or items within each list. Check the sections below for the operations that are currently supported.
List Names
Currently the servlet supports the following list names used for GET operations to return lists or messages. Singleton types return a message, list types return an array containing all items of requested type.
Name | GET | PUT | POST | Returns: |
---|---|---|---|---|
blocks | * | block array | ||
cars | * | car array | ||
configProfiles | * | configProfile array | ||
consists | * | consist array | ||
engines | * | engine array | ||
hello | * | hello message and power message | ||
layoutBlocks | * | layoutBlock array | ||
lights | * | light array | ||
locations | * | location array | ||
memories | * | memory array | ||
metadata | * | metadata array | ||
networkServices | * | networkService array | ||
node | * | node message | ||
panels | * | panel array | ||
power | * | * | * | power message |
railroad | * | railroad message | ||
reporters | * | reporter array | ||
roster | * | rosterEntry array | ||
rosterGroups | * | rosterGroup array | ||
routes | * | route array | ||
signalHeads | * | signalHead array | ||
signalMasts | * | signalMast array | ||
sensors | * | sensor array | ||
systemConnections | * | systemConnection array | ||
time | * | time message | ||
trains | * | train array | ||
turnouts | * | turnout array |
Note that these names are case sensitive, so you must supply them as shown above. As an example, let's say you issued the following GET command:
myjmri:12080/json/power
The would return JSON that looks something like this:
{"type":"power","data":{"state":2}}
The returned data consists of two parts:
- Type: The type of item returned, which in this case is "power"
- Data: Data that is specific to the type of object returned. For example, in this case the state of track power
Type Names
Here are the different type names supported for the second pattern, along with which HTTP operations are supported:
Name | GET | PUT | POST | DELETE | Module |
---|---|---|---|---|---|
block | * | * | * | PanelPro | |
car | * | OperationsPro | |||
consist | * | * | * | * | DecoderPro |
engine | * | OperationsPro | |||
layoutBlock | * | * | PanelPro | ||
light | * | * | * | PanelPro | |
location | * | OperationsPro | |||
memory | * | * | * | PanelPro | |
metadata | * | DecoderPro | |||
reporter | * | * | * | PanelPro | |
roster | * | DecoderPro | |||
rosterEntry | * | DecoderPro | |||
rosterGroup | * | DecoderPro | |||
route | * | * | PanelPro | ||
sensor | * | * | * | PanelPro | |
signalHead | * | * | PanelPro | ||
signalMast | * | * | PanelPro | ||
train | * | * | OperationsPro | ||
turnout | * | * | * | PanelPro |
Using HTTP JSON POST/PUT/DELETE
You can also insert, update, or delete items in the lists above using the HTTP POST, PUT, and DELETE methods. Not all combinations are supported.
You can use these type names to set values. Continuing with the power example above, you can turn the power on by posting to a URL like this:
myjmri:12080/json/power
With this as the body
{"state":2}
WebSocket
The WebSocket feature of this servlet currently handles JSON strings in four different forms:
- individual item state requests in the form:
{"type":"turnout","data":{"name":"LT14"}}
that are passed to type-specific handlers. These requests will initiate "listeners", which will send updated responses every time the item's state changes.- an item's state can be set by adding a
state node to the data node
in an HTTP POST request:
{"type":"turnout","data":{"name":"LT14","state":4}}
- individual types can be created if the request is an HTTP PUT request. Note that not all types support this.
- an item's state can be set by adding a
state node to the data node
in an HTTP POST request:
- list requests in the form:
{"list":"trains"}
or{"type":"list","list":"trains"}
that return an array of items, or an empty array ([]
). This request initiates a "listener" which will resend the entire list when items are added or removed, as well as set individual listeners for each item (see above). - a heartbeat in the form
*
or{"type":"ping"}
. The*
heartbeat gets no response, while the JSON heartbeat causes a{"type":"pong"}
response. - a signoff in the form:
{"type":"goodbye"}
to which an identical response is sent before the connection gets closed.
The WebSocket feature of the servlet can be seen by
browsing to the /json/ url, where a JSON
console is providing for testing.
Example commands and responses:
command | response | notes |
---|---|---|
{"type":"sensor","data":{"name":"IS2"}} |
{"type":"sensor","data":{"name":"IS2","state":4}} |
request current state of sensor IS2 |
{"type":"sensor","data":{"name":"IS2","state":4}} |
{"type":"sensor","data":{"name":"IS2","state":4}} |
set sensor IS2 to InActive (4) |
{"type":"turnout","data":{"name":"IT99","state":0}} |
{"type":"turnout","data":{"name":"IT99","state":4}} |
sending state=0 is also treated as request for current state |
{"type":"power","data":{}} |
{"type":"power","data":{"state":2}} |
power does not need a name |
{"type":"memory","data":{"name":"IMCURRENTTIME"}} |
{"type":"memory","data":{"name":"IMCURRENTTIME","userName":null,"comment":null,"value":"2:53
PM"}} |
get (fast)clock time, resent each minute |
{"type":"ping"} |
{"type":"pong"} |
ping request and response |
{"list":"panels"} |
[{"type":"panel","data":{"name":"ControlPanel/R&R","URL":"/panel/ControlPanel/R&R?format=xml","userName":"R&R","type":"Control
Panel"}},{"type":"panel","data":{"name":"Layout/Waccamaw%20Coast%20Line","URL":"/panel/Layout/Waccamaw%20Coast%20Line?format=xml","userName":"Waccamaw
Coast Line","type":"Layout"}}] |
request a list of panels, respond with array, example shows two panels |
{"type":"throttle","data":{"throttle":"CSX754","address":754}} |
{"type":"throttle","data":{"address":754,"speed":0.0,"forward":true,
"F0":false,"F1":false,"F2":false,"F3":false,"F4":false,"F5":false,"F6":false,"F7":false,
"F8":false,"F9":false,"F10":false,"F11":false,"F12":false,"F13":false,"F14":false,
"F15":false,"F16":false,"F17":false,"F18":false,"F19":false,"F20":false,"F21":false,
"F22":false,"F23":false,"F24":false,"F25":false,"F26":false,"F27":false,"F28":false,
"throttle":"CSX754"}} |
request throttle for address 754, refer to it as "CSX754" |
{"type":"throttle","data":{"throttle":"CSX754","speed":0.25}} |
{"type":"throttle","data":{"speed":0.25,"throttle":"CSX754"}} |
request speed of throttle "CSX754" to 25% |
{"type":"throttle","data":{"throttle":"CSX754","release":null}} |
{"type":"throttle","data":{"release":null,"throttle":"CSX754"}} |
release the throttle "CSX754" |
{"list":"trains"} |
If list is empty:[] |
Example showing list response if there are no objects of that type. |
{"type":"block","data":{"name":"IB1"}} |
{"type":"block","data":{"name":"IB1","userName":"AUTOBLK:1","comment":null,"value":"ns2608"}} |
request current value for block IB1 |
JMRI JSON Server
The JMRI JSON server is functionally identical to the JSON WebSocket, but running over a standard network socket.
jquery.jmri
jquery.jmri is a JavaScript library that ships
with JMRI and makes the JSON protocol support just work on
most current browsers.
Note: The support for non-WebSocket browsers is limited by the number
of open connections allowed. Maybe 5-10 active objects.
Examples of use of the jquery.jmri JavaScript library that ships with JMRI include (example links assume you are reading this on your JMRI web server):
- Operations Conductor (implemented in /js/operations.js
- Panel (implemented in /js/panel.js
- JSON Console (implemented in /js/json-console.js
- Power Demonstration (view the page source for the implementation)