JMRI is...


Information on writing scripts to control JMRI in more detail:


JMRI scripts are in Python, a popular general-purpose computer language


JMRI provides powerful tools for working with your layout.

Layout Automation

JMRI can be used to automate parts of your layout, from simply controlling a crossing gate to running trains in the background.

JMRI: Scripting Examples

The JMRI distributions come with a jython directory that contains a few example scripts. This page provides a short description of each, copied from the comment in the scripts themselves.

To run one of these scripts, start DecoderPro or PanelPro (set preferences to "LocoNet Simulator" to run without connecting to a layout), then under the Panels manu, select Run Script. Find and select the desired script file in the "jython" folder of the JMRI program directory and click the Run button.

To browse the most current set of scripts, please see the jython directory on the JMRI web site.

Sample script to show put a button on the screen that will enable or disable local control of AD4 accessory decoders.
This script has been superseded by the "Lock" capability in JMRI 1.9.3 and later. You can directly request that JMRI lock/unlock a Turnout via the Turnout Table, Routes and Logix.

Sample script to add a button to the main JMRI application window that loads a script file

This is an example script to pulse an output based on a Fast Clock.

This is an example script for invoking an AppleScript from JMRI on Mac OS X.

Simulator for Dispatcher AutoActiveTrains. While auto train(s) are "moving", repeatedly activates "next" allocated block, and deactivate "last" occupied Block. Waits for debounce time plus a bit to allow signals, etc. to respond.

This script provides full layout automation, using connectivity info provided by Layout Editor panels.

This script turns off power to the layout automatically after there has been no activity on the layout for a specified amount of time. (Activity is detected by monitoring block occupancy detectors.) It is intended to be run from the Start-up Preferences.

This is an example script for a JMRI "Automat" in Python. It listens to two sensors, running a locomotive back and forth between them by changing its direction when a sensor detects the engine. You need to set the speed of the engine using a throttle.

This is an example script for a JMRI "Automat" in Python. It is based on the AutomatonExample. It listens to two sensors, running a locomotive back and forth between them by changing its direction when a Sensor detects the engine.

This is an example script for a JMRI "Automat" in Python. It is based on the AutomatonExample. It runs a locomotive back and forth using time delays.

Sample script to show how to send and receive CAN Frames.

Sample script to show a set of JButtons that show/hide panel windows when clicked.
When this script is run, it finds all open Panels (either Panel Editor or Layout Editor) and creates a small window with a button for each. The buttons are labeled with the names of the Panels, and it's required that those names be unique.

This script manages an internal Sensor as a debounced version of another Sensor. Both the On and Off delays may be specified.

Python code to start a DecoderPro app, complete with menu bar

Sample script to navigate through the GUI and disable the Ops Mode button on the main DecoderPro window.

Sample script showing how to initialize turnouts based on the state of their input sensors (e.g. feedback)
This is particularly useful for a C/MRI system, where the turnouts need to be set to a particular state quickly.

Sample script to show a JFrame for data entry. The frame contains two JTextFields, and a button which is inactive until data has been entered. Once activated, the button prints a little diagnostic message when clicked. The print statement can be changed to include whatever desired, e.g. throw a turnout, program a CV, etc.
This script creates a panel called "Data entry" with two fields that data is to be entered in. The script waits for something in both fields to be entered and then enables the "Enter values" button. When "Enter values" button is clicked, it causes the data to be displayed on the Java console and the "Data entry" panel to disappear. To see the output on the Java console you need to open the Java console or select "Script Output" from the JMRI "Panels" menu.

Sample script to show a JButton which prints a little message when clicked. The print statement can be changed to include whatever desired, e.g. throw a turnout, program a CV, etc.

Python code to define common JMRI defaults. Assumes JMRI has already been initialized, so this can reference various managers, etc. This is only read once, when the JMRI library first executes a script, so changes will not take effect until after restarting the program.

Python code to start a PanelPro app, complete with menu bar. (probably obsolete at this point, the usual method now is to start DecoderPro or PanelPro and then run Python scripts from within it; left as an example of the approach)

Example of an event listener for a JMRI class, in this case a Turnout.

Sample script to show a JButton which sends a LocoNet message when clicked. In this case, the LocoNet message alternates between "On" and "Off" for a PM4 relay. The particular relay is addressed by the board and zone variables set in the code. Note that the message sent to the PM4 has fixed contents for the other three (of four) channels on the card. Will this cause a problem in normal operation?

This script will send several of the most command LocoNet type messages. These include switch, feedback and sensor type messages. DCC signal packets can also be sent via LocoNet. Messages are configured using radio buttons and combo boxes. Portions of this script are taken from by Bob Jacobsen.

