Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
| indigo_5_documentation:plugin_scripting_tutorial [2011/09/21 16:01] – [Scripting Indigo Plugins] jay | indigo_5_documentation:plugin_scripting_tutorial [2025/04/14 20:10] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Indigo Scripting Tutorial ====== | ||
| + | ===== Talking to the Indigo Server ===== | ||
| + | |||
| + | The [[plugin_guide# | ||
| + | |||
| + | To launch the Terminal utility application (inside //''/ | ||
| + | |||
| + | -- or -- | ||
| + | |||
| + | If you already have a Terminal shell running, you can launch it directly. The file path to the IPH executable is a bit deep, so create an alias to it inside your //'' | ||
| + | |||
| + | < | ||
| + | |||
| + | Next, close the Terminal window and open a new one to load the shortcut alias to the IPH executable. To start the IPH in interactive mode we pass the //'' | ||
| + | |||
| + | < | ||
| + | |||
| + | {{pluginhost_prompt.png? | ||
| + | |||
| + | As shown, the IPH will automatically connect to the IndigoServer running on the same Mac and will show the server' | ||
| + | |||
| + | Next, let's tell the Indigo Server to log a message to the Event Log window (again, via the Terminal application): | ||
| + | < | ||
| + | |||
| + | {{pluginhost_helloworld.png? | ||
| + | |||
| + | ===== Connecting Remotely over SSH ===== | ||
| + | |||
| + | If you have SSH configured so you can remotely connect to your Mac running the Indigo Server, then you can use SSH to start the IPH interactively anywhere using the syntax: | ||
| + | |||
| + | < | ||
| + | |||
| + | ===== What Else Can it Do? ===== | ||
| + | |||
| + | The IPH gives you full access to the [[object_model_reference|Indigo Object Model (IOM)]] providing access to create/ | ||
| + | |||
| + | ===== Executing Indigo Commands Directly ===== | ||
| + | |||
| + | In addition to communicating interactively with Indigo via the shell, you can also send direct python commands to Indigo via the IPH. For example, to get the current brightness of the device " | ||
| + | |||
| + | < | ||
| + | |||
| + | Or to toggle the device " | ||
| + | |||
| + | < | ||
| + | indigo.device.toggle(" | ||
| + | indigo.device.toggle(" | ||
| + | indigo.device.toggle(" | ||
| + | '</ | ||
| + | |||
| + | Note when your commands are executed the indigo module is already loaded and connected and you can execute standard python code (loops, conditionals, | ||
| + | |||
| + | //Caveat:// Each call creates a new IPH (indigohost) process which must establish a connection to the Indigo Server. Although this is relatively fast, calling it multiple times a second is not recommended. | ||
| + | |||
| + | ===== Executing Indigo Python Files ===== | ||
| + | |||
| + | The IPH can also be used to execute Indigo python (.py) files, like this: | ||
| + | |||
| + | < | ||
| + | |||
| + | //Caveat:// Each call creates a new IPH (indigohost) process which must establish a connection to the Indigo Server. Although this is relatively fast, calling it multiple times a second is not recommended. | ||
| + | |||
| + | ===== Shared Classes and Methods in Python Files (Python Attachments) ===== | ||
| + | |||
| + | In Indigo, if you want to write AppleScript handlers that are shared by any script that Indigo executes, you can just put an AppleScript full of handlers in the /// | ||
| + | |||
| + | /// | ||
| + | |||
| + | Any Python files in this directory that define methods and/or classes will be loaded by the Python interpreter whenever it's loaded (note that it's the Library directory at the top level of your boot disk, not the one in your user folder). So, you can create files of handlers you want to share between all Python scripts. Files here can also import the entire IOM - IF the script that's actually running is started by Indigo. Here's a simple shell that you can use that will safely import the IOM and will show a specific error when used from a Python script that's not started by Indigo: | ||
| + | |||
| + | < | ||
| + | """ | ||
| + | indigoAttachments.py | ||
| + | |||
| + | In this file you can insert any methods and classes that you define. | ||
| + | They will be shared by all Python scripts - you can even import the | ||
| + | IOM (as shown below) but if you do then you'll only be able to import | ||
| + | this script in Python processes started by Indigo. If you don't need | ||
| + | the IOM then skip the import and it'll work in any Python script | ||
| + | no matter where it's run from. | ||
| + | """ | ||
| + | |||
| + | try: | ||
| + | import indigo | ||
| + | except ImportError: | ||
| + | print " | ||
| + | raise ImportError | ||
| + | |||
| + | def specialLog(text): | ||
| + | indigo.server.log(text, | ||
| + | </ | ||
| + | |||
| + | Then, when you want to use any of the classes/ | ||
| + | |||
| + | < | ||
| + | indigoAttachments.specialLog(" | ||
| + | |||
| + | If you try to run this script in a normal python session, you'll see the print statement followed by the ImportError: | ||
| + | |||
| + | < | ||
| + | Attachments can only be used from within Indigo | ||
| + | Traceback (most recent call last): | ||
| + | File " | ||
| + | import indigoAttachments | ||
| + | File "/ | ||
| + | raise ImportError | ||
| + | ImportError</ | ||
| + | |||
| + | ===== Scripting Indigo Plugins ===== | ||
| + | |||
| + | Indigo plugins are also scriptable. Because plugin-defined devices look almost identical to built-in devices, you can get (but not set) state information from them (see [[#device examples]] a bit further down for a lot of examples). You can also get some of the other properties for a plugin. Most importantly you can execute plugin-defined actions, which is how you'd set their state values. | ||
| + | |||
| + | The first step is to get an instance of the plugin: | ||
| + | |||
| + | < | ||
| + | iTunesPlugin = indigo.server.getPlugin(iTunesId)</ | ||
| + | |||
| + | This will **always** return to you a plugin object, defined with the following properties: | ||
| + | |||
| + | | pluginDisplayName | ||
| + | | pluginId | ||
| + | | pluginSupportURL | ||
| + | | pluginVersion | ||
| + | |||
| + | There are also a couple of methods defined by this object. | ||
| + | |||
| + | |< | ||
| + | |< | ||
| + | |< | ||
| + | |||
| + | Plugin developers should [[indigo_5_documentation: | ||
| + | |||
| + | ==== Examples ==== | ||
| + | |||
| + | === iTunes Toggle Play State === | ||
| + | |||
| + | < | ||
| + | itunesPlugin = indigo.server.getPlugin(itunesId) | ||
| + | if itunesPlugin.isEnabled(): | ||
| + | itunesPlugin.executeAction(" | ||
| + | |||
| + | === iTunes Set Volume to 50 === | ||
| + | |||
| + | < | ||
| + | itunesPlugin = indigo.server.getPlugin(itunesId) | ||
| + | if itunesPlugin.isEnabled(): | ||
| + | itunesPlugin.executeAction(" | ||
| + | |||
| + | === Pause iTunes and Speak NOAA Weather === | ||
| + | |||
| + | < | ||
| + | itunesPlugin = indigo.server.getPlugin(itunesId) | ||
| + | if itunesPlugin.isEnabled(): | ||
| + | myWeatherStation = indigo.devices[1798384204] | ||
| + | outsideTemp = myWeatherStation.states[' | ||
| + | currentCondition = myWeatherStation.states[' | ||
| + | spokenString = "The current temperature is %s degrees. Current condition is %s." % (outsideTemp, | ||
| + | itunesPlugin.executeAction(" | ||
| + | |||
| + | ===== ===== | ||
| + | |||
| + | Check the various plugin documentation for the necessary information and more examples. | ||
| + | ===== Example Code Snippets ===== | ||
| + | |||
| + | Below are some example you can copy/paste directly into the Terminal application (running the IPH via the //'' | ||
| + | |||
| + | <color red> | ||
| + | |||
| + | ==== Device Examples ==== | ||
| + | |||
| + | ===Turn on the device " | ||
| + | < | ||
| + | indigo.device.turnOn(" | ||
| + | </ | ||
| + | |||
| + | ===Duplicate the device " | ||
| + | < | ||
| + | indigo.device.duplicate(" | ||
| + | </ | ||
| + | |||
| + | ===In 4 seconds turn on the device " | ||
| + | < | ||
| + | indigo.device.turnOn(" | ||
| + | </ | ||
| + | |||
| + | ===Turn off all devices:=== | ||
| + | < | ||
| + | indigo.device.allOff() | ||
| + | </ | ||
| + | |||
| + | ===Count the number of device modules:=== | ||
| + | < | ||
| + | indigo.devices.len() | ||
| + | </ | ||
| + | |||
| + | ===Count the number of dimmable device modules:=== | ||
| + | < | ||
| + | indigo.devices.len(filter=" | ||
| + | </ | ||
| + | |||
| + | ===Count the number of devices defined by all of our plugin types:=== | ||
| + | < | ||
| + | indigo.devices.len(filter=" | ||
| + | </ | ||
| + | |||
| + | ===Count the number of irBlaster type devices defined by our plugin:=== | ||
| + | < | ||
| + | indigo.devices.len(filter=" | ||
| + | </ | ||
| + | |||
| + | ===Get the on state of a device if it has the onState property (uses Python' | ||
| + | < | ||
| + | lamp = indigo.devices[" | ||
| + | if hasattr(lamp, | ||
| + | isOn = lamp.onState | ||
| + | </ | ||
| + | |||
| + | ===Get the class of a device (uses Python' | ||
| + | < | ||
| + | lamp = indigo.devices[" | ||
| + | if lamp.__class__ == indigo.DimmerDevice: | ||
| + | theBrightness = lamp.brightness | ||
| + | </ | ||
| + | |||
| + | ==== Variable Examples ==== | ||
| + | |||
| + | === Create a new Indigo variable named fooMonster, change its value multiple times, and delete it: === | ||
| + | < | ||
| + | newVar = indigo.variable.create(" | ||
| + | indigo.variable.updateValue(newVar, | ||
| + | indigo.variable.updateValue(newVar, | ||
| + | indigo.variable.delete(newVar) | ||
| + | </ | ||
| + | |||
| + | === Getting a variable object and using its value: === | ||
| + | < | ||
| + | if myVar.value == " | ||
| + | indigo.server.log(" | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Duplicating a variable: === | ||
| + | < | ||
| + | indigo.variable.duplicate(" | ||
| + | </ | ||
| + | |||
| + | ==== Date and Time Examples ==== | ||
| + | |||
| + | === Get the current server time: === | ||
| + | < | ||
| + | indigo.server.getTime() | ||
| + | </ | ||
| + | |||
| + | ===Calculate the sunset time in 1 week:=== | ||
| + | < | ||
| + | import datetime | ||
| + | one_week = indigo.server.getTime().date() + datetime.timedelta(days=7) | ||
| + | indigo.server.calculateSunset(one_week) | ||
| + | </ | ||
| + | |||
| + | ==== Action Group Examples ==== | ||
| + | |||
| + | ===Execute Action Group 12345678: | ||
| + | < | ||
| + | indigo.actionGroup.execute(12345678) | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== Log Examples ==== | ||
| + | |||
| + | ===Log to the Indigo Event Log window all the attributes/ | ||
| + | < | ||
| + | lamp = indigo.devices[" | ||
| + | indigo.server.log(lamp.name + ": \n" + str(lamp)) | ||
| + | </ | ||
| + | |||
| + | ===Print the last 5 Event Log entries:=== | ||
| + | < | ||
| + | logList = indigo.server.getEventLogList(lineCount=5) | ||
| + | print(logList) | ||
| + | </ | ||
| + | |||
| + | ==== Folder Examples ==== | ||
| + | |||
| + | ===Iterate over a list of all device folders=== | ||
| + | < | ||
| + | for folder in indigo.devices.folders: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | ===Create a trigger folder named "My Triggers" | ||
| + | < | ||
| + | try: | ||
| + | myFolder = indigo.triggers.folder.create(" | ||
| + | except ValueError, e: | ||
| + | if e.message == " | ||
| + | # a folder with that name already exists so just get it | ||
| + | myFolder = indigo.triggers.folders[" | ||
| + | else: | ||
| + | # you'll probably want to do something else to make myFolder a valid folder | ||
| + | myFolder = None | ||
| + | </ | ||
| + | |||
| + | ===Make a folder visible in remote clients (IWS, Indigo Touch, etc.)=== | ||
| + | < | ||
| + | indigo.devices.folder.displayInRemoteUI(123, | ||
| + | </ | ||
| + | |||
| + | ===Getting the folder a device is in=== | ||
| + | < | ||
| + | lamp = indigo.devices[" | ||
| + | # An object that's not in a folder will have a folder id of 0, which isn't a valid folder | ||
| + | # so we need to make sure it's a valid folder ID first | ||
| + | if lamp.folderId != 0: | ||
| + | lampsFolder = indigo.devices.folders[lamp.folderId] | ||
| + | else: | ||
| + | lampsFolder = None | ||
| + | </ | ||
| + | |||
| + | ==== Miscellaneous Examples ==== | ||
| + | |||
| + | ===Get a list of all serial ports, excluding any Bluetooth ports:=== | ||
| + | < | ||
| + | indigo.server.getSerialPorts(filter=" | ||
| + | </ | ||
| + | |||
| + | === Sending emails === | ||
| + | < | ||
| + | indigo.server.sendEmailTo(" | ||
| + | |||
| + | # Putting a variable' | ||
| + | theVar = indigo.variables[928734897] | ||
| + | theSubject = "The value of %s" % (theVar.name) | ||
| + | theBody = "The value of %s is now %s" % (theVar.name, | ||
| + | indigo.server.sendEmailTo(" | ||
| + | |||
| + | # Putting device data into the subject and body | ||
| + | theDevice = indigo.devices[980532604] | ||
| + | theSubject = " | ||
| + | theBody = "%s is %s\n%s is %s" % (" | ||
| + | indigo.server.sendEmailTo(" | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | FIXME Add examples for: | ||
| + | * refreshing objects | ||
| + | * replacing objects | ||
| + | * enabling/ | ||
| + | * sprinkler control | ||
| + | * etc. | ||