Indigo 7 v7.0.0 Released

Official announcements on new releases or other important events.
User avatar
matt (support)
Site Admin
Posts: 21476
Joined: Mon Jan 27, 2003 1:17 pm
Location: Texas
Contact:

Indigo 7 v7.0.0 Released

Post by matt (support) »

Indigo 7

We're extremely pleased to announce the immediate availability of Indigo 7 v7.0.0. Indigo 7 has been under development for quite a long time and we're very happy to finally be able to release it to you. We hope that you'll be as excited as we are about it. We've spent a lot of time on the underpinnings of Indigo to make it even more reliable, robust, and extendable, which makes it the best DIY smart home solution on the market. Read on to find out the details. Note: Indigo 7 is a paid upgrade from previous versions.

Indigo 7 and Indigo Up-to-Date

As we've previously described, Indigo 7 will come with a new way to receive updates/upgrades. It's a subscription called Indigo Up-to-Date. Every purchase of Indigo 7 (full or upgrade) comes with a 1-year UTD subscription, so all updates in the first year are free. If you have an active Up-to-Date subscription, you'll be entitled to any and all releases. This includes major (7.0, 8.0, etc) and minor (7.1, 7.2) feature releases as well as any bug release (7.1.2, 7.1.3, etc). Don't panic: you never have to have an active Up-to-Date subscription to use Indigo. Every purchase of Indigo 7 (full or upgrade) comes with a 1-year UTD subscription, so all updates in the first year are free. Check out the details of how this program works and the reasons behind it.

Indigo 7 New Features

So, what exactly is new in Indigo 7? Glad you asked:
  • Z-Wave Devices, Features, Enhancements, and Fixes
    • Support for Z-Wave Network Wide Inclusion (NWI) for simpler inclusion (leave your Z-Wave Interface plugged into your Mac).
    • Support for Z-Wave Network Optimization (including background operation and optimization of battery powered modules).
    • Support for Z-Wave encryption communication. Note encryption security keys are negotiated during device network inclusion, so to enable you must exclude and then re-include the module using the New with Encryption Enabled button inside the define/sync dialog.
    • Support for Z-Wave locks (several, but not all, lock manufacturer and models have been tested).
    • Support for new Z-Wave devices:
      • Aeotec Doorbell (ZW056)
      • Aeotec Door/Window Sensor (ZW120 Gen 5)
      • Aeotec Door/Window Sensor 6 (ZW112)
      • Aeotec Dry Contact Sensor (ZW097 Gen5)
      • Aeotec Heavy Duty Switch (ZW078)
      • Aeotec Home Energy Monitor (ZW095)
      • Aeotec Multi Sensor 6 (ZW100)
      • Aeotec Siren (ZW080)
      • Aeotec Smart Dimmer 6 (ZW099)
      • Aeotec Smart Switch 6 (ZW096)
      • Aeotec RGBW LED Bulb (ZW098)
      • Aeotec RGBW LED Strip (ZW121)
      • Aeotec WallMote Quad (ZW130)
      • D-Link Door/Window Sensor (DCH-Z110)
      • D-Link Multi Sensor (DCH-Z120)
      • Danfoss Thermostat Room Sensor (Link RS)
      • Devolo Radiator Thermostat (09356)
      • Domitech Smart LED Light (ZE27)
      • Domitech Smart LED Light Bulb (ZB22)
      • Enerwave Appliance Module (ZWN333)
      • Enerwave Dimmer Switch (ZW500D)
      • Enerwave Motion Sensor (ZWN-BPC)
      • Enerwave Smart Dimmer Switch (ZW500DM)
      • Enerwave Smart Wall Outlet (ZW15RM/ZW20RM)
      • Everspring Appliance Module (AN180)
      • Fibaro Button (FGPB101)
      • Fibaro Dimmer 2 (FGD212)
      • Fibaro Door/Window Sensor (FGK10x)
      • Fibaro Double Switch 2 (FGS223)
      • Fibaro Single Switch 2 (FGS213)
      • Fibaro Smoke Sensor (FGSD002)
      • FortrezZ I/O Module (MIMO2+)
      • Heatit Thermostat (TF021)
      • HomeSeer Dimmer Switch (HS-WD100+)
      • HomeSeer Relay Switch (HS-WS100+)
      • Horstmann Radiator Thermostat (SRT323)
      • Kwikset SmartCode Lock (910)
      • Nodon Micro Smart Plug (MSP-31X1)
      • Nodon Octan Remote (CRC310X)
      • Nodon Smart Plug (ASP-31X0)
      • Nodon Soft Remote (CRC-360X)
      • Nodon Wall Switch (CWS-310X)
      • NorthQ Gas Meter (NQ-9121)
      • Philio PST02 Multi Sensors (PST02-A/B/C)
      • POPP Radiator Thermostat (TRV)
      • POPP Smoke Detector and Siren (004001)
      • POPP Solar Outdoor Siren (005107)
      • POPP Z-Weather Station.
      • Qubino Flush 1 Micro Relay (ZMNHAA and ZMNHAD)
      • Qubino Flush 1D Micro Relay (ZMNHND)
      • Qubino Flush 2 Micro Relay (ZMNHBA and ZMNHBD)
      • Qubino Flush Micro Dimmer (ZMNHDA and ZMNHDD)
      • Qubino Flush Shutter (ZMNHCA and ZMNHCD), Flush Shutter DC (ZMNHOD)
      • Qubino Weather Station (ZMNHZD)
      • Remotec Scene Master (ZRC-90)
      • Schlage locks (BE369/468/469 and FE599)
      • Sensative Door/Window Sensor (Strips)
      • Vision Door/Window Sensor (newer version) (ZD2102)
      • Vision Keypad Deadbolt locks (ZM1701/1702)
      • Vision Recessed Door/Window Sensor (ZD2105)
      • Vision Shock and Vibration Sensor (ZS5101)
      • Vision Siren/Strobe (ZM1602)
      • Vision Zooz Multi Sensor (ZSE40)
      • Water Cop (WV01)
      • Yale Keypad Deadbolt (YRD210/220/240)
      • Yale Keypad Lever (YRL210)
      • Yale Touchscreen Deadbolt
    • New Z-Wave Match Raw Packet Trigger type to allow triggers on any raw incoming Z-Wave commands.
    • New Z-Wave Send Mode UI option to the Send Raw Z-Wave Command (and action) for more flexibility when communicating with battery operated (sleeping) modules.
    • Improved performance and reliability of Z-Wave communication, especially during define/sync process.
    • Improved usability and simplified layout of all Z-Wave Device Settings dialogs.
    • Improved reliability of polling Z-Wave device after activity.
    • Updated Z-Wave.ME (ZME-WCD2) settings UI to correctly limit button mode parameter values from 1 to 5.
    • Updated Z-Wave Vision ZD2102 device definition to not have an independent External Switch device (resyncing the device is required)
  • INSTEON Enhancements
    • Batch syncing for i2CS modules (greatly simplifies PowerLinc replacements)
    • Basic support for new Insteon devices:
      • Alert Module (2867-222)
      • Siren Module (2868-222)
      • New Motion Sensor (2844-222)
    • New Toggle option to the INSTEON Turn On/Off KeypadLinc Buttons action.
  • Other New Features and Enhancements
    • New Airfoil Pro plugin (works with Airfoil 5+). It uses a new and more reliable API introduced in Airfoil 5. The old Airfoil plugin will no longer ship with Indigo, though it will be available for anyone who wants it on our Github repo. The Indigo 7 installer will, however, move the old one to the Indigo 7 install if you're upgrading from Indigo 6.
    • Virtual Device Sprinkler Group type that allows chaining multiple sprinkler modules into one logical device.
    • Native Lock support including controls and icons.
    • Color picker swatch to Set RGBW Levels actions, including checkbox to set the cool (versus warm) white levels.
    • Live updating of device color as color level edit fields or swatch are updated.
    • Support to inspect and change individual RGBW levels for color devices.
    • Option to Only store device states that change in the SQL Logger plugin.
    • Improved migration of the indigo_history.sqlite file (SQL Logger plugin) by automatically copying the file from older installs to the Indigo 7/Logs/ folder on first launch.
