259 lines
12 KiB
Python
259 lines
12 KiB
Python
|
|
#
|
|
# A Digitrax BXP88 Short-Circuit-to-Sensor "follower"
|
|
#
|
|
# This script provides a set of JMRI sensors where each sensor's state "follows"
|
|
# one of the Digitrax BXP88 device's detection sections reported "Short Circuit state",
|
|
# as reported by LocoNet messaging.
|
|
#
|
|
# This script can be configured to monitor one BXP88 device or all devices. Within
|
|
# any BXP88 device, this script separately monitors all 8 of the device's detection
|
|
# sections. Each separate BXP88 detection section is monitored via a separate JMRI
|
|
# "internal" sensor.
|
|
#
|
|
# Sensor naming is of the form "ISPM88ShortX-Y". This is interpreted as:
|
|
# "I" for JMRI's "Internal" object grouping
|
|
# "S" for "Sensor" (in the "Internal" object grouping)
|
|
# "PM" for "Power Management" effects
|
|
# "88" for a source from a "BXP88" device
|
|
# "Short" to denote the sensor as reporting "Short-circuit detection" state
|
|
# "X" represents the BoardID number reported in the LocoNet message from the BXP88
|
|
# device
|
|
# "-" is a character to separate the device IDfrom the "Detection Section" number
|
|
# "Y" represents the "Detection Section" number
|
|
#
|
|
# Some Examples"
|
|
# ISPM88Short1-1 the JMRI internal sensor for BXP88 (board ID 1) Detection Section 1
|
|
# ISPM88Short1-2 the JMRI internal sensor for BXP88 (board ID 1) Detection Section 2
|
|
# ISPM88Short1-3 the JMRI internal sensor for BXP88 (board ID 1) Detection Section 3
|
|
# ...
|
|
# ISPM88Short1-8 the JMRI internal sensor for BXP88 (board ID 1) Detection Section 8
|
|
#
|
|
# ISPM88Short2-1 the JMRI internal sensor for BXP88 (board ID 2) Detection Section 1
|
|
# ISPM88Short2-2 the JMRI internal sensor for BXP88 (board ID 2) Detection Section 2
|
|
# ISPM88Short2-3 the JMRI internal sensor for BXP88 (board ID 2) Detection Section 3
|
|
# ...
|
|
# ISPM88Short2-8 the JMRI internal sensor for BXP88 (board ID 2) Detection Section 8
|
|
# ...
|
|
# ISPM88Shout127-1 the JMRI internal sensor for BXP88 (board ID 2) Detection Section 8
|
|
#
|
|
# As written, this script supports either
|
|
# - monitoring a single BXP88 device, specified by BoardId number; _all
|
|
# eight "Detection sections"_, via separate sensors
|
|
# - monitoring of _all_ BXP88 devices and each 8 Detection sensors
|
|
# of each BXP88, via separate sensors (8 sensors per BXP88).
|
|
#
|
|
# Configuring the script
|
|
# ----------------------
|
|
# - See comments below for information on configuring the behavior of this
|
|
# script:
|
|
# -- the "interestingBoardIdNumber" determines what BXP88 device BoardID
|
|
# value to watch for, or, alternately, configures the script to monitor
|
|
# for LocoNet messages from _all_ BXP88 BoardID values, and causes this
|
|
# script to follow each unique BXP88 BoardID number using a unique Sensor.
|
|
# -- DebuggingMessages determines whether debugging messages will be sent to
|
|
# the JMRI "Script Output" window.
|
|
#
|
|
# Script details
|
|
# --------------
|
|
# This script has three main functional parts (in order of appearance).
|
|
#
|
|
# The first part provides some "import" statements and declares some variables
|
|
# that influence script behavior. Users may wish to modify some variable values
|
|
# in this section.
|
|
#
|
|
# The second part is where the bulk of the work is done, because it declares and
|
|
# defines a "Bxp88ShortCircuitStateListener" class which implements a JMRI
|
|
# "LocoNetListener" which has BXP88-specific features. The class's "message()"
|
|
# method is triggered upon JMRI receipt of a LocoNet message. It "parses" the
|
|
# received LocoNet message to determine if it is a valid "Short-circuit" status
|
|
# message from a BXP88 device. If it is, the "BoardID" value is extracted and
|
|
# checked to determine if it is a BXP88 for which the message should be reported
|
|
# via a JMRI Sensor object(s). This determination is made in the
|
|
# isInterestingBoardId()method in Section 2, described below.
|
|
#
|
|
# For a message that is interesting to the script, the BoardId number from the
|
|
# message is used to create eight variables representing the JMRI Sensor name(s)
|
|
# associated with the eight detection sections which report short circuit status. Once
|
|
# created (if necessary), those variables are updated with the current short circuit
|
|
# status from the message.
|
|
#
|
|
# The isInterestingBoardId() method uses the user-customization variables of
|
|
# Section 1, along with the LocoNet BXP88 Short-circuit status message's extracted
|
|
# boardID value, to determine whether or not to update a sensor. It returns True
|
|
# if the message's BoardID value refers to a BXP88 which should be tracked via a
|
|
# JMRI sensor(s), or it returns False to indicate that the message should be ignored.
|
|
#
|
|
# The third part of the script creates an instance of the LocoNet Listener class
|
|
# and "connects" that instance to the LocoNet connection.
|
|
#
|
|
# Notes and Limitations
|
|
# ---------------------
|
|
#
|
|
# Note the following limitations:
|
|
# - So far as the script author knows, there is _no_ way to query the short-circuit
|
|
# state of a BXP88 device. As such, until a BXP88 device's detection section
|
|
# changes its short-circuit state, there is _no_ way to tell what the device's
|
|
# detection section's current state is.
|
|
#
|
|
# - This script creates, if necessary, the Internal Sensor used to "follow" the
|
|
# BXP88 device's detection section's short-circuit state. Before a BXP88 reports
|
|
# its short-circuit state, JMRI will _not_ have a corresponding Sensor object,
|
|
# unless you have opened a JMRI "panel" XML file which was saved when the
|
|
# corresponding sensor was known to JMRI.
|
|
#
|
|
# - If you open a saved JMRI Panel XML file and that file had one or more JMRI
|
|
# Sensor objects created by this script, such as if you "save" a panel XML
|
|
# file, JMRI will create the associated Sensors but will leave those sensors
|
|
# in the "unknown" state. Once a BXP88 sends a "Short-circuit" event
|
|
# LocoNet message, the associated sensor(s) will be updated to "Inactive" or
|
|
# "Active", as appropriate.
|
|
#
|
|
# - This script provides little if any "error-checking" of the configuration
|
|
# variables. Specifying an "out-of-range" connection index will result in
|
|
# an exception reported in the JMRI Console log as well as failure of the
|
|
# script to perform. Specifying a BoardID value of 0 will not result in
|
|
# capture of _any_ BXP88 short-circuit data.
|
|
# Various other configuration boo-boos may result in exceptions in the log
|
|
# and/or failure of this script to perform.
|
|
#
|
|
# Script version 1.0 created 25Nov2024 by Bob M.
|
|
|
|
# Part 1:
|
|
|
|
import jmri
|
|
import java
|
|
|
|
# Initialize the variable "connectionIndex" to specify which of potentially
|
|
# several LocoNet connections this script watches. This is specified by the
|
|
# LocoNet connection's "index":
|
|
# - When you have just a single connection, the only usable index is 1.
|
|
# - When you have more than one LocoNet connection defined, the index is the
|
|
# count, from the left, of the "tabs" for LocoNet connections as seen
|
|
# in the "Connections" page of the JMRI "Preferences".
|
|
connectionIndex = 1 # this is appropriate for a JMRI install with only a single
|
|
# LocoNet connection, or when monitoring the _first_ of
|
|
# available (and active) LocoNet connections.
|
|
|
|
reportAllBxp88s = False # assume that only a specific BXP88 Board ID number
|
|
# will be reported. This value may be overridden below.
|
|
|
|
# Initialize the variable "interestingBoardIdNumber" to reflect the
|
|
# BoardId of the BXP88 you care about. If you want to create a sensor
|
|
# for _each_ BXP88 BoardId that reports autoreversing state, set
|
|
# interestingBoardIdNumber to a negative value. Uncomment (and modify, # as
|
|
# needed) one of the examples shown below.
|
|
#
|
|
# Example: follow only Autoreversing messages from BXP88 BoardID 1
|
|
#interestingBoardIdNumber = 1
|
|
#
|
|
# Example: follow only Autoreversing messages from BXP88 BoardID 12
|
|
interestingBoardIdNumber = 12
|
|
|
|
# Example: follow every BXP88 Short-Circuit message, regardless of BoardID, by
|
|
# overriding the previous value of reportAllBxp88s. Note that the value of the
|
|
# interestingBoardIdNumber variable has no effect which reportAllBxp88s is True.:
|
|
reportAllBxp88s = True
|
|
|
|
# Print debugging messages to the "script output" window?
|
|
# - True enables the debugging messages.
|
|
# - False disables the debugging messages.
|
|
DebuggingMessages = True
|
|
|
|
# Part 2:
|
|
|
|
# Define a LocoNet "BXP88 Short-Circuit Event" listener class
|
|
class Bxp88ShortCircuitStateListener(jmri.jmrix.loconet.LocoNetListener) :
|
|
def isInterestingBoardId(self, boardId) :
|
|
# This method is used to determine whether a particular BXP88's
|
|
# short-circuit messages will be used to update appropriately-named
|
|
# JMRI sensors.
|
|
#
|
|
# Returns True to update the sensor based on the LocoNet message contents.
|
|
# Returns False to ignore the BXP88's LocoNet Message.
|
|
#
|
|
# The user may modify this method to suit his/her personal "selection"
|
|
# criteria.
|
|
|
|
if (reportAllBxp88s == True) :
|
|
return True
|
|
if (boardId == interestingBoardIdNumber) :
|
|
return True
|
|
return False
|
|
|
|
def message(self, msg) :
|
|
# This method (if registered as a LocoNet listener!) parses all incoming
|
|
# LocoNet messages and deals with BXP88 autoreversing messages.
|
|
|
|
# Is this message an autoreversing message from a BPX88 device?
|
|
if ((msg.getNumDataElements() == 6) and (msg.getElement(0) == 0xD0) \
|
|
and ((msg.getElement(1) & 0x7E) == 0x62) and ((msg.getElement(3) & 0xF0) == 0x20) \
|
|
and ((msg.getElement(4) & 0xF0) == 0x20)) :
|
|
|
|
# Yes, the message is for a BXP88 autoreversing message!
|
|
boardId = 1 + (msg.getElement(2) & 0x7F) + ((msg.getElement(1) & 0x1) << 7)
|
|
|
|
# Determine whether to update a sensor for the reported
|
|
# BoardId number seen in this LocoNet message
|
|
if (self.isInterestingBoardId(boardId) == False) :
|
|
# Not interested in this particular board number
|
|
if (DebuggingMessages == True) :
|
|
print ("Ignoring message apparantly from BXP88 with boardID #"),
|
|
print (boardId),
|
|
print (".")
|
|
return
|
|
|
|
for section in range (0,8):
|
|
# Specify the sensor to be updated (create it if it isn't
|
|
# present!)
|
|
s = sensors.provideSensor("ISPM88Short"+str(boardId)+"-"+str(section+1))
|
|
|
|
# Update the sensor based on data from the LocoNet message
|
|
if (section < 4) :
|
|
data = (msg.getElement(4) >> section) & 0x01
|
|
else:
|
|
data = (msg.getElement(3) >> (section - 4) ) & 0x01
|
|
|
|
if (data == 0) :
|
|
# Not Shorted!
|
|
s.state = INACTIVE
|
|
if (DebuggingMessages == True) :
|
|
print ("Sensor"),
|
|
print ( s.getSystemName()),
|
|
print ("is set to Inactive (i.e. 'live' track) for"),
|
|
print ("short-circuit state of section "),
|
|
print (str(section+1)),
|
|
print ("of BXP88 with boardID #"),
|
|
print (boardId),
|
|
print (".")
|
|
|
|
else :
|
|
# Shorted!
|
|
s.state = ACTIVE
|
|
if (DebuggingMessages == True) :
|
|
print ("Sensor"),
|
|
print ( s.getSystemName()),
|
|
print ("is set to Active (i.e. 'shorted' track) for"),
|
|
print ("short-circuit state of section "),
|
|
print (str(section+1)),
|
|
print ("of BXP88 with boardID #"),
|
|
print (boardId),
|
|
print (".")
|
|
|
|
|
|
# Nothing more to do, so ...
|
|
return
|
|
|
|
# Part 3:
|
|
|
|
# Create an instance of the listener class
|
|
ln = Bxp88ShortCircuitStateListener()
|
|
|
|
# Register the Listener
|
|
jmri.InstanceManager.getList(jmri.jmrix.loconet.LocoNetSystemConnectionMemo).get(connectionIndex - 1).getLnTrafficController().addLocoNetListener(0xFF,ln)
|
|
|
|
if (DebuggingMessages == True) :
|
|
print "Registered the BXP88 Short-Circuit Message listener"
|
|
|
|
# end of script
|