Author: Bob Jacobsen

# 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 Scripting {Old: Panels} menu, select Run Script. In DecoderPro, Run Script is in the Actions menu. 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 website.

AD4OnOff.py

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.

AddButton.py

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

AlarmClock.py

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

AppleScript.py

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

AssignIdTagToRollingStock.py

A more advanced example of scripting, this script "listens" for new or changed ID Tag Table entries (RFID Tags) and opens a window to allow the user to enter a user name (typically locomotive or car/wagon number) and comment. It does this by creating a property change listener on the ID Tag Table. It will also update the OperationsPro Locomotive Table or Car Table if requested (check box on the popup window). It will flag locomotive/car numbers that do not exist, as well as move an ID Tag from one loco or car to another and eliminate dupicate assignment of RFID Tag to cars or locomotives.

This script illustrates the use of the JMRI property change listener, writing to the Script Output window, writing information to the System Console, updating the ID Tag Table, updating the OperationsPro Locomotive and Car Tables, and using Java swing to create a popup window with entry fields and radio buttons.

For more information about the use of RFID and the Id Tags Table, see Getting Started with RFID.

AutoActiveTrains_Simulator.py

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.

AutoDispatcher2.py

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

AutoLayoutPowerOff.py

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.

AutomatonExample.py

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.

BackAndForth.py

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.

BackAndForthTimed.py

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.

CanExample.py

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

ControlPanel.py

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.

DebounceSensor.py

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

DecoderPro.py

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

DisableOpsMode.py

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

GrandReset.py

A script to remove All Transits, Sections, SignalMastLogics and remove all saved paths from the Block Table. Requires confirmation when you run it.

InitTurnouts.py

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.

JButtonComplexExample.py

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 PanelPro Scripting {Old: Panels} menu.

JButtonExample.py

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.

jmri_defaults.py

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.

PanelPro.py

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)

ListenerExample.py

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

LnBushbyForwarder.py

Since JMRI 4.25.2Provides a mechanism to forward "normal" LocoNet switch (Turnout) control messages to the DCC track signal when a Digitrax command station's Bushby feature is enabled. (Note that this script can be cause congestion on LocoNet when the Digitrax Bushby feature is in its default (disabled) condition.) See this page for additional information about this script.

LnPowerButton.py

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?

LnSendTool.py

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 LnPowerButton.py by Bob Jacobsen.

LocoTest.py

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.

MemorySiglet.py

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

MemoryValuesPersistence.py

Persist the values of selected memory variables between sessions. Before closing JMRI, this script stores to a .csv file the value of each selected memory variable, and reads back in the last known value after a restart. The script needs to run after the layout xml data file has been loaded. The script has to be copied to the user files location and modified. The `memoryNames` list has the system or user names of the selected memory variables.

NSelectorExample.py

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.

NumberInput.py

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

OpsProgExample.py

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.

ParallelPortTest.py

Try to send some bytes to a parallel port.

ParallelPortTurnouts.py

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.

PM4Announce.py

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.

PocketTesterExample.py

Example of an event listener for a PRICOM PocketTester.

PowerSensor.py

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.

RailDriver.py

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

ReporterFontControl.py

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.

ReporterFormatter.py

Provides an example of listening to a LocoNet Reporter, and putting the changes to a Memory in a nicer format. [As of JMRI Version 5.0, there are a dozen different types of Reporters and this example specifically refers to the types of messages coming from LocoNet transponding.] The Reporter and Memory names are hardcoded in the example near the bottom, but you can easily change these. The example first defines 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.

RobotThrottle.py

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

RosterLoop.py

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.

RpsRaceTrack.py

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.

SampleLnStats.py

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

SampleSound.py

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

SensorLog.py

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

Sensor-sound.py

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

SetTurnouts.py

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.

ShutDownExample.py

Schedule something to happen when a JMRI application ends.

SigletExample.py

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.

ThrottleSound.py

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

TurnoutReset.py

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.

TurnoutStatePersistence.py

Persist the state of turnouts between sessions. Before closing JMRI, this script stores to a .csv file the state of (each) turnout on the layout, and reads back in the last known status after a restart.
Add it to your preferences to load at startup. You may want to edit the script so that only actual turnouts are stored, skipping e.g. turnouts used on signals.

TwoOutputTurnouts.py

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.

USBThrottle.py

Use a USB device as a throttle

javaone

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