Indigo 7 Usability Improvements
  • Server status messages (above progress bar) to show real time feedback of server processing.
  • Improved efficiency and performance of plugins, Indigo Server, and Indigo Client.
  • Improved plugin UI updating to prevent flicker when buttons are pressed and menus selected.
  • Improved usability of plugin action UI by automatically opening action configuration dialog (if the action has not yet had its UI validated).
  • Increased number of Event Log lines that can be viewed in the log window.
  • Main window sorting by device states improved.
  • Main device dialog modified to allow resizing.
Developer API Enhancements

We've added so many changes for developers in Indigo 7 that we've separated the details out into separate posts following this one. Here's just a quick overview of what we've added that will allow developers to create even better plugins to extend Indigo.
  • Python 2.7 is now the version used by Indigo. We've also added/updated the following frequently used python libraries so you don't have to install them with your plugin: pyserial, enum, pyaes, requests.
  • Python debugger support - we've built-in the pdb and PuDB debuggers and enabled developers to debug using the fantastic Python IDE PyCharm Professional. Once you use a real debugger you'll never go back!
  • Plugin specific interactive shells allow you to have an interactive shell that has access to all of your plugin's methods, objects, etc.
  • Plugin specific logging - we've implemented the standard Python logging and provided each plugin with it's own dedicated log file where you can pretty much log anything in any format that works for you.
  • Broadcast (sometimes called Publish) and Subscribe - a simple way for a plugin to publish information that may be of use to other plugins.
  • Plugin action return values - an action in a plugin can now return values to the caller - either synchronously or asynchronously. You can also now hide actions from the UI. The combination of these two enable a developer to create a rudimantary API for their plugin.
  • Group management additions - you can now programmatically add and remove devices from a device group (historically created by the DeviceFactory).
  • Lock control APIs - control lock devices
  • RGB(W) device support - has been much more generalized so that plugin writers can add native controls to their RGB devices.
  • Z-Wave hooks and improvements - the Z-Wave API now has hooks that will allow you to control and capture Z-Wave devices and commands. While you can't add a Z-Wave device definition to the Z-Wave interface, you could add your own Z-Wave device if Indigo doesn't natively support it yet.
  • Config UI improvements to make your dialogs more interactive and smooth.
  • Multi-state updates in a single call to improve performance.
  • New device filters, reducing the need for custom callback filters.
See below for some great examples of how developers have already used some of the new APIs!

3rd Party Plugins for Indigo 7

We asked many of our loyal and prolific developers to help us beta test Indigo 7 and encouraged them to create new and updated plugins that take advantage of all the new developer features. And they've answered the call. Below are just a few of the new and enhanced plugins that will make your Indigo 7 experience even better.
  • Alexa-Hue Bridge (available soon)
    • Emulated Hue bridge now supported as an Indigo device (still with Alexa 27 device limit).
    • Multiple emulated Hue bridges supported thereby bypassing the overall 27 device limit.
    • Able to define multiple Alexa names to the same Indigo device by defining alternate names on different emulated Hue bridges.
  • Dynamic View Controller (available soon)
    • Enables Dynamic viewing of images on a Control Page.
    • Supports Foscam HD Controller folder structure traversal.
    • Supports generic folder traversal.
    • Page Forwards and Backwards by number, time, day.
  • FINGSCAN
    • Uses ~30% less CPU on the Indigo Server.
  • Foscam HD Controller (available soon)
    • Retrieve images from Foscam HD camera.
    • Enable / Disable Motion detection.
    • Set Motion detected timeout.
    • Enable / Disable Snap Image capture.
    • Enable / Disable camera ring tone alert.
  • Hue Lights plugin (version 1.4.0)
    • Added support for color picker in RGB and HSB color setting actions.
    • Added support for color and white temperature UI features in Indigo.
    • Added Toggle Debugging menu item in Hue Lights plugin menu.
    • Changed Hue Lights to now require Indigo 7 or later.
    • Changed LightStrip Plus handling so it appears with the original Hue LigthStrip model in Edit Device Settings dialog.
    • Updated Hue Group device name to show that it's no longer experimental.
  • INDIGOplotD
    • Added event data for things like door open / close. Event type lines will put a single dot at the point in time when the door was opened / closed.
  • LIFX
    • Support for the new Indigo7 RGBW native controls
  • Matplotlib Plugin (available soon) - easily create visually appealing charts for Indigo control pages.
    • Seamlessly manage attributes like color, fonts, line styles (and more!) for all charts at once.
    • Customize individual charts with markers, annotations, minimums and maximums, and user-defined constants.
    • Chart types Include: Line Charts, Bar Charts, Polar Charts, Multiline Text Charts, and WUnderground Plugin Charts.
    • Chart data that is created with the plugin, or incorporate your own (CSV).
    • Charts update automatically.
  • Mother Plugin
    • Uses ~50% less CPU on the Indigo Server. The old plugin will not start correctly on Indigo 7.
  • piBeacon
    • Added support for various OLED displays that can be attached directly to the RPI. they can be controlled by indigo actions or directly by the RPI: send sensor info directly to the display.
    • Added groups of iBeacons eg family guests .. a trigger can be set to all/one of the iBeacons in that group home or away.
    • Added support for ultrasound distance sensor.
    • Uses ~50% less CPU on the Indigo Server.
    • Charts update automatically.
    • Many smaller improvements.
  • Plex Media Server Plugin
    • Faster processing allows more frequent updates.
    • NEW! Control playback on Plex clients from Indigo.
    • NEW! Support for full media information when playing back music.
  • uniFi-WiFi-AP
    • Uses ~50% less CPU on the Indigo Server.
