Creating ScriptsScripts are files containing one or more commands to the Virtual Wiring system. Scripts are used to add devices to the Virtual Wiring system, initialize devices, and to create complex systems consisting of devices and Virtual Wires. Scripts can optionally take parameters, so one Script can be run in many different ways. Though it may be possible to never write a Script, Scripts save typing, they keep you from having to remember lots of details, and Scripts can be executed from the Scripts page. A Script is also interpreted within a single context by the Script Interpreter, so parameters and environment variables can be passed into and shared within a Script. Scripts are files containing lines, and each line is either a Console command or a command for the Script interpreter. Generally, one creates a Script by building something of interest using the Scripts page and/or the Console. Once the thing of interest is running, one copies the appropriate lines from the Console to a file, removes any status lines, and adds any of the various statements that will be explained here. The following is an example of a Script that creates an Arduino with a blinking LED.
This Script will be referenced in the following sections. Empty Lines and CommentsEmpty lines and comments make Scripts easier to read for humans. Many of the lines in the example Script are blank, or they start with or contain a "#" (pound) character. The pound character begins a "comment". Empty lines and comments are ignored by the Script interpreter. If a line starts with a pound, the entire line is ignored by the interpreter. If somewhere within a line, there is a pound, everything starting with and after the pound is ignored. Pounds within double quoted strings are part of the string (they are not the beginning of a comment). Script VariablesScript Variables make Scripts easier to read, and they make Scripts easier to modify. A Script Variable name, say LED_PIN, makes a lot more sense to a person reading a Script than the number 13. If a Script Variable is used in more than one place, a single change to the Variable's value will modify every Script line where the Variable is used. Lines which look like assignments (e.g. Script Variables must start with a capital letter. This constraint keeps them from colliding with variables that may have been created when the Script was invoked (see Script Parameters section). Within a Script, Script Variable values can be changed by another assignment statement. Any of the possible values in a Virtual Wiring system (numbers, true/false/nil, double quoted strings) can be assigned to Script Variables. Script ParametersScript Parameters make Scripts general purpose. Script parameters are identifiers within a Script, and when the Script is run, the identifiers get replaced by values. The values are defined at the Console command line or, if you are using the Scripts page, in a dialog box. It is possible to write a Script that takes no parameters, but if a Script has values that change from time to time or from system to system, these values are good Script parameter candidates. Script InvocationScript parameter values are passed to a Script when the Script is invoked. Scripts can be invoked from the Console or from the Scripts page. If you invoke the example Script above from the Console, the parameters are supplied on the command line. The following line:
invokes the Script in the "Scripts/user" directory with the name "blinking_led.script". What follows the Script name are the Script parameters. Script parameters are strings ending with a colon (:) followed by a value. The string part before the colon is the parameter name. In this example, there are 2 Script parameters, "arduino_port" and "osc_period", with values "/dev/cu.usbmodem411" and 1. If you invoked this same Script from the Scripts page, you would get a dialog box with two fields labeled "arduino_port" and "osc_period". The "arduino_port" field would be empty, and the "osc_period" field would be preloaded with the value 1. When invoking a Script, one can use as many parameters as one wishes - the system does not check if the Script actually needs the parameters. When a Script is invoked with a Script parameter, the system creates a variable in the Script's context with the same name and the value associated with the Script parameter. In this manner, external values are passed into Scripts for their internal use. Script parameter variables must begin with a small letter. The small letter distinguishes them from any Script Variables defined within the Script (see Script Variables section). Script Parameters StatementsWithin a Script, it is possible to check if a Script parameter exists. A "script_parameters" statement performs this check. The "script_parameters" statement is useful when a Script needs a parameter, the Script has no way of guessing it, and not having the parameter is fatal to the Script. A "script_parameters" statement looks like this:
The "script_parameters" statement takes one or more parameter names, separated by commas. The names are the parameter/variables we are checking for (in this case, "arduino_port"). If the "arduino_port" variable does not exist, the statement will generate an error and stop the Script from executing. One can declare more than one Script parameter within a single statement by having more than one parameter name. Alternately, one can declare more than one Script parameter by having more than one "script_parameters" statement. One can have as many "script_parameters" statements as one needs. When invoking a Script from the Scripts page, all the parameters that were defined by "script_parameters" statements will show up in the parameters dialog box with blank fields. The Scripts page identifies parameters and creates its dialog boxes based on what is defined in these statements. Because of Scripts page dialog boxes, it is important that you identify all your Script parameters explicitly in your Scripts. The fields within dialog boxes that come from "script_parameters" statements will be blank, because "script_parameters" statements provide no values. Optional Script Parameters StatementsThe "optional_script_parameters" statement does not error if a parameter is undefined. Instead, it checks if the parameter is defined and if it isn't, it defines the parameter and assigns a value to it. "optional_script_parameters" statements are useful when a Script has a reasonable default value, but you want to give the person running the Script the option of overriding that default. An "optional_script_parameters" statement looks like this:
The "optional_script_parameters" statement takes a parameter name and a value. The name is the parameter/variable we are checking for (in this case, "osc_period"). If the "osc_period" variable does not exist, the statement will create an "osc_period" variable and assign the value 1 to it. One can have as many "optional_script_parameters" statements as one wants in a Script, and one can define more than one parameter per statement - just separate each definition with a comma. When invoking a Script from the Scripts page, all the parameters that were defined by "optional_script_parameters" statements will show up in the parameters dialog box with filled in fields. The Scripts page identifies parameters and creates the dialog based on what is defined in these statements. Because of dialog boxes, it is important that you identify all your Script parameters explicitly in your Scripts. The dialog fields will be filled because the "optional_script_parameters" statement provides values. Nested Script ParametersSometimes, a Script calls a another Script, and that other Script needs a parameter that was supplied as a parameter to the calling Script. To pass parameters from one Script to another, one invokes the second Script using the parameters of the first. Suppose we wish to call an "oscillator" Script that takes a "period" parameter. The oscillator Script is called from a "blinker" Script, and the blinker Script was called with a parameter called blink_period. To pass the blink_period from the blinker Script to the oscillator Script:
Parameter and Variable Substitution within Double Quoted StringsIn Scripts, we commonly see double quoted strings (in "run_script" statements, "wire" statements, and in "optional_script_parameters" statements). Double quoted strings are any sequence of characters surrounded by double quote characters (""). Just like we use Script variables and parameters to make Scripts more flexible, we can substitute them in strings to make strings more flexible. Consider this Script:
There is one double quoted string, "Var1". Though the string may be the name of a previous Script variable, that's all it is. Var2 and the string have the value, "Var1" However, this Script is different:
"#{Var1}" now has the value 1, and so does Var2. In any quoted string, #{variable/parameter} will evaluate to the value in the variable or parameter (and be substituted into the string). In the short Script above, we didn't do anything very interesting, but consider our original blink script (some comments removed):
Notice we've added arduino_id and oscillator_id parameters. We are using them as ID parameters throughout the Script. Look at the "wire" statement. We've modified it so it wires to Devices with the IDs we choose. The whole Script creates blinking Arduinos in an abstract way, so we can use it as many times as we want with whatever Device IDs we want. #{}s allow Scripts to be fully parametrized, all the way down to the "wire" statements. Whenever you have a system with common elements, consider writing a fully parametrized Script and using it for each element. Calling Device Methods within a ScriptSometimes a Device is not completely configured after it has been added into a system. If this is the case, a method needs to be run to configure it. To run a Device method within a Script write:
Unlike the other "run_script" method calls we've seen, there is no Script name (just empty quotes). Instead, the "text" string is executed as though it came from a Script file. The "on_device" parameter tells "run_script" the ID of the Device to run the Script on. Here, the method "my_method" is run on the Device with ID "my_device". The "my_method" method has 2 parameters "p1" and 2. Notice when parameters are quoted, their quotes need escaping. If they weren't in this example, the Script interpreter would interpret the first quote of the "p1" parameter as the closing quote of the "text" string. |