Download as pdf or txt
Download as pdf or txt
You are on page 1of 93

Reference Guide

Extron Control System Programming


Using Python
Educational Supplement
Extron Control System Programming Using Python

Contents
Overview 5
Purpose 5
Assumptions 5
Implementation 6
Python Interpreter 6
Development Environment 6
Extron Library and Reserved Keywords 6
Global Scripter Introduction 7
Programming Interface 7
System Manager 8
Code Editor 8
Layout Window 9
Diagnostic Windows 10
Status Bar 12
Python Basics 13
Conventions and Syntax 13
Standard Practices for Extron Programming 13
General Recommendations 13
Identifiers 13
Line Length and Line Continuation 14
Strings 14
ID Ranges 14
Interpreter and Libraries 15
Objects and Programming 15
Lists and Dictionaries 15
Loops and Iterators 16
Programming from the Beginning 18
Creating a Project in Global Scripter 18
The main.py Entry Code File 22
Import Libraries 22
The AV Equivalent of "Hello World" 22
The Event Decorator 24

Page 2
Extron Control System Programming Using Python

Compound Event Decorators 25


Using Bookmarks 27
Programming Touchpanel Interface Navigation 29
Programming eBUS Devices 35
Programming for Device Control 38
Programming Data Communication with a Device 40
Sending Data to IR Ports 40
Sending Data to Unidirectional Serial Ports 43
Bidirectional Serial Port Communication 45
Asynchronous Communication 45
Synchronous Communication 52
Communication with Ethernet Ports 53
Establishing an Ethernet Connection 54
Programming Volume Interfaces 63
Programming Input and Output Interfaces 65
Relay Interface 65
Switched Power Interface 65
Contact Interface 65
Digital I/O Interface 66
Flex I/O Interface 67
Standard Package Libraries 68
exml ElementTree Module 68
System Package 70
Mutually Exclusive Sets 70
Tools Within the System Package 71
Programming Timing Events 74
Programming a Recurring Function Using a Timer 74
Delaying a Function Using a Wait 75
Scheduled Events Based on Clock Times 77
Using File and RFile 78
Managing Directories 79
Reading and Writing Files 79
Deleting Files 80
Debugging Tools 81
Breakpoints 81

Page 3
Extron Control System Programming Using Python

Variables and Watch Variables 83


Appendix A - Resources for Learning Python 85
Books and E-Books 85
Websites and Tutorials 85
Appendix B - Disallowed Python Objects 86
Disallowed Built-Ins 86
Disallowed Non-Built-In Modules 86
Glossary 88

Page 4
Extron Control System Programming Using Python

Overview
Global Scripter® is powerful and versatile control system programming software. This feature-rich integrated
development environment is used to program Extron Pro Series Control Systems, and utilizes the easy-to-learn
Python scripting language.

Like all aspects of Global Scripter, ControlScript® has been designed by Extron to increase the productivity of
AV programmers. This Extron exclusive Python library makes it simple to incorporate functions common to AV
control system projects and includes helpful tips and sample code for reference. Extron built Global Scripter
and the Python libraries with programmers in mind.

Purpose
This guide is intended to provide direction on how to use the Python programming language with Extron Pro
Series Control Systems. It has been divided into multiple chapters to guide the programmer with the
implementation of the language on the platform, as well as clarify the creation of program code in an organized
fashion using the Extron provided Python libraries.

Although this guide is not intended for use as a tutorial covering the Python language, it does introduce many of
the Python language elements and explains how Extron has implemented the language into Pro Series Control
Systems. For more information on resources for learning Python please see Appendix A. Extron also provides
an extensive library of online videos on Global Scripter and ControlScript, which can be found on the Extron
website: https://www.extron.com/technology/swvideos.aspx?tab=training.

Assumptions
Please be aware of the following assumptions made regarding the use of this guide:

l The programmer has awareness of the Python programming language. Direct experience with Python
makes learning how to program Extron Pro Series Control Systems even faster. This guide provides a
foundation for programming using Python.

l There are vast differences in versions prior to Python 3. Some keywords used in earlier versions have
been deprecated. If you are using a tutorial or documentation to provide more insight into Python, please
ensure that the tutorial or documentation refers to version 3.3 or higher.

l The programmer is familiar with the Extron Pro Series Control System hardware including user
interfaces.

l The programmer is using Global Scripter 2.0 or above, and the control processors are running firmware
version 3.0 or above.

l During the learning process, the programmer will have access to a control processor and user interface.
Valuable insight is gained through the ability to load a program to a system and see the interaction
among the devices.

l The programmer has a direct understanding of the typical components used in AV systems and
experience with AV system design.

Page 5
Extron Control System Programming Using Python

Implementation

Python Interpreter
Extron has implemented a Python 3 interpreter, allowing direct programming of Extron Pro Series Control
Systems using Extron Global Scripter. This selection was made for many reasons:

l It is well documented and has many resources available to help programmers quickly become familiar
with the language.

l The language is clean and not obscured by punctuation to determine program flow, which helps it to be
more readable than similar languages.

l It is object oriented and extensible; this allowed Extron to customize it for use in a control system
environment.

Development Environment
Extron GUI Designer is used to create the graphical user interface designs for TouchLink Pro user interfaces.
This program will also assign the control object and page IDs required for programming Extron Pro Series
Control Systems.

Extron Global Scripter enables the development of advanced control system programs. This application
provides the framework for the control system program, allowing the user to include all files necessary for the
implementation of the control program such as user interface files, IR files, sound files, data files, and code
files. This tool also provides an environment for transferring, testing, and debugging the control system
program. In addition, Global Scripter includes a Deployment Mode option for non-EAP certified technicians and
installers.

Extron Toolbelt facilitates the management and troubleshooting of Pro Series control systems, allowing users
to easily perform a variety of different tasks from a single application. IR Learner Pro is used to create custom
files for controlling IR devices. IR Learner Pro can also be used to modify existing IR files.

Extron Library and Reserved Keywords


As with all high level programming languages, there are certain words reserved for system use in
programming. These words cannot be used as identifiers. Extron has added the Extron Library to interface with
the Extron Pro Series Control System. The Extron Library contains ControlScript or built-in functions that allow
the Python interpreter to interact with specific control system objects defined in the firmware of the control
processors and user interfaces. This document, available from the Help menu in Global Scripter, describes
each element of the library with a usage example.

Page 6
Extron Control System Programming Using Python

Global Scripter Introduction


Global Scripter is an integrated design environment that is used to program Extron Pro Series Control Systems.
Global Scripter requires that the user/programmer maintain an Extron Insider Account and is licensed to use
the application. Licensing will occur in the same manner as Global Configurator Plus and Global Configurator
Professional with both online and offline options. Please contact your Extron representative if there are
additional questions regarding licensing and future certification requirements.

Programming Interface
Global Scripter is comprised of menus, toolbars, and many individual windows that provide insight into different
views of the control system. By default, the application is divided into four main areas: System Manager, Code
Editor and Layout window, Diagnostic windows, and status bar.

Page 7
Extron Control System Programming Using Python

System Manager
System Manager provides tools to add control processors, user interfaces, user interface layout files, code
files, and IR files to a project. Once added, these items are organized in a tree view.

Projects are the highest level of the System Manager. Currently, only one project can be open at a time in
Global Scripter.

The first control processor added to a project hosts the programming of the system and will contain the main.py
entry code file.

Code Editor
When double-clicked in the System Manager, a code file opens in the syntax highlighting editor, the Code
Editor window.

Page 8
Extron Control System Programming Using Python

The Code Editor window provides typical editing functions and programming-specific features such as
trimming of leading, trailing spaces, and conversion of tabs to spaces. (These options are available in the
Blank Operations sub-menu of the Edit menu.) Blocks of code can be commented or uncommented by using
the Comment/Uncomment menu items.

Various appearance options for the Code Editor are available pertaining to line numbering, syntax highlighting,
tab conversion settings, and adding a vertical ruler. These functions can be accessed through the menus,
hotkeys, and the context menus that are available when right-clicking inside the editing window.

Layout Window
The Layout window is visible in the Code Editor area by double-clicking on a layout file, touchpanel, or
eBUS device in the System Manager, or selecting View Layout from the drop-down menu. These options are
also available in a context menu by right-clicking on the file or device. The ability to view a layout directly in
Global Scripter is beneficial when programming user interface functions.

Page 9
Extron Control System Programming Using Python

The Layout window displays the button layout for eBUS devices, the GUI associated with a touchpanel, and the
bezel for that device. The Layout window provides the option to view control ID information for buttons
(including each state), levels, labels, and knobs on pages, modal pages, and popups. Using the Code
Generation option in the Layout window of an eBUS or touchpanel device, you are able to automatically
generate blocks of code for these user interface objects as well. After setting the identifier name used for the UI
Host, choose the desired code options and select the interface object. Click the Generate button than paste
the copied code where needed in the program.

Diagnostic Windows
By default the Diagnostic windows are shown as a tabbed collection at the bottom of the application. Each tab
can be "torn" off and placed anywhere on the computer screen either inside or outside of Global Scripter. If
these windows get displaced or moved off the screen, they can be reset from the Application Settings in the
Tools menu.

Page 10
Extron Control System Programming Using Python

Properties Panel
Information regarding a selected item in the System Manager is entered and viewed in Properties.

Build Messages Panel


Build Messages display information, warnings, and errors regarding build process for the currently selected
system. These items can be saved, cleared, and hidden if desired.

Trace Messages Panel


Trace Messages display the output of the print command for a currently running program. These messages
can be filtered, displayed as necessary, and can be useful for debugging.

Variables Panel
The Variables panel displays the local and global variables of your program each time it encounters a
breakpoint when running the program in debug mode.

Watch Variables Panel


The Watch Variables panel is used to inspect the behavior of specific variables, copied from the Variables
panel, while the program is running.

Program Log Panel


The Program Log provides details about the current state of the program load and execution.

Find Results Panel


Find Results displays the results of the latest find operation in the current Code Editor window. This panel takes
focus when starting a find.

Page 11
Extron Control System Programming Using Python

Status Bar
The status bar provides application licensing, cursor position, keyboard lock state, and debug mode
information at a glance.

Page 12
Extron Control System Programming Using Python

Python Basics
Python is an object oriented, high level programming language with an easy-to-learn structure and syntax. It is
an interpreted language that requires no compilation prior to execution. Python programs are stored in a plain
text file with a .py extension. This text file can be easily read using any plain text file reader/editor.

Conventions and Syntax


Python is unique among programming languages in that punctuation and special characters are less
important, but the use of indentation to group and promote program flow is crucial. Whitespace is important in
Python at the beginning of each line. Spaces, tabs, and linefeeds all create whitespace in a program. However,
some editors intended for program code development convert tabs to a series of spaces. When creating
Python programs or utilizing parts of programs saved from other editors, be aware of the way in which the
editor handles tabs and spaces. Blocks of code are defined by their indentation, not by any punctuation or
“BEGIN” and “END” statements. This use of whitespace makes Python code very easy to read.

Python is case sensitive. Although the identifiers, Touch_Panel, touch_panel, and TOUCH_PANEL, have the
same letters and indeed may refer to the same physical object, a Python program would interpret these as
distinct items since the cases do not match. When creating a Python program, the programmer must be aware
of the case that the identifiers use. A solution is to use only uppercase or lowercase characters, however this is
not recommended and doing so may affect the program’s readability.

The Python Software Foundation has many helpful documents on the python.org website that can assist in
standard practices used in Python programming such as the Style Guide for Python Code referred to as PEP 8.
See Appendix A for this and other references.

Standard Practices for Extron Programming


Extron will defer to the PEP 8 (Python Enhancement Proposal number 8), Style Guide for Python Code in
regards to formatting code files. Additionally, the following guidelines will be used in the examples and
programs provided by Extron.

General Recommendations
l Make the code as readable as possible. It will be read many more times than it is written.

l Comment the code efficiently with enough information to add to the understanding of the code. Ensure
that the comments do not contradict the code.

l Modules should stand on their own and only require the data passed to complete the assigned task.

l Use only one statement per line, with the possible exception of list comprehensions.

Refer to PEP 20, The Zen of Python for other beneficial recommendations.

Identifiers
In general, identifiers will follow “Camel Case” where the first letter of each unique word will be capitalized. In
programs, examples, and modules, Extron will use CamelCase for classes and their properties and methods.

Page 13
Extron Control System Programming Using Python

For parameters to functions that are not class properties, we will use mixedCase where the first letter of the first
word is lowercase and all subsequent words are title case. Single letter identifiers will not be used. Constants
will use only uppercase characters with an underscore character between words. It has been determined that
name_with_underscores was not very readable, leading to long lines or many multi-line expressions. With the
exception of constants, underscore characters will not be used in identifiers unless required for a specific
Python purpose. Since variables in Python can store any type of data, naming variables with sufficient clarity is
required. In the examples provided by Extron, identifiers such as the following will be used to clearly identify the
intended data type to be stored.

Description Example Usage


Device Object Room103Processor,
Room103PodiumTLP

Interface Object Room103Projector

Button Object BlurayPlayButton


MainPageStartButton

Level Object MainAudioLevel


Mic1Level

Label Object RoomNameLabel


PageNameLabel

Knob Object MainVolumeKnob

Wait Object WaitResetTextLabel


WaitPopupDelay

Clock Object ScheduledShutdownClock

Line Length and Line Continuation


Line length is kept to a maximum of 80 characters including the paragraph mark. Implicit line continuation is
used in instances where lines longer than 80 characters are needed. The use of the backslash character for
line continuation is avoided except where implicit line continuation is not allowed, such as the import
statements in the default entry file. The Code Editor window can show a column ruler at any column location.
By default, this ruler is set to 80 characters and visible.

