Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
| indigo_7_documentation:plugins:airfoilpro [2016/06/30 16:27] – jay | indigo_7_documentation:plugins:airfoilpro [2025/04/14 20:10] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Airfoil Pro ====== | ||
| + | |||
| + | [[http:// | ||
| + | |||
| + | The latest major release, [[http:// | ||
| + | |||
| + | Note: this plugin requires v1.5 or later of the Airfoil API. This was delivered in Airfoil 5 for Mac and Windows. If you need support for earlier versions of Airfoil for Mac, please see [[https:// | ||
| + | ===== Airfoil Device Types ===== | ||
| + | |||
| + | Each Airfoil instance that can be found on your local network can be added as a device in Indigo. When you add an Airfoil device, each speaker that's available in that instance of Airfoil will also be represented by its own device. This gives you a much more flexible set of devices that can be used in triggers, actions, and control pages. | ||
| + | |||
| + | ==== Airfoil Instance ==== | ||
| + | |||
| + | This device type represents a single instance of Airfoil running on a Mac or Windows computer. Every Airfoil instance knows about the source that's currently selected, and in some cases (such as iTunes) knows about what's currently playing (album name, album art, artist, source name/ | ||
| + | |||
| + | === Adding an Instance === | ||
| + | |||
| + | To create an Airfoil Instance device, click the **'' | ||
| + | |||
| + | {{: | ||
| + | |||
| + | In the first popup, select the Airfoil instance that you want to add. This popup is dynamically generated based on Airfoil' | ||
| + | |||
| + | The plugin can store a variety of images from Airfoil. You can use these images in refreshing image URLs on your control pages. The second field in the dialog is a full path to a directory where the plugin will store the image files. If you have multiple Airfoil instances, make sure you use a different directory since the image files have a fixed name. The plugin will store the following images in this directory: | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | Leave the field empty if you don't wish for the plugin to store these images. | ||
| + | |||
| + | One oversight that there is in the Airfoil API is the ability to know the play state of the source. So the plugin can't know whether iTunes is playing or paused. If you are using the iTunes Indigo plugin, you have this information, | ||
| + | |||
| + | When you click the " | ||
| + | |||
| + | This is what the Edit Device dialog will look like when it's finished: | ||
| + | |||
| + | {{: | ||
| + | |||
| + | Airfoil instances are actually a group of devices: the instance itself (the first tab), and then multiple speaker devices, one for each speaker device that your instance knows about. We set the name of the Airfoil Instance to the Airfoil name. For each speaker, we name the speaker with this pattern: " | ||
| + | |||
| + | Airfoil Instance devices have the following state changes that you can use in Triggers: | ||
| + | |||
| + | {{: | ||
| + | |||
| + | Those states can also be displayed in Control Pages. | ||
| + | |||
| + | === States available to Scripts === | ||
| + | |||
| + | If you want to use an Airfoil Instance device in a script, here are the state details: | ||
| + | |||
| + | | **State Key** | **Value Type** | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | |||
| + | === Notes === | ||
| + | |||
| + | If you change the name of your Mac, you'll need to perform the **'' | ||
| + | ==== Speaker ==== | ||
| + | |||
| + | Each Airfoil Instance device has a collection of " | ||
| + | |||
| + | We never automatically delete speakers: if you have a bluetooth speaker that fails and you won't ever use it again, you'll need to remove it manually. | ||
| + | |||
| + | <color red> | ||
| + | |||
| + | An unfortunate side effect of how Airfoil handles AirPlay devices, like AppleTVs, is that if you change the name of them it will create a new speaker instance (rather than just replacing it). From the API perspective, | ||
| + | |||
| + | === States available to Scripts === | ||
| + | |||
| + | If you want to use an Airfoil Instance device in a script, here are the state details: | ||
| + | |||
| + | | **State Key** | **Value Type** | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | | //'' | ||
| + | |||
| + | ===== Airfoil Actions ===== | ||
| + | |||
| + | The Airfoil plugin provides a variety of actions that allow you to fully manage an Airfoil Instance and Speakers. We'll separate these into Speaker actions and Instance actions. These actions are available on the **'' | ||
| + | |||
| + | {{: | ||
| + | |||
| + | For those interested in controlling Airfoil Pro devices from another plugin or script, you will find the details below after a description of each action in the **Scripting details** section. You don't need to know or understand those sections if you're not interested in writing scripts. | ||
| + | |||
| + | === Notes for Script/ | ||
| + | |||
| + | If you examine the example scripts below, you'll note that each action call will return a result (which is new in Indigo 7). Unless otherwise specified, it's just a boolean indicating if the action correctly ran. | ||
| + | |||
| + | You may also note that the action calls are inside a try block. If you specify // | ||
| + | |||
| + | Finally, at the very end of the list are Script Actions - these are actions that don't really appear in the UI, but will return something useful for your script/ | ||
| + | |||
| + | ==== Speaker Actions ==== | ||
| + | |||
| + | The things you want to do with speaker actions are pretty simple: control whether a speaker is being used and setting the volume of the speaker. To that end, here are the actions. | ||
| + | |||
| + | === Connect Speaker === | ||
| + | |||
| + | This action will cause Airfoil to begin broadcasting audio to the specified speaker. | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: connect | ||
| + | |||
| + | The deviceId is the Indigo ID of the Speaker device. | ||
| + | |||
| + | No properties for scripting required. | ||
| + | |||
| + | Example: | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(" | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Disconnect Speaker === | ||
| + | |||
| + | This action will cause Airfoil to stop broadcasting audio to the specified speaker. | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: disconnect | ||
| + | |||
| + | The deviceId is the Indigo ID of the Speaker device. | ||
| + | |||
| + | No properties for scripting required. | ||
| + | |||
| + | Example: | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(" | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | === Toggle Speaker === | ||
| + | |||
| + | This action will cause Airfoil to toggle the specified speaker between connected and disconnected. Useful to execute from a single element (i.e. button) from a control page. | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | The deviceId is the Indigo ID of the Speaker device. | ||
| + | |||
| + | **Action id**: toggle | ||
| + | |||
| + | No properties for scripting required. | ||
| + | |||
| + | Example: | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(" | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | === Save Current Speaker States === | ||
| + | |||
| + | This action will save the connection state for each speaker on the selected Airfoil device. This is useful if you need to temporarily change the state of some speakers but you want to be able to easily set them back to how they were before the change. You can optionally specify that Airfoil Group states also be saved though this option is usually not very useful since storing the current state of all speakers will usually accomplish the same as restoring a group. | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: saveCurrentSpeakerStates | ||
| + | |||
| + | The deviceId is the Indigo ID of the Airfoil device. | ||
| + | |||
| + | | //'' | ||
| + | |||
| + | Example 1 (no groups): | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(" | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | Example 2 (include groups): | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | # This time, we'll add the includeAirfoilGroups property that will also store group states | ||
| + | result = airfoilPlugin.executeAction(" | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | === Restore Saved Speaker States === | ||
| + | |||
| + | This action will restore speaker states to what was previously saved using the above action. | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: saveCurrentSpeakerStates | ||
| + | |||
| + | The deviceId is the Indigo ID of the Airfoil device. | ||
| + | |||
| + | Example 1 (no groups): | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(" | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | === Set Volume === | ||
| + | |||
| + | This action will cause Airfoil to set the volume of specified speaker. | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: setVolume | ||
| + | |||
| + | The deviceId is the Indigo ID of the Speaker device. | ||
| + | |||
| + | | //'' | ||
| + | |||
| + | Example: | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(' | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | === Increase Volume === | ||
| + | |||
| + | This action will cause Airfoil to increase the volume of specified speaker by the specified amount (defaults to 5). | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: increaseVolume | ||
| + | |||
| + | The deviceId is the Indigo ID of the Speaker device. | ||
| + | |||
| + | | //'' | ||
| + | |||
| + | Example 1 (using default delta): | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(' | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | Example 2 (specifying delta): | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(' | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | <color blue> | ||
| + | |||
| + | === Decrease Volume === | ||
| + | |||
| + | This action will cause Airfoil to decrease the volume of specified speaker by the specified amount (defaults to 5). | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: decreaseVolume | ||
| + | |||
| + | The deviceId is the Indigo ID of the Speaker device. | ||
| + | |||
| + | | //'' | ||
| + | |||
| + | Example 1 (using default delta): | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(' | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | Example 2 (specifying delta): | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(' | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | <color blue> | ||
| + | |||
| + | ==== Airfoil Instance Actions ==== | ||
| + | |||
| + | Actions that you can perform on Airfoil Instance devices relate to the current source. | ||
| + | |||
| + | === Disconnect All Speakers === | ||
| + | |||
| + | Tell Airfoil to disconnect all speakers. This is useful if you want to connect just the speakers in an Airfoil Group (disconnect everything first then connect the group). | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: disconnectAllSpeakers | ||
| + | |||
| + | No properties for scripting required. The deviceId is the Indigo ID of the Airfoil device. | ||
| + | |||
| + | Example: | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(' | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | === Change Source === | ||
| + | |||
| + | This action allows you to change the audio source of the Airfoil instance (as if you changed it by selecting a new source from the popup in the Airfoil app). | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: changeSource | ||
| + | |||
| + | The deviceId is the Indigo ID of the Airfoil device. | ||
| + | |||
| + | | //'' | ||
| + | | //'' | ||
| + | |||
| + | Example: | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | props = {" | ||
| + | result = airfoilPlugin.executeAction(" | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | === Save Current Source === | ||
| + | |||
| + | This action will save the currently selected source for the specified Airfoil device. This is useful if you need to temporarily change the source (for instance, to perform some kind of announcement), | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: saveCurrentSource | ||
| + | |||
| + | The deviceId is the Indigo ID of the Airfoil device. | ||
| + | |||
| + | Example: | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(" | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | === Restore Saved Source === | ||
| + | |||
| + | This action will restore the previously saved source for the specified Airfoil device. This is useful if you need to temporarily change the source (for instance, to perform some kind of announcement), | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: restoreSavedSource | ||
| + | |||
| + | The deviceId is the Indigo ID of the Airfoil device. | ||
| + | |||
| + | Example: | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(" | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | === Toggle Play/Pause === | ||
| + | |||
| + | Tell Airfoil to tell the source to toggle play/pause. This only works with some sources and there // | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: playPause | ||
| + | |||
| + | No properties for scripting required. The deviceId is the Indigo ID of the Airfoil device. | ||
| + | |||
| + | Example: | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(' | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | === Next Track === | ||
| + | |||
| + | Tell Airfoil to tell the source to go to the next track. This only works with some sources. | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: nextTrack | ||
| + | |||
| + | No properties for scripting required. The deviceId is the Indigo ID of the Airfoil device. | ||
| + | |||
| + | Example: | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(' | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | === Previous Track === | ||
| + | |||
| + | Tell Airfoil to tell the source to go to the next track. This only works with some sources. | ||
| + | |||
| + | == Scripting details == | ||
| + | |||
| + | **Action id**: prevTrack | ||
| + | |||
| + | No properties for scripting required. The deviceId is the Indigo ID of the Airfoil device. | ||
| + | |||
| + | Example: | ||
| + | |||
| + | < | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(' | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | ==== Airfoil Scripting Actions ==== | ||
| + | |||
| + | The following action is available specifically for scripts. | ||
| + | |||
| + | === getSources == | ||
| + | |||
| + | This script action will return an indigo.Dict object. The keys are the source groups, the values are lists of dicts with the following keys: friendlyName (the user friendly name), icon (a binhex' | ||
| + | |||
| + | **Action id**: getSources | ||
| + | |||
| + | No properties are required. The deviceId is the Indigo ID of the Airfoil device. | ||
| + | |||
| + | < | ||
| + | airfoilPlugin = indigo.server.getPlugin(" | ||
| + | if airfoilPlugin.isEnabled(): | ||
| + | try: | ||
| + | result = airfoilPlugin.executeAction(' | ||
| + | except Exception, e: | ||
| + | print " | ||
| + | </ | ||
| + | |||
| + | The //result// that's returned from this call will look something like this: | ||
| + | |||
| + | < | ||
| + | Data : (dict) | ||
| + | | ||
| + | Item : (dict) | ||
| + | | ||
| + | icon : [SNIP] | ||
| + | | ||
| + | Item : (dict) | ||
| + | | ||
| + | icon : [SNIP] | ||
| + | | ||
| + | Item : (dict) | ||
| + | | ||
| + | icon : [SNIP] | ||
| + | | ||
| + | | ||
| + | Item : (dict) | ||
| + | | ||
| + | icon : [SNIP] | ||
| + | | ||
| + | Item : (dict) | ||
| + | | ||
| + | icon : [SNIP] | ||
| + | | ||
| + | systemAudio : (list) | ||
| + | Item : (dict) | ||
| + | | ||
| + | icon : [SNIP] | ||
| + | | ||
| + | </ | ||
| + | |||
| + | That's an indigo.Dict() object. Each group is the key, and the value for each group is a list of " | ||