AppleScript Integration Strategies

As published in the The future of AppleScript and Indigo blog post, Indigo 7.3 will deprecate AppleScript communication to the Indigo Server. This article is meant to outline alternatives for using AppleScript and Indigo together.

Note that Indigo will continue to support executing external AppleScripts that do not target the Indigo Server (via a “tell IndigoServer” block), so if you use scripts that just do other things those will continue to work correctly.

Converting Indigo AppleScripts to Python

The preferred way of scripting Indigo is to use the Python scripting integration. Python is an easy-to-use but very powerful scripting language. Although the syntax is different than AppleScript, it seems that most users prefer it after spending just a bit of time getting used to the differences. Indigo's Scripting Tutorial is a great place to see examples for controlling devices, manipulating Indigo variables, executing Action Groups, and much more.

If you have an AppleScript that you are having difficulty converting, then post it on the user forum here. The Indigo community is the best (not an exaggeration!), and if you include both your AppleScript source as well as your attempt at converting it to Python then there will be plenty of others glad to help you.

Running AppleScripts from Python with py-applescript

Converting to Python may not always be possible or desirable and there are alternatives. Turns out there's a great Python module that allows a much tighter integration between Python and AppleScript: py-applescript. It’s included with Indigo 7.1 and later, but you can install it yourself (use sudo pip install py-applescript or see Installing py-applescript from source for details) if you are using an older version of Indigo.

The basics of using py-applescript

Using the module is very simple. As with any Python module, the first thing you want to do is import it:

import applescript

The next step is to create an AppleScript object. This can be done by loading an AppleScript from a file or by using an embedded AppleScript string. Here are examples of both ways:

import applescript

# From a file
path_to_script_file = "/Users/jay/Projects/Python/AppleScriptTest/sample.scpt"
my_ascript_from_file = applescript.AppleScript(path=path_to_script_file)

# From an script in a Python string
ascript_string = '''
say "Hello Python!"
set someDict to {abool: true, afloat: 35.730}
set someList to [1, "two", 3]
return {anum:1, astring:"fun!", adict: someDict, alist: someList}
'''
my_ascript_from_string = applescript.AppleScript(source=ascript_string)

Other than where the script source comes from, these two methods result in an identical Python AppleScript object. The contrived record in the embedded AppleScript string in the example above contains several different value types which are returned.

Finally, running the AppleScript object is quite simple:

reply = my_ascript_from_string.run()

This will execute the run() handler or, if there is none (as in the example), it will just execute the script. The Python reply variable will contain a Pythonic version of whatever is returned from the script. In the example it will be a Python dictionary:

{
    u'alist': [1, u'two', 3], 
    u'adict': {u'abool': True, u'afloat': 35.73}, 
    u'astring': u'fun!', 
    u'anum': 1
}

As you can see, the AppleScript record returned to the Python script has been converted to standard Python objects.

Calling handlers

If your AppleScript is complex or contains a lot of related logic, you can implement handlers (AppleScript functions) and then call those specific handlers. Let's say you have the following AppleScript:

on saySomething(speechString)
    say speechString
end saySomething

on getiTunesPlaylists()
    tell application "iTunes"
        set myPlaylists to name of every playlist
    end tell
    return myPlaylists
end getiTunesPlaylists

Note that it contains two handlers. One accepts a string and speaks it, the other doesn't have any parameters but calls out to iTunes to return a list of playlist names. Here's how you'd call those handlers from a Python script:

import applescript

# From a file
path_to_script_file = "/Users/jay/Projects/Python/AppleScriptTest/handlers.scpt"
my_ascript_from_file = applescript.AppleScript(path=path_to_script_file)

# You don't need to set the return value because the handler doesn't 
# return anything - it just speaks the string and returns.
my_ascript_from_file.call("saySomething", "Hello Python!")

# Call the method (it has no params) and assign the reply to the Python
# playlists
playlists = my_ascript_from_file.call("getiTunesPlaylists")

At the end of the above script snippit the playlists Python variable will contain a Python list of playlist names from iTunes.

As you can see, you can easily integrate data from Python, such as device state values, variable values, etc., into an AppleScript by passing that data to a handler. You can also just as easily pass back data from an AppleScript to Python and you'll get that data in native Python objects such as unicode strings, numbers, lists, dictionaries, etc. You can then use that data to insert into variables and/or device states (if running from a plugin for instance), etc.

AppleScript & the RESTful API

Another way to integrate Indigo from an AppleScript (or app that runs AppleScripts) is by using the curl command in a do shell script AppleScript call to the Indigo REST API.

For example, here's a simple AppleScript that will set the value of an Indigo variable:

set someValue to "hello"
set commandString to "curl -u username:password --digest -X PUT -d value=" & someValue & "http://127.0.0.1:8176/variables/someVariable"
do shell script commandString

Here's an example of getting a variable value:

set varValueJson to do shell script "curl -u username:password --digest http://127.0.0.1:8176/variables/someVariable.json"

tell application "JSON Helper"
	set varValueRecord to read JSON from varValueJson
	set varValue to value of varValueRecord
end tell

Note, to use this script you need the Mac App called JSON Helper, which is free from the Mac App Store. This free app does a fantastic job of converting JSON formatted data into AppleScript native data types (like lists and records).

This approach has the advantage of running from any Mac anywhere, whether on the same Mac as your server, another Mac on your local network, or a Mac somewhere out on the internet (use your reflector URL if you're doing the latter).

The downside to this approach is that you have to add the username and password of your Indigo Server to your script, and you must be running the Indigo Web Server. This may not be a big issue for you, but if you are running the script from a scriptable app that has no way to collect this information, it could be a hassle. This solution also requires that the Indigo Web server be running which may be an issue.

The Indigo Control AppleScript

In situations where you can't conveniently and/or securely get the username and password for your Indigo Server or where you can't run the Indigo Web Server, then you can use the Indigo Control AppleScript. This solution requires that the AppleScript be running on the Indigo Server Mac - but by doing so you can communicate with Indigo without a username/password.

There are a couple of ways to use the script. First, you can just copy/paste the script to where you want to use it then call the handlers you need to at the end of the script. There are examples at the bottom of the script of how to do that.

The other option is to save the script to your hard drive, then have any AppleScript that needs to use it load the script as an AppleScript script object:

set indigo to load script (POSIX file "/PATH/TO/YOUR/IndigoControl.scpt")
tell indigo
    toggle_byID("1894646715")
    updateVariable_byID("1991232156", "New variable value")
    executeActionGroup_byID("1493817435")
end tell

Help Converting AppleScript Scripts

We've created a special subforum on our forums where users can post AppleScripts that they need help converting - or even just verifying that the script will or won't work with Indigo 7.3+. We encourage you to use that resource.

developer/applescript_integration_strategies.txt · Last modified: 2018/08/29 16:27 by jay
 

© Perceptive Automation, LLC. · Privacy