This tutorial introduces you to the joys and pains of writing scripts for STUI.
Scripts are written in Python, and this tutorial does not attempt to teach the language. I strongly recommend the python tutorial at Python's home. Python is a simple and powerful language, and a little knowledge can be a tremendous asset.
The topics are as follows:
Let's start with the traditional greeting. Create a text file "hello.py" in your home directory (or anywhere convenient) containing the following text. Use tabs for indentation:
class ScriptClass(object): def __init__(self, sr): pass def run(self, sr): sr.showMsg("Hello") yield sr.waitMS(1000)
Start STUI (if it is not already running) and load your script using Open... in the Scripts menu. A new script window should appear; press "Start" to run your script. This causes the status bar to show "Hello" for 1 second, after which your script ends and the status bar shows "Done".
To reload a script (i.e. after modifying it), select Reload from the contextual pop-up menu for the status bar or any of the buttons along the bottom (Start, etc.). This is useful for developing scripts: you can modify the script in your favorite editor, then reload it in STUI and try it out.
Whenever your script calls an sr.wait... function (i.e. wants to wait for anything), it must use yield, as in:
yield sr.wait...(...)
This is a painful, but it could be worse. Most languages would force you to break your script into many small functions, each of which would have to be registered as a separate callback function. That style of programming is fine for user interfaces but is needlessly complicated for scripts.
If you forget the "yield", your script will plow ahead instead of waiting, which is a recipe for trouble. However, STUI will catch this problem the next time you call an sr.wait... function, at which point STUI will kill your script, print a message to the status bar and print details to the error log.
Sending commands to an instrument or other actor is straightforward. You need to know the name of the actor (e.g. "boss", "sop", "tcc") and the command you wish to send. See APO Documentationfor documentation for the instruments, TCC and hub.
This script simply pings boss.
class ScriptClass(object): """Ping two actors""" def __init__(self, sr): pass def run(self, sr): yield sr.waitCmd( actor = "alerts", cmdStr = "ping", ) yield sr.waitCmd( actor = "boss", cmdStr = "ping", )
Notes:
yield sr.waitCmd(...)
Often you will want to execute the a set of commands, or the same command multiple times with slight variations. Loops make this easy.
This version will halt at the first failure and display that failure in the status bar. We can do better, as shown by the next version of this script.
class ScriptClass(object): """Tutorial script to test the aliveness of several actors. This version uses a loop. """ def __init__(self, sr): pass def run(self, sr): for actorCmd in ( "alerts ping", "boss ping", "gcamera ping", "guider ping", "mcp ping", "platedb ping", "sop ping", "tcc show time", ): actor, cmdStr = actorCmd.split(None, 1) yield sr.waitCmd( actor = actor, cmdStr = cmdStr, )
Adding a few refinements to the ping script makes a script worth adapting for your own uses.
The improvements are as follows:
The resulting script still has no provision for user input, but often that is fine. We'll deal with user input in the next lesson.
import RO.Constants class ScriptClass(object): """Tutorial script to test the aliveness of various actors. This is the recommended version. Unlike 3 Looping Ping: - It outputs the results to a log window - It uses checkFail=False to continue and check all actors even if one command fails. """ def __init__(self, sr): """Display the exposure status panel. """ self.actorCmdList = ( "alerts ping", "boss ping", "gcamera ping", "guider ping", "mcp ping", "platedb ping", "sop ping", "tcc show time", ) self.logWdg = RO.Wdg.LogWdg( master = sr.master, width = 30, height = len(self.actorCmdList) + 1, # avoids scrolling ) self.logWdg.grid(row=0, column=0, sticky="news") def run(self, sr): """Run the script""" for actorCmd in self.actorCmdList: actor, cmdStr = actorCmd.split(None, 1) yield sr.waitCmd( actor = actor, cmdStr = cmdStr, checkFail = False, ) cmdVar = sr.value if cmdVar.didFail: self.logWdg.addMsg("%s FAILED" % (actor,), severity=RO.Constants.sevError) else: self.logWdg.addMsg("%s OK" % (actor,))
__init__
run
self
self.actorCmdList
self.logWdg
It is easy to incorporate information from an actor (e.g. instrument or the tcc) into your scripts. Each actor has a model that contains a set of keyword variables you can query. In this simple example we get and display the version of several actors.
The models are in the actorkeys product. You should get a copy of actorkeys (or browse it on the Trac wiki) before trying to read data from an instrument. Each model contains a description of each keyword output by the actor (at least those keywords you can get data for) and the description usually includes documentation. (One exception: documentation for TCC keywords is in the TCC Message Keywords Dictionary).
import RO.Wdg import TUI.Models class ScriptClass(object): """Tutorial script to print the version of some actors """ def __init__(self, sr): self.bossModel = TUI.Models.getModel("boss") self.gcameraModel = TUI.Models.getModel("gcamera") self.guiderModel = TUI.Models.getModel("guider") self.tccModel = TUI.Models.getModel("tcc") self.actorKeyVarList = ( ("boss", self.bossModel.version), ("gcamera", self.gcameraModel.version), ("guider", self.guiderModel.version), ) self.logWdg = RO.Wdg.LogWdg( master = sr.master, width = 40, height = len(self.actorKeyVarList) + 2, # avoids scrolling ) self.logWdg.grid(row=0, column=0, sticky="news") def run(self, sr): for actor, keyVar in self.actorKeyVarList: versionStr = sr.getKeyVar(keyVar, ind=0, defVal="?") self.logWdg.addMsg("%s\t%s" % (actor, versionStr)) yield sr.waitCmd(actor="tcc", cmdStr="show version", keyVars=[self.tccModel.version]) tccVers = sr.value.getLastKeyVarData(self.tccModel.version)[0] self.logWdg.addMsg("%s\t%s" % ("tcc", tccVers))
sr.getKeyVar
yield sr.waitKeyVar
You have seen how to write a variety of scripts, including scripts that use current status information from instruments and the telescope and that add widgets for user output. Now what?
sr
end
The sample scripts from this tutorial can be found in tui_root/STUI/Scripts/Tutorial (you may have to ask your sysadmin for the location of tui_root).