Indigo 7 is All Pro and Pricing

For Indigo 7, we’ve made some changes to Indigo pricing and versions. First, Indigo 7 is All Pro - we are no longer offering a Lite version (though we are offering upgrades from previous Lite versions). It’s clear that the strength of Indigo is it’s ability to integrate a variety of evolving smart home devices, which is a Pro-level feature. There are plenty of other point solutions for those with more modest needs, and we’ve determined that continued support of the Lite version just doesn’t make business sense.

Here’s the launch pricing for Indigo 7. All pricing is in USD.

Indigo 7 new license $249.95
Indigo 7 upgrade from Indigo 6 Pro $89.95
Indigo 7 upgrade from Indigo 6 Lite $169.95
Indigo 7 upgrade from Indigo 5 Pro $129.95
Indigo 7 upgrade from Indigo 5 Lite $189.95
Indigo 7 upgrade from Indigo 4 Pro $179.95
Indigo 7 upgrade from Indigo 4 Lite $219.95

Log in to your Indigo Account to purchase an upgrade.

Mac OS System Requirements and Indigo Touch Compatibility

Indigo 7 requires Mac OS X 10.7.5 (Lion) or better. Any Mac hardware that's officially supported by Mac OS X 10.7 is supported. This version is only compatible with Indigo Touch 1.7 or higher.

We think this is the most exciting Indigo release ever, and we are excited by how the entire Indigo community has made Indigo the most robust and powerful home automation platform available. Thanks again to our loyal customers and incredible plugin developers!

Matt & Jay

-------------------
Z-Wave® is a registered trademark of Sigma Designs, Inc. Indigo's support of Z-Wave hardware is neither endorsed nor certified by Sigma Designs.
Image
User avatar
jay (support)
Site Admin
Posts: 18416
Joined: Wed Mar 19, 2008 11:52 am
Location: Austin, Texas
Contact:

Changes for Developers - New APIs

Post by jay (support) »

With Indigo 7, we've bumped the API version number to 2.0, so if you use any new features remember to bump the ServerApiVersion version number in your Info.plist. We've added some great new APIs in Indigo 7, including features, optimizations, and plugin to plugin communication techniques. Here they are.

Deprecated Class, Enumeration, and Callback Names

The following indigo classes and action type enumerations have changed. The previous classes and enumerations still exists for backwards compatibility but should no longer be used.

     indigo.GeneralDeviceAction -> indigo.UniversalAction
     indigo.kDeviceGeneralAction -> indigo.kUniversalAction
     indigo.DimmerRelayAction -> indigo.DeviceAction
     indigo.kDimmerRelayAction -> indigo.kDeviceAction

And the following device action plugin callbacks have changed. The previous callbacks can still be used for backwards compatibility but should be changed.

     actionControlDimmerRelay -> actionControlDevice
     actionControlGeneral -> actionControlUniversal

Broadcast and subscribe interprocess communication

Did you ever want to have your plugins communicate with each other? Or wished for a lightweight way for another plugin to tell you something (or vice versa)? Well, your wait is over. Plugins can now broadcast out messages to other plugins and can subscribe to other broadcasts. This mechanism is significantly lighter weight than subscribing to device/variable changes, and more flexible because these messages can be anything (beyond just devices and variables).

The Indigo SDK download includes two examples plugins to illustrate broadcasting and subscribing: Example Custom Broadcaster and Example Custom Subscriber. However, it is pretty straightforward. To broadcast:

Code: Select all

indigo.server.broadcastToSubscribers(u"message_type_here", some_python_object)
You specify your message type (any unicode string) and the payload for the message. These can be simple python types (strings, numbers, lists, dictionaries). Complex objects may not work correctly (will have more details in the actual documentation).

To Subscribe:

Code: Select all

indigo.server.subscribeToBroadcast(pluginId, u"message_type_here", "message_handler")
You specify the plugin id of the plugin you want to subscribe to, the message type you want, and a method name (as a string) that will be called each time a broadcast is sent. The method signature is this:

Code: Select all

def message_handler(self, some_python_object)
That handler will be called any time a new message is broadcast. If you subscribe to broadcasts from a plugin not running then Indigo will automatically handle connecting the subscription when the plugin eventually starts up – you don't have to check to see if a plugin is running before subscribing.

Here's a real-world example that we're actually shipping: the guys over at Rogue Amoeba, makers of Airfoil, have a new network-based API (rather than the old AppleScript one) that is significantly more reliable and has more features, so we're using that in a new plugin for Indigo 7. One of the new features is the ability to get source track data if the source is iTunes (and, presumably, other media player type sources that they implement in the future). So if you have iTunes selected as the source, all the track data (including album art!) is made available to the new airfoil instance device type. Sure, it's a bit redundant with an iTunes device which shows the same thing, but it does include the album art among other things. What it doesn't show, however, is the actual play state of iTunes (playing, paused, etc). So the user would have to use two different sources to get the full picture of what's happening.

