def setSprinklerZone (self, dev, n): try: # Figure out which device we are on deviceNumber = 0 for y in range (1, 3): if dev.states["onDevice" + str(y)]: deviceNumber = y break # Turn off all zones but this one for y in range (1, 9): if y != n: self.debugLog("Turning off zone %i" % y) dev.updateStateOnServer ("onZone" + str(y), False) else: self.debugLog("Turning on zone %i" % y) dev.updateStateOnServer ("onZone" + str(y), True) # Set the status message to this zone schedule = ast.literal_eval(dev.states["device" + str(deviceNumber) + "Schedule"]) if schedule[n -1] != 0: # There is a schedule, flash the zone number for two seconds and then the duration dev.updateStateOnServer ("onZone" + str(n), True) self.setStatusMessage (dev, "zone" + str(n) + "SelectedUI", 0) self.sleep(2) # give them two seconds to see the message that we changed devices dev.updateStateOnServer ("keyCache", str(schedule[n-1]), uiValue=str(schedule[n-1])) else: # No schedule, show the zone number self.setStatusMessage (dev, "zone" + str(n) + "SelectedUI", 0) dev.updateStateOnServer ("keyCache", "", uiValue=dev.states["keyCache.ui"]) # so first key press clears the message except Exception as e: eps.printException(e)
def validateDeviceConfigUi(self, valuesDict, typeId, devId): try: dev = indigo.devices[devId] self.logger.debug(u"%s is validating device configuration UI" % dev.name) if len(valuesDict["devicelist"]) == 0: errorDict = indigo.Dict() errorDict["devicelist"] = "You must select at least one device" errorDict["showAlertText"] = "You must select at least one device for this plugin to work!" return (False, valuesDict, errorDict) # Make sure they aren't choosing a device that is already on another auto off device for deviceId in valuesDict["devicelist"]: for dev in indigo.devices.iter(self.pluginId): if str(dev.id) != str(devId): if eps.valueValid (dev.pluginProps, "devicelist", True): for d in dev.pluginProps["devicelist"]: if d == deviceId and valuesDict["allowSave"] == False: errorDict = indigo.Dict() errorDict["devicelist"] = "One or more devices are already managed by other Powermiser auto-off devices" errorDict["showAlertText"] = "You are already managing %s in another Powermiser auto-off device, the conditions could overlap and cause problems.\n\nBe sure that your conditions are different enough not to collide with the other Powermiser device.\n\nThis is only a warning, hit save again to ignore this warning." % indigo.devices[int(deviceId)].name valuesDict["allowSave"] = True return (False, valuesDict, errorDict) # All is good, set the allowSave back to false for the next round valuesDict["allowSave"] = False # If we get here all is good so far, return from conditions in case there are problems there return self.cond.validateDeviceConfigUi(valuesDict, typeId, devId) except Exception as e: eps.printException(e) return True
def onRunConcurrentThread (self): try: self.updateCheck(True, False) for dev in indigo.devices.iter(self.pluginId): if eps.valueValid (dev.states, "autoOffTimes", True): if dev.states["autoOffTimes"] != "{}": autoOffTimes = ast.literal_eval (dev.states["autoOffTimes"]) for devId, offDict in autoOffTimes.iteritems(): d = datetime.datetime.strptime (offDict["offTime"], "%Y-%m-%d %H:%M:%S") diff = dtutil.DateDiff ("seconds", d, indigo.server.getTime()) if diff < 0: self.logger.info("Turning off device %s" % indigo.devices[int(devId)].name) indigo.device.turnOff(devId) if dev.states["autoOffTimes"] == "{}" and dev.states["statedisplay"] != "off": dev.updateStateImageOnServer(indigo.kStateImageSel.PowerOff) dev.updateStateOnServer("statedisplay", "off") if dev.states["autoOffTimes"] != "{}" and dev.states["statedisplay"] == "off": dev.updateStateImageOnServer(indigo.kStateImageSel.PowerOn) dev.updateStateOnServer("statedisplay", "on") except Exception as e: eps.printException(e) return
def deviceStartComm(self, dev): self.logger.debug(u"%s starting communication" % dev.name) try: dev.stateListOrDisplayStateIdChanged() # Make sure any device.xml changes are incorporated if self.cache is None: return if "lastreset" in dev.states: d = indigo.server.getTime() if dev.states["lastreset"] == "": dev.updateStateOnServer("lastreset", d.strftime("%Y-%m-%d")) if eps.valueValid (dev.states, "autoOffTimes", True) == False: dev.updateStateOnServer("autoOffTimes", "{}") if self.cache.deviceInCache (dev.id) == False: self.logger.debug(u"%s not in cache, appears to be a new device or plugin was just started" % dev.name) self.cache.cacheDevices() # Failsafe self.addWatchedStates("*", dev.deviceTypeId, dev.id) # Failsafe #self.cache.dictDump (self.cache.devices[dev.id]) self.setStateDisplay(dev) except Exception as e: eps.printException(e) return
def runSprinklerSchedule (self, dev, devEx, schedule, deviceNum): try: deviceNum = str(deviceNum) if devEx.states["activeZone"] != 0: self.debugLog("Sprinkler device %s is running, stopping it" % devEx.name) if dev.pluginProps["runningAction"] == "replace": indigo.sprinkler.stop(devEx.id) if dev.pluginProps["runningAction"] == "add": runDict = devEx.zoneScheduledDurations if len(runDict) == 0: runDict = devEx.zoneMaxDurations # they aren't running a schedule d = indigo.server.getTime() start = datetime.datetime.strptime (dev.states["device" + deviceNum + "ZoneOn"], "%Y-%m-%d %H:%M:%S") diff = dtutil.DateDiff ("minutes", d, start) self.debugLog("Running zone has been running for %s minutes" % str(diff)) if len(runDict) > 0: for i in range (0, 8): if i > (devEx.states["activeZone"] - 1): schedule[i] = runDict[i] + schedule[i] if i == (devEx.states["activeZone"] - 1): schedule[i] = schedule[i] + (runDict[i] - diff) indigo.sprinkler.stop(devEx.id) self.debugLog("Turning on %s with schedule %s" % (devEx.name, unicode(schedule))) indigo.sprinkler.run(devEx.id, schedule=schedule) except Exception as e: eps.printException(e)
def setStateDisplay (self, dev, force = False): stateValue = None stateUIValue = "" stateIcon = None stateDecimals = -1 try: if dev.deviceTypeId == "devtemplate": X = 1 # placeholder else: return # failsafe if stateValue is None: return # nothing to do if force == False: if "statedisplay.ui" in dev.states: if stateValue == dev.states["statedisplay"] and stateUIValue == dev.states["statedisplay.ui"]: return # nothing to do else: if stateValue == dev.states["statedisplay"]: return # nothing to do dev.updateStateImageOnServer(stateIcon) if stateDecimals > -1: dev.updateStateOnServer("statedisplay", value=stateValue, uiValue=stateUIValue, decimalPlaces=stateDecimals) else: dev.updateStateOnServer("statedisplay", value=stateValue, uiValue=stateUIValue) except Exception as e: eps.printException(e)
def nextField (self, devAction): try: dev = indigo.devices[devAction.deviceId] # In case they use this command on a non-compatible device, redirect if dev.deviceTypeId == "securityKeypad": self.sendCharacter (devAction) if dev.deviceTypeId == "dimmerKeypad": self.sendCharacter (devAction) if dev.deviceTypeId == "sprinklerKeypad": # Next indicates they are switching zones zoneNum = 0 for i in range (1, 9): if dev.states["onZone" + str(i)]: zoneNum = i break if zoneNum == 1 and eps.valueValid (dev.pluginProps, "device2", True) == False and eps.valueValid (dev.pluginProps, "device3", True) == False: # Failsafe in case they didn't enter a duration for zone 1 and cause the timer to start for 2 minutes self.setDeviceTimeout(dev, 120) self.saveSchedule (dev) if zoneNum > 0: zoneNum = zoneNum + 1 if zoneNum > 8: zoneNum = 1 self.debugLog("Change to zone %i" % zoneNum) self.setSprinklerZone (dev, zoneNum) except Exception as e: eps.printException(e)
def saveSchedule (self, dev): try: # Next indicates they are switching zones zoneNum = 0 for i in range (1, 9): if dev.states["onZone" + str(i)]: zoneNum = i break # Set the duration of this zone before we switch zones deviceNumber = 0 for y in range (1, 3): if dev.states["onDevice" + str(y)]: deviceNumber = y break cache = dev.states["keyCache"] # so we can save this zone duration if cache == "": cache = "0" cache = int(cache) schedule = ast.literal_eval(dev.states["device" + str(deviceNumber) + "Schedule"]) self.debugLog ("Old schedule is %s" % unicode(schedule)) newSchedule = schedule newSchedule[zoneNum - 1] = cache # Save the new schedule self.debugLog ("New schedule is %s" % unicode(newSchedule)) dev.updateStateOnServer ("device" + str(deviceNumber) + "Schedule", unicode(newSchedule)) dev.updateStateOnServer ("keyCache", "", uiValue=" ") # Clear the cache for the next zone except Exception as e: eps.printException(e)
def sendCharacter_Dimmer (self, dev, devAction): try: if eps.valueValid (devAction.props, "devicelist", True): self.debugLog ("Setting action based devices on %s" % dev.name) devlist = [] for s in devAction.props["devicelist"]: devlist.append(s) dev.updateStateOnServer ("deviceList", unicode(devlist)) return cache = dev.states["keyCache"] + devAction.props["key"] if int(cache) > 100: cache = "100" ui = cache n = int(eps.getDictValue(dev.pluginProps, "resetTime", 10)) self.setDeviceTimeout (dev, n) dev.updateStateOnServer ("keyCache", cache, uiValue=ui) if len(cache) == 3: self.processCache (dev) # 3 characters is the most except Exception as e: eps.printException(e)
def cancelCode (self, devAction): try: dev = indigo.devices[devAction.deviceId] self.deviceReset (dev) except Exception as e: eps.printException(e)
def actionControlDimmerRelay(self, action, dev): try: if action.deviceAction == indigo.kDimmerRelayAction.TurnOn: sendSuccess = True self.activateScene (dev, "snapshot") if sendSuccess: self.logger.info(u"sent \"%s\" %s" % (dev.name, "on")) dev.updateStateOnServer("onOffState", True) else: self.logger.error(u"send \"%s\" %s failed" % (dev.name, "on")) elif action.deviceAction == indigo.kDimmerRelayAction.TurnOff: sendSuccess = True self.activateScene (dev, "memory") if sendSuccess: self.logger.info(u"sent \"%s\" %s" % (dev.name, "off")) dev.updateStateOnServer("onOffState", False) else: self.logger.error(u"send \"%s\" %s failed" % (dev.name, "off")) elif action.deviceAction == indigo.kDimmerRelayAction.Toggle: newOnState = not dev.onState sendSuccess = True if sendSuccess: self.logger.info(u"sent \"%s\" %s" % (dev.name, "toggle")) dev.updateStateOnServer("onOffState", newOnState) else: self.logger.error(u"send \"%s\" %s failed" % (dev.name, "toggle")) except Exception as e: eps.printException(e)
def deviceUpdated(self, origDev, newDev): if self.cache is None: return try: if eps.isNewDevice(origDev, newDev): self.logger.debug("New device '%s' detected, restarting device communication" % newDev.name) self.deviceStartComm (newDev) return if origDev.pluginId == self.pluginId: self.logger.debug(u"Plugin device %s was updated" % origDev.name) # Re-cache the device and it's subdevices and states if eps.dictChanged (origDev, newDev): self.logger.debug(u"Plugin device %s settings changed, rebuilding watched states" % origDev.name) self.cache.removeDevice (origDev.id) self.deviceStartComm (newDev) # Collapse conditions if they got expanded self.cond.collapseAllConditions (newDev) else: changedStates = self.cache.watchedStateChanged (origDev, newDev) if changedStates: self.logger.debug(u"The monitored device %s had a watched state change" % origDev.name) # Send parent device array and changed states array to function to disseminate #self.logger.info(unicode(changedStates)) X = 1 # placeholder except Exception as e: eps.printException(e) return
def getConditionsList (self, filter="conditions", valuesDict=None, typeId="", targetId=0): try: if filter.lower() == "conditions": return self.cond.appendUIConditions ([], "all") if filter.lower() == "evals": return self.cond.addUIEvals ([]) if filter.lower() == "conditionmenu": return self.cond.addUIConditionMenu ([]) except Exception as e: eps.printException(e)
def updateDeviceStates (self, parentDev, childDev = None): try: stateChanges = self.cache.deviceUpdate (parentDev) except Exception as e: eps.printException(e) return
def deviceDeleted(self, dev): try: if dev.pluginId == self.pluginId: self.logger.debug("%s was deleted" % dev.name) self.cache.removeDevice (dev.id) except Exception as e: eps.printException(e)
def onRunConcurrentThread (self): try: self.updateCheck(True, False) except Exception as e: eps.printException(e) return
def setDeviceTimeout (self, dev, seconds): try: d = indigo.server.getTime() d = dtutil.DateAdd ("seconds", seconds, d) dev.updateStateOnServer ("resetTime", d.strftime("%Y-%m-%d %H:%M:%S")) except Exception as e: eps.printException(e)
def setStatusMessage (self, dev, key, seconds=3): try: ui = eps.getDictValue (dev.pluginProps, key, " ") self.debugLog ("Setting status message on %s to '%s'" % (dev.name, ui)) dev.updateStateOnServer ("keyCache", dev.states["keyCache"], uiValue=ui) if seconds > 0: self.setDeviceTimeout (dev, seconds) except Exception as e: eps.printException(e)
def sendCharacter (self, devAction): try: dev = indigo.devices[devAction.deviceId] if dev.deviceTypeId == "securityKeypad": self.sendCharacter_Security(dev, devAction.props["key"]) if dev.deviceTypeId == "dimmerKeypad": self.sendCharacter_Dimmer(dev, devAction) if dev.deviceTypeId == "sprinklerKeypad": self.sendCharacter_Sprinkler (dev, devAction) except Exception as e: eps.printException(e)
def onConditionsChange (self, valuesDict, typeId, devId): # Just here so we can refresh the states for dynamic UI try: if typeId == "AutoOff": valuesDict = self.cond.setUIDefaults (valuesDict) except Exception as e: eps.printException(e) return valuesDict
def dateTimeDeviceUpdate (self, dev, value): try: value = unicode(value) d = datetime.datetime.strptime (value, dev.pluginProps["valueformat"]) if eps.valueValid (dev.pluginProps, "dateformat", True): value = d.strftime(dev.pluginProps["dateformat"]) value = self.lcd.stringToLCD (value, 20, dev.pluginProps["textspaces"]) self.lcd.stringToGraphics (dev, "currentDate", value) except Exception as e: eps.printException(e)
def updateCheck (self, onlyNewer = False, force = True): return try: try: if self.pluginUrl == "": if force: indigo.server.log ("This plugin currently does not check for newer versions", isError = True) return except: # Normal if pluginUrl hasn't been defined if force: indigo.server.log ("This plugin currently does not check for newer versions", isError = True) return d = indigo.server.getTime() if eps.valueValid (self.pluginPrefs, "latestVersion") == False: self.pluginPrefs["latestVersion"] = False if force == False and eps.valueValid (self.pluginPrefs, "lastUpdateCheck", True): last = datetime.datetime.strptime (self.pluginPrefs["lastUpdateCheck"], "%Y-%m-%d %H:%M:%S") lastCheck = dtutil.DateDiff ("hours", d, last) if self.pluginPrefs["latestVersion"]: if lastCheck < 72: return # if last check has us at the latest then only check once every 3 days else: if lastCheck < 2: return # only check every four hours in case they don't see it in the log self.debugLog("Checking for updates") page = urllib2.urlopen(self.pluginUrl) soup = BeautifulSoup(page) versions = soup.find(string=re.compile("\#Version\|")) versionData = unicode(versions) versionInfo = versionData.split("#Version|") newVersion = float(versionInfo[1][:-1]) if newVersion > float(self.pluginVersion): self.pluginPrefs["latestVersion"] = False indigo.server.log ("Version %s of %s is available, you are currently using %s." % (str(round(newVersion,2)), self.pluginDisplayName, str(round(float(self.pluginVersion), 2))), isError=True) else: self.pluginPrefs["latestVersion"] = True if onlyNewer == False: indigo.server.log("%s version %s is the most current version of the plugin" % (self.pluginDisplayName, str(round(float(self.pluginVersion), 2)))) self.pluginPrefs["lastUpdateCheck"] = d.strftime("%Y-%m-%d %H:%M:%S") except Exception as e: eps.printException(e)
def updateDevice (self, devAction): try: dev = indigo.devices[devAction.deviceId] children = self.cache.getSubDevices (dev) for devId in children: subDev = indigo.devices[int(devId)] self.updateDeviceStates (dev, subDev) except Exception as e: eps.printException(e) return
def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) try: self.TVERSION = "2.0.1" self.epsInit() self.pluginInit() except Exception as e: msg = eps.debugHeader ("Plugin intialization had an error, restart required!") self.logger.critical(msg) eps.printException(e) raise
def pluginInit (self): try: # New global for initialized class versions that the plugin adds #self.CLASSVERSIONS = [] #self.CLASSVERSIONS.append("xyz: " + self.xyz.version) return except Exception as e: msg = eps.debugHeader ("Plugin intialization had an error, restart required!") self.logger.critical(msg) eps.printException(e) raise
def sendCharacter_Sprinkler (self, dev, devAction): try: cache = dev.states["keyCache"] + devAction.props["key"] # Catch special phrases so we don't error out for i in range (1, 9): deviceNum = 0 zoneNum = 0 if cache.lower() == "#dev" + str(i): deviceNum = i if cache.lower() == "#zone" + str(i): deviceNum = i if deviceNum <> 0: self.setSprinklerDevice (dev, deviceNum) return if zoneNum <> 0: for y in range (1, 9): if y != i: dev.updateStateOnServer ("onZone" + str(i), False) dev.updateStateOnServer ("onZone" + str(i), True) self.setStatusMessage (dev, "zone" + str(i) + "SelectedUI") return # If we got here then we got an entry, determine if it's for a device, a zone or a duration isDevice = True for i in range (1, 4): if dev.states["onDevice" + str(i)]: isDevice = False break # If no device then our entry is a device selection if isDevice: self.debugLog("No device is currently active, setting device") if int(cache) > 3: cache = "3" # can't select more than device 3 self.setSprinklerDevice (dev, int(cache)) return if eps.valueValid (dev.pluginProps, "device2", True) == False and eps.valueValid (dev.pluginProps, "device3", True) == False: # If only a single device then we need to set the timeout for two minutes like when we select a device self.setDeviceTimeout(dev, 120) # Since when we select a device it automatically selects zone 1 it's a duration ui = cache dev.updateStateOnServer ("keyCache", cache, uiValue=ui) except Exception as e: eps.printException(e)
def runAction (self, dev, prefix="success"): try: if dev.ownerProps[prefix + "Type"] == "action" and dev.ownerProps[prefix + "Action"] != "": indigo.actionGroup.execute(int(dev.ownerProps[prefix + "Action"])) if dev.ownerProps[prefix + "Type"] == "device" and dev.ownerProps[prefix + "Device"] != "": if dev.ownerProps[prefix + "DeviceAction"] == "on": indigo.device.turnOn(int(dev.ownerProps[prefix + "Device"])) if dev.ownerProps[prefix + "DeviceAction"] == "off": indigo.device.turnOff(int(dev.ownerProps[prefix + "Device"])) if dev.ownerProps[prefix + "DeviceAction"] == "toggle": indigo.device.toggle(int(dev.ownerProps[prefix + "Device"])) if dev.ownerProps[prefix + "Type"] == "variable" and dev.ownerProps[prefix + "Variable"] != "": indigo.variable.updateValue(int(dev.ownerProps[prefix + "Variable"]), value=dev.ownerProps[prefix + "successVariableValue"]) if dev.ownerProps[prefix + "Type"] == "schedule" and dev.ownerProps[prefix + "ScheduleAction"] != "": if dev.ownerProps[prefix + "ScheduleAction"] == "enable": indigo.actionGroup.execute(int(dev.ownerProps[prefix + "Schedule"])) if dev.ownerProps[prefix + "ScheduleAction"] == "disable": indigo.actionGroup.execute(int(dev.ownerProps[prefix + "Schedule"])) except Exception as e: eps.printException(e)
def closedDeviceConfigUi(self, valuesDict, userCancelled, typeId, devId): try: dev = indigo.devices[devId] self.logger.debug(u"%s is closing device configuration UI" % dev.name) if userCancelled == False: self.logger.debug(u"%s configuration UI was not cancelled" % dev.name) #self.cache.dictDump (self.cache.devices[dev.id]) except Exception as e: eps.printException(e) return
def sendCharacter_Security (self, dev, key): try: # Make sure we aren't locked out if eps.valueValid (dev.states, "lockOut", True): d = datetime.datetime.strptime (dev.states["lockOut"], "%Y-%m-%d %H:%M:%S") diff = dtutil.DateDiff ("seconds", d, indigo.server.getTime()) if diff >= 0: indigo.server.log("Attempted to enter code on device %s but that device is in failed code lockout for %i more seconds" % (dev.name, diff), isError=True) msg = "L.OUT" secs = 5 if secs > diff: secs = diff ui = eps.getDictValue (dev.pluginProps, "lockoutUI", "L.OUT") dev.updateStateOnServer ("keyCache", dev.states["keyCache"], uiValue=ui) self.setDeviceTimeout (dev, secs) return else: dev.updateStateOnServer ("lockOutActive", False) self.debugLog ("Keypad button %s pressed, adding to characters" % key) cache = dev.states["keyCache"] + key ui = "" n = int(eps.getDictValue(dev.pluginProps, "resetTime", 10)) if dev.pluginProps["codeCharacter"] != "" and dev.pluginProps["codeCharacter"] != " ": for s in cache: ui += dev.pluginProps["codeCharacter"] self.setDeviceTimeout (dev, n) else: self.setDeviceTimeout (dev, n) ui = cache dev.updateStateOnServer ("keyCache", cache, uiValue=ui) self.processCache (dev) except Exception as e: eps.printException(e) return
def performanceOptions (self, valuesDict, typeId): self.logger.debug(u"Saving performance options") errorsDict = indigo.Dict() try: # Save the performance options into plugin prefs self.pluginPrefs["pollingMode"] = valuesDict["pollingMode"] self.pluginPrefs["pollingInterval"] = valuesDict["pollingInterval"] self.pluginPrefs["pollingFrequency"] = valuesDict["pollingFrequency"] self.cache.setPollingOptions (valuesDict["pollingMode"], valuesDict["pollingInterval"], valuesDict["pollingFrequency"]) except Exception as e: eps.printException(e) return (True, valuesDict, errorsDict)