Strings
Strings are enclosed in single quotes. Multi-line strings will use three single quotes to begin the string and three
single quotes on a separate line to end the string. Double quotes are only used to encapsulate a string that
includes a single quote. Documentation strings still use the triple double-quote marks (""") as indicated in the
PEP 8 and PEP 257 documents.

ID Ranges
eBUS devices and the CCI Pro 700 contain fixed control IDs and states. Touchpanel user interface design
layouts are created using GUI Designer software, with the option to begin with templates provided by Extron or
build a new layout. Pages, popup pages, hard buttons, soft buttons, labels, and other controls on a user
interface are assigned ID numbers within GUI Designer, and cannot be changed outside of the GUI Designer

Page 14
Extron Control System Programming Using Python

project. For details on ID number assignments, refer to the documentation within GUI Designer. This control ID
information is used when programming user interface functions in Global Scripter. Once a GUI layout,
touchpanel, or eBUS device is imported into Global Scripter, the Layout window provides the ability to view the
layout file with associated control ID and state information directly within Global Scripter.

Interpreter and Libraries


Programs and modules written in Python are executed inside of a shell interpreter protecting both the control
system and programmer from unforeseen issues should a program contain unchecked errors. To further
protect the security and stability of the system, not all Python elements are allowed as part of the control
system program. Some elements have been replaced with specific functions appropriate to a control system
running on a device that does not have a console output. For example, the Python print command would
typically display characters on the console of the computer running the interpreter. However, in the Pro Series
Control System the print command sends a user trace statement to be displayed in the Trace Messages panel
and Toolbelt application. A list of all excluded items can be found in Appendix B.

Additionally, Extron has extended the Python programming language using Python libraries to include elements
specific to AV control systems. These modules are named for specific communication or functions appropriate
to a control system. This implementation of the interpreter and the associated libraries is called ControlScript.

Objects and Programming


The Python language supports both procedural and functional programming as well as object oriented
programming. All of these can be used in the implementation of a Pro Series Control System. This makes the
writing and reading of programs easy to learn, implement, and follow for someone who is familiar with other
programming languages and is just now learning Python.

An object has both properties and methods. A property describes the object whereas a method takes some
action with the object.

Lists and Dictionaries


In Python, data can be stored in many ways from simple variables to lists, and key pairs of data stored in
dictionaries. A list is simply an ordered collection of values that do not have to all be of the same type. For
example, the following is a list of numbers:

Numbers = [1, 2, 3.0, '4', 'five', 2*3, '8-1', 8.0, 9, 0xA,]

Any element of a list is referenced by using an index (remember in Python elements are indexed beginning at 0)
such as Numbers[4] to return the string 'five' or Numbers[5] to return the integer with the value 6. (The
evaluation of 2*3 was made before storing the integer 6 in the fifth index of the list Numbers.) A list can be used
in any place where an array or collection might be used in other languages.

In a control system program, a list can be used for many things including names of functions in an IR file, a
group of mutually exclusive objects, a collection of relay ports, and more.

Dictionaries store items as a key and value pair. Since this is not an ordered list, values can only be retrieved
through the use of the key. Although this may sound limiting it can be very powerful as will be seen in some

Page 15
Extron Control System Programming Using Python

examples later. The key in a dictionary is usually defined by a string literal (or any immutable object) followed by
a colon then the value to be paired with that string. (Remember, strings can be written using either a double
quote pair or a single quote pair. Either is acceptable, but for this document single quote pairs will be used
except for where a string contains a single quote.)

For example, a dictionary could be used to define the potential passcodes for access to certain features of a
system:

PassCodes = {
'admin': '1234',
'user': '5678',
'null': '',
}

When comparing the entered passcode to the dictionary, the matching key would provide the appropriate level
of access as programmed. Additionally, these passcode values can be changed programmatically since
dictionary objects are mutable.

Loops and Iterators


One advantage of Python is the ability to dynamically loop (or iterate) based upon the elements in a list. In the
following example, a loop will run six times generating a button object (a ControlScript class object that will be
described later) for each item in the InputButtons list which will be appended to the InputButtonObjects list.
Additionally, TouchPanel is instantiated as a UIDevice. The variable InputButtonID is set equal to the value of
each item in the list as the loop runs. When the loop is initiated, InputButtonID will equal 601, the second run
InputButtonID will equal 602, and so on through the list.

As additional inputs or buttons are added to the system the elements of the list InputButtons can change.
However, the reference (Line 3) to the loop remains the list of the elements.

InputButtons = [601, 602, 603, 604, 605, 606,]


InputButtonObjects = []
for InputButtonID in InputButtons:
InputButtonObjects.append(Button(TouchPanel, InputButtonID))

For example, if the list is modified to include four more buttons for additional inputs, then the loop will run a total
of ten times defining the buttons. Keep in mind that elements in the list do not need to be consecutive.

InputButtons = [601, 602, 603, 604, 605, 606, 609, 611, 617, 614,]
InputButtonObjects = []
for InputButtonID in InputButtons:
InputButtonObjects.append(Button(TouchPanel, InputButtonID))

Once the button objects are defined, a function can be created to assign a value to a variable based upon
which button is pressed. Iterator loops like these will be used in several examples shown in this document.

Page 16
Extron Control System Programming Using Python

The best way to understand how Extron has implemented Python is to begin using it. The following sections will
step through several programs and describe the respective ControlScript language elements that are used.
This document is not designed to be an all-encompassing guide to programming the Extron Pro Series Control
System, nor is it a replacement for the training classes. It is an introduction to help make the training classes
more beneficial to you.

Page 17
Extron Control System Programming Using Python

Programming from the Beginning

Creating a Project in Global Scripter


A project in Global Scripter consists of many different elements: control processors, user interfaces, code files,
and other associated files such as a .gdl – GUI Designer Layout. These files can also be shared between
systems within a single project. When a file that has been associated with a project is updated, each system to
which that file is referenced will also be updated. A project file is stored with a .gs file extension.

To create a new project file, select New from the File menu or from the toolbar. Details about the project are
accessed from Project Properties within the Project menu or, with Project selected in the System Manager,
the Properties panel.

Once a project is created, systems can be added by clicking the Plus icon or object menu icon beside the
project name in the System Manager, or by right-clicking the project, and selecting the Add Controller option.
This opens the Add Controller dialog box.

Select the appropriate control processor, then enter the desired Device Alias that will be referenced in the
program. The alias should clearly identify the device to avoid confusion, or ambiguity. If the Name field is not
modified, the program will use a combination of the control processor's model name and IP address.

Enter the network connection details of the control processor. For control processors with dedicated
AV LAN ports, you will need to enter the IP address of the control processor, as well as the IP address of the
AV LAN port. The isolated AV LAN ports are designed to control local AV devices, and safeguard them from
outside intrusion or interference.

Page 18
Extron Control System Programming Using Python

If the device is on the same network as the programming computer, then verify communication with the
processor. Once all the properties are set as desired, click the Add button.

As the first control processor is added to a system, a Python code file, main.py, is generated. This file contains
statements to import the Extron libraries and should contain references to any other code file used in the
system. These import statements are discussed in more detail in latter sections of this document.

To complete the system, add the user interfaces and/or secondary control processors as necessary. This can
be accomplished by clicking the Plus icon or object menu icon beside the primary control processor in the
System Manager, and selecting the appropriate option. Additionally, these items can be added from the
context menu available by right-clicking the primary control processor.

Page 19
Extron Control System Programming Using Python

When Add TouchLink Panel is selected, the Add TouchLink Touchpanel dialog box launches. Select the
desired touchpanel type and enter the properties as required for that device. A GUI Designer layout file is not
required when adding a touchpanel to the project. One can be assigned later through the Properties menu
option when the user interface is selected in the System Manager.

Page 20
Extron Control System Programming Using Python

When adding a TouchLink Pro touchpanel to a control processor with dedicated AV LAN ports, you will also
need to select whether the touchpanel resides on the LAN or AV LAN. Extron software applications on the
LAN side can initiate a connection to the AV LAN side for firmware updates as well as loading a program for
devices connected to the AV LAN. Once the connection is successfully established, the data flow between the
LAN and AV LAN is bidirectional. However, no connections can be initiated from the AV LAN to the LAN.

When Add eBUS Device is selected, the Add eBUS Device dialog box launches. Select the desired
eBUS device and enter the required device properties.

Page 21
Extron Control System Programming Using Python

Other items such as layout files, sound files, drawings, and system documentation can all be added as system
files by clicking the Plus icon or by right-clicking the desired system and selecting Add Existing File from the
context menu.

Once the control processors and user interfaces have been added to the project, the system can be
programmed using the entry code file, main.py.

The main.py Entry Code File


Each system maintains a specific Python code file referred to as the Entry Code File. This file has been given
the name "main.py" since it is used as the main program run by the primary control processor. All other
program files, and modules, are imported to this program file.

Import Libraries
The first section of the main.py file includes the default import statements for the typical Extron Library objects.

from extronlib import event, Version


from extronlib.device import eBUSDevice, ProcessorDevice, UIDevice
from extronlib.interface import (ContactInterface, DigitalIOInterface,
EthernetClientInterface, EthernetServerInterfaceEx, FlexIOInterface,
IRInterface, RelayInterface, SerialInterface, SWPowerInterface,
VolumeInterface)
from extronlib.ui import Button, Knob, Label, Level
from extronlib.system import Clock, MESet, Wait

Programmer-defined classes and methods located in other Python files can be imported to the main.py file
after the initial Extron Library import statements. These files must be added to the System Manager using the
Add New Code File option in the System Manager.

The AV Equivalent of "Hello World"


Most programming languages begin any guide or tutorial with a program that allows a programmer to see the
results from just a few commands, and strings. The traditional first program is to have the programmed device
send the words "Hello World" to a primary output device. Python is no different. In Python, the following line of
code will display the words "Hello World" to the console.

print('Hello World!')

In the Extron Pro Series control processor there is no “primary output device” for displaying a message,
therefore any print message is output to the Trace Messages panel if Trace Messages have been started.
When programming, only the print statement is needed to display the message.

print('Hello World!')

Page 22
Extron Control System Programming Using Python

By adding a user interface to the project we can show the "Hello World!" message on the user interface. To
send messages for display on a touchpanel, the user interface along with its control objects must be
instantiated. Instantiation of these objects in ControlScript is easy using the Extron Library API (extronlib) and its
defined classes. In the following example, a user interface with an assigned GUI Designer layout file is added to
the project in association with a processor. The user interface device is instantiated in the program as
TouchPanel using the UIDevice class and its programmer-defined alias "TLP". The label MessageLabel of
the assigned GUI Designer layout is instantiated using the Label class and its button ID of "2". With the SetText
method for the object MessageLabel, the "Hello World!" message will now appear in the touchpanel's label
when running the program.

TouchPanel = UIDevice('TLP')
# Send Message to Trace window
print('Hello World!')

# Send Message to label with ID 2 on the UI Device TouchPanel


MessageLabel = Label(TouchPanel, 2)
MessageLabel.SetText('Hello World!')

However interesting this may be, a complete beginner project for a control system should include interaction
with a control processor and the devices connected to its interface ports, not just a message sent to a
diagnostic log or a touchpanel.

To include interaction, a processor must be instantiated along with any ports that will be used for control just
like a user interface. Each device (control processor or user interface) or device interface (control port) that is
to be programmed in the control system needs to be instantiated prior to use. Instantiating the device or device
interface makes the correlation between the identifier and the physical hardware represented by the Device
Alias. For example, the following processor is defined using the ProcessorDevice class and its programmer-
defined alias "Processor". Its relay port is defined using the RelayInterface class, its associated processor by
identifier name, and port ID - 'RLY1'.

ProProcessor = ProcessorDevice('Processor')
Relay1 = RelayInterface(ProProcessor, 'RLY1')

Now that the processor and its port have been defined, user interaction needs to be included in the program to
finish this beginner project. In this example, a toggle button will, when pressed, display the "Hello World"
message in the Trace Message panel, change visually, and open or close the identified relay port. As a best
practice, this section of code has been given a comment that briefly explains the intended functionality of the
program. Just as a user interface's label needs to be instantiated for use, so will the user interface's button. For
a button, the Button class is used with parameters for the appropriate user interface and layout ID number, in
this example, 1.

The press action for the toggle button is created in a custom function Button1Press. Defined by indentation,
the first item in the function is a documentation string """Button 1 on Welcome Page""" that provides more
information about the function, followed by the print message 'Hello World!'. A conditional statement
determines what action will take place depending on the visual state of the defined user interface button. The
IDs of the visual states for the button are taken from the Control States identified in GUI Designer. Depending

Page 23
Extron Control System Programming Using Python

on the state of the button, the processor's relay will open or close when the button is pressed. On the last line of
the program, the instantiated button Button1 of the TouchPanel device is assigned a Pressed event that runs
the Button1Press function whenever Button1 is pressed. When all this code is uploaded to a control
processor and the button pressed, the beginner project for Extron Control Programming is complete.

# Toggle the state of a relay when a button is pressed.


Button1 = Button(TouchPanel, 1)

def Button1Press(button, state):


"""Button 1 on Welcome Page"""
print('Hello World!')
if button.State == 1:
button.SetState(0)
Relay1.SetState('Open')
else:
button.SetState(1)
Relay1.SetState('Close')

Button1.Pressed = Button1Press

Regardless of previous Python exposure, Extron is confident that most programmers will find the lines of code
written in this beginner exercise very readable, even if the items are not familiar. The program is in an outline
format, specified in Python, and determines the hierarchy of the program. As mentioned earlier, whitespace is
important in Python which is why the defined function is indented. Additionally, there are no required line
ending marks such as a semicolon.

The Event Decorator


On the last line of the program the Button1Press function is assigned to the Pressed method for the button
class object Button1 which causes the function to be called every time Button1 is pressed. For a function with
very few lines of code, this does not pose much of a problem for readability, but if the function becomes very
long then it may become difficult for a reader, much less the programmer, to associate the button instantiation
with the function call. Extron has created a Python object that can be used to clarify the code above, further
improving readability – the event decorator.

By using an event decorator, the button definition and event call are defined first, prior to defining the function
to increase readability.

Using the event decorator, Button1 and Pressed are attributed to an event. Then, the event decorator's
parameter for Button1 is attributed to the button parameter of the Button1Press function. Just as the original
code example, when the button of the touchpanel is pressed the Button1Press function will run.

Page 24
Extron Control System Programming Using Python

# Toggle the state of a relay when a button is pressed.


Button1 = Button(TouchPanel, 1)

@event(Button1, 'Pressed')
def Button1Press(button, state):
"""Button 1 on Welcome Page"""
print('Hello World!') # Send Message to Trace window
if button.State == 1:
button.SetState(0)
dvRelay1.SetState('Open')
else:
button.SetState(1)
dvRelay1.SetState('Close')

Notice that the event decorator is preceded by an "@" symbol as is required in Python. The @event decorator
will be used throughout this document for most events. However, either method is acceptable and will achieve
the same results.

There are many different uses of the event decorator in ControlScript but all will be used to process an input to
the program.

Compound Event Decorators


Compound Event Decorators can replace multiple event decorators by accepting lists as parameters. In the
following example, a series of stacked events are used for button presses and releases. These can be
replaced with a compound event. The following code below shows stacked events. These can be converted to
a single event for each function.

Page 25
Extron Control System Programming Using Python

BtnInputHDMI = Button(TLP1025RoomA, 1)
BtnInputDecoder = Button(TLP1025RoomA, 2)
InputButtons = [BtnInputDecoder, BtnInputHDMI]

BtnSMDPlay = Button(TLP1025RoomA, 3)
BtnSMDPause = Button(TLP1025RoomA, 4)
BtnSMDStop = Button(TLP1025RoomA, 5)
TransportButtons = [BtnSMDPlay, BtnSMDPause, BtnSMDStop]

LblPlayerState = Label(TLP1025RoomA, 10)


LblCurrentTimeCode = Label(TLP1025RoomA, 11)

# Stacked events for Play, Stop and Pause for SMD


@event(BtnSMDPlay, 'Pressed')
@event(BtnSMDPause, 'Pressed')
@event(BtnSMDStop, 'Pressed')
def BtnSMDTransportEvent(button, state):
print(button.Name, state)
if button == BtnSMDPlay:
SMDPort.Send('wS1*1PLYR\r')
elif button == BtnSMDStop:
SMDPort.Send('wO1PLYR\r')
elif button == BtnSMDPause:
SMDPort.Send('wE1PLYR\r')

# Stacked events for Input selection for SMD


@event(BtnInputDecoder, 'Pressed')
@event(BtnInputDecoder, 'Released')
@event(BtnInputHDMI, 'Pressed')
@event(BtnInputHDMI, 'Released')
def BtnInputEvent(button, state):
print(button.Name, state)
if button == BtnInputDecoder:
SMDPort.Send('1!')
elif button == BtnInputHDMI:
SMDPort.Send('2!')
if state == 'Pressed':
button.SetState(1)
elif state == 'Released':
button.SetState(0)

The program contains a list called TransportButtons that contains the three button objects for Play, Pause,
and Stop. By replacing the button name with the TransportButtons list, a single event can be used for this
section. In this case, a single list replaces the three buttons, BtnSMDPlay, BtnSMDPause, and
BtnSMDStop, in the stacked events.

Page 26
Extron Control System Programming Using Python

@event(TransportButtons, 'Pressed')
def BtnSMDTransportEvent(button, state):
print(button.Name, state)
if button == BtnSMDPlay:
SMDPort.Send('wS1*1PLYR\r')
elif button == BtnSMDStop:
SMDPort.Send('wO1PLYR\r')
elif button == BtnSMDPause:
SMDPort.Send('wE1PLYR\r')

Similarly, the stacked events for input selection can be made into a single compound event. In this example, a
list is used for both parameters.

ButtonEventList = ['Pressed', 'Released', 'Held', 'Repeated', 'Tapped']


# Compound events for Input selection for SMD
@event(InputButtons, ButtonEventList)
def BtnInputEvent(button, state):
print(button.Name, state)
if button == BtnInputDecoder:
SMDPort.Send('1!')
elif button == BtnInputHDMI:
SMDPort.Send('2!')
if state == 'Pressed':
button.SetState(1)
elif state == 'Released':
button.SetState(0)

After uploading this program, pressing any of these buttons on a touchpanel provides the same outcome as
when stacked event decorators were used.

Using Bookmarks
Global Scripter enables you to bookmark locations within the code file, making it easier to navigate back and
forth through the program. Bookmarks enable you to get to certain locations very easily such as to flag code for
future reuse in a different location of the program.

To add a bookmark at the beginning of a line, click on the area to the left of the line number. Clicking this area
again will clear the bookmark. Bookmarks are placed at the beginning of a line and will stay with the line if
additional carriage returns are placed at the end of the previous line. If, however, carriage returns are placed at
the beginning of a bookmarked line, the bookmark will remain with the original line number.

Bookmark options can be accessed through the Bookmark submenu within the View menu, or by using the
toolbar or keyboard shortcuts. The Bookmark submenu indicates the various commands that are available
and the keystrokes to enable them directly.

To navigate between bookmarks, select Next Bookmark from the Bookmark submenu. You will notice that
the cursor jumps to the next bookmark. Select Next Bookmark again to continue moving to the next

Page 27
Extron Control System Programming Using Python

bookmarks that are placed in the program. To return to previous bookmarks, select Previous Bookmark from
the submenu.

Bookmarks are applicable, not only to a single code file, but to multiple code files in your project. You can either
clear bookmarks in the currently active code file by selecting Clear Bookmarks from the Bookmark
submenu, or clear bookmarks in all code files by selecting Clear All Bookmarks.

The following keyboard shortcuts correspond to the options within the Bookmark submenu. For a complete list
of shortcuts, please refer to the documentation within Global Scripter.

Keyboard Shortcut Command


<Ctrl + F2> Toggle Bookmark

<Shift + F2> Previous Bookmark

<F2> Next Bookmark

<Ctrl + Shift + F2> Clear Bookmarks

<Alt + Shift + F2> Previous Bookmark in Project

<Alt + F2> Next Bookmark in Project

Page 28
Extron Control System Programming Using Python

Programming Touchpanel Interface Navigation


In order to program a TouchLink Pro touchpanel, it must first be added to the System Manager, then
instantiated using the alias provided in the Device Properties. All control objects of a touchpanel layout to be
programmed need to be instantiated. The process of instantiation for control objects is as follows: create an
identifier that defines the object (button, label, level, etc.) and its ID number or name from the layout, then
define the function to be associated with the button. Creating the navigation for a user interface is similar to
programming the button in the "Hello World" example. However, rather than accessing the method of the
RelayInterface, methods of the UIDevice class will be accessed to trigger the user interface to show a page,
ShowPage( ). This method uses either an integer representing the ID of the page or its name defined in GUI
Designer. Using the page name, as opposed to the ID number, increases readability of the code while
performing the same task. Remember, the name needs to exactly match the name specified in GUI Designer.

The following examples use the Turbulence template for the TLP Pro 1025T. After instantiating the user
interface devices, the buttons that affect the navigation are defined. The Start button StartButton is
instantiated, then associated with a Pressed event that will cause the user interface layout page with ID 6 to be
shown when the button is pressed. Next, the System Off button SystemOffButton is instantiated and is
associated with a Pressed event that will show the page, ID 10.

TLP = UIDevice('PrimaryTouchPanel')

StartButton = Button(TLP, 8000)


@event(StartButton, 'Pressed')
def StartButtonPressed(button, state):
TLP.ShowPage(6)

SystemOffButton = Button(TLP, 8022)


@event(SystemOffButton, 'Pressed')
def SystemOffButtonPressed(button, state):
TLP.ShowPage(10)

The following creates the same button functionality, however it uses button and page names as opposed to
IDs.

TLP = UIDevice('PrimaryTouchPanel')

StartButton = Button(TLP, 'Start')


@event(StartButton, 'Pressed')
def StartButtonPressed(button, state):
TLP.ShowPage('Main SD')

SystemOffButton = Button(TLP, 'System Off')


@event(SystemOffButton, 'Pressed')
def SystemOffButtonPressed(button, state):
TLP.ShowPage('Start')

Page 29
Extron Control System Programming Using Python

User interface navigation of popup pages is programmed in a similar manner. Popup pages are shown,
ShowPopup( ), or hidden, HidePopup( ) also by using methods of the UIDevice class. The code following
example shows and hides the Start Audio Control popup.

When pressed, the Start Audio Control button will show the Start Audio Control popup page for an infinite
duration of time. Then when the Close Start Audio Control button is pressed, the Start Audio Control popup will
be hidden.

StartAudioControl = Button(TLP, 'Start Audio Control')


@event(StartAudioControl, 'Pressed' )
def StartAudioControlPressed(button, state):
TLP.ShowPopup('Start Audio Control', 0)

CloseStartAudioControl = Button(TLP, 'Close Start Audio')


@event(CloseStartAudioControl, 'Pressed')
def CloseStartAudioControlPressed(button, state):
TLP.HidePopup('Start Audio Control')

In each of the previous examples, page navigation is handled directly through a button Pressed event calling a
discrete function. It could just as easily be done by calling a custom function (similar to calling a macro in
Global Configurator Professional). In the following example, a single custom function will be used by several
buttons to show the appropriate popup pages for each.

In the Turbulence template for the TLP Pro 1025T touchpanel, the sources on the main page are as shown:

In the following example, each button is instantiated, then a compound event decorator is created for each
source button using the SourceButtons list. The SelectInputButtonPressed function will first send a
message to the Trace Window that will show what button has been pressed. The following conditional
statements will evaluate which button has been selected by its ID number and then change the value of a
variable. The value of the variable is used in another custom function ShowSourcePopup.

Page 30
Extron Control System Programming Using Python

SelectLaptop = Button(TLP, 8050)


SelectPC = Button(TLP, 8052)
SelectBluray = Button(TLP, 8054)
SelectDocCam = Button(TLP, 8058)
SelectTuner = Button(TLP, 8060)
SelectAux = Button(TLP, 8062)
SourceButtons = [SelectLaptop, SelectPC, SelectBluray, SelectDocCam,
SelectTuner, SelectAux,]

@event(SourceButtons, 'Pressed')
def SelectInputButtonPressed(button, state):
print('button pressed: {0}, ID – {1}'.format(button.Name, button.ID))
if button.ID == 8050:
CurrentInput = 'Laptop'
elif button.ID == 8052:
CurrentInput = 'PC'
elif button.ID == 8054:
CurrentInput = 'Bluray'
elif button.ID == 8058:
CurrentInput = 'DocCam'
elif button.ID == 8060:
CurrentInput = 'Tuner'
elif button.ID == 8062:
CurrentInput = 'Aux'
else:
CurrentInput = 'NotSelected'
print('CurrentInput: {0}'.format(CurrentInput))
ShowSourcePopup(CurrentInput, TLP)

The ShowSourcePopup function can be defined at any point in the program. The function evaluates the
CurrentInput variable and shows the specified popup accordingly.

def ShowSourcePopup(input, host):


if input is 'Laptop':
host.ShowPopup('Laptop 1')
elif input is 'PC':
host.ShowPopup('PC 1')
elif input is 'Bluray':
host.ShowPopup('Blu-ray 1')
elif input is 'DocCam':
host.ShowPopup('Doc Cam 1')
elif input is 'Tuner':
host.ShowPopup('Tuner 1')
elif input is 'Aux':
host.ShowPopup('AUX 1')
else:
print('No matching popup')

Page 31
Extron Control System Programming Using Python

This works very well for one user interface and can be easily adapted for successful implementation on
another user interface, as long as it uses the same source button ID numbers and names for the popup pages.
(Thankfully when using the default Extron templates this does occur!) For both panels to call the same function,
the second panel (TLP725) and source buttons need to be instantiated along with the associated events.

Finally, another call to the ShowSourcePopup function is necessary. One call is made for the primary
touchpanel and one for the new touchpanel that has been defined as TLP725. Now, whenever a source button
on either touchpanel is selected it will cause both panels to show the same popup, if it is available on both
panels. The following is the full code for this.

Page 32
Extron Control System Programming Using Python

SelectLaptop = Button(TLP, 8050)


SelectPC = Button(TLP, 8052)
SelectBluray = Button(TLP, 8054)
SelectDocCam = Button(TLP, 8058)
SelectTuner = Button(TLP, 8060)
SelectAux = Button(TLP, 8062)
SourceButtons = [SelectLaptop, SelectPC, SelectBluray, SelectDocCam,
SelectTuner, SelectAux,]

TLP725 = UIDevice('SecondTouchPanel')

SelectLaptop725 = Button(TLP725, 8050)


SelectPC725 = Button(TLP725, 8052)
SelectBluray725 = Button(TLP725, 8054)
SelectDocCam725 = Button(TLP725, 8058)
SelectTuner725 = Button(TLP725, 8060)
SourceButtons725 = [SelectLaptop725, SelectPC725, SelectBluray725, SelectDocCam725,
SelectTuner725,]

@event(SourceButtons725, 'Pressed')
@event(SourceButtons, 'Pressed')
def SelectInputButtonPressed(button, state):
print('button pressed: {0}, ID – {1}'.format(button.Name, button.ID))
if button.ID == 8050:
CurrentInput = 'Laptop'
elif button.ID == 8052:
CurrentInput = 'PC'
elif button.ID == 8054:
CurrentInput = 'Bluray'
elif button.ID == 8058:
CurrentInput = 'DocCam'
elif button.ID == 8060:
CurrentInput = 'Tuner'
elif button.ID == 8062:
CurrentInput = 'Aux'
else:
CurrentInput = 'NotSelected'
print('CurrentInput: {0}'.format(CurrentInput))
ShowSourcePopup(CurrentInput, TLP)
ShowSourcePopup(CurrentInput, TLP725)

def ShowSourcePopup(input, host):


if input is 'Laptop':
host.ShowPopup('Laptop 1')
elif input is 'PC':
host.ShowPopup('PC 1')
elif input is 'Bluray':
host.ShowPopup('Blu-ray 1')
elif input is 'DocCam':
host.ShowPopup('Doc Cam 1')

Page 33
Extron Control System Programming Using Python

elif input is 'Tuner':


host.ShowPopup('Tuner 1')
elif input is 'Aux':
if host is TLP725:
host.HidePopupGroup(1)
print('TLP725 does not contain an Aux Popup page')
else:
host.ShowPopup('AUX 1')
else:
print('No matching popup')

HidePopupGroup will hide only the popups in a specified group. For instance in the Turbulence template, a
group has been created for the source device transports popup pages. This group has the ID 1. In the example
above, the HidePopupGroup method is used to hide any popup from the group. This is shown on the TLP725
when the Aux source is selected on the TLP touchpanel.

In addition to the UIDevice methods already discussed, one more method can be used for user interface
navigation: HideAllPopups( ). The HideAllPopups method does not take any arguments and will hide all popups
on every page.

TLP.HideAllPopups()

Page 34
Extron Control System Programming Using Python

Programming eBUS Devices


eBUS devices connect to an IPCP Pro control processor using the eBUS port on the back of the control
processor. Each eBUS device is given a unique ID for the assigned control processor by physically setting a
series of DIP switches on the eBUS device (see the Setup Guide associated with the device for details on
setting the ID). In order to program an eBUS device, add it to the System Manager, then instantiate it using the
alias provided for the Device Properties.

Before being programmed, all buttons, knobs, or levels of an eBUS button panel must be instantiated. The
process for these control objects is similar to that of other UI devices: create an identifier that defines the object
and assign the appropriate class object (Button, Level, or Knob) using the identifier of the eBUS panel and the
ID number or name from the layout. Then the objects can be used in events, functions, or other actions as
necessary. Methods of the eBUSDevice class can be used to access other functions associated with
eBUS button panels, such as setting an inactivity timer or sleep timer for the button panel.

The layout of the eBUS button panel can be viewed in Global Scripter showing the object ID numbers and,
when selected, the available states of each button. Notice in the following image that the four states of the ON
button are shown; Dim (state 1), Off (state 0), White (state 2), and Red (state 4). Since this device does not
include state 3, that state cannot be programmed.

The following example uses an EBP 100 button panel. After instantiating the IPCP Pro control processor and
eBUS device, the button objects PowerOnBtn, PowerOffBtn are instantiated along with the associated
Pressed events. These Pressed events will cause an instantiated relay port on the IPCP Pro control processor
to turn on and off a display using an AC power controller such as the Extron IPL T PC 1, as well as setting the
associated button to White (state 2) when on and Dim (state 1) when off.

Page 35
Extron Control System Programming Using Python

Processor = ProcessorDevice('IPCPPro250')
EBP = eBUSDevice(Processor, 'eBUS100')
PowerOnBtn = Button(EBP, 60021) # EBP button for Power On
PowerOffBtn = Button(EBP, 60022) # EBP button for Power Off
Relay1 = RelayInterface(Processor, 'RLY1') # Relay for display power control

# eBUS panel button states used in SetState Method of the eBUS device
Dim = 1
White = 2
Red = 4
Off = 0

# Close the relay when the Power On button is pressed


@event(PowerOnBtn, 'Pressed')
def PowerOnBtnPressed(button, state):
if Relay1.State == 'Open':
print('Power On')
PowerOnBtn.SetState(White)
PowerOffBtn.SetState(Dim)
Relay1.SetState('Close')

# Open the relay when the Power Off button is pressed


@event(PowerOffBtn, 'Pressed')
def PowerOffBtnPressed(button, state):
if Relay1.State == 'Close':
print('Power Off')
PowerOffBtn.SetState(White)
PowerOnBtn.SetState(Dim)
Relay1.SetState('Open')

Continuing in the same program, in the example that follows, the first three lines instantiate the VolumeKnob
and VolumeLevel objects of the EBP 100 button panel, as well as the VolumePort of the control processor.
The volume knob is instantiated by providing the identifier of the host device, EBP in this case, and the volume
knob ID 61001 as parameters. The volume knob is then set to control the volume control port on the control
processor, with a clockwise turn increasing the volume and a counterclockwise turn decreasing the volume.
The volume level on the button panel will display the current level value of the volume control port.

Page 36
Extron Control System Programming Using Python

VolumeKnob = Knob(EBP, 61001) # EBP volume knob


VolumeLevel = Level(EBP, 61011) # EBP volume level
VolumePort = VolumeInterface(Processor, 'VOL1') # Processor volume port

# Set Volume level and UI level based on volume knob adjustment


@event(VolumeKnob, 'Turned')
def AdjustVolumeKnob(knob, direction):
if direction > 0:
if VolumeLevel.Level+direction < VolumeLevel.Max:
VolumeLevel.SetLevel(VolumeLevel.Level+direction)
VolumePort.SetLevel(VolumeLevel.Level+direction)
else:
VolumeLevel.SetLevel(VolumeLevel.Max)
VolumePort.SetLevel(VolumeLevel.Max)
print('EBP Knob turned clockwise. Level is', VolumeLevel.Level)
elif direction < 0:
if VolumeLevel.Level+direction > VolumeLevel.Min:
VolumeLevel.SetLevel(VolumeLevel.Level+direction)
VolumePort.SetLevel(VolumeLevel.Level+direction)
else:
VolumeLevel.SetLevel(VolumeLevel.Min)
VolumePort.SetLevel(VolumeLevel.Min)
print('EBP Knob turned counter-clockwise. Level is', VolumeLevel.Level)

Page 37
Extron Control System Programming Using Python

Programming for Device Control


Each port on an Extron Pro Series control processor can
communicate independently with a unique device. To program the
ports, an identifier is equated to the associated interface class. This
was demonstrated in the earlier example where a relay port on a
control processor was turned on and off using the identifier Relay1.

Each Interface has specific parameters required to instantiate that


port, however all contain two items - the control device that hosts the
control port, and the name of the specific port on that device. The host
device is the identifier given to the control processor when it is
instantiated. Using this information, any port type on a controller can
be defined and programmed.

The port names are shown in the following table.

Port Type Models Port Name Interface Class


Serial Port IPCP Pro 555, IPCP Pro 550, COMn SerialInterface
IPCP Pro 360, IPCP Pro 355DR,
IPCP Pro 355M, IPCP Pro 350,
IPCP Pro 350DR, IPCP Pro 350M,
IPCP Pro 255, IPCP Pro 250,
IPL Pro S1, S3, S6

IR/Serial Port IPCP Pro 555, IPCP Pro 550, IRSn IRInterface
IPCP Pro 360, IPCP Pro 355DR, SerialInterface
IPCP Pro 355M, IPCP Pro 350,
IPCP Pro 350DR, IPCP Pro 350M,
IPCP Pro 255, IPCP Pro 250,

Page 38
Extron Control System Programming Using Python

Port Type Models Port Name Interface Class


IPL Pro IRS8

Relays IPCP Pro 555, IPCP Pro 550, RLYn RelayInterface


IPCP Pro 360, IPCP Pro 355DR,
IPCP Pro 355M, IPCP Pro 350,
IPCP Pro 350DR, IPCP Pro 350M,
IPCP Pro 255, IPCP Pro 250, IPL Pro CR88

Flex I/O Port IPCP Pro 555, IPCP Pro 550 FIOn FlexIOInterface

Digital I/O Port IPCP Pro 360, IPCP Pro 355DR, DIOn DigitalIOInterface
IPCP Pro 355M, IPCP Pro 350,
IPCP Pro 350DR, IPCP Pro 350M,
IPCP Pro 255, IPCP Pro 250

Contact Closure Port IPL Pro CR88 CIIn ContactInterface

PoE Port IPCP Pro 360 POEn PoEInterface

12 VDC Port IPCP Pro 555, IPCP Pro 550 SPIn SWPowerInterface

Volume Port IPCP Pro 255, IPCP Pro 250 VOLn VolumeInterface

Page 39
Extron Control System Programming Using Python

Programming Data Communication with a Device


Sending data to a device through a control system port requires two things: instantiating the control system
port that can transmit data to a controlled device, and the data to be sent to such a device. In many cases the
data to be sent is very simple, such as the command name associated with an IR file used to control an
IR Interface device. Other serial or Ethernet devices may use simple text based protocols or very complex
protocols made up of binary or hexadecimal characters. To aid in the control of Serial and Ethernet Interface
devices, Extron has created many Global Scripter device modules making this task not only easier to include,
but easier to swap out in systems where changes will occur. Details regarding the use of Global Scripter device
modules are described in a companion document titled "Guide to Using Global Scripter Modules" available on
the Extron website. In this section, the IR and unidirectional serial ports will be addressed first, then the
bidirectional serial ports and Ethernet ports.

Sending Data to IR Ports


Just as in the "Hello World" example, an IR/S port must be instantiated using an interface from the interface
package before it is used in the system. In the following example, an IR port is instantiated using the IRInterface
class with the processor's identifier, the port name, and the file name of the desired IR driver.

Bluray = IRInterface(ProProcessor, 'IRS1', 'pana_3_6280_1.eir' )

To add an IR driver file to a project, right-click the desired control processor in the System Manager panel and
select Add Existing File... from the context menu. This option can also be accessed using the object menu
icon or Plus icon. This will launch the Open dialog where the appropriate IR file can be located and added to
the project. Adding this file to the project will link the IR file referenced in the program to the processor. When
the file is selected, the associated Properties window shows the IR commands contained in the IR driver file.

Page 40
Extron Control System Programming Using Python

There are three methods of the IRInterface to send an IR function to the IR port: PlayContinuous( ), PlayCount( )
and PlayTime( ). The first parameter for each of these commands is the name of the IR function to send, as
listed in the IR driver file. The function name can be copied from the Properties window. PlayContinuous
repeats the identified IR function until a Stop( ) method is used or another Play method is sent. PlayCount is
used to send an IR function for a specified number of times. If the repeat parameter is set to None, or omitted, it
will play the number of times defined in the IR driver file. PlayTime is used to send an IR function for a specific
amount of time. Which Play method to use is determined by the required IR function and how the controlled
device responds to the function.

In the following example, the PlayContinuous method is used to send an IR function named 'PLAY' when the
BlurayPlay button is pressed and the Stop method is used to stop sending the IR function once the button is
released.

BlurayPlay = Button(TLP, 5000)


@event(BlurayPlay, 'Pressed')
def BlurayPlayPressed(button, state):
Bluray.PlayContinuous('PLAY')
button.SetState(1)
print('Play function sent')

@event(BlurayPlay, 'Released')
def BlurayPlayReleased(button, state):
Bluray.Stop()
button.SetState(0)
print('Play function stopped')

A single custom function can be used by multiple buttons to send out the appropriate IR commands. First, the
IR functions found in the IR file are to be stored in a list, in the following example this list is called
BlurayIRFunctions.

Page 41
Extron Control System Programming Using Python

BlurayIRFunctions = [
'PLAY', 'STOP', 'PAUSE', 'FFWD', 'REW', 'F_STEP', 'R_STEP',
'UP', 'DOWN', 'LEFT', 'RIGHT', 'ENTER', 'MENU', 'TITLE',
]

In the Turbulence template for the TLP Pro 1025T, the popup page named "BluRay" uses ID numbers 5000
through 5013 for the transport and menu buttons. Each of these buttons is instantiated and a compound event
decorator for the Pressed events is created for the list BlurayButtons. Now, when any of the Bluray buttons
are pressed the BlurayButtonPressed function will be called with the selected button as a parameter.

Remember all indices in Python are zero based, so the string 'PLAY' is located at index 0 of the
BlurayIRFunctions list. Each IR function has been placed in the BlurayIRFunctions list strategically,
corresponding to their ID number from lowest to highest, from PLAY as 5000 to TITLE as 5013. When a button
is pressed, the BlurayButtonPressed function evaluates the button's ID and subtracts 5000, the resulting
number matching the Index position of the IR function. The port will then send out the appropriate IR function
based on the BlurayIRFunction list and, since PlayCount method is used, no Stop method is needed on the
released events.

Page 42
Extron Control System Programming Using Python

BlurayPlay = Button(TLP, 5000)


BlurayStop = Button(TLP, 5001)
BlurayPause = Button(TLP, 5002)
BlurayFFwd = Button(TLP, 5003)
BlurayRew = Button(TLP, 5004)
BlurayFStep = Button(TLP, 5005)
BlurayRStep = Button(TLP, 5006)
BlurayUp = Button(TLP, 5007)
BlurayDown = Button(TLP, 5008)
BlurayLeft = Button(TLP, 5009)
BlurayRight = Button(TLP, 5010)
BlurayEnter = Button(TLP, 5011)
BlurayMenu = Button(TLP, 5012)
BlurayTitle = Button(TLP, 5013)
BlurayButtons = [BlurayPlay, BlurayStop, BlurayPause, BlurayFFwd, BlurayRew,
BlurayFStep, BlurayRStep, BlurayUp, BlurayDown, BlurayLeft, BlurayRight,
BlurayEnter, BlurayMenu, BlurayTitle,]

@event(BlurayButtons, 'Pressed')
def BlurayButtonPressed(button, state):
# define the Bluray buttons to send the appropriate IR function
ButtonIndex = button.ID - 5000
Bluray.PlayCount(BlurayIRFunctions[ButtonIndex])
button.SetState(1)
print('{0} function sent'.format(BlurayIRFunctions[ButtonIndex]))

@event(BlurayButtons, 'Released')
def BlurayButtonReleased(button, state):
ButtonIndex = button.ID - 5000
button.SetState(0)
print('{0} function stopped'.format(BlurayIRFunctions[ButtonIndex]))

However in this example, a button Released event is needed in order to return the visual feedback or Control
State for the selected button to 0. This also provides a framework for later use, if it is decided that a different
IRInterface method is needed for the system.

Sending Data to Unidirectional Serial Ports


A unidirectional serial port is defined in a similar manner to the IR port. The SerialInterface class object has
specific parameters that must be included when defined. These parameters include Host which is the identifier
name of the processor used in the program and Port which identifies the appropriate serial port of the
processor. Please be aware that if a port has already been instantiated as an IRInterface class object, an
exception will occur terminating execution of the program. For example: previously in this section we
instantiated an IRInterface as 'IRS1'. If we instantiate a SerialInterface object using 'IRS1' for the port
parameter, an exception will occur in the event that both of these exist in the same program. Other parameters
are optional and can be omitted if the default values are appropriate for the device to be controlled. Note: The
following shows the default values.

Page 43
Extron Control System Programming Using Python

SerialDevice = SerialInterface(ProProcessor, 'COM1', Baud=9600, Data=8,


Parity='None', Stop=1, FlowControl='OFF', CharDelay=0, Mode='RS232')

The data to be sent to this port can simply be a string of alphabetic characters enclosed in quotes:

'POWER ON\r'

This string can contain unprintable characters including linefeeds, carriage returns, or any other character that
can be defined by a hexadecimal or escape character sequence. The string can contain multiple data types
and be built in steps as the appropriate buttons are pressed or input is acquired.

The following example sends the string POWER ON\r via the identified port on the processor specified as
SerialDevice.

SerialDevice.Send('POWER ON\r')

The following example defines an Extron DXP HDMI matrix switcher to be controlled from the IR/Serial port #2
on the IPCP Pro 550 control processor instantiated in this program as ProProcessor. After the processor is
instantiated, the DXP Matrix is defined using the SerialInterface class.

DXPMatrix = SerialInterface(ProProcessor, 'IRS2')

Once the serial interface port is defined, a command can be sent to the DXP HDMI Matrix using the Send( )
method of the SerialInterface class. The standard SIS command is used to tie input 1 to output 1 on the matrix
switcher in the following example.

DXPMatrix.Send('1*1!')

With regard to the navigation example, this command can be included in Pressed events to set the matrix to the
appropriate input when each source button is selected.

Page 44
Extron Control System Programming Using Python

def SelectInputButtonPressed(button, state):


print('button pressed: {0}, ID – {1}'.format(button.Name, button.ID))
if button.ID == 8050:
CurrentInput = 'Laptop'
DXPMatrix.Send('1*1!')
elif button.ID == 8052:
CurrentInput = 'PC'
DXPMatrix.Send('2*1!')
elif button.ID == 8054:
CurrentInput = 'Bluray'
DXPMatrix.Send('3*1!')
elif button.ID == 8058:
CurrentInput = 'DocCam'
DXPMatrix.Send('4*1!')
elif button.ID == 8060:
CurrentInput = 'Tuner'
DXPMatrix.Send('7*1!')
elif button.ID == 8062:
CurrentInput = 'Aux'
DXPMatrix.Send('8*1!')
else:
CurrentInput = 'NotSelected'
print('CurrentInput: {0}'.format(CurrentInput))
ShowSourcePopup(CurrentInput, TLP)

Bidirectional Serial Port Communication


Defining a bidirectional serial port is identical to defining a unidirectional serial port and uses the same class
construct. The only thing that changes is the Port name. For instance, if control for the DXP HDMI Matrix was
moved from the unidirectional IR/Serial port to a bidirectional serial port on the IPCP Pro 550, only the port
reference needs to change for DXPMatrix. With the reference "IRS2" changed to a bidirectional serial port,
such as "COM3", the rest of the program will work as written.

DXPMatrix = SerialInterface(ProProcessor, 'COM3')

This simple interaction between processor and device described in the previous section is only half of the
capability of the bidirectional serial port. The processor's port can receive a response to a sent command or
receive unsolicited responses from the device such as changes to ties made from the front panel. The
difference is primarily when responses are anticipated and processed.

Asynchronous Communication
In addition to receiving a device response to a command from the control system, there may be occasions
when a device may send unsolicited messages to the control system. If this scenario is anticipated, it is better
to use an asynchronous method of communication.

Page 45
Extron Control System Programming Using Python

Parsing Returned Data from a Device


The process by which a processor analyzes data returned from a device is called Parsing. To parse data, an
event handler is defined in order for the data to be received as a message that can be processed. As with
unidirectional communication through an IR/Serial port, when using asynchronous communication, the Send
method is used to send data to a device. The Pro Series control system will return the data as soon as possible
after it is received from the controlled device. Depending upon the speed of the communication, the length of
the messages, any inter-character delays, hardware handshaking if used, and the current load on the
processor, this data may not always contain an entire message from the device. For this reason it is important
to create a variable to hold the data returned from the device. The variable is filled as the data is received. In the
example listed at the end of this section, a variable MatrixBuffer is created for a DXP matrix and set with a null
(or empty) string:

MatrixBuffer = ''

In our example, if the port was defined as described in the previous section, then we can use that same device,
DXPMatrix, with the ReceiveData parameter in an event handler as shown below:

@event(DXPMatrix, 'ReceiveData')

The @event decorates a function that processes the message when it is received; in the following example the
parsing function is named MatrixParse. The function requires two parameters, one to represent the control
port interface and the other to represent the message received from that device. The response is returned as a
byte object. To process this byte object using the Python string methods, it must first be decoded from a byte
object to a string object.

When running MatrixParse, the function references the previously defined MatrixBuffer variable by using the
prepended keyword "global". This keyword instructs the function to reference a variable outside of the
function, not a new one created within it. On the subsequent line, we add the data returned from the event
handler to the current value of the MatrixBuffer variable, and store all of that information in MatrixBuffer.

def MatrixParse(interface, response):


global MatrixBuffer
MatrixBuffer = MatrixBuffer + response.decode()

Before processing the data, it needs to be determined whether the response received was complete. Using the
SIS protocol for the Extron DXP matrix switcher, a conditional expression is created to evaluate if the
MatrixBuffer contains the carriage return and linefeed that terminates the response from the device. If it is
determined that the response is complete, the DelimiterIndex variable is set to the location of the first pair. (It
is possible that the device will return data with more than one carriage return and linefeed pair. Therefore to
process only one, the MatrixBuffer will need to be split at the first pair.) The DelimiterIndex then retrieves the
first part of the MatrixBuffer and stores that data in the variable CurrentResponse. This is the data that will
be processed. Finally, if anything remains, the MatrixBuffer variable is redefined with the portion of the
MatrixBuffer after the first carriage return/linefeed pair as indicated by the DelimiterIndex+2 slice parameter.

Page 46
Extron Control System Programming Using Python

If the response is not complete, the function will wait until the next time the event handler is triggered and will
repeat the comparison.

if MatrixBuffer.rfind('\r\n') > 0:
DelimiterIndex = MatrixBuffer.rfind('\r')
CurrentResponse = MatrixBuffer[:DelimiterIndex]
MatrixBuffer = MatrixBuffer[DelimiterIndex+2:]
else:
print('waiting for more data')

Data processing is based upon not only the protocol, but what information is needed from the device. With
regard to the DXP matrix, the processor will look for information about what matrix ties have taken place (either
from the front panel or the built-in web pages) and that the matrix has made the requested ties as programmed.

When a switch is made from the front panel or from the internal web page of the DXP matrix, the 'Qik\r\n'
message is sent as specified in the user manual.

To determine if a switch has been made from the front panel, internal web pages, or from a Quick Tie
command, the CurrentResponse variable evaluates whether the response has a 'Qik' message. Note that it
does not indicate exactly what switch has occurred, only that one has happened. To determine which input is
connected to what output, a query will be sent from the serial port of the processor to the matrix to determine
the input tied to each output of the matrix.

if CurrentResponse == 'Qik': # Front Panel or Quick Tie Response


print('front panel switch made')
DXPMatrix.Send('1!2!3!4!')

When the matrix is in Verbose Mode 3, the response is identical to that of a matrix tie command and can be
parsed using that routine. Continuing with the example, if the CurrentResponse does not equal 'Qik', it will
proceed to the elif statement. The comparison of the elif will evaluate if the first three characters of the
response are equal to 'Out.' If this statement is true, a regular expression is used to retrieve meaningful data
from the information returned and sort that data into groups that can later be used in the program.

Page 47
Extron Control System Programming Using Python

elif CurrentResponse[0:3] == 'Out': # Tie command response


print('typical tie response')
ResponsePattern = re.compile(
'Out([0-9]{1,3}) In([0-9]{1,3}) (Aud|Vid|RGB|All)'
)
matchObject = ResponsePattern.search(CurrentResponse)
if matchObject:
input = int(matchObject.group(2))
output = int(matchObject.group(1))
tietype = matchObject.group(3)
MatrixOutput[output-1]=input
print('in={0} out={1} type={2}'.format(input, output, tietype))

Regular expressions provide a means to search, identify, replace, and parse through the received data to
provide meaningful information. This module can be imported into any Python program to provide access to
these rich and powerful tools. Since Extron ControlScript is based on Python, this module is available for use
without any additional programming other than the following import statement.

import re

Looking at the device protocol, the words "Out" and "In" are consistent in each response to a matrix tie
command. "Out" is followed by the associated output number and "In" is followed by the associated input
number. Lastly, the type of switch is identified as video, audio, or both. Therefore, we can use "Out", "In", and
the switch type as keys to parsing. The end of the string contains the carriage return and line feed characters,
and are the delimiters to responses from the device.

Since we know the format of the data to be returned, a regular expression pattern can be created to match the
data needed and place this data into groups. One of the easiest ways to do this is to start with the device
response string and replace the items that change with groups of matching parameters. Since this pattern will
be used in a search, it can be stored in a variable to be used many times.

In this case, the variable ResponsePattern is set equal to the compiled pattern. Without any further
modification, this will only match the response when output 1 is tied to input 1 for both audio and video.

ResponsePattern = re.compile('Out1 In1 All\r\n')

To make this pattern match any input or output number, the actual digits need to be replaced with expressions
that can be used to match the information needed. Begin building this pattern by replacing the “1” in Out1 with
a list of all possible numbers from 0 through 9. The pattern syntax for this is “[0123456789]” which can be
shortened to [0-9]. This pattern will match the “1” in the response, but if this was a larger matrix, it might need to
match output numbers into the three digits. The same pattern [0-9] can be used again, or a quantifier can be
used to let the regular expression know of the possibility that more than one digit needs to be captured. The
quantifier {1,3} will capture at a minimum one digit and up to three total. Since this is the first group we want to
capture and use in our program, these expressions will be placed in parentheses.

Page 48
Extron Control System Programming Using Python

ResponsePattern = re.compile('Out([0-9]{1,3}) In1 All\r\n')

The same thing can be done for the input, capturing the input number into the second group.

ResponsePattern = re.compile('Out([0-9]{1,3}) In([0-9]{1,3}) All\r\n')

Please be aware that spaces in the regular expression string are important. If the space before the word 'In' is
not included, the pattern we are creating would not match the response from the matrix.

The final step is to capture the tie type. The Command and Response Table of the DXP User Guide specifies
that responses from the switcher will identify the tie type by the word 'All' meaning both video and audio, and
the abbreviations 'RGB', 'Vid', and 'Aud'. Therefore, these items must be added to the ResponsePattern.

To match the tie types in the ResponsePattern, a list of the possible responses separated by the '|' (pipe)
character is created in the third group.

ResponsePattern = re.compile('Out([0-9]{1,3}) In([0-9]{1,3}) (Aud|Vid|RGB|All)')

When creating patterns be aware that, unless specified that the case should be ignored, the matching is case
sensitive.

Now that the pattern is created, the processor can match the response from the device using the variable
CurrentResponse, and then retrieve the desired data from the three groups created in the regular

Page 49
Extron Control System Programming Using Python

expression. To do so, create a variable to hold the response from the regular expression pattern match, such
as MatchObject. Then the values of each group can be placed into the appropriate variables.

MatchObject = ResponsePattern.search(CurrentResponse)
if MatchObject:
input = int(MatchObject.group(2))
output = int(MatchObject.group(1))
tietype = MatchObject.group(3)
print('in={0} out={1} tietype={2}'.format(input, output, tietype))

We can create similar parsing for any response from the matrix switcher. Please notice in this example that two
response patterns have been created, one for when a single input is tied to all outputs and another for a typical
matrix tie. These two regular expression compile statements are outside of the function where they are used so
that the compile only happens one time, not each time the function is called.

Once the data received from the controlled device is parsed, it can be used in many ways to provide
meaningful information to the system user. In this example, the current input assigned to each output is
referenced in the global list identified as MatrixOutput. Each time a response is received from the DXP matrix
that an input assignment has changed, this list is updated to reflect that change and is then printed to the Trace
Messages pane. The following shows code for parsing the matrix switcher responses.

Page 50
Extron Control System Programming Using Python

ProProcessor = ProcessorDevice('ProcessorAlias')
# Extron DXP 84 HD 4K
DXPMatrix = SerialInterface(ProProcessor, 'COM3')

# Identifier to reference the response from the Matrix Switcher


MatrixBuffer = ''
# List of the current status of inputs assigned to outputs by index
MatrixOutput = [0,0,0,0]
# Response pattern for one input to all outputs
ResponsePatternIn = re.compile('In([0-9]{1,3}) (Aud|Vid|RGB|All)')
# Response pattern for typical matrix tie response
ResponsePatternTie = re.compile('Out([0-9]{1,3}) In([0-9]{1,3}) (Aud|Vid|RGB|All)')

@event(DXPMatrix, 'ReceiveData')
def MatrixParse(interface, response):
global MatrixBuffer
global MatrixOutput
MatrixBuffer = MatrixBuffer + response.decode()
if MatrixBuffer.rfind('\r\n') > 0:
DelimiterIndex = MatrixBuffer.rfind('\r')
CurrentResponse = MatrixBuffer[:DelimiterIndex]
MatrixBuffer = MatrixBuffer[DelimiterIndex+2:]
if CurrentResponse == 'Qik': # Front Panel or Quick Tie Response
print('front panel switch made')
DXPMatrix.Send('1!2!3!4!')
elif CurrentResponse[0:2] == 'In': # Selected input to All response
print('selected input to all outputs')
MatchObject = ResponsePatternIn.search(CurrentResponse)
if MatchObject:
input = int(MatchObject.group(1))
tietype = MatchObject.group(2)
print('in={0} type={1}'.format(input, tietype))
for item in MatrixOutput:
MatrixOutput[MatrixOutput.index(item)]=input
print(MatrixOutput)
elif CurrentResponse[0:3] == 'Out': # Tie command response
print('typical tie command response')
MatchObject = ResponsePatternTie.search(CurrentResponse)
if MatchObject:
input = int(MatchObject.group(2))
output = int(MatchObject.group(1))
tietype = MatchObject.group(3)
MatrixOutput[output-1]=input
print('in={0} out={1} type={2}'.format(input, output, tietype))
print(MatrixOutput)
else:
print('CurrentResponse {0} is not processed'.format(CurrentResponse))
print('MatrixBuffer is now {0} characters long'.format(len(MatrixBuffer)))

Page 51
Extron Control System Programming Using Python

Synchronous Communication
With synchronous communication, a response is anticipated following the sending of a command. Although
the ReceiveData event handler can be used in the same manner as in asynchronous communication, the
SendAndWait( ) method of the SerialInterface class has been developed for this type of communication. Using
SendAndWait, a command is sent just as it is when using the Send method, however it will wait a specified
period of time for a response. Additionally, an optional delimiter can be specified that, once met, stops waiting
for the timeout and returns the data received from the device. One thing to note about the SendAndWait
method – it blocks any other action in the associated function from occurring until the timeout has expired or
the delimiter condition has been met. To demonstrate this, the Send method in the unidirectional serial example
has been changed to SendAndWait with a three second timeout and no delimiter. When a source selection
button is pressed, the command to change the matrix tie is sent, but the popup page does not change until after
the timeout expires.

def SelectInputButtonPressed(button, state):


print('button pressed: {0}, ID – {1}'.format(button.Name, button.ID))
if button.ID == 8050:
CurrentInput = 'Laptop'
Response = DXPMatrix.SendAndWait('1*1!', 3)
elif button.ID == 8052:
CurrentInput = 'PC'
Response = DXPMatrix.SendAndWait('2*1!', 3)
elif button.ID == 8054:
CurrentInput = 'Bluray'
Response = DXPMatrix.SendAndWait('3*1!', 3)
elif button.ID == 8058:
CurrentInput = 'DocCam'
Response = DXPMatrix.SendAndWait('4*1!', 3)
elif button.ID == 8060:
CurrentInput = 'Tuner'
Response = DXPMatrix.SendAndWait('7*1!', 3)
elif button.ID == 8062:
CurrentInput = 'Aux'
Response = DXPMatrix.SendAndWait('8*1!', 3)
else:
CurrentInput = 'NotSelected'
print('CurrentInput: {0}'.format(CurrentInput))
print('Response: {0}'.format(Response))
ShowSourcePopup(CurrentInput, TLP)

When the SelectInputButtonPressed function is executed, regardless of the button pressed, three distinct
Trace Messages will be sent to the Trace output. Notice the three second difference between the button press
and response.

print Command Laptop button is Pressed at 3:01:55 PM


print('button pressed: {0}, ID – {1}'.format(button.Name, 3:01:55 PM button pressed: Laptop, ID - 8050
button.ID))

print ( 'CurrentInput: {0}' .format (CurrentInput) ) 3:01:58 PM CurrentInput: Laptop

Page 52
Extron Control System Programming Using Python

print Command Laptop button is Pressed at 3:01:55 PM


print ('Response: {0}' .format (Response) ) 3:01:58 PM Response: b'Out1 In1 All\r\n'

The timeout should be reduced to a value small enough (0.1 second is the smallest value allowed) to where the
response is captured but any delays are minimized. When a delimiter is used in the SendAndWait method, the
timeout cancels as soon as the processor receives the anticipated response. For instance, based on the
SIS documentation for the DXP HDMI matrix, the anticipated response is at least 14 characters in length. This
is verified in the "Response:..." trace message of the SelectInputButtonPressed function. If 14 is used as the
delimiter length parameter in the SendAndWait method listed below, there will be almost no perceptible delay.

Response = DXPMatrix.SendAndWait('1*1!', 3, deliLen=14)

Notice in the SIS documentation that every response to a matrix tie command ends with a carriage return and
linefeed. In the Response trace message, these are identified by the \r\n characters at the end of the string.
Rather than using the deliLen parameter for the delimiter, \r\n can also be used with the SendAndWait method.
Then, no matter the length of the response, the matrix returns the response as soon as these characters
match. Be aware that the response is a byte string, therefore the deliTag parameter must be prepended with a
lowercase b as shown below.

Response = DXPMatrix.SendAndWait('1*1!', 3, deliTag=b'\r\n')

The last delimiter parameter that can be used looks for a match of certain strings with replaceable parameters
– a regular expression. Again looking at the SIS documentation, the response to a matrix tie command ends
with the type of tie that was made: All, RGB, Video, or Audio. Using this information we can look for any of those
responses as the delimiter. Once any of these strings is found in the response, the timeout is cancelled and the
response is returned.

Response = DXPMatrix.SendAndWait('1*1!', 3, deliRex=b'(All|RGB|Vid|Aud)')

Now that a response has been received, this information can be used to provide feedback to buttons, sent as
data to another object, or it can serve for any other use as needed by the scope of the system. This process is
the same for both synchronous and asynchronous communication. Please note that either the ReceiveData
event or the SendAndWait method should be on any individual SerialInterface port, but not both.

Communication with Ethernet Ports


Communicating with Ethernet connected devices is very similar to serial devices, with the exception that for
TCP and SSH protocols, Ethernet connections must be managed. If we change the communication type of the
DXP Matrix from serial to Ethernet, the same process for sending and receiving data could be used once the
connection is established and maintained.

Establishing and maintaining the connections are dependent upon the type of communications, the protocol to
be employed, and the behavior of the connected devices. For the purposes of this document, it is assumed that
the actual wired connection has been made between the controller and the device with which the controller

Page 53
Extron Control System Programming Using Python

will communicate. ControlScript provides the means to manage the programmatic connections and the means
to monitor the data traversing the path, ensuring the communication is not disconnected by either the client or
the server.

Establishing an Ethernet Connection


When establishing an Ethernet connection with the control processor, we must know several key parameters
of the device to be controlled:

l Does the controlled device act as a server or a client? Most AV devices operate as a server, requiring the
control system to act as a client connection.

l What type of protocol does the controlled device use – TCP, UDP, or SSH?

l What IP port number is used for the connection?

l What is the hostname or IP address of the controlled device?

This information is typically found in the controlled device's user manual or API documentation.

Client Communications - TCP


Many devices controlled by Ethernet, including Extron devices, utilize Transmission Control Protocol -
TCP communication. In client/server communication, the client establishes the initial connection request and
maintains the connection to the server. The server may disconnect the client after a period of no
communication.

For Extron devices, Ethernet communication information is found in the Extron User Guide. (The following
shows the appropriate section from the DXP Matrix User Guide.) Similar information should be available from
each manufacturer of Ethernet controlled devices.

Page 54
Extron Control System Programming Using Python

This documentation states that the DXP Matrix acts as a server by providing information regarding opening a
connection using clients like Extron DataViewer or Telnet. Therefore, the control processor is required to
connect using a client interface. For this example, the DXP Matrix will use its default IP address of
192.168.254.254 and a TCP connection on port 23. Since the device uses the default TCP protocol, only the
IP address or hostname, and the IP port number need to be specified when instantiating the
EthernetClientInterface class.

DXPMatrix = EthernetClientInterface('192.168.254.254', 23)

Once the Communication interface is instantiated, open a connection to the device using the Connect method
of the EthernetClientInterface class. The Connect method will accept a parameter indicating how long it will
continue to attempt a connection. It is recommended to set the Connect method timeout to a reasonable value
such as 10 seconds as shown in the example that follows.

DXPMatrix.Connect(10)

Upon a successful connection, the Connect method will return a string equal to 'Connected'. If the connection
is unsuccessful, it will provide a reason for the failure. The programmer can act upon this result and attempt to
retry or simply provide a status message.

There are many reasons why the Connect method may not be successful:

Page 55
Extron Control System Programming Using Python

l The IP address/hostname of the controlled device is incorrect

l The network path or cabling between the controller and controlled device is not functional or is
disconnected

l The controlled device did not respond to the connection request before the Connect method timed out

Any of these cases will trigger a 'Disconnected' event, if it is instantiated in the program.

In the following example, a function is created to attempt the connection to the DXPMatrix device with a
connection timeout of 10 seconds. If the result is 'Connected' then the result is printed to the Trace Messages
pane. If the connection is not successful, the result will be printed and the function will be called again after a
30 second wait.

def ConnectDXP():
result = DXPMatrix.Connect(10)
if result == 'Connected':
print(result)
# Do other things when connected
else:
print(result)
Wait(30, ConnectDXP)

The timeout parameter of the Connect method only affects how long the controller will attempt to make a
connection to the server. This does not relate to a communication timeout that may be documented for the
controlled device. For a device like the DXP Matrix, the internal Ethernet Server will close the communication
with a client if no activity is detected in the designated device timeout value. As previously shown in the excerpt
from the DXP Matrix manual, this device has a communication timeout of five minutes. (This value can be
changed in the properties of the DXP Matrix if desired using SIS commands.) If this occurs, the DXP Matrix will
no longer respond to any messages sent to it from the controller and will trigger a Disconnected event on the
control processor.

To purposely close the connection, use the Disconnect( ) method of the EthernetClientInterface class.

Page 56
Extron Control System Programming Using Python

When do Connection events occur?


'Connected' 'Disconnected'
Successful connection attempt Unsuccessful connection attempt due to
Connect method timeout

Unsuccessful connection attempt due to


incorrect IP address or hostname

Unsuccessful connection attempt due to


cabling or network error

Connection attempt refused by server

Server disconnected purposefully (e.g. HTTP


communication disconnects after responding
to request.)

Server timeout after connection

Client purposely disconnected using


Disconnect( ) method

Note: Loss of communication due to cabling or network error will not trigger a 'Disconnected'
event.

In the example that follows, the device will issue an event upon disconnection or connection with the device.
The Disconnected event triggers the MatrixConnectionHandler function and runs the StopKeepAlive( ). The
Connected event triggers the MatrixConnectionHandler function to send a command to the device, in this
case setting verbose mode to 3, and uses the method StartKeepAlive( ) to send a query every 60 seconds.

@event(DXPMatrix, ['Connected','Disconnected'])
def MatrixConnectionHandler(interface, ConnectionState):
print('Matrix Connection Event: {0}'.format(ConnectionState))
if 'Connected' == ConnectionState:
DXPMatrix.Send('W3CV\r')
DXPMatrix.StartKeepAlive(60, 'Q')
elif 'Disconnected' == ConnectionState:
DXPMatrix.StopKeepAlive()

Once the connection is established, the StartKeepAlive( ) method can be used to send a message at regular
intervals to keep the server from timing out and closing the connection. This method will send the first message
immediately and then at the specified interval thereafter, until stopped. The StopKeepAlive( ) method
terminates the StartKeepAlive( ) method, commonly used if a StartKeepAlive message interferes with the
operation of a device, or when a 'Disconnected' event is triggered. For instance, some display devices cannot
accept commands while the display is in the process of turning on or turning off. The particular message to use
and the response should be chosen based on the device to be controlled.

For the DXP matrix, to send the query command as suggested in the User Guide, we can add the "Q"
command to the program using the StartKeepAlive( ) method once the connection is established. The
ReceiveData event of the EthernetClientInterface can be set to monitor the response to the message that is

Page 57
Extron Control System Programming Using Python

sent using StartKeepAlive( ) and issue a Disconnect( ) if several responses are not received, indicating the
communication is no longer functional, such as when a cabling or network error has occurred after the initial
connection to the server. The ReceiveData event is discussed in more detail in the SerialInterface section of
this guide.

To monitor the state of an Ethernet connection, the programmer can start a Timer when the connection is first
established and communication from the device is received, then restart that Timer every time another
response is received. The last line in the function places itself in the wait list to be called again after the desired
amount of time. In the following example, an identifier called LastConnectionTime is set as described. A
function can be created to check whether this identifier has been set and, if true, how long since it was last set.

@event(DXPMatrix, 'ReceiveData')
def MatrixDataHandler(interface, data):
print('Matrix Data: {0}'.format(data))
CheckConnectionTimer.Restart()

def CheckConnections(timer, count):


"""Check the time since last data/connection. Reconnect if necessary."""
CurrentTime = time.monotonic()
# If the device was connected and last received data was more than 2 minutes
# ago then issue a Disconnect and attempt to reconnect to the device.
if timer.State is 'Running': # The Timer is only running if data has been
# received from the DXPMatrix.
ElapsedTime = timer.Interval * count
print('Time since last response: {0} seconds'.format(ElapsedTime))
# Was the last communication more than two minutes ago?
if ElapsedTime >= 120:
DXPMatrix.Disconnect()
ConnectDXP() # Reconnect to the DXP again using the defined function.
CheckConnectionTimer.Stop() # Stop checking until reconnected.
CheckConnectionTimer = Timer(60, CheckConnections)

This example uses a Timer object (more about that in the next section) to periodically check how long it has
been since a response was received by the ReceiveData event. Each time a response is received, the timer is
restarted and can be used to determine the elapsed time since the receipt of the previous response. In this
case the connection is checked every 60 seconds and, if a response is not received in the last two minutes, the
connection will terminate and trigger the 'Disconnected' event. The program will then attempt to reconnect
using the previously designed function and stop the timer used to check the connection.

The type of communication behavior described above is normal for many AV devices (servers) which utilize
terminal-like communication. However, some Ethernet protocols, particularly HTTP, will disconnect from a
client as soon as the server determines it has supplied the information requested after connection. This is
considered normal behavior for these communication types.

Page 58
Extron Control System Programming Using Python

Infographic depicting successful and unsuccessful connections:

Page 59
Extron Control System Programming Using Python

Client Communications - SSH


ControlScript can communicate using secure messaging via the SSH protocol. When 'SSH' is provided as the
argument to the Protocol parameter, the programmer must provide the Credentials parameter as well. For
example, to communicate using the SSH protocol to an Extron SMD 202 at an IP address of 192.168.31.32 you
can instantiate the client interface as follows:

SMDPort = EthernetClientInterface('192.168.31.32', 22023, 'SSH',


Credentials = ('admin', 'extron'))

All the other communication methods are the same as the TCP client described previously.

Client Communications - UDP


Some devices utilize the User Datagram Protocol - UDP communication. This protocol does not contain the
handshaking or error checking/correction used in TCP communication. With UDP communication, the sender
does not know if a message is actually received and typically the connection is closed once the message is
sent. This can make the messaging process faster, but the message may not always be delivered in full.

Creating an EthernetClientInterface object for a device utilizing UDP communication is like the TCP
communication with an additional optional parameter, ServicePort, if the client should listen for a response on
a different port from the one used to send the message when a response is anticipated.

BACnet = EthernetClientInterface('192.168.254.254', 0xBAC0, 'UDP', OxBAC1)

Or

LightingSystem = EthernetClientInterface('192.168.31.56', 23, 'UDP')

Due to the nature of UDP communication, the Connect/Disconnect methods and Connect/Disconnect events
do not apply to objects defined as UDP clients.

The Send method is used to transmit messages to a UDP server just as is done with a TCP server. Due to the
nature of UDP communications, the SendAndWait method should not be used. If it is anticipated that a
response may be received from the connected device, a ReceiveData event should be created to handle the
response similar to a typical TCP communication.

Server Communications
There may be instances where the control system will need to act as an Ethernet Server to allow clients to
connect to the control system. This may be needed where disparate systems may need to communicate to
share devices (such as a resource sharing system) or simply need to transfer information via a messaging
application. ControlScript has provided two classes of Ethernet server interfaces that can be used for this
purpose: EthernetServerInterface and EthernetServerInterfaceEx. We recommend using the
EthernetServerInterfaceEx class, which provides more flexibility and allows multiple clients to connect to a
server simultaneously. The EthernetServerInterfaceEx class will be used for examples in this document.

Page 60
Extron Control System Programming Using Python

Since a server is the host for the communication, the only information necessary to set up the server interface
is the protocol type and IP port number of the communication. To instantiate a Server Interface object, simply
provide the port number and any parameters that need to be changed from the default such as the protocol or
a limited number of clients that can connect simultaneously.

CommunicationServer = EthernetServerInterfaceEx(1024)

To enable the server interface to listen for clients who may want to connect, the programmer calls the
StartListen( ) method with the default value for the timeout, 0, indicating that it will keep trying to establish the
server in listening mode with no timeout. The StartListen( ) method will respond with the string 'Listening' if the
server is successful in establishing the server in listening mode. If the server cannot be established before the
timeout occurs, the reason for the failure will be returned by the method as a string – typically this is
'PortUnavailable'.

Once the server is listening, a client can connect and begin communication. The following is an example of an
Ethernet server set up to communicate with a TCP client on port 10000. Once the connection is made from the
client, the server will send the message 'Hello.\n'. In this simple example, the server is expecting one of two
messages from the client. If the 'ping' message is received at least once every 15 seconds, the connection will
be maintained. If the 'ping' message is not received, or an 'end' message is received, the connection will be
disconnected. This will cause the 'Disconnected' event to occur, which will once again start the server
listening for connections.

Page 61
Extron Control System Programming Using Python

import time # For monotonic()


serv = EthernetServerInterfaceEx(10000, 'TCP')
def startServer():
"""Start the server. Reattempt on failure after 1s."""
if serv.StartListen() != 'Listening': # Port unavailable
print('Port unavailable')
Wait(1, startServer)
@Timer(1)
def checkTimer(timer.count):
"""Check the time since last message received. Reconnect if needed."""
global connected
# If connected and keepalive not received in last 15 seconds,
# disconnect and listen again.
if connected and time.monotonic() - connected > 15:
serv.Disconnect()
startServer()
connected = None
def Initialize():
startServer()
@event(serv, 'ReceiveData')
def HandleReceiveData(interface, data):
global connected
print('Rx: {}'.format(data.decode()))
# This simulates a condition where the server has ended the
# session and closed the connection.
if b'end' in data: # Disconnect on 'end'
print('End signal received.')
interface.Disconnect()
startServer()
# This simulates a keepalive message received from the client.
# Check for missed keepalives in checkTimer()
elif b'ping' in data: # Record last keepalive time
connected = time.monotonic()
@event(serv, 'Connected')
def HandleClientConnect(interface, state):
global connected
print('Client connected ({}).'.format(interface.IPAddress))
interface.Send(b'Hello.\n')
connected = time.monotonic() # Reset the keepalive time
@event(serv, 'Disconnected')
def HandleClientDisconnect(interface, state):
global connected
print('Server/Client disconnected.')
connected = None # Clear the keepalive
Initialize()

Similar servers can be programmed to provide communication using any agreed upon protocol and port
numbers between the server and client utilizing TCP or UDP communications.

Page 62
Extron Control System Programming Using Python

Programming Volume Interfaces


Defining the volume control port of a Pro Series control processor is similar to defining other port types. The
VolumeInterface class is used to program the remote volume control port, such as the one on the
IPCP Pro 250. This control allows smooth operation of volume level adjustment over the entire range of control.

Volume levels are set discretely with all increments programmed directly. In the following code example, the
first two lines instantiate the processor and the VolumeInterface port of the IPCP Pro 250. Next, a dictionary
Pro250Vol is defined with information for the VolumeInterface – note that this is not necessary for the definition
of the port. Lastly, the value of the 'Level' key in the Pro250Vol dictionary is set to the current level of the
volume control port.

Pro250Controller = ProcessorDevice('Pro250')
Pro250VolumePort = VolumeInterface(Pro250Controller, 'VOL1')
Pro250Vol = {
'Level':0,
'Step':2,
}
Pro250Vol['Level'] = Pro250VolumePort.Level

The upper and lower limits of the range can be set using the SetRange( ) method. In the example that follows,
the Main Volume buttons of the Turbulence template on a TLP Pro 725T will control the volume level for the
remote volume control port. The level indicator on the user interface with the ID 8023 is also instantiated. The
level bar is set to display the current level value of the volume control port. The subsequent sections instantiate
the volume up and down buttons, as well as set the events for what should happen when the buttons are
pressed and held. Notice that volume buttons include both the 'Pressed' and 'Repeated' events in a single
function for each button. When the Up or Down button is either pressed or held longer than two seconds, the
commands will be issued. If the button remains held beyond 2.2 seconds, the commands will be issued every
two tenths of a second thereafter. If it was desired that specific actions occur at the 2 second mark, a 'Held'
event could have been programmed.

Page 63
Extron Control System Programming Using Python

TLP725 = UIDevice('725T')
TLP725MainVolLevel = Level(TLP725, 8023)
TLP725MainVolLevel.SetLevel(Pro250Vol['Level'])
MainVolUpButton = Button(TLP725, 8120, holdTime=2, repeatTime=0.2)

@event(MainVolUpButton, ['Pressed', 'Repeated'])


def MainVolUpPressed(button, state):
MainVolUpButton.SetState(1)
if Pro250Vol['Level'] < 100:
Pro250Vol['Level'] += Pro250Vol['Step']
Pro250VolumePort.SetLevel(Pro250Vol['Level']
TLP725MainVolLevel.SetLevel(Pro250Vol['Level'])

MainVolDownButton = Button(TLP725, 8121, holdTime=2, repeatTime=0.2)


@event(MainVolDownButton, ['Pressed', 'Repeated'])
def MainVolDnPressed(button, state):
MainVolDownButton.SetState(1)
if Pro250Vol['Level'] > 0:
Pro250Vol['Level'] -= Pro250Vol['Step']
Pro250VolumePort.SetLevel(Pro250Vol['Level']
TLP725MainVolLevel.SetLevel(Pro250Vol['Level'])

Additionally, notice the 'Released' and 'Tapped' (functionally equivalent to the Quick Release in Global
Configurator Professional) events set the button state to 0.

@event(MainVolUpButton, ['Released', 'Tapped'])


def MainVolUpReleased(button, state):
MainVolUpButton.SetState(0)

@event(MainVolDownButton, ['Released', 'Tapped'])


def MainVolDnReleased(button, state):
MainVolDownButton.SetState(0)

The Mute functionality is similar, but is programmed to toggle the state of the mute. When the button is Pressed,
if the Mute is currently "On", it will be set to "Off" and its visual feedback set to Control State 0. So the change is
noticed immediately, State 1 is listed first.

MainVolMuteButton = Button(TLP725, 8021)


@event(MainVolMuteButton, 'Pressed')
def MainVolMutePressed(button, state):
if Pro250VolumePort.Mute == 'On':
Pro250VolumePort.SetMute('Off')
MainVolMuteButton.SetState(0)
else:
Pro250VolumePort.SetMute('On')
MainVolMuteButton.SetBlinking('Medium',[1, 0])

Page 64
Extron Control System Programming Using Python

Programming Input and Output Interfaces


The Extron Pro Series control processors have many other types of input and output (I/O) interfaces. To
program each type of port, both the processor and its I/O interface needs to be instantiated.

Relay Interface
Each relay on a control processor is identifiable by port name (RLY1, RLY2, etc.).

Relay1 = RelayInterface(Proc, 'RLY01')


Relay2 = RelayInterface(Proc, 'RLY02')

There are several methods to control the state of the relay: Pulse, SetState, and Toggle.

Relay1.Pulse(2.25) # Pulse the relay on for 2.25 seconds


Relay2.SetState(1) # Close the relay
Relay2.SetState(0) # Open the relay
Relay1.Toggle() # Set the relay to the opposite state – no parameter required

The state of a relay can be stored in a variable and used in later conditional statements based on the state
property.

Relay2Status = Relay2.State

Switched Power Interface


The IPCP Pro 555 and IPCP Pro 550 control processors include 12 volt switched power outlets that can be
controlled in a similar manner to the relay interface. These power outlets are instantiated using the
SWPowerInterface class of the interface package.

Power1 = SWPowerInterface(Proc, 'SPI1')


Power2 = SWPowerInterface(Proc, 'SPI2')
Power1.SetState('Off') # Set the switched power outlet #1 off
Power2.SetState('On') # Set the switched power outlet #2 on

Contact Interface
Contact inputs, such as those on the IPL Pro CR88, sense a closure of an external contact or switch between
the input port and ground. A contact input is instantiated using the ContactInterface class of the interface
package. The parameters required are the identifier for the processor and the input name. There are no
methods for controlling this port, but it does have the property for the current state of the input. When a closure
is made on this port, a "StateChanged" event can be used to trigger an associated function. In the following

Page 65
Extron Control System Programming Using Python

function, when the contact state changes to "On", a message is shown on the specific touchpanel. It could
however trigger any action to occur in the system.

Contact1 = ContactInterface(Proc, 'CII1')

@event(Contact1, 'StateChanged')
def Contact1Change(interface, state):
if state is 'On'
TLP.ShowPopup('PartitionMessageClose')
else:
TLP.ShowPopup('PartitionMessageOpen')

Digital I/O Interface


The behavior of the Digital I/O Interface port for Extron Pro Series devices is determined by how it is
instantiated in the system using the DigitalIOInterface class. When in Digital Input mode, it works similar to the
Contact interface. The DigitalIOInterface class has a keyword argument labeled Mode that will determine the
operation of the port. It defaults to "DigitalInput". In the code example, the ports are instantiated as DigitalIO1
set to the Digital Input mode, and as DigitalIO2 set to the Digital Output mode.

DigitalIO1 = DigitalIOInterface(Proc, 'DIO1', Mode='DigitalInput')


DigitalIO2 = DigitalIOInterface(Proc, 'DIO2', Mode='DigitalOutput')

There is also an additional keyword argument that is not shown in the example, "Pullup" which has a default
value of False. As with all Python classes or functions, keyword arguments that have default values are optional
and do not need to be declared when calling the class or function. With this in mind, the port DigitalIO1 could
be defined as follows, if the default values for Mode and Pullup are appropriate:

DigitalIO1 = DigitalIOInterface(Proc, 'DIO1')

If the pull-up resistor is to be used in the interface circuit, overwrite the default value and specify that Pullup
should be True.

DigitalIO1 = DigitalIOInterface(Proc, 'DIO1', Pullup=True)

However, with readability being a goal of any good program, providing each of the arguments makes it most
clear.

DigitalIO1 = DigitalIOInterface(Proc, 'DIO1', Mode='DigitalInput', Pullup=True)

When set to the Digital Input mode, a "StateChanged" event is triggered when the state changes. This works in
the same manner as the StateChanged event of the ContactClosureInterface.

Page 66
Extron Control System Programming Using Python

Flex I/O Interface


The Flex I/O Interface port adds analog voltage input capability to an Extron control system. The Flex I/O has
three modes of operation: digital input, digital output, and analog input. When operating as a digital input or
digital output, this interface will work like the DigitalIOInterface class described previously. However, when the
mode is set to "AnalogInput" it can sense a voltage in the range from 0 to 25.3 volts DC at the input. In the
example, Flex I/O ports 1 to 3 have been defined as an Analog Input, Digital Input, and Digital Output.

FlexIO1 = FlexIOInterface(Proc, 'FIO1', Mode='AnalogInput')


FlexIO2 = FlexIOInterface(Proc, 'FIO2', Mode='DigitalInput', Pullup=False)
FlexIO3 = FlexIOInterface(Proc, 'FIO3', Mode='DigitalOutput')

Two additional parameters are provided to set the upper and lower voltage thresholds for when the Flex I/O
port is set to the Digital Input mode. This can be set either at the time the port is instantiated or it can be
initialized as shown below.

FlexIO2.Initialize(Upper=3.0, Lower=1.9)

When set to the Digital Input mode, a "StateChanged" event is triggered when the state changes beyond the
set threshold values. When in the Analog Input mode, an "AnalogVoltageChanged" event is triggered when the
voltage changes more than 0.05 volts.

Page 67
Extron Control System Programming Using Python

Standard Package Libraries


The ControlScript Standard package includes restricted or modified versions of standard Python libraries.
These libraries have been altered to meet the requirements for an AV control system while maintaining the
integral security of the system. The first library added to this package is the exml modules library. These
modules provide the same functionality as the standard Python xml modules. This is not intended as a
comprehensive discussion regarding the Python xml modules, but it will demonstrate how to retrieve data from
an XML document using the etree.ElementTree module.

exml ElementTree Module


The ElementTree module, which is part of the etree library, provides many methods for manipulating an
XML document. Below is a sample XML document representing the "What's New" RSS feed from the Extron
website. It is important to understand the elements, referred to as tags, of the XML document you will be
working with.

The parse module of the ElementTree processes the XML document into an object that can then be searched
for the desired information. Before the parse method can be used, it must first be imported into the
ControlScript program.

from extronlib.standard.exml.etree.ElementTree import parse

After it is imported it can be used directly on an XML document.

FeedContent = parse(rssfeed)

Page 68
Extron Control System Programming Using Python

This line of code will parse the XML document into an XML object referred to as FeedContent in this program.
Once the document has been parsed, the programmer can use the ElementTree object methods called find( ),
iterfind( ), and findtext( ) are used to retrieve the data stored in the tags of the XML document called 'title',
'pubDate', 'category', 'description', and 'link'.

for item in FeedContent.iterfind('channel/item'):


title = item.findtext('title')
print(title)
pubDate = item.findtext('pubDate')
print(pubDate)
category = item.findtext('category')
print(category)
desc = item.findtext('description')
print(desc)
link = item.findtext('link')
print(link)

Referring back to the XML document listed above, you can see that the for loop processes each tag called
'item' found inside the 'channel' tag, one at a time, retrieving the text found in each of the tags listed. Now that
the information has been saved to individual identifiers, the programmer can use this for any purpose such as
displaying this information on a touchpanel.

For more information about the exml modules, refer to the documentation regarding the standard Python xml
modules.

Page 69
Extron Control System Programming Using Python

System Package
The System package includes several tools that Extron created for AV systems. These tools are classes and
methods that help with timing in a program, scheduling programmed actions, sending email notifications,
reading and writing files to a system, as well as object grouping, and other system actions. Tools in the System
package can be imported along with other objects or individually.

Mutually Exclusive Sets


The MESet class of the System package provides the ability to group similar objects in which only one object
can have its state set to 'On' at the same time. This class will work on any object containing a SetState method
that can accept an integer as a parameter.

Consider the example shown in the User Interface Navigation Programming section. The input selection
buttons are used to show the appropriate popup page on the touchpanel. However, in that example we did not
change the button state to indicate which input was selected. One way to do this is to add all of these input
buttons to a mutually exclusive set, then set the appropriate button when it is pressed. Since only one can be
'On' at a time, the MESet class will turn off the other buttons.

Following the instantiation of the buttons, an MESet object is created containing each button object in a list.

SelectLaptop = Button(TLP, 8050)


SelectPC = Button(TLP, 8052)
SelectBluray = Button(TLP, 8054)
SelectDocCam = Button(TLP, 8058)
SelectTuner = Button(TLP, 8060)
SelectAux = Button(TLP, 8062)
InputBtnSet = MESet([SelectLaptop, SelectPC, SelectBluray, SelectDocCam,
SelectTuner, SelectAux])

The MESet class can also accept a list identifier as an argument instead of listing the buttons individually as
shown. Both are functionally equivalent.

InputBtnList = [SelectLaptop, SelectPC, SelectBluray, SelectDocCam,


SelectTuner, SelectAux]

InputBtnSet = MESet(InputBtnList)

The SetCurrent method of the MESet class is used to turn 'On' a specific button. This can be used wherever
appropriate in the program. In the following example, it is placed inside the event when an input selection
button is pressed.

Page 70
Extron Control System Programming Using Python

@event(SelectLaptop, 'Pressed')
@event(SelectPC, 'Pressed')
@event(SelectBluray, 'Pressed')
@event(SelectDocCam, 'Pressed')
@event(SelectTuner, 'Pressed')
@event(SelectAux, 'Pressed')
def SelectInputButtonPressed(button, state):
print('button pressed: {0}, ID - {1}'.format(button.Name, button.ID))
InputBtnSet.SetCurrent(button)

A mutually exclusive set is frequently used for devices that are controlled by relays or other contact output
ports. In many cases it would be detrimental or even dangerous for more than one relay or output port to be
active at the same time. Rather than directly controlling the relay, the programmer could simply set which relay
is currently active in a mutually exclusive group, preventing the other relays from closing.

RelayScreenUp = RelayInterface(ProProcessor, 'RLY1')


RelayScreenDown = RelayInterface(ProProcessor, 'RLY2')
RelayScreenStop = RelayInterface(ProProcessor, 'RLY3')

ScreenRelaySet = MESet([RelayScreenUp, RelayScreenDown, RelayScreenStop])

Once the MESet has been created, the programmer can simply call the SetCurrent( ) method of the MESet
class with the appropriate relay object. This closes the relay object, and opens the other relays.

ScreenRelaySet.SetCurrent(RelayScreenUp)

A programmer can use the MESet class with any object, including class objects created by the programmer,
as long as the objects have a SetState method that can accept an integer as an argument.

Tools Within the System Package


In addition to the class objects, several tools are available as part of the System package. These tools include
GetSystemUpTime( ), Ping( ), ProgramLog( ), and WakeOnLan( ).

These tools can be imported from the System package along with other objects or individually:

from extronlib.system import GetSystemUpTime, Ping, ProgramLog, WakeOnLan

GetSystemUpTime( ) takes no parameters and simply returns an integer indicating the number of seconds
elapsed since the system began. This can be used in any way desired by the programmer.

Page 71
Extron Control System Programming Using Python

print(GetSystemUpTime())

UpTime = GetSystemUpTime()

Ping( ) will send a ping message from the controller's Ethernet port to the provided IP address or hostname
and will return the results as successful or failure, and the average time for the successful pings. The
command can accept two parameters, the hostname or IP address formatted as a string and the number of
times to try the ping message. By default, the count is set to 5.

Ping('192.168.31.32', 5)

Ping( ) can be used programmatically to verify communication to a device if commands or responses from that
device have stopped.

The ProgramLog( ) method is used to send messages to the program log of the controller. This method will
also display a Trace message if Trace is running. The program log has three levels of severity that can be
supplied with the message: 'info', 'warning', or 'error'. By default, the severity is set to 'error.' The programmer
can set the severity level when the ProgramLog( ) method is called as follows:

ProgramLog('ProgramLogInfoMessage', Severity = 'Info')

In the following program, if the Ethernet device does not connect, Ping( ) can be used to verify communication
with the device. In the program log and Trace Messages window, we can see that the device failed to respond
to the Ping( ) three times.

Page 72
Extron Control System Programming Using Python

def ConnectSMD():
result = SMDPort.Connect(5)
if result == 'Connected':
SMDPort.Send('W3CV\r')
SMDPort.StartKeepAlive(30, 'Q')
else:
print('ConnectSMD Result:', result)
host = SMDPort.IPAddress
try:
host = SMDPort.IPAddress
success, failure, average = Ping(host)
if success == 5:
ProgramLog('Ping to SMD {0} averaged {1} seconds'.format(host,
average), 'info')
elif failure < 3:
ProgramLog('Ping to SMD {0} failed {1} times'.format(host,
failure), 'warning')
else:
ProgramLog('Ping to SMD {0} failure rate {1}% '.format(host,
failure/5*100), 'error')
except (Exception) as e:
print('Except Error', e)

Page 73
Extron Control System Programming Using Python

WakeOnLan( ) is a tool that will send the "Magic Packet" as a broadcast message on UDP port 9 to wake a
specified computer that is set to activate using the WakeOnLan standard. This method takes a single
parameter – the MAC address of the Ethernet port on the target computer formatted as a string:

WakeOnLan('01-23-45-67-ab-cd')

This can be used in rooms where a computer needs to be turned on when the system is activated by including
this method in the start-up functions of the room.

Programming Timing Events


ControlScript provides several different class objects that can be used to trigger events based on an interval, a
delay, or for a specific time. These are the Clock, Timer, and Wait class objects. The Clock class is used to
schedule a function for a specific time on a specific day of the week. The Timer class is used to execute a
function at regular intervals. The Wait class is used to delay a function for a specific period of time.

Programming a Recurring Function Using a Timer


There comes a time where you find you need to have a function repeating at a regular interval. The Timer class
was made specifically to fit this need. Consider a device, such as a 4K display, that will not send unsolicited
responses about its current state. Using a Timer as a decorator, as shown in the following example, the
DisplayPolling function will continue to repeat at the interval specified.

@Timer(5) # Every 5 seconds call the DisplayPolling function.


def DisplayPolling(timer, count):
MainDisplay.Send('get Input\r')
if not count % 12: # Every 12th time request Power status.
MainDisplay.Send('get Power\r')

This @Timer decorator will continue to execute the HandlePolling function every five seconds as long as the
control processor is running this program. In many cases this is exactly what is needed. However, in other
cases it would be good to be able to change the interval or even stop and start the Timer. The Timer class
provides the ability to name a Timer which then can be modified as needed by the program.

Let's say we wanted the ability to only poll the display when the AV system is turned on. In this case we can
create the DisplayPolling function, then create a named instance of the Timer class referencing the
DisplayPolling function as shown below:

def DisplayPolling(timer, count):


MainDisplay.Send('get Input\r')
if not count % 12: # Every 12th time request Power status.
MainDisplay.Send('get Power\r')

# Every 5 seconds call DisplayPolling function using the DisplayPolling Timer.


DisplayPollingTimer = Timer(5, DisplayPolling)

Page 74
Extron Control System Programming Using Python

Now we can modify when the Timer is running by using the Stop( ), Pause( ), and Restart( ) methods of the
Timer class. For instance, when the Start button is pressed we can pause polling the display, since some
devices cannot accept incoming commands while the power is being turned on.

# Pause Timer when Start button is pressed and Display turns on


@event(StartBtn, 'Pressed')
def StartBtnEvent(button, state):
DisplayPollingTimer.Pause()
Display.Send('set Power On\r')

# Restart Timer when Display is on


# set Power On\r replies with 'Power On' when it is completed
@event(Display, 'ReceiveData')
def DisplayDataEvent(interface, data):
if 'Power On' in data.decode():
DisplayPollingTimer.Restart()

# Stop Timer when SystemPowerDown button is pressed


@event(SystemPowerDownBtn, 'Pressed')
def SystemPowerDownBtnEvent(button, state):
DisplayPollingTimer.Stop()
Display.Send('set Power Off\r')
# Do other power down things

The Timer class also provides a method to change the interval of a Timer as needed using the Change method.
Other attributes of the Timer class include State, Interval, Count, and Function, as well as a StateChanged
event that is triggered whenever the State of a timer changes among 'Running', 'Paused', and 'Stopped'.

@event(DisplayPollingTimer, 'StateChanged')
def DisplayPollingStateChanged(timer, state):
if state == 'Running':
ShowTimerRunning()
elif state == 'Paused':
ShowTimerPaused()
else:
ShowTimerNotRunning()

Delaying a Function Using a Wait


Waits can be used as a one-time event, or a Wait can be named and reused throughout the program.

One-Time Wait as a Decorator


A function can be decorated with a Wait to provide a one-time delay for that function. Consider the following
function:

Page 75
Extron Control System Programming Using Python

# Function containing tasks to perform when power is restored to the system


# or when the program is reloaded.
def PowerupTasks():
print('Begin Powerup Tasks')
TLP1.ShowPage('Start')
RoomNameLabel.SetText(RoomName)
UserMessageLabel.SetText('System is Ready for Use')
PowerupTasks()

If, after some testing, it was determined that it takes a few seconds for the system to initialize, a short delay is
required. The @Wait decorator can be added before the function definition with an appropriate delay time. As
noted on the last line of the example, it is not necessary to call the function directly as was shown in the first
example.

# Function containing tasks to perform when power is restored to the system


# or when the program is reloaded.
@Wait(5) # Wait 5 seconds before executing the Powerup Tasks
def PowerupTasks():
print('Begin Powerup Tasks')
TLP1.ShowPage('Start')
RoomNameLabel.SetText(RoomName)
UserMessageLabel.SetText('System is Ready for Use')
# The function is called automatically from the @Wait decorator

Named Waits
If a delayed function is to be used multiple times, it would be preferable to name the Wait and then reuse and
potentially modify the Wait as needed in the program or from the user interface. The amount of delay in a
named Wait can be extended, changed, cancelled, and restarted as needed. For example, when displaying a
popup page, the delay before automatically closing the popup page can be changed if a button event occurs.
Consider a popup for adjusting the audio in an AV system. When the popup is first displayed, a Wait can be set
to a specific time. If a volume control button is pressed or released, the delay can be changed to ensure that
the popup does not close while adjustments are being made or for a period of time after a button is released.

AudioControlButton = Button(TLP1, 8110, holdTime = None, repeatTime = None)


PopupPageDelay = None
def ClosePopupPage():
TLP1.HidePopup(37)

@event(AudioControlButton, 'Pressed')
def AudioControlButtonPressed(button, state):
global PopupPageDelay
TLP1.ShowPopup(37,0)
PopupPageDelay = Wait(15, ClosePopupPage)

Page 76
Extron Control System Programming Using Python

When the button is pressed, the time of the Wait can be restarted to prevent the page from closing too soon.
(Actual commands to control the volume have been omitted for brevity.)

MainVolUpButton = Button(TLP725, 8120, holdTime = 2, repeatTime = 0.2)


@event(MainVolUpButton, 'Pressed')
def MainVolUpPressed(button, state):
PopupPageDelay.Restart() # Restart the delay with the initial delay time
MainVolUpButton.SetState(1)

When the released event occurs, the delay can be changed to a lower value.

@event(MainVolUpButton, 'Released')
def MainVolUpReleased(button, state):
PopupPageDelay.Change(5) # Change delay to close 5 secs after button is released
MainVolUpButton.SetState(0)

If the Close button on the popup page is pressed, the named Wait can be cancelled.

AudioControlCloseButton = Button(TLP, 9027)


@event(AudioControlCloseButton, 'Pressed')
def AudioControlClosePressed(button, state):
PopupPageDelay.Cancel() # Cancel Wait
TLP.HidePopup(41)

Time can also be added to a named Wait using the Add method of the Wait class. This will add the specified
time to the current value of the delay. For instance, when the Mute button is pressed, a period of time could be
added to the current wait time.

MainVolMuteButton = Button(TLP, 8021)


@event(MainVolMuteButton, 'Pressed')
def MainVolMute(button, state):
PopupPageDelay.Add(5) # Add 5 seconds to the Wait time

Scheduled Events Based on Clock Times


With the Clock Class, a schedule can be created to specify a time and day that a function should run.
Schedules are typically used for functions that automate a system shutdown, startup, or to simply set variables
to default values. To use the Clock class, import the class from the system package of the extronlib library.

from extronlib.system import Clock

Instantiate a schedule with an identifier for the Clock class with the appropriate parameters: Times, Days, and
the name of the function to be executed.

Page 77
Extron Control System Programming Using Python

The time can be specified as a list of strings formatted as 'HH:MM:SS' using a 24-hour time format.

['19:30:00', '21:00:00']

The days of the week are specified as a list of strings:

['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday',]

Since these lists become quite long if multiple times or all the days of a week are included, it's a best practice to
instantiate lists to be used with the scheduled event definition. Below the days of the week are values in the list
ShutdownDays.

def ScheduledShutdown(interface, event):


global SystemPower=False
TLP.ShowPopup(9) # Show Shutdown Page
@Wait(30)
def HidePopupShutdown():
TLP.HidePopup(9)
# Other functions as needed for shutdown
ShutdownDays=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',]
ShutdownClock=Clock(['19:30:00','21:00:00'], ShutdownDays,
ScheduledShutdown)

Unlike a Wait, once the Clock schedule is defined it needs to be enabled to cause the function to be executed
at the scheduled times. In the code example that follows, a user can enable or disable scheduled events from a
button press on a user interface.

ScheduledShutdownEnableButton = Button(TLP, 8010)


@event(ScheduledShutdownEnableButton, 'Pressed')
def ScheduledShutdownEnablePressed(button, state):
global ScheduledShutdownEnabled
if ScheduledShutdownEnabled == True:
ScheduledShutdownEnabled = False
ShutdownClock.Disable()
ScheduledShutdownEnableButton.SetState(0)
else:
ScheduledShutdownEnabled = True
ShutdownClock.Enable()
ScheduledShutdownEnableButton.SetState(1)
print('Schedule Enabled: {0}'.format(ScheduledShutdownEnabled))

Using File and RFile


The ControlScript System package includes two classes that provide the ability to read and write files stored on
the control processor.

Page 78
Extron Control System Programming Using Python

The File class allows the programmer to read/write files located in a user accessible storage area that can be
externally accessed using an SFTP client with appropriate authorization. The File class accesses this area
using ‘admin’ account privileges. To access the area associated with the ‘user’ account privileges, the file
name should be prefixed with the path "/user/".

The RFile class accesses files that are stored in a restricted storage area. These restricted files can only be
created and accessed within a ControlScript program; they are not accessible externally.

Managing Directories
In the user accessible storage area, a default directory named '/user/' exists. The restricted storage area does
not contain any default directories. Other directories can be managed using the ChangeDir( ), DeleteDir( ),
GetCurrentDir( ), ListDir( ), and MakeDir( ) methods of both classes.

Whereas the ChangeDir( ) and List( ) methods enable the programmer to modify the current working directory
to a newly designated path and to list the directory contents for the user accessible storage area, these
methods behave differently for the RFile class. When the interpreter uses a file from the restricted storage area,
a copy of the file is created. By using ChangeDir( ), the programmer can change the currently working directory
where this copy will be stored. ListDir( ) lists the contents of either the current directory or the directory for
which a path is indicated.

Reading and Writing Files


Reading and writing data to files only requires one parameter – the name of the file to be read. The file name
can include the complete path from the root of the storage area or the relative path from the current directory.
Other parameters are available and are described in the Extron Library documentation.

In the following example, a function has been created to save selected system data to a file that can be used to
return the system to a previous state. (Please be aware this program was written only to support data types that
can be converted to a string type when written to a file. This approach was taken so that both the program and
the written file are easy to read and modify.) By default, the File class will open the file in read mode, therefore
in the SaveData function the File class opens the file in write mode by adding the 'w'. The File and RFile classes
utilize the same modes as the Python built-in function Open. The function writes the information to the file using
the write( ) method.

# Function to Save System State Data to a file


def SaveData(DataToFile, filename='data.txt'):
with File(filename, mode='w') as datafile:
DataAsString = ''
for key in DataToFile:
DataAsString = ''.join((DataAsString, str(key), ':' ,
str(DataToFile[key]), ','))
DataAsString = DataAsString[:-1] # Remove trailing comma from string
print('Saving Data to file: ', DataAsString)
datafile.write(DataAsString)

A companion function has also been created to read from a file formatted in the manner of the SaveData
function. This function opens the file for reading using the File class with the mode parameter set to 'r'. In this

Page 79
Extron Control System Programming Using Python

function, a try/except conditional framework is used to handle the exception if a file named 'data.txt' is not
found.

# Function to Retrieve System State Data from a file


def RetrieveData(DefaultData, filename='data.txt'):
try:
with File(filename, 'r') as datafile:
DefaultData = {}
for element in datafile.read().split(','):
ReadValue = element.split(':')
DefaultData[ReadValue[0]] = ReadValue[1]
DefaultData['CurrentVolLevel'] = int(DefaultData['CurrentVolLevel'])
except FileNotFoundError as ErrMsg:
ProgramLog('File not found: {} - Using default data.'.format(filename),
'error')
print(DefaultData)
return DefaultData

In both functions, the "with" statement code block is used to ensure the file is closed properly when reading or
writing the file is completed. Therefore, the file.close method is not required since the file is closed when the
code associated with the "with" statement code block ends.

Using the RFile class, the programmer can upload files to provide initial values via the Global Scripter project.
When files within the restricted area are programmatically modified, the interpreter uses a copy of the files,
leaving the original files stored in the Global Scripter project on the processor unmodified. Each time that the
Global Scripter project is reloaded, the versions contained in the project are placed within the same restricted
storage area, overwriting any previously modified versions of the same name.

Deleting Files
The File and RFile classes include a DeleteFile( ) method that enables a programmer to remove a file. When
accessing files using the File class, the DeleteFile( ) method can be used to remove one or more files from the
user accessible storage area. The file is therefore also removed from the Global Scripter project.

When working with files in the restricted storage area using the RFile class, DeleteFile( ) only deletes the copy
of the file that resides in the restricted area. The original file will remain in the Global Scripter project.

Page 80
Extron Control System Programming Using Python

Debugging Tools
Global Scripter provides several debugging tools to assist with troubleshooting a program. These tools enable
you to inspect specific sections of a program and examine variable behavior while a program is running in
debug mode.

Breakpoints
Breakpoints can be placed within a program to inspect specific sections of code in one or more code files in a
project. When the interpreter encounters a breakpoint, further interpretation is suspended until Continue
Debugging is selected. To add a breakpoint to a line of code, click on the Toggle Breakpoint option from the
Debug menu or from the toolbar. The breakpoint will be placed at the beginning of the selected line.
Additionally, clicking on the space to the right of the line number will also add a breakpoint to the line.

In order to run the program with breakpoints select Start Debugging from the Debug menu. This will
synchronize the code in the editor with the code on the control processor, and once this is complete, the
interpreter begins running the program up to the first breakpoint. The Messages window will display a message
as the interpreter encounters a breakpoint, as shown in the following example.

Page 81
Extron Control System Programming Using Python

To proceed to the next breakpoint, select Continue Debugging from the Debug menu. Breakpoints occur
before the first character on a line, which signifies that a program running in debug mode will stop executing
the code prior to that line. If a breakpoint is placed inside an event, it will only be triggered when that event
occurs. This can be seen in the following example where the breakpoint will only occur by pressing the Start
button on the Main page of the touchpanel.

Page 82
Extron Control System Programming Using Python

To exit debugging mode select Stop Program/Debugging from the Debug menu. Then, re-run the program
by selecting Start Program.

When breakpoints are no longer needed in a project, selecting Delete All Breakpoints from the Debug menu
will remove the breakpoints from all of the code files in the project.

The following keyboard shortcuts correspond to the options within the Debug menu. For a complete list of
shortcuts, please refer to the documentation within Global Scripter.

Keyboard Shortcut Command


<Ctrl + F5> Start Debugging

<F5> Continue Debugging

<F9> Toggle Breakpoint

Variables and Watch Variables


When a breakpoint is encountered, Global Scripter will display information about the variables at that point in
the program. This is helpful in many instances, such as when troubleshooting conditional logic statements.
Details about variables in a program can be viewed in the Variables and Watch Variables window, which are
accessible through the View menu.

Page 83
Extron Control System Programming Using Python

The Variables window displays local variables and global variables, with the option to filter the variable list to
only locals or globals as desired. The interpreter will load the variables into this window each time it encounters
a breakpoint when running the program in debug mode. Only the variables that are defined in the context of the
breakpoint will be shown. A variable will have its value shown in red if the variable has changed since the last
breakpoint was encountered.

If there are variables of specific interest, they can be copied into the Watch Variables window via drag and drop
to inspect their behavior while the program is running. These variables will be updated in the Watch Variables
window every time the breakpoint is encountered, similar to those in the Variables window. If a variable no
longer exists at the current scope, it will be removed from the Variables list. Variables will re-appear in the list
when continuing to run through the breakpoints and returning to that scope. To clear all variables being
watched in the program, select Clear All in the Watch Variables window.

Page 84
Extron Control System Programming Using Python

Appendix A - Resources for Learning Python


For a programmer with very little experience or someone who simply needs a refresher on advanced topics,
there are many resources available to aid in the understanding of Python. This is by no means a
comprehensive list and may not include some very beneficial references, but it is intended as a good starting
point.

Books and E-Books


l McGrath, Mike. Python in Easy Steps. Leamington Spa, Warwickshire, U.K.: In Easy Steps, 2013

l Lutz, Mark. Learning Python. 5th ed. Sebastopol: O'Reilly, 2013.

l Pilgrim, Mark. Dive into Python 3. New York: Apress, 2009.


(Also available as an e-book http://www.diveintopython3.net at no cost.)

l Harrison, Matt. Guide To: Learning Python Decorators.: CreateSpace Independent Platform, 2013.

Websites and Tutorials


l https://www.python.org

l https://docs.python.org/3.3/tutorial/

l https://www.python.org/dev/peps/pep-0008/ - Python Style Guide

l http://www.coursera.org/course/interactivepython

l http://www.learnpython.org

l http://www.codecademy.com/tracks/python - This tutorial references Python 2.7, but does give a good
overview of Python

Page 85
Extron Control System Programming Using Python

Appendix B - Disallowed Python Objects


The following Python objects are excluded from use in ControlScript.

Disallowed Built-Ins
compile exit locals
dir globals open
eval help quit
exec input SystemExit
vars

Disallowed Non-Built-In Modules


__future__ imp shlex
_pyio importlib shutil
_strptime inspect signal
aifc io site
argparse linecache smtpd
ast locale smtplib
asynchat logging sndhdr
asyncore lzma socket
atexit mailbox socketserver
bdb mailcap spwd
builtins marshal sqlite3
bz2 mimetypes sre_compile
cgi mmap sre_constants
cgitb modulefinder sre_parse
cmd msilib ssl
code msvcrt stat
codecs multiprocessing subprocess
codeop netrc sunau
compileall nis symbol
concurrent nntplib symtable
configparser ntpath sys
copyreg nturl2path sysconfig
cProfile opcode syslog
crypt optparse tabnanny
ctypes os tarfile
curses os2emxpath telnetlib
dbm ossaudiodev tempfile
difflib parser termios
dis pdb test

Page 86
Extron Control System Programming Using Python

disutils pickle threading


doctest pickletools timeit
dummy_threading pipes tkinter
email PixMapWrapper token
faulthandler pkgutil tokenize
fcntl platform trace
filecmp plistlib traceback
fileinput posix tty
fnmatch posixpath turtle
fpectl profile unittest
ftplib pstats uu
gc pty venv
genericpath pwd wave
getopt py_compile webbrowser
getpass pyclbr winreg
gettext pydoc winsound
glob quopri wsgiref
grp readline xml
gzip resource xmlrpc
hotshot rlcompleter zipfile
http runpy zipimport
idlelib select
imghdr shelve

Page 87
Extron Control System Programming Using Python

Glossary

A Build Code Only


The process of uploading only the code files
Application Licensing associated with the project to the primary control
Consists of user/programmer certification and processor.
application authorization. Global Scripter requires
that the user maintain an Extron Insider Account Build Message
and is licensed to use the application based on A message that displays information, a warning, or
meeting appropriate certification criteria. an error regarding the build process for the
Licensing occurs with both online and offline currently selected system in the Build Messages
options. window.

Argument Build Project


A value that is passed to a function when making a The process of preparing all the files in the project,
function call. A keyword argument is preceded by verifying that the hardware in the project is ready,
an identifier in a function call, and once arguments and uploading the files and settings to the primary
are specified by keywords, they no longer need to control processor and appropriate hardware.
be presented in the same order that the
parameters were defined. Positional arguments, Built-In Function
by default, are presented in the order in which the One of many blocks of organized, reusable code
parameters of the object are defined. built into Python for performing actions when
invoked by a call method. Note that some Python
Attribute built-in functions are disallowed in ControlScript.
A variable that is associated to a specific instance
of a class, or to the class itself.
C

B Class
Defines a set of attributes that characterize any
Bookmark object of a class. These attributes include class
A flag inserted by the programmer to track a key variables, instance variables, and methods, which
line of the code. are accessed via dot notation.

Boolean Code Editor


One of the two constant objects "True" and "False" One of the main areas of the Global Scripter
representing a truth value. In numeric contexts, application for editing code files using typical code
Boolean values behave similar to integers 0 and 1, editing functions and programming-specific
respectively. features.

Breakpoint Code File


A pause in the code that is intentionally placed by A file that contains the ControlScript code required
the programmer when debugging a section of the for a program.
program. When the interpreter comes across a
breakpoint during runtime, the program pauses Code Snippet
and allows the programmer to verify the code at A reusable block of code that can be inserted into a
that point by inspecting variable values and states. program to save time when incorporating a
commonly used function.

Page 88
Extron Control System Programming Using Python

Comment/Uncomment Dictionary
To comment means to annotate a portion of the A collection of unordered values that are accessed
code with programmer notes, using a specific by key rather than by index. For each key, there is
syntax. Lines of code can be commented so that an associated value.
they are temporarily ignored by the compiler. To
uncomment means to remove the characters that Docstring
are typically added before a comment. A Python documentation string that associates
documentation with Python modules, functions,
Constant classes, and methods. It is defined by including a
A value that is defined on a module level and does string literal, indicated by triple double quotes ("""),
not change anywhere in the program. Constants as the first statement in an object’s definition.
should be written in only uppercase characters
with an underscore character between words.
E
Control Port Interface Entry Code File
One of several classes pertaining to various A specific Python code file into which other
control ports, such as a relay port or a serial port, program files, modules, are imported. This is the
that are instantiated using a specific block of code file that is read and parsed upon initialization of the
in the Code Editor window of Global Scripter. Python interpreter.

