AppleScript Integration Strategies

As published in the The future of AppleScript and Indigo blog post, Indigo 7.4 (and beyond), released September 2019, 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 are only targeting other applications those will continue to work correctly. If you have an embedded script that doesn't target IndigoServer, then just convert it to an external script (save it as a file in Apple's Script Editor application) and it should work fine.

Consider Easier Alternatives to Scripts

Many times, AppleScript was used to solve a specific need for your automation due to missing features in Indigo. Over the years, however, Indigo has advanced to accomplish much more. We highly recommend walking through the documentation for the latest version to see if you can switch to using newer built-in features.

Also, Indigo now has a very comprehensive 3rd party Plugin Store that has a lot of free plugins developed by our very active 3rd party developers to enhance Indigo in a variety of ways. It's very likely that there is a plugin that may help to implement your solution without the need for any scripting at all!

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.

Also new to Indigo 7.4 is that embedded script conditionals (in Triggers and Schedules) are now Python and not AppleScript, so you can write a Python condition script to replace your AppleScript conditions. Use the forum above to get help converting those as well.

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.

The Indigo Control AppleScript

In situations where you cannot conveniently and/or securely get the username and password for your Indigo Server or where you cannot 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 sub-forum 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.4+. We encourage everyone to visit that forum if they need help.

developer/applescript_integration_strategies.txt · Last modified: 2022/09/05 18:43 by jay
 

© Perceptive Automation, LLC. · Privacy