Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
indigo_5_documentation:plugin_extending_tutorial [2013/08/09 18:18] – [Indigo Plugin SDK Source Code Examples] jayindigo_5_documentation:plugin_extending_tutorial [2025/02/18 20:36] (current) – external edit 127.0.0.1
Line 1: Line 1:
 +====== Indigo Server Plugin Tutorial ======
 +
 +Note most of the code examples below are calling methods on the object //''self''//. In this context, //''self''// is meant to be the Plugin instance as defined inside the //''plugin.py''// file. To execute the sample code outside Plugin instance methods use the //''indigo.activePlugin''// object instead.
 +
 +//Important:// For simplicity some of the samples below specify objects based on name (//''"office desk lamp"''//). However, the preferred lookup mechanism is to use the object's ID which can be retrieved by control-clicking on the object name in Indigo's Main Window. By using the ID you ensure the object will be found even if its name is changed.
 +
 +===== Indigo Plugin SDK Source Code Examples =====
 +
 +The Indigo Plugin SDK ([[http://www.indigodomo.com/Indigo5SDK|available here]]) includes example plugins with full XML and python source. They are a great place to start when developing new plugins.
 +
 +Included in the SDK are examples that create plugin based relay, dimmer, thermostat, and custom devices. Also included is an example showing basic Indigo database traversal, how to catch low-level X10/INSTEON messages, and how to create an Indigo telnet server using the python twisted framework.
 +
 +We'll be adding additional example plugins in the future.
 +
 +===== Other Useful Plugin Source Code Examples =====
 +
 +Additionally, below is a table of common plugin tasks and built-in plugins that implement those tasks in some form or another (from simplest to most complex):
 +
 +^  Plugin task  ^  Plugin that illustrates an approach  ^
 +| Parsing XML from an IP source  | NOAA Weather, WeatherSnoop |
 +| Integrating with native Mac Apps  | Airfoil   |
 +| Sending RS232 (serial port & network serial port) Commands   | EasyDAQ  |
 +| Reading RS232 (serial & network serial port) Input  | EasyDAQ  |
 +| Interacting with an IMAP mail server  | iCal Alarm Processor  |
 +| Creating custom devices with states  | Simple: NOAA Weather, WeatherSnoop - Complex: EasyDAQ, iTunes  |
 +| Creating custom actions  | Growl, Action Collection  |
 +| Creating custom events  | Airfoil  |
 +
 +Each of these plugins is installed by default with Indigo 5 - in the ''/Library/Application Support/Perceptive Automation/Indigo 5/Plugins (Disabled)/'' folder. To see the various XML and python source files, just right-click on it in the **''Finder''** and select ''**Show Package Contents**''.
 +
 +Both the SDK example plugins and the plugins included with Indigo above are great places to see working examples of plugins and their source code.
 +
 +===== How to Read and Write Plugin Preferences =====
 +
 +FIXME (useful, but very rough notes below)
 +
 +  * Per plugin prefs file is automatically managed (created, loaded, updated).
 +  * Pref values can be numbers, boolean, strings, indigo.Dict() or indigo.List().
 +  * Key values defined in PluginConfig.xml are automatically mapped into the plugin's prefs space which is available via:<code>
 +self.pluginPrefs["somePrefKey"]
 +</code> or, if you're not sure the key exists:<code>self.pluginPrefs.get("somePrefKey", "default value if key doesn't exist")</code> The latter will return the second parameter if they key doesn't exist in the dictionary - it's your responsibility to add it to the prefs dict if you want it to be stored permanently.
 +  * Plugin can also insert other values into its pluginPrefs space (not just values shown in the plugin's config UI).
 +  * To read a preference value access its key:<code>
 +someVal = self.pluginPrefs["somePrefKey"]
 +indigo.server.log("value is " + str(someVal))
 +</code>
 +  * To update a preference value assign it a new value:<code>
 +self.pluginPrefs["somePrefKey"] = 1234
 +</code>
 +
 +===== How to Add Plugin Metadata to Devices, Trigger & Scheduled Events, Variables, etc. =====
 +
 +FIXME (useful, but very rough notes below)
 +
 +  * Most Indigo database objects support the addition of plugin specific metadata.
 +  * Every plugin has its own name space accessed via the object instance //''.pluginProps''//.
 +  * The pluginProps dictionary supports numbers, boolean, strings, indigo.Dict() or indigo.List().
 +  * Example adding new plugin metadata to the Device "den fixture":<code>
 +dev = indigo.devices["den fixture"]
 +newProps = dev.pluginProps
 +newProps["onCycles"] = 5
 +newProps["moreData1"] = "abc"
 +newProps["moreData2"] = True
 +newProps["moreData3"] = 123.45
 +dev.replacePluginPropsOnServer(newProps)
 +</code>
 +  * Example reading the plugin specific property onCycles from the Device "den fixture":<code>
 +dev = indigo.devices["den fixture"]
 +onCycles = dev.pluginProps["onCycles"]
 +indigo.server.log("onCycles is " + str(onCycles))
 +</code>
 +  * Example incrementing by 1 the plugin specific property onCycles for the Device "den fixture":<code>
 +dev = indigo.devices["den fixture"]
 +newProps = dev.pluginProps
 +newProps["onCycles"] += 1
 +dev.replacePluginPropsOnServer(newProps)
 +
 +dev = indigo.devices["den fixture"]
 +onCycles = dev.pluginProps["onCycles"]
 +indigo.server.log("onCycles is now " + str(onCycles))
 +</code>
 +  * Plugins have read-only access to other plugin metadata via //''.globalProps''//.
 +  * Plugins have read/write access to their own metadata space.
 +
 +===== Creating a Custom Plugin Device =====
 +
 +FIXME (useful, but very rough notes below)
 +
 +  * Plugin Device state and properties are defined in Devices.xml.
 +  * Properties define the user configurable options for a device instance, and are specified in the //''<ConfigUI>''// XML node. Every field //''id''// is automatically mapped into the device instance //''.pluginProps''// metadata dictionary (described above) as a unique key.
 +  * States are specified in the Devices.xml //''<States>''// XML node, and are used to define the transient state information for a device (ex: on/off setting, brightness, temperature, etc.).
 +  * States defined in Devices.xml are automatically shows in the Trigger Event ''//Device State Changed//'' options when that plugin device type is selected, and are automatically shown in the Control Page editor when a control is created inspecting that plugin device.
 +  * States are read-only for everyone except the plugin that defines the device's states.
 +  * Plugins should update a device state after it has sent commands to hardware, or somehow received new state information from hardware. Example that increments the plugin defined state ''//heatSetPoint//'' by 1:<code>
 +dev = indigo.devices["Custom Plugin Thermostat"]
 +dev.updateStateOnServer("heatSetPoint", dev.states["heatSetPoint"] + 1)
 +</code>
 +  * Plugins should subclass ''//deviceStartComm//'' and ''//deviceEndComm//'' to start/stop any hardware communication (normally via a new per-device thread):<code>
 +def deviceStartComm(self, dev):
 + self.easydaq.startCommThread(dev)
 +
 +def deviceStopComm(self, dev):
 + self.easydaq.stopCommThread(dev)
 +</code>
 +  * Calls to ''//deviceStartComm//'' and ''//deviceEndComm//'' are automatically managed by the Indigo Server and Indigo Plugin Host. When a plugin first connects all enabled device instances owned by the plugin will receive ''//deviceStartComm//'' calls. Likewise, ''//deviceStartComm//'' is called when a new plugin device is created or duplicated. ''//deviceEndComm//'' is called whenever a plugin is disabled, deleted, or when the plugin is shutting down. Therefore, these two functions should be the primary bottlenecks for starting/stopping device hardware or network connections.
 +
 +===== Creating a Custom Plugin Trigger Event =====
 +
 +FIXME Explain Events.xml. Show example plugin subclasses of functions: triggerStartProcessing, triggerStopProcessing, didTriggerProcessingPropertyChange. Note it works very similarly to devices.
 +
 +===== Monitoring Device State Changes from a Plugin =====
 +
 +FIXME (useful, but very rough notes below)
 +
 +FIXME Give examples of using indigo.devices.subscribeToChanges() and plugin subclasses of functions: deviceCreated, deviceDeleted, deviceUpdated.
 +
 +===== Monitoring Changes to Variables, Triggered & Scheduled Events, Action Groups, and Control Pages =====
 +
 +FIXME (useful, but very rough notes below)
 +
 +FIXME Give examples of using indigo.*.subscribeToChanges() and plugin subclasses of functions: variableCreated, variableDeleted, variableUpdated, triggerCreated, triggerDeleted, triggerUpdated, scheduleCreated, scheduleDeleted, scheduleUpdated, actionGroupCreated, actionGroupDeleted, actionGroupUpdated, controlPageCreated, controlPageDeleted, controlPageUpdated.