ControlScript Escape Sequence


The programming library that accompanies Extron A sequence of characters used within a character
Global Scripter. It is a simple and consistent literal or string literal to express characters that are
control methodology that handles message not printable or conflict with the syntax.
queuing and interfacing with low level firmware
and automation processes. Event
The event decorator is preceded by an "@" symbol
D in the code, i.e. @event.

Data Type Extensible


A particular kind of data item as defined by the Capable of being extended. Python 3.3 is object
values it accepts or the operations that can be oriented and extensible, which allowed Extron to
performed on it. customize it for use in AV control system
environments.
Decorator
Using syntax where an "@" symbol precedes the Extron Library
name of a function or method, a decorator wraps a The Extron Library is a collection of pre-
function or method and modifies its behavior. assembled, reusable programming objects that a
programmer can call when writing code,
Deprecated minimizing the steps of writing a full routine.
Keywords that are no longer recommended and
should be avoided.
F
Device Alias Floating Point Number
A user-friendly name for control system hardware A numeric type supported by Python. A floating
that is used in ProcessorDevice, UIDevice, and point number is one where there is no fixed
eBUSDevice instantiation. number of digits before or after the decimal point.

Page 89
Extron Control System Programming Using Python

Function Initialization
A block of organized, reusable code used to The process of defining a function that is used by a
perform actions when invoked by a call method. program when called.

