Files
JIMRI/jython/LocoTracker.py
T
2026-06-17 14:00:51 +02:00

105 lines
5.6 KiB
Python

# This script uses JMRI reporters to identify locos (fitted with transponding decoders) that occupy blocks on a layout. The
# decoder addresses or user names of locos present are formatted in a memory variable that can be displayed on a control panel.
# Based on a modified version of Bob Jacobsen's 'ReporterFormatter.py' script.
#
# Author: Ian Price
# Version: 1.21 17-Jun-22
# Part of the JMRI distribution
#
# Change history:
# 1.10 Added support for ID Tags with multiple-character connection prefixes.
# Removed checks for LocoNet enter and exits messages.
# 1.20 Used getTagID() method to derive loco decoder addresses.
# Added methods to select whether loco decoder addresses or user names are returned.
# 1.21 Changed import statement for java datetime module to resolve naming issue that arose with recent Java/JMRI releases.
# Corrected typo in name of variable used for target reporter.
# Removed trailing space from loco list stored in memory variable.
# Extended notes explaining how to start a property change listener for each reporter.
#
# The script comprises a class used to add a property change listener to one or more reporters on a layout. When a loco
# moves into or out of a block associated with a reporter, the listener is triggered and the collection of ID Tags
# maintained by the reporter object is used to populate a memory variable with a list of the locos' identities. This list
# can be displayed on a JMRI layout control panel.
#
# Notes:
# The script uses the ID Tag informaton format introduced in JMRI 4.15.3 and cannot be used with earlier releases.
# DCC controllers may need to be power-cycled after loading the script to ensure locos already in blocks are detected.
# Print statements are included in the script to help diagnose its operation. Enable these by uncommenting them.
import jmri
import java
import java.beans
import datetime
class LocoTracker(java.beans.PropertyChangeListener):
def propertyChange(self, event):
if (event.propertyName == "currentReport"):
self.report = event.newValue # Get the reporter event object
if (isinstance(self.report, jmri.Reportable)):
#print datetime.datetime.now().strftime("%H:%M:%S.%f")[:-3] + " " + self.reporterName + " triggered: " + self.report.toReportString()
# Compile a list of loco decoder addresses or user names from the reporter's ID Tag collection
reporterManager = jmri.InstanceManager.getDefault(jmri.ReporterManager)
reporter = reporterManager.getReporter(self.reporterName)
locoAddresses = ""
for idTag in reporter.getCollection().toArray():
locoAddress = None
if (self.returnUserNames):
locoAddress = idTag.getUserName()
if (locoAddress is None):
locoAddress = jmri.IdTag.getTagID(idTag)
locoAddresses += locoAddress + " "
# Update the reporter's associated memory variable with the list of locos
self.memory.setValue(locoAddresses.rstrip())
#if (locoAddresses != ""): print datetime.datetime.now().strftime("%H:%M:%S.%f")[:-3] + " Loco(s) " + locoAddresses + "in " + self.reporterName
return
# start() : Starts the listener and initialises the reporter's associated memory variable to blank.
# Method paramaters:
# reporterName: System name of the reporter
# memoryName: System name of the memory variable associated with the reporter
def start(self, reporterName, memoryName):
self.memory = memories.provideMemory(memoryName)
self.memory.setValue("")
reporters.provideReporter(reporterName).addPropertyChangeListener(self)
self.reporterName = reporterName
self.returnUserNames = False # Loco decoder addresses will be returned by default
return self
# useDecoderAddresses() : Decoder addresses of identified locos will be returned in the memory variable
# If this or the useUserNames() method is not called, loco decoder addresses will be returned by default
def useDecoderAddresses(self):
self.returnUserNames = False
return
# useUserNames() : User names of identified locos will be returned in the memory variable
# If a loco is not assigned a user name, its decoder address will be returned instead
def useUserNames(self):
self.returnUserNames = True
return
# stop() : Stops the listener
def stop(self):
reporters.getReporter(self.reporterName).removePropertyChangeListener(self)
return
# End of class definition
#
#
# Sample code for using the class
# A property change listener needs to be setup for each reporter and its associated memory variable.
# In the example statements below, memory variables IM1, IM2, etc are associated with reporters LR1, LR2, etc.
# Listeners can be setup in one of two ways. Use this syntax to identify locos using their decoder addresses:
#m1 = LocoTracker().start("LR1", "IM1").useDecoderAddresses()
#m2 = LocoTracker().start("LR2", "IM2").useDecoderAddresses()
#m3 = LocoTracker().start("LR3", "IM3").useDecoderAddresses()
#etc
#
# If you've assigned user names to locos in your JMRI ID Tags table, use this syntax to identify locos by their names:
#m4 = LocoTracker().start("LR4", "IM4").useUserNames()
#m5 = LocoTracker().start("LR5", "IM5").useUserNames()
#m6 = LocoTracker().start("LR6", "IM6").useUserNames()
#etc
#
# Note that you must only use one of the above methods for starting each reporter listener.