304 lines
15 KiB
Plaintext
304 lines
15 KiB
Plaintext
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta name="generator" content="HTML Tidy for HTML5 for Apple macOS version 5.8.0">
|
|
<meta name="keywords" content=
|
|
"save store jython script, jython naming, jython threads, jython automation, jython siglets, jython AbstractAutomaton">
|
|
|
|
<title>JMRI: "What...Where" of Jython Scripting with JMRI</title>
|
|
<!--#include virtual="/help/en/parts/Style.shtml" -->
|
|
</head>
|
|
<body>
|
|
<!--#include virtual="/help/en/parts/Header.shtml" -->
|
|
|
|
<div id="mBody">
|
|
<!--#include virtual="Sidebar.shtml" -->
|
|
|
|
<div id="mainContent">
|
|
<!-- Page Body -->
|
|
|
|
<h1 id="WhatWhereTopOfPage">JMRI: "What...Where" of Jython Scripting with JMRI</h1>
|
|
<!-- Page reorganized by Jerry Grochow 2018-11-29 -->
|
|
|
|
<p class="subtitle">Other interesting tidbits about scripting in JMRI with Jython</p>
|
|
|
|
<ul>
|
|
<li>
|
|
<a href="#storescripts">Where should I store my JMRI Jython scripts?</a>
|
|
</li>
|
|
|
|
<li>
|
|
<a href="#classes">Where can I find more information on the JMRI classes?</a>
|
|
</li>
|
|
|
|
<li>
|
|
<a href="#names">What is the difference between System names and User names?</a>
|
|
</li>
|
|
|
|
<li>
|
|
<a href="#import">What do the words "<code>import</code>" and "<code>class</code>"
|
|
mean?</a>
|
|
</li>
|
|
|
|
<li>
|
|
<a href="#threads">Why should I based my script on "Siglet" and "AbstractAutomaton"
|
|
classes?</a>
|
|
</li>
|
|
|
|
<li>
|
|
<a href="#siglet-automaton">What's the difference between the "Siglet" and
|
|
"AbstractAutomaton" classes?</a>
|
|
</li>
|
|
</ul>
|
|
|
|
<p>See the <a href="Examples.shtml">examples page</a> for many sample scripts. Also, the
|
|
<a href="Start.shtml">introductory page</a> shows some of the basic commands.</p>
|
|
|
|
<p>See also <a href="HowTo.shtml">JMRI Scripting "How To..."</a></p>
|
|
|
|
<p>See also <a href="Python.shtml">Jython/Python Language</a> for general info about the
|
|
language.</p>
|
|
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
|
|
|
<h2><a id="storescripts">Where should I store my JMRI Jython scripts?</a>
|
|
</h2>
|
|
|
|
<div class="para">
|
|
<p>You CAN use any location for your own scripts, including locations within a Dropbox (or
|
|
other file sharing system) folder where they will be available across multiple computers.
|
|
[Instructions on using Dropbox with various JMRI files can be found at <a href=
|
|
"../../setup/Dropbox.shtml" target="_blank">JMRI Setup: Sharing Files with
|
|
Dropbox</a>.]</p>
|
|
|
|
<p>However, you should NEVER store your own scripts (or any other user-created files)
|
|
anywhere within your Program Location as they will be lost in a JMRI upgrade.
|
|
Unfortunately, JMRI currently defaults the Scripts Location to the Jython sample scripts
|
|
folder located within your JMRI Program Location. To resolve this, change the Scripts
|
|
Location in Preferences (Preferences->File Locations) so that your location will be displayed
|
|
automatically.</p>
|
|
|
|
<p><a href="#WhatWhereTopOfPage">[Go to top of page]</a>
|
|
</p>
|
|
</div>
|
|
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
|
|
|
<h2 id="classes">Where can I find more information on the JMRI classes?</h2>
|
|
|
|
<div class="para">
|
|
The <a href="https://www.jmri.org/JavaDoc/doc/" target="_blank">class documentation pages</a>
|
|
include automatically-built summary information on every class.
|
|
<p>There are a lot of classes! To help you find things, it might be useful to look at the
|
|
<a href="../../doc/Technical/Patterns.shtml">page on JMRI structure</a>, which is part of
|
|
the <a href="../../doc/Technical/index.shtml">JMRI technical documentation</a>. Note the
|
|
references on the left-hand side.</p>
|
|
|
|
<p>Additional information can be found in the JavaDocs for specific types of classes, for
|
|
example:</p>
|
|
|
|
<p><a href="https://www.jmri.org/JavaDoc/doc/jmri/SensorManager.html" target=
|
|
"_blank">https://www.jmri.org/JavaDoc/doc/jmri/SensorManager.html</a><br>
|
|
<a href="https://www.jmri.org/JavaDoc/doc/jmri/TurnoutManager.html" target=
|
|
"_blank">https://www.jmri.org/JavaDoc/doc/jmri/TurnoutManager.html</a><br>
|
|
<a href="https://www.jmri.org/JavaDoc/doc/jmri/LightManager.html" target=
|
|
"_blank">https://www.jmri.org/JavaDoc/doc/jmri/LightManager.html</a><br>
|
|
<a href="https://www.jmri.org/JavaDoc/doc/jmri/BlockManager.html" target=
|
|
"_blank">https://www.jmri.org/JavaDoc/doc/jmri/BlockManager.html</a>
|
|
</p>
|
|
|
|
<p><a href="#WhatWhereTopOfPage">[Go to top of page]</a>
|
|
</p>
|
|
</div>
|
|
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
|
|
|
<h2 id="names">What is the difference between System Names and User Names?</h2>
|
|
|
|
<p>Click for more information on <a href=
|
|
"../../../../../help/en/html/doc/Technical/Names.shtml">Names and Naming</a>.</p>
|
|
|
|
<p>System names for sensors, turnouts, lights and others, are connection specific. A LocoNet
|
|
sensor name begins with "LS" while a CMRI sensor begins with "CS" and an internal sensor with
|
|
"IS". "provide" methods check the prefix of the passed string to determine if it matches a
|
|
defined connection or internal. If so, and the rest of the name is valid, the sensor is
|
|
created. If a match does not exist, it assigns the prefix for the first connection in the
|
|
currently open connection list.</p>
|
|
|
|
<p>Example: If your connections are LocoNet and CMRI, a provideSensor request without a
|
|
prefix of LS, CS or IS, will be assigned LS. If the name value is not one to four numeric
|
|
digits (a LocoNet requirement), you get a bad format error. Memories are only internal, so
|
|
provideMemory uses "IM" as the default prefix.</p>
|
|
|
|
<p>Since System names follow a prescribed format, there is a procedure for checking whether a
|
|
name is valid. Use this code to create a sensor with a valid name:</p>
|
|
<!-- Example adapted from Randall Wood post to jmriusers@groups.io 2019-09-06 -->
|
|
|
|
<pre style="font-family: monospace;">
|
|
try:
|
|
sensors.validateSystemNameFormat(MySensorSystemName)
|
|
except jmri.NamedBean.BadSystemNameException:
|
|
print 'Invalid name: ', MySensorSystemName
|
|
</pre>
|
|
<p>User names are set after input and outputs are created. They can be any character string
|
|
you want. You can use user name or system name in scripts and Logix. The use of user names is
|
|
recommended for these purposes if there is the possibility that you will be changing your
|
|
control system in which case system names will be changing as well.</p>
|
|
|
|
<h3>Obtaining User Names from Objects</h3>
|
|
|
|
<p>If a returned object from a query is a NamedBean Object, ( ie. it appears in a JMRI Table
|
|
) the return value ( from Java #toString() ) is the Hardware Address.<br>
|
|
If you require the ID Tag UserName, eg. For a Block with username "BlockUserName", you could
|
|
use :</p>
|
|
|
|
<pre style="font-family: monospace;">
|
|
mylocostring=blocks.getByUserName("BlockUserName").getValue() #Block value Object could be a String or ID Tag
|
|
if (isinstance(mylocostring,jmri.NamedBean)) : # The object is a NamedBean
|
|
mylocostring = mylocostring .getUserName() # Set to the User Name
|
|
print mylocostring
|
|
</pre>
|
|
<p>It can sometimes be handy to get further information on a Reporter value. The
|
|
toReportString method provides an object specific report, which may or may not actually
|
|
contain the user name by itself.<br>
|
|
For example, a LocoNet TranspondingTag may report strings such as '1234 enter' or '1234
|
|
exit', while Railcom objects will add any detector supplied values, such as orientation, to
|
|
the string.</p>
|
|
|
|
<p>Eg. For a Block with username "BlockUserName", you could use :</p>
|
|
|
|
<pre style="font-family: monospace;">
|
|
mylocostring=blocks.getByUserName("BlockUserName").getValue() #Block Object could be a String or ID Tag
|
|
if (isinstance(mylocostring,jmri.Reportable)) : # The object is a Reportable
|
|
mylocostring = mylocostring .toReportString() # Set to the Report String
|
|
print mylocostring
|
|
</pre>
|
|
<p><a href="#WhatWhereTopOfPage">[Go to top of page]</a>
|
|
</p>
|
|
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
|
|
|
<h2 id="import">What do the words "<code>import</code>", "<code>class</code>" mean?</h2>
|
|
|
|
<div class="para">
|
|
They're part of the jython language used for the scripting.
|
|
<p>"import" allow you to refer to things by shorter names, essentially telling jython
|
|
"search the imported packages (e.g. jarray and jmri) packages and recognize all the names
|
|
there". For somebody trying to understand this script, you can just treat them as "ensuring
|
|
the program can find parts we want".</p>
|
|
|
|
<p>"class" means "start the definition of a group of things that go together" (all you
|
|
other experts, please don't jump on me about this; I understand both intrinsic/extrinsic
|
|
polymorphism, I'm just trying to get the general idea across).</p>
|
|
|
|
<p>For example, in the SigletExample.py file is a description of a "class" called
|
|
SigletExample, which contains two routines/functions/members: A subroutine called
|
|
"defineIO", and one called "setOutput"</p>
|
|
|
|
<p>This "class" is associated with another called "Siglet" (actually
|
|
jmri.jmrit.automat.Siglet; that's that long naming thing again), which knows when to invoke
|
|
routines by those two names to get done what you want.</p>
|
|
|
|
<p>Essentially, you're defining two parts ("defineIO" & "setOutput") that plug into a
|
|
pre-existing structure to drive signals. That pre-existing structure is very powerful, and
|
|
lets you do all sorts of things, but also provides this method to try to keep it
|
|
simpler.</p>
|
|
|
|
<p>OK, at this point most people's eyes are fully glazed over. Your best bet when starting
|
|
with this stuff is to use the "copy and modify" approach to software development. It's good
|
|
to try to understand the entire content of the file, but don't worry about understanding it
|
|
well enough to be able to recreate it from scratch. Instead, just modify little bits and
|
|
play with it.</p>
|
|
|
|
<p><a href="#WhatWhereTopOfPage">[Go to top of page]</a>
|
|
</p>
|
|
</div>
|
|
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
|
|
|
<h2 id="threads">Why should I base my scripts on "Siglet" and "AbstractAutomaton"
|
|
classes?</h2>
|
|
<!-- Section created by Jerry Grochow 2019-10-14 based on post to jmriusers@groups.io by Bob Jacobson 2018-11-01 -->
|
|
|
|
<div class="para">
|
|
<p>Scripts are part of the main JMRI program. This creates a bit of a problem: when
|
|
something goes wrong in a script, it may crash JMRI. When a script goes to sleep, the whole
|
|
program sleeps. However, if you want to run independent of JMRI, you can via a separate
|
|
"thread." The Siglet and AbstractAutomaton classes have created to allow you to base your
|
|
scripts on a class that will run as an independent thread but with the ability to
|
|
communicate with the rest of JMRI. For more information, see <a href=
|
|
"../../../../../help/en/html/doc/Technical/Threads.shtml">the section on threads.</a></p>
|
|
|
|
<p>Effectively, each Automat or Siglet is a separate program running when it needs to.
|
|
Since they run in separate threads, they can wait for something to happen while the rest of
|
|
the JMRI program proceeds - a very useful capability indeed.</p>
|
|
</div>
|
|
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
|
|
|
<h2 id="siglet-automaton">What's the difference between the "Siglet" and "AbstractAutomaton"
|
|
classes?</h2>
|
|
|
|
<div class="para">
|
|
<p>Some examples use the <a href=
|
|
"https://www.jmri.org/JavaDoc/doc/jmri/jmrit/automat/AbstractAutomaton.html" target=
|
|
"_blank">AbstractAutomaton</a> class as a base, while others use the <a href=
|
|
"https://www.jmri.org/JavaDoc/doc/jmri/jmrit/automat/Siglet.html" target="_blank">Siglet</a>
|
|
class. This is because those are intended for two different purposes.</p>
|
|
|
|
<p>"Siglet" is meant to be used for driving signals. You provide two pieces of code:</p>
|
|
|
|
<dl>
|
|
<dt><strong>defineIO</strong>
|
|
</dt>
|
|
|
|
<dd>which defines the various sensors, turnouts and signals that the output signal
|
|
depends on as input when calculating the appearance of the signal.</dd>
|
|
|
|
<dt><strong>setOutout</strong>
|
|
</dt>
|
|
|
|
<dd>which recalculates the signal appearance from the defined inputs.</dd>
|
|
</dl>
|
|
|
|
<p>The Siglet base class then handles all of the listening for changes, setting up for
|
|
parallel execution, etc. Your defineIO routine will be called once at the beginning, and
|
|
after than any time one or more of the inputs changes, your setOutput routine will be
|
|
called to recalculate the signal appearance.</p>
|
|
|
|
<p>Of course, you can use this class to calculate other things than signal appearances. But
|
|
the key element is that the calculation is redone when the inputs change, and only when the
|
|
inputs change.</p>
|
|
|
|
<p>AbstractAutomaton is a more general class that's intended to allow more powerful
|
|
operations (and Siglet actually uses that more powerful base). You define two
|
|
functions:</p>
|
|
|
|
<dl>
|
|
<dt><strong>init</strong>
|
|
</dt>
|
|
|
|
<dd>which is called exactly once to do any one-time setup you need</dd>
|
|
|
|
<dt><strong>handle</strong>
|
|
</dt>
|
|
|
|
<dd>which is called over and over and over again until it returns FALSE.</dd>
|
|
</dl>
|
|
Using AbstractAutomoton provides you with a number of tools: you can wait for a particular
|
|
sensor to go active, do something, then wait for a different sensor to go inactive, etc.
|
|
This allows you much more freedom to create complicated and powerful sequences than the
|
|
Siglet class, because Siglets are limited to doing just one thing (they aren't intended to
|
|
do sequences of operations).
|
|
<p>For more info on the routines that AbstractAutomaton provides to help you, see the
|
|
<a href=
|
|
"https://www.jmri.org/JavaDoc/doc/jmri/jmrit/automat/AbstractAutomaton.html#method_summary"
|
|
target="_blank">Javadocs</a> for the class. (Scroll down to the section called "Method
|
|
Summary")</p>
|
|
|
|
<p><a href="#WhatWhereTopOfPage">[Go to top of page]</a>
|
|
</p>
|
|
</div>
|
|
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
|
<!--#include virtual="/help/en/parts/Footer.shtml" -->
|
|
</div>
|
|
<!-- closes #mainContent-->
|
|
</div>
|
|
<!-- closes #mBody-->
|
|
</body>
|
|
</html>
|