Instantiation
G The creation of an instance of an object.
Global Scripter
Integer
An integrated development environment that is
A numeric type supported by Python. An integer is
used to program Extron Pro Series Control
a whole number that does not include any decimal
Systems. It includes all the tools needed for
places.
developing control system programming, as well
as the ControlScript API. Global Scripter requires Interpreter
that the user/programmer maintain an Extron A computer program that directly executes
Insider Account and is licensed to use the instructions written in a programming language,
application. without compiling them into machine code prior to
execution. An interpreter allows examination and
Global Variable
modification of the program while it is running.
A variable that is defined in the main body of a file
and intended to be used throughout the program. Iterator
An object that allows a sequential or "next item"
Graphical Object
method to access items present in a container,
A design element in a GUI layout, such as a button,
such as in lists or other data structures, one at a
that can be assigned a control function.
time.
GUI Layout
A graphical touchscreen layout that is designed L
with controls to suit the needs of an AV control
system, such as transport controls or those for List
switching input sources. A collection of ordered values that are accessed
by index. The index in Python starts at 0.

I List Comprehension
A convenient way to modify information from one
Immutable
list to a new list.
An object that cannot be modified after it is
created, such as numbers or strings. Local Variable
A variable that is defined inside a function, and
Import
exists for as long as the function is executing.
The process of making the code in one module
available to another module, which allows the use Loop
of functions defined outside of the entry code file. A sequence of instructions that is continually
repeated until a certain condition is reached.
Indentation
Space at the beginning of a line that is used to
define blocks of code, as well as to group and
promote program flow.