Script to test a locomotive and decoder after installation. It pops a pane for entering the locomotive address, and a "Go" button. Upon clicking the button, it sequences through a series of operations: F0 on, F0 off, F1 on, F1 off.

This is an example script for a JMRI "Siglet" in Python. It listens to a Memory object, and prints the new state to stdout.

This is an example script for putting an "N-way" selector on a Panel. The panel contains N Sensor icons (in this example numbered 101, 102, 103). When one is clicked on the panel, the others Sensors are forced to Inactive and the program sets outputs appropriately (in this case setting Turnouts 101 and 102). For N large, this would be better done with arrays and closures, but for N = 3 a direct approach is better.

Fill a memory with a two-digit number, using 10 Sensors as digit inputs.

This sample Automaton watches a Sensor, and adjusts the momentum of a locomotive using ops-mode programming when the Sensor state changes. The Sensor and decoder address are hardcoded, as this is an example of just the Automaton function. Adding a GUI to configure these would be straight-forward. The values could be passed via the constructor, or the constructor (which can run in any required thread) could invoke a dialog.

Try to send some bytes to a parallel port.

Connect JMRI Turnouts to parallel port logic. Maps internal Turnouts to specific values to be send to the parallel port. Note that JMRI must be set up to have a valid turnout table; if you're not using some other DCC connection, configure JMRI to use LocoNet Simulator.

Sample script to make an announcement when a PM4 section changes state. This assumes that the PM4 sections are doing short protection. If they are doing auto-reversing, you might want to change the announcement message in the script. Also, it assumes that only one PM4 is going to trip at a time.
Note that the previous state (oldStateN variables) is not kept per-board, but just as one single copy. If you want to track changes in multiple boards, this needs to become a more complicated data structure that's e.g. indexed by board.
Also note that if multiple sections change at once and you're using the "speak" command, the announcements may overlap.

Example of an event listener for a PRICOM PocketTester.

Provides an example of listening to the PowerManager, and operating a Sensor to indicate changes. The Sensor address used to indicate the power status is hardcoded as "100". Change this if you want to use some other sensor.

Connect a RailDriver Modern Desktop (USB device) to a throttle.

Script to go through each open Panel, walk down the object hierarchy and search for all ReporterIcon objects. Every ReporterIcon will have its font size and color set as specified at the top of the script. In addition to being a useful tool in itself, this is a good example of stepping through the object structure of a Panel.

Provides an example of listening to a Reporter, and putting the changes to a Memory in a nicer format. The Reporter and Memory names are hardcoded in the example near the bottom. Change those to something that makes sense for your layout. First, define the listener class. This gets messages from the Reporter, uses them to keep track of the decoders in a Block, and writes that list to a Memory for display.

This script runs a loco around the track, controlling the speed according to signals and following the Blocks.

Sample script showing how to loop through the Roster entries. This example just prints the name, but you can extract or use other info too.

RaceTrack using RPS position measurement; loco1 is faster, loco2 is slower. When loco1 comes within dmin=24 inches of loco2, it will: slow to 1/4 of its speed, wait 6 seconds, return to its original speed and check again. This is time-based (checks every 200 msec), rather than measurement based (listeners) for ease of debugging. Changing it over later on will be good.

This is script for samples the LocoNet statistics once per minute and prints them out.

This is an example script for playing a sound in a JMRI script.

Listen to all Sensors, printing a line when they change state.

Listens for specific Sensor (Sensor #4), plays crossing gate sound on train entering Block.

Sample script showing how to set multiple turnouts to specific positions, with a time delay between them, separately from other things that the program is doing. By putting the turnout commands in a separate class, they'll run independently after the "start" operation.

Schedule something to happen when a JMRI application ends.

This is an example script for a JMRI "Siglet" in Python. It listens for changes to two Sensors and a Turnout, and then recalculates a Signal Mast Aspect based on the values.

Play a sound when the F3 key is pressed on the handheld and loco 1001 selected.

Reset a Turnout to Closed every time it's clicked Thrown This might be used so that a Turnout icon on a panel sits in one position, ready to be clicked and fire a Route. The top of the file defines the needed code. There are some lines near the bottom you should edit to adapt it to your particular layout.

Drive a turnout from two C/MRI outputs. Some C/MRI users connect slow-motion switch machines between two C/MRI outputs, and then set the outputs to complementary states (one active, one inactive) to drive the machine in the two directions. This script slaves a 2nd turnout to a first one, so that when the first one is commanded to a particular state, the second one goes to the other state. To use this, edit the script to include your Turnouts at the bottom (see the existing example; you should remove that). Then select this file as a script to be run at startup from the "Advanced Preferences" on the Preferences Start Up pane.

Use a USB device as a throttle


The jython/javaone directory contains scripts that were first created for the JavaOne test layout.