Fortunately, there was a very simple way to address this: allow the user to pick an iTunes device to provide the playstate. Now, we could have done this with the current device subscription model where we subscribed to all device changes, but that's a very heavy solution. Rather, we added one line of code to the iTunes plugin that broadcast out any time the play state changes. Then we subscribed to those changes in the Airfoil plugin and update as necessary.

We think that this mechanism is going to enable you guys to come up with some really cool new ideas that we haven't even thought of yet.

Plugin action return values

Another thing we've heard periodically and wanted ourselves is the ability for a plugin action to return a value such that it can be called from another plugin, script (or even the Indigo Server). We've added a new argument to plugin action callbacks to indicate that the caller is waiting for a reply:

Code: Select all

def actionSomeXmlDefineActionCallback(self, action, dev, callerWaitingForResult):
    # do your typical action stuff here
    return some_value
The action can block until it has the result of the action (which it can then just return directly), but note that all callbacks must be executed in the same plugin host thread. This means that other callbacks would become blocked, including those to get configuration UI XML and values. This turns into a potential usability problems in the Indigo client, as the plugin configuration, actions, trigger, etc., UI will become unresponsive and start to timeout.

Instead, if the plugin cannot immediately return a result for the action (because it has to communicate with hardware, for example), then it can can acquire a completion handler callback function that can be executed later (asynchronously) in another thread.

The pattern would then be something like:

Code: Select all

def actionSomeXmlDefineActionCallback(self, action, dev, callerWaitingForResult):
	completeHandler = None
	if callerWaitingForResult:	# only acquire the completion handler if caller is wanting a result
		completeHandler = indigo.acquireCallbackCompleteHandler()

	self.pluginsActionQueue.put((action, dev, completeHandler))
	# Note self.pluginsActionQueue is not implemented by the base plugin and is just an example
	# of how one might pass the action and completeHandler to another thread using a queue.

def anotherThreadQueueHandlerFunc(self)
	try:
		(action, dev, completeHandler) = self.pluginsActionQueue.get(True, 60)
		
		# Process the requested action here. This can block and take a long
		# time without impacting UI usability because this method would be
		# called from another thread.

		# Upon completion you can return the result to the original action caller
		# via:
		if completeHandler is not None:
			completeHandler.returnResult("success performing action")
	except Exception, exc:
		# If there was an exception performing the action (hardware not available, etc.)
		# then the exception can be returned to the original action caller via:
		if completeHandler is not None:
			completeHandler.returnException(exc)
So, rather than return a value from the actual callback, you request a callback completion handler from the server. You then can queue up data, including the handler object, so that some other async thread can perform whatever communication, calculation, etc., is needed and use the completion handler to return the result. As shown in the example above, you can also return an exception which will be thrown in the requesting process if necessary.

Group management additions

In Indigo 6, we introduce the DeviceFactory pattern which allows your plugin to have a factory like method that creates any number of devices as part of the config process. If your plugin creates multiple devices, those devices are automatically linked together into a device group. However, the only way to manage groups was through the DeviceFactory config UI. You couldn't add/remove devices from the group outside of that dialog. We've now added some arguments to allow you to manage these groups outside of the DeviceFactory UI.