Page 90
Extron Control System Programming Using Python

M Primary User Interface


The user interface that will serve as the main point
Main.py of control for the AV control system, such as a
A Python code file that is generated when the first TouchLink Pro touchpanel.
control processor is added to a system in Global
Scripter. Also referred to as the Entry Code File. Processor Device
A block of code that instantiates the control
Method processor class in the Code Editor window of
A type of function that is defined in a class Global Scripter.
definition.
Program
Mirrored User Interface A set of coded instructions that a control processor
A user interface that displays the same graphical can understand to produce a desired result.
content and controls as the primary user interface.
Program Log
Module Lists errors and other helpful information about a
Part of the program that is independently program while it is running.
developed for reuse in different applications. Using
modules in a program makes it more readable and Project Level File
allows easier code troubleshooting. A file that is associated with a specific project in
Global Scripter. This type of file can be linked to
Mutable any control system in the project.
An object that can be modified after it is created,
such as dictionaries or lists.
R

O Regular Expression
A special sequence of characters that helps match
Object or identify other strings, such as to match varying
A unique instance of a data structure that is sets of characters or to specify that portions of a
defined by its class. An object is comprised of class regular expression must be repeated a certain
variables or instance variables, and methods. number of times. Regular expressions are
compiled into pattern objects, which have methods
Object Oriented Programming
for various operations. The module is included in
A paradigm that makes it easy to model real life
the Entry Code File by using the "import re"
objects into software objects for programming. For
statement.
example, a touchpanel has characteristics like a
graphical user interface, brightness, motion sense, Reserved Keywords
and volume. These characteristics can be These words are reserved for system use in
modeled as properties and methods of a programming and cannot be used as identifiers.
touchpanel object in OOP - Object Oriented
Programming languages.
S

