Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
indigo_5_documentation:object_model_reference [2014/04/28 13:19]
mattb [Indigo specific data types]
indigo_5_documentation:object_model_reference [2022/04/30 22:24] (current)
mattb [Introduction]
Line 1: Line 1:
 +====== Indigo 5 Object Model Reference ======
 +===== About this Reference =====
  
 +This guide is meant to provide specific reference information about the Indigo Object Model (IOM) as used by scripters writing embedded scripts as well as developers writing Server plugins. Scripters can be Developers and vice versa - we just wanted to define the different potential uses for IOM.
 +
 +The IOM is divided up based on the major object types: [[device_class|Devices]],​ [[trigger_class|Triggers]],​ [[schedule_class|Schedules]] FIXME //(not yet implemented)//,​ [[action_group_class|Action Groups]] FIXME //(not yet implemented)//,​ [[variable_class|Variables]],​ and [[folder_class|Folders]]. There is also a utility base class (and subclasses),​ [[action_class|Action]] FIXME //(not yet complete)//,​ that's used with the major object types that support actions.
 +
 +For ease of discussion, any Python program that uses the object model will be referred to as a “script” throughout this document. From a style perspective,​ anything that’s in //''​code text''//​ is generally considered to be Python (or in the various example sections, AppleScript) code and represents the exact code needed. You'll also see code blocks like this:
 +
 +<​code>#​ some code here
 +# that does something</​code>​
 +
 +You should be able to tell from the context if it's Python code or, sometimes, AppleScript,​ if we're comparing how to do something.
 +
 +Some conventions of the Python API: all values are represented in camelCase, where words aren’t separated but each starts with an uppercase letter. The first character of all class names are uppercase (//''​DimmerDevice''//​) and the first character of class properties are lowercase letter (//''​folderId''//​). Constant enumerations start with a lowercase “k” (//''​kEnumerationName''//​),​ and each enumerated value begins with an uppercase letter (//''​kEnumerationName.EnumeratedValue''//​).
 +
 +**<color red>A note about version numbers</​color>​**:​ As we've revised the API and added features, we've incremented the API version number. Up until Indigo 5 v5.1.1, the API remained 1.0 and the documents were just updated with new features (which could lead to incompatible features if using an older release of Indigo). As of Indigo 5 v 5.1.2, we've begun incrementing the API minor version number (1.X) whenever we add new features. The major number (X.0) will only be incremented when we do something that will break backwards compatibility. See the [[API version chart]] to see which API versions were released in which Indigo version.
 +
 +If any of the API tables in the documentation don't have a version number you can assume that the feature is available in API version 1.0 and later.
 +
 +**<color red>​NOTE</​color>​**:​ Indigo uses Python v2.5. Python 2.6 is the default installation on Snow Leopard and 2.7 is the default installation on Lion (2.5 is default on Leopard), and there are differences,​ so make sure that you're using Python 2.5 for your development or you could get a nasty surprise when you turn your code into a plugin (if you're developing code outside of the plugin architecture). Both Lion and Snow Leopard do have 2.5 installed, it's just not the default install. It's in this directory:
 +
 +//''/​System/​Library/​Frameworks/​Python.framework/​Versions/​2.5/​bin/''//​
 +
 +If you execute "​python2.5"​ at the command line instead of "​python"​ you'll get the installed 2.5 version.
 +
 +Definitions of terms used throughout this manual are listed below:
 +
 +^Term^Meaning^
 +|Action Group |An action (or collection of actions) that can be used by multiple Schedules, Triggers, and Action Groups. This allows you to change the collection in a single place rather than editing multiple Schedules, Triggers, etc., that require identical actions to be executed.|
 +|Developer |A person who writes Server Plugins. |
 +|Direct Parameter ​ |The first parameter to a command, although it may be optional. Any further parameters to a command must have a name specified. ​ |
 +|Event ​ |Some external plugin defined event (outside Indigo) that is used to instruct the IndigoServer to execute a Trigger. ​ |
 +|Protocol ​ |Any built-in home automation technology that Indigo supports (INSTEON, X10, etc.). This does not include plugins that might implement their own protocol. ​ |
 +|Schedule ​ |An action (or collection of actions) that will be executed based on some temporal settings - dates and times. When the appropriate time and date is met, IndigoServer evaluates any conditions specified in the schedule in order to decide if the actions associated with the event should execute. In previous versions of Indigo, these were referred to as Time/Date Actions. ​ |
 +|Script |Any section of code using the IOM regardless of language being used. |
 +|Scripter |A person who writes embedded scripts. |
 +|Trigger ​ |An action (or collection of actions) that will executed based on some input event - a device state change, an event from a plugin, an email received, etc. When the  event occurs, IndigoServer evaluates any conditions specified in the trigger in order to decide if the actions associated with the event should execute. ​ |
 +
 +===== Indigo Object Model (IOM) Overview =====
 +==== Introduction ====
 +
 +The Indigo Object Model (IOM) is a collection of objects and methods that allow scripts to interact with objects in Indigo.
 +
 +From an architectural perspective,​ the most fundamental design point that needs to be understood is that the host process that executes python scripts is a separate process from the IndigoServer process - which where the objects actually reside. We do this so that a single script or plugin can't bring down the entire IndigoServer.
 +
 +So, when you get an object, it’s actually a copy of the object, not the real object. We could have implemented a distributed object model with object locking, etc., but that would have added significant complexity. Instead, we decided to create some simple rules that you need to follow in order to use the IOM correctly:
 +
 +For Scripters and Developers:
 +
 +  * To create, duplicate, delete, and send commands to an object (i.e. turnOn, nextZone, displayInRemoteUI,​ moveToFolder,​ etc.), use the appropriate command namespace and a reference to the object rather than altering the object directly (you can see the list of objects and their command name spaces in the table below)
 +  * To modify an object'​s definition (name, description,​ etc.), get a copy of it, make the necessary changes directly to the object, then call //''​myObject.replaceOnServer()''//​
 +  * To update a copy of an object that you previously obtained, call the object'​s //''​myObject.refreshFromServer()''//​ method.
 +
 +For Developers:
 +
 +  * To update a plugin'​s props on an object on the server, call //''​myDevice.replacePluginPropsOnServer(newPropsDict)''//​ rather than try to update them on the local device
 +  * To change a device'​s state on the server, use //''​myDevice.updateStateOnServer(key="​keyName",​ value="​Value"​)''//​
 +
 +A couple of notes to help you understand these rules. First, the IOM allows [[plugin_guide#​indigo_server_plugins|Server Plugins]] to attach arbitrary attributes to any object. We call these plugin properties, or just props. Currently, those properties are only available through Python (they aren't exposed in the UI and they aren't exposed in AppleScript). They are only read-write for Server Plugin, but are readonly for all Python scripts.
 +
 +Second, as discussed in the [[plugin_guide|Plugin Developer'​s Guide]], a [[plugin_guide#​indigo_server_plugins|Server Plugin]] may define multiple device types. All devices have some state (or states): on/off, paused/​playing/​stopped,​ heating/​cooling/​off,​ etc. These states are used in Triggers and shown on Control Pages. Your Server Plugin will need to be able to tell the server whenever a state changes for one of it's devices. That's what the last rule above is referring to. See the [[device_class|Devices]] description for more information and examples.
 +
 +We’ve divided the commands into name spaces such that if the command applies to a specific class type, it’s put into a namespace that matches the type. Here is a chart that maps the classes to their associated namespace:
 +
 +^Class^Command namespace^Notes ​ ^
 +^**[[device_class|Devices]]** ^^^
 +|//''​[[device_class#​device_base_class|Device]] (indigo.Device)''//​|[[device_class#​commands_indigodevice|indigo.device.*]]|for commands and properties that apply to all device subclasses|
 +|//''​[[device_class#​dimmerdevice|DimmerDevice]] (indigo.DimmerDevice)''//​|[[device_class#​commands_indigodimmer|indigo.dimmer.*]]|manipulate a dimmer|
 +|//''​[[device_class#​inputoutputdevice|InputOutputDevice]] (indigo.InputOutputDevice)''//​|[[device_class#​commands_indigoiodevice|indigo.iodevice.*]]|manipulate an I/O device|
 +|//''​[[device_class#​sensordevice|SensorDevice]] (indigo.SensorDevice)''//​|[[device_class#​commands_indigosensor|indigo.sensor.*]]|manipulate a sensor (motion, etc)|
 +|//''​[[device_class#​relaydevice|RelayDevice]] (indigo.RelayDevice)''//​|[[device_class&#​commands_indigorelay|indigo.relay.*]]|manipulate a relay device|
 +|//''​[[device_class&#​sprinklerdevice|SprinklerDevice]] (indigo.SprinklerDevice)''//​|[[device_class&#​commands_indigosprinkler|indigo.sprinkler.*]]|manipulate a sprinkler device|
 +|//''​[[device_class&#​thermostatdevice|ThermostatDevice]] (indigo.ThermostatDevice)''//​|[[device_class&#​commands_indigothermostat|indigo.thermostat.*]]|manipulate a thermostat|
 +^**Schedule** ^^^
 +|//''​Schedule (indigo.Schedule)''//​|indigo.schedule.*|manipulate a scheduled event FIXME not yet implemented|
 +^**[[trigger_class|Trigger]]** ^^^
 +|//''​[[trigger_class&#​trigger_base_class|Trigger]] (indigo.Trigger)''//​|[[trigger_class&#​commands_indigotrigger|indigo.trigger.*]]|commands and properties that apply to all trigger subclasses|
 +|//''​[[trigger_class&#​devicestatechangetrigger|DeviceStateChangeTrigger]] (indigo.DeviceStateChangeTrigger''//​|[[trigger_class&#​commands_indigodevstatechange|indigo.devStateChange.*]]|manipulate a device state change trigger|
 +|//''​[[trigger_class&#​emailreceivedtrigger|EmailReceivedTrigger]] (indigo.EmailReceivedTrigger)''//​|[[trigger_class&#​commands_indigoemailrcvd|indigo.emailRcvd.*]]|manipulate an email received trigger|
 +|//''​[[trigger_class&#​InsteonCommandReceivedTrigger]] (indigo.InsteonCommandReceivedTrigger)''//​|[[trigger_class&#​commands_indigoinsteoncmdrcvd|indigo.insteonCmdRcvd.*]]|manipulate an INSTEON command received trigger|
 +|//''​[[trigger_class&#​interfacefailuretrigger|InterfaceFailureTrigger]] (indigo.InterfaceFailureTrigger)''//​|[[trigger_class&#​commands_indigointerfacefail|indigo.interfaceFail.*]]|manipulate an interface failure trigger|
 +|//''​[[trigger_class&#​InterfaceInitializedTrigger|InterfaceInitializedTrigger]] (indigo.InterfaceInitializedTrigger)''//​|[[trigger_class&#​commands_indigointerfaceinit|indigo.interfaceInit.*]]|manipulate an interface initialized trigger|
 +|//''​[[trigger_class&#​PluginEventTrigger|PluginEventTrigger]] (indigo.PluginEventTrigger)''//​|[[trigger_class&#​commands_indigopluginevent|indigo.pluginEvent.*]]|manipulate an trigger defined by a plugin event|
 +|//''​[[trigger_class&#​PowerFailureTrigger|PowerFailureTrigger]] (indigo.PowerFailureTrigger)''//​|[[trigger_class&#​commands_indigopowerfailure|indigo.powerFail.*]]|manipulate a power failure trigger|
 +|//''​[[trigger_class&#​ServerStartupTrigger|ServerStartupTrigger]] (indigo.ServerStartupTrigger)''//​|[[trigger_class&#​commands_indigoserverstartup|indigo.serverStartup.*]]|manipulate a server startup trigger|
 +|''//​[[trigger_class&#​X10CommandReceivedTrigger|X10CommandReceivedTrigger]] (indigo.X10CommandReceivedTrigger)//''​ |[[trigger_class&#​commands_indigox10cmdrcvd|indigo.x10CmdRcvd.*]]|manipulate an X10 command received trigger|
 +|//''​[[trigger_class&#​VariableChangeETrigger|VariableChangeETrigger]] (indigo.VariableChangeETrigger)''//​|[[trigger_class&#​commands_indigovarchange|indigo.varValueChange.*]]|manipulate a variable changed trigger|
 +^**Action Groups** ^^^
 +|//''​ActionGroup (indigo.ActionGroup)''//​|indigo.actionGroup.*|manipulate an action group FIXME not yet implemented|
 +^**[[variable_class|Variables]]** ^^^
 +|//''​[[variable_class|Variable]] (indigo.Variable)''//​|[[variable_class#​commands_indigovariable|indigo.variable.*]]|manipulate a variable|
 +^**Protocol Specific Commands** ^^^
 +|[[INSTEON specific commands]]|indigo.insteon.*|commands specific to the INSTEON protocol FIXME not yet complete|
 +|[[X10 specific commands]]|indigo.x10.*|commands specific to the X10 protocol FIXME not yet complete|
 +^**General Commands** ^^^
 +|[[server_commands|General and commonly used commands]]|indigo.server.*|for commands that are more general in nature|
 +
 +The next question you probably have is “How do I create a new object in the IndigoServer?​”. The simple answer is that most class namespaces have a //''​create()''//​ method. They work a bit differently based on the class type (for instance, //''​indigo.device.create()''//​ is used as a factory method to create all types of devices), but it's always named the same. There are also //''​duplicate()''//​ and //''​delete()''//​ methods for each. See the individual class pages for details.
 +
 +This will keep the IOM simple and understandable and it avoids significant complexity. In this section we’ll describe the classes exposed to your script so that you can use them for whatever your script needs: checking the value of a variable, the state of a device, the definition of an event or action, etc.
 +
 +There are a few classes that are special. One is //''​Action''//​ and it’s subclasses (collectively referred to as "​actions"​). Why are these classes different? Because outside of the trigger, schedule, action group, or control page that they’re associated with they aren’t individually addressable in the IndigoServer:​ for instance, there is no way to identify an action without first identifying the trigger that it’s associated with.
 +
 +So, how do you interact with actions? Directly, as you would any other object. You can create one (which creates it locally), edit it, etc. Once you have the object set up correctly, you can add it to the appropriate local copy of an object then call the object'​s //''​replaceOnServer()''//​ method. If you have a local copy of an object and you want to ensure that it's in sync with what's on the server then call the object'​s //''​refreshFromServer()''//​ method. Don’t worry if this seems abstract: the examples section for each class page has examples of how to manipulate actions.
 +
 +Another very important concept that we’re introducing along with the IOM is the concept of an identifier, or //''​id''//​. Every top-level object in Indigo (action group, device, folder, schedule, trigger, variable) now has a globally unique integer ID associated with it. For those who never used AppleScript with the IndigoServer,​ the only way to reference an object in AppleScript is via the object’s name. This presents a problem: what if the name you stored in your script changes?
 +
 +All commands in the IOM accept the //''​id''//​ of an object or the object reference itself (along with the name). You should **never** store the object’s name. The //''​id''//​ is visible in the various lists throughout the UI. You can also select any object in the GUI and right click it to get it’s contextual menu where you'll find a new **''​Copy ID (123)''​** item that shows the ID and allows you to copy it to the clipboard. Server plugins that define config UIs that use the built-in lists will get the //''​id''//​(s) of the object(s) selected in the lists rather than the name.
 +
 +Now, if you're being very observant, you'll notice something missing: Control Pages. It is our intention to support Control Pages in the IOM, but unfortunately it just didn't make it into v1. Look for it in an upcoming IOM revision.
 +==== IOM vs AppleScript Dictionary ====
 +
 +If you are a user of the Indigo AppleScript Dictionary, you may have certain expectations set about how you would use the IOM in Python. While there are similarities,​ there are also some non-trivial differences. Most of these will become apparent in the following sections, but we’d like to outline a few here.
 +
 +First, and most obvious, is the nature of most objects in the IOM as we discussed earlier - using copies and updating the server when you change the properties. In AppleScript,​ when you alter an object’s property the change in instantaneous since the script is running in the IndigoServer process. That significant architectural difference is what led us to the split between objects and the commands that work on them.
 +
 +The next difference that you’ll notice is that there are many more classes in the IOM than there are in AppleScript. That’s because in AppleScript the classes are very flat: a device contains all possible properties for all devices. The same applies to the //''​action step''//​ (//''​Action''//​ in the IOM) class: in AppleScript it contains all possible properties for every action type. In the IOM, we broke these out into an object hierarchy in which a base class is defined that contains the common properties, then subclasses add the specifics for each type. Check out the figure in the next section for a graphical depiction of the object hierarchies in the IOM.
 +
 +One further note: AppleScript arrays are 1-based arrays. To get the first item in an array, you’d do something like this:
 +
 +//''​item 1 of myArray''//​
 +
 +In Python, they are 0-based (zero), so getting the first item would look like this:
 +
 +//''​myArray[0]''//​
 +
 +This will come as no surprise to anyone that’s used a C-based language. However, if you’re coming from AppleScript you’ll need to keep this in mind.
 +
 +==== IOM Class Hierarchy ====
 +
 +{{iom_object_hierarchy.png|}}
 +
 +===== IOM Data Types and Object manipulation =====
 +
 +==== Indigo specific data types ====
 +
 +Indigo exposes a couple of special classes in Python: //''​indigo.Dict()''//​ and //''​indigo.List()''//​. These are very similar to their Python counterparts (//''​dict''//​ and //''​list''//​). The big difference is that when you're dealing with dictionaries and lists that come from the IndigoServer and that go to the IndigoServer,​ you'll want to use these rather than the built-in Python types because they are handled natively by Indigo and can automatically be saved to the database and preference files.
 +
 +
 +The behavior of //''​indigo.Dict''//​ and //''​indigo.List''//​ is similar but not identical to the native python containers. Specifically,​ the Indigo containers:
 +  * must contain values that are of types: **bool**, **float**, **int**, **string**, **list** or **dict**. Any list/dict containers must recursively contain only compatible values.
 +  * do **not** support value access via slicing (we might add this eventually).
 +  * always retrieve values (ex: myprops["​key"​] or mylist[2]) as a copy and not reference of the object.
 +  * keys can only contain letters, numbers, and other ASCII characters.
 +  * keys cannot contain spaces.
 +  * keys cannot start with a number or punctuation character.
 +  * keys cannot start with the letters XML, xml, or Xml.
 +
 +The last point can lead to some unexpected behaviors when compared to python dicts and lists, especially when multiple levels of container nesting is being used. What this means is that you can set items and append to items, but the items returned from the get / iterators are always new copies of the values and not references. For example, consider:
 +
 +<​code>​c = indigo.List()
 +c.append(4)
 +c.append(5)
 +c.append(True)
 +c.append(False)
 +
 +a = indigo.Dict()
 +a['​a'​] = "the letter a"
 +a['​b'​] = False
 +a['​c'​] = c # a COPY of list C above is inserted (not a reference)
 +print(str(a))
 +
 +# Because a['​c'​] has a COPY of list C this will NOT append to instance a:
 +c.append(6)
 +print(str(a)) #​ no change from previous output!
 +
 +# And because a['​c'​] returns a COPY of its value this will also NOT append to instance a:
 +a['​c'​].append(6)
 +print(str(a)) #​ no change from previous output!</​code>​
 +
 +But all is not lost. You can just re-assign the nested object to the root container:
 +
 +<​code>#​ Instead you must re-assign a copy to the container. Since we already
 +# appended c with 6 above, we just need to reassign it now:
 +a['​c'​] = c
 +print(str(a)) #​ now has a COPY of the updated object, c</​code>​
 +
 +If you just need to override an existing value in a container (and not append to it), then a more efficient solution is to use our helper method //''​setitem_in_item''//​. It avoids creating temporary copies of values.
 +
 +<​code>​a.setitem_in_item('​c',​ 4, "the number six")
 +print(str(a))</​code>​
 +
 +Likewise, it is most efficient to use //''​getitem_in_item''//​ when accessing nested items since it avoids temporary copies of containers. For example, this creates a temporary copy of the c object before accessing index 4:
 +
 +<​code>​a['​c'​][4] #​ works, but is slow because a temporary copy of a['​c'​] is created</​code>​
 +
 +Where this returns the same result but is more efficient:
 +
 +<​code>​a.getitem_in_item('​c',​ 4) # same result, but fast</​code>​
 +==== Built-in objects ====
 +
 +The IOM supplies the following built-in objects:
 +
 +^  Object ​ ^  Description ​ ^
 +|indigo.devices|All devices in the database|
 +|indigo.triggers|A ll triggers in the database|
 +|indigo.schedules|All schedules in the database|
 +|indigo.actionGroups|All action groups in the database|
 +|indigo.variables|All variables in the database|
 +
 +These objects are very similar to an indigo.Dict - but have some special abilities and constraints:​
 +
 +  - They are read-only - you can't modify them directly but rather use other methods to change them
 +  - They contain a "​folders"​ property that has all the folders defined for that object type
 +  - They define a couple of convenience methods that are specialized for their use
 +
 +Let's elaborate on each of these a bit. First, they'​re read-only in that you can't do something like this:
 +
 +<​code>​indigo.devices[123] = someOtherDevice</​code>​
 +
 +To change a device, in most cases you get a copy of the device, make the necessary changes, then //''​replaceOnServer()''//​. You'll find specific information about each of those in the appropriate section linked below in the [[#Classes and Commands]] section.
 +
 +Each of the objects above corresponds to one of the high-level objects in Indigo. In the UI, you know that you can create folders for each of those object types. To access the folders available for each type, you can reference the "​folders"​ property: i.e. //''​indigo.devices.folders''//​. This is also a read-only //''​indigo.Dict''//​ of [[folder_class|folder]] objects. As with the other top-level classes, you manipulate folders within specific namespaces, described on the [[folder_class|folder class]] page.
 +
 +Finally, these objects define some convenience methods as well as supporting most of the standard Python [[http://​docs.python.org/​library/​stdtypes.html#​typesmapping|dict]] object methods.
 +
 +The first added method, //''​getName(elemId),''//​ is a shortcut to get the string name of the item. Normally you would need to get a copy of the object (which would pull the entire object from the IndigoServer) then get the name, but this method is more efficient since it only gets the name from the IndigoServer rather than the whole object. So, an easy way to get a variable folder'​s name (maybe for logging) would be to do this: //''​indigo.variables.folders.getname(1234)''//​. Make sure you use the correct object (//''​indigo.variables''//​) so that we'll know where to search for the folder.
 +
 +The other additional method is //''​subscribeToChanges()''//​. This method doesn'​t return anything - rather, it tells the IndigoServer that your plugin wants notification of all changes to the specific object type. Use this method sparingly as it causes a significant amount of traffic between IndigoServer and your plugin. What kind of plugins would use this? One good example is a logging plugin - one that's logging activity within Indigo (FIXME like our SQL Logger). Another example is a plugin that's doing some kind of scene management - you would probably want to issue a //''​indigo.devices.subscribeToChanges()''//​ at plugin start so that you'll always be notified when any device changes - you can then determine if your scene "​state"​ has changed and act accordingly. Note that subscribeToChanges() only reports actual changes to devices - so for instance when a light turns ON you'll get a notification. If the light is commanded to turn ON again, you won't get the notification because the device state didn't change. Use the lower-level subscribeToIncoming() and subscribeToOutgoing() methods to see commands regardless of their effect on device state.
 +
 +For each of the built-in objects, we've also provided some handy iterators that in some cases will allow you to filter. For instance, if you would like to iterate over the list of all devices in Indigo, here's what you would do in Python and AppleScript:​
 +
 +^  Python ​ ^  AppleScript ​ ^
 +|<​code>​for dev in indigo.devices:​
 +    # do stuff with dev here
 +
 +
 +</​code>​|<​code>​repeat with dev in every device
 + -- do stuff with dev here
 +end repeat
 +</​code>​|
 +
 +A note on iteration: when the above loop begins, the list of devices is fixed. So if mid-loop an element is added then it will NOT be iterated (unless the entire loop runs again later).
 +Likewise, if an element is deleted midway through, then the iterator gracefully handles it and just ignores that deleted item (it skips to the next item automatically).
 +So if items are added/​removed during an iteration it never throws an exception -- it handles it gracefully but you are not guaranteed to get the new ones.
 +
 +You can also iterate with just the ID of the object:
 +
 +<​code>​for devId in indigo.devices.iterkey():​
 +    # all device id's (rather than the whole device object)</​code>​
 +
 +For some of the built-in objects, you can filter the results:
 +
 +<​code>​for dev in indigo.devices.iter("​indigo.dimmer"​):​
 +    # all devices will be dimmer devices</​code>​
 +
 +You can further restrict some filters - for instance, you can specify the device type and the protocol:
 +
 +<​code>​for dev in indigo.devices.iter("​indigo.dimmer,​ indigo.insteon"​):​
 +    # all devices will be INSTEON dimmer devices</​code>​
 +
 +Or you can iterate just devices defined by custom plugin types:
 +
 +<​code>​for dev in indigo.devices.iter("​self"​):​
 +    # each dev will be one that matches one of our custom plugin devices</​code>​
 +
 +Here's a list of all device filters:
 +^  Filter ​ ^  Description ​ ^
 +|indigo.zwave|include Z-Wave devices|
 +|indigo.insteon|include INSTEON devices|
 +|indigo.x10|include X10 devices|
 +|com.mycompany.myplugin|include all devices defined by a plugin|
 +|indigo.responder|include devices whose state can be changed|
 +|indigo.controller|include devices that can send commands|
 +|indigo.relay|relay devices|
 +|indigo.dimmer|dimmer devices|
 +|indigo.sprinkler|sprinklers|
 +|indigo.thermostat|thermostats|
 +|indigo.iodevice|input/​output devices|
 +|indigo.sensor|sensor devices (motion, temperature,​ etc.)|
 +|self|include devices defined by the calling plugin|
 +|self.myDeviceType|include myDeviceType'​s devices defined by the calling plugin|
 +|com.company.plugin.xyzDeviceType|include xyzDeviceType'​s defined by another plugin|
 +
 +Triggers also have filters:
 +
 +^  Filter ​ ^  Description ​ ^
 +|indigo.insteonCmdRcvd|insteon command received triggers|
 +|indigo.x10CmdRcvd|x10 command received triggers|
 +|indigo.devStateChange|device state changed triggers|
 +|indigo.varValueChange|variable changed triggers|
 +|indigo.serverStartup|startup triggers|
 +|indigo.powerFail|power failure triggers|
 +|indigo.interfaceFail|interface failure triggers - can be used with or without a specified protocol|
 +|indigo.interfaceInit|interface connection triggers - can be used with or without a specified protocol|
 +|indigo.emailRcvd|email received triggers|
 +|indigo.pluginEvent|plugin defined triggers|
 +|self|include triggers defined by the calling plugin|
 +|self.myTriggerType|include myTriggerType'​s triggers defined by the calling plugin|
 +|com.company.plugin.xyzTriggerType|include all xyzTriggerType'​s defined by another plugin|
 +
 +So, to iterate over a list of device state change triggers, you would:
 +
 +<​code>​for trigger in indigo.triggers.iter("​indigo.devStateChange"​):​
 +    # each trigger will be a device state change trigger</​code>​
 +
 +Or to iterate over all triggers defined by our plugin types:
 +
 +<​code>​for trigger in indigo.triggers.iter("​self"​):​
 +    # each trigger will be one that matches one of our custom plugin triggers</​code>​
 +
 +Unlike devices, however, you may only use a single trigger filter - anything else will result in an empty list.
 +
 +There is a special filter for variables as well. To iterate over the variable list, you would probably guess this:
 +
 +<​code>​for var in indigo.variables:​
 +    # all variables</​code>​
 +
 +And you'd be correct. You can also just iterate through the writable variables:
 +
 +<​code>​for varName in indigo.variables.iter("​indigo.readWrite"​):​
 +    # you'll only get readwrite variables</​code>​
 +
 +==== Common Python Exceptions ====
 +
 +All IOM Commands can throw exceptions if there is a missing or incorrect parameter, or if there is a runtime problem that prevents the command or request from completing successfully. Common exceptions that may be raised include:
 +
 +^Possible Exceptions ​ ^^
 +|//''​ArgumentError''//​ |a required parameter is missing, or is not the correct type |
 +|//''​IndexError''//​ |an index parameter value is out-of-range |
 +|//''​KeyError''//​ |a key parameter (to a dictionary) was not found in the dictionary |
 +|//''​PluginNotFoundError''//​ |a plugin that you're trying to talk to (on a create() perhaps) isn't avaliable (disabled or gone) |
 +|//''​TypeError''//​ |a parameter had the incorrect runtime type |
 +|//''​ValueError''//​ |a parameter has a value that is illegal or not allowed |
 +
 +Other exceptions, such as //''​IOError''//,​ //''​MemoryError''//,​ //''​OverflowError''//,​ etc., are also possible although less likely to occur.
 +
 +FIXME Need more explanation and example of how to handle exceptions here?
 +
 +===== Classes and Commands =====
 +
 +Indigo provides many classes and commands to work on those classes. You can use standard Python introspection methods to find out information about those classes (these examples are done using the [[indigo_5_documentation:​plugin_scripting_tutorial|Scripting Shell]]):
 +
 +<​code>#​ first, let's get an indigo.DimmerDevice like a LampLinc
 +>>>​ dev = indigo.devices[238621905]
 +>>>​ dev.__class__
 +<class '​indigo.DimmerDevice'>​
 +>>>​ hasattr(dev,'​onState'​)
 +True
 +>>>​ dir(dev)
 +['​__class__',​ '​__delattr__',​ '​__dict__',​ '​__doc__',​ '​__getattribute__',​ '​__hash__',​ '​__init__',​ '​__module__',​ '​__new__',​ '​__reduce__',​ '​__reduce_ex__',​ '​__repr__',​ '​__setattr__',​ '​__str__',​ '​__weakref__',​ '​address',​ '​brightness',​ '​buttonGroupCount',​ '​description',​ '​deviceTypeId',​ '​enabled',​ '​folderId',​ '​globalProps',​ '​id',​ '​lastChanged',​ '​model',​ '​name',​ '​onState',​ '​pluginId',​ '​pluginProps',​ '​protocol',​ '​refreshFromServer',​ '​remoteDisplay',​ '​replaceOnServer',​ '​replacePluginPropsOnServer',​ '​states',​ '​supportsAllLightsOnOff',​ '​supportsAllOff',​ '​supportsStatusRequest',​ '​updateStateOnServer',​ '​version'​]
 +
 +# Next, an indigo.ThermostatDevice
 +>>>​ thermo = indigo.devices[171495708]
 +>>>​ thermo.__class__
 +<class '​indigo.ThermostatDevice'>​
 +>>>​ dir(thermo)
 +['​__class__',​ '​__delattr__',​ '​__dict__',​ '​__doc__',​ '​__getattribute__',​ '​__hash__',​ '​__init__',​ '​__module__',​ '​__new__',​ '​__reduce__',​ '​__reduce_ex__',​ '​__repr__',​ '​__setattr__',​ '​__str__',​ '​__weakref__',​ '​address',​ '​buttonGroupCount',​ '​coolIsOn',​ '​coolSetpoint',​ '​description',​ '​deviceTypeId',​ '​enabled',​ '​fanIsOn',​ '​fanMode',​ '​folderId',​ '​globalProps',​ '​heatIsOn',​ '​heatSetpoint',​ '​humidities',​ '​humiditySensorCount',​ '​hvacMode',​ '​id',​ '​lastChanged',​ '​model',​ '​name',​ '​pluginId',​ '​pluginProps',​ '​protocol',​ '​refreshFromServer',​ '​remoteDisplay',​ '​replaceOnServer',​ '​replacePluginPropsOnServer',​ '​states',​ '​supportsAllLightsOnOff',​ '​supportsAllOff',​ '​supportsStatusRequest',​ '​temperatureSensorCount',​ '​temperatures',​ '​updateStateOnServer',​ '​version'​]
 +
 +# Here's a plugin defined device
 +>>>​ tunes = indigo.devices["​Whole House iTunes"​]
 +# notice that it only shows the Device base class
 +>>>​ tunes.__class__
 +<class '​indigo.Device'>​
 +>>>​ dir(tunes)
 +['​__class__',​ '​__delattr__',​ '​__dict__',​ '​__doc__',​ '​__getattribute__',​ '​__hash__',​ '​__init__',​ '​__module__',​ '​__new__',​ '​__reduce__',​ '​__reduce_ex__',​ '​__repr__',​ '​__setattr__',​ '​__str__',​ '​__weakref__',​ '​address',​ '​buttonGroupCount',​ '​description',​ '​deviceTypeId',​ '​enabled',​ '​folderId',​ '​globalProps',​ '​id',​ '​lastChanged',​ '​model',​ '​name',​ '​pluginId',​ '​pluginProps',​ '​protocol',​ '​refreshFromServer',​ '​remoteDisplay',​ '​replaceOnServer',​ '​replacePluginPropsOnServer',​ '​states',​ '​supportsAllLightsOnOff',​ '​supportsAllOff',​ '​supportsStatusRequest',​ '​updateStateOnServer',​ '​version'​]
 +# You can use the deviceTypeId property to get the plugin'​s defined type
 +>>>​ tunes.deviceTypeId
 +u'​mediaserver'​
 +</​code>​
 +
 +So, from a discovery perspective,​ the //''​dir(obj)''//​ method will list all properties and methods for an object. The //''​hasattr(obj,​ attr)''//​ will test an object to see if it has a specific property. The //''​obj.%%__class__%%''//​ property will show you what class the object is. As you explore IOM objects, these methods will help you figure out how to use IOM objects effectively.
 +
 +Here are the major groupings of classes defined in the IOM (the command namespace for each is described with the classes):
 +
 +  * [[device_class|Device]] classes
 +  * [[trigger_class|Trigger]] classes
 +  * [[schedule_class|Schedule]] class FIXME not yet implemented
 +  * [[action_class|Action]] classes FIXME not yet complete
 +  * [[action_group_class|Action Group]] class FIXME not yet implemented
 +  * [[variable_class|Variable]] class
 +  * [[folder_class|Folder]] class
 +
 +Here are the command namespaces that are independent (to some extent) from the classes they effect:
 +
 +  * [[server_commands|Server Commands]]
 

© Perceptive Automation, LLC. · Privacy