The create() method on the indigo.Device class can now have another argument passed: groupWithDevice. The default value is None (so it won't be grouped with anything), but you may pass an ID of any other device that your plugin manages to have it added to that device's group (or one will be created if the target device isn't already in a group).

Also, we've added another argument to the delete() method on the indigo.Device class: autoDeleteSiblingDevices. The default value is True, but if you pass False then just the device itself will be deleted, but other devices in the device group will be left alone.

Support for lock/unlock (deadbolts, entry keypads, etc.) devices

Indigo 7 includes native support for relay devices that specify a lock sub-type, including UI for locking and unlocking in the Main Window and actions panel via the Device Actions->Lock-> action types. Plugins can define their own lock devices as well, taking advantage of the included UI and actions.

A locking device can be controlled with the new methods on the indigo.device command namespace:

Code: Select all

indigo.device.lock(device, delay, duration)
indigo.device.unlock(device, delay, duration)
where the arguments delay and duration are optional (like indigo.device.turnOn and indigo.device.turnOff).

If a plugin wants to create an instance of the indigo.RelayDevice class that is a lock then it would set the property IsLockSubType to True, either in Devices.xml or via the device replacePluginPropsOnServer() method. Indigo will then show the lock/unlock icons for the device and use locked and unlocked as the state labels (versus on/off). An example definition for Devices.xml would be:

Code: Select all

	...
	<Device type="relay" id="myLockType">
		<Name>My Lock Module</Name>
		<ConfigUI>
			<Field type="checkbox" id="IsLockSubType" hidden="true" defaultValue="true" />
		</ConfigUI>
	</Device>
	...
The plugin.py's actionControlDevice callback will then be called with action.deviceAction set to indigo.kDeviceAction.Unlock or indigo.kDeviceAction.Lock whenever a lock action (or API) has been called. For a detailed example of how to define a plugin lock device (including commented plugin.py action callback code) see the Example Device - Relay and Dimmer plugin in the Indigo SDK download.

Because there are native Lock and Unlock action types built into Indigo (along with corresponding action UI), a plugin that supports locking hardware does not need to add custom lock or unlock actions (to their Actions.xml file). Adding custom actions is acceptable, of course, if a plugin needs control not provided by Indigo's default actions.

Better support for RGB and white color devices

Indigo 7 includes native support for RGBW devices, including UI for setting color levels in the Main Window and actions panel via the Device Actions->Light/Appliance Controls->Set RGB Levels action type. Plugins can define their own dimmable color devices as well, taking advantage of the included UI and actions for settings color levels.

First, we've added some new properties and methods to the indigo.DimmerDevice class to better support RGB and white color devices. To dimmer device instances we've added these new properties:
  • supportsColor – true if the device supports setting either color (RGB) values or white level values
  • supportsRGB – true if the device supports setting individual RGB values
  • supportsWhite – true if the device supports setting white level(s)
  • supportsTwoWhiteLevels – true if the device supports setting both a cool and a warm white levels
  • supportsTwoWhiteLevelsSimultaneously – true if the device supports having both white levels on at the same time
  • supportsWhiteTemperature – true if the device supports setting a white temperature value (Kelvin)
  • supportsRGBandWhiteSimultaneously – true if the device supports having both the color (RGB) and white levels on at the same time
  • redLevel – the red level (0-100)
  • greenLevel – the green level (0-100)
  • blueLevel – the blue level (0-100)
  • whiteLevel – the white level (0-100)
  • whiteLevel2 – the white level (0-100)
  • whiteTemperature – the white temperature in Kelvin (1200-15000)
And a new method on the indigo.dimmer command class:

Code: Select all

indigo.dimmer.setColorLevels(device,
               redLevel,
               greenLevel,
               blueLevel,
               whiteLevel,
               whiteLevel2,
               whiteTemperature,
               delay, # defaults to 0
               suppressLogging, # defaults to False
               updateStatesOnly #defaults to False
)
The levels are the same as brightness, so 0 to 100, except for whiteTemperature which ranges from 1200-15000. Real number precision is allowed and the actions UI will display precision up to the hundredths digit, allowing for relatively good precision if a plugin needs to convert between RGB and HSB.

Some RGBW devices (Aeotec bulb) support 2 different white channels with unique white temperatures: warm and cool. In those cases both whiteLevel and whiteLevel2 can be used. Other white color devices allow for a specific temperature value to be specified (in Kelvin). For those devices you would use both the whiteLevel parameter in combination with the whiteTemperature parameter. Note for specifying white color temperature devices should support either the 2 white level technique, or the single white level + white temperature technique. That is, if the whiteLevel2 parameter is used then whiteTemperature will be ignored.

updateStatesOnly is a new argument that exists on several device instance APIs that has Indigo update its device state/UI but does not have the corresponding action sent out to physical module. The use cases for this are pretty few, but sometimes you just want the internal state to update and can skip the actual command to the module.

Plugins that are adding support for color or white temperature hardware should define their devices (in Devices.xml) to be of type dimmer and set the following pluginProps (ConfigUI) based on the hardware's capability:
  • SupportsColor – true if the device supports setting either color (RGB) values or white level values
  • SupportsRGB – true if the device supports setting individual RGB values (requires SupportsColor to be True)
  • SupportsWhite – true if the device supports setting white level(s) (requires SupportsColor to be True)
  • SupportsTwoWhiteLevels – true if the device supports setting both a cool and a warm white levels (requires SupportsWhite to be True)
  • SupportsTwoWhiteLevelsSimultaneously – true if the device supports having both white levels on at the same time (requires SupportsTwoWhiteLevels to be True)
  • SupportsWhiteTemperature – true if the device supports setting a white temperature value (Kelvin) (requires SupportsWhite to be True)
  • SupportsRGBandWhiteSimultaneously – true if the device supports having both the color (RGB) and white levels on at the same time (requires SupportsRGB and SupportsWhite to be True)
An example definition for Devices.xml would be:

Code: Select all

	...
	<Device type="dimmer" id="myColorType">
		<Name>My Color Module</Name>
		<ConfigUI>
			<Field type="checkbox" id="SupportsColor" hidden="true" defaultValue="true" />
			<Field type="checkbox" id="SupportsRGB" hidden="true" defaultValue="true" />
			<Field type="checkbox" id="SupportsWhite" hidden="true" defaultValue="true" />
			<Field type="checkbox" id="SupportsWhiteTemperature" hidden="true" defaultValue="true" />
		</ConfigUI>
	</Device>
	...
The plugin.py's actionControlDevice callback will then be called with action.deviceAction set to indigo.kDeviceAction.SetColorLevels whenever a color action (or API) has been called. For a detailed example of how to define a plugin color device (including commented plugin.py action callback code) see the Example Device - Relay and Dimmer plugin in the Indigo SDK download.

Because there is a native Set RGBW Levels action type built into Indigo (along with corresponding action UI), a plugin that supports color hardware does not need to add a custom set color action (to their Actions.xml file). Adding custom actions is acceptable, of course, if a plugin needs control not provided by Indigo's default Set RGBW Levels action or if it is providing some alternative color selection technqiue.

If a plugin does need to present custom UI that has a color swatch (compatible with the system color picker) then it can use the new control field type, colorpicker. Here is an example XML field definition for the colorpicker control type:

Code: Select all

	...
		<ConfigUI>
			<Field id="rgbColor" type="colorpicker" defaultValue="=">
				<Label>Color:</Label>
				<CallbackMethod>rgbColorPickerUpdated</CallbackMethod>
			</Field>
		</ConfigUI>
		...
And the plugin.py callback, rgbColorPickerUpdated, would look like this:

Code: Select all

	def rgbColorPickerUpdated(self, valuesDict, typeId, devId):
		rgbHexList = valuesDict["rgbColor"].split()
		redLevel = 100 * int(rgbHexList[0], 16) / 255
		greenLevel = 100 * int(rgbHexList[1], 16) / 255
		blueLevel = 100 * int(rgbHexList[2], 16) / 255

		# Could send the new color values to the hardware here, or just
		# update internal red, green, blue level properties for use later
		# by the plugin:
		valuesDict["redLevel"] = redLevel
		valuesDict["greenLevel"] = greenLevel
		valuesDict["blueLevel"] = blueLevel

		return (valuesDict)
Z-Wave hooks and improvements

Not only have we added a bunch of new Z-Wave devices, we've also beefed up the Z-Wave API. Several new methods are available in the indigo.zwave class:

Code: Select all

# Returns True if the interface is enabled, False otherwise
indigo.zwave.isEnabled() 

# Send a Z-Wave command to set RGBW values
indigo.zwave.sendSetRGBW(device,    # device arg is optional - if not specified you must specify a nodeId
               nodeId,              # optional - if not specified you must specify a device
               endpoint,            # optional - if a nodeId is specified and supports multiple endpoints
               redLevel,
               greenLevel,
               blueLevel,
               whiteLevel,
               setCoolWhiteChannel, # defaults to False
               delay,               # defaults to 0
               suppressLogging,     # defaults to False
               updateStatesOnly     # defaults to False
)

# Modify a Z-Wave config param
indigo.zwave.sendConfigParm(device, # device arg is optional - if not specified you must specify a nodeId
               nodeId,              # optional - if not specified you must specify a device
               endpoint,            # optional - if a nodeId is specified and supports multiple endpoints
               paramIndex,
               paramSize,
               paramValue,
               waitUntilAck         # defaults to True if not specified
)

# Send a Z-Wave command
indigo.zwave.sendRaw(device,        # device arg is optional - if not specified you must specify a nodeId
               nodeId,              # optional - if not specified you must specify a device
               endpoint,            # optional - if a nodeId is specified and supports multiple endpoints
               cmdBytes,
               sendMode,            # 0: immediate, 1: immediate first, if no ACK wait for wake, 2: wait for wake
               waitUntilAck         # defaults to True if not specified
)

# Start a Z-Wave network optimization
indigo.zwave.startNetworkOptimize(nodeId)
# (nodeId arguument is optional - if not specified then the entire network will be optimized)

# Stop a previously started Z-Wave network optimization
indigo.zwave.stopNetworkOptimize()

# Have controller enter inclusion or exclusion modes:
indigo.zwave.enterInclusionMode(useEncryption)
indigo.zwave.enterExclusionMode()

# Have controller exit either inclusion or exclusion mode:
indigo.zwave.exitInclusionExclusionMode()

# Subscribe to incoming raw Z-Wave command bytes
indigo.zwave.subscribeToIncoming()

#Subscribe to outgoing raw Z-Wave command bytes
indigo.zwave.subscribeToOutgoing()
The final two methods will cause the following methods to be called if your plugin defines them:

Code: Select all

	########################################
	def zwaveCommandReceived(self, cmd):
		byteList = cmd['bytes']         # List of the raw bytes just received.
		byteListStr = convertListToHexStr(byteList)  # this method is defined in the example SDK plugin
		nodeId = cmd['nodeId']          # Can be None!
		endpoint = cmd['endpoint']      # Often will be None!

		if nodeId and endpoint:
			self.debugLog(u"received: %s (node %03d, endpoint %s)" % (byteListStr, nodeId, endpoint))
		elif nodeId:
			self.debugLog(u"received: %s (node %03d)" % (byteListStr, nodeId))
		else:
			self.debugLog(u"received: %s" % (byteListStr))

	def zwaveCommandSent(self, cmd):
		byteList = cmd['bytes']         # List of the raw bytes just sent.
		byteListStr = convertListToHexStr(byteList)    # this method is defined in the example SDK plugin
		timeDelta = cmd['timeDelta']    # The time duration it took to receive an Z-Wave ACK for the command.
		cmdSuccess = cmd['cmdSuccess']  # True if an ACK was received (or no ACK expected), false if NAK.
		nodeId = cmd['nodeId']          # Can be None!
		endpoint = cmd['endpoint']      # Often will be None!

		if cmdSuccess:
			if nodeId:
				self.debugLog(u"sent: %s (node %03d ACK after %d milliseconds)" % (byteListStr, nodeId, timeDelta))
			else:
				self.debugLog(u"sent: %s (ACK after %d milliseconds)" % (byteListStr, timeDelta))
		else:
			self.debugLog(u"sent: %s (failed)" % (byteListStr))
The new subscription method and the ability to send any raw Z-Wave command should open up a lot more possibilities for developers. You could, in fact, add support for some unsupported Z-Wave device. Of course, the device wouldn't be a standard Indigo Z-Wave interface device (we're not quite there yet), but rather it would be a device defined by your plugin (so you'd need to manage all aspects of the device). This is not the end-goal of allowing others to add native Z-Wave device models, but it does get us a bit closer by providing a lower-level solution for adding some device support.

Configuration UI additions and improvements
  • Added support for valuesDict['refreshCallbackMethod'] attribute which allows plugins to specify a UI refreshing callback method that is called approximately every second for updates. The callback method has the same signature as UI button actions and can return both a modified valuesDict and errorsDict for dynamic UI updating.
  • Added XML support for optional <CallbackMethod> element to ConfigUI textfield field types so that whenever the user typing is completed in an edit field (tab or cursor focus changes) the specified callback method will be called.
  • Added XML <Field> node attribute type alwaysUseInDialogHeightCalc which can be set to true to have the initial dialog's height expanded to include the height of the control even if it is initially invisible.
  • Enhanced plugin valuesDict handling so that plugin methods that return a valuesDict can modify key/value pairs in an instance's pluginProps attribute even if there are no UI <Field> nodes defined for those pairs inside the Devices.xml, Events.xml, etc.
Update multiple states in one call

dev.updateStatesOnServer(keyValueList, triggerEvents, clearErrorState)

One of the things that we noticed pretty much immediately after releasing the API with Indigo 5 was that often times we needed to update multiple states at the same time. Of course, there was no API to do multiple updates in a single statement. We've finally addressed that with this new device method. So, for instance, multiple updates once would have looked like this:

Code: Select all

		dev.updateStateOnServer("someKey1", True)
		dev.updateStateOnServer("someKey2", 456)
		dev.updateStateOnServer("someKey3", 789.123, uiValue="789.12 lbs", decimalPlaces=2)
Can now look like this:

Code: Select all

		# New code equivalent that is much more efficient:
		keyValueList = [
			{'key':'someKey1', 'value':True},
			{'key':'someKey2', 'value':456},
			{'key':'someKey3', 'value':789.123, 'uiValue':"789.12 lbs", 'decimalPlaces':2}
		]
		dev.updateStatesOnServer(keyValueList)
This not only can improve performance of plugins, the Indigo Server and the Indigo Client, but we've also updated the SQL Logger plugin to understand the new state updates which can result in several less SQL rows being inserted (and thus smaller databases).

The clearErrorState parameter works as it does for the singular update call. We've added a new parameter, triggerEvents, which will allow you to update states without causing any device state update triggers to fire. You likely won't want to use that option very much as it can cause end-user confusion when Device State Changed triggers stop firing, but if you ever have the need it's now there (it's also available on the single state update as well).

Device Filtering Improvements

The filter argument used during device enumeration, len(), and from "filter=" menu and list fields (in .xml files), can now accept multiple filter identifiers. For example, to calculate the total number of all relays and dimmers you can now use:

Code: Select all

indigo.devices.len(filter="indigo.relay, indigo.dimmer")
Or for the number of all x10 and insteon modules:

Code: Select all

indigo.devices.len(filter="indigo.insteon, indigo.x10")
You can also now test the existence and boolean value of device pluginProps defined by your plugin. For example, to get all dimmers that support color:

Code: Select all

for elem in indigo.devices.iter("indigo.dimmer, props.SupportsColor"):
	print(elem.name + " (" + str(elem.id) + ")")
Or to count all dimmers that support either RGB or white temperature:

Code: Select all

indigo.devices.len(filter="indigo.dimmer, props.SupportsColor, props.SupportsWhiteTemperature")
Note that logically the search is performed by AND'ing the categories (protocol, class, and props) and OR'ing the items within a category. For example, using a filter string of:

Code: Select all

indigo.insteon, indigo.x10, indigo.relay, indigo.dimmer, props.SupportsColor, props.SupportsWhiteTemperature
logically performs a search using:

Code: Select all

(insteon OR x10) AND (relay OR dimmer) AND (props["SupportsColor"] OR props["SupportsWhiteTemperature"])
Using filters is strongly encouraged when needing to count, enumerate, or search for devices. The filtering occurs as the Indigo Server level and can significantly improve performance by reducing the amount of data (device instances) that have to be serialized and sent to the plugin for processing.

Updated and New Python modules

We've updated and added some Python modules that many of you use (and some that we need) so that they're available to all plugins and scripts:
  • pyserial updated to v3.1.1 (was v2.7). This fixes some outstanding bugs that were in the older 2.x version.
  • enum - enumerations as officially implemented in Python 3.4 but available for Python 2.x
  • pyaes - AES encryption library
  • requests - library to make HTTP requests really REALLY easy
Miscellaneous new APIs and changes
  • self variable added to interactive shell that points to instance indigo.activePlugin
  • indigo.server.savePluginPrefs() - force the Indigo Server to save the plugin prefs file immediately. File is automatically saved on plugin shutdown, so only call this method if you want an immediate save because critical data has been recently stored.
  • dev.supportsOnState and dev.supportsSensorValue properties added to indigo.sensor device instances.
  • dev.supportsHvacFanMode, dev.supportsHvacOperationMode, dev.supportsCoolSetpoint, dev.supportsHeatSetpoint properties added to indigo.thermostat device instances.
Jay (Indigo Support)
Twitter | Facebook | LinkedIn
User avatar
jay (support)
Site Admin
Posts: 18416
Joined: Wed Mar 19, 2008 11:52 am
Location: Austin, Texas
Contact:

Changes for developers - Debugging and Logging

Post by jay (support) »

Python Debugger Support

We've added the ability to use a variety of Python debuggers: pdb, PuDB, and PyCharm (professional version). Each has its pros and cons, but all are a significant improvement over self.debugLog()...

In the Plugins Preferences tab, there is a new Development section:
ss88.png
ss88.png (175.85 KiB) Viewed 27357 times
(bet you didn't even remember that tab was there). Because we need to start plugins in a special way for debugging to work, we need to show some special debugging menus. Check the checkbox to see those menus in each plugin's submenu. Next, each debugger needs to be started in a specific way, so select the debugger that you want to use.

By enabling debugging menus, each plugin will have some additional menu items on their submenu:
  • Enable/Reload in Debugger
  • Enable/Reload in Interactive Shell (discussed next)
Selecting the first will enable or restart the plugin with the plumbing enabled for the debugger you selected. We'll talk about the specifics for each next.

pdb

pdb is a command line debugger that's built-in to Python. We'll let you read the docs to find commands and features. What you do need to know is when you select Enable/Reload in Debugger, Indigo will restart your plugin and open a terminal window running pdb:
ss89.png
ss89.png (230.83 KiB) Viewed 27357 times
To add breakpoints to your code, you just add indigo.debugger() method calls where ever you want plugin execution to pause in the debugger. Trying to interactively add breakpoints from pdb or PuDB is hit-or-miss because of the threaded way in which Indigo plugins run. The most reliable to way to force a breakpoint is by manually adding the indigo.debugger() call to the python source and restarting the plugin. Also note indigo.debugger() calls are ignored (NOPs) when the plugin is not launched in debugger mode, so don't lose sleep over leaving an indigo.debugger() call in a shipping plugin.

PuDB

PuDB is a more graphical debugger, much like to the old Borland Turbo debugger from many years ago:
ss90.png
ss90.png (446.59 KiB) Viewed 27357 times
As with pdb, you add breakpoints to your code by adding indigo.debugger() method calls where ever you want plugin execution to pause in the debugger.

PyCharm

Finally, we were able to use PyCharm's remote debugging feature to enable plugin debugging. It requires a bit more setup, but if want to use a fantastic modern IDE, this is the choice for you. Note that because we're using the remote debugging feature, you can only use the professional version of PyCharm as the community edition doesn't support it.

With your plugin's project open in PyCharm, create a run configuration of type Remote Python Debug:
ss91.png
ss91.png (165.5 KiB) Viewed 27357 times
There are three important config parameters in this dialog (you can name the configuration anything you want). The first two tell how to connect: specify localhost in the Local host name box and 5678 in the Port field. The next field you need to adjust is the Path mappings field.

Recall that the recommended way of developing Indigo plugins is to put your plugin in a central location (not inside the Indigo folders), then make a symbolic link to it in the Plugins directory. We do this because the Indigo server moves a plugin between two different folders when enabling/disabling. An IDE/editor will get confused when this happens, so by putting the actual code in a place that never moves and allowing the Indigo Server to move a symbolic link around, you get around this issue.

Because of this, you need to tell PyCharm where the actual path to the source is when the plugin is enabled and being debugged. Click the ellipsis button at the end of the Path mappings field to add a mapping. On the Local path side, you want to specify the actual path to your plugin's source (i.e. /Users/you/path/to/myplugin.indigoPlugin). On the Remote path side, you want to specify the path to your plugin's symlink when the plugin is enabled (i.e. /Library/Application Support/Perceptive Automation/Indigo 7/Plugins/myplugin.indigoPlugin). Tip: to get the path to a file in the Finder, right click on the file to show the contextual menu, then press the Option key. The Copy item will change to Copy as Pathname which is exactly what you want.

One other option is the Suspend after connect checkbox: if you have that checked, then when your plugin restarts with the debugger, it will pause execution in the __init__ method. We don't recommend doing this since you can add breakpoints anywhere you want in the code, including in the __init__ method.

That's it for setup! To debug, just run the remote debug configuration and then restart your plugin in the debugger. Unlike when using pdb and PuDB, you don't need to add explicit breakpoints to the source code using indigo.debugger() – rather, just interactively add breakpoints in PyCharm:
ss92.png
ss92.png (279.33 KiB) Viewed 27357 times
You can step through code, inspect, etc., just like you are debugging any other Python project.

We hope that you'll find a great debugging solution for your needs in one of these options. We've added a couple of new API methods on the plugin objects that are part of this change:
  • plugin.isRunning() – will return true if the plugin is enabled, initialized, and running
  • plugin.restartAndDebug() – a parallel to the restart() method except that it starts the plugin running in the selected debugger
Plugin Specific Interactive Shell

Another great debugging tool is the ability to open a scripting shell that's specific to your plugin's context. This shell is like the more general shell you get when you select the Plugins->Open Scripting Shell menu item, except that because we launch it as part of your plugins startup, it has access to everything in your plugin. You can call methods that your plugin implements, inspect your plugin's objects, etc.

Plugin Specific Logging

Something that we started working on in more recent Indigo 6 releases is switching our logging over to the standard Python logging module (unfortunately, we introduced a few bumps that you guys had to deal with - sorry about that!) But, you guys are gonna love this! Your plugin will now inherit some new logging functionality including a plugin specific log file.

We highly recommend you read through the Python logging module basic tutorial to get a basic understanding of how logging works. We've done some work for you, in terms of setting up the logging, so once you're in your plugin's __init__() method, your logger and handlers are already to go.

Your plugin will inherit a property, self.logger, which is a standard Python logger object. You can use the standard logger module methods (self.logger.debug(), self.logger.info(), etc) to write logging information. The logger is named "Plugin" (which we'll discuss more later), and has its debug level set to logging.THREADDEBUG (which is level 5, also discussed later). This means that the logger will pass all messages level 5 or higher to all of it's handlers.

The logger has two handlers associated with it: self.indigo_log_handler, which emits log data to the Indigo Event Log. This handler basically mimics the indigo.server.log() method (and the self.debugLog(), self.errorLog() methods defined in the plugin base - those are now just wrappers around the standard logging debug() and error() methods). The default level of this handler is logging.INFO - meaning only informational, warning, errors, and critical errors will get written to the Indigo Log. You can, of course, change the log level of this handler to logging.DEBUG (or any level you want). In fact, we've made some under the hood changes so that if you use the defacto self.debug property to control whether debug information is written to the Indigo Log, it will now actually change the log level for self.indigo_log_handler for you, so you really don't have to change anything about how you log there.

The other handler, self.plugin_file_handler, emits log data to a log file that's specific to your plugin (located in /Library/Application Support/Perceptive Automation/Indigo 7/Logs/your.plugin.id/plugin.log). This is a standard logging.handlers.TimedRotatingFileHandler which rotates at midnight. It keeps 5 days worth of log files and appends the date to the end of the file name when it rolls over to a new day. The default level of this handler is logging.THREADDEBUG (level 5), so pretty much everything that's logged will get logged there. The formatter for the handler is defined like this:

Code: Select all

pfmt = logging.Formatter('%(asctime)s.%(msecs)03d\t%(levelname)s\t%(name)s.%(funcName)s:\t%(message)s', datefmt='%Y-%m-%d %H:%M:%S')
so log lines will look something like this:

Code: Select all

2016-06-06 10:44:49.227	THREADDEBUG	Plugin.ssr.Receiver.run:	collecting and splitting data
2016-06-06 10:44:49.231	THREADDEBUG	Plugin.ssr.Receiver.run:	found 1 messages
2016-06-06 10:44:49.231	THREADDEBUG	Plugin.ssr.Receiver.run:	messages found in stream: 1
2016-06-06 10:44:50.177	DEBUG	Plugin._processMessage:	_processMessage got a reply to message: 19
2016-06-06 10:44:50.177	DEBUG	Plugin._processMessage:	iTunesSubscribeDict new entries: {860050058: [288403608]}
2016-06-06 10:44:50.186	DEBUG	Plugin._processMessage:	expectedReplies dict: {288403608: {}}
The theory here being that you can write really detailed information into your log file without it cluttering up the Indigo Event Log. When a user is having an issue, you can instruct them to send you log files which you can then examine and more quickly find issues.

In the example above, you may notice a couple of interesting things: first, THREADDEBUG is listed as the level. We've added our own level to the existing python logging module levels. It's called logging.THREADDEBUG and it's level 5 (lower than DEBUG). When developing threaded applications, we've found that having a lower level specifier for debugging inside the threads made it easier for us to use the logging effectively. We also added a corresponding self.logger.threaddebug() convenience method call to make it easy to log at this level. Feel free to ignore it if you like and just use the standard levels or your own levels.

The next thing you may notice is there seem to be not only logged method calls that are defined in your plugin subclass, but there appear to be some kind of name spaced log entries (i.e. Plugin.ssr.Receiver.run). As you may know from reading the logging docs, you can create a logging object that's a child of a parent logger. If your plugin defines some other modules, those modules can get a new logger that's a child of the "Plugin" logger that we create for you (for instance logging.getLogger("Plugin.somemodule.submodule")). All log messages from this logger will get propagated up to the parent "Plugin" logger (as the namespace implies, it's a child) and the parent will send them to all it's handlers. The benefit is that log file entries will now have much more explicit information about where the log entry came from. It also gives you a place to do other logging if you like: you can add another type of handler to your logger (maybe a network emitter or a separate file).

You are welcome, of course, to change the log format, level, etc., so that it works better for you if you like. You can add more handlers, remove handlers, alter them as you see fit. Python logging is fairly complex, but it's also extremely flexible so you should always be able to find the right configuration for your needs. We've added a new method that will return the path to the Logs directory so you can construct the path to your plugin-specific directory:

Code: Select all

indigo.server.getLogsFolderPath()
You can pass it an optional pluginId argument to get the path to that specific plugin's log directory:

Code: Select all

indigo.server.getLogsFolderPath(pluginId='some.plugin.id.here')
Jay (Indigo Support)
Twitter | Facebook | LinkedIn
Post Reply

Return to “Announcements”