P Secondary Control Processor


A control processor that is added subsequent to
Primary Control Processor the primary control processor and is used for port
The control processor that runs the Entry Code File expansion when the system requires more ports
and to which secondary control processors, user than are available on the primary control
interfaces, or code files can be added. processor.

Page 91
Extron Control System Programming Using Python

Secondary User Interface U


A user interface that serves as another option for
interacting with the AV control system, such as UIDevice
Extron Control for Web, but requires the Primary A block of code that instantiates the user interface
User Interface to remain connected. class in the Code Editor window of Global Scripter.

Slice V
An object containing extracted elements, such as
from a string, based on a start and stop point. Variable
A container for a value that may change. A class
String variable represents an attribute or method shared
A list of characters that form words or phrases, by all instances of a class, while an instance
such as "Hello world!" to be displayed or exported variable represents data unique to each instance
from the program. Strings are indicated using of a class.
single quotes, double quotes are used to
encapsulate a string that includes a single quote, Variable Scope
and documentation strings use triple double-quote The part of a program where a variable is defined
marks. and accessible. Scope rules determine when the
same variable name does or does not refer to the
Subclass same thing.
A class that is derived from another class and
inherits one or more entities from the parent class. Version
A particular form of a project file that differs in
Syntax certain respects from an earlier form of the file.
The set of rules that defines how symbols or
characters can be put together to form a correctly
structured and valid program. W

Watch Variables
System Level File
The process of watching for value changes in local
A file that is associated with a project on a system
or global variables while a program is running. This
level, such as a .py code file. This type of file is only
can be helpful when troubleshooting conditional
available to the hardware associated with the
logic statements.
same control system.
Whitespace
T Spaces, tabs, and line feeds used throughout the
program to define blocks or levels of code.
Toolbelt
A powerful Extron utility for managing and
troubleshooting Extron Pro Series control
products.

Trace Message
A message from a debug statement in the code,
which facilitates troubleshooting.

Page 92
Rev. C
2018 Extron Electronics. All rights reserved. All trademarks mentioned are the property of their respective owners. 8/14/2018

You might also like