diff --git a/Example Custom Broadcaster.indigoPlugin/Contents/Info.plist b/Example Custom Broadcaster.indigoPlugin/Contents/Info.plist
index 238f64c..c2cbfcd 100644
--- a/Example Custom Broadcaster.indigoPlugin/Contents/Info.plist
+++ b/Example Custom Broadcaster.indigoPlugin/Contents/Info.plist
@@ -2,24 +2,24 @@
- PluginVersion
- 2022.1.0
- ServerApiVersion
- 3.0
- IwsApiVersion
- 1.0.0
- CFBundleDisplayName
- Example Custom Broadcaster
- CFBundleIdentifier
- com.perceptiveautomation.indigoplugin.custom-broadcaster
- CFBundleVersion
- 1.0.0
- CFBundleURLTypes
-
-
- CFBundleURLName
- https://wiki.indigodomo.com/doku.php?id=plugins:example_custom_broadcaster_1
-
-
+ PluginVersion
+ 2022.1.0
+ ServerApiVersion
+ 3.0
+ IwsApiVersion
+ 1.0.0
+ CFBundleDisplayName
+ Example Custom Broadcaster
+ CFBundleIdentifier
+ com.perceptiveautomation.indigoplugin.custom-broadcaster
+ CFBundleVersion
+ 1.0.0
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ https://wiki.indigodomo.com/doku.php?id=plugins:example_custom_broadcaster_1
+
+
diff --git a/Example Custom Broadcaster.indigoPlugin/Contents/Server Plugin/MenuItems.xml b/Example Custom Broadcaster.indigoPlugin/Contents/Server Plugin/MenuItems.xml
index 0ac49ec..aecccaf 100644
--- a/Example Custom Broadcaster.indigoPlugin/Contents/Server Plugin/MenuItems.xml
+++ b/Example Custom Broadcaster.indigoPlugin/Contents/Server Plugin/MenuItems.xml
@@ -1,15 +1,15 @@
-
+
diff --git a/Example Custom Broadcaster.indigoPlugin/Contents/Server Plugin/plugin.py b/Example Custom Broadcaster.indigoPlugin/Contents/Server Plugin/plugin.py
index d2b8b71..2f6602f 100644
--- a/Example Custom Broadcaster.indigoPlugin/Contents/Server Plugin/plugin.py
+++ b/Example Custom Broadcaster.indigoPlugin/Contents/Server Plugin/plugin.py
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
####################
# Copyright (c) 2022, Perceptive Automation, LLC. All rights reserved.
-# http://www.indigodomo.com
+# https://www.indigodomo.com
import indigo
@@ -13,38 +13,38 @@
################################################################################
class Plugin(indigo.PluginBase):
- ########################################
- def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs):
- super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs)
- self.debug = True
+ ########################################
+ def __init__(self, plugin_id, plugin_display_name, plugin_version, plugin_prefs):
+ super().__init__(plugin_id, plugin_display_name, plugin_version, plugin_prefs)
+ self.debug = True
- ########################################
- def startup(self):
- self.logger.debug("startup called -- broadcasting startup to all subscribers")
- # Broadcast to all listeners that we have started using the "broadcasterStarted"
- # broadcast key. Note the key is arbitrary and will just be used by the
- # subscribers in their subscribeToBroadcast() call.
- indigo.server.broadcastToSubscribers("broadcasterStarted")
+ ########################################
+ def startup(self):
+ self.logger.debug("startup called -- broadcasting startup to all subscribers")
+ # Broadcast to all listeners that we have started using the "broadcasterStarted"
+ # broadcast key. Note the key is arbitrary and will just be used by the
+ # subscribers in their subscribeToBroadcast() call.
+ indigo.server.broadcastToSubscribers("broadcasterStarted")
- def shutdown(self):
- self.logger.debug("shutdown called -- broadcasting shutdown to all subscribers")
- # Broadcast to all listeners that we have shutdown using the "broadcasterShutdown"
- # broadcast key.
- indigo.server.broadcastToSubscribers(u"broadcasterShutdown")
+ def shutdown(self):
+ self.logger.debug("shutdown called -- broadcasting shutdown to all subscribers")
+ # Broadcast to all listeners that we have shutdown using the "broadcasterShutdown"
+ # broadcast key.
+ indigo.server.broadcastToSubscribers("broadcasterShutdown")
- ########################################
- def runConcurrentThread(self):
- try:
- # Every 3 seconds broadcast to subscribers a new random color from our list:
- colorList = ["red", "green", "blue", "indigo", "orange", "black", "white", "magento", "silver", "gold"]
- while True:
- color = colorList[random.randint(0, len(colorList)-1)]
- # broadcastToSubscribers can take an additional argument to be passed to
- # the subscribers. Allowed types include basic python objects: string, number,
- # boolean, dict, or list. For server performance please keep the data size
- # sent small (a few kilobytes at most), and try not to broadcast more frequently
- # than once per second. Bursts of higher data rates should be fine.
- indigo.server.broadcastToSubscribers("colorChanged", color)
- self.sleep(3)
- except self.StopThread:
- pass # Optionally catch the StopThread exception and do any needed cleanup.
+ ########################################
+ def runConcurrentThread(self):
+ try:
+ # Every 3 seconds broadcast to subscribers a new random color from our list:
+ color_list = ["red", "green", "blue", "indigo", "orange", "black", "white", "magento", "silver", "gold"]
+ while True:
+ color = color_list[random.randint(0, len(color_list)-1)]
+ # broadcastToSubscribers can take an additional argument to be passed to
+ # the subscribers. Allowed types include basic python objects: string, number,
+ # boolean, dict, or list. For server performance please keep the data size
+ # sent small (a few kilobytes at most), and try not to broadcast more frequently
+ # than once per second. Bursts of higher data rates should be fine.
+ indigo.server.broadcastToSubscribers("colorChanged", color)
+ self.sleep(3)
+ except self.StopThread:
+ pass # Optionally catch the StopThread exception and do any needed cleanup.
diff --git a/Example Custom Subscriber.indigoPlugin/Contents/Info.plist b/Example Custom Subscriber.indigoPlugin/Contents/Info.plist
index bffbc3a..dd30d56 100644
--- a/Example Custom Subscriber.indigoPlugin/Contents/Info.plist
+++ b/Example Custom Subscriber.indigoPlugin/Contents/Info.plist
@@ -2,24 +2,24 @@
- PluginVersion
- 2022.1.0
- ServerApiVersion
- 3.0
- IwsApiVersion
- 1.0.0
- CFBundleDisplayName
- Example Custom Subscriber
- CFBundleIdentifier
- com.perceptiveautomation.indigoplugin.custom-subscriber
- CFBundleVersion
- 1.0.0
- CFBundleURLTypes
-
-
- CFBundleURLName
- https://wiki.indigodomo.com/doku.php?id=plugins:example_custom_subscriber_1
-
-
+ PluginVersion
+ 2022.1.0
+ ServerApiVersion
+ 3.0
+ IwsApiVersion
+ 1.0.0
+ CFBundleDisplayName
+ Example Custom Subscriber
+ CFBundleIdentifier
+ com.perceptiveautomation.indigoplugin.custom-subscriber
+ CFBundleVersion
+ 1.0.0
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ https://wiki.indigodomo.com/doku.php?id=plugins:example_custom_subscriber_1
+
+
diff --git a/Example Custom Subscriber.indigoPlugin/Contents/Server Plugin/MenuItems.xml b/Example Custom Subscriber.indigoPlugin/Contents/Server Plugin/MenuItems.xml
index 0ac49ec..aecccaf 100644
--- a/Example Custom Subscriber.indigoPlugin/Contents/Server Plugin/MenuItems.xml
+++ b/Example Custom Subscriber.indigoPlugin/Contents/Server Plugin/MenuItems.xml
@@ -1,15 +1,15 @@
-
+
diff --git a/Example Custom Subscriber.indigoPlugin/Contents/Server Plugin/plugin.py b/Example Custom Subscriber.indigoPlugin/Contents/Server Plugin/plugin.py
index a689afd..ae413e5 100644
--- a/Example Custom Subscriber.indigoPlugin/Contents/Server Plugin/plugin.py
+++ b/Example Custom Subscriber.indigoPlugin/Contents/Server Plugin/plugin.py
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
####################
# Copyright (c) 2022, Perceptive Automation, LLC. All rights reserved.
-# http://www.indigodomo.com
+# https://www.indigodomo.com
import indigo
@@ -10,36 +10,36 @@
# our global name space by the host process.
# Plugin ID of the Example Custom Broadcaster plugin (taken from its Info.plist file):
-kBroadcasterPluginId = "com.perceptiveautomation.indigoplugin.custom-broadcaster"
+BROADCASTER_PLUGINID = "com.perceptiveautomation.indigoplugin.custom-broadcaster"
################################################################################
class Plugin(indigo.PluginBase):
- ########################################
- def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs):
- super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs)
- self.debug = True
-
- ########################################
- def startup(self):
- self.debugLog("startup called -- subscribing to messages from Example Custom Broadcaster plugin")
- # The Example Custom Broadcaster plugin defines three broadcast keys: broadcasterStarted,
- # broadcasterShutdown, and colorChanged. We subscribe to notifications of all three. The
- # second argument is the broadcast key used by the broadcasting plugin, the third argument
- # is the name of our callback method. In this case they are the same, but they don't have
- # to be.
- indigo.server.subscribeToBroadcast(kBroadcasterPluginId, "broadcasterStarted", "broadcasterStarted")
- indigo.server.subscribeToBroadcast(kBroadcasterPluginId, "broadcasterShutdown", "broadcasterShutdown")
- indigo.server.subscribeToBroadcast(kBroadcasterPluginId, "colorChanged", "colorChanged")
-
- def shutdown(self):
- self.logger.debug("shutdown called")
-
- ########################################
- def broadcasterStarted(self):
- self.logger.info("received broadcasterStarted message")
-
- def broadcasterShutdown(self):
- self.logger.info("received broadcasterShutdown message")
-
- def colorChanged(self, arg):
- self.logger.info(f"received colorChanged message: {arg}")
+ ########################################
+ def __init__(self, plugin_id, plugin_display_name, plugin_version, plugin_prefs):
+ super().__init__(plugin_id, plugin_display_name, plugin_version, plugin_prefs)
+ self.debug = True
+
+ ########################################
+ def startup(self):
+ self.logger.debug("startup called -- subscribing to messages from Example Custom Broadcaster plugin")
+ # The Example Custom Broadcaster plugin defines three broadcast keys: broadcasterStarted,
+ # broadcasterShutdown, and colorChanged. We subscribe to notifications of all three. The
+ # second argument is the broadcast key used by the broadcasting plugin, the third argument
+ # is the name of our callback method. In this case they are the same, but they don't have
+ # to be.
+ indigo.server.subscribeToBroadcast(BROADCASTER_PLUGINID, "broadcasterStarted", "broadcasterStarted")
+ indigo.server.subscribeToBroadcast(BROADCASTER_PLUGINID, "broadcasterShutdown", "broadcasterShutdown")
+ indigo.server.subscribeToBroadcast(BROADCASTER_PLUGINID, "colorChanged", "colorChanged")
+
+ def shutdown(self):
+ self.logger.debug("shutdown called")
+
+ ########################################
+ def broadcasterStarted(self):
+ self.logger.info("received broadcasterStarted message")
+
+ def broadcasterShutdown(self):
+ self.logger.info("received broadcasterShutdown message")
+
+ def colorChanged(self, arg):
+ self.logger.info(f"received colorChanged message: {arg}")
diff --git a/Example Database Traverse.indigoPlugin/Contents/Info.plist b/Example Database Traverse.indigoPlugin/Contents/Info.plist
index d1f72e1..c97e031 100644
--- a/Example Database Traverse.indigoPlugin/Contents/Info.plist
+++ b/Example Database Traverse.indigoPlugin/Contents/Info.plist
@@ -2,24 +2,24 @@
- PluginVersion
- 2022.1.0
- ServerApiVersion
- 3.0
- IwsApiVersion
- 1.0.0
- CFBundleDisplayName
- Example Database Traverse
- CFBundleIdentifier
- com.perceptiveautomation.indigoplugin.example-db-traverse
- CFBundleVersion
- 1.0.0
- CFBundleURLTypes
-
-
- CFBundleURLName
- https://wiki.indigodomo.com/doku.php?id=plugins:example_db_traverse_1
-
-
+ PluginVersion
+ 2022.1.0
+ ServerApiVersion
+ 3.0
+ IwsApiVersion
+ 1.0.0
+ CFBundleDisplayName
+ Example Database Traverse
+ CFBundleIdentifier
+ com.perceptiveautomation.indigoplugin.example-db-traverse
+ CFBundleVersion
+ 1.0.0
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ https://wiki.indigodomo.com/doku.php?id=plugins:example_db_traverse_1
+
+
diff --git a/Example Database Traverse.indigoPlugin/Contents/Server Plugin/MenuItems.xml b/Example Database Traverse.indigoPlugin/Contents/Server Plugin/MenuItems.xml
index cf3646d..ec0058b 100644
--- a/Example Database Traverse.indigoPlugin/Contents/Server Plugin/MenuItems.xml
+++ b/Example Database Traverse.indigoPlugin/Contents/Server Plugin/MenuItems.xml
@@ -1,31 +1,31 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/Example Database Traverse.indigoPlugin/Contents/Server Plugin/plugin.py b/Example Database Traverse.indigoPlugin/Contents/Server Plugin/plugin.py
index e30fba1..c3c4e36 100644
--- a/Example Database Traverse.indigoPlugin/Contents/Server Plugin/plugin.py
+++ b/Example Database Traverse.indigoPlugin/Contents/Server Plugin/plugin.py
@@ -1,8 +1,8 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
####################
-# Copyright (c) 2014, Perceptive Automation, LLC. All rights reserved.
-# http://www.indigodomo.com
+# Copyright (c) 2022, Perceptive Automation, LLC. All rights reserved.
+# https://www.indigodomo.com
import indigo
@@ -11,282 +11,282 @@
################################################################################
class Plugin(indigo.PluginBase):
- ########################################
- def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs):
- super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs)
+ ########################################
+ def __init__(self, plugin_id, plugin_display_name, plugin_version, plugin_prefs):
+ super().__init__(plugin_id, plugin_display_name, plugin_version, plugin_prefs)
- ########################################
- # IOM logging methods
- ####################
- def logListDivider(self, sectionName):
- self.logger.info("===================================================")
- self.logger.info(sectionName)
- self.logElemDivider()
+ ########################################
+ # IOM logging methods
+ ####################
+ def log_list_divider(self, section_name):
+ self.logger.info("===================================================")
+ self.logger.info(section_name)
+ self.log_elem_divider()
- def logElemDivider(self):
- self.logger.info("---------------------------------------------------")
+ def log_elem_divider(self):
+ self.logger.info("---------------------------------------------------")
- def logBaseElem(self, elem, folders):
- self.logger.info(f" INSTANCE: {elem.__class__.__name__}")
- if len(elem.description) > 0:
- self.logger.info(f" DESCRIPTION: {elem.description}")
- if folders and elem.folderId != 0:
- self.logger.info(f" IN FOLDER: {folders.getName(elem.folderId)}")
- self.logger.info(f" REMOTE DISPLAY: {elem.remoteDisplay}")
+ def log_base_elem(self, elem, folders):
+ self.logger.info(f" INSTANCE: {elem.__class__.__name__}")
+ if len(elem.description) > 0:
+ self.logger.info(f" DESCRIPTION: {elem.description}")
+ if folders and elem.folderId != 0:
+ self.logger.info(f" IN FOLDER: {folders.getName(elem.folderId)}")
+ self.logger.info(f" REMOTE DISPLAY: {elem.remoteDisplay}")
- def logBaseFolder(self, elem):
- if len(elem.description) > 0:
- self.logger.info(f" DESCRIPTION: {elem.description}")
- self.logger.info(f" REMOTE DISPLAY: {elem.remoteDisplay}")
+ def log_base_folder(self, elem):
+ if len(elem.description) > 0:
+ self.logger.info(f" DESCRIPTION: {elem.description}")
+ self.logger.info(f" REMOTE DISPLAY: {elem.remoteDisplay}")
- ########################################
- def logDeviceBase(self, elem):
- self.logBaseElem(elem, indigo.devices.folders)
- self.logger.info(f" PROTOCOL: {elem.protocol}")
- self.logger.info(f" MODEL NAME: {elem.model}")
- self.logger.info(f" ADDRESS: {elem.address}")
- if elem.protocol == indigo.kProtocol.Insteon and elem.buttonGroupCount > 0:
- self.logger.info(f" BUTTON COUNT: {elem.buttonGroupCount}")
- self.logger.info(f" LAST CHANGED: {elem.lastChanged}")
+ ########################################
+ def log_device_base(self, elem):
+ self.log_base_elem(elem, indigo.devices.folders)
+ self.logger.info(f" PROTOCOL: {elem.protocol}")
+ self.logger.info(f" MODEL NAME: {elem.model}")
+ self.logger.info(f" ADDRESS: {elem.address}")
+ if elem.protocol == indigo.kProtocol.Insteon and elem.buttonGroupCount > 0:
+ self.logger.info(f" BUTTON COUNT: {elem.buttonGroupCount}")
+ self.logger.info(f" LAST CHANGED: {elem.lastChanged}")
- supports = ""
- if elem.supportsAllLightsOnOff:
- supports += "AllLightsOnOff "
- if elem.supportsAllOff:
- supports += "AllOff "
- if elem.supportsStatusRequest:
- supports += "StatusRequest "
- if len(supports) == 0:
- supports = "--"
- self.logger.info(f" SUPPORTS: {supports}")
+ supports = ""
+ if elem.supportsAllLightsOnOff:
+ supports += "AllLightsOnOff "
+ if elem.supportsAllOff:
+ supports += "AllOff "
+ if elem.supportsStatusRequest:
+ supports += "StatusRequest "
+ if len(supports) == 0:
+ supports = "--"
+ self.logger.info(f" SUPPORTS: {supports}")
- ####################
- def logDeviceSensor(self, elem):
- self.logDeviceBase(elem)
- self.logger.info(f" IS ON: {elem.onState}")
+ ####################
+ def log_device_sensor(self, elem):
+ self.log_device_base(elem)
+ self.logger.info(f" IS ON: {elem.onState}")
- ####################
- def logDeviceRelay(self, elem):
- self.logDeviceBase(elem)
- self.logger.info(f" IS ON: {elem.onState}")
+ ####################
+ def log_device_relay(self, elem):
+ self.log_device_base(elem)
+ self.logger.info(f" IS ON: {elem.onState}")
- ####################
- def logDeviceDimmer(self, elem):
- self.logDeviceRelay(elem)
- self.logger.info(f" BRIGHTNESS: {elem.brightness}")
+ ####################
+ def log_device_dimmer(self, elem):
+ self.log_device_relay(elem)
+ self.logger.info(f" BRIGHTNESS: {elem.brightness}")
- ####################
- def logDeviceMultiIO(self, elem):
- self.logDeviceBase(elem)
- if elem.analogInputCount > 0:
- self.logger.info(f" ANALOG INPUTS: {elem.analogInputs}")
- if elem.binaryInputCount > 0:
- self.logger.info(f" BINARY INPUTS: {elem.binaryInputs}")
- if elem.sensorInputCount > 0:
- self.logger.info(f" SENSOR INPUTS: {elem.sensorInputs}")
- if elem.binaryOutputCount > 0:
- self.logger.info(f" BINARY OUTPUTS: {elem.binaryOutputs}")
+ ####################
+ def log_device_multi_io(self, elem):
+ self.log_device_base(elem)
+ if elem.analogInputCount > 0:
+ self.logger.info(f" ANALOG INPUTS: {elem.analogInputs}")
+ if elem.binaryInputCount > 0:
+ self.logger.info(f" BINARY INPUTS: {elem.binaryInputs}")
+ if elem.sensorInputCount > 0:
+ self.logger.info(f" SENSOR INPUTS: {elem.sensorInputs}")
+ if elem.binaryOutputCount > 0:
+ self.logger.info(f" BINARY OUTPUTS: {elem.binaryOutputs}")
- ####################
- def logDeviceSprinkler(self, elem):
- self.logDeviceBase(elem)
- self.logger.info(f" ZONE COUNT: {elem.zoneCount}")
- self.logger.info(f" ZONE NAMES: {elem.zoneNames}")
- self.logger.info(f" MAX DURATIONS: {elem.zoneMaxDurations}")
- if len(elem.zoneScheduledDurations) > 0:
- self.logger.info(f" SCHEDULED DURA.: {elem.zoneScheduledDurations}")
- if elem.activeZone:
- self.logger.info(f" ACTIVE ZONE: {elem.zoneNames[elem.activeZone]}")
+ ####################
+ def log_device_sprinkler(self, elem):
+ self.log_device_base(elem)
+ self.logger.info(f" ZONE COUNT: {elem.zoneCount}")
+ self.logger.info(f" ZONE NAMES: {elem.zoneNames}")
+ self.logger.info(f" MAX DURATIONS: {elem.zoneMaxDurations}")
+ if len(elem.zoneScheduledDurations) > 0:
+ self.logger.info(f" SCHEDULED DURA.: {elem.zoneScheduledDurations}")
+ if elem.activeZone:
+ self.logger.info(f" ACTIVE ZONE: {elem.zoneNames[elem.activeZone]}")
- ####################
- def logDeviceThermostat(self, elem):
- self.logDeviceBase(elem)
- self.logger.info(f" HVAC MODE: {elem.hvacMode}")
- self.logger.info(f" FAN MODE: {elem.fanMode}")
- self.logger.info(f" COOL SETPOINT: {elem.coolSetpoint}")
- self.logger.info(f" HEAT SETPOINT: {elem.heatSetpoint}")
- self.logger.info(f" TEMP COUNT: {elem.temperatureSensorCount}")
- self.logger.info(f" TEMPS: {elem.temperatures}")
- self.logger.info(f" HUMIDITY COUNT: {elem.humiditySensorCount}")
- self.logger.info(f" HUMIDITY: {elem.humidities}")
- self.logger.info(f" COOL IS ON: {elem.coolIsOn}")
- self.logger.info(f" HEAT IS ON: {elem.heatIsOn}")
- self.logger.info(f" FAN IS ON: {elem.fanIsOn}")
+ ####################
+ def log_device_thermostat(self, elem):
+ self.log_device_base(elem)
+ self.logger.info(f" HVAC MODE: {elem.hvacMode}")
+ self.logger.info(f" FAN MODE: {elem.fanMode}")
+ self.logger.info(f" COOL SETPOINT: {elem.coolSetpoint}")
+ self.logger.info(f" HEAT SETPOINT: {elem.heatSetpoint}")
+ self.logger.info(f" TEMP COUNT: {elem.temperatureSensorCount}")
+ self.logger.info(f" TEMPS: {elem.temperatures}")
+ self.logger.info(f" HUMIDITY COUNT: {elem.humiditySensorCount}")
+ self.logger.info(f" HUMIDITY: {elem.humidities}")
+ self.logger.info(f" COOL IS ON: {elem.coolIsOn}")
+ self.logger.info(f" HEAT IS ON: {elem.heatIsOn}")
+ self.logger.info(f" FAN IS ON: {elem.fanIsOn}")
- ####################
- def logDevice(self, elem):
- if isinstance(elem, indigo.DimmerDevice):
- self.logDeviceDimmer(elem)
- elif isinstance(elem, indigo.RelayDevice):
- self.logDeviceRelay(elem)
- elif isinstance(elem, indigo.SensorDevice):
- self.logDeviceSensor(elem)
- elif isinstance(elem, indigo.MultiIODevice):
- self.logDeviceMultiIO(elem)
- elif isinstance(elem, indigo.SprinklerDevice):
- self.logDeviceSprinkler(elem)
- elif isinstance(elem, indigo.ThermostatDevice):
- self.logDeviceThermostat(elem)
- else:
- self.logDeviceBase(elem)
+ ####################
+ def log_device(self, elem):
+ if isinstance(elem, indigo.DimmerDevice):
+ self.log_device_dimmer(elem)
+ elif isinstance(elem, indigo.RelayDevice):
+ self.log_device_relay(elem)
+ elif isinstance(elem, indigo.SensorDevice):
+ self.log_device_sensor(elem)
+ elif isinstance(elem, indigo.MultiIODevice):
+ self.log_device_multi_io(elem)
+ elif isinstance(elem, indigo.SprinklerDevice):
+ self.log_device_sprinkler(elem)
+ elif isinstance(elem, indigo.ThermostatDevice):
+ self.log_device_thermostat(elem)
+ else:
+ self.log_device_base(elem)
- ########################################
- def logEventBase(self, elem, folders):
- self.logBaseElem(elem, folders)
- self.logger.info(f" ENABLED: {elem.enabled}")
- self.logger.info(f" UPLOAD: {elem.upload}")
- if elem.suppressLogging:
- self.logger.info("SUPPRESS LOGGING: True")
- # TODO: Need to add conditional tree and action list traversal here.
+ ########################################
+ def log_event_base(self, elem, folders):
+ self.log_base_elem(elem, folders)
+ self.logger.info(f" ENABLED: {elem.enabled}")
+ self.logger.info(f" UPLOAD: {elem.upload}")
+ if elem.suppressLogging:
+ self.logger.info("SUPPRESS LOGGING: True")
+ # TODO: Need to add conditional tree and action list traversal here.
- ####################
- def logTrigger(self, elem):
- self.logEventBase(elem, indigo.triggers.folders)
+ ####################
+ def log_trigger(self, elem):
+ self.log_event_base(elem, indigo.triggers.folders)
- if isinstance(elem, indigo.DeviceStateChangeTrigger):
- self.logger.info(f" DEVICE: {indigo.devices.getName(elem.deviceId)}")
- self.logger.info(f" CHANGE TYPE: {elem.stateChangeType}")
- self.logger.info(f" SELECTOR KEY: {elem.stateSelector}")
- if elem.stateSelectorIndex > 0:
- self.logger.info(f" SELECTOR INDEX: {elem.stateSelectorIndex}")
- if len(elem.stateValue) > 0:
- self.logger.info(f" STATE VALUE: {elem.stateValue}")
- elif isinstance(elem, indigo.VariableValueChangeTrigger):
- self.logger.info(f" VARIABLE: {indigo.variables.getName(elem.variableId)}")
- self.logger.info(f" CHANGE TYPE: {elem.variableChangeType}")
- if len(elem.variableValue) > 0:
- self.logger.info(f" VARIABLE VALUE: {elem.variableValue}")
- elif isinstance(elem, indigo.InsteonCommandReceivedTrigger):
- self.logger.info(f" INSTEON COMMAND: {elem.command}")
- self.logger.info(f" SOURCE TYPE: {elem.commandSourceType}")
- if elem.commandSourceType == indigo.kDeviceSourceType.DeviceId:
- self.logger.info(f" DEVICE: {indigo.devices.getName(elem.deviceId)}")
- self.logger.info(f" GROUP NUM: {elem.buttonOrGroup}")
- elif isinstance(elem, indigo.X10CommandReceivedTrigger):
- self.logger.info(f" X10 COMMAND: {elem.command}")
- self.logger.info(f" SOURCE TYPE: {elem.commandSourceType}")
- if elem.commandSourceType == indigo.kDeviceSourceType.DeviceId:
- self.logger.info(f" DEVICE: {indigo.devices.getName(elem.deviceId)}")
- elif elem.commandSourceType == indigo.kDeviceSourceType.RawAddress:
- self.logger.info(f" ADDRESS: {elem.address}")
- elif elem.command == indigo.kX10Cmd.AvButtonPressed:
- self.logger.info(f" A/V BUTTON: {elem.avButton}")
- elif isinstance(elem, indigo.EmailReceivedTrigger):
- self.logger.info(f" EMAIL FILTER: {elem.emailFilter}")
- if elem.emailFilter == indigo.kEmailFilter.MatchEmailFields:
- self.logger.info(f" FROM FILTER: {elem.emailFrom}")
- self.logger.info(f" SUBJECT FILTER: {elem.emailSubject}")
+ if isinstance(elem, indigo.DeviceStateChangeTrigger):
+ self.logger.info(f" DEVICE: {indigo.devices.getName(elem.deviceId)}")
+ self.logger.info(f" CHANGE TYPE: {elem.stateChangeType}")
+ self.logger.info(f" SELECTOR KEY: {elem.stateSelector}")
+ if elem.stateSelectorIndex > 0:
+ self.logger.info(f" SELECTOR INDEX: {elem.stateSelectorIndex}")
+ if len(elem.stateValue) > 0:
+ self.logger.info(f" STATE VALUE: {elem.stateValue}")
+ elif isinstance(elem, indigo.VariableValueChangeTrigger):
+ self.logger.info(f" VARIABLE: {indigo.variables.getName(elem.variableId)}")
+ self.logger.info(f" CHANGE TYPE: {elem.variableChangeType}")
+ if len(elem.variableValue) > 0:
+ self.logger.info(f" VARIABLE VALUE: {elem.variableValue}")
+ elif isinstance(elem, indigo.InsteonCommandReceivedTrigger):
+ self.logger.info(f" INSTEON COMMAND: {elem.command}")
+ self.logger.info(f" SOURCE TYPE: {elem.commandSourceType}")
+ if elem.commandSourceType == indigo.kDeviceSourceType.DeviceId:
+ self.logger.info(f" DEVICE: {indigo.devices.getName(elem.deviceId)}")
+ self.logger.info(f" GROUP NUM: {elem.buttonOrGroup}")
+ elif isinstance(elem, indigo.X10CommandReceivedTrigger):
+ self.logger.info(f" X10 COMMAND: {elem.command}")
+ self.logger.info(f" SOURCE TYPE: {elem.commandSourceType}")
+ if elem.commandSourceType == indigo.kDeviceSourceType.DeviceId:
+ self.logger.info(f" DEVICE: {indigo.devices.getName(elem.deviceId)}")
+ elif elem.commandSourceType == indigo.kDeviceSourceType.RawAddress:
+ self.logger.info(f" ADDRESS: {elem.address}")
+ elif elem.command == indigo.kX10Cmd.AvButtonPressed:
+ self.logger.info(f" A/V BUTTON: {elem.avButton}")
+ elif isinstance(elem, indigo.EmailReceivedTrigger):
+ self.logger.info(f" EMAIL FILTER: {elem.emailFilter}")
+ if elem.emailFilter == indigo.kEmailFilter.MatchEmailFields:
+ self.logger.info(f" FROM FILTER: {elem.emailFrom}")
+ self.logger.info(f" SUBJECT FILTER: {elem.emailSubject}")
- ####################
- def logSchedule(self, elem):
- self.logEventBase(elem, indigo.schedules.folders)
- self.logger.info(f" DATE TYPE: {elem.dateType}")
- self.logger.info(f" TIME TYPE: {elem.timeType}")
- if elem.dateType == indigo.kDateType.Absolute and elem.timeType == indigo.kTimeType.Absolute:
- self.logger.info(f" DATE AND TIME: {elem.absoluteDateTime}")
- elif elem.dateType == indigo.kDateType.Absolute:
- self.logger.info(f" ABSOLUTE DATE: {elem.absoluteDate.date()}")
- elif elem.timeType == indigo.kTimeType.Absolute:
- self.logger.info(f" ABSOLUTE TIME: {elem.absoluteTime.time()}")
- if elem.sunDelta > 0:
- self.logger.info(f" SUN DELTA: {elem.sunDelta} seconds")
- if elem.randomizeBy > 0:
- self.logger.info(f" RANDOMIZE BY: {elem.randomizeBy} seconds")
- try:
- self.logger.info(f" NEXT EXECUTION: {elem.nextExecution}")
- except:
- self.logger.info(f" NEXT EXECUTION: - none scheduled -")
- # TODO: Need to log additional properties after they are implemented here.
+ ####################
+ def log_schedule(self, elem):
+ self.log_event_base(elem, indigo.schedules.folders)
+ self.logger.info(f" DATE TYPE: {elem.dateType}")
+ self.logger.info(f" TIME TYPE: {elem.timeType}")
+ if elem.dateType == indigo.kDateType.Absolute and elem.timeType == indigo.kTimeType.Absolute:
+ self.logger.info(f" DATE AND TIME: {elem.absoluteDateTime}")
+ elif elem.dateType == indigo.kDateType.Absolute:
+ self.logger.info(f" ABSOLUTE DATE: {elem.absoluteDate.date()}")
+ elif elem.timeType == indigo.kTimeType.Absolute:
+ self.logger.info(f" ABSOLUTE TIME: {elem.absoluteTime.time()}")
+ if elem.sunDelta > 0:
+ self.logger.info(f" SUN DELTA: {elem.sunDelta} seconds")
+ if elem.randomizeBy > 0:
+ self.logger.info(f" RANDOMIZE BY: {elem.randomizeBy} seconds")
+ try:
+ self.logger.info(f" NEXT EXECUTION: {elem.nextExecution}")
+ except:
+ self.logger.info(" NEXT EXECUTION: - none scheduled -")
+ # TODO: Need to log additional properties after they are implemented here.
- ####################
- def logActionGroup(self, elem):
- self.logBaseElem(elem, indigo.actionGroups.folders)
- # TODO: Need to add action list traversal here.
+ ####################
+ def log_action_group(self, elem):
+ self.log_base_elem(elem, indigo.actionGroups.folders)
+ # TODO: Need to add action list traversal here.
- ####################
- def logControlPage(self, elem):
- self.logBaseElem(elem, indigo.controlPages.folders)
- self.logger.info(f" HIDE TABBAR: {elem.hideTabBar}")
- if len(elem.backgroundImage) > 0:
- self.logger.info(f"BACKGROUND IMAGE: {elem.backgroundImage}")
- # TODO: Need to log additional properties after they are implemented here.
- # TODO: Need to add control list traversal here.
+ ####################
+ def log_control_page(self, elem):
+ self.log_base_elem(elem, indigo.controlPages.folders)
+ self.logger.info(f" HIDE TABBAR: {elem.hideTabBar}")
+ if len(elem.backgroundImage) > 0:
+ self.logger.info(f"BACKGROUND IMAGE: {elem.backgroundImage}")
+ # TODO: Need to log additional properties after they are implemented here.
+ # TODO: Need to add control list traversal here.
- ####################
- def logVariable(self, elem):
- self.logBaseElem(elem, indigo.variables.folders)
- self.logger.info(f" VALUE: {elem.value}")
- if elem.readOnly:
- self.logger.info(" READ ONLY: True")
+ ####################
+ def log_variable(self, elem):
+ self.log_base_elem(elem, indigo.variables.folders)
+ self.logger.info(f" VALUE: {elem.value}")
+ if elem.readOnly:
+ self.logger.info(" READ ONLY: True")
- ########################################
- # Actions defined in MenuItems.xml:
- ####################
- def traverseDevices(self):
- self.logListDivider("DEVICES")
- for folder in indigo.devices.folders:
- self.logger.info(f" FOLDER: {folder.name}")
- self.logBaseFolder(folder)
- for elem in indigo.devices:
- self.logElemDivider()
- self.logger.info(f" DEVICE: {elem.name}")
- self.logDevice(elem)
+ ########################################
+ # Actions defined in MenuItems.xml:
+ ####################
+ def traverse_devices(self):
+ self.log_list_divider("DEVICES")
+ for folder in indigo.devices.folders:
+ self.logger.info(f" FOLDER: {folder.name}")
+ self.log_base_folder(folder)
+ for elem in indigo.devices:
+ self.log_elem_divider()
+ self.logger.info(f" DEVICE: {elem.name}")
+ self.log_device(elem)
- def traverseTriggers(self):
- self.logListDivider("TRIGGERS")
- for folder in indigo.triggers.folders:
- self.logger.info(f" FOLDER: {folder.name}")
- self.logBaseFolder(folder)
- for elem in indigo.triggers:
- self.logElemDivider()
- self.logger.info(f" TRIGGER: {elem.name}")
- self.logTrigger(elem)
+ def traverse_triggers(self):
+ self.log_list_divider("TRIGGERS")
+ for folder in indigo.triggers.folders:
+ self.logger.info(f" FOLDER: {folder.name}")
+ self.log_base_folder(folder)
+ for elem in indigo.triggers:
+ self.log_elem_divider()
+ self.logger.info(f" TRIGGER: {elem.name}")
+ self.log_trigger(elem)
- def traverseSchedules(self):
- self.logListDivider("SCHEDULES")
- for folder in indigo.schedules.folders:
- self.logger.info(f" FOLDER: {folder.name}")
- self.logBaseFolder(folder)
- for elem in indigo.schedules:
- self.logElemDivider()
- self.logger.info(f" SCHEDULE: {elem.name}")
- self.logSchedule(elem)
+ def traverse_schedules(self):
+ self.log_list_divider("SCHEDULES")
+ for folder in indigo.schedules.folders:
+ self.logger.info(f" FOLDER: {folder.name}")
+ self.log_base_folder(folder)
+ for elem in indigo.schedules:
+ self.log_elem_divider()
+ self.logger.info(f" SCHEDULE: {elem.name}")
+ self.log_schedule(elem)
- def traverseActionGroups(self):
- self.logListDivider("ACTION GROUPS")
- for folder in indigo.actionGroups.folders:
- self.logger.info(f" FOLDER: {folder.name}")
- self.logBaseFolder(folder)
- for elem in indigo.actionGroups:
- self.logElemDivider()
- self.logger.info(f" ACTION GROUP: {elem.name}")
- self.logActionGroup(elem)
+ def traverse_action_groups(self):
+ self.log_list_divider("ACTION GROUPS")
+ for folder in indigo.actionGroups.folders:
+ self.logger.info(f" FOLDER: {folder.name}")
+ self.log_base_folder(folder)
+ for elem in indigo.actionGroups:
+ self.log_elem_divider()
+ self.logger.info(f" ACTION GROUP: {elem.name}")
+ self.log_action_group(elem)
- def traverseControlPages(self):
- self.logListDivider("CONTROL PAGES")
- for folder in indigo.controlPages.folders:
- self.logger.info(f" FOLDER: {folder.name}")
- self.logBaseFolder(folder)
- for elem in indigo.controlPages:
- self.logElemDivider()
- self.logger.info(f" CONTROL PAGE: {elem.name}")
- self.logControlPage(elem)
+ def traverse_control_pages(self):
+ self.log_list_divider("CONTROL PAGES")
+ for folder in indigo.controlPages.folders:
+ self.logger.info(f" FOLDER: {folder.name}")
+ self.log_base_folder(folder)
+ for elem in indigo.controlPages:
+ self.log_elem_divider()
+ self.logger.info(f" CONTROL PAGE: {elem.name}")
+ self.log_control_page(elem)
- def traverseVariables(self):
- self.logListDivider("VARIABLES")
- for folder in indigo.variables.folders:
- self.logger.info(f" FOLDER: {folder.name}")
- self.logBaseFolder(folder)
- for elem in indigo.variables:
- self.logElemDivider()
- self.logger.info(f" VARIABLE: {elem.name}")
- self.logVariable(elem)
+ def traverse_variables(self):
+ self.log_list_divider("VARIABLES")
+ for folder in indigo.variables.folders:
+ self.logger.info(f" FOLDER: {folder.name}")
+ self.log_base_folder(folder)
+ for elem in indigo.variables:
+ self.log_elem_divider()
+ self.logger.info(f" VARIABLE: {elem.name}")
+ self.log_variable(elem)
- ####################
- def traverseDatabase(self):
- self.traverseDevices()
- self.traverseTriggers()
- self.traverseSchedules()
- self.traverseActionGroups()
- self.traverseControlPages()
- self.traverseVariables()
+ ####################
+ def traverse_database(self):
+ self.traverse_devices()
+ self.traverse_triggers()
+ self.traverse_schedules()
+ self.traverse_action_groups()
+ self.traverse_control_pages()
+ self.traverse_variables()
diff --git a/Example Device - Custom.indigoPlugin/Contents/Info.plist b/Example Device - Custom.indigoPlugin/Contents/Info.plist
index 319ae50..df65011 100644
--- a/Example Device - Custom.indigoPlugin/Contents/Info.plist
+++ b/Example Device - Custom.indigoPlugin/Contents/Info.plist
@@ -3,9 +3,9 @@
PluginVersion
- 2021.1.0
+ 2022.1.0ServerApiVersion
- 2.5
+ 3.0IwsApiVersion1.0.0CFBundleDisplayName
@@ -18,7 +18,7 @@
CFBundleURLName
- http://wiki.indigodomo.com/doku.php?id=plugins:example_dev_1
+ https://wiki.indigodomo.com/doku.php?id=plugins:example_dev_1
diff --git a/Example Device - Custom.indigoPlugin/Contents/Server Plugin/Actions.xml b/Example Device - Custom.indigoPlugin/Contents/Server Plugin/Actions.xml
index 2a2d617..36a4a7d 100644
--- a/Example Device - Custom.indigoPlugin/Contents/Server Plugin/Actions.xml
+++ b/Example Device - Custom.indigoPlugin/Contents/Server Plugin/Actions.xml
@@ -1,26 +1,26 @@
- http://wiki.indigodomo.com/doku.php?id=plugins:example_dev_1
-
- Reset Hardware
- resetHardware
-
-
- Update Hardware Firmware
- updateHardwareFirmware
-
- http://wiki.indigodomo.com/doku.php?id=plugins:example_dev_1
-
-
-
-
-
- Update to the latest beta version (not really)
-
-
-
- Send notifications when there's a new beta version (not really)
-
-
-
+ https://wiki.indigodomo.com/doku.php?id=plugins:example_dev_1
+
+ Reset Hardware
+ reset_hardware
+
+
+ Update Hardware Firmware
+ update_hardware_firmware
+
+ https://wiki.indigodomo.com/doku.php?id=plugins:example_dev_1
+
+
+
+
+
+ Update to the latest beta version (not really)
+
+
+
+ Send notifications when there's a new beta version (not really)
+
+
+
diff --git a/Example Device - Custom.indigoPlugin/Contents/Server Plugin/Devices.xml b/Example Device - Custom.indigoPlugin/Contents/Server Plugin/Devices.xml
index de76ebc..76787c4 100644
--- a/Example Device - Custom.indigoPlugin/Contents/Server Plugin/Devices.xml
+++ b/Example Device - Custom.indigoPlugin/Contents/Server Plugin/Devices.xml
@@ -1,149 +1,149 @@
-
-
- Current Server Time
-
-
-
-
-
-
-
-
-
-
- Integer
- Current Server Seconds
- Current Server Seconds
-
-
- Boolean
- Current Server Seconds is Even
- Current Server Seconds is Even
-
-
- Separator
-
-
- String
- Current Server Date and Time
- Current Server Date and Time
-
-
- serverTimeSeconds
-
+
+
+ Current Server Time
+
+
+
+
+
+
+
+
+
+
+ Integer
+ Current Server Seconds
+ Current Server Seconds
+
+
+ Boolean
+ Current Server Seconds is Even
+ Current Server Seconds is Even
+
+
+ Separator
+
+
+ String
+ Current Server Date and Time
+ Current Server Date and Time
+
+
+ serverTimeSeconds
+
-
-
- State Value Updater
-
-
- Integer
- Always Integer Value
- Always Integer Value
-
-
- Number
- Always Float Value
- Always Float Value
-
-
- String
- String Value Toggle 0.0 and 0.000
- String Value Toggle 0.0 and 0.000
-
-
- String
- String Value Toggle abc to def
- String Value Toggle abc to def
-
-
- Integer
- Integer to Float Value
- Integer to Float Value
-
-
- Integer
- Integer to String Value
- Integer to String Value
-
-
- Number
- Float to String Value
- Float to String Value
-
-
- Integer
- Timestamp
- Timestamp
-
-
- timeStamp
-
+
+
+ State Value Updater
+
+
+ Integer
+ Always Integer Value
+ Always Integer Value
+
+
+ Number
+ Always Float Value
+ Always Float Value
+
+
+ String
+ String Value Toggle 0.0 and 0.000
+ String Value Toggle 0.0 and 0.000
+
+
+ String
+ String Value Toggle abc to def
+ String Value Toggle abc to def
+
+
+ Integer
+ Integer to Float Value
+ Integer to Float Value
+
+
+ Integer
+ Integer to String Value
+ Integer to String Value
+
+
+ Number
+ Float to String Value
+ Float to String Value
+
+
+ Integer
+ Timestamp
+ Timestamp
+
+
+ timeStamp
+
-
-
- Scene
-
-
-
-
-
-
-
- Add Device
- addDevice
-
-
-
-
-
-
-
-
- Delete Devices
- deleteDevices
-
-
-
-
-
-
+
+
+ Scene
+
+
+
+
+
+
+
+ Add Device
+ add_device
+
+
+
+
+
+
+
+
+ Delete Devices
+ delete_devices
+
+
+
+
+
+
diff --git a/Example Device - Custom.indigoPlugin/Contents/Server Plugin/MenuItems.xml b/Example Device - Custom.indigoPlugin/Contents/Server Plugin/MenuItems.xml
index c4e995c..4210815 100644
--- a/Example Device - Custom.indigoPlugin/Contents/Server Plugin/MenuItems.xml
+++ b/Example Device - Custom.indigoPlugin/Contents/Server Plugin/MenuItems.xml
@@ -1,13 +1,13 @@
-
+
diff --git a/Example Device - Custom.indigoPlugin/Contents/Server Plugin/plugin.py b/Example Device - Custom.indigoPlugin/Contents/Server Plugin/plugin.py
index 1f80ea1..7b365ab 100644
--- a/Example Device - Custom.indigoPlugin/Contents/Server Plugin/plugin.py
+++ b/Example Device - Custom.indigoPlugin/Contents/Server Plugin/plugin.py
@@ -1,13 +1,10 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
####################
-# Copyright (c) 2014, Perceptive Automation, LLC. All rights reserved.
-# http://www.indigodomo.com
+# Copyright (c) 2022, Perceptive Automation, LLC. All rights reserved.
+# https://www.indigodomo.com
import indigo
-
-import os
-import sys
import time
# Note the "indigo" module is automatically imported and made available inside
@@ -15,270 +12,293 @@
################################################################################
class Plugin(indigo.PluginBase):
- ########################################
- def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs):
- super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs)
- self.debug = True
- self.timeWarpOn = False
- self.timeWarpCount = 0
+ ########################################
+ def __init__(self, plugin_id, plugin_display_name, plugin_version, plugin_prefs):
+ super().__init__(plugin_id, plugin_display_name, plugin_version, plugin_prefs)
+ self.debug = True
+ self.time_warp_on = False
+ self.time_warp_count = 0
+ self.state_updater_dev = None
+ self.server_time_dev = None
- ########################################
- def startup(self):
- self.debugLog(u"startup called")
+ ########################################
+ def startup(self):
+ self.logger.debug("startup called")
+ # Most plugins that expose new device types will depend on the user
+ # creating the new device from the Indigo UI (just like a native device).
+ #
+ # However, it is also possible for the plugin to create the devices
+ # automatically at runtime:
+ if "Example Server Time" in indigo.devices:
+ self.server_time_dev = indigo.devices["Example Server Time"]
+ else:
+ self.logger.info("creating test device: Example Server Time")
+ self.server_time_dev = indigo.device.create(
+ indigo.kProtocol.Plugin,
+ "Example Server Time",
+ "test device created by example plugin",
+ deviceTypeId="serverTimeDevice"
+ )
+ # Override the state icon shown (in Indigo Touch and client Main Window)
+ # for this device to be the timer image icon:
+ self.server_time_dev.updateStateImageOnServer(indigo.kStateImageSel.TimerOn)
+ if "Example State Updater" in indigo.devices:
+ self.state_updater_dev = indigo.devices["Example State Updater"]
+ else:
+ self.logger.info("creating test device: Example State Updater")
+ self.state_updater_dev = indigo.device.create(
+ indigo.kProtocol.Plugin,
+ "Example State Updater",
+ "test state value updating device created by example plugin device",
+ deviceTypeId="stateUpdater"
+ )
+ # Override the state icon shown (in Indigo Touch and client Main Window)
+ # for this device to be the timer image icon:
+ self.state_updater_dev.updateStateImageOnServer(indigo.kStateImageSel.TimerOn)
- # Most plugins that expose new device types will depend on the user
- # creating the new device from the Indigo UI (just like a native device).
- #
- # However, it is also possible for the plugin to create the devices
- # automatically at runtime:
- if "Example Server Time" in indigo.devices:
- self.serverTimeDev = indigo.devices["Example Server Time"]
- else:
- indigo.server.log(u"creating test device: Example Server Time")
- self.serverTimeDev = indigo.device.create(indigo.kProtocol.Plugin, "Example Server Time", "test device created by example plugin", deviceTypeId="serverTimeDevice")
- # Override the state icon shown (in Indigo Touch and client Main Window)
- # for this device to be the timer image icon:
- self.serverTimeDev.updateStateImageOnServer(indigo.kStateImageSel.TimerOn)
+ def shutdown(self):
+ self.logger.debug("shutdown called")
+ key_value_list = [
+ {'key': 'serverTimeSeconds', 'value': 0},
+ {'key': 'serverSecondsEven', 'value': False},
+ {'key': 'serverDateTime', 'value': "--"},
+ ]
+ self.server_time_dev.updateStatesOnServer(key_value_list)
- if "Example State Updater" in indigo.devices:
- self.stateUpdaterDev = indigo.devices["Example State Updater"]
- else:
- indigo.server.log(u"creating test device: Example State Updater")
- self.stateUpdaterDev = indigo.device.create(indigo.kProtocol.Plugin, "Example State Updater", "test state value updating device created by example plugin device", deviceTypeId="stateUpdater")
- # Override the state icon shown (in Indigo Touch and client Main Window)
- # for this device to be the timer image icon:
- self.stateUpdaterDev.updateStateImageOnServer(indigo.kStateImageSel.TimerOn)
+ ########################################
+ # If runConcurrentThread() is defined, then a new thread is automatically created
+ # and runConcurrentThread() is called in that thread after startup() has been called.
+ #
+ # runConcurrentThread() should loop forever and only return after self.stopThread
+ # becomes True. If this function returns prematurely then the plugin host process
+ # will log an error and attempt to call runConcurrentThread() again after several seconds.
+ def runConcurrentThread(self):
+ try:
+ while True:
+ server_time = indigo.server.getTime()
+ server_time_second = server_time.second
+ if self.time_warp_on:
+ self.time_warp_count += 1
+ server_time_second = self.time_warp_count
- def shutdown(self):
- self.debugLog(u"shutdown called")
+ key_value_list = [
+ {'key': 'serverTimeSeconds', 'value': server_time_second},
+ {'key': 'serverSecondsEven', 'value': not bool(server_time_second % 2)},
+ {'key': 'serverDateTime', 'value': str(server_time)}
+ ]
+ self.server_time_dev.updateStatesOnServer(key_value_list)
- keyValueList = []
- keyValueList.append({'key':'serverTimeSeconds', 'value':0})
- keyValueList.append({'key':'serverSecondsEven', 'value':False})
- keyValueList.append({'key':'serverDateTime', 'value':"--"})
- self.serverTimeDev.updateStatesOnServer(keyValueList)
+ key_value_list = []
+ if server_time_second % 2:
+ key_value_list.append({'key': 'alwaysInteger', 'value': 0})
+ key_value_list.append({'key': 'alwaysFloat', 'value': 0.01})
+ key_value_list.append({'key': 'stringToggleFloats', 'value': "0.0"})
+ key_value_list.append({'key': 'stringToggleStrings', 'value': "abc"})
+ key_value_list.append({'key': 'integerToFloat', 'value': 0})
+ key_value_list.append({'key': 'integerToString', 'value': 0})
+ key_value_list.append({'key': 'floatToString', 'value': 0.1})
+ else:
+ key_value_list.append({'key': 'alwaysInteger', 'value': 1})
+ key_value_list.append({'key': 'alwaysFloat', 'value': 0.123456, 'decimalPlaced': 4})
+ key_value_list.append({'key': 'stringToggleFloats', 'value': "0.0000"})
+ key_value_list.append({'key': 'stringToggleStrings', 'value': "def"})
+ key_value_list.append({'key': 'integerToFloat', 'value': 0.1})
+ key_value_list.append({'key': 'integerToString', 'value': "abc"})
+ key_value_list.append({'key': 'floatToString', 'value': "abc"})
+ key_value_list.append({'key': 'timeStamp', 'value': str(time.time()).split(".")[0]})
+ try:
+ self.state_updater_dev.updateStatesOnServer(key_value_list)
+ except Exception as exc:
+ self.logger.exception(exc)
+ if self.time_warp_on:
+ self.sleep(0.12)
+ else:
+ self.sleep(1)
+ except self.StopThread:
+ pass # Optionally catch the StopThread exception and do any needed cleanup.
- ########################################
- # If runConcurrentThread() is defined, then a new thread is automatically created
- # and runConcurrentThread() is called in that thread after startup() has been called.
- #
- # runConcurrentThread() should loop forever and only return after self.stopThread
- # becomes True. If this function returns prematurely then the plugin host process
- # will log an error and attempt to call runConcurrentThread() again after several seconds.
- def runConcurrentThread(self):
- try:
- while True:
- serverTime = indigo.server.getTime()
- serverTimeSecond = serverTime.second
- if self.timeWarpOn:
- self.timeWarpCount += 1
- serverTimeSecond = self.timeWarpCount
+ ########################################
+ # Actions defined in MenuItems.xml:
+ ####################
+ def time_warp(self):
+ if not self.time_warp_on:
+ self.logger.info("starting mega time warp")
+ self.time_warp_on = True
+ else:
+ self.logger.info("stopping mega time warp")
+ self.time_warp_on = False
- keyValueList = []
- keyValueList.append({'key':'serverTimeSeconds', 'value':serverTimeSecond})
- keyValueList.append({'key':'serverSecondsEven', 'value':not bool(serverTimeSecond % 2)})
- keyValueList.append({'key':'serverDateTime', 'value':str(serverTime)})
- self.serverTimeDev.updateStatesOnServer(keyValueList)
+ ########################################
+ """
+ Buttons and dynamic list methods defined for the scenes custom device
- keyValueList = []
- if serverTimeSecond % 2:
- keyValueList.append({'key':'alwaysInteger', 'value':0})
- keyValueList.append({'key':'alwaysFloat', 'value':0.01})
- keyValueList.append({'key':'stringToggleFloats', 'value':"0.0"})
- keyValueList.append({'key':'stringToggleStrings', 'value':"abc"})
- keyValueList.append({'key':'integerToFloat', 'value':0})
- keyValueList.append({'key':'integerToString', 'value':0})
- keyValueList.append({'key':'floatToString', 'value':0.1})
- else:
- keyValueList.append({'key':'alwaysInteger', 'value':1})
- keyValueList.append({'key':'alwaysFloat', 'value':0.123456, 'decimalPlaced':4})
- keyValueList.append({'key':'stringToggleFloats', 'value':"0.0000"})
- keyValueList.append({'key':'stringToggleStrings', 'value':"def"})
- keyValueList.append({'key':'integerToFloat', 'value':0.1})
- keyValueList.append({'key':'integerToString', 'value':"abc"})
- keyValueList.append({'key':'floatToString', 'value':"abc"})
- keyValueList.append({'key':'timeStamp', 'value':str(time.time()).split(".")[0]})
- self.stateUpdaterDev.updateStatesOnServer(keyValueList)
- if self.timeWarpOn:
- self.sleep(0.12)
- else:
- self.sleep(1)
- except self.StopThread:
- pass # Optionally catch the StopThread exception and do any needed cleanup.
+ Overview of scene devices:
+ Scene devices are custom devices that will contain multiple devices.
+ We implement this custom device by storing a comma-delimited list of
+ device IDs which is manipulated by clicking Add and Delete buttons
+ in the device config dialog. There are two dynamic list controls in
+ the dialog:
+ 1) one popup button control on which the user selects a device
+ to add then clicks the Add Device button.
+ 2) one list control which shows all the devices that have already
+ been added to the scene and in which the user can select devices
+ and click the Delete Devices button
+ There is a hidden field "memberDevices" that stores a comma-delimited
+ list of device ids for each member of the scene. The add_device and
+ delete_devices methods will take the selections from the respective
+ dynamic lists and do the right thing with the list.
+ Finally, there are the two methods that build the dynamic lists.
+ The method that builds the source list will inspect the "memberDevices"
+ field and won't include those devices in the source list (so the user
+ won't be confused by seeing a device that's already in the member list
+ in the source list). The method that builds the member list of course
+ uses "memberDevices" to build the list.
- ########################################
- # Actions defined in MenuItems.xml:
- ####################
- def timeWarp(self):
- if not self.timeWarpOn:
- indigo.server.log(u"starting mega time warp")
- self.timeWarpOn = True
- else:
- indigo.server.log(u"stopping mega time warp")
- self.timeWarpOn = False
+ One other thing that should be done probably - in the deviceStartComm
+ method (or the appropriate CRUD methods if you're using them instead)
+ you should check the IDs to make sure they're still around and if not
+ remove them from the device id list.
- ########################################
- # Buttons and dynamic list methods defined for the scenes custom device
- #
- # Overview of scene devices:
- # Scene devices are custom devices that will contain multiple devices.
- # We implement this custom device by storing a comma-delimited list of
- # device IDs which is manipulated by clicking Add and Delete buttons
- # in the device config dialog. There are two dynamic list controls in
- # the dialog:
- # 1) one popup button control on which the user selects a device
- # to add then clicks the Add Device button.
- # 2) one list control which shows all the devices that have already
- # been added to the scene and in which the user can select devices
- # and click the Delete Devices button
- # There is a hidden field "memberDevices" that stores a comma-delimited
- # list of device ids for each member of the scene. The addDevice and
- # deleteDevices methods will take the selections from the respective
- # dynamic lists and do the right thing with the list.
- # Finally, there are the two methods that build the dynamic lists.
- # The method that builds the source list will inspect the "memberDevices"
- # field and won't include those devices in the source list (so the user
- # won't be confused by seeing a device that's already in the member list
- # in the source list). The method that builds the member list of course
- # uses "memberDevices" to build the list.
- #
- # One other thing that should be done probably - in the deviceStartComm
- # method (or the appropriate CRUD methods if you're using them instead)
- # you should check the IDs to make sure they're still around and if not
- # remove them from the device id list.
- #
- # The device id list property ("memberDevices") could, of course, be
- # formatted in some other way besides a comma-delimited list of ids
- # if you need to store more information. You could, for instance, store
- # some kind of formatted text like JSON or XML that had much more
- # information.
+ The device id list property ("memberDevices") could, of course, be
+ formatted in some other way besides a comma-delimited list of ids
+ if you need to store more information. You could, for instance, store
+ some kind of formatted text like JSON or XML that had much more
+ information.
+ """
- ####################
- # This is the method that's called by the Add Device button in the scene
- # device config UI.
- ####################
- def addDevice(self, valuesDict, typeId, devId):
- self.debugLog(u"addDevice called")
- # just making sure that they have selected a device in the source
- # list - it shouldn't be possible not to but it's safer
- if "sourceDeviceMenu" in valuesDict:
- # Get the device ID of the selected device
- deviceId = valuesDict["sourceDeviceMenu"]
- if deviceId == "":
- return
- # Get the list of devices that have already been added to the "scene"
- # If the key doesn't exist then return an empty string indicating
- # no devices have yet been added. "memberDevices" is a hidden text
- # field in the dialog that holds a comma-delimited list of device
- # ids, one for each of the devices in the scene.
- selectedDevicesString = valuesDict.get("memberDevices","")
- self.debugLog(u"adding device: %s to %s" % (deviceId, selectedDevicesString))
- # If no devices have been added then just set the selected device string to
- # the device id of the device they selected in the popup
- if selectedDevicesString == "":
- selectedDevicesString = deviceId
- # Otherwise append it to the end separated by a comma
- else:
- selectedDevicesString += "," + str(deviceId)
- # Set the device string back to the hidden text field that contains the
- # list of device ids that are in the scene
- valuesDict["memberDevices"] = selectedDevicesString
- self.debugLog(u"valuesDict = " + str(valuesDict))
- # Delete the selections on both dynamic lists since we don't
- # want to preserve those across dialog runs
- if "memberDeviceList" in valuesDict:
- del valuesDict["memberDeviceList"]
- if "sourceDeviceMenu" in valuesDict:
- del valuesDict["sourceDeviceMenu"]
- # return the new dict
- return valuesDict
+ ####################
+ # This is the method that's called by the Add Device button in the scene
+ # device config UI.
+ ####################
+ def add_device(self, values_dict, type_id, dev_id):
+ self.logger.debug("add_device called")
+ # just making sure that they have selected a device in the source
+ # list - it shouldn't be possible not to but it's safer
+ if "sourceDeviceMenu" in values_dict:
+ # Get the device ID of the selected device
+ device_id = values_dict["sourceDeviceMenu"]
+ if device_id == "":
+ return None
+ # Get the list of devices that have already been added to the "scene"
+ # If the key doesn't exist then return an empty string indicating
+ # no devices have yet been added. "memberDevices" is a hidden text
+ # field in the dialog that holds a comma-delimited list of device
+ # ids, one for each of the devices in the scene.
+ dev_list_str = values_dict.get("memberDevices", "")
+ self.logger.debug(f"adding device: {device_id} to {dev_list_str}")
+ # If no devices have been added then just set the selected device string to
+ # the device id of the device they selected in the popup
+ if dev_list_str == "":
+ dev_list_str = device_id
+ # Otherwise append it to the end separated by a comma
+ else:
+ dev_list_str += f",{device_id}"
+ # Set the device string back to the hidden text field that contains the
+ # list of device ids that are in the scene
+ values_dict["memberDevices"] = dev_list_str
+ self.logger.debug(f"values_dict: {values_dict}")
+ # Delete the selections on both dynamic lists since we don't
+ # want to preserve those across dialog runs
+ if "memberDeviceList" in values_dict:
+ del values_dict["memberDeviceList"]
+ if "sourceDeviceMenu" in values_dict:
+ del values_dict["sourceDeviceMenu"]
+ # return the new dict
+ return values_dict
- ####################
- # This is the method that's called by the Delete Device button in the scene
- # device config UI.
- ####################
- def deleteDevices(self, valuesDict, typeId, devId):
- self.debugLog(u"deleteDevices called")
- if "memberDevices" in valuesDict:
- # Get the list of devices that are already in the scene
- devicesInScene = valuesDict.get("memberDevices","").split(",")
- # Get the devices they've selected in the list that they want
- # to remove
- selectedDevices = valuesDict.get("memberDeviceList", [])
- # Loop through the devices to be deleted list and remove them
- for deviceId in selectedDevices:
- self.debugLog(u"remove deviceId: " + deviceId)
- if deviceId in devicesInScene:
- devicesInScene.remove(deviceId)
- # Set the "memberDevices" field back to the new list which
- # has the devices deleted from it.
- valuesDict["memberDevices"] = ",".join(devicesInScene)
- # Delete the selections on both dynamic lists since we don't
- # want to preserve those across dialog runs
- if "memberDeviceList" in valuesDict:
- del valuesDict["memberDeviceList"]
- if "sourceDeviceMenu" in valuesDict:
- del valuesDict["sourceDeviceMenu"]
- return valuesDict
+ ####################
+ # This is the method that's called by the Delete Device button in the scene
+ # device config UI.
+ ####################
+ def delete_devices(self, values_dict, type_id, dev_id):
+ self.logger.debug("delete_devices called")
+ if "memberDevices" in values_dict:
+ # Get the list of devices that are already in the scene
+ devs_in_scene = []
+ dev_list_str = values_dict.get("memberDevices", "")
+ if dev_list_str:
+ devs_in_scene = dev_list_str.split(",")
+ # Get the devices they've selected in the list that they want
+ # to remove
+ sel_devs = values_dict.get("memberDeviceList", [])
+ # Loop through the devices to be deleted list and remove them
+ for device_id in sel_devs:
+ self.logger.debug(f"remove device_id: {device_id}")
+ if device_id in devs_in_scene:
+ devs_in_scene.remove(device_id)
+ # Set the "memberDevices" field back to the new list which
+ # has the devices deleted from it.
+ values_dict["memberDevices"] = ",".join(devs_in_scene)
+ # Delete the selections on both dynamic lists since we don't
+ # want to preserve those across dialog runs
+ if "memberDeviceList" in values_dict:
+ del values_dict["memberDeviceList"]
+ if "sourceDeviceMenu" in values_dict:
+ del values_dict["sourceDeviceMenu"]
+ return values_dict
- ####################
- # This is the method that's called to build the source device list. Note
- # that valuesDict is read-only so any changes you make to it will be discarded.
- ####################
- def sourceDevices(self, filter="", valuesDict=None, typeId="", targetId=0):
- self.debugLog(u"sourceDevices called with filter: %s typeId: %s targetId: %s" % (filter, typeId, str(targetId)))
- returnList = list()
- # if valuesDict doesn't exist yet - if this is a brand new device
- # then we just create an empty dict so the rest of the logic will
- # work correctly. Many other ways to skin that particular cat.
- if not valuesDict:
- valuesDict = {}
- # Get the member device id list, loop over all devices, and if the device
- # id isn't in the member list then include it in the source list.
- deviceList = valuesDict.get("memberDevices","").split(",")
- for devId in indigo.devices.iterkeys():
- if str(devId) not in deviceList:
- returnList.append((str(devId),indigo.devices.get(devId).name))
- return returnList
+ ####################
+ # This is the method that's called to build the source device list. Note
+ # that values_dict is read-only so any changes you make to it will be discarded.
+ ####################
+ def source_devices(self, filter_str="", values_dict=None, type_id="", target_id=0):
+ self.logger.debug(f"source_devices called with filter: {filter_str} type_id: {type_id} target_id: {target_id}")
+ return_list = []
+ # if values_dict doesn't exist yet - if this is a brand new device
+ # then we just create an empty dict so the rest of the logic will
+ # work correctly. Many other ways to skin that particular cat.
+ if not values_dict:
+ values_dict = {}
+ # Get the member device id list, loop over all devices, and if the device
+ # id isn't in the member list then include it in the source list.
+ device_list = []
+ dev_list_str = values_dict.get("memberDevices", "")
+ if dev_list_str:
+ device_list = dev_list_str.split(",")
+ for dev_id in indigo.devices.keys():
+ if str(dev_id) not in device_list:
+ return_list.append((str(dev_id), indigo.devices.get(dev_id).name))
+ return return_list
- ####################
- # This is the method that's called to build the member device list. Note
- # that valuesDict is read-only so any changes you make to it will be discarded.
- ####################
- def memberDevices(self, filter="", valuesDict=None, typeId="", targetId=0):
- self.debugLog(u"memberDevices called with filter: %s typeId: %s targetId: %s" % (filter, typeId, str(targetId)))
- returnList = list()
- # valuesDict may be empty or None if it's a brand new device
- if valuesDict and "memberDevices" in valuesDict:
- # Get the list of devices
- deviceListString = valuesDict["memberDevices"]
- self.debugLog(u"memberDeviceString: " + deviceListString)
- deviceList = deviceListString.split(",")
- # Iterate over the list and if the device exists (it could have been
- # deleted) then add it to the list.
- for devId in deviceList:
- if int(devId) in indigo.devices:
- returnList.append((devId, indigo.devices[int(devId)].name))
- return returnList
+ ####################
+ # This is the method that's called to build the member device list. Note
+ # that values_dict is read-only so any changes you make to it will be discarded.
+ ####################
+ def member_devices(self, filter_str="", values_dict=None, type_id="", target_id=0):
+ self.logger.debug(f"member_devices called with filter: {filter_str} type_id: {type_id} target_id: {target_id}")
+ return_list = []
+ # values_dict may be empty or None if it's a brand new device
+ if values_dict and "memberDevices" in values_dict:
+ # Get the list of devices
+ dev_list_str = values_dict["memberDevices"]
+ self.logger.debug(f"memberDeviceString: {dev_list_str}")
+ if dev_list_str:
+ device_list = dev_list_str.split(",")
+ # Iterate over the list and if the device exists (it could have been
+ # deleted) then add it to the list.
+ for dev_id in device_list:
+ if int(dev_id) in indigo.devices:
+ return_list.append((dev_id, indigo.devices[int(dev_id)].name))
+ return return_list
- ########################################
- def validateDeviceConfigUi(self, valuesDict, typeId, devId):
- # If the typeId is "scene", we want to clear the selections on both
- # dynamic lists so that they're not stored since we really don't
- # care about those.
- self.debugLog(u"validateDeviceConfigUi: typeId: %s devId: %s" % (typeId, str(devId)))
- if typeId == "scene":
- if "memberDeviceList" in valuesDict:
- valuesDict["memberDeviceList"] = ""
- if "sourceDeviceMenu" in valuesDict:
- valuesDict["sourceDeviceMenu"] = ""
- return (True, valuesDict)
+ ########################################
+ def validateDeviceConfigUi(self, values_dict, type_id, dev_id):
+ # If the type_id is "scene", we want to clear the selections on both
+ # dynamic lists so that they're not stored since we really don't
+ # care about those.
+ self.logger.debug(f"validateDeviceConfigUi: type_id: {type_id} dev_id: {dev_id}")
+ if type_id == "scene":
+ if "memberDeviceList" in values_dict:
+ values_dict["memberDeviceList"] = ""
+ if "sourceDeviceMenu" in values_dict:
+ values_dict["sourceDeviceMenu"] = ""
+ return (True, values_dict)
- ########################################
- # Plugin Actions object callbacks (pluginAction is an Indigo plugin action instance)
- ######################
- def resetHardware(self, pluginAction):
- self.debugLog(u"resetHardware action called:\n" + str(pluginAction))
+ ########################################
+ # Plugin Actions object callbacks (action is an Indigo plugin action instance)
+ ######################
+ def reset_hardware(self, action):
+ self.logger.debug(f"reset_hardware action called:\n {action}")
- def updateHardwareFirmware(self, pluginAction):
- self.debugLog(u"updateHardwareFirmware action called:\n" + str(pluginAction))
+ def update_hardware_firmware(self, action):
+ self.logger.debug(f"update_hardware_firmware action called:\n {action}")
diff --git a/Example Device - Energy Meter.indigoPlugin/Contents/Info.plist b/Example Device - Energy Meter.indigoPlugin/Contents/Info.plist
index 3d601d3..09c441b 100644
--- a/Example Device - Energy Meter.indigoPlugin/Contents/Info.plist
+++ b/Example Device - Energy Meter.indigoPlugin/Contents/Info.plist
@@ -2,24 +2,24 @@
- PluginVersion
- 2022.1.0
- ServerApiVersion
- 3.0
- IwsApiVersion
- 1.0.0
- CFBundleDisplayName
- Example Device - Energy Meter
- CFBundleIdentifier
- com.perceptiveautomation.indigoplugin.example-device-energymeter
- CFBundleVersion
- 1.0.0
- CFBundleURLTypes
-
-
- CFBundleURLName
- https://wiki.indigodomo.com/doku.php?id=plugins:example_dev_energymeter_1
-
-
+ PluginVersion
+ 2022.1.0
+ ServerApiVersion
+ 3.0
+ IwsApiVersion
+ 1.0.0
+ CFBundleDisplayName
+ Example Device - Energy Meter
+ CFBundleIdentifier
+ com.perceptiveautomation.indigoplugin.example-device-energymeter
+ CFBundleVersion
+ 1.0.0
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ https://wiki.indigodomo.com/doku.php?id=plugins:example_dev_energymeter_1
+
+
diff --git a/Example Device - Energy Meter.indigoPlugin/Contents/Server Plugin/Actions.xml b/Example Device - Energy Meter.indigoPlugin/Contents/Server Plugin/Actions.xml
index 0e044e2..4bdbf87 100644
--- a/Example Device - Energy Meter.indigoPlugin/Contents/Server Plugin/Actions.xml
+++ b/Example Device - Energy Meter.indigoPlugin/Contents/Server Plugin/Actions.xml
@@ -1,25 +1,25 @@
-
- Set Backlight Brightness
- set_backlight_brightness
-
-
-
-
-
-
-
-
-
+
+ Set Backlight Brightness
+ set_backlight_brightness
+
+
+
+
+
+
+
+
+
diff --git a/Example Device - Energy Meter.indigoPlugin/Contents/Server Plugin/Devices.xml b/Example Device - Energy Meter.indigoPlugin/Contents/Server Plugin/Devices.xml
index 922f724..c0ded95 100644
--- a/Example Device - Energy Meter.indigoPlugin/Contents/Server Plugin/Devices.xml
+++ b/Example Device - Energy Meter.indigoPlugin/Contents/Server Plugin/Devices.xml
@@ -1,73 +1,73 @@
-
-
- Example Energy Meter
-
-
-
-
-
+
+
+ Example Energy Meter
+
+
+
+
+
-
-
+
+
-
-
- Show current power load (Watts) in UI
-
-
-
-
-
- Integer
- Backlight Brightness
- Backlight Brightness
-
-
-
+ accumEnergyTotal (kWh)
+ curEnergyLevel (W) - only exists SupportsPowerMeter is True
+
+ The plugin can specify additional custom states and custom
+ actions (in Actions.xml) to modify custom states. As an example
+ here, we define a new custom state, backlightBrightness, which
+ is used to control the brightness of the backlit display of
+ the module.
+ -->
+
+ Integer
+ Backlight Brightness
+ Backlight Brightness
+
+
+
diff --git a/Example Device - Energy Meter.indigoPlugin/Contents/Server Plugin/plugin.py b/Example Device - Energy Meter.indigoPlugin/Contents/Server Plugin/plugin.py
index a4f5ff4..aa4593f 100644
--- a/Example Device - Energy Meter.indigoPlugin/Contents/Server Plugin/plugin.py
+++ b/Example Device - Energy Meter.indigoPlugin/Contents/Server Plugin/plugin.py
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
####################
# Copyright (c) 2022, Perceptive Automation, LLC. All rights reserved.
-# http://www.indigodomo.com
+# https://www.indigodomo.com
import random
@@ -12,125 +12,122 @@
################################################################################
class Plugin(indigo.PluginBase):
- ########################################
- def __init__(self, plugin_id, plugin_display_name, plugin_version, plugin_prefs):
- super(Plugin, self).__init__(plugin_id, plugin_display_name, plugin_version, plugin_prefs)
- self.debug = True
+ ########################################
+ def __init__(self, plugin_id, plugin_display_name, plugin_version, plugin_prefs):
+ super().__init__(plugin_id, plugin_display_name, plugin_version, plugin_prefs)
+ self.debug = True
- ########################################
- def startup(self):
- self.logger.debug("startup called")
+ ########################################
+ def startup(self):
+ self.logger.debug("startup called")
- def shutdown(self):
- self.logger.debug("shutdown called")
+ def shutdown(self):
+ self.logger.debug("shutdown called")
- ########################################
- # Poll all of the states from the energy meter and pass new values to
- # Indigo Server.
- def _refresh_states_from_hardware(self, dev, log_refresh):
- # As an example here we update the current power (Watts) to a random
- # value, and we increase the kWh by a smidge.
- #
- # Note the states are automatically created based on the SupportsEnergyMeter
- # and SupportsPowerMeter device properties.
- #
- # The plugin instance property is updated by updating the states.
- key_value_list = list()
- if "curEnergyLevel" in dev.states:
- simulate_watts = random.randint(0, 500)
- simulate_watts_str = f"{simulate_watts} W"
- if log_refresh:
- self.logger.info(f'received "{dev.name}" power load to {simulate_watts_str}')
- key_value_list.append({'key': 'curEnergyLevel', 'value': simulate_watts, 'uiValue': simulate_watts_str})
- if "accumEnergyTotal" in dev.states:
- simulate_kwh = dev.states.get("accumEnergyTotal", 0) + 0.001
- simulate_kwh_str = f"{simulate_kwh:.3f} kWh"
- if log_refresh:
- self.logger.info(f'received "{dev.name}" energy total to {simulate_kwh_str}')
- key_value_list.append({'key': 'accumEnergyTotal', 'value': simulate_kwh, 'uiValue': simulate_kwh_str})
- dev.updateStatesOnServer(key_value_list)
+ ########################################
+ # Poll all of the states from the energy meter and pass new values to
+ # Indigo Server.
+ def _refresh_states_from_hardware(self, dev, log_refresh):
+ # As an example here we update the current power (Watts) to a random
+ # value, and we increase the kWh by a smidge.
+ #
+ # Note the states are automatically created based on the SupportsEnergyMeter
+ # and SupportsPowerMeter device properties.
+ #
+ # The plugin instance property is updated by updating the states.
+ key_value_list = []
+ if "curEnergyLevel" in dev.states:
+ simulate_watts = random.randint(0, 500)
+ simulate_watts_str = f"{simulate_watts} W"
+ if log_refresh:
+ self.logger.info(f'received "{dev.name}" power load to {simulate_watts_str}')
+ key_value_list.append({'key': 'curEnergyLevel', 'value': simulate_watts, 'uiValue': simulate_watts_str})
+ if "accumEnergyTotal" in dev.states:
+ simulate_kwh = dev.states.get("accumEnergyTotal", 0) + 0.001
+ simulate_kwh_str = f"{simulate_kwh:.3f} kWh"
+ if log_refresh:
+ self.logger.info(f'received "{dev.name}" energy total to {simulate_kwh_str}')
+ key_value_list.append({'key': 'accumEnergyTotal', 'value': simulate_kwh, 'uiValue': simulate_kwh_str})
+ dev.updateStatesOnServer(key_value_list)
- ########################################
- def runConcurrentThread(self):
- try:
- while True:
- for dev in indigo.devices.iter("self"):
- if not dev.enabled or not dev.configured:
- continue
- # Plugins that need to poll out the status from the meter
- # could do so here, then broadcast back the new values to the
- # Indigo Server.
- self._refresh_states_from_hardware(dev, False)
- self.sleep(2)
- except self.StopThread:
- pass # Optionally catch the StopThread exception and do any needed cleanup.
+ ########################################
+ def runConcurrentThread(self):
+ try:
+ while True:
+ for dev in indigo.devices.iter("self"):
+ if not dev.enabled or not dev.configured:
+ continue
+ # Plugins that need to poll out the status from the meter
+ # could do so here, then broadcast back the new values to the
+ # Indigo Server.
+ self._refresh_states_from_hardware(dev, False)
+ self.sleep(2)
+ except self.StopThread:
+ pass # Optionally catch the StopThread exception and do any needed cleanup.
- ########################################
- def validateDeviceConfigUi(self, values_dict, type_id, dev_id):
- return (True, values_dict)
+ ########################################
+ def validateDeviceConfigUi(self, values_dict, type_id, dev_id):
+ return (True, values_dict)
- ########################################
- def deviceStartComm(self, dev):
- # Called when communication with the hardware should be established.
- # Here would be a good place to poll out the current states from the
- # meter. If periodic polling of the meter is needed (that is, it
- # doesn't broadcast changes back to the plugin somehow), then consider
- # adding that to runConcurrentThread() above.
- self._refresh_states_from_hardware(dev, True)
+ ########################################
+ def deviceStartComm(self, dev):
+ # Called when communication with the hardware should be established.
+ # Here would be a good place to poll out the current states from the
+ # meter. If periodic polling of the meter is needed (that is, it
+ # doesn't broadcast changes back to the plugin somehow), then consider
+ # adding that to runConcurrentThread() above.
+ self._refresh_states_from_hardware(dev, True)
- def deviceStopComm(self, dev):
- # Called when communication with the hardware should be shutdown.
- pass
+ def deviceStopComm(self, dev):
+ # Called when communication with the hardware should be shutdown.
+ pass
- ########################################
- # General Action callback
- ######################
- def actionControlUniversal(self, action, dev):
- ###### BEEP ######
- if action.deviceAction == indigo.kUniversalAction.Beep:
- # Beep the hardware module (dev) here:
- # FIXME: add implementation here
- self.logger.info(f"sent '{dev.name}' beep request")
- ###### ENERGY UPDATE ######
- elif action.deviceAction == indigo.kUniversalAction.EnergyUpdate:
- # Request hardware module (dev) for its most recent meter data here:
- # FIXME: add implementation here
- self._refresh_states_from_hardware(dev, True)
- ###### ENERGY RESET ######
- elif action.deviceAction == indigo.kUniversalAction.EnergyReset:
- # Request that the hardware module (dev) reset its accumulative energy usage data here:
- # FIXME: add implementation here
- self.logger.info(f"sent '{dev.name}' energy usage reset")
- # And then tell Indigo to reset it by just setting the value to 0.
- # This will automatically reset Indigo's time stamp for the accumulation.
- dev.updateStateOnServer("accumEnergyTotal", 0.0)
- ###### STATUS REQUEST ######
- elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
- # Query hardware module (dev) for its current status here:
- # FIXME: add implementation here
- self._refresh_states_from_hardware(dev, True)
+ ########################################
+ # General Action callback
+ ######################
+ def actionControlUniversal(self, action, dev):
+ ###### BEEP ######
+ if action.deviceAction == indigo.kUniversalAction.Beep:
+ # Beep the hardware module (dev) here:
+ # FIXME: add implementation here
+ self.logger.info(f"sent '{dev.name}' beep request")
+ ###### ENERGY UPDATE ######
+ elif action.deviceAction == indigo.kUniversalAction.EnergyUpdate:
+ # Request hardware module (dev) for its most recent meter data here:
+ # FIXME: add implementation here
+ self._refresh_states_from_hardware(dev, True)
+ ###### ENERGY RESET ######
+ elif action.deviceAction == indigo.kUniversalAction.EnergyReset:
+ # Request that the hardware module (dev) reset its accumulative energy usage data here:
+ # FIXME: add implementation here
+ self.logger.info(f"sent '{dev.name}' energy usage reset")
+ # And then tell Indigo to reset it by just setting the value to 0.
+ # This will automatically reset Indigo's time stamp for the accumulation.
+ dev.updateStateOnServer("accumEnergyTotal", 0.0)
+ ###### STATUS REQUEST ######
+ elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
+ # Query hardware module (dev) for its current status here:
+ # FIXME: add implementation here
+ self._refresh_states_from_hardware(dev, True)
- ########################################
- # Custom Plugin Action callbacks (defined in Actions.xml)
- ######################
- def set_backlight_brightness(self, action, dev):
- try:
- new_brightness = int(action.props.get("brightness", 100))
- except ValueError:
- # The int() cast above might fail if the user didn't enter a number:
- self.logger.info(
- f"set backlight brightness action to device '{dev.name}' -- invalid brightness value",
- isError=True
- )
- return
- # Command hardware module (dev) to set backlight brightness here:
- # FIXME: add implementation here
- send_success = True # Set to False if it failed.
- if send_success:
- # If success then log that the command was successfully sent.
- self.logger.info(f"sent '{dev.name}' set backlight brightness to {new_brightness}")
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("backlightBrightness", new_brightness)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- self.logger.info(f"send '{dev.name}' set backlight brightness to {new_brightness} failed", isError=True)
+ ########################################
+ # Custom Plugin Action callbacks (defined in Actions.xml)
+ ######################
+ def set_backlight_brightness(self, plugin_action, dev):
+ try:
+ new_brightness = int(plugin_action.props.get("brightness", 100))
+ except ValueError:
+ # The int() cast above might fail if the user didn't enter a number:
+ self.logger.error(f"set backlight brightness action to device \"{dev.name}\" -- invalid brightness value")
+ return
+ # Command hardware module (dev) to set backlight brightness here:
+ # FIXME: add implementation here
+ send_success = True # Set to False if it failed.
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" set backlight brightness to {new_brightness}")
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("backlightBrightness", new_brightness)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" set backlight brightness to {new_brightness} failed")
diff --git a/Example Device - Factory.indigoPlugin/Contents/Info.plist b/Example Device - Factory.indigoPlugin/Contents/Info.plist
index 566b482..67a3805 100644
--- a/Example Device - Factory.indigoPlugin/Contents/Info.plist
+++ b/Example Device - Factory.indigoPlugin/Contents/Info.plist
@@ -2,24 +2,24 @@
- PluginVersion
- 2021.1.0
- ServerApiVersion
- 2.5
- IwsApiVersion
- 1.0.0
- CFBundleDisplayName
- Example Device - Factory
- CFBundleIdentifier
- com.perceptiveautomation.indigoplugin.example-device-factory1
- CFBundleVersion
- 1.0.0
- CFBundleURLTypes
-
-
- CFBundleURLName
- http://wiki.indigodomo.com/doku.php?id=plugins:example_dev_factory1
-
-
+ PluginVersion
+ 2022.1.0
+ ServerApiVersion
+ 3.0
+ IwsApiVersion
+ 1.0.0
+ CFBundleDisplayName
+ Example Device - Factory
+ CFBundleIdentifier
+ com.perceptiveautomation.indigoplugin.example-device-factory1
+ CFBundleVersion
+ 1.0.0
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ https://wiki.indigodomo.com/doku.php?id=plugins:example_dev_factory1
+
+
diff --git a/Example Device - Factory.indigoPlugin/Contents/Server Plugin/Actions.xml b/Example Device - Factory.indigoPlugin/Contents/Server Plugin/Actions.xml
index 5939fe1..098ebf7 100644
--- a/Example Device - Factory.indigoPlugin/Contents/Server Plugin/Actions.xml
+++ b/Example Device - Factory.indigoPlugin/Contents/Server Plugin/Actions.xml
@@ -1,24 +1,24 @@
-
- Set Backlight Brightness
- setBacklightBrightness
-
-
-
-
-
-
-
-
-
+
+ Set Backlight Brightness
+ set_backlight_brightness
+
+
+
+
+
+
+
+
+
diff --git a/Example Device - Factory.indigoPlugin/Contents/Server Plugin/Devices.xml b/Example Device - Factory.indigoPlugin/Contents/Server Plugin/Devices.xml
index 3c2580a..fdfd494 100644
--- a/Example Device - Factory.indigoPlugin/Contents/Server Plugin/Devices.xml
+++ b/Example Device - Factory.indigoPlugin/Contents/Server Plugin/Devices.xml
@@ -1,141 +1,141 @@
-
-
- Define Device Group...
- Close
-
-
-
-
-
+
+
+ Define Device Group...
+ Close
+
+
+
+
+
-
+
-
- Add Plugin Relay
- _addRelay
-
-
- Add Plugin Dimmer
- _addDimmer
-
+
+ Add Plugin Relay
+ _add_relay
+
+
+ Add Plugin Dimmer
+ _add_dimmer
+
-
+
-
- Remove All Relay Devices
- _removeRelayDevices
-
-
- Remove All Dimmer Devices
- _removeDimmerDevices
-
-
- Remove All Devices
- _removeAllDevices
-
+
+ Remove All Relay Devices
+ _remove_relay_devices
+
+
+ Remove All Dimmer Devices
+ _remove_dimmer_devices
+
+
+ Remove All Devices
+ _remove_all_devices
+
-
-
-
- Relay
-
-
-
-
-
-
-
-
-
- Integer
- Backlight Brightness
- Backlight Brightness
-
-
-
+
+
+
+ Relay
+
+
+
+
+
+
+
+
+
+ Integer
+ Backlight Brightness
+ Backlight Brightness
+
+
+
-
-
- Dimmer
-
-
-
-
-
-
-
-
-
- Integer
- Backlight Brightness
- Backlight Brightness
-
-
-
+
+
+ Dimmer
+
+
+
+
+
+
+
+
+
+ Integer
+ Backlight Brightness
+ Backlight Brightness
+
+
+
diff --git a/Example Device - Factory.indigoPlugin/Contents/Server Plugin/plugin.py b/Example Device - Factory.indigoPlugin/Contents/Server Plugin/plugin.py
index f71c102..8660de9 100644
--- a/Example Device - Factory.indigoPlugin/Contents/Server Plugin/plugin.py
+++ b/Example Device - Factory.indigoPlugin/Contents/Server Plugin/plugin.py
@@ -1,8 +1,8 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
####################
-# Copyright (c) 2014, Perceptive Automation, LLC. All rights reserved.
-# http://www.indigodomo.com
+# Copyright (c) 2022, Perceptive Automation, LLC. All rights reserved.
+# https://www.indigodomo.com
import indigo
@@ -14,283 +14,275 @@
################################################################################
class Plugin(indigo.PluginBase):
- ########################################
- def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs):
- super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs)
- self.debug = True
-
- ########################################
- def startup(self):
- self.debugLog(u"startup called")
-
- def shutdown(self):
- self.debugLog(u"shutdown called")
-
- ########################################
- # DeviceFactory methods (specified in Devices.xml):
- #
- # All device factory methods are passed a devIdList argument, which is
- # a list of device IDs in the current group being edited. Plugins add
- # and remove devices to/from the group by making indigo.device.create()
- # and indigo.device.delete(). On subsequent factory method calls the
- # devIdList will automatically be updated to reflect any changes.
- #
- # Plugins should set the main model type using dev.model, and the sub-
- # type using dev.subType, which is used for the tabbed UI. Be sure
- # and call dev.replaceOnServer() after modifying the .model and .subType
- # attributes to push those changes to the server.
- ####################
- def getDeviceFactoryUiValues(self, devIdList):
- valuesDict = indigo.Dict()
- errorMsgDict = indigo.Dict()
- return (valuesDict, errorMsgDict)
-
- def validateDeviceFactoryUi(self, valuesDict, devIdList):
- errorsDict = indigo.Dict()
- return (True, valuesDict, errorsDict)
-
- def closedDeviceFactoryUi(self, valuesDict, userCancelled, devIdList):
- return
-
- ####################
- def _getDeviceGroupList(self, filter, valuesDict, devIdList):
- menuItems = []
- for devId in devIdList:
- if devId in indigo.devices:
- dev = indigo.devices[devId]
- devName = dev.name
- else:
- devName = u"- device not found -"
- menuItems.append((devId, devName))
- return menuItems
-
- def _addRelay(self, valuesDict, devIdList):
- newdev = indigo.device.create(indigo.kProtocol.Plugin, deviceTypeId="myRelayType")
- newdev.model = "Example Multi-Device"
- newdev.subType = "Relay" # Manually need to set the model and subType names (for UI only)
- newdev.replaceOnServer()
- return valuesDict
-
- def _addDimmer(self, valuesDict, devIdList):
- newdev = indigo.device.create(indigo.kProtocol.Plugin, deviceTypeId="myDimmerType")
- newdev.model = "Example Multi-Device"
- newdev.subType = "Dimmer" # Manually need to set the model and subType names (for UI only)
- newdev.replaceOnServer()
- return valuesDict
-
- def _addX10MotionSensor(self, valuesDict, devIdList):
- # Not fully supported -- device groups currently should only contain
- # devices defined by the plugin. The UI doesn't properly handle showing
- # and editing X10 / INSTEON / etc. devices as part of the group.
- #
- # newdev = indigo.device.create(indigo.kProtocol.X10, deviceTypeId="Motion Detector")
- # newdev.model = "Example Multi-Device"
- # newdev.subType = "Motion" # Manually need to set the model and subType names (for UI only)
- # newdev.replaceOnServer()
- return valuesDict
-
- def _addX10SprinklerDevice(self, valuesDict, devIdList):
- # Not fully supported -- device groups currently should only contain
- # devices defined by the plugin. The UI doesn't properly handle showing
- # and editing X10 / INSTEON / etc. devices as part of the group.
- #
- # newdev = indigo.device.create(indigo.kProtocol.X10, deviceTypeId="Rain8 (8 zone)")
- # newdev.model = "Example Multi-Device"
- # newdev.subType = "Sprinkler" # Manually need to set the model and subType names (for UI only)
- # newdev.replaceOnServer()
- return valuesDict
-
- def _removeDimmerDevices(self, valuesDict, devIdList):
- for devId in devIdList:
- try:
- dev = indigo.devices[devId]
- if dev.deviceTypeId == "myDimmerType":
- indigo.device.delete(dev)
- except:
- pass # delete doesn't allow (throws) on root elem
- return valuesDict
-
- def _removeRelayDevices(self, valuesDict, devIdList):
- for devId in devIdList:
- try:
- dev = indigo.devices[devId]
- if dev.deviceTypeId == "myRelayType":
- indigo.device.delete(dev)
- except:
- pass # delete doesn't allow (throws) on root elem
- return valuesDict
-
- def _removeAllDevices(self, valuesDict, devIdList):
- for devId in devIdList:
- try:
- indigo.device.delete(devId)
- except:
- pass # delete doesn't allow (throws) on root elem
- return valuesDict
-
- ########################################
- def validateDeviceConfigUi(self, valuesDict, typeId, devId):
- return (True, valuesDict)
-
- ########################################
- # Relay / Dimmer Action callback
- ######################
- def actionControlDevice(self, action, dev):
- ###### TURN ON ######
- if action.deviceAction == indigo.kDeviceAction.TurnOn:
- # Command hardware module (dev) to turn ON here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "on"))
-
- # And then tell the Indigo Server to update the state.
- dev.updateStateOnServer("onOffState", True)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s failed" % (dev.name, "on"), isError=True)
-
- ###### TURN OFF ######
- elif action.deviceAction == indigo.kDeviceAction.TurnOff:
- # Command hardware module (dev) to turn OFF here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "off"))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("onOffState", False)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s failed" % (dev.name, "off"), isError=True)
-
- ###### TOGGLE ######
- elif action.deviceAction == indigo.kDeviceAction.Toggle:
- # Command hardware module (dev) to toggle here:
- # ** IMPLEMENT ME **
- newOnState = not dev.onState
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "toggle"))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("onOffState", newOnState)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s failed" % (dev.name, "toggle"), isError=True)
-
- ###### SET BRIGHTNESS ######
- elif action.deviceAction == indigo.kDeviceAction.SetBrightness:
- # Command hardware module (dev) to set brightness here:
- # ** IMPLEMENT ME **
- newBrightness = action.actionValue
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %d" % (dev.name, "set brightness", newBrightness))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("brightnessLevel", newBrightness)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %d failed" % (dev.name, "set brightness", newBrightness), isError=True)
-
- ###### BRIGHTEN BY ######
- elif action.deviceAction == indigo.kDeviceAction.BrightenBy:
- # Command hardware module (dev) to do a relative brighten here:
- # ** IMPLEMENT ME **
- newBrightness = dev.brightness + action.actionValue
- if newBrightness > 100:
- newBrightness = 100
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %d" % (dev.name, "brighten", newBrightness))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("brightnessLevel", newBrightness)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %d failed" % (dev.name, "brighten", newBrightness), isError=True)
-
- ###### DIM BY ######
- elif action.deviceAction == indigo.kDeviceAction.DimBy:
- # Command hardware module (dev) to do a relative dim here:
- # ** IMPLEMENT ME **
- newBrightness = dev.brightness - action.actionValue
- if newBrightness < 0:
- newBrightness = 0
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %d" % (dev.name, "dim", newBrightness))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("brightnessLevel", newBrightness)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %d failed" % (dev.name, "dim", newBrightness), isError=True)
-
-
- ########################################
- # General Action callback
- ######################
- def actionControlUniversal(self, action, dev):
- ###### BEEP ######
- if action.deviceAction == indigo.kUniversalAction.Beep:
- # Beep the hardware module (dev) here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "beep request"))
-
- ###### ENERGY UPDATE ######
- elif action.deviceAction == indigo.kUniversalAction.EnergyUpdate:
- # Request hardware module (dev) for its most recent meter data here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "energy update request"))
-
- ###### ENERGY RESET ######
- elif action.deviceAction == indigo.kUniversalAction.EnergyReset:
- # Request that the hardware module (dev) reset its accumulative energy usage data here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "energy reset request"))
-
- ###### STATUS REQUEST ######
- elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
- # Query hardware module (dev) for its current status here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "status request"))
-
- ########################################
- # Custom Plugin Action callbacks (defined in Actions.xml)
- ######################
- def setBacklightBrightness(self, pluginAction, dev):
- try:
- newBrightness = int(pluginAction.props.get(u"brightness", 100))
- except ValueError:
- # The int() cast above might fail if the user didn't enter a number:
- indigo.server.log(u"set backlight brightness action to device \"%s\" -- invalid brightness value" % (dev.name,), isError=True)
- return
-
- # Command hardware module (dev) to set backlight brightness here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %d" % (dev.name, "set backlight brightness", newBrightness))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("backlightBrightness", newBrightness)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %d failed" % (dev.name, "set backlight brightness", newBrightness), isError=True)
-
+ ########################################
+ def __init__(self, plugin_id, plugin_display_name, plugin_version, plugin_prefs):
+ super().__init__(plugin_id, plugin_display_name, plugin_version, plugin_prefs)
+ self.debug = True
+
+ ########################################
+ def startup(self):
+ self.logger.debug("startup called")
+
+ def shutdown(self):
+ self.logger.debug("shutdown called")
+
+ ########################################
+ # DeviceFactory methods (specified in Devices.xml):
+ #
+ # All device factory methods are passed a dev_id_list argument, which is
+ # a list of device IDs in the current group being edited. Plugins add
+ # and remove devices to/from the group by making indigo.device.create()
+ # and indigo.device.delete(). On subsequent factory method calls the
+ # dev_id_list will automatically be updated to reflect any changes.
+ #
+ # Plugins should set the main model type using dev.model, and the sub-
+ # type using dev.subType, which is used for the tabbed UI. Be sure
+ # and call dev.replaceOnServer() after modifying the .model and .subType
+ # attributes to push those changes to the server.
+ ####################
+ def getDeviceFactoryUiValues(self, dev_id_list):
+ values_dict = indigo.Dict()
+ error_msg_dict = indigo.Dict()
+ return (values_dict, error_msg_dict)
+
+ def validateDeviceFactoryUi(self, values_dict, dev_id_list):
+ errors_dict = indigo.Dict()
+ return (True, values_dict, errors_dict)
+
+ def closedDeviceFactoryUi(self, values_dict, user_cancelled, dev_id_list):
+ return
+
+ ####################
+ def _get_device_group_list(self, filter, values_dict, dev_id_list):
+ menu_items = []
+ for dev_id in dev_id_list:
+ if dev_id in indigo.devices:
+ dev = indigo.devices[dev_id]
+ dev_name = dev.name
+ else:
+ dev_name = "- device not found -"
+ menu_items.append((dev_id, dev_name))
+ return menu_items
+
+ def _add_relay(self, values_dict, dev_id_list):
+ newdev = indigo.device.create(indigo.kProtocol.Plugin, deviceTypeId="myRelayType")
+ newdev.model = "Example Multi-Device"
+ newdev.subType = "Relay" # Manually need to set the model and subType names (for UI only)
+ newdev.replaceOnServer()
+ return values_dict
+
+ def _add_dimmer(self, values_dict, dev_id_list):
+ newdev = indigo.device.create(indigo.kProtocol.Plugin, deviceTypeId="myDimmerType")
+ newdev.model = "Example Multi-Device"
+ newdev.subType = "Dimmer" # Manually need to set the model and subType names (for UI only)
+ newdev.replaceOnServer()
+ return values_dict
+
+ def _add_x10_motion_sensor(self, values_dict, dev_id_list):
+ # Not fully supported -- device groups currently should only contain
+ # devices defined by the plugin. The UI doesn't properly handle showing
+ # and editing X10 / INSTEON / etc. devices as part of the group.
+ #
+ # newdev = indigo.device.create(indigo.kProtocol.X10, deviceTypeId="Motion Detector")
+ # newdev.model = "Example Multi-Device"
+ # newdev.subType = "Motion" # Manually need to set the model and subType names (for UI only)
+ # newdev.replaceOnServer()
+ return values_dict
+
+ def _add_x10_sprinkler_device(self, values_dict, dev_id_list):
+ # Not fully supported -- device groups currently should only contain
+ # devices defined by the plugin. The UI doesn't properly handle showing
+ # and editing X10 / INSTEON / etc. devices as part of the group.
+ #
+ # newdev = indigo.device.create(indigo.kProtocol.X10, deviceTypeId="Rain8 (8 zone)")
+ # newdev.model = "Example Multi-Device"
+ # newdev.subType = "Sprinkler" # Manually need to set the model and subType names (for UI only)
+ # newdev.replaceOnServer()
+ return values_dict
+
+ def _remove_dimmer_devices(self, values_dict, dev_id_list):
+ for dev_id in dev_id_list:
+ try:
+ dev = indigo.devices[dev_id]
+ if dev.deviceTypeId == "myDimmerType":
+ indigo.device.delete(dev)
+ except:
+ pass # delete doesn't allow (throws) on root elem
+ return values_dict
+
+ def _remove_relay_devices(self, values_dict, dev_id_list):
+ for dev_id in dev_id_list:
+ try:
+ dev = indigo.devices[dev_id]
+ if dev.deviceTypeId == "myRelayType":
+ indigo.device.delete(dev)
+ except:
+ pass # delete doesn't allow (throws) on root elem
+ return values_dict
+
+ def _remove_all_devices(self, values_dict, dev_id_list):
+ for dev_id in dev_id_list:
+ try:
+ indigo.device.delete(dev_id)
+ except:
+ pass # delete doesn't allow (throws) on root elem
+ return values_dict
+
+ ########################################
+ def validateDeviceConfigUi(self, values_dict, type_id, dev_id):
+ return (True, values_dict)
+
+ ########################################
+ # Relay / Dimmer Action callback
+ ######################
+ def actionControlDevice(self, action, dev):
+ ###### TURN ON ######
+ if action.deviceAction == indigo.kDeviceAction.TurnOn:
+ # Command hardware module (dev) to turn ON here:
+ # ** IMPLEMENT ME **
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" on")
+
+ # And then tell the Indigo Server to update the state.
+ dev.updateStateOnServer("onOffState", True)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" on failed")
+
+ ###### TURN OFF ######
+ elif action.deviceAction == indigo.kDeviceAction.TurnOff:
+ # Command hardware module (dev) to turn OFF here:
+ # ** IMPLEMENT ME **
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" off")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("onOffState", False)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" off failed")
+
+ ###### TOGGLE ######
+ elif action.deviceAction == indigo.kDeviceAction.Toggle:
+ # Command hardware module (dev) to toggle here:
+ # ** IMPLEMENT ME **
+ new_on_state = not dev.onState
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" toggle")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("onOffState", new_on_state)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" toggle failed")
+
+ ###### SET BRIGHTNESS ######
+ elif action.deviceAction == indigo.kDeviceAction.SetBrightness:
+ # Command hardware module (dev) to set brightness here:
+ # ** IMPLEMENT ME **
+ new_brightness = action.actionValue
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" set brightness to {new_brightness}")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("brightnessLevel", new_brightness)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" set brightness to {new_brightness} failed")
+
+ ###### BRIGHTEN BY ######
+ elif action.deviceAction == indigo.kDeviceAction.BrightenBy:
+ # Command hardware module (dev) to do a relative brighten here:
+ # ** IMPLEMENT ME **
+ new_brightness = min(dev.brightness + action.actionValue, 100)
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" brighten to {new_brightness}")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("brightnessLevel", new_brightness)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" brighten to {new_brightness} failed")
+
+ ###### DIM BY ######
+ elif action.deviceAction == indigo.kDeviceAction.DimBy:
+ # Command hardware module (dev) to do a relative dim here:
+ # ** IMPLEMENT ME **
+ new_brightness = max(dev.brightness - action.actionValue, 0)
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" dim to {new_brightness}")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("brightnessLevel", new_brightness)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" dim to {new_brightness} failed")
+
+
+ ########################################
+ # General Action callback
+ ######################
+ def actionControlUniversal(self, action, dev):
+ ###### BEEP ######
+ if action.deviceAction == indigo.kUniversalAction.Beep:
+ # Beep the hardware module (dev) here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" beep request")
+
+ ###### ENERGY UPDATE ######
+ elif action.deviceAction == indigo.kUniversalAction.EnergyUpdate:
+ # Request hardware module (dev) for its most recent meter data here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" energy update request")
+
+ ###### ENERGY RESET ######
+ elif action.deviceAction == indigo.kUniversalAction.EnergyReset:
+ # Request that the hardware module (dev) reset its accumulative energy usage data here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" energy reset request")
+
+ ###### STATUS REQUEST ######
+ elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
+ # Query hardware module (dev) for its current status here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" status request")
+
+ ########################################
+ # Custom Plugin Action callbacks (defined in Actions.xml)
+ ######################
+ def set_backlight_brightness(self, plugin_action, dev):
+ try:
+ new_brightness = int(plugin_action.props.get("brightness", 100))
+ except ValueError:
+ # The int() cast above might fail if the user didn't enter a number:
+ self.logger.error(f"set backlight brightness action to device \"{dev.name}\" -- invalid brightness value")
+ return
+ # Command hardware module (dev) to set backlight brightness here:
+ # FIXME: add implementation here
+ send_success = True # Set to False if it failed.
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" set backlight brightness to {new_brightness}")
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("backlightBrightness", new_brightness)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" set backlight brightness to {new_brightness} failed")
diff --git a/Example Device - Relay and Dimmer.indigoPlugin/Contents/Info.plist b/Example Device - Relay and Dimmer.indigoPlugin/Contents/Info.plist
index e2d9fe9..fea8a89 100644
--- a/Example Device - Relay and Dimmer.indigoPlugin/Contents/Info.plist
+++ b/Example Device - Relay and Dimmer.indigoPlugin/Contents/Info.plist
@@ -2,24 +2,24 @@
- PluginVersion
- 2021.1.0
- ServerApiVersion
- 2.5
- IwsApiVersion
- 1.0.0
- CFBundleDisplayName
- Example Device - Relay/Dimmer
- CFBundleIdentifier
- com.perceptiveautomation.indigoplugin.example-device-relay1
- CFBundleVersion
- 1.0.0
- CFBundleURLTypes
-
-
- CFBundleURLName
- http://wiki.indigodomo.com/doku.php?id=plugins:example_dev_relay_1
-
-
+ PluginVersion
+ 2022.1.0
+ ServerApiVersion
+ 3.0
+ IwsApiVersion
+ 1.0.0
+ CFBundleDisplayName
+ Example Device - Relay/Dimmer
+ CFBundleIdentifier
+ com.perceptiveautomation.indigoplugin.example-device-relay1
+ CFBundleVersion
+ 1.0.0
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ https://wiki.indigodomo.com/doku.php?id=plugins:example_dev_relay_1
+
+
diff --git a/Example Device - Relay and Dimmer.indigoPlugin/Contents/Server Plugin/Actions.xml b/Example Device - Relay and Dimmer.indigoPlugin/Contents/Server Plugin/Actions.xml
index 5939fe1..098ebf7 100644
--- a/Example Device - Relay and Dimmer.indigoPlugin/Contents/Server Plugin/Actions.xml
+++ b/Example Device - Relay and Dimmer.indigoPlugin/Contents/Server Plugin/Actions.xml
@@ -1,24 +1,24 @@
-
- Set Backlight Brightness
- setBacklightBrightness
-
-
-
-
-
-
-
-
-
+
+ Set Backlight Brightness
+ set_backlight_brightness
+
+
+
+
+
+
+
+
+
diff --git a/Example Device - Relay and Dimmer.indigoPlugin/Contents/Server Plugin/Devices.xml b/Example Device - Relay and Dimmer.indigoPlugin/Contents/Server Plugin/Devices.xml
index 8b9ffc0..262e570 100644
--- a/Example Device - Relay and Dimmer.indigoPlugin/Contents/Server Plugin/Devices.xml
+++ b/Example Device - Relay and Dimmer.indigoPlugin/Contents/Server Plugin/Devices.xml
@@ -1,203 +1,203 @@
-
-
- Example Relay Module
-
-
-
-
-
-
-
-
-
- Integer
- Backlight Brightness
- Backlight Brightness
-
-
-
+
+
+ Example Relay Module
+
+
+
+
+
+
+
+
+
+ Integer
+ Backlight Brightness
+ Backlight Brightness
+
+
+
-
-
- Example Dimmer Module
-
-
-
-
-
-
-
-
-
- Integer
- Backlight Brightness
- Backlight Brightness
-
-
-
+
+
+ Example Dimmer Module
+
+
+
+
+
+
+
+
+
+ Integer
+ Backlight Brightness
+ Backlight Brightness
+
+
+
-
-
- Example Color Module
-
-
-
-
-
+
+
+ Example Color Module
+
+
+
+
+
-
-
-
-
- Shows RGB control and level fields in UI
-
-
-
-
- Shows White level fields in UI
-
-
-
- Shows Two White level fields in UI
-
-
-
-
-
-
- Shows White Temperature field in UI
-
-
-
- Minimum White Temperature used on UI controls
-
-
-
- Maximum White Temperature used on UI controls
-
+ Two white level fields (SupportsTwoWhiteLevels) is used by some hardware
+ to mix cool and warm white levels. Other hardware provides this capability
+ by using a white temperature value (SupportsWhiteTemperature). The two
+ techniques are mutually exlcusive, so choosing to enable two white levels
+ will override (and not show) the white temperature UI.
+ -->
+
+
+
+ Shows RGB control and level fields in UI
+
+
+
+
+ Shows White level fields in UI
+
+
+
+ Shows Two White level fields in UI
+
+
+
+
+
+
+ Shows White Temperature field in UI
+
+
+
+ Minimum White Temperature used on UI controls
+
+
+
+ Maximum White Temperature used on UI controls
+
-
-
+
+
-
-
- Example Lock Module
-
-
-
-
-
-
-
-
-
- Integer
- Backlight Brightness
- Backlight Brightness
-
-
-
+
+
+ Example Lock Module
+
+
+
+
+
+
+
+
+
+ Integer
+ Backlight Brightness
+ Backlight Brightness
+
+
+
diff --git a/Example Device - Relay and Dimmer.indigoPlugin/Contents/Server Plugin/plugin.py b/Example Device - Relay and Dimmer.indigoPlugin/Contents/Server Plugin/plugin.py
index 803674c..2499f8a 100644
--- a/Example Device - Relay and Dimmer.indigoPlugin/Contents/Server Plugin/plugin.py
+++ b/Example Device - Relay and Dimmer.indigoPlugin/Contents/Server Plugin/plugin.py
@@ -1,8 +1,8 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
####################
-# Copyright (c) 2016, Perceptive Automation, LLC. All rights reserved.
-# http://www.indigodomo.com
+# Copyright (c) 2022, Perceptive Automation, LLC. All rights reserved.
+# https://www.indigodomo.com
import indigo
@@ -15,317 +15,310 @@
################################################################################
class Plugin(indigo.PluginBase):
- ########################################
- def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs):
- super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs)
- self.debug = True
-
- ########################################
- def startup(self):
- self.debugLog(u"startup called")
-
- def shutdown(self):
- self.debugLog(u"shutdown called")
-
- ########################################
- # deviceStartComm() is called on application launch for all of our plugin defined
- # devices, and it is called when a new device is created immediately after its
- # UI settings dialog has been validated. This is a good place to force any properties
- # we need the device to have, and to cleanup old properties.
- def deviceStartComm(self, dev):
- # self.debugLog(u"deviceStartComm: %s" % (dev.name,))
-
- props = dev.pluginProps
- if dev.deviceTypeId == 'myColorType':
- # Set SupportsColor property so Indigo knows device accepts color actions and should use color UI.
- props["SupportsColor"] = True
-
- # Cleanup properties used by other device types. These can exist if user switches the device type.
- if "IsLockSubType" in props:
- del props["IsLockSubType"]
-
- dev.replacePluginPropsOnServer(props)
- elif dev.deviceTypeId == 'myLockType':
- # Set IsLockSubType property so Indigo knows device accepts lock actions and should use lock UI.
- props["IsLockSubType"] = True
-
- # Cleanup properties used by other device types. These can exist if user switches the device type.
- if "SupportsColor" in props:
- del props["SupportsColor"]
-
- dev.replacePluginPropsOnServer(props)
-
- ########################################
- def validateDeviceConfigUi(self, valuesDict, typeId, devId):
- return (True, valuesDict)
-
- ########################################
- # Relay / Dimmer Action callback
- ######################
- def actionControlDevice(self, action, dev):
- ###### TURN ON ######
- if action.deviceAction == indigo.kDeviceAction.TurnOn:
- # Command hardware module (dev) to turn ON here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "on"))
-
- # And then tell the Indigo Server to update the state.
- dev.updateStateOnServer("onOffState", True)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s failed" % (dev.name, "on"), isError=True)
-
- ###### TURN OFF ######
- elif action.deviceAction == indigo.kDeviceAction.TurnOff:
- # Command hardware module (dev) to turn OFF here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "off"))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("onOffState", False)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s failed" % (dev.name, "off"), isError=True)
-
- ###### LOCK ######
- if action.deviceAction == indigo.kDeviceAction.Lock:
- # Command hardware module (dev) to LOCK here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "lock"))
-
- # And then tell the Indigo Server to update the state.
- dev.updateStateOnServer("onOffState", True)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s failed" % (dev.name, "lock"), isError=True)
-
- ###### UNLOCK ######
- elif action.deviceAction == indigo.kDeviceAction.Unlock:
- # Command hardware module (dev) to turn UNLOCK here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "unlock"))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("onOffState", False)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s failed" % (dev.name, "unlock"), isError=True)
-
- ###### TOGGLE ######
- elif action.deviceAction == indigo.kDeviceAction.Toggle:
- # Command hardware module (dev) to toggle here:
- # ** IMPLEMENT ME **
- newOnState = not dev.onState
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "toggle"))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("onOffState", newOnState)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s failed" % (dev.name, "toggle"), isError=True)
-
- ###### SET BRIGHTNESS ######
- elif action.deviceAction == indigo.kDeviceAction.SetBrightness:
- # Command hardware module (dev) to set brightness here:
- # ** IMPLEMENT ME **
- newBrightness = action.actionValue
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %d" % (dev.name, "set brightness", newBrightness))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("brightnessLevel", newBrightness)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %d failed" % (dev.name, "set brightness", newBrightness), isError=True)
-
- ###### BRIGHTEN BY ######
- elif action.deviceAction == indigo.kDeviceAction.BrightenBy:
- # Command hardware module (dev) to do a relative brighten here:
- # ** IMPLEMENT ME **
- newBrightness = dev.brightness + action.actionValue
- if newBrightness > 100:
- newBrightness = 100
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %d" % (dev.name, "brighten", newBrightness))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("brightnessLevel", newBrightness)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %d failed" % (dev.name, "brighten", newBrightness), isError=True)
-
- ###### DIM BY ######
- elif action.deviceAction == indigo.kDeviceAction.DimBy:
- # Command hardware module (dev) to do a relative dim here:
- # ** IMPLEMENT ME **
- newBrightness = dev.brightness - action.actionValue
- if newBrightness < 0:
- newBrightness = 0
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %d" % (dev.name, "dim", newBrightness))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("brightnessLevel", newBrightness)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %d failed" % (dev.name, "dim", newBrightness), isError=True)
-
- ###### SET COLOR LEVELS ######
- elif action.deviceAction == indigo.kDeviceAction.SetColorLevels:
- # action.actionValue is a dict containing the color channel key/value
- # pairs. All color channel keys (redLevel, greenLevel, etc.) are optional
- # so plugin should handle cases where some color values are not specified
- # in the action.
- actionColorVals = action.actionValue
-
- # Construct a list of channel keys that are possible for what this device
- # supports. It may not support RGB or may not support white levels, for
- # example, depending on how the device's properties (SupportsColor, SupportsRGB,
- # SupportsWhite, SupportsTwoWhiteLevels, SupportsWhiteTemperature) have
- # been specified.
- channelKeys = []
- usingWhiteChannels = False
- if dev.supportsRGB:
- channelKeys.extend(['redLevel', 'greenLevel', 'blueLevel'])
- if dev.supportsWhite:
- channelKeys.extend(['whiteLevel'])
- usingWhiteChannels = True
- if dev.supportsTwoWhiteLevels:
- channelKeys.extend(['whiteLevel2'])
- elif dev.supportsWhiteTemperature:
- channelKeys.extend(['whiteTemperature'])
- # Note having 2 white levels (cold and warm) takes precedence over
- # the use of a white temperature value. You cannot have both, although
- # you can have a single white level and a white temperature value.
-
- # Next enumerate through the possible color channels and extract that
- # value from the actionValue (actionColorVals).
- keyValueList = []
- resultVals = []
- for channel in channelKeys:
- if channel in actionColorVals:
- brightness = float(actionColorVals[channel])
- brightnessByte = int(round(255.0 * (brightness / 100.0)))
-
- # Command hardware module (dev) to change its color level here:
- # ** IMPLEMENT ME **
-
- if channel in dev.states:
- keyValueList.append({'key':channel, 'value':brightness})
- result = str(int(round(brightness)))
- elif channel in dev.states:
- # If the action doesn't specify a level that is needed (say the
- # hardware API requires a full RGB triplet to be specified, but
- # the action only contains green level), then the plugin could
- # extract the currently cached red and blue values from the
- # dev.states[] dictionary:
- cachedBrightness = float(dev.states[channel])
- cachedBrightnessByte = int(round(255.0 * (cachedBrightness / 100.0)))
- # Could show in the Event Log '--' to indicate this level wasn't
- # passed in by the action:
- result = '--'
- # Or could show the current device state's cached level:
- # result = str(int(round(cachedBrightness)))
-
- # Add a comma to separate the RGB values from the white values for logging.
- if channel == 'blueLevel' and usingWhiteChannels:
- result += ","
- elif channel == 'whiteTemperature' and result != '--':
- result += " K"
- resultVals.append(result)
- # Set to False if it failed.
- sendSuccess = True
-
- resultValsStr = ' '.join(resultVals)
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %s" % (dev.name, "set color", resultValsStr))
-
- # And then tell the Indigo Server to update the color level states:
- if len(keyValueList) > 0:
- dev.updateStatesOnServer(keyValueList)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %s failed" % (dev.name, "set color", resultValsStr), isError=True)
-
- ########################################
- # General Action callback
- ######################
- def actionControlUniversal(self, action, dev):
- ###### BEEP ######
- if action.deviceAction == indigo.kUniversalAction.Beep:
- # Beep the hardware module (dev) here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "beep request"))
-
- ###### ENERGY UPDATE ######
- elif action.deviceAction == indigo.kUniversalAction.EnergyUpdate:
- # Request hardware module (dev) for its most recent meter data here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "energy update request"))
-
- ###### ENERGY RESET ######
- elif action.deviceAction == indigo.kUniversalAction.EnergyReset:
- # Request that the hardware module (dev) reset its accumulative energy usage data here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "energy reset request"))
-
- ###### STATUS REQUEST ######
- elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
- # Query hardware module (dev) for its current status here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "status request"))
-
- ########################################
- # Custom Plugin Action callbacks (defined in Actions.xml)
- ######################
- def setBacklightBrightness(self, pluginAction, dev):
- try:
- newBrightness = int(pluginAction.props.get(u"brightness", 100))
- except ValueError:
- # The int() cast above might fail if the user didn't enter a number:
- indigo.server.log(u"set backlight brightness action to device \"%s\" -- invalid brightness value" % (dev.name,), isError=True)
- return
-
- # Command hardware module (dev) to set backlight brightness here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %d" % (dev.name, "set backlight brightness", newBrightness))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("backlightBrightness", newBrightness)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %d failed" % (dev.name, "set backlight brightness", newBrightness), isError=True)
+ ########################################
+ def __init__(self, plugin_id, plugin_display_name, plugin_version, plugin_prefs):
+ super().__init__(plugin_id, plugin_display_name, plugin_version, plugin_prefs)
+ self.debug = True
+
+ ########################################
+ def startup(self):
+ self.logger.debug("startup called")
+
+ def shutdown(self):
+ self.logger.debug("shutdown called")
+
+ ########################################
+ # deviceStartComm() is called on application launch for all of our plugin defined
+ # devices, and it is called when a new device is created immediately after its
+ # UI settings dialog has been validated. This is a good place to force any properties
+ # we need the device to have, and to cleanup old properties.
+ def deviceStartComm(self, dev):
+ # self.logger.debug(f"deviceStartComm: {dev.name}")
+
+ props = dev.pluginProps
+ if dev.deviceTypeId == 'myColorType':
+ # Set SupportsColor property so Indigo knows device accepts color actions and should use color UI.
+ props["SupportsColor"] = True
+
+ # Cleanup properties used by other device types. These can exist if user switches the device type.
+ if "IsLockSubType" in props:
+ del props["IsLockSubType"]
+
+ dev.replacePluginPropsOnServer(props)
+ elif dev.deviceTypeId == 'myLockType':
+ # Set IsLockSubType property so Indigo knows device accepts lock actions and should use lock UI.
+ props["IsLockSubType"] = True
+
+ # Cleanup properties used by other device types. These can exist if user switches the device type.
+ if "SupportsColor" in props:
+ del props["SupportsColor"]
+
+ dev.replacePluginPropsOnServer(props)
+
+ ########################################
+ def validateDeviceConfigUi(self, values_dict, type_id, dev_id):
+ return (True, values_dict)
+
+ ########################################
+ # Relay / Dimmer Action callback
+ ######################
+ def actionControlDevice(self, action, dev):
+ ###### TURN ON ######
+ if action.deviceAction == indigo.kDeviceAction.TurnOn:
+ # Command hardware module (dev) to turn ON here:
+ # ** IMPLEMENT ME **
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" on")
+
+ # And then tell the Indigo Server to update the state.
+ dev.updateStateOnServer("onOffState", True)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" on failed")
+
+ ###### TURN OFF ######
+ elif action.deviceAction == indigo.kDeviceAction.TurnOff:
+ # Command hardware module (dev) to turn OFF here:
+ # ** IMPLEMENT ME **
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" off")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("onOffState", False)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" off failed")
+
+ ###### LOCK ######
+ if action.deviceAction == indigo.kDeviceAction.Lock:
+ # Command hardware module (dev) to LOCK here:
+ # ** IMPLEMENT ME **
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" lock")
+
+ # And then tell the Indigo Server to update the state.
+ dev.updateStateOnServer("onOffState", True)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" lock failed")
+
+ ###### UNLOCK ######
+ elif action.deviceAction == indigo.kDeviceAction.Unlock:
+ # Command hardware module (dev) to turn UNLOCK here:
+ # ** IMPLEMENT ME **
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" unlock")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("onOffState", False)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" unlock failed")
+
+ ###### TOGGLE ######
+ elif action.deviceAction == indigo.kDeviceAction.Toggle:
+ # Command hardware module (dev) to toggle here:
+ # ** IMPLEMENT ME **
+ new_on_state = not dev.onState
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" toggle")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("onOffState", new_on_state)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" toggle failed")
+
+ ###### SET BRIGHTNESS ######
+ elif action.deviceAction == indigo.kDeviceAction.SetBrightness:
+ # Command hardware module (dev) to set brightness here:
+ # ** IMPLEMENT ME **
+ new_brightness = action.actionValue
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" set brightness to {new_brightness}")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("brightnessLevel", new_brightness)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" set brightness to {new_brightness} failed")
+
+ ###### BRIGHTEN BY ######
+ elif action.deviceAction == indigo.kDeviceAction.BrightenBy:
+ # Command hardware module (dev) to do a relative brighten here:
+ # ** IMPLEMENT ME **
+ new_brightness = min(dev.brightness + action.actionValue, 100)
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" brighten to {new_brightness}")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("brightnessLevel", new_brightness)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" brighten to {new_brightness} failed")
+
+ ###### DIM BY ######
+ elif action.deviceAction == indigo.kDeviceAction.DimBy:
+ # Command hardware module (dev) to do a relative dim here:
+ # ** IMPLEMENT ME **
+ new_brightness = max(dev.brightness - action.actionValue, 0)
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" dim to {new_brightness}")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("brightnessLevel", new_brightness)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" dim to {new_brightness} failed")
+
+ ###### SET COLOR LEVELS ######
+ elif action.deviceAction == indigo.kDeviceAction.SetColorLevels:
+ # action.actionValue is a dict containing the color channel key/value
+ # pairs. All color channel keys (redLevel, greenLevel, etc.) are optional
+ # so plugin should handle cases where some color values are not specified
+ # in the action.
+ action_color_vals = action.actionValue
+
+ # Construct a list of channel keys that are possible for what this device
+ # supports. It may not support RGB or may not support white levels, for
+ # example, depending on how the device's properties (SupportsColor, SupportsRGB,
+ # SupportsWhite, SupportsTwoWhiteLevels, SupportsWhiteTemperature) have
+ # been specified.
+ channel_keys = []
+ using_white_channels = False
+ if dev.supportsRGB:
+ channel_keys.extend(['redLevel', 'greenLevel', 'blueLevel'])
+ if dev.supportsWhite:
+ channel_keys.extend(['whiteLevel'])
+ using_white_channels = True
+ if dev.supportsTwoWhiteLevels:
+ channel_keys.extend(['whiteLevel2'])
+ elif dev.supportsWhiteTemperature:
+ channel_keys.extend(['whiteTemperature'])
+ # Note having 2 white levels (cold and warm) takes precedence over
+ # the use of a white temperature value. You cannot have both, although
+ # you can have a single white level and a white temperature value.
+
+ # Next enumerate through the possible color channels and extract that
+ # value from the actionValue (action_color_vals).
+ kv_list = []
+ result_vals = []
+ for channel in channel_keys:
+ if channel in action_color_vals:
+ brightness = float(action_color_vals[channel])
+ brightness_byte = int(round(255.0 * (brightness / 100.0)))
+
+ # Command hardware module (dev) to change its color level here:
+ # ** IMPLEMENT ME **
+
+ if channel in dev.states:
+ kv_list.append({'key':channel, 'value':brightness})
+ result = str(int(round(brightness)))
+ elif channel in dev.states:
+ # If the action doesn't specify a level that is needed (say the
+ # hardware API requires a full RGB triplet to be specified, but
+ # the action only contains green level), then the plugin could
+ # extract the currently cached red and blue values from the
+ # dev.states[] dictionary:
+ cached_brightness = float(dev.states[channel])
+ cached_brightness_byte = int(round(255.0 * (cached_brightness / 100.0)))
+ # Could show in the Event Log '--' to indicate this level wasn't
+ # passed in by the action:
+ result = '--'
+ # Or could show the current device state's cached level:
+ # result = str(int(round(cached_brightness)))
+
+ # Add a comma to separate the RGB values from the white values for logging.
+ if channel == 'blueLevel' and using_white_channels:
+ result += ","
+ elif channel == 'whiteTemperature' and result != '--':
+ result += " K"
+ result_vals.append(result)
+ # Set to False if it failed.
+ send_success = True
+
+ result_vals_str = ' '.join(result_vals)
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" set color to {result_vals_str}")
+
+ # And then tell the Indigo Server to update the color level states:
+ if len(kv_list) > 0:
+ dev.updateStatesOnServer(kv_list)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" set color to {result_vals_str} failed")
+
+ ########################################
+ # General Action callback
+ ######################
+ def actionControlUniversal(self, action, dev):
+ ###### BEEP ######
+ if action.deviceAction == indigo.kUniversalAction.Beep:
+ # Beep the hardware module (dev) here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" beep request")
+
+ ###### ENERGY UPDATE ######
+ elif action.deviceAction == indigo.kUniversalAction.EnergyUpdate:
+ # Request hardware module (dev) for its most recent meter data here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" energy update request")
+
+ ###### ENERGY RESET ######
+ elif action.deviceAction == indigo.kUniversalAction.EnergyReset:
+ # Request that the hardware module (dev) reset its accumulative energy usage data here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" energy reset request")
+
+ ###### STATUS REQUEST ######
+ elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
+ # Query hardware module (dev) for its current status here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" status request")
+
+ ########################################
+ # Custom Plugin Action callbacks (defined in Actions.xml)
+ ######################
+ def set_backlight_brightness(self, plugin_action, dev):
+ try:
+ new_brightness = int(plugin_action.props.get("brightness", 100))
+ except ValueError:
+ # The int() cast above might fail if the user didn't enter a number:
+ self.logger.error(f"set backlight brightness action to device \"{dev.name}\" -- invalid brightness value")
+ return
+ # Command hardware module (dev) to set backlight brightness here:
+ # FIXME: add implementation here
+ send_success = True # Set to False if it failed.
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" set backlight brightness to {new_brightness}")
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("backlightBrightness", new_brightness)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" set backlight brightness to {new_brightness} failed")
diff --git a/Example Device - Sensor.indigoPlugin/Contents/Info.plist b/Example Device - Sensor.indigoPlugin/Contents/Info.plist
index a4dbe63..2e95a7a 100644
--- a/Example Device - Sensor.indigoPlugin/Contents/Info.plist
+++ b/Example Device - Sensor.indigoPlugin/Contents/Info.plist
@@ -2,10 +2,10 @@
- PluginVersion
- 2021.1.0
- ServerApiVersion
- 2.5
+ PluginVersion
+ 2022.1.0
+ ServerApiVersion
+ 3.0IwsApiVersion1.0.0CFBundleDisplayName
@@ -18,7 +18,7 @@
CFBundleURLName
- http://wiki.indigodomo.com/doku.php?id=plugins:example_dev_sensor_1
+ https://wiki.indigodomo.com/doku.php?id=plugins:example_dev_sensor_1
diff --git a/Example Device - Sensor.indigoPlugin/Contents/Server Plugin/Actions.xml b/Example Device - Sensor.indigoPlugin/Contents/Server Plugin/Actions.xml
index 9534414..a96c236 100644
--- a/Example Device - Sensor.indigoPlugin/Contents/Server Plugin/Actions.xml
+++ b/Example Device - Sensor.indigoPlugin/Contents/Server Plugin/Actions.xml
@@ -1,24 +1,24 @@
-
- Set Backlight Brightness
- setBacklightBrightness
-
-
-
-
-
-
-
-
-
+
+ Set Backlight Brightness
+ set_backlight_brightness
+
+
+
+
+
+
+
+
+
diff --git a/Example Device - Sensor.indigoPlugin/Contents/Server Plugin/Devices.xml b/Example Device - Sensor.indigoPlugin/Contents/Server Plugin/Devices.xml
index f7314fb..e8d071f 100644
--- a/Example Device - Sensor.indigoPlugin/Contents/Server Plugin/Devices.xml
+++ b/Example Device - Sensor.indigoPlugin/Contents/Server Plugin/Devices.xml
@@ -1,105 +1,105 @@
-
-
- Example Adjustable Sensor Module
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ Example Adjustable Sensor Module
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- Integer
- Backlight Brightness
- Backlight Brightness
-
-
-
-
- Example Smoke Sensor Module
-
-
-
-
-
-
-
-
-
-
-
-
-
- Example Door/Window Sensor Module
-
-
-
-
-
-
-
-
-
-
-
-
+ The plugin can specify additional custom states and custom
+ actions (in Actions.xml) to modify custom states. As an example
+ here, we define a new custom state, backlightBrightness, which
+ is used to control the brightness of the backlit display of
+ the module.
+ -->
+
+ Integer
+ Backlight Brightness
+ Backlight Brightness
+
+
+
+
+ Example Smoke Sensor Module
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Example Door/Window Sensor Module
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example Device - Sensor.indigoPlugin/Contents/Server Plugin/plugin.py b/Example Device - Sensor.indigoPlugin/Contents/Server Plugin/plugin.py
index f683ab3..4e881d7 100644
--- a/Example Device - Sensor.indigoPlugin/Contents/Server Plugin/plugin.py
+++ b/Example Device - Sensor.indigoPlugin/Contents/Server Plugin/plugin.py
@@ -1,8 +1,8 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
####################
-# Copyright (c) 2021, Perceptive Automation, LLC. All rights reserved.
-# http://www.indigodomo.com
+# Copyright (c) 2022, Perceptive Automation, LLC. All rights reserved.
+# https://www.indigodomo.com
import indigo
@@ -15,136 +15,132 @@
################################################################################
class Plugin(indigo.PluginBase):
- ########################################
- def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs):
- super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs)
- self.debug = True
-
- ########################################
- def startup(self):
- self.debugLog(u"startup called")
-
- def shutdown(self):
- self.debugLog(u"shutdown called")
-
- ########################################
- def runConcurrentThread(self):
- try:
- while True:
- for dev in indigo.devices.iter("self"):
- if not dev.enabled or not dev.configured:
- continue
-
- # Plugins that need to poll out the status from the sensor
- # could do so here, then broadcast back the new values to the
- # Indigo Server via updateStateOnServer. For this example, we
- # could toggle the onOffState every 2 seconds. If the sensor
- # always broadcasts out changes (or is just 1-way), then this
- # entire runConcurrentThread() method can be deleted.
- if dev.deviceTypeId == u"myTempSensor":
- if dev.sensorValue is not None:
- exampleTempFloat = random.randint(560, 880) / 10.0 # random between 56.0 and 88.0 degrees F
- exampleTempStr = "%.1f °F" % (exampleTempFloat)
-
- keyValueList = []
- keyValueList.append({'key':'sensorValue', 'value':exampleTempFloat, 'uiValue':exampleTempStr})
- # Override the state icon shown (in Indigo Touch and client Main Window)
- # for this device to be the a temperature sensor:
- if dev.onState is not None:
- keyValueList.append({'key':'onOffState', 'value':not dev.onState})
- dev.updateStatesOnServer(keyValueList)
- if dev.onState:
- dev.updateStateImageOnServer(indigo.kStateImageSel.TemperatureSensorOn)
- else:
- dev.updateStateImageOnServer(indigo.kStateImageSel.TemperatureSensor)
- else:
- dev.updateStatesOnServer(keyValueList)
- dev.updateStateImageOnServer(indigo.kStateImageSel.TemperatureSensor)
- elif dev.onState is not None:
- dev.updateStateOnServer("onOffState", not dev.onState)
- dev.updateStateImageOnServer(indigo.kStateImageSel.Auto)
- else:
- dev.updateStateImageOnServer(indigo.kStateImageSel.Auto)
- self.sleep(2)
- except self.StopThread:
- pass # Optionally catch the StopThread exception and do any needed cleanup.
-
- ########################################
- def validateDeviceConfigUi(self, valuesDict, typeId, devId):
- return (True, valuesDict)
-
- ########################################
- def deviceStartComm(self, dev):
- # Called when communication with the hardware should be started.
- pass
-
- def deviceStopComm(self, dev):
- # Called when communication with the hardware should be shutdown.
- pass
-
- ########################################
- # Sensor Action callback
- ######################
- def actionControlSensor(self, action, dev):
- ###### TURN ON ######
- # Ignore turn on/off/toggle requests from clients since this is a read-only sensor.
- if action.sensorAction == indigo.kSensorAction.TurnOn:
- indigo.server.log(u"ignored \"%s\" %s request (sensor is read-only)" % (dev.name, "on"))
- # But we could request a sensor state update if we wanted like this:
- # dev.updateStateOnServer("onOffState", True)
-
- ###### TURN OFF ######
- # Ignore turn on/off/toggle requests from clients since this is a read-only sensor.
- elif action.sensorAction == indigo.kSensorAction.TurnOff:
- indigo.server.log(u"ignored \"%s\" %s request (sensor is read-only)" % (dev.name, "off"))
- # But we could request a sensor state update if we wanted like this:
- # dev.updateStateOnServer("onOffState", False)
-
- ###### TOGGLE ######
- # Ignore turn on/off/toggle requests from clients since this is a read-only sensor.
- elif action.sensorAction == indigo.kSensorAction.Toggle:
- indigo.server.log(u"ignored \"%s\" %s request (sensor is read-only)" % (dev.name, "toggle"))
- # But we could request a sensor state update if we wanted like this:
- # dev.updateStateOnServer("onOffState", not dev.onState)
-
- ########################################
- # General Action callback
- ######################
- def actionControlUniversal(self, action, dev):
- ###### BEEP ######
- if action.deviceAction == indigo.kUniversalAction.Beep:
- # Beep the hardware module (dev) here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "beep request"))
-
- ###### STATUS REQUEST ######
- elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
- # Query hardware module (dev) for its current status here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "status request"))
-
- ########################################
- # Custom Plugin Action callbacks (defined in Actions.xml)
- ######################
- def setBacklightBrightness(self, pluginAction, dev):
- try:
- newBrightness = int(pluginAction.props.get(u"brightness", 100))
- except ValueError:
- # The int() cast above might fail if the user didn't enter a number:
- indigo.server.log(u"set backlight brightness action to device \"%s\" -- invalid brightness value" % (dev.name,), isError=True)
- return
-
- # Command hardware module (dev) to set backlight brightness here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %d" % (dev.name, "set backlight brightness", newBrightness))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("backlightBrightness", newBrightness)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %d failed" % (dev.name, "set backlight brightness", newBrightness), isError=True)
-
+ ########################################
+ def __init__(self, plugin_id, plugin_display_name, plugin_version, plugin_prefs):
+ super().__init__(plugin_id, plugin_display_name, plugin_version, plugin_prefs)
+ self.debug = True
+
+ ########################################
+ def startup(self):
+ self.logger.debug("startup called")
+
+ def shutdown(self):
+ self.logger.debug("shutdown called")
+
+ ########################################
+ def runConcurrentThread(self):
+ try:
+ while True:
+ for dev in indigo.devices.iter("self"):
+ if not dev.enabled or not dev.configured:
+ continue
+
+ # Plugins that need to poll out the status from the sensor
+ # could do so here, then broadcast back the new values to the
+ # Indigo Server via updateStateOnServer. For this example, we
+ # could toggle the onOffState every 2 seconds. If the sensor
+ # always broadcasts out changes (or is just 1-way), then this
+ # entire runConcurrentThread() method can be deleted.
+ if dev.deviceTypeId == "myTempSensor":
+ if dev.sensorValue is not None:
+ example_temp_float = random.randint(560, 880) / 10.0 # random between 56.0 and 88.0 degrees F
+ example_temp_str = f"{example_temp_float:.1f} °F"
+
+ key_val_list = []
+ key_val_list.append({'key':'sensorValue', 'value':example_temp_float, 'uiValue':example_temp_str})
+ # Override the state icon shown (in Indigo Touch and client Main Window)
+ # for this device to be the a temperature sensor:
+ if dev.onState is not None:
+ key_val_list.append({'key':'onOffState', 'value':not dev.onState})
+ dev.updateStatesOnServer(key_val_list)
+ if dev.onState:
+ dev.updateStateImageOnServer(indigo.kStateImageSel.TemperatureSensorOn)
+ else:
+ dev.updateStateImageOnServer(indigo.kStateImageSel.TemperatureSensor)
+ else:
+ dev.updateStatesOnServer(key_val_list)
+ dev.updateStateImageOnServer(indigo.kStateImageSel.TemperatureSensor)
+ elif dev.onState is not None:
+ dev.updateStateOnServer("onOffState", not dev.onState)
+ dev.updateStateImageOnServer(indigo.kStateImageSel.Auto)
+ else:
+ dev.updateStateImageOnServer(indigo.kStateImageSel.Auto)
+ self.sleep(2)
+ except self.StopThread:
+ pass # Optionally catch the StopThread exception and do any needed cleanup.
+
+ ########################################
+ def validateDeviceConfigUi(self, values_dict, type_id, dev_id):
+ return (True, values_dict)
+
+ ########################################
+ def deviceStartComm(self, dev):
+ # Called when communication with the hardware should be started.
+ pass
+
+ def deviceStopComm(self, dev):
+ # Called when communication with the hardware should be shutdown.
+ pass
+
+ ########################################
+ # Sensor Action callback
+ ######################
+ def actionControlSensor(self, action, dev):
+ ###### TURN ON ######
+ # Ignore turn on/off/toggle requests from clients since this is a read-only sensor.
+ if action.sensorAction == indigo.kSensorAction.TurnOn:
+ self.logger.info(f"ignored \"{dev.name}\" on request (sensor is read-only)")
+ # But we could request a sensor state update if we wanted like this:
+ # dev.updateStateOnServer("onOffState", True)
+
+ ###### TURN OFF ######
+ # Ignore turn on/off/toggle requests from clients since this is a read-only sensor.
+ elif action.sensorAction == indigo.kSensorAction.TurnOff:
+ self.logger.info(f"ignored \"{dev.name}\" off request (sensor is read-only)")
+ # But we could request a sensor state update if we wanted like this:
+ # dev.updateStateOnServer("onOffState", False)
+
+ ###### TOGGLE ######
+ # Ignore turn on/off/toggle requests from clients since this is a read-only sensor.
+ elif action.sensorAction == indigo.kSensorAction.Toggle:
+ self.logger.info(f"ignored \"{dev.name}\" toggle request (sensor is read-only)")
+ # But we could request a sensor state update if we wanted like this:
+ # dev.updateStateOnServer("onOffState", not dev.onState)
+
+ ########################################
+ # General Action callback
+ ######################
+ def actionControlUniversal(self, action, dev):
+ ###### BEEP ######
+ if action.deviceAction == indigo.kUniversalAction.Beep:
+ # Beep the hardware module (dev) here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" beep request")
+
+ ###### STATUS REQUEST ######
+ elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
+ # Query hardware module (dev) for its current status here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" status request")
+
+ ########################################
+ # Custom Plugin Action callbacks (defined in Actions.xml)
+ ######################
+ def set_backlight_brightness(self, plugin_action, dev):
+ try:
+ new_brightness = int(plugin_action.props.get("brightness", 100))
+ except ValueError:
+ # The int() cast above might fail if the user didn't enter a number:
+ self.logger.error(f"set backlight brightness action to device \"{dev.name}\" -- invalid brightness value")
+ return
+ # Command hardware module (dev) to set backlight brightness here:
+ # FIXME: add implementation here
+ send_success = True # Set to False if it failed.
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" set backlight brightness to {new_brightness}")
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("backlightBrightness", new_brightness)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" set backlight brightness to {new_brightness} failed")
diff --git a/Example Device - Speed Control.indigoPlugin/Contents/Info.plist b/Example Device - Speed Control.indigoPlugin/Contents/Info.plist
index 04b7719..092db83 100644
--- a/Example Device - Speed Control.indigoPlugin/Contents/Info.plist
+++ b/Example Device - Speed Control.indigoPlugin/Contents/Info.plist
@@ -2,24 +2,24 @@
- PluginVersion
- 2021.1.0
- ServerApiVersion
- 2.5
- IwsApiVersion
- 1.0.0
- CFBundleDisplayName
- Example Device - Speed Control (ceiling fan)
- CFBundleIdentifier
- com.perceptiveautomation.indigoplugin.example-device-speedcontrol1
- CFBundleVersion
- 1.0.0
- CFBundleURLTypes
-
-
- CFBundleURLName
- http://wiki.indigodomo.com/doku.php?id=plugins:example_dev_speedcontrol_1
-
-
+ PluginVersion
+ 2022.1.0
+ ServerApiVersion
+ 3.0
+ IwsApiVersion
+ 1.0.0
+ CFBundleDisplayName
+ Example Device - Speed Control (ceiling fan)
+ CFBundleIdentifier
+ com.perceptiveautomation.indigoplugin.example-device-speedcontrol1
+ CFBundleVersion
+ 1.0.0
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ https://wiki.indigodomo.com/doku.php?id=plugins:example_dev_speedcontrol_1
+
+
diff --git a/Example Device - Speed Control.indigoPlugin/Contents/Server Plugin/Actions.xml b/Example Device - Speed Control.indigoPlugin/Contents/Server Plugin/Actions.xml
index c149a1b..150aa2f 100644
--- a/Example Device - Speed Control.indigoPlugin/Contents/Server Plugin/Actions.xml
+++ b/Example Device - Speed Control.indigoPlugin/Contents/Server Plugin/Actions.xml
@@ -1,24 +1,24 @@
-
- Set Backlight Brightness
- setBacklightBrightness
-
-
-
-
-
-
-
-
-
+
+ Set Backlight Brightness
+ set_backlight_brightness
+
+
+
+
+
+
+
+
+
diff --git a/Example Device - Speed Control.indigoPlugin/Contents/Server Plugin/Devices.xml b/Example Device - Speed Control.indigoPlugin/Contents/Server Plugin/Devices.xml
index 6ace7b9..7debef2 100644
--- a/Example Device - Speed Control.indigoPlugin/Contents/Server Plugin/Devices.xml
+++ b/Example Device - Speed Control.indigoPlugin/Contents/Server Plugin/Devices.xml
@@ -1,58 +1,58 @@
-
-
- Example Ceiling Fan Module
-
-
-
-
-
-
-
-
+
+ Example Ceiling Fan Module
+
+
+
+
+
+
+
+
-
- Integer
- Backlight Brightness
- Backlight Brightness
-
-
-
+ The plugin can specify additional custom states and custom
+ actions (in Actions.xml) to modify custom states. As an example
+ here, we define a new custom state, backlightBrightness, which
+ is used to control the brightness of the backlit display of
+ the module.
+ -->
+
+ Integer
+ Backlight Brightness
+ Backlight Brightness
+
+
+
diff --git a/Example Device - Speed Control.indigoPlugin/Contents/Server Plugin/plugin.py b/Example Device - Speed Control.indigoPlugin/Contents/Server Plugin/plugin.py
index 2b35ac2..b6a43fe 100644
--- a/Example Device - Speed Control.indigoPlugin/Contents/Server Plugin/plugin.py
+++ b/Example Device - Speed Control.indigoPlugin/Contents/Server Plugin/plugin.py
@@ -1,8 +1,8 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
####################
-# Copyright (c) 2014, Perceptive Automation, LLC. All rights reserved.
-# http://www.indigodomo.com
+# Copyright (c) 2022, Perceptive Automation, LLC. All rights reserved.
+# https://www.indigodomo.com
import indigo
@@ -14,200 +14,192 @@
################################################################################
class Plugin(indigo.PluginBase):
- ########################################
- def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs):
- super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs)
- self.debug = True
- self.speedLabels = [u"off", u"low", u"medium", u"high"]
-
- ########################################
- def startup(self):
- self.debugLog(u"startup called")
-
- def shutdown(self):
- self.debugLog(u"shutdown called")
-
- ########################################
- def validateDeviceConfigUi(self, valuesDict, typeId, devId):
- return (True, valuesDict)
-
- ########################################
- # Speed Control Action callback
- ######################
- def actionControlSpeedControl(self, action, dev):
- ###### TURN ON ######
- if action.speedControlAction == indigo.kSpeedControlAction.TurnOn:
- # Command hardware module (dev) to turn ON here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "on"))
-
- # And then tell the Indigo Server to update the state.
- dev.updateStateOnServer("onOffState", True)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s failed" % (dev.name, "on"), isError=True)
-
- ###### TURN OFF ######
- elif action.speedControlAction == indigo.kSpeedControlAction.TurnOff:
- # Command hardware module (dev) to turn OFF here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "off"))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("onOffState", False)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s failed" % (dev.name, "off"), isError=True)
-
- ###### TOGGLE ######
- elif action.speedControlAction == indigo.kSpeedControlAction.Toggle:
- # Command hardware module (dev) to toggle here:
- # ** IMPLEMENT ME **
- newOnState = not dev.onState
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "toggle"))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("onOffState", newOnState)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s failed" % (dev.name, "toggle"), isError=True)
-
- ###### SET SPEED INDEX ######
- elif action.speedControlAction == indigo.kSpeedControlAction.SetSpeedIndex:
- # Command hardware module (dev) to change the speed here to a specific
- # speed index (0=off, 1=low, ..., 3=high):
- # ** IMPLEMENT ME **
- newSpeedIndex = action.actionValue
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %s" % (dev.name, "set motor speed", self.speedLabels[newSpeedIndex]))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("speedIndex", newSpeedIndex)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %s failed" % (dev.name, "set motor speed", self.speedLabels[newSpeedIndex]), isError=True)
-
- ###### SET SPEED LEVEL ######
- elif action.speedControlAction == indigo.kSpeedControlAction.SetSpeedLevel:
- # Command hardware module (dev) to change the speed here to an absolute
- # speed level (0 to 100):
- # ** IMPLEMENT ME **
- newSpeedLevel = action.actionValue
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %d" % (dev.name, "set motor speed", newSpeedLevel))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("speedLevel", newSpeedLevel)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %d failed" % (dev.name, "set motor speed", newSpeedLevel), isError=True)
-
- ###### INCREASE SPEED INDEX BY ######
- elif action.speedControlAction == indigo.kSpeedControlAction.IncreaseSpeedIndex:
- # Command hardware module (dev) to do a relative speed increase here:
- # ** IMPLEMENT ME **
- newSpeedIndex = dev.speedIndex + action.actionValue
- if newSpeedIndex > 3:
- newSpeedIndex = 3
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %s" % (dev.name, "motor speed increase", self.speedLabels[newSpeedIndex]))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("speedIndex", newSpeedIndex)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %s failed" % (dev.name, "motor speed increase", self.speedLabels[newSpeedIndex]), isError=True)
-
- ###### DECREASE SPEED INDEX BY ######
- elif action.speedControlAction == indigo.kSpeedControlAction.DecreaseSpeedIndex:
- # Command hardware module (dev) to do a relative speed decrease here:
- # ** IMPLEMENT ME **
- newSpeedIndex = dev.speedIndex - action.actionValue
- if newSpeedIndex < 0:
- newSpeedIndex = 0
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %s" % (dev.name, "motor speed decrease", self.speedLabels[newSpeedIndex]))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("speedIndex", newSpeedIndex)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %s failed" % (dev.name, "motor speed decrease", self.speedLabels[newSpeedIndex]), isError=True)
-
- ########################################
- # General Action callback
- ######################
- def actionControlUniversal(self, action, dev):
- ###### BEEP ######
- if action.deviceAction == indigo.kUniversalAction.Beep:
- # Beep the hardware module (dev) here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "beep request"))
-
- ###### ENERGY UPDATE ######
- elif action.deviceAction == indigo.kUniversalAction.EnergyUpdate:
- # Request hardware module (dev) for its most recent meter data here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "energy update request"))
-
- ###### ENERGY RESET ######
- elif action.deviceAction == indigo.kUniversalAction.EnergyReset:
- # Request that the hardware module (dev) reset its accumulative energy usage data here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "energy reset request"))
-
- ###### STATUS REQUEST ######
- elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
- # Query hardware module (dev) for its current status here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "status request"))
-
- ########################################
- # Custom Plugin Action callbacks (defined in Actions.xml)
- ######################
- def setBacklightBrightness(self, pluginAction, dev):
- try:
- newBrightness = int(pluginAction.props.get(u"brightness", 100))
- except ValueError:
- # The int() cast above might fail if the user didn't enter a number:
- indigo.server.log(u"set backlight brightness action to device \"%s\" -- invalid brightness value" % (dev.name,), isError=True)
- return
-
- # Command hardware module (dev) to set backlight brightness here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %d" % (dev.name, "set backlight brightness", newBrightness))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("backlightBrightness", newBrightness)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %d failed" % (dev.name, "set backlight brightness", newBrightness), isError=True)
-
+ ########################################
+ def __init__(self, plugin_id, plugin_display_name, plugin_version, plugin_prefs):
+ super().__init__(plugin_id, plugin_display_name, plugin_version, plugin_prefs)
+ self.debug = True
+ self.speed_labels = ["off", "low", "medium", "high"]
+
+ ########################################
+ def startup(self):
+ self.logger.debug("startup called")
+
+ def shutdown(self):
+ self.logger.debug("shutdown called")
+
+ ########################################
+ def validateDeviceConfigUi(self, values_dict, type_id, dev_id):
+ return (True, values_dict)
+
+ ########################################
+ # Speed Control Action callback
+ ######################
+ def actionControlSpeedControl(self, action, dev):
+ ###### TURN ON ######
+ if action.speedControlAction == indigo.kSpeedControlAction.TurnOn:
+ # Command hardware module (dev) to turn ON here:
+ # ** IMPLEMENT ME **
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" on")
+
+ # And then tell the Indigo Server to update the state.
+ dev.updateStateOnServer("onOffState", True)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" on failed")
+
+ ###### TURN OFF ######
+ elif action.speedControlAction == indigo.kSpeedControlAction.TurnOff:
+ # Command hardware module (dev) to turn OFF here:
+ # ** IMPLEMENT ME **
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" off")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("onOffState", False)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" off failed")
+
+ ###### TOGGLE ######
+ elif action.speedControlAction == indigo.kSpeedControlAction.Toggle:
+ # Command hardware module (dev) to toggle here:
+ # ** IMPLEMENT ME **
+ new_on_state = not dev.onState
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" toggle")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("onOffState", new_on_state)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" toggle failed")
+
+ ###### SET SPEED INDEX ######
+ elif action.speedControlAction == indigo.kSpeedControlAction.SetSpeedIndex:
+ # Command hardware module (dev) to change the speed here to a specific
+ # speed index (0=off, 1=low, ..., 3=high):
+ # ** IMPLEMENT ME **
+ new_speed_index = action.actionValue
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" set motor speed to {self.speed_labels[new_speed_index]}")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("speedIndex", new_speed_index)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" set motor speed to {self.speed_labels[new_speed_index]} failed")
+
+ ###### SET SPEED LEVEL ######
+ elif action.speedControlAction == indigo.kSpeedControlAction.SetSpeedLevel:
+ # Command hardware module (dev) to change the speed here to an absolute
+ # speed level (0 to 100):
+ # ** IMPLEMENT ME **
+ new_speed_level = action.actionValue
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" set motor speed to {new_speed_level}")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("speedLevel", new_speed_level)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" set motor speed to {new_speed_level} failed")
+
+ ###### INCREASE SPEED INDEX BY ######
+ elif action.speedControlAction == indigo.kSpeedControlAction.IncreaseSpeedIndex:
+ # Command hardware module (dev) to do a relative speed increase here:
+ # ** IMPLEMENT ME **
+ new_speed_index = min(dev.speedIndex + action.actionValue, 3)
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" motor speed increase to {self.speed_labels[new_speed_index]}")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("speedIndex", new_speed_index)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" motor speed increase to {self.speed_labels[new_speed_index]} failed")
+
+ ###### DECREASE SPEED INDEX BY ######
+ elif action.speedControlAction == indigo.kSpeedControlAction.DecreaseSpeedIndex:
+ # Command hardware module (dev) to do a relative speed decrease here:
+ # ** IMPLEMENT ME **
+ new_speed_index = max(dev.speedIndex - action.actionValue, 0)
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" motor speed decrease to {self.speed_labels[new_speed_index]}")
+
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("speedIndex", new_speed_index)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" motor speed decrease to {self.speed_labels[new_speed_index]} failed")
+
+ ########################################
+ # General Action callback
+ ######################
+ def actionControlUniversal(self, action, dev):
+ ###### BEEP ######
+ if action.deviceAction == indigo.kUniversalAction.Beep:
+ # Beep the hardware module (dev) here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" beep request")
+
+ ###### ENERGY UPDATE ######
+ elif action.deviceAction == indigo.kUniversalAction.EnergyUpdate:
+ # Request hardware module (dev) for its most recent meter data here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" energy update request")
+
+ ###### ENERGY RESET ######
+ elif action.deviceAction == indigo.kUniversalAction.EnergyReset:
+ # Request that the hardware module (dev) reset its accumulative energy usage data here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" energy reset request")
+
+ ###### STATUS REQUEST ######
+ elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
+ # Query hardware module (dev) for its current status here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" status request")
+
+ ########################################
+ # Custom Plugin Action callbacks (defined in Actions.xml)
+ ######################
+ def set_backlight_brightness(self, plugin_action, dev):
+ try:
+ new_brightness = int(plugin_action.props.get("brightness", 100))
+ except ValueError:
+ # The int() cast above might fail if the user didn't enter a number:
+ self.logger.error(f"set backlight brightness action to device \"{dev.name}\" -- invalid brightness value")
+ return
+ # Command hardware module (dev) to set backlight brightness here:
+ # FIXME: add implementation here
+ send_success = True # Set to False if it failed.
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" set backlight brightness to {new_brightness}")
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("backlightBrightness", new_brightness)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" set backlight brightness to {new_brightness} failed")
diff --git a/Example Device - Sprinkler.indigoPlugin/Contents/Info.plist b/Example Device - Sprinkler.indigoPlugin/Contents/Info.plist
index f2b30c9..7e6ac69 100644
--- a/Example Device - Sprinkler.indigoPlugin/Contents/Info.plist
+++ b/Example Device - Sprinkler.indigoPlugin/Contents/Info.plist
@@ -2,24 +2,24 @@
- PluginVersion
- 2021.1.0
- ServerApiVersion
- 2.5
- IwsApiVersion
- 1.0.0
- CFBundleDisplayName
- Example Device - Sprinkler
- CFBundleIdentifier
- com.perceptiveautomation.indigoplugin.example-device-sprinkler1
- CFBundleVersion
- 1.0.0
- CFBundleURLTypes
-
-
- CFBundleURLName
- http://wiki.indigodomo.com/doku.php?id=plugins:example_dev_sprinkler_1
-
-
+ PluginVersion
+ 2022.1.0
+ ServerApiVersion
+ 3.0
+ IwsApiVersion
+ 1.0.0
+ CFBundleDisplayName
+ Example Device - Sprinkler
+ CFBundleIdentifier
+ com.perceptiveautomation.indigoplugin.example-device-sprinkler1
+ CFBundleVersion
+ 1.0.0
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ https://wiki.indigodomo.com/doku.php?id=plugins:example_dev_sprinkler_1
+
+
diff --git a/Example Device - Sprinkler.indigoPlugin/Contents/Server Plugin/Actions.xml b/Example Device - Sprinkler.indigoPlugin/Contents/Server Plugin/Actions.xml
index 6e2cf67..2705e66 100644
--- a/Example Device - Sprinkler.indigoPlugin/Contents/Server Plugin/Actions.xml
+++ b/Example Device - Sprinkler.indigoPlugin/Contents/Server Plugin/Actions.xml
@@ -1,24 +1,24 @@
-
- Set Backlight Brightness
- setBacklightBrightness
-
-
-
-
-
-
-
-
-
+
+ Set Backlight Brightness
+ set_backlight_brightness
+
+
+
+
+
+
+
+
+
diff --git a/Example Device - Sprinkler.indigoPlugin/Contents/Server Plugin/Devices.xml b/Example Device - Sprinkler.indigoPlugin/Contents/Server Plugin/Devices.xml
index 22c794b..2f3ae86 100644
--- a/Example Device - Sprinkler.indigoPlugin/Contents/Server Plugin/Devices.xml
+++ b/Example Device - Sprinkler.indigoPlugin/Contents/Server Plugin/Devices.xml
@@ -1,116 +1,116 @@
-
-
- Example Sprinkler Module
-
-
-
-
-
+
+
+ Example Sprinkler Module
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Last zone of controller is used as a pump
-
-
+ Plugins can update these properties either in device ConfigUI
+ (like below), or can update them from python by using the
+ dev.replacePluginPropsOnServer() method, most likely inside your
+ deviceStartComm method. Both will trigger the Indigo Server to
+ automatically rebuild the device's states list based on the needed
+ changes.
+ -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Last zone of controller is used as a pump
+
+
-
-
-
- Plugin overrides high-level actions
-
-
-
-
+
+
+ Plugin overrides high-level actions
+
+
+
+
-
- Integer
- Backlight Brightness
- Backlight Brightness
-
-
-
+ The plugin can specify additional custom states and custom
+ actions (in Actions.xml) to modify custom states. As an example
+ here, we define a new custom state, backlightBrightness, which
+ is used to control the brightness of the backlit display of
+ the module.
+ -->
+
+ Integer
+ Backlight Brightness
+ Backlight Brightness
+
+
+
diff --git a/Example Device - Sprinkler.indigoPlugin/Contents/Server Plugin/plugin.py b/Example Device - Sprinkler.indigoPlugin/Contents/Server Plugin/plugin.py
index ceb083b..b613df7 100644
--- a/Example Device - Sprinkler.indigoPlugin/Contents/Server Plugin/plugin.py
+++ b/Example Device - Sprinkler.indigoPlugin/Contents/Server Plugin/plugin.py
@@ -1,8 +1,8 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
####################
-# Copyright (c) 2014, Perceptive Automation, LLC. All rights reserved.
-# http://www.indigodomo.com
+# Copyright (c) 2022, Perceptive Automation, LLC. All rights reserved.
+# https://www.indigodomo.com
import indigo
@@ -14,254 +14,250 @@
################################################################################
class Plugin(indigo.PluginBase):
- ########################################
- def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs):
- super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs)
- self.debug = True
-
- ########################################
- def startup(self):
- # self.debugLog(u"startup called")
- pass
-
- def shutdown(self):
- # self.debugLog(u"shutdown called")
- pass
-
- ########################################
- def validateDeviceConfigUi(self, valuesDict, typeId, devId):
- return (True, valuesDict)
-
- ########################################
- # Sprinkler Control Action callback
- ######################
- def actionControlSprinkler(self, action, dev):
- ########################################
- # Required plugin sprinkler actions: These actions must be handled by the plugin.
- ########################################
- ###### ZONE ON ######
- if action.sprinklerAction == indigo.kSprinklerAction.ZoneOn:
- # Command hardware module (dev) to turn ON a specific zone here.
- # ** IMPLEMENT ME **
- zoneName = u"no zone"
- if action.zoneIndex is not None:
- zoneName = dev.zoneNames[action.zoneIndex - 1]
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s - %s\" on" % (dev.name, zoneName))
-
- # And then tell the Indigo Server to update the state.
- dev.updateStateOnServer("activeZone", action.zoneIndex)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s - %s\" on failed" % (dev.name, zoneName), isError=True)
-
- ###### ALL ZONES OFF ######
- elif action.sprinklerAction == indigo.kSprinklerAction.AllZonesOff:
- # Command hardware module (dev) to turn OFF here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "all zones off"))
-
- # And then tell the Indigo Server to update the state.
- dev.updateStateOnServer("activeZone", 0)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s failed" % (dev.name, "all zones off"), isError=True)
-
- ########################################
- # Optional plugin sprinkler actions: These actions are *only* dispatched to the plugin
- # if the device property "OverrideScheduleActions" is set to True. The default behavior
- # (False) is for the Indigo Server to handle these higher level commands and scheduling
- # automatically, which will dispatch the required lower-level indigo.kSprinklerAction.ZoneOn
- # and indigo.kSprinklerAction.AllZonesOff actions above at the appropriate times.
- #
- # Note if a plugin defines the higher level actions below then it must handle all zone
- # scheduling, pausing, resuming, and next/previous skipping. Given the complexity in
- # handling the individual zone scheduling, pausing, resuming, and next/previous zones
- # it is recommended to use the default value of OverrideScheduleActions False, so that
- # IndigoServer can handle this higher level scheduling and complexity.
- ########################################
- ###### RUN SCHEDULE OF ZONE DURATIONS ######
- elif action.sprinklerAction == indigo.kSprinklerAction.RunNewSchedule:
- # Plugin should handle its own scheduling here and tell the device
- # to turn on the first zone in the schedule, _or_ (if supported by
- # the device) send the entire schedule to the device.
- # ** IMPLEMENT ME **
- indigo.server.log(u"scheduled \"%s\" zone durations: %s" % (dev.name, str(action.zoneDurations)))
-
- # The ScheduledZoneDurations property is used by Indigo to show the
- # currently running schedule (in the client, Web, and Indigo Touch UI),
- # so set based on the durations requested in the action.
- props = dev.pluginProps
- # Plugin should use dev.zoneEnableList, dev.zoneMaxDurations and
- # dev.zoneCount to make sure action.zoneDurations are within the
- # range and bounds specified.
- zoneListStr = ', '.join(str(dur) for dur in action.zoneDurations)
- props["PreviousZoneDurations"] = zoneListStr
- props["ScheduledZoneDurations"] = zoneListStr
- dev.replacePluginPropsOnServer(props)
-
- # Plugin will then need to update the activeZone state appropriately.
- # As an example here we'll just turn on zone 1 (plugin should really
- # inspect action.zoneDurations for the first non-zero item).
- dev.updateStateOnServer("activeZone", 1)
-
- ###### RUN LAST USED SCHEDULE ######
- elif action.sprinklerAction == indigo.kSprinklerAction.RunPreviousSchedule:
- # Plugin should re-run the last schedule that was used here and tell
- # the device to turn on the first zone in the schedule, _or_ (if
- # supported by the device) send the device a run last schedule command.
- # ** IMPLEMENT ME **
-
- # Plugin will then need to update the ScheduledZoneDurations property
- # and the activeZone state appropriately.
- props = dev.pluginProps
- if "PreviousZoneDurations" in props:
- indigo.server.log(u"running last used scheduled for \"%s\": %s" % (dev.name, props["PreviousZoneDurations"]))
-
- props["ScheduledZoneDurations"] = props["PreviousZoneDurations"]
- dev.replacePluginPropsOnServer(props)
- dev.updateStateOnServer("activeZone", 1)
-
- ###### PAUSE SCHEDULE ######
- elif action.sprinklerAction == indigo.kSprinklerAction.PauseSchedule:
- # Plugin should pause its schedule here and tell the device to
- # turn off the active zone, _or_ (if supported by the device)
- # send the device a pause command.
- # ** IMPLEMENT ME **
- indigo.server.log(u"pausing \"%s\" schedule" % (dev.name))
-
- # Plugin will then need to update the ScheduledZoneDurations property
- # and the activeZone state appropriately.
- props = dev.pluginProps
- props["PauseScheduleZoneIndex"] = dev.activeZone
- props["PauseScheduleRemainingZoneDuration"] = 15 # plugin needs to calc and store remaining duration for active zone
- props["ScheduledZoneDurations"] = '' # empty so UI doesn't show active schedule
- dev.replacePluginPropsOnServer(props)
- dev.updateStateOnServer("activeZone", 0)
-
- ###### RESUME SCHEDULE ######
- elif action.sprinklerAction == indigo.kSprinklerAction.ResumeSchedule:
- # Plugin should resume the active schedule here and tell the device
- # to turn on the paused zone, _or_ (if supported by the device) send
- # the device a resume command.
- # ** IMPLEMENT ME **
-
- # Plugin will then need to update the ScheduledZoneDurations property
- # and the activeZone state appropriately.
- props = dev.pluginProps
- if "PreviousZoneDurations" in props and "PauseScheduleZoneIndex" in props and "PauseScheduleRemainingZoneDuration" in props:
- indigo.server.log(u"resuming \"%s\" schedule zone durations: %s" % (dev.name, props["PreviousZoneDurations"]))
-
- resumeZone = int(props["PauseScheduleZoneIndex"])
- resumeDuration = int(props["PauseScheduleRemainingZoneDuration"])
-
- props["PauseScheduleZoneIndex"] = 0
- props["PauseScheduleRemainingZoneDuration"] = 0
- props["ScheduledZoneDurations"] = props["PreviousZoneDurations"]
- dev.replacePluginPropsOnServer(props)
- dev.updateStateOnServer("activeZone", resumeZone)
-
- # Plugin should now use resumeDuration for its own internal timer of how long
- # the activeZone (resumeZone) should remain ON before advancing to next zone.
-
- ###### STOP SCHEDULE ######
- elif action.sprinklerAction == indigo.kSprinklerAction.StopSchedule:
- # Plugin should stop the active schedule here and tell the device
- # to turn off all zones, _or_ (if supported by the device) send
- # the device both a stop schedule and all zones off command.
- # ** IMPLEMENT ME **
- indigo.server.log(u"stopping \"%s\" schedule" % (dev.name))
-
- # Clear out ScheduledZoneDurations so the UI doesn't show an active schedule anymore.
- props = dev.pluginProps
- props["PauseScheduleZoneIndex"] = 0
- props["PauseScheduleRemainingZoneDuration"] = 0
- props["ScheduledZoneDurations"] = ''
- dev.replacePluginPropsOnServer(props)
-
- # Plugin will then need to update the activeZone state appropriately.
- dev.updateStateOnServer("activeZone", 0)
-
- ###### JUMP TO PREVIOUS ZONE ######
- elif action.sprinklerAction == indigo.kSprinklerAction.PreviousZone:
- # Plugin should jump to the previous zone in the current
- # schedule here and tell the device to turn that zone on, _or_
- # (if supported by the device) send the device a previous zone
- # command.
- # ** IMPLEMENT ME **
- indigo.server.log(u"skipping \"%s\" to previous zone" % (dev.name))
-
- # Plugin will then need to update the activeZone state appropriately.
- # dev.updateStateOnServer("activeZone", current zone - 1)
-
- ###### SKIP TO NEXT ZONE ######
- elif action.sprinklerAction == indigo.kSprinklerAction.NextZone:
- # Plugin should jump to the next zone in the current schedule
- # here and tell the device to turn that zone on, _or_ (if
- # supported by the device) send the device a next zone command.
- # ** IMPLEMENT ME **
- indigo.server.log(u"advancing \"%s\" to next zone" % (dev.name))
-
- # Plugin will then need to update the activeZone state appropriately.
- # dev.updateStateOnServer("activeZone", current zone + 1)
-
- ########################################
- # General Action callback
- ######################
- def actionControlUniversal(self, action, dev):
- ###### BEEP ######
- if action.deviceAction == indigo.kUniversalAction.Beep:
- # Beep the hardware module (dev) here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "beep request"))
-
- ###### ENERGY UPDATE ######
- elif action.deviceAction == indigo.kUniversalAction.EnergyUpdate:
- # Request hardware module (dev) for its most recent meter data here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "energy update request"))
-
- ###### ENERGY RESET ######
- elif action.deviceAction == indigo.kUniversalAction.EnergyReset:
- # Request that the hardware module (dev) reset its accumulative energy usage data here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "energy reset request"))
-
- ###### STATUS REQUEST ######
- elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
- # Query hardware module (dev) for its current status here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "status request"))
-
- ########################################
- # Custom Plugin Action callbacks (defined in Actions.xml)
- ######################
- def setBacklightBrightness(self, pluginAction, dev):
- try:
- newBrightness = int(pluginAction.props.get(u"brightness", 100))
- except ValueError:
- # The int() cast above might fail if the user didn't enter a number:
- indigo.server.log(u"set backlight brightness action to device \"%s\" -- invalid brightness value" % (dev.name,), isError=True)
- return
-
- # Command hardware module (dev) to set backlight brightness here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %d" % (dev.name, "set backlight brightness", newBrightness))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("backlightBrightness", newBrightness)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %d failed" % (dev.name, "set backlight brightness", newBrightness), isError=True)
-
+ ########################################
+ def __init__(self, plugin_id, plugin_display_name, plugin_version, plugin_prefs):
+ super().__init__(plugin_id, plugin_display_name, plugin_version, plugin_prefs)
+ self.debug = True
+
+ ########################################
+ def startup(self):
+ # self.logger.debug("startup called")
+ pass
+
+ def shutdown(self):
+ # self.logger.debug("shutdown called")
+ pass
+
+ ########################################
+ def validateDeviceConfigUi(self, values_dict, type_id, dev_id):
+ return (True, values_dict)
+
+ ########################################
+ # Sprinkler Control Action callback
+ ######################
+ def actionControlSprinkler(self, action, dev):
+ ########################################
+ # Required plugin sprinkler actions: These actions must be handled by the plugin.
+ ########################################
+ ###### ZONE ON ######
+ if action.sprinklerAction == indigo.kSprinklerAction.ZoneOn:
+ # Command hardware module (dev) to turn ON a specific zone here.
+ # ** IMPLEMENT ME **
+ zone_name = "no zone"
+ if action.zoneIndex is not None:
+ zone_name = dev.zoneNames[action.zoneIndex - 1]
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name} - {zone_name}\" on")
+
+ # And then tell the Indigo Server to update the state.
+ dev.updateStateOnServer("activeZone", action.zoneIndex)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name} - {zone_name}\" on failed")
+
+ ###### ALL ZONES OFF ######
+ elif action.sprinklerAction == indigo.kSprinklerAction.AllZonesOff:
+ # Command hardware module (dev) to turn OFF here:
+ # ** IMPLEMENT ME **
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" all zones off")
+
+ # And then tell the Indigo Server to update the state.
+ dev.updateStateOnServer("activeZone", 0)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" all zones off failed")
+
+ ########################################
+ # Optional plugin sprinkler actions: These actions are *only* dispatched to the plugin
+ # if the device property "OverrideScheduleActions" is set to True. The default behavior
+ # (False) is for the Indigo Server to handle these higher level commands and scheduling
+ # automatically, which will dispatch the required lower-level indigo.kSprinklerAction.ZoneOn
+ # and indigo.kSprinklerAction.AllZonesOff actions above at the appropriate times.
+ #
+ # Note if a plugin defines the higher level actions below then it must handle all zone
+ # scheduling, pausing, resuming, and next/previous skipping. Given the complexity in
+ # handling the individual zone scheduling, pausing, resuming, and next/previous zones
+ # it is recommended to use the default value of OverrideScheduleActions False, so that
+ # IndigoServer can handle this higher level scheduling and complexity.
+ ########################################
+ ###### RUN SCHEDULE OF ZONE DURATIONS ######
+ elif action.sprinklerAction == indigo.kSprinklerAction.RunNewSchedule:
+ # Plugin should handle its own scheduling here and tell the device
+ # to turn on the first zone in the schedule, _or_ (if supported by
+ # the device) send the entire schedule to the device.
+ # ** IMPLEMENT ME **
+ self.logger.info(f"scheduled \"{dev.name}\" zone durations: {action.zoneDurations}")
+
+ # The ScheduledZoneDurations property is used by Indigo to show the
+ # currently running schedule (in the client, Web, and Indigo Touch UI),
+ # so set based on the durations requested in the action.
+ props = dev.pluginProps
+ # Plugin should use dev.zoneEnableList, dev.zoneMaxDurations and
+ # dev.zoneCount to make sure action.zoneDurations are within the
+ # range and bounds specified.
+ zone_list_str = ', '.join(str(dur) for dur in action.zoneDurations)
+ props["PreviousZoneDurations"] = zone_list_str
+ props["ScheduledZoneDurations"] = zone_list_str
+ dev.replacePluginPropsOnServer(props)
+
+ # Plugin will then need to update the activeZone state appropriately.
+ # As an example here we'll just turn on zone 1 (plugin should really
+ # inspect action.zoneDurations for the first non-zero item).
+ dev.updateStateOnServer("activeZone", 1)
+
+ ###### RUN LAST USED SCHEDULE ######
+ elif action.sprinklerAction == indigo.kSprinklerAction.RunPreviousSchedule:
+ # Plugin should re-run the last schedule that was used here and tell
+ # the device to turn on the first zone in the schedule, _or_ (if
+ # supported by the device) send the device a run last schedule command.
+ # ** IMPLEMENT ME **
+
+ # Plugin will then need to update the ScheduledZoneDurations property
+ # and the activeZone state appropriately.
+ props = dev.pluginProps
+ if "PreviousZoneDurations" in props:
+ self.logger.info(f"running last used scheduled for \"{dev.name}\": {props['PreviousZoneDurations']}")
+
+ props["ScheduledZoneDurations"] = props["PreviousZoneDurations"]
+ dev.replacePluginPropsOnServer(props)
+ dev.updateStateOnServer("activeZone", 1)
+
+ ###### PAUSE SCHEDULE ######
+ elif action.sprinklerAction == indigo.kSprinklerAction.PauseSchedule:
+ # Plugin should pause its schedule here and tell the device to
+ # turn off the active zone, _or_ (if supported by the device)
+ # send the device a pause command.
+ # ** IMPLEMENT ME **
+ self.logger.info(f"pausing \"{dev.name}\" schedule")
+
+ # Plugin will then need to update the ScheduledZoneDurations property
+ # and the activeZone state appropriately.
+ props = dev.pluginProps
+ props["PauseScheduleZoneIndex"] = dev.activeZone
+ props["PauseScheduleRemainingZoneDuration"] = 15 # plugin needs to calc and store remaining duration for active zone
+ props["ScheduledZoneDurations"] = '' # empty so UI doesn't show active schedule
+ dev.replacePluginPropsOnServer(props)
+ dev.updateStateOnServer("activeZone", 0)
+
+ ###### RESUME SCHEDULE ######
+ elif action.sprinklerAction == indigo.kSprinklerAction.ResumeSchedule:
+ # Plugin should resume the active schedule here and tell the device
+ # to turn on the paused zone, _or_ (if supported by the device) send
+ # the device a resume command.
+ # ** IMPLEMENT ME **
+
+ # Plugin will then need to update the ScheduledZoneDurations property
+ # and the activeZone state appropriately.
+ props = dev.pluginProps
+ if "PreviousZoneDurations" in props and "PauseScheduleZoneIndex" in props and "PauseScheduleRemainingZoneDuration" in props:
+ self.logger.info(f"resuming \"{dev.name}\" schedule zone durations: {props['PreviousZoneDurations']}")
+
+ resume_zone = int(props["PauseScheduleZoneIndex"])
+ resume_duration = int(props["PauseScheduleRemainingZoneDuration"])
+
+ props["PauseScheduleZoneIndex"] = 0
+ props["PauseScheduleRemainingZoneDuration"] = 0
+ props["ScheduledZoneDurations"] = props["PreviousZoneDurations"]
+ dev.replacePluginPropsOnServer(props)
+ dev.updateStateOnServer("activeZone", resume_zone)
+
+ # Plugin should now use resume_duration for its own internal timer of how long
+ # the activeZone (resume_zone) should remain ON before advancing to next zone.
+
+ ###### STOP SCHEDULE ######
+ elif action.sprinklerAction == indigo.kSprinklerAction.StopSchedule:
+ # Plugin should stop the active schedule here and tell the device
+ # to turn off all zones, _or_ (if supported by the device) send
+ # the device both a stop schedule and all zones off command.
+ # ** IMPLEMENT ME **
+ self.logger.info(f"stopping \"{dev.name}\" schedule")
+
+ # Clear out ScheduledZoneDurations so the UI doesn't show an active schedule anymore.
+ props = dev.pluginProps
+ props["PauseScheduleZoneIndex"] = 0
+ props["PauseScheduleRemainingZoneDuration"] = 0
+ props["ScheduledZoneDurations"] = ''
+ dev.replacePluginPropsOnServer(props)
+
+ # Plugin will then need to update the activeZone state appropriately.
+ dev.updateStateOnServer("activeZone", 0)
+
+ ###### JUMP TO PREVIOUS ZONE ######
+ elif action.sprinklerAction == indigo.kSprinklerAction.PreviousZone:
+ # Plugin should jump to the previous zone in the current
+ # schedule here and tell the device to turn that zone on, _or_
+ # (if supported by the device) send the device a previous zone
+ # command.
+ # ** IMPLEMENT ME **
+ self.logger.info(f"skipping \"{dev.name}\" to previous zone")
+
+ # Plugin will then need to update the activeZone state appropriately.
+ # dev.updateStateOnServer("activeZone", current zone - 1)
+
+ ###### SKIP TO NEXT ZONE ######
+ elif action.sprinklerAction == indigo.kSprinklerAction.NextZone:
+ # Plugin should jump to the next zone in the current schedule
+ # here and tell the device to turn that zone on, _or_ (if
+ # supported by the device) send the device a next zone command.
+ # ** IMPLEMENT ME **
+ self.logger.info(f"advancing \"{dev.name}\" to next zone")
+
+ # Plugin will then need to update the activeZone state appropriately.
+ # dev.updateStateOnServer("activeZone", current zone + 1)
+
+ ########################################
+ # General Action callback
+ ######################
+ def actionControlUniversal(self, action, dev):
+ ###### BEEP ######
+ if action.deviceAction == indigo.kUniversalAction.Beep:
+ # Beep the hardware module (dev) here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" beep request")
+
+ ###### ENERGY UPDATE ######
+ elif action.deviceAction == indigo.kUniversalAction.EnergyUpdate:
+ # Request hardware module (dev) for its most recent meter data here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" energy update request")
+
+ ###### ENERGY RESET ######
+ elif action.deviceAction == indigo.kUniversalAction.EnergyReset:
+ # Request that the hardware module (dev) reset its accumulative energy usage data here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" energy reset request")
+
+ ###### STATUS REQUEST ######
+ elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
+ # Query hardware module (dev) for its current status here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" status request")
+
+ ########################################
+ # Custom Plugin Action callbacks (defined in Actions.xml)
+ ######################
+ def set_backlight_brightness(self, plugin_action, dev):
+ try:
+ new_brightness = int(plugin_action.props.get("brightness", 100))
+ except ValueError:
+ # The int() cast above might fail if the user didn't enter a number:
+ self.logger.error(f"set backlight brightness action to device \"{dev.name}\" -- invalid brightness value")
+ return
+ # Command hardware module (dev) to set backlight brightness here:
+ # FIXME: add implementation here
+ send_success = True # Set to False if it failed.
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" set backlight brightness to {new_brightness}")
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("backlightBrightness", new_brightness)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" set backlight brightness to {new_brightness} failed")
diff --git a/Example Device - Thermostat.indigoPlugin/Contents/Info.plist b/Example Device - Thermostat.indigoPlugin/Contents/Info.plist
index e0d0300..358ebb1 100644
--- a/Example Device - Thermostat.indigoPlugin/Contents/Info.plist
+++ b/Example Device - Thermostat.indigoPlugin/Contents/Info.plist
@@ -2,24 +2,24 @@
- PluginVersion
- 2021.1.0
- ServerApiVersion
- 2.5
- IwsApiVersion
- 1.0.0
- CFBundleDisplayName
- Example Device - Thermostat
- CFBundleIdentifier
- com.perceptiveautomation.indigoplugin.example-device-thermo1
- CFBundleVersion
- 1.0.0
- CFBundleURLTypes
-
-
- CFBundleURLName
- http://wiki.indigodomo.com/doku.php?id=plugins:example_dev_thermo_1
-
-
+ PluginVersion
+ 2022.1.0
+ ServerApiVersion
+ 3.0
+ IwsApiVersion
+ 1.0.0
+ CFBundleDisplayName
+ Example Device - Thermostat
+ CFBundleIdentifier
+ com.perceptiveautomation.indigoplugin.example-device-thermo1
+ CFBundleVersion
+ 1.0.0
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ https://wiki.indigodomo.com/doku.php?id=plugins:example_dev_thermo_1
+
+
diff --git a/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/Actions.xml b/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/Actions.xml
index 640119e..d0520a6 100644
--- a/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/Actions.xml
+++ b/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/Actions.xml
@@ -1,24 +1,24 @@
-
- Set Backlight Brightness
- setBacklightBrightness
-
-
-
-
-
-
-
-
-
+
+ Set Backlight Brightness
+ set_backlight_brightness
+
+
+
+
+
+
+
+
+
diff --git a/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/Devices.xml b/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/Devices.xml
index 404adfd..46b8d8e 100644
--- a/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/Devices.xml
+++ b/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/Devices.xml
@@ -1,141 +1,141 @@
-
-
- Example Thermostat Module
-
-
-
-
-
-
+
+ Example Thermostat Module
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Show heat setpoint controls in UI
-
-
-
- Show cool setpoint controls in UI
-
-
-
- Show thermostat mode controls (heat/cool/auto) in UI
-
-
-
- Show fan mode controls (auto/always on) in UI
-
-
-
- Show compressor/furnace states in UI
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Show heat setpoint controls in UI
+
+
+
+ Show cool setpoint controls in UI
+
+
+
+ Show thermostat mode controls (heat/cool/auto) in UI
+
+
+
+ Show fan mode controls (auto/always on) in UI
+
+
+
+ Show compressor/furnace states in UI
+
+
+
+
-
- Integer
- Backlight Brightness
- Backlight Brightness
-
-
-
+ The plugin can specify additional custom states and custom
+ actions (in Actions.xml) to modify custom states. As an example
+ here, we define a new custom state, backlightBrightness, which
+ is used to control the brightness of the backlit display of
+ the thermostat.
+ -->
+
+ Integer
+ Backlight Brightness
+ Backlight Brightness
+
+
+
diff --git a/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/MenuItems.xml b/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/MenuItems.xml
index d14a46e..3132c73 100644
--- a/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/MenuItems.xml
+++ b/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/MenuItems.xml
@@ -1,37 +1,37 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/plugin.py b/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/plugin.py
index 616e062..b3cce89 100644
--- a/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/plugin.py
+++ b/Example Device - Thermostat.indigoPlugin/Contents/Server Plugin/plugin.py
@@ -1,8 +1,8 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
####################
-# Copyright (c) 2016, Perceptive Automation, LLC. All rights reserved.
-# http://www.indigodomo.com
+# Copyright (c) 2022, Perceptive Automation, LLC. All rights reserved.
+# https://www.indigodomo.com
import indigo
@@ -14,380 +14,380 @@
# our global name space by the host process.
################################################################################
-kHvacModeEnumToStrMap = {
- indigo.kHvacMode.Cool : u"cool",
- indigo.kHvacMode.Heat : u"heat",
- indigo.kHvacMode.HeatCool : u"auto",
- indigo.kHvacMode.Off : u"off",
- indigo.kHvacMode.ProgramHeat : u"program heat",
- indigo.kHvacMode.ProgramCool : u"program cool",
- indigo.kHvacMode.ProgramHeatCool : u"program auto"
+HVAC_MODE_ENUM_TO_STR_MAP = {
+ indigo.kHvacMode.Cool : "cool",
+ indigo.kHvacMode.Heat : "heat",
+ indigo.kHvacMode.HeatCool : "auto",
+ indigo.kHvacMode.Off : "off",
+ indigo.kHvacMode.ProgramHeat : "program heat",
+ indigo.kHvacMode.ProgramCool : "program cool",
+ indigo.kHvacMode.ProgramHeatCool : "program auto"
}
-kFanModeEnumToStrMap = {
- indigo.kFanMode.AlwaysOn : u"always on",
- indigo.kFanMode.Auto : u"auto"
+FAN_MODE_ENUM_TO_STR_MAP = {
+ indigo.kFanMode.AlwaysOn : "always on",
+ indigo.kFanMode.Auto : "auto"
}
-def _lookupActionStrFromHvacMode(hvacMode):
- return kHvacModeEnumToStrMap.get(hvacMode, u"unknown")
+def _lookup_action_str_from_hvac_mode(hvac_mode):
+ return HVAC_MODE_ENUM_TO_STR_MAP.get(hvac_mode, "unknown")
-def _lookupActionStrFromFanMode(fanMode):
- return kFanModeEnumToStrMap.get(fanMode, u"unknown")
+def _lookup_action_str_from_fan_mode(fan_mode):
+ return FAN_MODE_ENUM_TO_STR_MAP.get(fan_mode, "unknown")
################################################################################
class Plugin(indigo.PluginBase):
- ########################################
- def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs):
- super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs)
- self.debug = False
- self.simulateTempChanges = True # Every few seconds update to random temperature values
- self.simulateHumidityChanges = True # Every few seconds update to random humidity values
- self.refreshDelay = 2 # Simulate new temperature values every 2 seconds
-
- ########################################
- # Internal utility methods. Some of these are useful to provide
- # a higher-level abstraction for accessing/changing thermostat
- # properties or states.
- ######################
- def _changeTempSensorCount(self, dev, count):
- newProps = dev.pluginProps
- newProps["NumTemperatureInputs"] = count
- dev.replacePluginPropsOnServer(newProps)
-
- def _changeHumiditySensorCount(self, dev, count):
- newProps = dev.pluginProps
- newProps["NumHumidityInputs"] = count
- dev.replacePluginPropsOnServer(newProps)
-
- def _changeAllTempSensorCounts(self, count):
- for dev in indigo.devices.iter("self"):
- self._changeTempSensorCount(dev, count)
-
- def _changeAllHumiditySensorCounts(self, count):
- for dev in indigo.devices.iter("self"):
- self._changeHumiditySensorCount(dev, count)
-
- ######################
- def _changeTempSensorValue(self, dev, index, value, keyValueList):
- # Update the temperature value at index. If index is greater than the "NumTemperatureInputs"
- # an error will be displayed in the Event Log "temperature index out-of-range"
- stateKey = u"temperatureInput" + str(index)
- keyValueList.append({'key':stateKey, 'value':value, 'uiValue':"%d °F" % (value)})
- self.debugLog(u"\"%s\" updating %s %d" % (dev.name, stateKey, value))
-
- def _changeHumiditySensorValue(self, dev, index, value, keyValueList):
- # Update the humidity value at index. If index is greater than the "NumHumidityInputs"
- # an error will be displayed in the Event Log "humidity index out-of-range"
- stateKey = u"humidityInput" + str(index)
- keyValueList.append({'key':stateKey, 'value':value, 'uiValue':"%d%%" % (value)})
- self.debugLog(u"\"%s\" updating %s %d" % (dev.name, stateKey, value))
-
- ######################
- # Poll all of the states from the thermostat and pass new values to
- # Indigo Server.
- def _refreshStatesFromHardware(self, dev, logRefresh, commJustStarted):
- # As an example here we update the temperature and humidity
- # sensor states to random values.
- keyValueList = []
- if self.simulateTempChanges:
- # Simulate changing temperature values coming in from the
- # hardware by updating all temp values randomly:
- numTemps = dev.temperatureSensorCount
- for index in range(1, numTemps + 1):
- exampleTemp = random.randint(62, 88)
- self._changeTempSensorValue(dev, index, exampleTemp, keyValueList)
- if logRefresh:
- indigo.server.log(u"received \"%s\" temperature%d update to %.1f°" % (dev.name, index, exampleTemp))
- if dev.pluginProps.get("ShowCoolHeatEquipmentStateUI", False) and "hvacOperationMode" in dev.states and "setpointCool" in dev.states and "setpointHeat" in dev.states:
- if dev.states["hvacOperationMode"] in [indigo.kHvacMode.Cool, indigo.kHvacMode.HeatCool, indigo.kHvacMode.ProgramCool, indigo.kHvacMode.ProgramHeatCool]:
- keyValueList.append({'key':'hvacCoolerIsOn', 'value':exampleTemp > dev.states["setpointCool"]})
- if dev.states["hvacOperationMode"] in [indigo.kHvacMode.Heat, indigo.kHvacMode.HeatCool, indigo.kHvacMode.ProgramHeat, indigo.kHvacMode.ProgramHeatCool]:
- keyValueList.append({'key':'hvacHeaterIsOn', 'value':exampleTemp < dev.states["setpointHeat"]})
- if self.simulateHumidityChanges:
- # Simulate changing humidity values coming in from the
- # hardware by updating all humidity values randomly:
- numSensors = dev.humiditySensorCount
- for index in range(1, numSensors + 1):
- exampleHumidity = random.randint(15, 90)
- self._changeHumiditySensorValue(dev, index, exampleHumidity, keyValueList)
- if logRefresh:
- indigo.server.log(u"received \"%s\" humidity%d update to %.0f%%" % (dev.name, index, exampleHumidity))
-
- # Other states that should also be updated:
- # ** IMPLEMENT ME **
- # keyValueList.append({'key':'setpointHeat', 'value':floating number here})
- # keyValueList.append({'key':'setpointCool', 'value':floating number here})
- # keyValueList.append({'key':'hvacOperationMode', 'value':some indigo.kHvacMode.* value here})
- # keyValueList.append({'key':'hvacFanMode', 'value':some indigo.kFanMode.* value here})
- # keyValueList.append({'key':'hvacCoolerIsOn', 'value':True or False here})
- # keyValueList.append({'key':'hvacHeaterIsOn', 'value':True or False here})
- # keyValueList.append({'key':'hvacFanIsOn', 'value':True or False here})
- if commJustStarted:
- # As an example, we force these thermostat states to specific values.
- if "setpointHeat" in dev.states:
- keyValueList.append({'key':'setpointHeat', 'value':66.5, 'uiValue':"66.5 °F"})
- if "setpointCool" in dev.states:
- keyValueList.append({'key':'setpointCool', 'value':77.5, 'uiValue':"77.5 °F"})
- if "hvacOperationMode" in dev.states:
- keyValueList.append({'key':'hvacOperationMode', 'value':indigo.kHvacMode.HeatCool})
- if "hvacFanMode" in dev.states:
- keyValueList.append({'key':'hvacFanMode', 'value':indigo.kFanMode.Auto})
- keyValueList.append({'key':'backlightBrightness', 'value':85, 'uiValue':"85%"})
-
- if len(keyValueList) > 0:
- dev.updateStatesOnServer(keyValueList)
-
- if logRefresh:
- if "setpointHeat" in dev.states:
- indigo.server.log(u"received \"%s\" cool setpoint update to %.1f°" % (dev.name, dev.states["setpointHeat"]))
- if "setpointCool" in dev.states:
- indigo.server.log(u"received \"%s\" heat setpoint update to %.1f°" % (dev.name, dev.states["setpointCool"]))
- if "hvacOperationMode" in dev.states:
- indigo.server.log(u"received \"%s\" main mode update to %s" % (dev.name, _lookupActionStrFromHvacMode(dev.states["hvacOperationMode"])))
- if "hvacFanMode" in dev.states:
- indigo.server.log(u"received \"%s\" fan mode update to %s" % (dev.name, _lookupActionStrFromFanMode(dev.states["hvacFanMode"])))
- indigo.server.log(u"received \"%s\" backlight brightness update to %d%%" % (dev.name, dev.states["backlightBrightness"]))
-
- ######################
- # Process action request from Indigo Server to change main thermostat's main mode.
- def _handleChangeHvacModeAction(self, dev, newHvacMode):
- # Command hardware module (dev) to change the thermostat mode here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- actionStr = _lookupActionStrFromHvacMode(newHvacMode)
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" mode change to %s" % (dev.name, actionStr))
-
- # And then tell the Indigo Server to update the state.
- if "hvacOperationMode" in dev.states:
- dev.updateStateOnServer("hvacOperationMode", newHvacMode)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" mode change to %s failed" % (dev.name, actionStr), isError=True)
-
- ######################
- # Process action request from Indigo Server to change thermostat's fan mode.
- def _handleChangeFanModeAction(self, dev, newFanMode):
- # Command hardware module (dev) to change the fan mode here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- actionStr = _lookupActionStrFromFanMode(newFanMode)
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" fan mode change to %s" % (dev.name, actionStr))
-
- # And then tell the Indigo Server to update the state.
- if "hvacFanMode" in dev.states:
- dev.updateStateOnServer("hvacFanMode", newFanMode)
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" fan mode change to %s failed" % (dev.name, actionStr), isError=True)
-
- ######################
- # Process action request from Indigo Server to change a cool/heat setpoint.
- def _handleChangeSetpointAction(self, dev, newSetpoint, logActionName, stateKey):
- if newSetpoint < 40.0:
- newSetpoint = 40.0 # Arbitrary -- set to whatever hardware minimum setpoint value is.
- elif newSetpoint > 95.0:
- newSetpoint = 95.0 # Arbitrary -- set to whatever hardware maximum setpoint value is.
-
- sendSuccess = False
-
- if stateKey == u"setpointCool":
- # Command hardware module (dev) to change the cool setpoint to newSetpoint here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
- elif stateKey == u"setpointHeat":
- # Command hardware module (dev) to change the heat setpoint to newSetpoint here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %.1f°" % (dev.name, logActionName, newSetpoint))
-
- # And then tell the Indigo Server to update the state.
- if stateKey in dev.states:
- dev.updateStateOnServer(stateKey, newSetpoint, uiValue="%.1f °F" % (newSetpoint))
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %.1f° failed" % (dev.name, logActionName, newSetpoint), isError=True)
-
- ########################################
- def startup(self):
- self.debugLog(u"startup called")
-
- def shutdown(self):
- self.debugLog(u"shutdown called")
-
- ########################################
- def runConcurrentThread(self):
- try:
- while True:
- for dev in indigo.devices.iter("self"):
- if not dev.enabled or not dev.configured:
- continue
-
- # Plugins that need to poll out the status from the thermostat
- # could do so here, then broadcast back the new values to the
- # Indigo Server.
- self._refreshStatesFromHardware(dev, False, False)
-
- self.sleep(self.refreshDelay)
- except self.StopThread:
- pass # Optionally catch the StopThread exception and do any needed cleanup.
-
- ########################################
- def validateDeviceConfigUi(self, valuesDict, typeId, devId):
- return (True, valuesDict)
-
- ########################################
- def deviceStartComm(self, dev):
- # Called when communication with the hardware should be established.
- # Here would be a good place to poll out the current states from the
- # thermostat. If periodic polling of the thermostat is needed (that
- # is, it doesn't broadcast changes back to the plugin somehow), then
- # consider adding that to runConcurrentThread() above.
- self._refreshStatesFromHardware(dev, True, True)
-
- def deviceStopComm(self, dev):
- # Called when communication with the hardware should be shutdown.
- pass
-
- ########################################
- # Thermostat Action callback
- ######################
- # Main thermostat action bottleneck called by Indigo Server.
- def actionControlThermostat(self, action, dev):
- ###### SET HVAC MODE ######
- if action.thermostatAction == indigo.kThermostatAction.SetHvacMode:
- self._handleChangeHvacModeAction(dev, action.actionMode)
-
- ###### SET FAN MODE ######
- elif action.thermostatAction == indigo.kThermostatAction.SetFanMode:
- self._handleChangeFanModeAction(dev, action.actionMode)
-
- ###### SET COOL SETPOINT ######
- elif action.thermostatAction == indigo.kThermostatAction.SetCoolSetpoint:
- newSetpoint = action.actionValue
- self._handleChangeSetpointAction(dev, newSetpoint, u"change cool setpoint", u"setpointCool")
-
- ###### SET HEAT SETPOINT ######
- elif action.thermostatAction == indigo.kThermostatAction.SetHeatSetpoint:
- newSetpoint = action.actionValue
- self._handleChangeSetpointAction(dev, newSetpoint, u"change heat setpoint", u"setpointHeat")
-
- ###### DECREASE/INCREASE COOL SETPOINT ######
- elif action.thermostatAction == indigo.kThermostatAction.DecreaseCoolSetpoint:
- newSetpoint = dev.coolSetpoint - action.actionValue
- self._handleChangeSetpointAction(dev, newSetpoint, u"decrease cool setpoint", u"setpointCool")
-
- elif action.thermostatAction == indigo.kThermostatAction.IncreaseCoolSetpoint:
- newSetpoint = dev.coolSetpoint + action.actionValue
- self._handleChangeSetpointAction(dev, newSetpoint, u"increase cool setpoint", u"setpointCool")
-
- ###### DECREASE/INCREASE HEAT SETPOINT ######
- elif action.thermostatAction == indigo.kThermostatAction.DecreaseHeatSetpoint:
- newSetpoint = dev.heatSetpoint - action.actionValue
- self._handleChangeSetpointAction(dev, newSetpoint, u"decrease heat setpoint", u"setpointHeat")
-
- elif action.thermostatAction == indigo.kThermostatAction.IncreaseHeatSetpoint:
- newSetpoint = dev.heatSetpoint + action.actionValue
- self._handleChangeSetpointAction(dev, newSetpoint, u"increase heat setpoint", u"setpointHeat")
-
- ###### REQUEST STATE UPDATES ######
- elif action.thermostatAction in [indigo.kThermostatAction.RequestStatusAll, indigo.kThermostatAction.RequestMode,
- indigo.kThermostatAction.RequestEquipmentState, indigo.kThermostatAction.RequestTemperatures, indigo.kThermostatAction.RequestHumidities,
- indigo.kThermostatAction.RequestDeadbands, indigo.kThermostatAction.RequestSetpoints]:
- self._refreshStatesFromHardware(dev, True, False)
-
- ########################################
- # General Action callback
- ######################
- def actionControlUniversal(self, action, dev):
- ###### BEEP ######
- if action.deviceAction == indigo.kUniversalAction.Beep:
- # Beep the hardware module (dev) here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "beep request"))
-
- ###### ENERGY UPDATE ######
- elif action.deviceAction == indigo.kUniversalAction.EnergyUpdate:
- # Request hardware module (dev) for its most recent meter data here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "energy update request"))
-
- ###### ENERGY RESET ######
- elif action.deviceAction == indigo.kUniversalAction.EnergyReset:
- # Request that the hardware module (dev) reset its accumulative energy usage data here:
- # ** IMPLEMENT ME **
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "energy reset request"))
-
- ###### STATUS REQUEST ######
- elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
- # Query hardware module (dev) for its current status here. This differs from the
- # indigo.kThermostatAction.RequestStatusAll action - for instance, if your thermo
- # is battery powered you might only want to update it only when the user uses
- # this status request (and not from the RequestStatusAll). This action would
- # get all possible information from the thermostat and the other call
- # would only get thermostat-specific information:
- # ** GET BATTERY INFO **
- # and call the common function to update the thermo-specific data
- self._refreshStatesFromHardware(dev, True, False)
- indigo.server.log(u"sent \"%s\" %s" % (dev.name, "status request"))
-
- ########################################
- # Custom Plugin Action callbacks (defined in Actions.xml)
- ######################
- def setBacklightBrightness(self, pluginAction, dev):
- try:
- newBrightness = int(pluginAction.props.get(u"brightness", 100))
- except ValueError:
- # The int() cast above might fail if the user didn't enter a number:
- indigo.server.log(u"set backlight brightness action to device \"%s\" -- invalid brightness value" % (dev.name,), isError=True)
- return
-
- # Command hardware module (dev) to set backlight brightness here:
- # ** IMPLEMENT ME **
- sendSuccess = True # Set to False if it failed.
-
- if sendSuccess:
- # If success then log that the command was successfully sent.
- indigo.server.log(u"sent \"%s\" %s to %d" % (dev.name, "set backlight brightness", newBrightness))
-
- # And then tell the Indigo Server to update the state:
- dev.updateStateOnServer("backlightBrightness", newBrightness, uiValue="%d%%" % (newBrightness))
- else:
- # Else log failure but do NOT update state on Indigo Server.
- indigo.server.log(u"send \"%s\" %s to %d failed" % (dev.name, "set backlight brightness", newBrightness), isError=True)
-
- ########################################
- # Actions defined in MenuItems.xml. In this case we just use these menu actions to
- # simulate different thermostat configurations (how many temperature and humidity
- # sensors they have).
- ####################
- def changeTempSensorCountTo1(self):
- self._changeAllTempSensorCounts(1)
-
- def changeTempSensorCountTo2(self):
- self._changeAllTempSensorCounts(2)
-
- def changeTempSensorCountTo3(self):
- self._changeAllTempSensorCounts(3)
-
- def changeHumiditySensorCountTo0(self):
- self._changeAllHumiditySensorCounts(0)
-
- def changeHumiditySensorCountTo1(self):
- self._changeAllHumiditySensorCounts(1)
-
- def changeHumiditySensorCountTo2(self):
- self._changeAllHumiditySensorCounts(2)
-
- def changeHumiditySensorCountTo3(self):
- self._changeAllHumiditySensorCounts(3)
+ ########################################
+ def __init__(self, plugin_id, plugin_display_name, plugin_version, plugin_prefs):
+ super().__init__(plugin_id, plugin_display_name, plugin_version, plugin_prefs)
+ self.debug = False
+ self.simulate_temp_changes = True # Every few seconds update to random temperature values
+ self.simulate_humidity_changes = True # Every few seconds update to random humidity values
+ self.refresh_delay = 2 # Simulate new temperature values every 2 seconds
+
+ ########################################
+ # Internal utility methods. Some of these are useful to provide
+ # a higher-level abstraction for accessing/changing thermostat
+ # properties or states.
+ ######################
+ def _change_temp_sensor_count(self, dev, count):
+ new_props = dev.pluginProps
+ new_props["NumTemperatureInputs"] = count
+ dev.replacePluginPropsOnServer(new_props)
+
+ def _change_humidity_sensor_count(self, dev, count):
+ new_props = dev.pluginProps
+ new_props["NumHumidityInputs"] = count
+ dev.replacePluginPropsOnServer(new_props)
+
+ def _change_all_temp_sensor_counts(self, count):
+ for dev in indigo.devices.iter("self"):
+ self._change_temp_sensor_count(dev, count)
+
+ def _change_all_humidity_sensor_counts(self, count):
+ for dev in indigo.devices.iter("self"):
+ self._change_humidity_sensor_count(dev, count)
+
+ ######################
+ def _change_temp_sensor_value(self, dev, index, value, key_val_list):
+ # Update the temperature value at index. If index is greater than the "NumTemperatureInputs"
+ # an error will be displayed in the Event Log "temperature index out-of-range"
+ state_key = "temperatureInput" + str(index)
+ key_val_list.append({'key':state_key, 'value':value, 'uiValue':f"{value} °F"})
+ self.logger.debug(f"\"{dev.name}\" updating {state_key} {value}")
+
+ def _change_humidity_sensor_value(self, dev, index, value, key_val_list):
+ # Update the humidity value at index. If index is greater than the "NumHumidityInputs"
+ # an error will be displayed in the Event Log "humidity index out-of-range"
+ state_key = "humidityInput" + str(index)
+ key_val_list.append({'key':state_key, 'value':value, 'uiValue':f"{value}%"})
+ self.logger.debug(f"\"{dev.name}\" updating {state_key} {value}")
+
+ ######################
+ # Poll all of the states from the thermostat and pass new values to
+ # Indigo Server.
+ def _refresh_states_from_hardware(self, dev, log_refresh, comm_just_started):
+ # As an example here we update the temperature and humidity
+ # sensor states to random values.
+ key_val_list = []
+ if self.simulate_temp_changes:
+ # Simulate changing temperature values coming in from the
+ # hardware by updating all temp values randomly:
+ num_temps = dev.temperatureSensorCount
+ for index in range(1, num_temps + 1):
+ example_temp = random.randint(62, 88)
+ self._change_temp_sensor_value(dev, index, example_temp, key_val_list)
+ if log_refresh:
+ self.logger.info(f"received \"{dev.name}\" temperature{index} update to {example_temp:.1f}°")
+ if dev.pluginProps.get("ShowCoolHeatEquipmentStateUI", False) and "hvacOperationMode" in dev.states and "setpointCool" in dev.states and "setpointHeat" in dev.states:
+ if dev.states["hvacOperationMode"] in [indigo.kHvacMode.Cool, indigo.kHvacMode.HeatCool, indigo.kHvacMode.ProgramCool, indigo.kHvacMode.ProgramHeatCool]:
+ key_val_list.append({'key':'hvacCoolerIsOn', 'value':example_temp > dev.states["setpointCool"]})
+ if dev.states["hvacOperationMode"] in [indigo.kHvacMode.Heat, indigo.kHvacMode.HeatCool, indigo.kHvacMode.ProgramHeat, indigo.kHvacMode.ProgramHeatCool]:
+ key_val_list.append({'key':'hvacHeaterIsOn', 'value':example_temp < dev.states["setpointHeat"]})
+ if self.simulate_humidity_changes:
+ # Simulate changing humidity values coming in from the
+ # hardware by updating all humidity values randomly:
+ num_sensors = dev.humiditySensorCount
+ for index in range(1, num_sensors + 1):
+ example_humidity = random.randint(15, 90)
+ self._change_humidity_sensor_value(dev, index, example_humidity, key_val_list)
+ if log_refresh:
+ self.logger.info(f"received \"{dev.name}\" humidity{index} update to {example_humidity:.0f}%")
+
+ # Other states that should also be updated:
+ # ** IMPLEMENT ME **
+ # key_val_list.append({'key':'setpointHeat', 'value':floating number here})
+ # key_val_list.append({'key':'setpointCool', 'value':floating number here})
+ # key_val_list.append({'key':'hvacOperationMode', 'value':some indigo.kHvacMode.* value here})
+ # key_val_list.append({'key':'hvacFanMode', 'value':some indigo.kFanMode.* value here})
+ # key_val_list.append({'key':'hvacCoolerIsOn', 'value':True or False here})
+ # key_val_list.append({'key':'hvacHeaterIsOn', 'value':True or False here})
+ # key_val_list.append({'key':'hvacFanIsOn', 'value':True or False here})
+ if comm_just_started:
+ # As an example, we force these thermostat states to specific values.
+ if "setpointHeat" in dev.states:
+ key_val_list.append({'key':'setpointHeat', 'value':66.5, 'uiValue':"66.5 °F"})
+ if "setpointCool" in dev.states:
+ key_val_list.append({'key':'setpointCool', 'value':77.5, 'uiValue':"77.5 °F"})
+ if "hvacOperationMode" in dev.states:
+ key_val_list.append({'key':'hvacOperationMode', 'value':indigo.kHvacMode.HeatCool})
+ if "hvacFanMode" in dev.states:
+ key_val_list.append({'key':'hvacFanMode', 'value':indigo.kFanMode.Auto})
+ key_val_list.append({'key':'backlightBrightness', 'value':85, 'uiValue':"85%"})
+
+ if len(key_val_list) > 0:
+ dev.updateStatesOnServer(key_val_list)
+
+ if log_refresh:
+ if "setpointHeat" in dev.states:
+ self.logger.info(f"received \"{dev.name}\" cool setpoint update to {dev.states['setpointHeat']:.1f}°")
+ if "setpointCool" in dev.states:
+ self.logger.info(f"received \"{dev.name}\" heat setpoint update to {dev.states['setpointCool']:.1f}°")
+ if "hvacOperationMode" in dev.states:
+ action_str = _lookup_action_str_from_hvac_mode(dev.states["hvacOperationMode"])
+ self.logger.info(f"received \"{dev.name}\" main mode update to {action_str}")
+ if "hvacFanMode" in dev.states:
+ action_str = _lookup_action_str_from_fan_mode(dev.states["hvacFanMode"])
+ self.logger.info(f"received \"{dev.name}\" fan mode update to {action_str}")
+ self.logger.info(f"received \"{dev.name}\" backlight brightness update to {dev.states['backlightBrightness']}%")
+
+ ######################
+ # Process action request from Indigo Server to change main thermostat's main mode.
+ def _handle_change_hvac_mode_action(self, dev, new_hvac_mode):
+ # Command hardware module (dev) to change the thermostat mode here:
+ # ** IMPLEMENT ME **
+ send_success = True # Set to False if it failed.
+
+ action_str = _lookup_action_str_from_hvac_mode(new_hvac_mode)
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" mode change to {action_str}")
+
+ # And then tell the Indigo Server to update the state.
+ if "hvacOperationMode" in dev.states:
+ dev.updateStateOnServer("hvacOperationMode", new_hvac_mode)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" mode change to {action_str} failed")
+
+ ######################
+ # Process action request from Indigo Server to change thermostat's fan mode.
+ def _handle_change_fan_mode_action(self, dev, new_fan_mode):
+ # Command hardware module (dev) to change the fan mode here:
+ # ** IMPLEMENT ME **
+ send_success = True # Set to False if it failed.
+
+ action_str = _lookup_action_str_from_fan_mode(new_fan_mode)
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" fan mode change to {action_str}")
+
+ # And then tell the Indigo Server to update the state.
+ if "hvacFanMode" in dev.states:
+ dev.updateStateOnServer("hvacFanMode", new_fan_mode)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" fan mode change to {action_str} failed")
+
+ ######################
+ # Process action request from Indigo Server to change a cool/heat setpoint.
+ def _handle_change_setpoint_action(self, dev, new_setpoint, log_action_name, state_key):
+ if new_setpoint < 40.0:
+ new_setpoint = 40.0 # Arbitrary -- set to whatever hardware minimum setpoint value is.
+ elif new_setpoint > 95.0:
+ new_setpoint = 95.0 # Arbitrary -- set to whatever hardware maximum setpoint value is.
+
+ send_success = False
+
+ if state_key == "setpointCool":
+ # Command hardware module (dev) to change the cool setpoint to new_setpoint here:
+ # ** IMPLEMENT ME **
+ send_success = True # Set to False if it failed.
+ elif state_key == "setpointHeat":
+ # Command hardware module (dev) to change the heat setpoint to new_setpoint here:
+ # ** IMPLEMENT ME **
+ send_success = True # Set to False if it failed.
+
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" {log_action_name} to {new_setpoint:.1f}°")
+
+ # And then tell the Indigo Server to update the state.
+ if state_key in dev.states:
+ dev.updateStateOnServer(state_key, new_setpoint, uiValue=f"{new_setpoint:.1f} °F")
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" {log_action_name} to {new_setpoint:.1f}° failed")
+
+ ########################################
+ def startup(self):
+ self.logger.debug("startup called")
+
+ def shutdown(self):
+ self.logger.debug("shutdown called")
+
+ ########################################
+ def runConcurrentThread(self):
+ try:
+ while True:
+ for dev in indigo.devices.iter("self"):
+ if not dev.enabled or not dev.configured:
+ continue
+
+ # Plugins that need to poll out the status from the thermostat
+ # could do so here, then broadcast back the new values to the
+ # Indigo Server.
+ self._refresh_states_from_hardware(dev, False, False)
+
+ self.sleep(self.refresh_delay)
+ except self.StopThread:
+ pass # Optionally catch the StopThread exception and do any needed cleanup.
+
+ ########################################
+ def validateDeviceConfigUi(self, values_dict, type_id, dev_id):
+ return (True, values_dict)
+
+ ########################################
+ def deviceStartComm(self, dev):
+ # Called when communication with the hardware should be established.
+ # Here would be a good place to poll out the current states from the
+ # thermostat. If periodic polling of the thermostat is needed (that
+ # is, it doesn't broadcast changes back to the plugin somehow), then
+ # consider adding that to runConcurrentThread() above.
+ self._refresh_states_from_hardware(dev, True, True)
+
+ def deviceStopComm(self, dev):
+ # Called when communication with the hardware should be shutdown.
+ pass
+
+ ########################################
+ # Thermostat Action callback
+ ######################
+ # Main thermostat action bottleneck called by Indigo Server.
+ def actionControlThermostat(self, action, dev):
+ ###### SET HVAC MODE ######
+ if action.thermostatAction == indigo.kThermostatAction.SetHvacMode:
+ self._handle_change_hvac_mode_action(dev, action.actionMode)
+
+ ###### SET FAN MODE ######
+ elif action.thermostatAction == indigo.kThermostatAction.SetFanMode:
+ self._handle_change_fan_mode_action(dev, action.actionMode)
+
+ ###### SET COOL SETPOINT ######
+ elif action.thermostatAction == indigo.kThermostatAction.SetCoolSetpoint:
+ new_setpoint = action.actionValue
+ self._handle_change_setpoint_action(dev, new_setpoint, "change cool setpoint", "setpointCool")
+
+ ###### SET HEAT SETPOINT ######
+ elif action.thermostatAction == indigo.kThermostatAction.SetHeatSetpoint:
+ new_setpoint = action.actionValue
+ self._handle_change_setpoint_action(dev, new_setpoint, "change heat setpoint", "setpointHeat")
+
+ ###### DECREASE/INCREASE COOL SETPOINT ######
+ elif action.thermostatAction == indigo.kThermostatAction.DecreaseCoolSetpoint:
+ new_setpoint = dev.coolSetpoint - action.actionValue
+ self._handle_change_setpoint_action(dev, new_setpoint, "decrease cool setpoint", "setpointCool")
+
+ elif action.thermostatAction == indigo.kThermostatAction.IncreaseCoolSetpoint:
+ new_setpoint = dev.coolSetpoint + action.actionValue
+ self._handle_change_setpoint_action(dev, new_setpoint, "increase cool setpoint", "setpointCool")
+
+ ###### DECREASE/INCREASE HEAT SETPOINT ######
+ elif action.thermostatAction == indigo.kThermostatAction.DecreaseHeatSetpoint:
+ new_setpoint = dev.heatSetpoint - action.actionValue
+ self._handle_change_setpoint_action(dev, new_setpoint, "decrease heat setpoint", "setpointHeat")
+
+ elif action.thermostatAction == indigo.kThermostatAction.IncreaseHeatSetpoint:
+ new_setpoint = dev.heatSetpoint + action.actionValue
+ self._handle_change_setpoint_action(dev, new_setpoint, "increase heat setpoint", "setpointHeat")
+
+ ###### REQUEST STATE UPDATES ######
+ elif action.thermostatAction in [indigo.kThermostatAction.RequestStatusAll, indigo.kThermostatAction.RequestMode,
+ indigo.kThermostatAction.RequestEquipmentState, indigo.kThermostatAction.RequestTemperatures, indigo.kThermostatAction.RequestHumidities,
+ indigo.kThermostatAction.RequestDeadbands, indigo.kThermostatAction.RequestSetpoints]:
+ self._refresh_states_from_hardware(dev, True, False)
+
+ ########################################
+ # General Action callback
+ ######################
+ def actionControlUniversal(self, action, dev):
+ ###### BEEP ######
+ if action.deviceAction == indigo.kUniversalAction.Beep:
+ # Beep the hardware module (dev) here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" beep request")
+
+ ###### ENERGY UPDATE ######
+ elif action.deviceAction == indigo.kUniversalAction.EnergyUpdate:
+ # Request hardware module (dev) for its most recent meter data here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" energy update request")
+
+ ###### ENERGY RESET ######
+ elif action.deviceAction == indigo.kUniversalAction.EnergyReset:
+ # Request that the hardware module (dev) reset its accumulative energy usage data here:
+ # ** IMPLEMENT ME **
+ self.logger.info(f"sent \"{dev.name}\" energy reset request")
+
+ ###### STATUS REQUEST ######
+ elif action.deviceAction == indigo.kUniversalAction.RequestStatus:
+ # Query hardware module (dev) for its current status here. This differs from the
+ # indigo.kThermostatAction.RequestStatusAll action - for instance, if your thermo
+ # is battery powered you might only want to update it only when the user uses
+ # this status request (and not from the RequestStatusAll). This action would
+ # get all possible information from the thermostat and the other call
+ # would only get thermostat-specific information:
+ # ** GET BATTERY INFO **
+ # and call the common function to update the thermo-specific data
+ self._refresh_states_from_hardware(dev, True, False)
+ self.logger.info(f"sent \"{dev.name}\" status request")
+
+ ########################################
+ # Custom Plugin Action callbacks (defined in Actions.xml)
+ ######################
+ def set_backlight_brightness(self, plugin_action, dev):
+ try:
+ new_brightness = int(plugin_action.props.get("brightness", 100))
+ except ValueError:
+ # The int() cast above might fail if the user didn't enter a number:
+ self.logger.error(f"set backlight brightness action to device \"{dev.name}\" -- invalid brightness value")
+ return
+ # Command hardware module (dev) to set backlight brightness here:
+ # FIXME: add implementation here
+ send_success = True # Set to False if it failed.
+ if send_success:
+ # If success then log that the command was successfully sent.
+ self.logger.info(f"sent \"{dev.name}\" set backlight brightness to {new_brightness}")
+ # And then tell the Indigo Server to update the state:
+ dev.updateStateOnServer("backlightBrightness", new_brightness)
+ else:
+ # Else log failure but do NOT update state on Indigo Server.
+ self.logger.error(f"send \"{dev.name}\" set backlight brightness to {new_brightness} failed")
+
+ ########################################
+ # Actions defined in MenuItems.xml. In this case we just use these menu actions to
+ # simulate different thermostat configurations (how many temperature and humidity
+ # sensors they have).
+ ####################
+ def change_temp_sensor_count_to_1(self):
+ self._change_all_temp_sensor_counts(1)
+
+ def change_temp_sensor_count_to_2(self):
+ self._change_all_temp_sensor_counts(2)
+
+ def change_temp_sensor_count_to_3(self):
+ self._change_all_temp_sensor_counts(3)
+
+ def change_humidity_sensor_count_to_0(self):
+ self._change_all_humidity_sensor_counts(0)
+
+ def change_humidity_sensor_count_to_1(self):
+ self._change_all_humidity_sensor_counts(1)
+
+ def change_humidity_sensor_count_to_2(self):
+ self._change_all_humidity_sensor_counts(2)
+
+ def change_humidity_sensor_count_to_3(self):
+ self._change_all_humidity_sensor_counts(3)
+
diff --git a/Example HTTP Responder.indigoPlugin/Contents/Info.plist b/Example HTTP Responder.indigoPlugin/Contents/Info.plist
index 07a27ba..9bb3883 100644
--- a/Example HTTP Responder.indigoPlugin/Contents/Info.plist
+++ b/Example HTTP Responder.indigoPlugin/Contents/Info.plist
@@ -2,24 +2,24 @@
- PluginVersion
- 2021.2.0
- ServerApiVersion
- 2.6
- IwsApiVersion
- 1.0.0
- CFBundleDisplayName
- Example HTTP Responder
- CFBundleIdentifier
- com.indigodomo.indigoplugin.example-http-responder
- CFBundleVersion
- 1.0.0
- CFBundleURLTypes
-
-
- CFBundleURLName
- /com.indigodomo.indigoplugin.example-http-responder/static/html/about.html
-
-
+ PluginVersion
+ 2022.1.0
+ ServerApiVersion
+ 3.0
+ IwsApiVersion
+ 1.0.0
+ CFBundleDisplayName
+ Example HTTP Responder
+ CFBundleIdentifier
+ com.indigodomo.indigoplugin.example-http-responder
+ CFBundleVersion
+ 1.0.0
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ /com.indigodomo.indigoplugin.example-http-responder/static/html/about.html
+
+
diff --git a/Example HTTP Responder.indigoPlugin/Contents/Resources/templates/base.html b/Example HTTP Responder.indigoPlugin/Contents/Resources/templates/base.html
index 8ee13a7..164e725 100644
--- a/Example HTTP Responder.indigoPlugin/Contents/Resources/templates/base.html
+++ b/Example HTTP Responder.indigoPlugin/Contents/Resources/templates/base.html
@@ -10,7 +10,7 @@