-
Notifications
You must be signed in to change notification settings - Fork 331
/
Start.shtml
343 lines (262 loc) · 13.2 KB
/
Start.shtml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta name="generator" content=
"HTML Tidy for Mac OS X (vers 31 October 2006 - Apple Inc. build 15.17), see www.w3.org">
<meta name="keywords" content="start jmri jython, hello world jython, jython layout commands,
jython access jmri objects, access jmri tables">
<title>JMRI: Getting Started with Scripting</title>
<!-- Style -->
<meta http-equiv="Content-Type" content=
"text/html; charset=us-ascii">
<link rel="stylesheet" type="text/css" href="/css/default.css"
media="screen">
<link rel="stylesheet" type="text/css" href="/css/print.css"
media="print">
<link rel="icon" href="/images/jmri.ico" type="image/png">
<link rel="home" title="Home" href="/">
<!-- /Style -->
</head>
<body>
<!--#include virtual="/Header.shtml" -->
<div id="mBody">
<!--#include virtual="Sidebar.shtml" -->
<div id="mainContent">
<!-- Page Body -->
<h1><a id="StartTopOfPage" name="StartTopOfPage">JMRI: Getting Started with Scripting</a></h1>
<p>The easiest way to learn how to use scripts in JMRI is to study the simplest examples first
and work your way into more complex details. The sections below discuss various aspects of scripting
that will help you to understand the more complex scripts found in the <a href="Examples.shtml" target="_blank">
JMRI examples library</a> included in the distribution and online:</p>
<ul>
<li><a href="#helloworld">Running "Hello World"</a></li>
<li><a href="#debugging">Basic debugging tools in JMRI</a></li>
<li><a href="#layoutcommands">Sample layout commands</a></li>
<li><a href="#objects">Access to JMRI Objects</a></li>
<li><a href="#scripts">Script files, listeners, and classes</a></li>
</ul>
<h4>CAUTION: Python and its Jython variant do not use braces, brackets, or parentheses to
indicate program structure, but rather rely on formatting, specifically indentation. To avoid
confusion, it is STRONGLY recommended that you DO NOT USE TABS but rather use spaces (four is typical)
to show statements that part of a class or controlled structure where you might have used some bracketing.
Most program editors have a setting to automatically changes tabs to a set number of spaces to make this easier.</h4>
<h2><a id="helloworld" name="helloworld">Running "Hello World"</a></h2>
<div class="para">
There are several ways to use
Python scripts with JMRI. The easiest is to use the built-in
support in the standard JMRI applications: PanelPro,
DecoderPro, etc.<br>
To do that:
<ul>
<li><a href=
"../../../package/jmri/jmrit/beantable/images/jmriScriptWindow.png">
<img src=
"../../../package/jmri/jmrit/beantable/images/jmriScriptWindow.png"
width="250" height="136" align="right" alt="JMRI Jython Script Window"></a>From the
"Panels" menu, select "Script Entry". This will give you a
window where you can type one or more commands to execute.
(Note that it might take a little while the first time you
do this as the program finds its libraries; it will be
faster the next time) The commands stay in the window, so
you can edit them and rerun them until you like them.</li>
<li>From the "Panels" menu, select "Script Output". This
creates a window that shows the output from the script
commands you issue.</li>
<li>To see this in operation, type
<pre style="font-family: monospace;">
print "Hello World"
</pre>in the input window, and click "Execute". You should see the
output in the Script Output window immediately:
<pre style="font-family: monospace;">
>>> print "Hello World"
Hello World
</pre>
</li>
<li>Python also evaluates expressions, etc. Remove the
contents of the input window (select it and hit delete),
and enter
<pre style="font-family: monospace;">
print 1+2
</pre>then click execute. The output window should then show
something like:
<pre style="font-family: monospace;">
>>> print 1+2
3
</pre>
</li>
</ul>
<p><a href="#StartTopOfPage">[Go to top of page]</a></p>
</div>
<h2><a id="debugging" name="debugging">Basic debugging tools in JMRI</a></h2>
<!--Section added by Jerry Grochow 2018-10-18 based on comments found in the JMRI Users online forum from
Cliff in BajaSoCal and Bob Jacobson-->
<div class="para">
<p>JMRI does not provide a full "development environment," but it does provide some basic information
that can help with debugging your scripts.</p>
<p>Open the JMRI System Console window (Help->System Console).
This will give you instant information pertaining to WARN and ERROR messages. Text can be copied to a
text editor for further review.</p>
<p>Open the Script Output window (Panels->Script Output). This will display the results of any
"print" statements in your script as well as some error messages (NOTE that some errors go here and
some to the System Console so you you should have both windows open when you are debugging).
Text can be copied to a text editor for further review.
<p>Investigate the information found in the
<a href="../../doc/Technical/Logging.shtml" target="_blank">technical reference</a>
to be better able to insert more of your own DEBUG and INFO messages into the session.log file,
and also the JMRI System Console window. You might also investigate the "default.lcf" file that is
described in that link.</p>
<p>Note to Mac OS users: BBEdit and similar tools do some syntax checking. For PC users, Notepad++
is a good tool for getting indentation correct.</p>
<p><a href="#StartTopOfPage">[Go to top of page]</a></p>
</div>
<h2><a id="layoutcommands">Sample layout commands</a></h2>
<div class="para">
<pre style="font-family: monospace;">
>>> lt1 = turnouts.provideTurnout("1")
>>> lt1.setCommandedState(CLOSED)
>>> print lt1.commandedState
2
>>> lt1.commandedState = THROWN
>>> print lt1.commandedState
4
>>> turnouts.provideTurnout("1").getCommandedState()
1
</pre>
<p>Note that this is running a complete version of the JMRI
application; all of the windows and menus are presented the same
way, configuration is done by the preferences panel, etc. What the
Jython connection adds is a command line from which you can
directly manipulate things.
<p>This also shows some of the simplifications that Jython
and the Python language brings to using JMRI code. The Java
member function:</p>
<pre style="font-family: monospace;">
turnout.SetCommandedState(jmri.Turnout.CLOSED);
</pre>
can also be expressed in Jython as:
<pre style="font-family: monospace;">
turnout.commandedState = CLOSED
</pre>
<p>This results in much easier-to-read code.</p>
<p>There are a lot of useful Python books and online
tutorials. For more information on the Jython language and
it's relations with Java, the best reference is the <a href=
"http://www.oreilly.com/catalog/jythoness/" target="_blank">Jython
Essentials</a> book published by O'Reilly. The <a href=
"https://www.jython.org/" target="_blank">jython.org web site</a> is also very
useful.</p>
<p><a href="#StartTopOfPage">[Go to top of page]</a></p>
</div>
<h2><a id="objects" name="objects">Access to JMRI Objects</a></h2>
<div class="para">
JMRI uses the factory-pattern
extensively to get access to objects. In Java this results in
verbose code like
<pre style="font-family: monospace;">
Turnout t2 = InstanceManager.getDefault(TurnoutManager.class).newTurnout("LT2", "turnout 2");
t2.SetCommandedState(Turnout.THROWN)
</pre>Jython simplifies that by allowing us to provide useful
variables, and by shortening certain method calls.
<p>To get easier access to the SignalHead, Sensor and Turnout
managers and the CommandStation object, several shortcut
variables are defined:</p>
<ul>
<li>sensors</li>
<li>turnouts</li>
<li>lights</li>
<li>signals (SignalHeads)</li>
<li>masts (SignalMasts)</li>
<li>routes</li>
<li>blocks</li>
<li>reporters</li>
<li>memories</li>
<li>powermanager</li>
<li>addressedProgrammers</li>
<li>globalProgrammers</li>
<li>dcc (current command station)</li>
<li>audio</li>
<li>shutdown (current shutdown manager)</li>
<li>layoutblocks</li>
<li>warrants</li>
</ul>These can then be referenced directly in Jython as
<pre style="font-family: monospace;">t2 = turnouts.provideTurnout("12");
</pre>Note that the variable t2 did not need to be declared.
<p>Jython provides a shortcut for parameters that have been
defined with Java-Bean-like get and set methods:</p>
<pre style="font-family: monospace;">
t2.SetCommandedState(Turnout.THROWN)
</pre>can be written as
<pre style="font-family: monospace;">
t2.commandedState = THROWN
</pre>
<p>where the assignment is actually invoking the set method.</p>
<p>Also note that THROWN was defined when running the Python script at
startup;<br> CLOSED, ACTIVE, INACTIVE, RED, YELLOW and GREEN are also
defined. ( <a
href="https://github.com/JMRI/JMRI/blob/master/java/src/jmri/script/JmriScriptEngineManager.java">These
shortcut bindings are defined in Java</a> )
</p>
<p>A similar mechanism can be used to check the state of
something:</p>
<pre style="font-family: monospace;">
>>> print sensors.provideSensor("3").knownState == ACTIVE
1
>>> print sensors.provideSensor("3").knownState == INACTIVE
0
</pre>Note that Jython uses "1" to indicate true, and "0" to
indicate false, so sensor 3 is currently active in this example.
You can also use the symbols "True" and "False" respectively.
<p>You can directly invoke more complicated methods, e.g. to
send a DCC packet to the rails you type:</p>
<pre style="font-family: monospace;">
dcc.sendPacket([0x01, 0x03, 0xbb], 4)
</pre>This sends that three-byte packet four times, and then
returns to the command line.
Also see <a href="WhatWhere.shtml#names">JMRI Jython : The difference between System Names and User Names</a>
<p><a href="#StartTopOfPage">[Go to top of page]</a></p>
</div>
<h2><a id="scripts" name="scripts">Script files, listeners, and classes</a></h2>
<div class="para">
<p>[See also <a href="HowTo.shtml" target="_blank">the scripting "How To" page</a> for more information
on these topics.]</p>
<p>Scripting would
not be very interesting if you had to type the commands each
time. So you can put scripts in a text file and execute them
by selecting the "Run Script..." menu item, or by using the
"Advanced Preferences" to run the script file when the
program starts.</p>
<p>Although the statements we showed above were so fast you
couldn't see it, the rest of the program was waiting while
you run these samples. This is not a problem for a couple
statements, or for a script file that just does a bunch of
things (perhaps setting a couple turnouts, etc) and quits.
But you might want things to happen over a longer period, or
perhaps even wait until something happens on the layout
before some part of your script runs. For example, you might
want to reverse a locomotive when some sensor indicates it's
reached the end of the track.</p>
<p>There are a couple of ways to do this. First, your script
could define a "listener", and attach it to a particular
sensor, turnout, etc. A listener is a small subroutine which
gets called when whatever it's attached to has it's state
change. For example, a listener subroutine attached to a
particular turnout gets called when the turnout goes from
thrown to closed, or from closed to thrown. The subroutine
can then look around, decide what to do, and execute the
necessary commands. When the subroutine returns, the rest of
the program then continues until the listened-to object has
it's state change again, when the process repeats.</p>
<p>For more complicated things, where you really want your
script code to be free-running within the program, you define
a "class" that does what you want. In short form, this gives
you a way to have independent code to run inside the program.
But don't worry about this until you've got some more
experience with scripting.</p>
<p><a href="#StartTopOfPage">[Go to top of page]</a></p>
</div>
<!--#include virtual="/Footer.shtml" -->
</div><!-- closes #mainContent-->
</div><!-- closes #mBody-->
</body>
</html>