def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.updater = GitHubPluginUpdater( self) #'tenallero', 'Indigo-XBMC', self) # Port self.listenPortDef = 8189 self.listenPort = 0 self.apiVersion = "2.0" self.localAddress = "" # Pooling self.pollingInterval = 0 self.requestID = 0 # Flag buttonRequest is processing self.reqRunning = 0 # create empty device list self.deviceList = {} self.sock = None self.socketBufferSize = 512 self.socketStop = False
def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.updater = GitHubPluginUpdater(self) self.ControllerIP = "" self.ControllerPort = "" self.ControllerRel = "V4" self.ControllerSite = "" self.ControllerAuth = False self.ControllerUsername = "" self.ControllerPassword = "" self.ControllerInterval = 0 self.ControllerURL = "" self.ControllerURLAPI = "" self.CurlCommand = "" # create empty device list self.userDeviceList = {} self.wlanDeviceList = {} self.sock = None self.socketBufferSize = 512 self.socketStop = False self.pushoverPlugin = None
def startup(self): self.logger.debug(u"Starting Plugin. startup() method called.") self.updater = GitHubPluginUpdater(self) self.myThread = threading.Thread(target=self.listenHTTP, args=()) self.myThread.daemon = True self.myThread.start()
def startup(self): self.debug = self.pluginPrefs.get('showDebugInLog', False) self.debugLog(u"startup called") self.updater = GitHubPluginUpdater(self) #self.updater.checkForUpdate() self.updateFrequency = float(self.pluginPrefs.get('updateFrequency', 24)) * 60.0 * 60.0 self.debugLog(u"updateFrequency = " + str(self.updateFrequency)) self.next_update_check = time.time() self.buildAvailableDeviceList()
def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.updater = GitHubPluginUpdater(self) self.apiVersion = "2.0" self.localAddress = "" # create empty device list self.deviceList = {}
def startup(self): indigo.server.log(u"Starting MyQ") self.updater = GitHubPluginUpdater(self) self.updateFrequency = float(self.pluginPrefs.get('updateFrequency', "24")) * 60.0 * 60.0 if self.updateFrequency > 0: self.next_update_check = time.time() self.statusFrequency = float(self.pluginPrefs.get('statusFrequency', "10")) * 60.0 if self.statusFrequency > 0: self.next_status_check = time.time()
def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) pfmt = logging.Formatter( '%(asctime)s.%(msecs)03d\t[%(levelname)8s] %(name)20s.%(funcName)-25s%(msg)s', datefmt='%Y-%m-%d %H:%M:%S') self.plugin_file_handler.setFormatter(pfmt) try: self.logLevel = int(self.pluginPrefs[u"logLevel"]) except: self.logLevel = logging.INFO self.indigo_log_handler.setLevel(self.logLevel) self.logger.debug(u"logLevel = " + str(self.logLevel)) self.debugLog(u"Initializing Cisco/Sipura VOIP plugin.") self.timeOutCount = 0 self.deviceNeedsUpdated = '' self.prefServerTimeout = int( self.pluginPrefs.get('configMenuServerTimeout', "15")) self.updater = GitHubPluginUpdater(self) self.configUpdaterInterval = self.pluginPrefs.get( 'configUpdaterInterval', 24) self.configUpdaterForceUpdate = self.pluginPrefs.get( 'configUpdaterForceUpdate', False) self.useNumberConversion = self.pluginPrefs.get( 'useNumberConversion', False) self.folderLocation = self.pluginPrefs.get('folderLocation', '') #self.sipServer = self.pluginPrefs.get('configUpdaterForceUpdate', False) self.deviceId = 0 self.ringing = False self.connected = False self.callType = '' self.connectTime = '' self.kill = True self.checkTime = t.time() self.triggers = {} self.currentNumber = '' self.numberstoConvert = []
def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = pluginPrefs.get("chkDebug", False) self.updater = GitHubPluginUpdater(self) self.updater.checkForUpdate(str(self.pluginVersion)) self.lastUpdateCheck = datetime.datetime.now() self.pollingInterval = 60 self.APIKey = pluginPrefs.get("txtAPIKey", None) self.currentEventN = "0" if "EVENTS" in self.pluginPrefs: self.EVENTS = json.loads(self.pluginPrefs["EVENTS"]) else: self.EVENTS = {}
class Plugin(indigo.PluginBase): ######################################## def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = self.pluginPrefs.get("showDebugInfo", False) self.debugLog(u"Debugging enabled") def __del__(self): indigo.PluginBase.__del__(self) def startup(self): indigo.server.log(u"Starting LIFX Bridge") self.updater = GitHubPluginUpdater(self) self.updater.checkForUpdate() self.next_update_check = time.time() + float( self.pluginPrefs.get('updateFrequency', 24)) * 60.0 * 60.0 self.refreshDeviceList() # Need to subscribe to device changes here so we can call the refreshDeviceList method # in case there was a change or deletion of a device that's published indigo.devices.subscribeToChanges() try: self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) except socket.error, msg: self.debugLog('Failed to create socket. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]) return try: self.sock.bind(('', DEFAULT_LIFX_PORT)) self.sock.settimeout(1) except socket.error, msg: self.debugLog('Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]) return
def testUpdateCheck(self): indigo.server.log('-- BEGIN testUpdateCheck --') self.updater.checkForUpdate() self.updater.checkForUpdate('0.0.0') emptyUpdater = GitHubPluginUpdater('jheddings', 'indigo-ghpu') emptyUpdater.checkForUpdate() emptyUpdater.checkForUpdate('0.0.0') emptyUpdater.checkForUpdate(str(self.pluginVersion)) indigo.server.log('-- END testUpdateCheck --')
def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.updater = GitHubPluginUpdater( self) #'tenallero', 'Indigo-UniPi', self) self.apiVersion = "2.0" # Pooling self.pollingInterval = 0 # create empty device list self.boardList = {} self.relayList = {} self.digitalInputList = {} self.digitalCounterList = {} self.analogInputList = {} self.analogOutputList = {} self.tempSensorList = {} self.humiditySensorList = {} self.websocketEnabled = True
def startup(self): indigo.server.log(u"Starting Harmony Hub") self.updater = GitHubPluginUpdater(self) self.updater.checkForUpdate() self.updateFrequency = self.pluginPrefs.get('updateFrequency', 24) if self.updateFrequency > 0: self.next_update_check = time.time() + float(self.updateFrequency) * 60.0 * 60.0 self.hubDict = dict() self.triggers = { }
def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = True timeNow = time.time() self.nextCheck = timeNow - 86400 self.updater = GitHubPluginUpdater('lindehoff', 'Indigo-Verisure', self) self.tryingToLogin = False self.loginErrorCount = 0 self.currentSleepTime = int(self.pluginPrefs.get('updateRate', 300))
def testUpdateCheck(self): indigo.server.log('-- BEGIN testUpdateCheck --') self.updater.checkForUpdate() self.updater.checkForUpdate('0.0.0') emptyUpdater = GitHubPluginUpdater() emptyUpdater.checkForUpdate() emptyUpdater.checkForUpdate('0.0.0') emptyUpdater.checkForUpdate(str(self.pluginVersion)) indigo.server.log('-- END testUpdateCheck --')
def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.updater = GitHubPluginUpdater(self) # Timeout self.reqTimeout = 8 # Pooling self.pollingInterval = 2 # Flag buttonRequest is processing self.reqRunning = False # create empty device list self.deviceList = {} # install authenticating opener self.passman = urllib2.HTTPPasswordMgrWithDefaultRealm() authhandler = urllib2.HTTPBasicAuthHandler(self.passman) opener = urllib2.build_opener(authhandler) urllib2.install_opener(opener)
def startup(self): indigo.server.log(u"Starting SMTPd") self.updater = GitHubPluginUpdater(self) self.updateFrequency = float(self.pluginPrefs.get('updateFrequency', '24')) * 60.0 * 60.0 self.next_update_check = time.time() if "SMTPd" in indigo.variables.folders: myFolder = indigo.variables.folders["SMTPd"] else: myFolder = indigo.variables.folder.create("SMTPd") self.pluginPrefs["folderId"] = myFolder.id self.triggers = { }
def startup(self): indigo.server.log(u"Starting LIFX Bridge") self.updater = GitHubPluginUpdater(self) self.updater.checkForUpdate() self.next_update_check = time.time() + float( self.pluginPrefs.get('updateFrequency', 24)) * 60.0 * 60.0 self.refreshDeviceList() # Need to subscribe to device changes here so we can call the refreshDeviceList method # in case there was a change or deletion of a device that's published indigo.devices.subscribeToChanges() try: self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) except socket.error, msg: self.debugLog('Failed to create socket. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]) return
def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.updater = GitHubPluginUpdater(self) #'tenallero', 'Indigo-XBMC', self) # Port self.listenPortDef = 8189 self.listenPort = 0 self.apiVersion = "2.0" self.localAddress = "" # Pooling self.pollingInterval = 0 self.requestID = 0 # Flag buttonRequest is processing self.reqRunning = 0 # create empty device list self.deviceList = {} self.sock = None self.socketBufferSize = 512 self.socketStop = False
class Plugin(indigo.PluginBase): def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) pfmt = logging.Formatter( '%(asctime)s.%(msecs)03d\t[%(levelname)8s] %(name)20s.%(funcName)-25s%(msg)s', datefmt='%Y-%m-%d %H:%M:%S') self.plugin_file_handler.setFormatter(pfmt) try: self.logLevel = int(self.pluginPrefs[u"logLevel"]) except: self.logLevel = logging.INFO self.indigo_log_handler.setLevel(self.logLevel) self.logger.debug(u"logLevel = " + str(self.logLevel)) self.debugLog(u"Initializing Cisco/Sipura VOIP plugin.") self.timeOutCount = 0 self.deviceNeedsUpdated = '' self.prefServerTimeout = int( self.pluginPrefs.get('configMenuServerTimeout', "15")) self.updater = GitHubPluginUpdater(self) self.configUpdaterInterval = self.pluginPrefs.get( 'configUpdaterInterval', 24) self.configUpdaterForceUpdate = self.pluginPrefs.get( 'configUpdaterForceUpdate', False) self.useNumberConversion = self.pluginPrefs.get( 'useNumberConversion', False) self.folderLocation = self.pluginPrefs.get('folderLocation', '') #self.sipServer = self.pluginPrefs.get('configUpdaterForceUpdate', False) self.deviceId = 0 self.ringing = False self.connected = False self.callType = '' self.connectTime = '' self.kill = True self.checkTime = t.time() self.triggers = {} self.currentNumber = '' self.numberstoConvert = [] def __del__(self): self.debugLog(u"__del__ method called.") indigo.PluginBase.__del__(self) def closedPrefsConfigUi(self, valuesDict, userCancelled): self.debugLog(u"closedPrefsConfigUi() method called.") if userCancelled: self.debugLog(u"User prefs dialog cancelled.") if not userCancelled: self.debugLog(u"User prefs saved.") indigo.server.log(u"Debugging Level: {0}".format(self.logLevel)) self.useNumberConversion = self.pluginPrefs.get( 'useNumberConversion', False) self.folderLocation = self.pluginPrefs.get('folderLocation', '') if self.useNumberConversion: self.loadFileNumbers() else: self.numberstoConvert = [] self.logger.debug(u'Numbers to Convert Removed:' + str(self.numberstoConvert)) return True def loadFileNumbers(self): self.logger.debug(u'loadFile of Number Conversions called') self.folderLocation = self.pluginPrefs.get('folderLocation', '') if self.folderLocation == '': self.logger.info(u'Folder Name cannot be empty') return self.numberstoConvert = [] try: folder = self.folderLocation filename = 'numbersConvert.txt' #f = open(folder+'/'+filename, 'r') with open(folder + '/' + filename, 'rb') as fp: for i in fp.readlines(): tmp = i.split(',') try: self.numberstoConvert.append( (str(tmp[0].strip()), str(tmp[1].strip()))) except Exception as error: self.logger.error( u'Error with numbersConvert.txt file Data Format File: are they comma seperated with each on new line?' ) self.logger.debug(error) pass self.logger.debug(self.numberstoConvert) except Exception as error: self.logger.info(u'Exception within loadFileNumbers:' + str(error)) return def calltoLoadFile(self, valuesDict): self.logger.debug(u'LoadFile Config Button Pressed') self.loadFileNumbers() return # Start 'em up. def deviceStartComm(self, dev): self.debugLog(u"deviceStartComm() method called.") self.debugLog(u'deviceID equals:' + str(dev.id)) self.debugLog(u"Starting Device: {0}:".format(dev.name)) dev.updateStateOnServer("currentNumber", '') dev.updateStateOnServer("deviceStatus", '') dev.updateStateOnServer("callType", '') update_time = t.strftime("%m/%d/%Y at %H:%M") #dev.updateStateOnServer('deviceLastUpdated', value=update_time) dev.updateStateOnServer('callTime', value='') self.deviceId = dev.id dev.updateStateOnServer('deviceOnline', False) self.kill = False if self.useNumberConversion: self.loadFileNumbers() # Shut 'em down. def deviceStopComm(self, dev): self.debugLog(u"deviceStopComm() method called.") indigo.server.log(u"Stopping SIPURA device: " + dev.name) dev.updateStateOnServer('deviceOnline', False) self.kill = True def forceUpdate(self): self.updater.update(currentVersion='0.0.0') def checkForUpdates(self): if self.updater.checkForUpdate() == False: indigo.server.log(u"No Updates are Available") def updatePlugin(self): self.updater.update() def runConcurrentThread(self): # Gra # b the first device (don' want to multithread0 while self.stopThread == False: for dev in indigo.devices.itervalues('self'): if dev.configured and dev.enabled: dev.updateStateOnServer('deviceOnline', True) porttouse = dev.pluginProps['sourcePort'] s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.settimeout(1) self.logger.info(u"Socket Connection Opened on port:" + str(porttouse)) try: s.bind(('', int(porttouse))) except socket.error, msg: self.errorLog(u'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + str(msg[1])) dev.updateStateOnServer('deviceOnline', False) dev.setErrorStateOnServer(u'Offline') self.sleep(5) try: while True and dev.enabled and dev.configured and self.kill == False: # Only support one VOIP device # very likely easier way to do it #self.debugLog(u"MainLoop running: {0}:".format(dev.name)) #How to limit indigo that only one device is allowed? try: self.updateStates(dev) data, addr = s.recvfrom(9024) self.parseData(dev, data, addr) except socket.timeout: # or no data received. #self.debugLog(u"SOCKET Error {0}:".format(e)) pass if self.connected or self.ringing: self.sleep(0.2) else: self.sleep(1) except self.stopThread: self.debugLog( u'Restarting/or error. Stopping SpiruaVOIP thread.' ) s.close() pass self.debugLog(u' No Configured & Enabled Device:') # How to limit indigo that only one device is allowed? self.sleep(60)
class Plugin(indigo.PluginBase): def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.startingUp = True self.pluginIsShuttingDown = False self.versionPlugin = pluginVersion # Okay Versions across two applications # First Number 0 - ignore # Second Number is the Mac Version -- increasing this without breaking PC app versions # Third Number is the PC Version -- # e.g 0.2.2 -- 2 is current mac version, 2 is current PC version # if version goes to 0.2.4 -- PC version needs to be updated if less than 4 and will organise message # if version is 0.4.2 -- PC version remains on 2 - so only Mac update needed/done. self.listenPort = 9123 self.logger.info(u"") self.logger.info( u"{0:=^130}".format(" Initializing New Plugin Session ")) self.logger.info(u"{0:<30} {1}".format("Plugin name:", pluginDisplayName)) self.logger.info(u"{0:<30} {1}".format("Plugin version:", pluginVersion)) self.logger.info(u"{0:<30} {1}".format("Plugin ID:", pluginId)) self.logger.info(u"{0:<30} {1}".format("Indigo version:", indigo.server.version)) self.logger.info(u"{0:<30} {1}".format("Python version:", sys.version.replace('\n', ''))) self.logger.info(u"{0:=^130}".format("")) pfmt = logging.Formatter( '%(asctime)s.%(msecs)03d\t[%(levelname)8s] %(name)20s.%(funcName)-25s%(msg)s', datefmt='%Y-%m-%d %H:%M:%S') self.plugin_file_handler.setFormatter(pfmt) try: self.logLevel = int(self.pluginPrefs[u"showDebugLevel"]) except: self.logLevel = logging.INFO self.indigo_log_handler.setLevel(self.logLevel) self.logger.debug(u"logLevel = " + str(self.logLevel)) self.triggers = {} self.validatePrefsConfigUi(pluginPrefs) self.debugLevel = self.pluginPrefs.get('showDebugLevel', "20") self.debugextra = self.pluginPrefs.get('debugextra', False) self.debugserver = True #self.configUpdaterForceUpdate = self.pluginPrefs.get('configUpdaterForceUpdate', False) self.openStore = self.pluginPrefs.get('openStore', False) self.updateFrequency = float( self.pluginPrefs.get('updateFrequency', "24")) * 60.0 * 60.0 self.next_update_check = t.time() + 20 self.pluginIsInitializing = False #self.startlistenHttpThread() def __del__(self): if self.debugLevel >= 2: self.debugLog(u"__del__ method called.") indigo.PluginBase.__del__(self) def closedPrefsConfigUi(self, valuesDict, userCancelled): if self.debugLevel >= 2: self.debugLog(u"closedPrefsConfigUi() method called.") if userCancelled: self.debugLog(u"User prefs dialog cancelled.") if not userCancelled: self.debugLevel = valuesDict.get('showDebugLevel', "10") self.debugLog(u"User prefs saved.") self.listenPort = int(valuesDict.get('serverport', 9123)) self.debugextra = valuesDict.get('debugextra', False) try: self.logLevel = int(valuesDict[u"showDebugLevel"]) except: self.logLevel = logging.INFO self.indigo_log_handler.setLevel(self.logLevel) self.logger.debug(u"logLevel = " + str(self.logLevel)) return True def validateDeviceConfigUi(self, valuesDict, typeID, devId): self.logger.debug(u'validateDeviceConfigUi Called') errorDict = indigo.Dict() return (True, valuesDict, errorDict) def validatePrefsConfigUi(self, valuesDict): """ docstring placeholder """ self.logger.debug(u"------ validatePrefsConfigUi() method called.") errorDict = indigo.Dict() if 'serverport' in valuesDict: try: # self.logger.debug(u'Old listenPort is :' + unicode(self.oldlistenPort)) self.listenPort = int(valuesDict['serverport']) except: # self.logger.exception(u'Httpserverport Error') self.listenPort = 9123 self.pluginPrefs['serverport'] = 9123 errorDict['serverport'] = 'Please enter valid Port Number' errorDict[ 'showAlertText'] = 'The field is invalid as it is not an integer' return (False, valuesDict, errorDict) #self.logger.info(unicode(valuesDict)) return True, valuesDict def restartPlugin(self): self.logger.debug(u"Restarting the Plugin Called.") plugin = indigo.server.getPlugin('com.GlennNZ.indigoplugin.WinRemote') if plugin.isEnabled(): plugin.restart(waitUntilDone=False) # Start 'em up. def deviceStartComm(self, dev): self.logger.debug(u"deviceStartComm() method called.") dev.stateListOrDisplayStateIdChanged() dev.updateStateOnServer('pendingCommands', value='', uiValue='None') dev.updateStateOnServer('onOffState', value=False) dev.updateStateOnServer('deviceIsOnline', value=False) def createupdatevariable(self, variable, result): if self.debugextra: self.logger.debug(u'createupdate variable called.') if variable not in indigo.variables: indigo.variable.create(variable, str(result), folder='WinRemote') return else: indigo.variable.updateValue(str(variable), str(result)) return # Shut 'em down. def deviceStopComm(self, dev): self.logger.debug(u"deviceStopComm() method called.") #indigo.server.log(u"Stopping device: " + dev.name) def runConcurrentThread(self): try: self.checkComputers = t.time( ) + 10 # check for offline every 60 seconds while self.pluginIsShuttingDown == False: self.prefsUpdated = False self.sleep(0.5) if t.time() >= self.checkComputers: self.checktheComputers() self.checkComputers = t.time() + 60 # nothing else will run... self.sleep(1) except self.StopThread: self.logger.info(u'Restarting/or error. Stopping thread.') pass def checktheComputers(self): if self.debugextra: self.logger.debug(u'checkComputers run') for dev in indigo.devices.itervalues('self.WindowsComputer'): if dev.enabled: if dev.states['deviceIsOnline']: if (float(t.time()) - 120) > float( dev.states['deviceTimestamp'] ): #2 minutes no communication self.logger.debug(u't.time +120 equals:' + unicode(float(t.time()) + 120)) self.logger.debug( u'Offline : deviceTimestamp:t.time:' + unicode(t.time()) + ' Timestamp:' + unicode(dev.states['deviceTimestamp'])) dev.updateStateOnServer('deviceIsOnline', value=False, uiValue='Offline') dev.updateStateOnServer('onOffState', value=False) return def shutdown(self): self.logger.debug(u"shutdown() method called.") self.pluginIsShuttingDown = True self.prefsUpdated = True def startup(self): self.logger.debug(u"Starting Plugin. startup() method called.") self.updater = GitHubPluginUpdater(self) self.myThread = threading.Thread(target=self.listenHTTP, args=()) self.myThread.daemon = True self.myThread.start() def toggleDebugEnabled(self): """ Toggle debug on/off. """ self.logger.debug(u"toggleDebugEnabled() method called.") if self.debugLevel == int(logging.INFO): self.debug = True self.debugLevel = int(logging.DEBUG) self.pluginPrefs['showDebugInfo'] = True self.pluginPrefs['showDebugLevel'] = int(logging.DEBUG) self.logger.info(u"Debugging on.") self.logger.debug(u"Debug level: {0}".format(self.debugLevel)) self.logLevel = int(logging.DEBUG) self.logger.debug(u"New logLevel = " + str(self.logLevel)) self.indigo_log_handler.setLevel(self.logLevel) else: self.debug = False self.debugLevel = int(logging.INFO) self.pluginPrefs['showDebugInfo'] = False self.pluginPrefs['showDebugLevel'] = int(logging.INFO) self.logger.info(u"Debugging off. Debug level: {0}".format( self.debugLevel)) self.logLevel = int(logging.INFO) self.logger.debug(u"New logLevel = " + str(self.logLevel)) self.indigo_log_handler.setLevel(self.logLevel) ################################################################################################# def pluginTriggering(self, valuesDict): self.logger.debug(u'pluginTriggering called') try: #self.logger.info(unicode(valuesDict)) action = valuesDict.pluginTypeId actionevent = valuesDict.props['plugintriggersetting'] cameras = valuesDict.props['deviceCamera'] #self.logger.info(unicode(cameras)) for dev in indigo.devices.itervalues('self.WindowsComputer'): if str(dev.id) in cameras: self.logger.debug(u'Action is:' + unicode(action) + u' & Camera is:' + unicode(dev.name) + u' and action:' + unicode(actionevent)) if actionevent == 'False': dev.updateStateOnServer('PluginTriggeringEnabled', value=False) dev.updateStateOnServer('Motion', value=False, uiValue='False') if actionevent == 'True': dev.updateStateOnServer('PluginTriggeringEnabled', value=True) dev.updateStateOnServer('Motion', value=False, uiValue='False') return except: self.logger.exception(u'Caught Exception within pluginTriggerin') ################## communication to Computers ################## Triggers def triggerStartProcessing(self, trigger): self.logger.debug("Adding Trigger %s (%d) - %s" % (trigger.name, trigger.id, trigger.pluginTypeId)) assert trigger.id not in self.triggers self.triggers[trigger.id] = trigger def triggerStopProcessing(self, trigger): self.logger.debug("Removing Trigger %s (%d)" % (trigger.name, trigger.id)) assert trigger.id in self.triggers del self.triggers[trigger.id] def triggerCheck(self, device, camera, event): if self.debugtriggers: self.logger.debug('triggerCheck run. device.id:' + unicode(device.id) + ' Camera:' + unicode(camera) + ' Event:' + unicode(event)) try: if self.pluginIsInitializing: self.logger.info( u'Trigger: Ignore as WinRemote Plugin Just started.') return if device.states['deviceIsOnline'] == False: if self.debugtriggers: self.logger.debug( u'Trigger Cancelled as Device is Not Online') return if device.states['PluginTriggeringEnabled'] == False: if self.debugtriggers: self.logger.debug( u'Plugin Triggering is Disable for this Camera') return for triggerId, trigger in sorted(self.triggers.iteritems()): if self.debugtriggers: self.logger.debug( "Checking Trigger %s (%s), Type: %s, Camera: %s" % (trigger.name, trigger.id, trigger.pluginTypeId, camera)) #self.logger.debug(unicode(trigger)) #self.logger.error(unicode(trigger)) # Change to List for all Cameras if str(device.id) not in trigger.pluginProps['deviceCamera']: if self.debugtriggers: self.logger.debug( "\t\tSkipping Trigger %s (%s), wrong Camera: %s" % (trigger.name, trigger.id, device.id)) elif trigger.pluginTypeId == "motionTriggerOn" and event == 'motiontrue': if self.debugtriggers: self.logger.debug( "===== Executing motionTriggerOn/motiontrue Trigger %s (%d)" % (trigger.name, trigger.id)) indigo.trigger.execute(trigger) elif trigger.pluginTypeId == "motionTriggerOff" and event == 'motionfalse': if self.debugtriggers: self.logger.debug( "===== Executing motionTriggerOff/motionfalse Trigger %s (%d)" % (trigger.name, trigger.id)) indigo.trigger.execute(trigger) else: if self.debugtriggers: self.logger.debug( "Not Run Trigger Type %s (%d), %s" % (trigger.name, trigger.id, trigger.pluginTypeId)) except: self.logger.exception(u'Caught Exception within Trigger Check') return ## Update routines def checkForUpdates(self): updateavailable = self.updater.getLatestVersion() if updateavailable and self.openStore: self.logger.info( u'WinRemote Plugin: Update Checking. Update is Available. Taking you to plugin Store. ' ) self.sleep(2) self.pluginstoreUpdate() elif updateavailable and not self.openStore: self.errorLog( u'WinRemote Plugin: Update Checking. Update is Available. Please check Store for details/download.' ) def updatePlugin(self): self.updater.update() def pluginstoreUpdate(self): iurl = 'http://www.indigodomo.com/pluginstore/160/' self.browserOpen(iurl) ###################### def listenHTTP(self): try: self.debugLog(u"Starting HTTP listener thread") indigo.server.log(u"Http Server Listening on TCP port " + str(self.listenPort)) self.server = ThreadedHTTPServer( ('', self.listenPort), lambda *args: httpHandler(self, *args)) self.server.serve_forever() except self.StopThread: self.logger.debug(u'Self.Stop Thread called') pass except: self.logger.exception(u'Caught Exception in ListenHttp') ################## Actions def actionControlDevice(self, action, dev): self.logger.debug(u'Turn On/Turn Off Called') if action.deviceAction == indigo.kDeviceAction.TurnOff: turnOff = dev.pluginProps.get('turnOff', False) self.logger.debug(u"actionControlDevice: \"%s\" Turn Off" % dev.name) if turnOff == False: tobesent = { 'COMMAND': 'OFF', 'COMMAND2': '', 'COMMAND3': '', 'COMMAND4': '' } dev.updateStateOnServer('pendingCommands', value=str(tobesent), uiValue='Pending...') else: self.logger.debug( u'Turn Off Command not sent as Disabled within Device Config' ) return elif action.deviceAction == indigo.kDeviceAction.TurnOn: self.logger.debug(u"actionControlDevice: \"%s\" Turn On" % dev.name) self.actionWakeMACbydevid(dev.id) return elif action.deviceAction == indigo.kDeviceAction.RequestStatus: self.logger.info(u'Send Status Not Supported.') return def actionrunProcess(self, valuesDict): self.logger.debug(u'Send Message Called.') try: computers = valuesDict.props['computer'] process = valuesDict.props['process'] arguments = valuesDict.props['arguments'] for dev in indigo.devices.itervalues('self.WindowsComputer'): if str(dev.id) in computers: tobesent = { 'COMMAND': 'PROCESS', 'COMMAND2': str(process), 'COMMAND3': str(arguments), 'COMMAND4': '' } dev.updateStateOnServer('pendingCommands', value=str(tobesent), uiValue='Pending...') except: self.logger.exception(u'Exception in action Send Message') return def actionSendMessage(self, valuesDict): self.logger.debug(u'Send Message Called.') try: computers = valuesDict.props['computer'] message = valuesDict.props['message'] for dev in indigo.devices.itervalues('self.WindowsComputer'): if str(dev.id) in computers: #tobesent = 'COMMAND MESSAGE',message tobesent = { 'COMMAND': 'MESSAGE', 'COMMAND2': str(message), 'COMMAND3': '', 'COMMAND4': '' } dev.updateStateOnServer('pendingCommands', value=str(tobesent), uiValue='Pending...') except: self.logger.exception(u'Exception in action Send Message') return def actionRestart(self, valuesDict): self.logger.debug(u'Restart Command Called.') try: computers = valuesDict.props['computer'] message = 'This computer will be restarted in 20 seconds' for dev in indigo.devices.itervalues('self.WindowsComputer'): if str(dev.id) in computers: turnOff = dev.pluginProps.get('turnOff', False) tobesent = { 'COMMAND': 'RESTART', 'COMMAND2': '', 'COMMAND3': '', 'COMMAND4': '' } # check device settings ignore if turn off ignored. if turnOff == False: dev.updateStateOnServer('pendingCommands', value=str(tobesent), uiValue='Pending...') else: self.logger.info( u'Restart Command not sent as Disabled within Device Config' ) except: self.logger.exception(u'Exception in action Send Message') return def actionRemovecommand(self, valuesDict): self.logger.debug(u'action Remove Command.') try: computers = valuesDict.props['computer'] #message = 'This computer will be turned off in 10 seconds' for dev in indigo.devices.itervalues('self.WindowsComputer'): if str(dev.id) in computers: dev.updateStateOnServer('pendingCommands', value='', uiValue='') except: self.logger.exception( u'Exception in action Remove Command Message') return def actionTurnOff(self, valuesDict): self.logger.debug(u'Turn Off Called.') try: computers = valuesDict.props['computer'] message = 'This computer will be turned off in 10 seconds' for dev in indigo.devices.itervalues('self.WindowsComputer'): if str(dev.id) in computers: turnOff = dev.pluginProps.get('turnOff', False) # tobesent = 'COMMAND OFF',message tobesent = { 'COMMAND': 'OFF', 'COMMAND2': '', 'COMMAND3': '', 'COMMAND4': '' } if turnOff == False: dev.updateStateOnServer('pendingCommands', value=str(tobesent), uiValue='Pending...') else: self.logger.debug( u'Turn Off Command not sent as Disabled within Device Config' ) except: self.logger.exception(u'Exception in action Turn Off') return def actionLock(self, valuesDict): self.logger.debug(u'actionLock Message Called.') try: computers = valuesDict.props['computer'] message = 'This computer will be Locked off in 10 seconds' for dev in indigo.devices.itervalues('self.WindowsComputer'): if str(dev.id) in computers: tobesent = 'COMMAND LOCK', message tobesent = { 'COMMAND': 'LOCK', 'COMMAND2': '', 'COMMAND3': '', 'COMMAND4': '' } dev.updateStateOnServer('pendingCommands', value=str(tobesent), uiValue='Pending...') except: self.logger.exception(u'Exception in action Lock') return def actionWakeMACbydevid(self, devid): self.logger.debug(u'actionWakeMAC by devid called') try: dev = indigo.devices[devid] # Take the entered MAC address and format it to be sent via socket if dev.states['MACaddress'] != 'unknown' or dev.states[ 'MACaddress'] != '': macaddress = str(dev.states['MACaddress']) #ipaddress = dev.states if len(macaddress) == 12: if len(macaddress) == 12: pass elif len(macaddress) == 17: sep = macaddress[2] macaddress = macaddress.replace(sep, '') else: self.logger.debug( u'Wrong Format of MAC address ? not known.') return data = b'FFFFFFFFFFFF' + (macaddress * 20).encode() self.logger.debug('Macaddress now:' + unicode(macaddress)) send_data = b'' # Split up the hex values in pack for i in range(0, len(data), 2): send_data += struct.pack(b'B', int(data[i:i + 2], 16)) self.packet = send_data s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) self.logger.debug('sending magicPacket:') s.connect(('255.255.255.255', 9)) s.send(self.packet) # s.send(self.packet) s.close() else: self.logger.info(u'MAC Address not known as yet.') return except: self.logger.exception(u'Exception in Action wake MAC') def actionWakeMAC(self, valuesDict): self.logger.debug(u'actionWakeonLAN MAC called') try: computers = valuesDict.props['computer'] for dev in indigo.devices.itervalues('self.WindowsComputer'): if str(dev.id) in computers: # Take the entered MAC address and format it to be sent via socket if dev.states['MACaddress'] != 'unknown' or dev.states[ 'MACaddress'] != '': macaddress = str(dev.states['MACaddress']) #ipaddress = dev.states if len(macaddress) == 12: if len(macaddress) == 12: pass elif len(macaddress) == 17: sep = macaddress[2] macaddress = macaddress.replace(sep, '') else: self.logger.debug( u'Wrong Format of MAC address ? not known.') return data = b'FFFFFFFFFFFF' + (macaddress * 20).encode() self.logger.debug('Macaddress now:' + unicode(macaddress)) send_data = b'' # Split up the hex values in pack for i in range(0, len(data), 2): send_data += struct.pack(b'B', int(data[i:i + 2], 16)) self.packet = send_data s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) self.logger.debug('sending magicPacket:') s.connect(('255.255.255.255', 9)) s.send(self.packet) # s.send(self.packet) s.close() except: self.logger.exception(u'Exception in Action wake MAC')
class Plugin(indigo.PluginBase): ######################################## def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = False self.updater = GitHubPluginUpdater(self) ######################################### # Plugin startup and shutdown ######################################### def startup(self): self.debugLog(u"startup called") def shutdown(self): self.debugLog(u"shutdown called") def didDeviceCommPropertyChange(self, origDev, newDev): return False ######################################### # Main Loop ######################################### def runConcurrentThread(self): try: ######################################### # Variable Setup ######################################### timeremaining = 0 refreshduration = 5 refreshcycle = refreshduration repeat = "" shuffle = "" logdevice = self.logger while True: for device in indigo.devices.iter("self"): ######################################### # Main Code ######################################### state = device.states["state"] if state == "playing": timeremaining = timeremaining - 1000 device.updateStateOnServer("timeremaining", value=timeremaining) consec, conmin = convertms(timeremaining) device.updateStateOnServer("timeremainingtext", value=str(conmin) + ":" + str(consec).zfill(2)) else: device.updateStateOnServer("timeremainingtext", value="0") refreshcycle = refreshcycle + 1 #Check for status of player every five seconds if timeremaining < 0 or refreshcycle > refreshduration: spotifykey = device.pluginProps["SpotifyKey"] refreshkey = device.pluginProps["RefreshKey"] refreshcycle = 0 playingsong = False playerstate = False try: playerstate = GetPlayerState( self.logger, device, spotifykey) except Exception as errtxt: self.logger.debug("error 85:" + str(errtxt)) #indigo.server.log(str(playerstate)) #indigo.server.log("A:" + getspotifydevice(device)) #indigo.server.log("1:" + str(playerstate['isplaying'])) if getspotifydevice( self.logger, device) != "Device Not Found" and (str( playerstate['result']) == "True") and (str( playerstate['isplaying']) == "True"): spotifydevice = playerstate['spotifydevice'] keyValueList = [{ 'key': 'state', 'value': 'playing' }] #device.updateStateOnServer("state", "playing") contextmeta = playerstate[ 'spotifycontexturi'].split(":") #indigo.server.log(playlistmeta[2]) #indigo.server.log(playlistmeta[4]) #indigo.server.log(str(contextmeta)) #indigo.server.log(playerstate['spotifycontexttype']) GetContextDetail(self.logger, device, playerstate['spotifycontexttype'], spotifykey, contextmeta) #Check volume if int(playerstate['spotifyvolume']) != int( device.states["volume"]): keyValueList.append({ 'key': 'volume', 'value': playerstate['spotifyvolume'] }) #device.updateStateOnServer("volume", playerstate['spotifyvolume']) #Check repeat if playerstate['repeat'] != device.states["repeat"]: if device.states["repeat"] == "off": keyValueList.append({ 'key': 'repeat', 'value': 'context' }) #device.updateStateOnServer("repeat", value="context") else: keyValueList.append({ 'key': 'repeat', 'value': 'off' }) #device.updateStateOnServer("repeat", value="off") #Check shuffle if str(playerstate['shuffle']) != str( device.states["shuffle"]): if str(device.states["shuffle"]) == "False": keyValueList.append({ 'key': 'shuffle', 'value': 'True' }) #device.updateStateOnServer("shuffle", value="True") else: keyValueList.append({ 'key': 'shuffle', 'value': 'False' }) #device.updateStateOnServer("shuffle", value="False") #Update song information playingsong = GetCurrentSong( self.logger, device, spotifykey) if playingsong['result'] != "False": timeremaining = playingsong[ 'duration'] - playingsong['progress'] consec, conmin = convertms( playingsong['duration']) keyValueList.append({ 'key': 'durationtext', 'value': str(conmin) + ":" + str(consec).zfill(2) }) if playingsong['track'] != device.states[ "c_track"]: UpdateCurrentSong(self.logger, device, playingsong) else: self.logger.debug(u"Get playing song failed") device.updateStatesOnServer(keyValueList) else: if getspotifydevice(self.logger, device) != "Device Not Found": device.updateStateOnServer("state", value="paused") self.sleep(1) except self.StopThread: indigo.server.log("thread stopped") pass ################################################################################ # Plugin menus ################################################################################ def checkForUpdate(self): ActiveVersion = str(self.pluginVersion) CurrentVersion = str(self.updater.getVersion()) if ActiveVersion == CurrentVersion: indigo.server.log("Running the most recent version of Indify") else: indigo.server.log("The current version of Indify is " + str(CurrentVersion) + " and the running version " + str(ActiveVersion) + ".") def updatePlugin(self): ActiveVersion = str(self.pluginVersion) CurrentVersion = str(self.updater.getVersion()) if ActiveVersion == CurrentVersion: indigo.server.log( "Already running the most recent version of Indify") else: indigo.server.log("The current version of Indify is " + str(CurrentVersion) + " and the running version " + str(ActiveVersion) + ".") self.updater.update() def RefreshKey(self): indigo.server.log("?? Refresh Key") #RefreshKey(device, refreshkey) ############################################################################ # Plugin Actions object callbacks ############################################################################ #015 def toggle(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifykey = device.pluginProps["SpotifyKey"] state = device.states["state"] spotifydevice = getspotifydevice(self.logger, device) if state == "playing": response = callspotifycommand( self.logger, "015", device, "put", "https://api.spotify.com/v1/me/player/pause") if response != "Error": device.updateStateOnServer("state", value="paused") else: response = callspotifycommand( self.logger, "015", device, "put", "https://api.spotify.com/v1/me/player/", { "device_ids": [spotifydevice], "play": True }) if response != "Error": device.updateStateOnServer("state", value="playing") #016 def play(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifydevice = getspotifydevice(self.logger, device) response = callspotifycommand(self.logger, "016", device, "put", "https://api.spotify.com/v1/me/player/", { "device_ids": [spotifydevice], "play": True }) if response != "Error": device.updateStateOnServer("state", value="playing") #017 def pause(self, pluginAction): device = indigo.devices[pluginAction.deviceId] response = callspotifycommand( self.logger, "017", device, "put", "https://api.spotify.com/v1/me/player/pause") if response != "Error": device.updateStateOnServer("state", value="paused") #018 def next(self, pluginAction): device = indigo.devices[pluginAction.deviceId] state = device.states["state"] if state == "playing": response = callspotifycommand( self.logger, "018", device, "post", "https://api.spotify.com/v1/me/player/next") #019 def previous(self, pluginAction): device = indigo.devices[pluginAction.deviceId] state = device.states["state"] if state == "playing": response = callspotifycommand( self.logger, "019", device, "post", "https://api.spotify.com/v1/me/player/previous") #020 def playuri(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifyuri = pluginAction.props["spotifyuri"] uribody = {"context_uri": spotifyuri} response = callspotifycommand( self.logger, "020", device, "put", "https://api.spotify.com/v1/me/player/play", uribody) def repeat(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifykey = device.pluginProps["SpotifyKey"] repeat = device.states["repeat"] if repeat == "off": device.updateStateOnServer("repeat", value="context") ChangeRepeat(self.logger, device, spotifykey, "context") else: device.updateStateOnServer("repeat", value="off") ChangeRepeat(self.logger, device, spotifykey, "off") def shuffle(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifykey = device.pluginProps["SpotifyKey"] shuffle = device.states["shuffle"] if shuffle == "False": device.updateStateOnServer("shuffle", value="True") ChangeShuffle(self.logger, device, spotifykey, "True") else: device.updateStateOnServer("shuffle", value="False") ChangeShuffle(self.logger, device, spotifykey, "False") def setvolume(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifykey = device.pluginProps["SpotifyKey"] newvolume = int(pluginAction.props["setpercent"]) SetVolume(self.logger, device, spotifykey, newvolume) device.updateStateOnServer("volume", value=newvolume) def increasevolume(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifykey = device.pluginProps["SpotifyKey"] oldvolume = int(device.states['volume']) increasepercent = int(pluginAction.props["increasepercent"]) if int(oldvolume) < 100: newvolume = oldvolume + increasepercent SetVolume(self.logger, device, spotifykey, newvolume) device.updateStateOnServer("volume", value=newvolume) def decreasevolume(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifykey = device.pluginProps["SpotifyKey"] oldvolume = device.states['volume'] decreasepercent = int(pluginAction.props["decreasepercent"]) if int(oldvolume) > 0: newvolume = oldvolume - decreasepercent SetVolume(self.logger, device, spotifykey, newvolume) device.updateStateOnServer("volume", value=newvolume) def loadplaylistpage(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifykey = device.pluginProps["SpotifyKey"] state = device.states["state"] itemsperpage = int(device.pluginProps["PlaylistsPerPage"]) pagenumber = int(pluginAction.props["pagenumber"]) LoadPlayListPage(self.logger, device, spotifykey, pagenumber, itemsperpage) def nextplaylistpage(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifykey = device.pluginProps["SpotifyKey"] playlistpage = int(device.states["playlistpage"]) itemsperpage = int(device.pluginProps["PlaylistsPerPage"]) pagenumber = playlistpage + 1 LoadPlayListPage(self.logger, device, spotifykey, pagenumber, itemsperpage) def previousplaylistpage(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifykey = device.pluginProps["SpotifyKey"] playlistpage = int(device.states["playlistpage"]) itemsperpage = int(device.pluginProps["PlaylistsPerPage"]) pagenumber = playlistpage - 1 LoadPlayListPage(self.logger, device, spotifykey, pagenumber, itemsperpage) def selectplaylist(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifykey = device.pluginProps["SpotifyKey"] selectedplaylist = int(pluginAction.props["selectedplaylist"]) playlistid = device.states["playlistid_" + str(selectedplaylist)] playlistuser = device.states["playlistuser_" + str(selectedplaylist)] LoadPlaylistDetail(self.logger, device, spotifykey, playlistuser, playlistid) itemsperpage = int(device.pluginProps["TracksPerPage"]) LoadTrackPage(self.logger, device, playlistuser, playlistid, spotifykey, 1, itemsperpage) def loadtrackspage(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifykey = device.pluginProps["SpotifyKey"] pagenumber = int(pluginAction.props["trackpagenumber"]) playlistid = device.states["playlistid"] playlistuser = device.states["playlistuserid"] itemsperpage = int(device.pluginProps["TracksPerPage"]) LoadTrackPage(self.logger, device, playlistuser, playlistid, spotifykey, pagenumber, itemsperpage) def nexttrackspage(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifykey = device.pluginProps["SpotifyKey"] trackpage = int(device.states["trackpage"]) playlistid = device.states["playlistid"] playlistuser = device.states["playlistuserid"] itemsperpage = int(device.pluginProps["TracksPerPage"]) pagenumber = trackpage + 1 LoadTrackPage(self.logger, device, playlistuser, playlistid, spotifykey, pagenumber, itemsperpage) def previoustrackspage(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifykey = device.pluginProps["SpotifyKey"] trackpage = int(device.states["trackpage"]) playlistid = device.states["playlistid"] playlistuser = device.states["playlistuserid"] itemsperpage = int(device.pluginProps["TracksPerPage"]) pagenumber = trackpage - 1 LoadTrackPage(self.logger, device, playlistuser, playlistid, spotifykey, pagenumber, itemsperpage) #020 def getspotifydevices(self, filter, valuesDict, typeId, devId): device = indigo.devices[devId] refreshkey = device.pluginProps["SpotifyKey"] keysuccess = "False" spotifydevicearray = [] try: spotifykey = device.pluginProps["SpotifyKey"] spotifyurl = "https://api.spotify.com/v1/me/player/devices" spotifyheader = {"Authorization": "Bearer " + spotifykey} response = requests.get(spotifyurl, headers=spotifyheader, timeout=(1, 6)) data = json.loads(response.text) for spotifydevices in data['devices']: spotifydevice = (spotifydevices['name'], spotifydevices['name']) spotifydevicearray.append(spotifydevice) except: indigo.server.log("error 020: Refreshing Spotify Key") keysuccess = RefreshKey(self.logger, device, refreshkey) if keysuccess == "True": self.logger.debug("New Key Aquired") else: #### add code to retry device lookup without getting into crazy loop #### set spotify state to offline #### wait 30 seconds and try again spotifydevicearray.append(("0", "Error in Spotify key Lookup")) return spotifydevicearray #020 def playselectedplaylist(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifydevice = getspotifydevice(self.logger, device) spotifydata = { "context_uri": "spotify:user:"******"playlistuserid"] + ":playlist:" + device.states["playlistid"], "device_ids": [spotifydevice] } response = callspotifycommand( self.logger, "020", device, "put", "https://api.spotify.com/v1/me/player/play", spotifydata) if response != "Error": device.updateStateOnServer("state", value="playing") #021 def playplaylist(self, pluginAction): device = indigo.devices[pluginAction.deviceId] spotifydevice = getspotifydevice(self.logger, device) selectedplaylist = int(pluginAction.props["PlaySelectedPlaylist"]) playlistid = device.states["playlistid_" + str(selectedplaylist)] playlistuser = device.states["playlistuser_" + str(selectedplaylist)] spotifydata = { "context_uri": "spotify:user:"******":playlist:" + playlistid, "device_ids": [spotifydevice] } response = callspotifycommand( self.logger, "021", device, "put", "https://api.spotify.com/v1/me/player/play", spotifydata) if response != "Error": device.updateStateOnServer("state", value="playing") def validatespotifyid(self, valuesDict, typeId, devId): device = indigo.devices[devId] device.replacePluginPropsOnServer(valuesDict) indigo.server.log("Updating Spotify device list")
class Plugin(indigo.PluginBase): ######################################## def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.NuHeat = NuHeat(self) self.debug = pluginPrefs.get("debug", False) self.UserID = None self.Password = None self.deviceList = {} self.loginFailed = False self.restartCount = 0 ###################### 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)) ###################### # Poll all of the states from the thermostat and pass new values to # Indigo Server. def _refreshStatesFromHardware(self, dev, logRefresh, commJustStarted): thermostatId = dev.pluginProps["thermostatId"] self.debugLog(u"Getting data for thermostatId: %s" % thermostatId) thermostat = NuHeat.GetThermostat(self.NuHeat, thermostatId) self.debugLog(u"Device Name: %s" % thermostat.room) self.debugLog(u"***Device SystemSwitch: %s" % thermostat.Mode) try: self.updateStateOnServer(dev, "name", thermostat.room) except: self.de(dev, "name") try: self.updateStateOnServer(dev, "setpointHeat", float(thermostat.SetPointTemp)) except: self.de(dev, "setpointHeat") try: self.updateStateOnServer(dev, "maxHeatSetpoint", thermostat.MaxTemp) except: self.de(dev, "maxHeatSetpoint") try: self.updateStateOnServer(dev, "minHeatSetpoint", thermostat.MinTemp) except: self.de(dev, "minHeatSetpoint") try: self.updateStateOnServer(dev, "online", thermostat.Online) except: pass try: self.updateStateOnServer(dev, "temperatureInput1", thermostat.Temperature) except: pass self.debugLog(u"Heating: %s" % thermostat.Heating) if thermostat.Heating == True: self.updateStateOnServer(dev, "hvacHeaterIsOn", True) else: self.updateStateOnServer(dev, "hvacHeaterIsOn", False) def updateStateOnServer(self, dev, state, value): if dev.states[state] != value: self.debugLog(u"Updating Device: %s, State: %s, Value: %s" % (dev.name, state, value)) dev.updateStateOnServer(state, value) def de(self, dev, value): self.errorLog("[%s] No value found for device: %s, field: %s" % (time.asctime(), dev.name, value)) ###################### # Process action request from Indigo Server to change a cool/heat setpoint. def _handleChangeSetpointAction(self, dev, newSetpoint, Permanent, duration, logActionName, stateKey): self.debugLog(u"_handleChangeSetpointAction - StateKey: %s" % stateKey) sendSuccess = False thermostatId = dev.pluginProps["thermostatId"] self.debugLog(u"Getting data for thermostatId: %s" % thermostatId) self.debugLog(u"NewSetpoint: %s, Permanent: %s, Duration: %s" % (newSetpoint, Permanent, duration)) thermostat = NuHeat.GetThermostat(self.NuHeat, thermostatId) if stateKey == u"setpointHeat": # if newSetpoint < dev.states["maxHeatSetpoint"]: # newSetpoint = dev.states["maxHeatSetpoint"] # elif newSetpoint > dev.states["minHeatSetpoint"]: # newSetpoint = dev.states["minHeatSetpoint"] if Permanent == True: duration = -1 sendSuccess = self.NuHeat.SetThermostatHeatSetpoint( thermostat, newSetpoint, duration) if sendSuccess: # If success then log that the command was successfully sent. indigo.server.log(u"sent \"%s\" %s to %.1f°" % (dev.name, logActionName, float(newSetpoint))) # And then tell the Indigo Server to update the state. if stateKey in dev.states: dev.updateStateOnServer(stateKey, newSetpoint, uiValue="%.1f °F" % float(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, float(newSetpoint)), isError=True) def _handleResumeScheduleAction(self, dev, logActionName, stateKey): self.debugLog(u"_handleResumeScheduleAction - StateKey: %s" % stateKey) sendSuccess = False thermostatId = dev.pluginProps["thermostatId"] self.debugLog(u"Getting data for thermostatId: %s" % thermostatId) thermostat = NuHeat.GetThermostat(self.NuHeat, thermostatId) sendSuccess = self.NuHeat.SetResumeSchedule(thermostat) if sendSuccess: # If success then log that the command was successfully sent. indigo.server.log(u"sent \"%s\" %s" % (dev.name, logActionName)) else: # Else log failure but do NOT update state on Indigo Server. indigo.server.log(u"send \"%s\" %s failed" % (dev.name, logActionName), isError=True) ######################################## def startup(self): self.debugLog(u"NuHeat startup called") self.debug = self.pluginPrefs.get('showDebugInLog', False) self.updater = GitHubPluginUpdater(self) #self.updater.checkForUpdate() self.updateFrequency = float( self.pluginPrefs.get('updateFrequency', 24)) * 60.0 * 60.0 self.debugLog(u"updateFrequency = " + str(self.updateFrequency)) self.next_update_check = time.time() self.login(False) def login(self, force): if self.NuHeat.startup(force) == False: indigo.server.log( u"Login to mynuheat.com site failed. Canceling processing!", isError=True) self.loginFailed = True return else: self.loginFailed = False self.buildAvailableDeviceList() def shutdown(self): self.debugLog(u"shutdown called") ######################################## def runConcurrentThread(self): try: while True: if self.loginFailed == False: if (self.updateFrequency > 0.0) and (time.time() > self.next_update_check): self.next_update_check = time.time( ) + self.updateFrequency self.updater.checkForUpdate() for dev in indigo.devices.iter("self"): if not dev.enabled: 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.restartCount = self.restartCount + 1 if (self.restartCount > 10000): self.restartCount = 0 indigo.server.log( u"Memory Leak Prevention. Restarting Plugin. - This will happen until I find and fix the leak" ) serverPlugin = indigo.server.getPlugin(self.pluginId) serverPlugin.restart(waitUntilDone=False) break self.sleep(20) except self.StopThread: pass # Optionally catch the StopThread exception and do any needed cleanup. ######################################## def validateDeviceConfigUi(self, valuesDict, typeId, devId): indigo.server.log(u"validateDeviceConfigUi \"%s\"" % (valuesDict)) return (True, valuesDict) def validatePrefsConfigUi(self, valuesDict): self.debugLog(u"Vaidating Plugin Configuration") errorsDict = indigo.Dict() if len(errorsDict) > 0: self.errorLog(u"\t Validation Errors") return (False, valuesDict, errorsDict) else: self.debugLog(u"\t Validation Succesful") return (True, valuesDict) return (True, valuesDict) ######################################## def deviceStartComm(self, dev): if self.loginFailed == True: return # 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.initDevice(dev) dev.stateListOrDisplayStateIdChanged() #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. #Called when the device is changed via UI def actionControlThermostat(self, action, dev): ###### SET HVAC MODE ###### if action.thermostatAction == indigo.kThermostatAction.SetHeatSetpoint: newSetpoint = action.actionValue self._handleChangeSetpointAction(dev, newSetpoint, False, 1, u"change heat setpoint", u"setpointHeat") ###### DECREASE/INCREASE HEAT SETPOINT ###### elif action.thermostatAction == indigo.kThermostatAction.DecreaseHeatSetpoint: newSetpoint = dev.heatSetpoint - action.actionValue self._handleChangeSetpointAction(dev, newSetpoint, False, 1, u"decrease heat setpoint", u"setpointHeat") elif action.thermostatAction == indigo.kThermostatAction.IncreaseHeatSetpoint: newSetpoint = dev.heatSetpoint + action.actionValue self._handleChangeSetpointAction(dev, newSetpoint, False, 1, 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) ######################################## # 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 _actionSetMode(self, pluginAction): self.debugLog(u"\t Setting Mode: %s" % pluginAction.props.get("mode")) dev = indigo.devices[pluginAction.deviceId] self._handleChangeHvacModeAction( dev, map_to_indigo_hvac_mode[pluginAction.props.get("mode")]) def _actionSetpoint(self, pluginAction): self.debugLog( u"\t Set %s - Setpoint: %s" % (pluginAction.pluginTypeId, pluginAction.props.get("Temprature"))) dev = indigo.devices[pluginAction.deviceId] self.debugLog(u"\t Permanent: %s " % (pluginAction.props)) self._handleChangeSetpointAction(dev, pluginAction.props.get("Temprature"), pluginAction.props.get("Timing"), pluginAction.props.get("Duration"), "Action Setpoint", pluginAction.pluginTypeId) def _actionResumeSchedule(self, pluginAction): self.debugLog(u"\t Resume Schedule") dev = indigo.devices[pluginAction.deviceId] self._handleResumeScheduleAction(dev, "Action Resume Schedule", pluginAction.pluginTypeId) def closedPrefsConfigUi(self, valuesDict, userCancelled): if not userCancelled: #Check if Debugging is set try: self.debug = self.pluginPrefs[u'showDebugInLog'] except: self.debug = False try: if (self.UserID != self.pluginPrefs["UserID"]) or \ (self.Password != self.pluginPrefs["Password"]): indigo.server.log("[%s] Replacting Username/Password." % time.asctime()) self.UserID = self.pluginPrefs["UserID"] self.Password = self.pluginPrefs["Password"] except: pass indigo.server.log("[%s] Processed plugin preferences." % time.asctime()) self.login(True) return True def validateDeviceConfigUi(self, valuesDict, typeId, devId): self.debugLog(u"validateDeviceConfigUi called with valuesDict: %s" % str(valuesDict)) # Set the address valuesDict["ShowCoolHeatEquipmentStateUI"] = True return (True, valuesDict) def initDevice(self, dev): new_props = dev.pluginProps new_props['SupportsHvacFanMode'] = False new_props['SupportsHvacOperationMode'] = False dev.replacePluginPropsOnServer(new_props) self.debugLog("Initializing thermostat device: %s" % dev.name) def buildAvailableDeviceList(self): self.debugLog("Building Available Device List") self.deviceList = self.NuHeat.GetDevices() indigo.server.log("Number of thermostats found: %i" % (len(self.deviceList))) for (k, v) in self.deviceList.iteritems(): indigo.server.log("\t%s (id: %s)" % (v.room, k)) def showAvailableThermostats(self): indigo.server.log("Number of thermostats found: %i" % (len(self.deviceList))) for (id, details) in self.deviceList.iteritems(): indigo.server.log("\t%s (id: %s)" % (details.room, id)) def thermostatList(self, filter, valuesDict, typeId, targetId): self.debugLog("thermostatList called") deviceArray = [] deviceListCopy = deepcopy(self.deviceList) for existingDevice in indigo.devices.iter("self"): for id in self.deviceList: self.debugLog(" comparing %s against deviceList item %s" % (existingDevice.pluginProps["thermostatId"], id)) if existingDevice.pluginProps["thermostatId"] == id: self.debugLog(" removing item %s" % (id)) del deviceListCopy[id] break if len(deviceListCopy) > 0: for (id, value) in deviceListCopy.iteritems(): deviceArray.append((id, value.room)) else: if len(self.deviceList): indigo.server.log("All thermostats found are already defined") else: indigo.server.log( "No thermostats were discovered on the network - select \"Rescan for Thermostats\" from the plugin's menu to rescan" ) self.debugLog(" thermostatList deviceArray:\n%s" % (str(deviceArray))) return deviceArray def thermostatSelectionChanged(self, valuesDict, typeId, devId): self.debugLog("thermostatSelectionChanged") if valuesDict["thermostat"] in self.deviceList: selectedThermostatData = self.deviceList[valuesDict["thermostat"]] valuesDict["address"] = valuesDict["thermostat"] valuesDict["thermostatId"] = valuesDict["thermostat"] valuesDict["name"] = selectedThermostatData.room self.debugLog( " thermostatSelectionChanged valuesDict to be returned:\n%s" % (str(valuesDict))) return valuesDict ########################################## def checkForUpdates(self): self.updater.checkForUpdate() def updatePlugin(self): self.updater.update() def forceUpdate(self): self.updater.update(currentVersion='0.0.0')
class Plugin(indigo.PluginBase): def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.updater = GitHubPluginUpdater(self) self.ControllerIP = "" self.ControllerPort = "" self.ControllerRel = "V4" self.ControllerSite = "" self.ControllerAuth = False self.ControllerUsername = "" self.ControllerPassword = "" self.ControllerInterval = 0 self.ControllerURL = "" self.ControllerURLAPI = "" self.CurlCommand = "" # create empty device list self.userDeviceList = {} self.wlanDeviceList = {} self.sock = None self.socketBufferSize = 512 self.socketStop = False self.pushoverPlugin = None def __del__(self): indigo.PluginBase.__del__(self) ################################################################### # Plugin ################################################################### def deviceStartComm(self, device): self.debugLog(device.name + ": Starting device") device.stateListOrDisplayStateIdChanged() self.addDeviceToList (device) def addDeviceToList(self,device): if device: if device.deviceTypeId == u"unifiuser": self.addDeviceToListUser(device) elif device.deviceTypeId == u"unifiwlan": self.addDeviceToListWlan(device) def addDeviceToListUser(self,device): propsIPAddress = '' propsMACAddress = '' if device.id not in self.userDeviceList: propsIPAddress = device.pluginProps["ipaddress"].strip().replace (' ','') propsMACAddress = device.pluginProps["macaddress"].strip().replace (' ','') self.userDeviceList[device.id] = {'ref':device, 'ipaddress':propsIPAddress, 'macaddress':propsMACAddress} if propsMACAddress > '': device.pluginProps["address"] = propsMACAddress else: device.pluginProps["address"] = propsIPAddress def addDeviceToListWlan(self,device): if device.id not in self.wlanDeviceList: ssid = device.pluginProps["ssid"].strip() self.wlanDeviceList[device.id] = {'ref':device, 'ssid':ssid} def deleteDeviceFromList(self, device): if device: if device.deviceTypeId == u"unifiuser": if device.id in self.userDeviceList: del self.userDeviceList[device.id] elif device.deviceTypeId == u"unifiwlan": if device.id in self.wlanDeviceList: del self.wlanDeviceList[device.id] def deviceStopComm(self,device): if device.id not in self.userDeviceList: return self.debugLog(device.name + ": Stoping device") self.deleteDeviceFromList(device) def startup(self): self.loadPluginPrefs() self.debugLog(u"startup called") self.requestID = 0 self.pushoverPlugin = indigo.server.getPlugin("io.thechad.indigoplugin.pushover") if not self.pushoverPlugin.isEnabled(): self.debugLog (u"Error: Pushover plugin is not enabled") self.updater.checkForUpdate() def shutdown(self): self.debugLog(u"shutdown called") def deviceCreated(self, device): self.debugLog(u"Created device of type \"%s\"" % device.deviceTypeId) def validateDeviceConfigUi(self, valuesDict, typeId, devId): self.debugLog(u"validating device Prefs called") if typeId == "unifiuser": ipAdr = valuesDict[u'ipaddress'] macAdr = valuesDict[u'macaddress'] if (ipAdr > "") or (macAdr > ""): pass else: errorMsgDict = indigo.Dict() errorMsgDict[u'ipaddress'] = u"Mac or IP address needed." errorMsgDict[u'macaddress'] = u"Mac or IP address needed." return (False, valuesDict, errorMsgDict) if (ipAdr > ""): if ipAdr.count('.') != 3: errorMsgDict = indigo.Dict() errorMsgDict[u'ipaddress'] = u"This needs to be a valid IP address." return (False, valuesDict, errorMsgDict) if self.validateAddress (ipAdr) == False: errorMsgDict = indigo.Dict() errorMsgDict[u'ipaddress'] = u"This needs to be a valid IP address." return (False, valuesDict, errorMsgDict) if (macAdr > ""): #1c:ab:a7:d8:23:d2 if macAdr.count(':') != 5: errorMsgDict = indigo.Dict() errorMsgDict[u'macaddress'] = u"This needs to be a valid MAC address." return (False, valuesDict, errorMsgDict) if typeId == "unifiwlan": ssid = valuesDict[u'ssid'].strip() if not ssid: errorMsgDict = indigo.Dict() errorMsgDict[u'ssid'] = u"SSID needed." return (False, valuesDict, errorMsgDict) return (True, valuesDict) def validatePrefsConfigUi(self, valuesDict): self.debugLog(u"validating Prefs called") ipAdr = valuesDict[u'ipaddress'] if ipAdr.count('.') != 3: errorMsgDict = indigo.Dict() errorMsgDict[u'ipaddress'] = u"This needs to be a valid IP address." return (False, valuesDict, errorMsgDict) if self.validateAddress (ipAdr) == False: errorMsgDict = indigo.Dict() errorMsgDict[u'ipaddress'] = u"This needs to be a valid IP address." return (False, valuesDict, errorMsgDict) tcpPort = valuesDict[u'port'] try: iPort = int(tcpPort) if iPort <= 0: errorMsgDict = indigo.Dict() errorMsgDict[u'port'] = u"This needs to be a valid TCP port." return (False, valuesDict, errorMsgDict) except Exception, e: errorMsgDict = indigo.Dict() errorMsgDict[u'port'] = u"This needs to be a valid TCP port." return (False, valuesDict, errorMsgDict) if (valuesDict[u'useAuthentication']): if not(valuesDict[u'username']>""): errorMsgDict = indigo.Dict() errorMsgDict[u'username'] = u"Must be filled." return (False, valuesDict, errorMsgDict) if not(valuesDict[u'password']>""): errorMsgDict = indigo.Dict() errorMsgDict[u'password'] = u"Must be filled." return (False, valuesDict, errorMsgDict) return (True, valuesDict)
class Plugin(indigo.PluginBase): def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.updater = GitHubPluginUpdater(self) self.apiVersion = "2.0" self.localAddress = "" # create empty device list self.deviceList = {} self.updateableList = {} self.unifiPlugin = None self.beaconPlugin = None def __del__(self): indigo.PluginBase.__del__(self) ################################################################### # Plugin ################################################################### def deviceStartComm(self, device): self.debugLog(u"Started device: " + device.name) device.stateListOrDisplayStateIdChanged() self.addDeviceToList (device) def deviceStopComm(self,device): if device.id in self.deviceList: self.debugLog("Stoping device: " + device.name) self.deleteDeviceFromList(device) def deviceCreated(self, device): indigo.server.log (u"Created new device \"%s\" of type \"%s\"" % (device.name, device.deviceTypeId)) pass def deviceDeleted(self, device): indigo.server.log (u"Deleted device \"%s\" of type \"%s\"" % (device.name, device.deviceTypeId)) if device.id in self.deviceList: del self.deviceList[device.id] def addDeviceToList(self,device): if device: if device.id not in self.deviceList: statusNextTime = datetime.datetime.now() - datetime.timedelta(seconds=10) statusInterval = 600 #device.pluginProps["statusInterval"] self.deviceList[device.id] = { 'ref':device, 'statusInterval':statusInterval, 'statusNextTime': statusNextTime, 'analyze': False, 'analyzeNextTime': statusNextTime, 'lastSeen': 0, 'firstSeen': 0, 'onUnifi': False, 'onGeo1': False, 'onGeo2': False, 'onGeo3': False } self.addDeviceToUpdateable(device) def addDeviceToUpdateable(self,device): unifideviceid = int(device.pluginProps["unifidevice"]) geofencedevice1id = int(device.pluginProps["geofencedevice1"]) geofencedevice2id = int(device.pluginProps["geofencedevice2"]) geofencedevice3id = int(device.pluginProps["geofencedevice3"]) self.updateableList[unifideviceid] = {'parentDeviceId': device.id} self.updateableList[geofencedevice1id] = {'parentDeviceId': device.id} self.updateableList[geofencedevice2id] = {'parentDeviceId': device.id} self.updateableList[geofencedevice3id] = {'parentDeviceId': device.id} def deleteDeviceFromList(self, device): if device: if device.id in self.deviceList: del self.deviceList[device.id] self.deleteDeviceFromUpdateable(device) def deleteDeviceFromUpdateable(self,device): unifideviceid = int(device.pluginProps["unifidevice"]) geofencedevice1id = int(device.pluginProps["geofencedevice1"]) geofencedevice2id = int(device.pluginProps["geofencedevice2"]) geofencedevice3id = int(device.pluginProps["geofencedevice3"]) if unifideviceid in self.updateableList: del self.updateableList[unifideviceid] if geofencedevice1id in self.updateableList: del self.updateableList[geofencedevice1id] if geofencedevice2id in self.updateableList: del self.updateableList[geofencedevice2id] if geofencedevice3id in self.updateableList: del self.updateableList[geofencedevice3id] def startup(self): self.loadPluginPrefs() self.debugLog(u"startup called") self.unifiPlugin = indigo.server.getPlugin("com.tenallero.indigoplugin.unifi") self.beaconPlugin = indigo.server.getPlugin("se.furtenbach.indigo.plugin.beacon") if not self.unifiPlugin.isEnabled(): self.errorLog (u"Error: Unifi plugin is not enabled") if not self.beaconPlugin.isEnabled(): self.errorLog (u"Error: Beacon plugin is not enabled") self.updater.checkForUpdate() indigo.devices.subscribeToChanges() def shutdown(self): self.debugLog(u"shutdown called") def getDeviceConfigUiValues(self, pluginProps, typeId, devId): valuesDict = pluginProps errorMsgDict = indigo.Dict() return (valuesDict, errorMsgDict) def validateDeviceConfigUi(self, valuesDict, typeId, devId): self.debugLog(u"validating device Prefs called") return (True, valuesDict) def validatePrefsConfigUi(self, valuesDict): return (True, valuesDict) def closedDeviceConfigUi(self, valuesDict, userCancelled, typeId, devId): if userCancelled is False: indigo.server.log ("Device preferences were updated.") device = indigo.devices[devId] self.deleteDeviceFromList (device) self.addDeviceToList (device) def closedPrefsConfigUi ( self, valuesDict, UserCancelled): # If the user saves the preferences, reload the preferences if UserCancelled is False: indigo.server.log ("Preferences were updated, reloading Preferences...") self.loadPluginPrefs() def loadPluginPrefs(self): # set debug option if 'debugEnabled' in self.pluginPrefs: self.debug = self.pluginPrefs['debugEnabled'] else: self.debug = False def menuGetDevsUnifi(self, filter, valuesDict, typeId, elemId): menuList = [] for dev in indigo.devices.iter(filter="com.tenallero.indigoplugin.unifi.unifiuser"): if dev.enabled: menuList.append((dev.id, dev.name)) return menuList def menuGetDevsPing(self, filter, valuesDict, typeId, elemId): menuList = [] for dev in indigo.devices.iter(filter="com.tenallero.indigoplugin.ping.pingdevice"): if dev.enabled: menuList.append((dev.id, dev.name)) return menuList def menuGetDevsGeofence(self, filter, valuesDict, typeId, elemId): menuList = [] for dev in indigo.devices.iter(filter="se.furtenbach.indigo.plugin.beacon.beacon"): if dev.enabled: menuList.append((dev.id, dev.name)) return menuList def deviceUpdated (self, origDev, newDev): if origDev.id in self.updateableList: if not origDev.states['onOffState'] == newDev.states['onOffState']: parentDeviceId = int(self.updateableList[origDev.id]["parentDeviceId"]) if parentDeviceId in self.deviceList: msg = u'device "' + origDev.name + u'" has been updated. Now is ' if newDev.states['onOffState']: msg += u'on.' else: msg += u'off.' self.debugLog(msg) #indigo.server.log (msg) self.deviceList[parentDeviceId]['statusNextTime'] = datetime.datetime.now() - datetime.timedelta(seconds=10) ################################################################### # Concurrent Thread. ################################################################### def runConcurrentThread(self): self.debugLog(u"Starting Concurrent Thread") try: while self.stopThread == False: indigoDevice = None try: todayNow = datetime.datetime.now() for presenceDevice in self.deviceList: if self.deviceList[presenceDevice]['statusInterval'] > 0: statusNextTime = self.deviceList[presenceDevice]['statusNextTime'] if statusNextTime <= todayNow: statusInterval = self.deviceList[presenceDevice]['statusInterval'] statusNextTime = todayNow + datetime.timedelta(seconds=int(statusInterval)) self.deviceList[presenceDevice]['statusNextTime'] = statusNextTime indigoDevice = self.deviceList[presenceDevice]['ref'] self.deviceList[presenceDevice]['analyze'] = True self.deviceList[presenceDevice]['analyzeNextTime'] = todayNow + datetime.timedelta(seconds=1) self.debugLog(u'ConcurrentThread. Sent "' + indigoDevice.name + '" status request') self.deviceRequestStatus(indigoDevice) self.debugLog(u'ConcurrentThread. Received "' + indigoDevice.name + '" status') if self.deviceList[presenceDevice]['analyze']: analyzeNextTime = self.deviceList[presenceDevice]['analyzeNextTime'] if analyzeNextTime <= todayNow: indigoDevice = self.deviceList[presenceDevice]['ref'] self.debugLog(u'ConcurrentThread. Analyzing "' + indigoDevice.name + '"') self.deviceList[presenceDevice]['analyze'] = False self.deviceAnalyzeStatus(indigoDevice) except Exception,e: self.errorLog (u"Error: " + str(e)) pass self.sleep(0.3) except self.StopThread: pass except Exception, e: self.errorLog (u"Error: " + str(e)) pass
def startup(self): self.logger.debug(u"startup called") self.logger.debug(u'Getting plugin updater') self.updater = GitHubPluginUpdater(self)
class Plugin(indigo.PluginBase): ######################################## # Main Plugin methods ######################################## def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = self.pluginPrefs.get(u"showDebugInfo", False) self.debugLog(u"Debugging enabled") def startup(self): indigo.server.log(u"Starting SMTPd") self.updater = GitHubPluginUpdater(self) self.updateFrequency = float(self.pluginPrefs.get('updateFrequency', '24')) * 60.0 * 60.0 self.next_update_check = time.time() if "SMTPd" in indigo.variables.folders: myFolder = indigo.variables.folders["SMTPd"] else: myFolder = indigo.variables.folder.create("SMTPd") self.pluginPrefs["folderId"] = myFolder.id self.triggers = { } def shutdown(self): indigo.server.log(u"Shutting down SMTPd") def runConcurrentThread(self): port = int(self.pluginPrefs.get('smtpPort', '2525')) user = self.pluginPrefs.get('smtpUser', 'guest') password = self.pluginPrefs.get('smtpPassword', 'password') portal = Portal(SimpleRealm()) checker = InMemoryUsernamePasswordDatabaseDontUse() checker.addUser(user, password) portal.registerChecker(checker) try: self.smtpFactory = MySMTPFactory(portal) self.listeningPort = reactor.listenTCP(port, self.smtpFactory) reactor.run() except self.StopThread: pass # Optionally catch the StopThread exception and do any needed cleanup. def stopConcurrentThread(self): indigo.PluginBase.stopConcurrentThread(self) reactor.callFromThread(self.listeningPort.stopListening) reactor.callFromThread(reactor.stop) #################### def triggerStartProcessing(self, trigger): self.debugLog("Adding Trigger %s (%d) - %s" % (trigger.name, trigger.id, trigger.pluginTypeId)) assert trigger.id not in self.triggers self.triggers[trigger.id] = trigger def triggerStopProcessing(self, trigger): self.debugLog("Removing Trigger %s (%d)" % (trigger.name, trigger.id)) assert trigger.id in self.triggers del self.triggers[trigger.id] def triggerCheck(self): for triggerId, trigger in sorted(self.triggers.iteritems()): self.debugLog("\tChecking Trigger %s (%s), Type: %s" % (trigger.name, trigger.id, trigger.pluginTypeId)) if trigger.pluginTypeId == 'messageReceived': indigo.trigger.execute(trigger) #################### def validatePrefsConfigUi(self, valuesDict): self.debugLog(u"validatePrefsConfigUi called") errorDict = indigo.Dict() updateFrequency = int(valuesDict['updateFrequency']) if (updateFrequency < 0) or (updateFrequency > 24): errorDict['updateFrequency'] = u"Update frequency is invalid - enter a valid number (between 0 and 24)" smtpPort = int(valuesDict['smtpPort']) if smtpPort < 1024: errorDict['smtpPort'] = u"SMTP Port Number invalid" if len(errorDict) > 0: return (False, valuesDict, errorDict) return (True, valuesDict) ######################################## def closedPrefsConfigUi(self, valuesDict, userCancelled): if not userCancelled: self.debug = valuesDict.get("showDebugInfo", False) if self.debug: self.debugLog(u"Debug logging enabled") else: self.debugLog(u"Debug logging disabled") ######################################## # Menu Methods ######################################## def toggleDebugging(self): self.debug = not self.debug self.pluginPrefs["debugEnabled"] = self.debug indigo.server.log("Debug set to: " + str(self.debug)) def checkForUpdates(self): self.updater.checkForUpdate() def updatePlugin(self): self.updater.update() def forceUpdate(self): self.updater.update(currentVersion='0.0.0')
class Plugin(indigo.PluginBase): def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.updater = GitHubPluginUpdater(self) self.apiVersion = "2.0" self.localAddress = "" # create empty device list self.deviceList = {} def __del__(self): indigo.PluginBase.__del__(self) ################################################################### # Plugin ################################################################### def deviceStartComm(self, device): self.debugLog(u"Started device: " + device.name) device.stateListOrDisplayStateIdChanged() self.addDeviceToList (device) def deviceStopComm(self,device): if device.id in self.deviceList: self.debugLog("Stoping device: " + device.name) self.deleteDeviceFromList(device) def deviceCreated(self, device): self.debugLog(u'Created device "' + device.name) pass def addDeviceToList(self,device): if device: if device.id not in self.deviceList: propsAddress = device.pluginProps["address"] propsAddress = propsAddress.strip() propsAddress = propsAddress.replace (' ','') pingNextTime = datetime.datetime.now() - datetime.timedelta(seconds=10) pingInterval = device.pluginProps["pingInterval"] self.deviceList[device.id] = {'ref':device, 'address':propsAddress, 'pingInterval':pingInterval, 'pingNextTime': pingNextTime} def deleteDeviceFromList(self, device): if device: if device.id in self.deviceList: del self.deviceList[device.id] def startup(self): self.loadPluginPrefs() self.debugLog(u"startup called") self.updater.checkForUpdate() def shutdown(self): self.debugLog(u"shutdown called") def getDeviceConfigUiValues(self, pluginProps, typeId, devId): valuesDict = pluginProps errorMsgDict = indigo.Dict() if "pingInterval" not in valuesDict: valuesDict["pingInterval"] = 300 return (valuesDict, errorMsgDict) def validateDeviceConfigUi(self, valuesDict, typeId, devId): self.debugLog(u"validating device Prefs called") self.debugLog(u"validating IP Address") ipAdr = valuesDict[u'address'] if ipAdr.count('.') != 3: errorMsgDict = indigo.Dict() errorMsgDict[u'address'] = u"This needs to be a valid IP address." return (False, valuesDict, errorMsgDict) if self.validateAddress (ipAdr) == False: errorMsgDict = indigo.Dict() errorMsgDict[u'address'] = u"This needs to be a valid IP address." return (False, valuesDict, errorMsgDict) pingInterval = valuesDict[u'pingInterval'] try: iInterval = int (pingInterval) if iInterval < 1: errorMsgDict = indigo.Dict() errorMsgDict[u'pingInterval'] = u"This needs to be > 0." return False except Exception, e: errorMsgDict = indigo.Dict() errorMsgDict[u'pingInterval'] = u"This needs to be a valid number." return False return (True, valuesDict)
class Plugin(indigo.PluginBase): #--------------------------------------------------------------------------- def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = pluginPrefs.get('debug', False) self.updater = GitHubPluginUpdater('jheddings', 'indigo-ghpu', self) #--------------------------------------------------------------------------- def __del__(self): indigo.PluginBase.__del__(self) #--------------------------------------------------------------------------- def selfInstall(self): self.updater.install() #--------------------------------------------------------------------------- def forceUpdate(self): self.updater.update(currentVersion='0.0.0') #--------------------------------------------------------------------------- def updatePlugin(self): self.updater.update() #--------------------------------------------------------------------------- def checkForUpdates(self): self.updater.checkForUpdate() #--------------------------------------------------------------------------- def checkRateLimit(self): limiter = self.updater.getRateLimit() indigo.server.log('RateLimit {limit:%d remaining:%d resetAt:%d}' % limiter) #--------------------------------------------------------------------------- def testUpdateCheck(self): indigo.server.log('-- BEGIN testUpdateCheck --') self.updater.checkForUpdate() self.updater.checkForUpdate('0.0.0') emptyUpdater = GitHubPluginUpdater('jheddings', 'indigo-ghpu') emptyUpdater.checkForUpdate() emptyUpdater.checkForUpdate('0.0.0') emptyUpdater.checkForUpdate(str(self.pluginVersion)) indigo.server.log('-- END testUpdateCheck --') #--------------------------------------------------------------------------- def toggleDebugging(self): self.debug = not self.debug self.pluginPrefs['debug'] = self.debug #--------------------------------------------------------------------------- def closedPrefsConfigUi(self, values, canceled): if (not canceled): self.debug = values.get('debug', False) #--------------------------------------------------------------------------- def runConcurrentThread(self): while True: # this checks for any updates on a regular interval self.updater.checkForUpdate() # we are checking every 300 seconds (5 minutes) here as an example # in practice, this should not be less than 3600 seconds (1 hour) self.sleep(300)
class Plugin(indigo.PluginBase): ######################################## def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = pluginPrefs.get("chkDebug", False) self.updater = GitHubPluginUpdater(self) self.updater.checkForUpdate(str(self.pluginVersion)) self.lastUpdateCheck = datetime.datetime.now() self.pollingInterval = 60 self.APIKey = pluginPrefs.get("txtAPIKey", None) self.currentEventN = "0" if "EVENTS" in self.pluginPrefs: self.EVENTS = json.loads(self.pluginPrefs["EVENTS"]) else: self.EVENTS = {} ######################################## def startup(self): self.debugLog(u"startup called") def checkForUpdates(self): self.updater.checkForUpdate() def updatePlugin(self): self.updater.update() def shutdown(self): self.pluginPrefs["EVENTS"] = json.dumps(self.EVENTS) self.debugLog(u"shutdown called") def deviceStartComm(self, dev): self.debugLog(u"deviceStartComm: %s" % (dev.name, )) ######################################## def validateDeviceConfigUi(self, valuesDict, typeId, devId): return (True, valuesDict) def updateConfig(self, valuesDict): return valuesDict def closedPrefsConfigUi(self, valuesDict, userCancelled): if not userCancelled: self.APIKey = valuesDict["txtAPIKey"] self.debug = valuesDict["chkDebug"] def eventConfigCallback(self, valuesDict, typeId=""): self.currentEventN = str(valuesDict["selectEvent"]) if self.currentEventN == "0": errorDict = valuesDict return valuesDict if not self.currentEventN in self.EVENTS: self.EVENTS[self.currentEventN] = copy.deepcopy(emptyEVENT) valuesDict["eventType"] = str( self.EVENTS[self.currentEventN]["eventType"]) valuesDict["txtOCR"] = str(self.EVENTS[self.currentEventN]["txtOCR"]) valuesDict["txtLabel"] = str( self.EVENTS[self.currentEventN]["txtLabel"]) valuesDict["txtLogo"] = str(self.EVENTS[self.currentEventN]["txtLogo"]) valuesDict["txtNotLabel"] = str( self.EVENTS[self.currentEventN]["txtNotLabel"]) valuesDict["txtLabelScore"] = str( self.EVENTS[self.currentEventN]["txtLabelScore"]) valuesDict["txtFaceScore"] = str( self.EVENTS[self.currentEventN]["txtFaceScore"]) valuesDict["txtLogoScore"] = str( self.EVENTS[self.currentEventN]["txtLogoScore"]) valuesDict["noFace"] = self.EVENTS[self.currentEventN]["noFace"] valuesDict["enableDisable"] = self.EVENTS[ self.currentEventN]["enableDisable"] self.updatePrefs = True return valuesDict def getMenuActionConfigUiValues(self, menuId): #indigo.server.log(u'Called getMenuActionConfigUiValues(self, menuId):') #indigo.server.log(u' (' + unicode(menuId) + u')') valuesDict = indigo.Dict() valuesDict["selectEvent"] = "0" valuesDict["eventType"] = "0" valuesDict["enableDisable"] = "0" errorMsgDict = indigo.Dict() return (valuesDict, errorMsgDict) def sendImageToGoogleForAnnotation(self, image, ocr, label, face, logo): request = {"requests": []} if image[:4].lower() == "http": request["requests"].append( {"image": { "source": { "imageUri": image } }}) else: try: with io.open(image, 'rb') as image_file: content = image_file.read() except: self.logger.error( "Error opening image to send to Google Vision") return request["requests"].append( {"image": { "content": b64encode(content) }}) request["requests"][0]["features"] = [] if ocr: request["requests"][0]["features"].append({ "type": "TEXT_DETECTION", "maxResults": MAX_RESULTS }) if label: request["requests"][0]["features"].append({ "type": "LABEL_DETECTION", "maxResults": MAX_RESULTS }) if face: request["requests"][0]["features"].append({ "type": "FACE_DETECTION", "maxResults": MAX_RESULTS }) if logo: request["requests"][0]["features"].append({ "type": "LOGO_DETECTION", "maxResults": MAX_RESULTS }) # self.logger.debug(json.dumps(request)) try: response = requests.post( url="https://vision.googleapis.com/v1/images:annotate?" + "key=" + self.APIKey, headers={"Content-Type": CONTENT_TYPE}, data=json.dumps(request)) self.logger.debug( 'Response HTTP Status Code: {status_code}'.format( status_code=response.status_code)) self.logger.debug('Response HTTP Response Body: {content}'.format( content=response.content)) except requests.exceptions.RequestException: self.logger.error('HTTP Request failed') return response.json() def sendImageToGoogleVisionAction(self, pluginAction, dev): if pluginAction.props["locationOption"] == "static": image = pluginAction.props["location"] else: image = indigo.variables[int( pluginAction.props["locationVariable"])].value indigo.server.log("sending " + image + " to Google Vision API") processOCR = False processLabel = False processFace = False processLogo = False for i in self.EVENTS: evnt = self.EVENTS[i] if pluginAction.props["event" + str(i)]: if evnt["eventType"] == "OCR": processOCR = True elif evnt["eventType"] == "Face": processFace = True elif evnt["eventType"] == "Label": processLabel = True elif evnt["eventType"] == "Logo": processLogo = True result = self.sendImageToGoogleForAnnotation(image, processOCR, processLabel, processFace, processLogo) self.logger.debug(json.dumps(result)) buildstr = "" facecounter = 0 resultsFound = False if "labelAnnotations" in result["responses"][0]: resultsFound = True for lbl in result["responses"][0]["labelAnnotations"]: buildstr += lbl["description"] + " (score:" + str( lbl["score"]) + "), " indigo.server.log("Label Results: " + buildstr[:-2]) buildstr = "" if "textAnnotations" in result["responses"][0]: resultsFound = True for ocr in result["responses"][0]["textAnnotations"]: if "locale" in ocr: buildstr += ocr["description"].replace( '\n', '') + " (language:" + ocr["locale"] + "), " else: buildstr += ocr["description"].replace('\n', '') + ", " indigo.server.log("OCR Results: " + buildstr[:-2]) buildstr = "" if "faceAnnotations" in result["responses"][0]: resultsFound = True for face in result["responses"][0]["faceAnnotations"]: facecounter += 1 buildstr += "Face " + str( facecounter) + " with confidence of " + str( face["detectionConfidence"]) + ". " buildstr += "joyLikelihood: " + str( face["joyLikelihood"]) + ", " buildstr += "sorrowLikelihood: " + str( face["sorrowLikelihood"]) + ", " buildstr += "angerLikelihood: " + str( face["angerLikelihood"]) + ", " buildstr += "surpriseLikelihood: " + str( face["surpriseLikelihood"]) + ", " buildstr += "underExposedLikelihood: " + str( face["underExposedLikelihood"]) + ", " buildstr += "blurredLikelihood: " + str( face["blurredLikelihood"]) + ", " buildstr += "headwearLikelihood: " + str( face["headwearLikelihood"]) + "; " buildstr = "Found a total of " + str( facecounter) + " face(s). " + buildstr indigo.server.log("Face Results: " + buildstr[:-2]) buildstr = "" if "logoAnnotations" in result["responses"][0]: resultsFound = True for logo in result["responses"][0]["logoAnnotations"]: if "locale" in logo: buildstr += logo["description"] + " (score:" + str( logo["score"] ) + ", language: " + logo["locale"] + "), " else: buildstr += logo["description"] + " (score:" + str( logo["score"]) + "), " indigo.server.log("Logo Results: " + buildstr[:-2]) buildstr = "" if not resultsFound: indigo.server.log("No results found in image.") for trigger in indigo.triggers.iter("self"): eventID = trigger.pluginTypeId[5:].strip() # self.logger.debug("size of self.EVENTS: " + str(len(self.EVENTS)) + " , eventID: " + eventID) if int(eventID) <= len(self.EVENTS): eventType = self.EVENTS[eventID]["eventType"] else: self.logger.error( "Trigger '" + trigger.name + "'' is configured for a disabled Google Vision event, skipping..." ) continue if not self.EVENTS[eventID]["enableDisable"]: self.logger.error( "Trigger '" + trigger.name + "'' is configured for a disabled Google Vision event, skipping..." ) continue if not pluginAction.props["event" + eventID]: self.logger.debug("Trigger '" + trigger.name + "' is not applicable for event " + eventID + ", skipping...") continue self.logger.debug("Evaluating trigger '" + trigger.name + "' (eventID: " + eventID + ", eventType: " + eventType + ")") if eventType == "OCR": ocrSearch = self.EVENTS[eventID]["txtOCR"] if "textAnnotations" in result["responses"][0]: for ocr in result["responses"][0]["textAnnotations"]: if ocrSearch.lower() in ocr["description"].lower(): indigo.trigger.execute(trigger) break elif eventType == "Face": if facecounter == 0 and self.EVENTS[eventID]["noFace"]: indigo.trigger.execute(trigger) elif facecounter == 0: continue else: for face in result["responses"][0]["faceAnnotations"]: if face["detectionConfidence"] >= float( self.EVENTS[eventID]["txtFaceScore"]): indigo.trigger.execute(trigger) break elif eventType == "Label": foundLabel = False foundNotLabel = False self.logger.debug("Trigger '" + trigger.name + "' Looking for labels: " + self.EVENTS[eventID]["txtLabel"] + "; and not for labels:" + self.EVENTS[eventID]["txtNotLabel"]) if "labelAnnotations" in result["responses"][0]: for lbl in result["responses"][0]["labelAnnotations"]: if len(self.EVENTS[eventID]["txtLabel"]) > 0: for lblSearch in self.EVENTS[eventID][ "txtLabel"].replace(" ", "").split(","): # self.logger.debug("Trigger '" + trigger.name + "' Evaluating label " + lblSearch) if lblSearch.lower( ) == lbl["description"].lower( ) and lbl["score"] >= float( self.EVENTS[eventID]["txtLabelScore"]): self.logger.debug( "Trigger '" + trigger.name + "' Found label of interest: " + lblSearch) foundLabel = True if len(self.EVENTS[eventID]["txtNotLabel"]) > 0: for lblNotSearch in self.EVENTS[eventID][ "txtNotLabel"].replace(" ", "").split(","): if lblNotSearch.lower( ) == lbl["description"].lower( ) and lbl["score"] >= float( self.EVENTS[eventID]["txtLabelScore"]): self.logger.debug( "Found anti-label of interest: " + lblNotSearch) foundNotLabel = True break if (len(self.EVENTS[eventID]["txtLabel"]) > 0 and foundLabel ) or (len(self.EVENTS[eventID]["txtNotLabel"]) > 0 and not foundNotLabel): indigo.trigger.execute(trigger) elif eventType == "Logo": foundLogo = False self.logger.debug("Looking for logos: " + self.EVENTS[eventID]["txtLogo"]) if "logoAnnotations" in result["responses"][0]: for logo in result["responses"][0]["logoAnnotations"]: if len(self.EVENTS[eventID]["txtLogo"]) > 0: for logoSearch in self.EVENTS[eventID][ "txtLogo"].replace(" ", "").split(","): if logoSearch.lower( ) == logo["description"].lower( ) and logo["score"] >= float( self.EVENTS[eventID]["txtLogoScore"]): self.logger.debug( "Found logo of interest: " + logoSearch) foundLogo = True if foundLogo: indigo.trigger.execute(trigger) ######################################## def buttonConfirmDevicesCALLBACK(self, valuesDict, typeId=""): errorDict = indigo.Dict() self.currentEventN = str(valuesDict["selectEvent"]) if self.currentEventN == "0" or self.currentEventN == "": return valuesDict if not self.currentEventN in self.EVENTS: self.EVENTS[self.currentEventN] = copy.deepcopy(emptyEVENT) if valuesDict["DeleteEvent"]: valuesDict["DeleteEvent"] = False valuesDict["eventType"] = "OCR" valuesDict["txtOCR"] = "" valuesDict["txtLabel"] = "" valuesDict["txtLogo"] = "" valuesDict["txtNotLabel"] = "" valuesDict["txtLabelScore"] = .90 valuesDict["txtLogoScore"] = .90 valuesDict["txtFaceScore"] = .90 valuesDict["enableDisable"] = False valuesDict["noFace"] = False self.EVENTS[self.currentEventN] = copy.deepcopy(emptyEVENT) self.currentEventN = "0" valuesDict["selectEvent"] = "0" valuesDict["EVENT"] = json.dumps(self.EVENTS) return valuesDict ##### not delete if valuesDict["enableDisable"] != "": self.EVENTS[self.currentEventN]["enableDisable"] = valuesDict[ "enableDisable"] else: self.EVENTS[self.currentEventN]["enableDisable"] = emptyEVENT[ "enableDisable"] valuesDict["enableDisable"] = emptyEVENT["enableDisable"] errorDict["enableDisable"] = emptyEVENT["enableDisable"] self.EVENTS[self.currentEventN]["eventType"] = valuesDict["eventType"] self.EVENTS[self.currentEventN]["txtOCR"] = valuesDict["txtOCR"] self.EVENTS[self.currentEventN]["txtLabel"] = valuesDict["txtLabel"] self.EVENTS[self.currentEventN]["txtLogo"] = valuesDict["txtLogo"] self.EVENTS[ self.currentEventN]["txtNotLabel"] = valuesDict["txtNotLabel"] self.EVENTS[ self.currentEventN]["txtLabelScore"] = valuesDict["txtLabelScore"] self.EVENTS[ self.currentEventN]["txtLogoScore"] = valuesDict["txtLogoScore"] self.EVENTS[ self.currentEventN]["txtFaceScore"] = valuesDict["txtFaceScore"] self.EVENTS[self.currentEventN]["noFace"] = valuesDict["noFace"] self.EVENTS[ self.currentEventN]["enableDisable"] = valuesDict["enableDisable"] valuesDict["EVENTS"] = json.dumps(self.EVENTS) if len(errorDict) > 0: return valuesDict, errorDict return valuesDict
class Plugin(indigo.PluginBase): ######################################## # Main Plugin methods ######################################## def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = self.pluginPrefs.get(u"showDebugInfo", False) self.debugLog(u"Debugging enabled") def __del__(self): indigo.PluginBase.__del__(self) def startup(self): indigo.server.log(u"Starting Harmony Hub") self.updater = GitHubPluginUpdater(self) self.updater.checkForUpdate() self.updateFrequency = self.pluginPrefs.get('updateFrequency', 24) if self.updateFrequency > 0: self.next_update_check = time.time() + float(self.updateFrequency) * 60.0 * 60.0 self.hubDict = dict() self.triggers = { } def shutdown(self): indigo.server.log(u"Shutting down Harmony Hub") def runConcurrentThread(self): try: while True: # All hub messages are done in callbacks. No polling. # Plugin Update check if self.updateFrequency > 0: if time.time() > self.next_update_check: self.updater.checkForUpdate() self.next_update_check = time.time() + float(self.pluginPrefs['updateFrequency']) * 60.0 * 60.0 self.sleep(1.0) except self.stopThread: pass #################### # def getDeviceConfigUiValues(self, pluginProps, typeId, devId): # valuesDict = indigo.Dict(pluginProps) # errorsDict = indigo.Dict() # return (valuesDict, errorsDict) #################### def triggerStartProcessing(self, trigger): self.debugLog("Adding Trigger %s (%d) - %s" % (trigger.name, trigger.id, trigger.pluginTypeId)) assert trigger.id not in self.triggers self.triggers[trigger.id] = trigger def triggerStopProcessing(self, trigger): self.debugLog("Removing Trigger %s (%d)" % (trigger.name, trigger.id)) assert trigger.id in self.triggers del self.triggers[trigger.id] def triggerCheck(self, device, eventType): # Execute the trigger if it's the right type and for the right hub device for triggerId, trigger in sorted(self.triggers.iteritems()): self.debugLog("\tChecking Trigger %s (%s), Type: %s" % (trigger.name, trigger.id, trigger.pluginTypeId)) if trigger.pluginProps["hubID"] != str(device.id): self.debugLog("\t\tSkipping Trigger %s (%s), wrong hub: %s" % (trigger.name, trigger.id, device.id)) else: if trigger.pluginTypeId != eventType: self.debugLog("\t\tSkipping Trigger %s (%s), wrong type: %s" % (trigger.name, trigger.id, eventType)) else: self.debugLog("\t\tExecuting Trigger %s (%s) on Device %s (%s)" % (trigger.name, trigger.id, device.name ,device.id)) indigo.trigger.execute(trigger) #################### def validatePrefsConfigUi(self, valuesDict): self.debugLog(u"validatePrefsConfigUi called") errorMsgDict = indigo.Dict() try: poll = int(valuesDict['updateFrequency']) if (poll < 0) or (poll > 24): raise except: errorMsgDict['updateFrequency'] = u"Update frequency is invalid - enter a valid number (between 0 and 24)" if len(errorMsgDict) > 0: return (False, valuesDict, errorMsgDict) return (True, valuesDict) ######################################## def closedPrefsConfigUi(self, valuesDict, userCancelled): if not userCancelled: self.debug = valuesDict.get("showDebugInfo", False) if self.debug: self.debugLog(u"Debug logging enabled") else: self.debugLog(u"Debug logging disabled") ######################################## # Called for each enabled Device belonging to plugin # Verify connectivity to servers and start polling IMAP/POP servers here # def deviceStartComm(self, device): self.debugLog(u'Called deviceStartComm(self, device): %s (%s)' % (device.name, device.id)) instanceVers = int(device.pluginProps.get('devVersCount', 0)) self.debugLog(device.name + u": Device Current Version = " + str(instanceVers)) if instanceVers >= kCurDevVersCount: self.debugLog(device.name + u": Device Version is up to date") elif instanceVers < kCurDevVersCount: newProps = device.pluginProps else: self.errorLog(u"Unknown device version: " + str(instanceVers) + " for device " + device.name) if device.id not in self.hubDict: if device.deviceTypeId == "harmonyHub": self.debugLog(u"%s: Starting harmonyHub device (%s)" % (device.name, device.id)) hubClient = HubClient(self, device) if (hubClient.ready): self.hubDict[device.id] = hubClient else: self.debugLog(u"%s: Error starting harmonyHub device (%s), disabling..." % (device.name, device.id)) indigo.device.enable(device, value=False) indigo.device.updateStateOnServer(key="serverStatus", value="Disabled") indigo.device.updateStateImageOnServer(indigo.kStateImageSel.SensorOff) else: self.errorLog(u"Unknown server device type: " + device.deviceTypeId) else: self.debugLog(device.name + u": Duplicate Device ID" ) ######################################## # Terminate communication with servers # def deviceStopComm(self, device): self.debugLog(u'Called deviceStopComm(self, device): %s (%s)' % (device.name, device.id)) try: hub = self.hubDict[device.id] hub.client.disconnect(send_close=True) self.hubDict.pop(device.id, None) except: pass ######################################## def validateDeviceConfigUi(self, valuesDict, typeId, devId): errorsDict = indigo.Dict() if len(errorsDict) > 0: return (False, valuesDict, errorsDict) return (True, valuesDict) ######################################## def validateActionConfigUi(self, valuesDict, typeId, devId): errorsDict = indigo.Dict() try: pass except: pass if len(errorsDict) > 0: return (False, valuesDict, errorsDict) return (True, valuesDict) ######################################## # Plugin Actions object callbacks def startActivity(self, pluginAction): hubDevice = indigo.devices[pluginAction.deviceId] hub = self.hubDict[hubDevice.id] activityID = pluginAction.props["activity"] activityLabel = hub.activityList[activityID]["label"] self.debugLog(hubDevice.name + u": Start Activity - " + activityLabel) try: hub.client.start_activity(int(activityID)) except sleekxmpp.exceptions.IqTimeout: self.debugLog(hubDevice.name + u": Time out in hub.client.startActivity") except sleekxmpp.exceptions.IqError: self.debugLog(hubDevice.name + u": IqError in hub.client.startActivity") except Exception as e: self.debugLog(hubDevice.name + u": Error in hub.client.startActivity: " + str(e)) else: hub.current_activity_id = activityID # hubDevice.updateStateOnServer(key="currentActivityNum", value=activityID) # hubDevice.updateStateOnServer(key="currentActivityName", value=activityLabel) # self.triggerCheck(hubDevice, "activityNotification") def powerOff(self, pluginAction): hubDevice = indigo.devices[pluginAction.deviceId] hub = self.hubDict[hubDevice.id] self.debugLog(hubDevice.name + u": Power Off") try: hub.client.start_activity(-1) except sleekxmpp.exceptions.IqTimeout: self.debugLog(hubDevice.name + u": Time out in hub.client.startActivity") except sleekxmpp.exceptions.IqError: self.debugLog(hubDevice.name + u": IqError in hub.client.startActivity") except Exception as e: self.debugLog(hubDevice.name + u": Error in hub.client.startActivity: " + str(e)) else: hub.current_activity_id = "-1" # hubDevice.updateStateOnServer(key="currentActivityNum", value="-1") # hubDevice.updateStateOnServer(key="currentActivityName", value="PowerOff") # self.triggerCheck(hubDevice, "activityNotification") def volumeMute(self, pluginAction): hubDevice = indigo.devices[pluginAction.deviceId] if not hubDevice.enabled: self.debugLog(hubDevice.name + u": Can't send Volume commands when hub is not enabled") return hub = self.hubDict[hubDevice.id] if (int(hub.current_activity_id) <= 0): self.debugLog(hubDevice.name + u": Can't send Volume commands when no Activity is running") return soundDev = hub.activityList[hub.current_activity_id]["soundDev"] self.debugLog(hubDevice.name + u": sending Mute to " + soundDev) try: hub.client.send_command(soundDev, "Mute") except sleekxmpp.exceptions.IqTimeout: self.debugLog(hubDevice.name + u": Time out in hub.client.send_command") except sleekxmpp.exceptions.IqError: self.debugLog(hubDevice.name + u": IqError in hub.client.send_command") except Exception as e: self.debugLog(hubDevice.name + u": Error in hub.client.send_command: " + str(e)) def volumeDown(self, pluginAction): hubDevice = indigo.devices[pluginAction.deviceId] if not hubDevice.enabled: self.debugLog(hubDevice.name + u": Can't send Volume commands when hub is not enabled") return hub = self.hubDict[hubDevice.id] if (int(hub.current_activity_id) <= 0): self.debugLog(hubDevice.name + u": Can't send Volume commands when no Activity is running") return soundDev = hub.activityList[hub.current_activity_id]["soundDev"] self.debugLog(hubDevice.name + u": sending VolumeDown to " + soundDev) try: hub.client.send_command(soundDev, "VolumeDown") except sleekxmpp.exceptions.IqTimeout: self.debugLog(hubDevice.name + u": Time out in hub.client.send_command") except sleekxmpp.exceptions.IqError: self.debugLog(hubDevice.name + u": IqError in hub.client.send_command") except Exception as e: self.debugLog(hubDevice.name + u": Error in hub.client.send_command: " + str(e)) def volumeUp(self, pluginAction): hubDevice = indigo.devices[pluginAction.deviceId] if not hubDevice.enabled: self.debugLog(hubDevice.name + u": Can't send Volume commands when hub is not enabled") return hub = self.hubDict[hubDevice.id] if (int(hub.current_activity_id) <= 0): self.debugLog(hubDevice.name + u": Can't send Volume commands when no Activity is running") return soundDev = hub.activityList[hub.current_activity_id]["soundDev"] self.debugLog(hubDevice.name + u": sending VolumeUp to " + soundDev) try: hub.client.send_command(soundDev, "VolumeUp") except sleekxmpp.exceptions.IqTimeout: self.debugLog(hubDevice.name + u": Time out in hub.client.send_command") except sleekxmpp.exceptions.IqError: self.debugLog(hubDevice.name + u": IqError in hub.client.send_command") except Exception as e: self.debugLog(hubDevice.name + u": Error in hub.client.send_command: " + str(e)) def sendActivityCommand(self, pluginAction): hubDevice = indigo.devices[pluginAction.deviceId] if not hubDevice.enabled: self.debugLog(hubDevice.name + u": Can't send Volume commands when hub is not enabled") return hub = self.hubDict[hubDevice.id] if (int(hub.current_activity_id) <= 0): self.debugLog(hubDevice.name + u": Can't send Activity commands when no Activity is running") return command = pluginAction.props["command"] activity = pluginAction.props["activity"] device = pluginAction.props["device"] self.debugLog(hubDevice.name + u": sendActivityCommand: " + command + " to " + device + " for " + activity) try: hub.client.send_command(device, command) except sleekxmpp.exceptions.IqTimeout: self.debugLog(hubDevice.name + u": Time out in hub.client.send_command") except sleekxmpp.exceptions.IqError: self.debugLog(hubDevice.name + u": IqError in hub.client.send_command") except Exception as e: self.debugLog(hubDevice.name + u": Error in hub.client.send_command: " + str(e)) def sendDeviceCommand(self, pluginAction): hubDevice = indigo.devices[pluginAction.deviceId] if not hubDevice.enabled: self.debugLog(hubDevice.name + u": Can't send Volume commands when hub is not enabled") return hub = self.hubDict[hubDevice.id] command = pluginAction.props["command"] device = pluginAction.props["device"] self.debugLog(hubDevice.name + u": sendDeviceCommand: " + command + " to " + device) try: hub.client.send_command(device, command) except sleekxmpp.exceptions.IqTimeout: self.debugLog(hubDevice.name + u": Time out in hub.client.send_command") except sleekxmpp.exceptions.IqError: self.debugLog(hubDevice.name + u": IqError in hub.client.send_command") except Exception as e: self.debugLog(hubDevice.name + u": Error in hub.client.send_command: " + str(e)) def sendCommand(self, pluginAction): hubDevice = indigo.devices[pluginAction.deviceId] if not hubDevice.enabled: self.debugLog(hubDevice.name + u": Can't send Volume commands when hub is not enabled") return hub = self.hubDict[hubDevice.id] command = pluginAction.props["command"] device = pluginAction.props["device"] self.debugLog(hubDevice.name + u": sendCommand: " + command + " to " + device) try: hub.client.send_command(device, command) except sleekxmpp.exceptions.IqTimeout: self.debugLog(hubDevice.name + u": Time out in hub.client.send_command") except sleekxmpp.exceptions.IqError: self.debugLog(hubDevice.name + u": IqError in hub.client.send_command") except Exception as e: self.debugLog(hubDevice.name + u": Error in hub.client.send_command: " + str(e)) ######################################## # Menu Methods ######################################## def syncHub(self, valuesDict, typeId): self.debugLog(u"Syncing Hub") hubID = int(valuesDict['hubID']) client = self.hubDict[hubID].client client.sync() return (True, valuesDict) def dumpConfig(self, valuesDict, typeId): hubID = int(valuesDict['hubID']) config = self.hubDict[hubID].config self.debugLog(json.dumps(config, sort_keys=True, indent=4, separators=(',', ': '))) return (True, valuesDict) def parseConfig(self, valuesDict, typeId): hubID = int(valuesDict['hubID']) config = self.hubDict[hubID].config for activity in config["activity"]: if activity["id"] == "-1": # skip Power Off continue self.debugLog(u"Activity: %s, id: %s, order: %i, type: %s, isAVActivity: %s, isTuningDefault: %s" % (activity['label'], activity['id'], activity['activityOrder'], activity['type'], str(activity['isAVActivity']), str(activity['isTuningDefault']))) for group in activity["controlGroup"]: self.debugLog(u"\tControl Group %s:" % group['name']) for function in group['function']: self.debugLog(u"\t\tFunction %s, label: %s, action %s:" % (function['name'], function['label'], function['action'])) for device in config["device"]: self.debugLog(u"Device: %s, id: %s, type: %s, Manufacturer: %s, Model: %s" % (device['label'], device['id'], device['type'], device['manufacturer'], device['model'])) for group in device["controlGroup"]: self.debugLog(u"\tControl Group %s:" % group['name']) for function in group['function']: self.debugLog(u"\t\tFunction %s, label: %s, action %s:" % (function['name'], function['label'], function['action'])) return (True, valuesDict) def checkForUpdates(self): self.updater.checkForUpdate() def updatePlugin(self): self.updater.update() def forceUpdate(self): self.updater.update(currentVersion='0.0.0') def toggleDebugging(self): if self.debug: self.debugLog(u"Turning off debug logging") self.pluginPrefs["showDebugInfo"] = False else: self.debugLog(u"Turning on debug logging") self.pluginPrefs["showDebugInfo"] = True self.debug = not self.debug ######################################## # ConfigUI methods ######################################## def activityListGenerator(self, filter, valuesDict, typeId, targetId): retList = [] for id,info in self.hubDict[targetId].activityList.iteritems(): if id != -1: retList.append((id, info["label"])) retList.sort(key=lambda tup: tup[1]) return retList def deviceListGenerator(self, filter, valuesDict, typeId, targetId): retList = [] config = self.hubDict[targetId].config for device in config["device"]: retList.append((device['id'], device["label"])) retList.sort(key=lambda tup: tup[1]) return retList def commandGroupListGenerator(self, filter, valuesDict, typeId, targetId): retList = [] if not valuesDict: return retList config = self.hubDict[targetId].config if typeId == "sendActivityCommand": for activity in config["activity"]: if activity["id"] != valuesDict['activity']: continue self.debugLog(u"commandGroupListGenerator Activity: %s, id: %s" % (activity['label'], activity['id'])) for group in activity["controlGroup"]: retList.append((group['name'], group["name"])) elif typeId == "sendDeviceCommand": for device in config["device"]: if device["id"] != valuesDict['device']: continue self.debugLog(u"commandGroupListGenerator Device: %s, id: %s" % (device['label'], device['id'])) for group in device["controlGroup"]: retList.append((group['name'], group["name"])) else: self.debugLog(u"commandGroupListGenerator Error: Unknown typeId (%s)" % typeId) retList.sort(key=lambda tup: tup[1]) return retList def commandListGenerator(self, filter, valuesDict, typeId, targetId): retList = [] if not valuesDict: return retList config = self.hubDict[targetId].config if typeId == "sendActivityCommand": for activity in config["activity"]: if activity["id"] != valuesDict['activity']: continue self.debugLog(u"commandListGenerator Activity: %s, id: %s" % (activity['label'], activity['id'])) for group in activity["controlGroup"]: if group["name"] != valuesDict['group']: continue for function in group['function']: retList.append((function['name'], function["label"])) elif typeId == "sendDeviceCommand": for device in config["device"]: if device["id"] != valuesDict['device']: continue self.debugLog(u"commandListGenerator Device: %s, id: %s" % (device['label'], device['id'])) for group in device["controlGroup"]: if group["name"] != valuesDict['group']: continue for function in group['function']: retList.append((function['name'], function["label"])) else: self.debugLog(u"commandGroupListGenerator Error: Unknown typeId (%s)" % typeId) retList.sort(key=lambda tup: tup[1]) return retList # doesn't do anything, just needed to force other menus to dynamically refresh def menuChanged(self, valuesDict, typeId, devId): return valuesDict def validateActionConfigUi(self, valuesDict, typeId, actionId): errorDict = indigo.Dict() if typeId == "startActivity": self.debugLog(u"validateActionConfigUi startActivity") elif typeId == "sendCommand": self.debugLog(u"validateActionConfigUi sendCommand") if valuesDict['device'] == "": errorDict["device"] = "Device must be entered" if valuesDict['command'] == "": errorDict["command"] = "Command must be entered" elif typeId == "sendActivityCommand": self.debugLog(u"validateActionConfigUi sendActivityCommand") config = self.hubDict[actionId].config for activity in config["activity"]: if activity["id"] != valuesDict['activity']: continue for group in activity["controlGroup"]: if group["name"] != valuesDict['group']: continue for function in group['function']: if function['name'] != valuesDict['command']: continue action = json.loads(function["action"]) valuesDict['device'] = action["deviceId"] if valuesDict['activity'] == "": errorDict["activity"] = "Activity must be selected" if valuesDict['group'] == "": errorDict["group"] = "Command Group must be selected" if valuesDict['command'] == "": errorDict["command"] = "Command must be selected" elif typeId == "sendDeviceCommand": self.debugLog(u"validateActionConfigUi sendDeviceCommand") if valuesDict['device'] == "": errorDict["device"] = "Device must be selected" if valuesDict['group'] == "": errorDict["group"] = "Command Group must be selected" if valuesDict['command'] == "": errorDict["command"] = "Command must be selected" else: self.debugLog(u"validateActionConfigUi Error: Unknown typeId (%s)" % typeId) if len(errorDict) > 0: return (False, valuesDict, errorDict) else: return (True, valuesDict) def pickHub(self, filter=None, valuesDict=None, typeId=0, targetId=0): retList =[] for id, hub in self.hubDict.items(): hubDevice = indigo.devices[id] retList.append((id,hubDevice.name)) retList.sort(key=lambda tup: tup[1]) return retList
class Plugin(indigo.PluginBase): def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.updater = GitHubPluginUpdater(self) def __del__(self): indigo.PluginBase.__del__(self) def startup(self): indigo.server.log("----- startup called ------") indigo.server.log("Checking for update") ActiveVersion = str(self.pluginVersion) CurrentVersion = str(self.updater.getVersion()) if ActiveVersion == CurrentVersion: indigo.server.log("Running the current version of Security Camera") else: indigo.server.log("The current version of Security Camera is " + str(CurrentVersion) + " and the running version " + str(ActiveVersion) + ".") indigo.server.log("WARNING !: Upgrading to this version will require recreating all existing cameras.") SnapshotDir = indigo.activePlugin.pluginPrefs["SnapshotDirectory"] MainDir = indigo.activePlugin.pluginPrefs["MainDirectory"] #Main dir test MainDirTest = os.path.isdir(MainDir) if MainDirTest is False: indigo.server.log("Home image directory not found. Creating...") os.makedirs(MainDir) indigo.server.log("Created: " + MainDir) #Snapshot Test SnapshotDirTest = os.path.isdir(SnapshotDir) if SnapshotDirTest is False: indigo.server.log("Snapshot image directory not found. Creating...") os.makedirs(SnapshotDir) indigo.server.log("Created: " + SnapshotDir) def shutdown(self): indigo.server.log(u"shutdown called") def validatePrefsConfigUi(self, valuesDict): MainDir = valuesDict["MainDirectory"] ArchiveDir = MainDir + "/Archive" #Main Dir Test MainDirTest = os.path.isdir(MainDir) if MainDirTest is False: indigo.server.log("Home image directory not found. Creating...") os.makedirs(MainDir) indigo.server.log("Created: " + MainDir) #archive dir test ArchiveDirTest = os.path.isdir(ArchiveDir) if ArchiveDirTest is False: indigo.server.log("Archive image directory not found. Creating...") os.makedirs(ArchiveDir) indigo.server.log("Created: " + ArchiveDir) return True def didDeviceCommPropertyChange(self, origDev, newDev): return False def deviceStartComm(self, dev): CameraName = dev.pluginProps["CameraName"] #url = dev.pluginProps["CameraAddress"] <remove> dev.stateListOrDisplayStateIdChanged() localPropsCopy = dev.pluginProps MainDir = indigo.activePlugin.pluginPrefs["MainDirectory"] #IMDir = indigo.activePlugin.pluginPrefs["IMDirectory"] CameraDir = MainDir + "/" + CameraName NotActiveImage = CameraDir + "/NotActive.jpg" CameraDirTest = os.path.isdir(CameraDir) if CameraDirTest is False: indigo.server.log("Camera image directory not found. Creating...") os.makedirs(CameraDir) NotActiveImageTest = os.path.isfile(NotActiveImage) if NotActiveImageTest is False: img = Image.new("RGB", (200, 200), "grey") draw = ImageDraw.Draw(img) font = ImageFont.truetype("Verdana.ttf", 24) center = 100 - ((len(CameraName)*13)/2) draw.text((center, 75),CameraName,(255,255,255),font=font) center = 100 - ((len("Not Active")*12)/2) draw.text((center, 100),"Not Active",(255,255,255),font=font) img.save(NotActiveImage) indigo.server.log("Not Active Image not found. Creating...") if dev.states["CameraState"] != "Off": dev.updateStateOnServer("CameraState", value="On") dev.stateListOrDisplayStateIdChanged() return True ################################################################################ # # Main looping thread # ################################################################################ def runConcurrentThread(self): CarouselCount = 0 CarouselTimer = 0 MainDir = indigo.activePlugin.pluginPrefs["MainDirectory"] DebugMode = indigo.activePlugin.pluginPrefs["Debug"] self.debug = DebugMode try: for device in indigo.devices.iter("self"): CameraName = device.pluginProps["CameraName"] CameraState = device.states["CameraState"] tw = threading.Thread(name=CameraName, target=CameraThread, args=(device.id, MainDir)) tw.start() indigo.server.log("Thread started for " + CameraName + " camera. id: " + str(tw.ident)) #Debug Mode indigo.server.log("Starting main loop") while True: self.sleep(1) ################################################################################ # Setup ################################################################################ MainDir = indigo.activePlugin.pluginPrefs["MainDirectory"] RecordingCount = int(indigo.activePlugin.pluginPrefs["RecordingCount"]) RecordingPause = indigo.activePlugin.pluginPrefs["RecordingPause"] CarouselCameraPause = str(indigo.activePlugin.pluginPrefs["CarouselCameraPause"]) ################################################################################ # Recording setup ################################################################################ try: if RecordingPause == "False": #set record loop frame if RecordingCount > 29: RecordingCount = 0 else: RecordingCount = RecordingCount + 1 RecordingFrame = str(RecordingCount) indigo.activePlugin.pluginPrefs["RecordingFrame"] = RecordingFrame indigo.activePlugin.pluginPrefs["RecordingCount"] = RecordingCount except Exception as errtxt: indigo.server.log("Record Setup " + str(errtxt)) ################################################################################ # Create image carousel ################################################################################ #indigo.server.log("Carousel Paused: " + CarouselCameraPause) try: CarouselCount = int(indigo.activePlugin.pluginPrefs["CarouselCount"]) if CarouselCameraPause == "false": #indigo.server.log("Starting Carousel") CarouselTimer = RunCarousel(MainDir, CarouselCount, CarouselTimer) except Exception as errtxt: indigo.server.log("Carousel: " + str(errtxt)) ################################################################################ # Set Master Image ################################################################################ #indigo.server.log("Starting Master Image") try: MasterID = int(indigo.activePlugin.pluginPrefs["MasterCamera"]) #indigo.server.log(str(MasterID)) if MasterID != "": MasterImage() except Exception as errtxt: indigo.server.log("Unable to run Master Image: " + str(MasterID)) except self.StopThread: indigo.server.log("thread stopped") pass ################################################################################ # # Plugin menus # ################################################################################ def checkForUpdate(self): ActiveVersion = str(self.pluginVersion) CurrentVersion = str(self.updater.getVersion()) if ActiveVersion == CurrentVersion: indigo.server.log("Running the most recent version of Security Camera") else: indigo.server.log("The current version of Security Camera is " + str(CurrentVersion) + " and the running version " + str(ActiveVersion) + ".") def updatePlugin(self): ActiveVersion = str(self.pluginVersion) CurrentVersion = str(self.updater.getVersion()) if ActiveVersion == CurrentVersion: indigo.server.log("Already running the most recent version of Security Camera") else: indigo.server.log("The current version of Security Camera is " + str(CurrentVersion) + " and the running version " + str(ActiveVersion) + ".") self.updater.update() ################################################################################ # # Plugin actions # ################################################################################ def StopCamera(self, pluginAction): ## add code to stop thread CameraDevice = indigo.devices[pluginAction.deviceId] CameraName = CameraDevice.pluginProps["CameraName"] indigo.server.log("Stop Camera action called:" + CameraName) CameraDevice.updateStateOnServer("CameraState", value="Off") def StartCamera(self, pluginAction): ## add code to start thread CameraDevice = indigo.devices[pluginAction.deviceId] CameraName = CameraDevice.pluginProps["CameraName"] indigo.server.log("Start Camera action called:" + CameraName) CameraDevice.updateStateOnServer("CameraState", value="On") CameraDevice.updateStateOnServer("OfflineSeconds", value="On") def ToggleCamera(self, pluginAction): ## add code to start/stop thread CameraDevice = indigo.devices[pluginAction.deviceId] CameraName = CameraDevice.pluginProps["CameraName"] CameraState = CameraDevice.states["CameraState"] localPropsCopy = CameraDevice.pluginProps if CameraState == "On": indigo.server.log("Stop Camera action called:" + CameraName) CameraDevice.updateStateOnServer("CameraState", value="Off") else: indigo.server.log("Start Camera action called:" + CameraName) CameraDevice.updateStateOnServer("CameraState", value="On") CameraDevice.updateStateOnServer("OfflineSeconds", value="0") def MasterCamera(self, pluginAction): indigo.activePlugin.pluginPrefs["MasterCamera"] = pluginAction.deviceId indigo.activePlugin.pluginPrefs["RecordingFlag"] = 0 CameraDevice = indigo.devices[pluginAction.deviceId] CameraName = CameraDevice.pluginProps["CameraName"] try: MasterImage() except Exception as errtxt: LogMessage = CameraName + " Master: " + str(errtxt) indigo.server.log(LogMessage) def MotionOn(self, pluginAction): CameraDevice = indigo.devices[pluginAction.deviceId] CameraName = CameraDevice.pluginProps["CameraName"] Motion = CameraDevice.pluginProps["Motion"] props = CameraDevice.pluginProps indigo.server.log("Start motion action called:" + CameraName) props['Motion'] = True CameraDevice.replacePluginPropsOnServer(props) def MotionOff(self, pluginAction): CameraDevice = indigo.devices[pluginAction.deviceId] CameraName = CameraDevice.pluginProps["CameraName"] Motion = CameraDevice.pluginProps["Motion"] props = CameraDevice.pluginProps indigo.server.log("Stop motion action called:" + CameraName) props['Motion'] = False CameraDevice.replacePluginPropsOnServer(props) def ToggleMotion(self, pluginAction): CameraDevice = indigo.devices[pluginAction.deviceId] CameraName = CameraDevice.pluginProps["CameraName"] Motion = CameraDevice.pluginProps["Motion"] props = CameraDevice.pluginProps try: if Motion == True: indigo.server.log("Stop motion action called:" + CameraName) props['Motion'] = False CameraDevice.replacePluginPropsOnServer(props) else: indigo.server.log("Start motion action called:" + CameraName) props['Motion'] = True CameraDevice.replacePluginPropsOnServer(props) except Exception as errtxt: LogMessage = CameraName + "Toggle Motion: " + str(errtxt) indigo.server.log(LogMessage) def RecordCamera(self, pluginAction): try: CameraDevice = indigo.devices[pluginAction.deviceId] CameraName = CameraDevice.pluginProps["CameraName"] CameraDevice.updateStateOnServer("RecordSeconds", value=0) SavedDir = time.strftime("%m %d %Y %H.%M.%S") MainDir = indigo.activePlugin.pluginPrefs["MainDirectory"] SourceDir = MainDir + "/" + CameraName RecordingDir = MainDir + "/" + CameraName + "/" + SavedDir filecounter = 0 time.sleep(20) os.makedirs(RecordingDir) src_files = getSortedDir(SourceDir, "img", 0, 30) for file_name in src_files: filecounter = filecounter + 1 try: shutil.copy(file_name, RecordingDir) except Exception as errtxt: indigo.server.log(str(errtxt)) sortedList = getSortedDir(SourceDir, "img", 3, 4) CurrentImage = sortedList[0] for num in reversed(range(2, 10)): LeadingNum = "0" + str(num) Current = LeadingNum[-2:] LeadingPrev = "0" + str(num - 1) Previous = LeadingPrev[-2:] PrevValue = CameraDevice.states["Recording" + Previous] PrevNewValue = CameraDevice.states["NewRecording" + Previous] CameraDevice.updateStateOnServer("Recording" + Current, value=PrevValue) CameraDevice.updateStateOnServer("NewRecording" + Current, value=PrevNewValue) ThumbTo = SourceDir +"/thumb" + Current + ".jpg" ThumbFrom = SourceDir +"/thumb" + Previous + ".jpg" try: os.rename(ThumbFrom, ThumbTo) except Exception as errtxt: indigo.server.log("Thumb: " + str(errtxt)) CurrentThumb = SourceDir + "/Thumb01.jpg" shutil.copy (CurrentImage, CurrentThumb) CameraDevice.updateStateOnServer("Recording01", value=SavedDir) CameraDevice.updateStateOnServer("NewRecording01", value="New") except Exception as errtxt: indigo.server.log(CameraName + " Record: " + str(errtxt)) def ToggleCarousel(self, pluginAction): ToggleCarousel = indigo.activePlugin.pluginPrefs["CarouselOn"] if ToggleCarousel == "true": indigo.activePlugin.pluginPrefs["CarouselOn"] = "false" else: indigo.activePlugin.pluginPrefs["CarouselOn"] = "true" def ToggleCarouselCamera(self, pluginAction): ToggleCarousel = indigo.activePlugin.pluginPrefs["CarouselCameraPause"] if ToggleCarousel == "true": indigo.activePlugin.pluginPrefs["CarouselCameraPause"] = "false" else: indigo.activePlugin.pluginPrefs["CarouselCameraPause"] = "true" def NextCarouselCamera(self, pluginAction): MainDir = indigo.activePlugin.pluginPrefs["MainDirectory"] CarouselCount = int(indigo.activePlugin.pluginPrefs["CarouselCount"]) indigo.activePlugin.pluginPrefs["CarouselCount"] = CarouselCount + 1 RunCarousel(MainDir, CarouselCount, 5) def ToggleResolution(self, pluginAction): ToggleResolution = indigo.activePlugin.pluginPrefs["LowRes"] if ToggleResolution == "true": indigo.activePlugin.pluginPrefs["LowRes"] = "false" else: indigo.activePlugin.pluginPrefs["LowRes"] = "true" def PlayRecording(self, pluginAction): try: CameraDevice = indigo.devices[pluginAction.deviceId] CameraName = CameraDevice.pluginProps["CameraName"] RecordingID = pluginAction.props["PlaySelect"] Recording = CameraName + "/" + CameraDevice.states["Recording" + RecordingID] indigo.activePlugin.pluginPrefs["RecordingPause"] = "False" for device in indigo.devices.iter("self"): device.updateStateOnServer("Playing", value="Play") indigo.activePlugin.pluginPrefs["RecordingFrame"] = "0" indigo.activePlugin.pluginPrefs["RecordingCount"] = "0" indigo.activePlugin.pluginPrefs["RecordingFlag"] = 1 indigo.activePlugin.pluginPrefs["PlayRecording"] = Recording indigo.server.log("Play recording action called:" + CameraName) CameraDevice.updateStateOnServer("NewRecording" + RecordingID, value="") except Exception as errtxt: indigo.server.log(CameraName + " Play: " + str(errtxt)) def Snapshot(self, pluginAction): device = indigo.devices[pluginAction.deviceId] CameraName = device.pluginProps["CameraName"] SnapshotDir = indigo.activePlugin.pluginPrefs["SnapshotDirectory"] SnapshotImage = SnapshotDir + "/Snap001.jpg" Quality = int(pluginAction.props["Quality"]) CameraAddress = "http://" + device.pluginProps["CameraAddress"] CameraUser = device.pluginProps["uname"] CameraPwd = device.pluginProps["pwd"] Digest = device.pluginProps["Digest"] Rotation = device.pluginProps["CameraRotation"] Brightness = device.pluginProps["Brightness"] Contrast = device.pluginProps["Contrast"] Sharpness = device.pluginProps["Sharpness"] BorderWidth = int(device.pluginProps["BorderWidth"])*2 BorderColor = device.pluginProps["BorderColor"] ImageWidth = 640 ImageHeight = 480 nowtime = datetime.datetime.now() displaytime = str(nowtime).split(".")[0] labelText = CameraName + " : " + displaytime #indigo.server.log("Capture Image") #indigo.server.log(CameraAddress) img=getURLImage(CameraAddress,CameraUser,CameraPwd, Digest) #indigo.server.log("Set Size") img.thumbnail((ImageWidth, ImageHeight)) #indigo.server.log(Brightness +":"+ Contrast +":"+ Sharpness) img=editImage(img, int(Rotation), float(Brightness), float(Contrast), float(Sharpness), False) #indigo.server.log("Add black bars") img=addBorder(img, ImageWidth, ImageHeight, "black") #indigo.server.log("Add Text") img=addLabel(img, labelText) #indigo.server.log("Add Border") img=addBorder(img, ImageWidth + BorderWidth, ImageHeight + BorderWidth, BorderColor) #save image history for num in reversed(range(1, 5)): fromfile = "Snap00" + str(num) fromfile = SnapshotDir + "/" + fromfile + ".jpg" tofile = "Snap00" + str(num+1) tofile = SnapshotDir + "/" + tofile + ".jpg" if os.path.isfile(fromfile): os.rename(fromfile, tofile) try: img.save(SnapshotImage,optimize=True,quality=Quality) except Exception as errtxt: indigo.server.log(str(errtxt)) def GIF(self, pluginAction): CameraDevice = indigo.devices[pluginAction.deviceId] CameraName = CameraDevice.pluginProps["CameraName"] SnapshotDir = indigo.activePlugin.pluginPrefs["SnapshotDirectory"] MainDir = indigo.activePlugin.pluginPrefs["MainDirectory"] SourceDir = MainDir + "/" + CameraName +"/" DestName = SnapshotDir + "/" + CameraName + ".gif" sortedList = getSortedDir(SourceDir, "img", 0, 30) images = [Image.open(fn) for fn in sortedList] writeGif(DestName, images, duration=1) indigo.server.log("done giffing") def PauseRecording(self, pluginAction): RecordingPaused = indigo.activePlugin.pluginPrefs["RecordingPause"] PlayState = "" if RecordingPaused == "False": indigo.activePlugin.pluginPrefs["RecordingPause"] = "True" PlayState = "Pause" else: indigo.activePlugin.pluginPrefs["RecordingPause"] = "False" PlayState = "Play" for device in indigo.devices.iter("self"): device.updateStateOnServer("Playing", value=PlayState) def FrameBackward(self, pluginAction): RecordingCount = int(indigo.activePlugin.pluginPrefs["RecordingCount"]) #set record loop frame if RecordingCount < 0: RecordingCount = 20 else: RecordingCount = RecordingCount - 1 RecordingFrame = str(RecordingCount) indigo.activePlugin.pluginPrefs["RecordingFrame"] = RecordingFrame indigo.activePlugin.pluginPrefs["RecordingCount"] = RecordingCount def FrameForward(self, pluginAction): RecordingCount = int(indigo.activePlugin.pluginPrefs["RecordingCount"]) #set record loop frame if RecordingCount > 20: RecordingCount = 0 else: RecordingCount = RecordingCount + 1 RecordingFrame = str(RecordingCount) indigo.activePlugin.pluginPrefs["RecordingFrame"] = RecordingFrame indigo.activePlugin.pluginPrefs["RecordingCount"] = RecordingCount def Mosaic(self, pluginAction): CameraDevice = indigo.devices[pluginAction.deviceId] CameraName = CameraDevice.pluginProps["CameraName"] try: GetMosaic(CameraDevice) except Exception as errtxt: indigo.server.log(CameraName + " Mosaic: " + str(errtxt)) def CameraCommand(self, pluginAction): ReturnVariable = pluginAction.props["ReturnVariable"] CameraAddress = "http://" + device.pluginProps["CameraAddress"] CameraUser = device.pluginProps["uname"] CameraPwd = device.pluginProps["pwd"] ReturnVariable = ReturnVariable.replace(" ", "_") try: ReturnVar = indigo.variables[ReturnVariable] except Exception as errtxt: indigo.server.log(str(errtxt)) indigo.variable.create(ReturnVariable) indigo.server.log(ReturnVariable + " created") #indigo.server.log("start url Command") if digest: try: response = requests.get(CameraAddress, auth=HTTPDigestAuth(CameraUser, CameraPwd), timeout=(1, 3)) indigo.variable.updateValue(ReturnVariable, value=str(returnvalue)) except: indigo.variable.updateValue(ReturnVariable, value="Command Failed") else: try: response = requests.get(CameraAddress, auth=(CameraUser, CameraPwd), timeout=(1, 3)) indigo.variable.updateValue(ReturnVariable, value=str(returnvalue)) except: indigo.variable.updateValue(ReturnVariable, value="Command Failed") def DeleteRecording(self, pluginAction): CameraDevice = indigo.devices[pluginAction.deviceId] CameraName = CameraDevice.pluginProps["CameraName"] Months = pluginAction.props["DeleteMonths"] Days = int(Months) * 30 MainDir = indigo.activePlugin.pluginPrefs["MainDirectory"] ArchiveDir = MainDir + "/" + "Archive" + "/" + CameraName OldDirs = [] today = date.today() StartPath = MainDir + "/" + CameraName for root, dirs, files in os.walk(StartPath): for FileName in dirs: filedate = date.fromtimestamp(os.path.getmtime(os.path.join(root, FileName))) if (today - filedate).days >= Days: CurrentDir = StartPath + "/" + FileName shutil.copytree(CurrentDir,ArchiveDir+ "/" + FileName) shutil.rmtree(CurrentDir) indigo.server.log("Archived videos older than " + Months + " months:" + CameraName)
def startup(self): if self.debugextra: self.debugLog(u"Starting Plugin. startup() method called.") self.updater = GitHubPluginUpdater(self)
class Plugin(indigo.PluginBase): ######################################## def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs) #indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.errorState = False self.pluginName = u'Six50Joe' # Set plugin preferences self.setUpdatePluginPrefs() ######################################## def __del__(self): indigo.PluginBase.__del__(self) ######################################## def startup(self): self.logger.debug(u"startup called") self.logger.debug(u'Getting plugin updater') self.updater = GitHubPluginUpdater(self) ######################################## def updatePlugin(self): self.logger.info(u'Initiating plugin update') updateResult = self.updater.update() return updateResult ######################################## def checkPluginUpdates(self, notify = False, performUpdate = False): self.logger.debug(u'Checking for plugin updates') updateAvailable = self.updater.checkForUpdate() if updateAvailable: if notify and len(self.checkForUpdatesEmail) > 0: self.logger.debug(u'Notifying that new plugin version is available via e-mail') indigo.server.sendEmailTo(self.checkForUpdatesEmail, subject=u'Indigo %s plugin update available' % (self.pluginName), body=u'A new update of %s plugin is available and can be updated from the plugin menu within Indigo' % (self.pluginName)) if performUpdate: self.updatePlugin() return updateAvailable # Catch changes to config prefs def closedPrefsConfigUi(self, valuesDict, userCancelled): self.extDebug(u'CALL closedPrefsConfigUi, valuesDict: %s' % unicode(valuesDict)) self.extDebug(u'CALL closedPrefsConfigUi, userCancelled: %s' % unicode(userCancelled)) self.setUpdatePluginPrefs(True) # FIX DO VALIDATION self.pluginConfigErrorState = False ######################################## def shutdown(self): self.logger.debug(u"shutdown called") # moved to stopThread in runConcurrentThread, don't believe the below saved prefs at all times # if self.keepStats: # self.logger.debug(u'Saving z-wave node statistics') # self.pluginPrefs[u'nodeStats'] = self.store(self.nodeStats) ######################################## def wakeUp(self): indigo.PluginBase.wakeUp(self) self.logger.debug("wakeUp method called") ######################################## def prepareToSleep(self): indigo.PluginBase.prepareToSleep(self) self.logger.debug("prepareToSleep method called") ######################################## def extDebug(self, msg): if self.extensiveDebug: self.debugLog(msg) ######################################## # 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: counter = 0 while True: self.logger.debug(u'runConcurrentThread') counter += 1 self.sleep(3613) except self.StopThread: self.logger.debug(u'runConcurrentThread self.StopThread') if self.keepStats: self.logger.debug(u'Saving z-wave node statistics before quitting plugin') self.pluginPrefs[u'nodeStats'] = self.store(self.nodeStats) # if self.errorState: # # FIX, find some way to shutdown if there are errors # self.logger.error(u'Plugin in error state, stopping concurrent thread') # pass ##### # Set or update plugin preferences # running : True if plugin is already running and prefs are to be changed # def setUpdatePluginPrefs(self, running = False): self.logger.debug(u'CALL setUpdatePluginPrefs, running: %s' % unicode(running)) # Set log levels if running: setText = u'Changing' else: setText = u'Setting' self.indigo_log_handler.setLevel(self.pluginPrefs.get(u'logLevel', u'INFO')) self.plugin_file_handler.setLevel(u'DEBUG') self.extensiveDebug = self.pluginPrefs.get(u'extensiveDebug', False) self.logger.info(u'%s log level to %s' % (setText, self.pluginPrefs.get(u'logLevel', u'INFO'))) self.logger.debug(u'Extensive debug logging set to %s' % unicode(self.extensiveDebug)) self.logger.debug(u'%s file handler log level to DEBUG' % (setText)) # DEBUG : All debug info # INFO : Informational messages relevant to the user # WARNING : More critical information to the user, warnings # ERROR : Errors not critical for plugin execution # CRITICAL : Errors critical for plugin execution, plugin will stop self.checkForUpdatesInterval = self.pluginPrefs.get(u'checkForUpdatesInterval', 24) if self.checkForUpdatesInterval == u'': self.checkForUpdates = False else: self.checkForUpdates = True try: self.checkForUpdatesInterval = int(self.checkForUpdatesInterval) except: self.logger.error(u'Invalid plugin prefs value for update check frequency, defaulting to 24 hours') self.checkForUpdatesInterval = 24 self.checkForUpdatesEmail = self.pluginPrefs.get(u'checkForUpdatesEmail', '') #self.autoUpdate = self.pluginPrefs.get(u'autoUpdate', False) # FIX, Indigo will ask for confirmation before plugin is updates, so best to leave as manual menu option self.autoUpdate = False self.keepStats = self.pluginPrefs.get(u'keepStats', False) if self.keepStats: self.nodeStats = self.load(self.pluginPrefs.get(u'nodeStats', self.store(dict()))) # see def emptyNodeStatList() for description # Update older versions of nodeStats for l in self.nodeStats: # after adding outNR if len(l) == 9: l = l[0:1] + [0] + l[2:] # Check plugin dependencies self.checkDependantPlugins() ##### # Check for dependant plugins, if they are enabled and correct version is installed etc. # def checkDependantPlugins(self): self.logger.debug(u'Checking status of other plugins this plugin depends on') # [<plugin pref for enable of plugin>, <plugin id>, <Friendly name>, <min plugin version>] pluginList = [] for plug in pluginList: usePlugin = self.pluginPrefs.get(plug[0], False) self.logger.debug(u'Checking plugin "%s"' % plug[2]) try: if not usePlugin: raise try: indigoPlug = indigo.server.getPlugin(plug[1]) if not indigoPlug.isRunning(): raise ImportError(u'Plugin "%s" is not running, please install/enable, and re-enable in %s plugin preferences' % (plug[2], self.pluginName)) if len(indigoPlug.pluginVersion) == 0 or indigoPlug.pluginVersion < plug[3]: raise ImportError(u'Plugin "%s" version %s is less than %s requires (%s), please update the plugin.\nUse of this plugin in %s has been disabled' % (plug[2], indigoPlug.pluginVersion, self.pluginName, plug[3], self.pluginName)) # Plugin specific checks: if plug[1] == u'com.flyingdiver.indigoplugin.betteremail': smtpDevId = self.pluginPrefs.get(u'plugin-betteremail-smtpdevice', u'') if len(smtpDevId) == 0: raise ImportError(u'You need to specify a valid "%s" SMTP device in %s plugin preferences' % plug[2], self.pluginName) else: try: smtpDev = indigo.devices[int(smtpDevId)] if not smtpDev.enabled: raise except: raise ImportError(u'The specified "%s" SMTP device could not be loaded, please check\n%s plugin preferences and that the SMTP device is enabled' % (self.pluginName)) except ImportError as e: self.logger.error(e) raise except: self.logger.error(u'Could not load plugin "%s". Please install and re-enable in %s plugin preferences' % (plug[2], self.pluginName)) raise except: # Common code for disabling use of the plugin if usePlugin: # configured to use plugin, so some error happened self.logger.debug(u'Disabling use of plugin "%s" in plugin prefs' % plug[2]) if len(indigoPlug.pluginSupportURL) > 0: self.logger.info(u'"%s" support/install link: %s' % (plug[2], indigoPlug.pluginSupportURL)) else: self.logger.debug(u'Not configured to use plugin "%s"' % plug[2]) self.pluginPrefs[plug[0]] = False if plug[1] in self.dependantPlugins: del self.dependantPlugins[plug[1]] else: # Plugin is successfully initialized, add to dict of enabled plugins self.logger.debug(u'Plugin "%s" successfully checked' % plug[2]) self.dependantPlugins[plug[1]] = indigoPlug def ping(self, ipOrUrl): rc = subprocess.call("/sbin/ping -t 1 -c 1 %s" \ % (ipOrUrl), shell=True, stdout=subprocess.PIPE) if rc == 0: return True else: return False ######################################## def getPresenceDevices(self, filter="", valuesDict=None, typeId="", targetId=0): list = [] for v in indigo.variables: if v.name.startswith("S50_PRESDT") \ and not v.name.endswith("_reached"): list.append({'name' : v.name, 'value' : v.value}) return list ######################################## def getPresenceDeviceList(self, filter="", valuesDict=None, typeId="", targetId=0): devList = self.getPresenceDevices() list = [] for dev in devList: list.append([dev['name'], dev['value']]) return list ######################################## # UI List generators and callbackmethods ######################################## ######################################## # Actions ######################################## def doPingAddressAtPort(self, ipOrUrl, port, numRetries, retrySecs, var=None): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(retrySecs) for r in range(1, numRetries + 1): try: s.connect((ipOrUrl, port)) s.shutdown(2) self.logger.debug("%s is reachable at port %d" % (ipOrUrl, port)) if var: indigo.variable.updateValue(var, value=unicode("true")) return True except Exception as e: self.logger.debug(str(e)) self.logger.debug("%s is NOT reachable at port %d, retry %d" % (ipOrUrl, port, r)) time.sleep(retrySecs) if var: indigo.variable.updateValue(var, value=unicode("false")) return False def pingAddress(self, action, port=None): props = action.props varName = props[u'resultVarName'] var = None if len(varName) > 0: var = indigo.variables[varName] numRetries = int(props[u'numRetries']) retrySecs = int(props[u'retrySecs']) ipOrUrl = props[u'ipOrUrl'] if not port: port = int(props[u'port']) else: port = int(port) self.doPingAddressAtPort(ipOrUrl, port, numRetries, retrySecs, var) def pingOtherHouse(self, action): self.pingAddress(action, 8176) def checkDevicePresence(self, action): devList = self.getPresenceDevices() deviceReached = False for d in devList: reachable = self.ping(d['value']) if not deviceReached and reachable: deviceReached = True self.logger.debug("dev: %s: %s" % (d['name'], reachable)) varName = d['name'] + "_reached" var = None if varName not in indigo.variables: var = indigo.variable.create(varName, unicode(reachable)) else: var = indigo.variable.updateValue(varName, unicode(reachable)) presenceVarName = 'DevicesPresent' if presenceVarName not in indigo.variables: var = indigo.variable.create(presenceVarName, unicode(deviceReached)) else: var = indigo.variable.updateValue(presenceVarName, unicode(deviceReached)) def iterate(self, iterable): iterator = iter(iterable) item = iterator.next() for next_item in iterator: yield item, next_item item = next_item yield item, None def readPropaneThresholds(self): global PropaneThresholds PropaneThresholds = {} path = CONFIG_FILE_DIR + "/" + RELAY_THRESHOLDS_FILENAME if os.path.exists(path): inputFile = open(path, 'r') for line in inputFile: (pct, thresh) = line.split(',') PropaneThresholds[pct] = thresh.strip() #for key in sorted(PropaneThresholds.iterkeys()): # self.logger.debug("%s: %s" % (key, PropaneThresholds[key])) lastVal = 0 for item, next_item in self.iterate(sorted(PropaneThresholds.iterkeys(), key=int)): if next_item is not None and \ PropaneThresholds[item] > PropaneThresholds[next_item]: self.logger.warn("WARNING: propane thresholds out of order: %s(%d) < %s(%d)" \ % (item, int(PropaneThresholds[item]), next_item, int(PropaneThresholds[next_item]))) lastVal = PropaneThresholds[item] self.logger.debug("%s - next %s" % (str(item), str(next_item))) def writePropaneThresholds(self): path = CONFIG_FILE_DIR + "/" + RELAY_THRESHOLDS_FILENAME if os.path.exists(path): backup = path + "_" + datetime.datetime.today().strftime('%Y-%m-%d_%H:%M:%S') os.rename(path, backup) outFile = open(path, 'w') for key in sorted(PropaneThresholds.iterkeys(), key=int): outFile.write("%s,%s\n" % (key, PropaneThresholds[key])) def getPropaneSensorReading(self): relay = indigo.devices["Propane - Relay Output"] analog = indigo.devices["Propane - Analog Input"] indigo.device.turnOn(relay, duration=100) indigo.activePlugin.sleep(1) indigo.device.statusRequest(analog) self.logger.info("sensor value is: " + str(analog.sensorValue)) return analog.sensorValue def getPropaneLevel(self, action): props = action.props testValStr = props[u'testSensorVal'] testVal = None if testValStr.isdigit(): testVal = int(float(testValStr)) self.readPropaneThresholds() sensor = None if testVal is None: sensor = self.getPropaneSensorReading() else: sensor = testVal propaneVar = indigo.variables["PropaneLevel"] prevPct = int(float(propaneVar.value)) retry = 0 pct=0 nextPct=0 calcPct=0 level = "" while retry < 3: firstThreshold=True for pct, nextPct in self.iterate(sorted(PropaneThresholds.iterkeys(), key=int)): thresh = int(float(PropaneThresholds[pct])) nextThresh = -1 if nextPct: nextThresh = int(float(PropaneThresholds[nextPct])) self.logger.debug("%s(%d) - next %s(%d)" % (str(pct), thresh, str(nextPct), nextThresh)) # for t, threshold in enumerate(thresholds): calcPct = None if thresh <= sensor: if nextPct is None: # This reading is above the high level = "> %s%%" % (pct) calcPct = pct break if sensor <= nextThresh: # The reading is between two thresholds rangeBottom = thresh rangeTop = nextThresh range = (rangeTop - rangeBottom) span = int(nextPct) - int(pct) increment = 1 if range > span: increment = float(range) / float(span) calcPct = int(pct) + ((sensor - rangeBottom) / increment) self.logger.debug("range: %d span: %d increment: %f calcPct: %d" \ % (range, span, increment, calcPct)) level = "%d%%" % (calcPct) break else: if firstThreshold: # Reading is below the lowest level = "< %s%%" % (pct) calcPct = pct break firstThreshold = False delta = prevPct - int(pct) if delta <= 10: break # Might have been a bad reading; retry time.sleep(2) retry += 1 indigo.server.log("possible bad value, retrying: " + str(pct)) indigo.variable.updateValue(propaneVar, str(calcPct)) propaneStrVar = indigo.variables["PropaneLevelStr"] indigo.variable.updateValue(propaneStrVar, level) sensorVar = indigo.variables["PropaneGaugeReading"] indigo.variable.updateValue(sensorVar, str(sensor)) self.logger.info("Propane level is %s" % level) def calibratePropaneLevel(self, action): props = action.props gaugePctInput = props[u'gaugePct'] self.readPropaneThresholds() testValStr = props[u'testSensorVal'] testVal = None if testValStr.isdigit(): testVal = int(testValStr) gaugePct = None if gaugePctInput.isdigit(): gaugePct = int(props[u'gaugePct']) else: var = indigo.variables['PropaneCalibrationPct'] gaugePct = int(var.value) self.logger.info("Propane calibratrion pct input is: %d" % gaugePct) sensor = None if testVal is None: # Get multiple readings, in case 1st one is bad for x in range(1, 3): sensor = self.getPropaneSensorReading() time.sleep(3) else: sensor = testVal # Insert the new reading into the list, replacing the # cuyrrent pct reading if it already exists PropaneThresholds[str(gaugePct)] = sensor # Now, iterate through the list and remove entries that # cross over the new threshold out of order toRemove = [] firstThreshold = True for pct, nextPct in self.iterate(sorted(PropaneThresholds.iterkeys(), key=int)): thresh = int(float(PropaneThresholds[pct])) if int(pct) < gaugePct and thresh > sensor: toRemove.append(pct) self.logger.info("Existing threshold %d for %d%% is higher than new threshold %d, at %d%%, removing existing" \ % (thresh, int(pct), sensor, gaugePct)) if int(pct) > gaugePct and thresh < sensor: toRemove.append(pct) self.logger.info("Existing threshold %d for %d%% is lower than new threshold %d, at %d%%, removing existing" \ % (thresh, int(pct), sensor, gaugePct)) for pct in toRemove: del PropaneThresholds[pct] self.logger.info("After calibration:") for item, next_item in self.iterate(sorted(PropaneThresholds.iterkeys(), key=int)): prefix = "" if int(item) == gaugePct: prefix = "NEW--> " self.logger.info("PRP: %s %s(%d)" % (prefix, item, int(float(PropaneThresholds[item])))) self.writePropaneThresholds() def archivePriorMonthLogs(self, action=None): var = indigo.variables['LogArchiveDir'] if not var: self.logger.error("LogArchiveDir variable not set") return archiveDir = var.value var = indigo.variables['LogDir'] if not var: self.logger.error("LogDir variable not set") return logDir = var.value dtNow = datetime.datetime.now() dtLastMonth = dtNow + dateutil.relativedelta.relativedelta(months=-1) # dtMatch = "%4d-%02d.*Events.txt" % (dtLastMonth.year, dtLastMonth.day) # files = [f for f in os.listdir(logDir) if re.match(dtMatch, f)] # for f in files: # self.logger.debug(f) yearDir = "%s/%4d" % (archiveDir, dtLastMonth.year) self.logger.debug("YearDir=%s" % yearDir) if (not os.path.isdir(yearDir)): os.mkdir(yearDir) tarPath = "%s/%s.tar" % (yearDir, dtLastMonth.strftime("%Y-%b")) tarPathGz = "%s.gz" % tarPath if (os.path.exists(tarPathGz)): self.logger.info("Last month archive already created; no action taken (%s)" % tarPathGz) return else: self.logger.info("Creating last month archive: %s" % tarPath) tarPath = tarPath.replace(" ","\ ") logDir = logDir.replace(" ","\ ") tarcmd = "cd %s;tar -cvf %s %4d-%02d*" \ % (logDir, tarPath, dtLastMonth.year, dtLastMonth.month) self.logger.debug(tarcmd) rc = subprocess.call(tarcmd, shell=True, stdout=subprocess.PIPE) gzcmd = "gzip %s" % tarPath rc = subprocess.call(gzcmd, shell=True, stdout=subprocess.PIPE) def redrawCharts(self, param1=None): matplotlibPlugin = indigo.server.getPlugin("com.fogbert.indigoplugin.matplotlib") try: result = matplotlibPlugin.executeAction('refreshTheChartsAction') if result is not None: indigo.server.log(result['message']) except Exception as err: indigo.server.log(u"Exception occurred: {0}".format(err)) def mailAttachment(self, title, volume, path): path = path.replace("/", ":") if not path.startswith(":"): path = ":" + path if not path.endswith(":"): path = path + ":" path = volume + path applescript=''' tell application "Finder" set folderPath to folder "%s" set theFile to file "indigo_logs.tar" in folderPath as alias set fileName to name of theFile end tell set theSubject to fileName set theBody to "Indigo logs collection: " & fileName set theAddress to "*****@*****.**" set theAttachment to theFile set theSender to "*****@*****.**" tell application "Mail" set theNewMessage to make new outgoing message with properties {subject:theSubject, content:theBody, visible:false} tell theNewMessage set visibile to true set sender to theSender make new to recipient at end of to recipients with properties {address:theAddress} try make new attachment with properties {file name:theAttachment} at after the last word of the last paragraph set message_attachment to 0 on error errmess -- oops log errmess -- log the error set message_attachment to 1 end try delay 15 send end tell end tell ''' % path args = [item for x in [("-e",l.strip()) for l in applescript.split('\n') if l.strip() != ''] for item in x] self.logger.debug(args) proc = subprocess.Popen(["osascript"] + args ,stdout=subprocess.PIPE ) out = proc.stdout.read().strip() self.logger.debug(str(out)) return out def mailRecentLogs(self, action=None): var = indigo.variables['LogDir'] if not var: self.logger.error("LogDir variable not set") return logDir = var.value var = indigo.variables['LogArchiveDir'] if not var: self.logger.error("LogArchiveDir variable not set") return archiveDir = var.value dtNow = datetime.datetime.now() priorDate = dtNow + dateutil.relativedelta.relativedelta(days=-14) self.logger.debug("Prior date=%s" % (priorDate)) files = [f for f in os.listdir(logDir) if re.match(".*Events.txt", f)] arcName = "indigo_logs.tar" #archiveDir = archiveDir.replace(" ","\ ") # cmd = "tar -cvf %s/%s" % (archiveDir, arcName) # self.logger.debug(cmd) # rc = subprocess.call(cmd, # shell=True, # stdout=subprocess.PIPE) # if rc != 0: # self.logger.error("Couldn't create log archive file") if (os.path.exists("%s/%s" % (archiveDir, arcName))): os.remove("%s/%s" % (archiveDir, arcName)) for f in files: m = re.match("(\d\d\d\d)-(\d\d)-(\d\d).*", f) if m: year = int(m.group(1)) month = int(m.group(2)) day = int(m.group(3)) fdt = datetime.datetime(year=year, month=month, day=day) self.logger.debug("Year=%d month=%d day=%d" % (year, month, day)) if fdt > priorDate: cmd = "cd \"%s\";tar -rvf \"%s/%s\" \"%s\"" % (logDir, archiveDir, arcName, f) # self.logger.debug(cmd) rc = subprocess.call(cmd, shell=True, stdout=subprocess.PIPE) if rc != 0: self.logger.error("Couldn't update log archive file") self.mailAttachment("Recent Indigo Logs", "Macintosh HD", archiveDir) def updateElecUsageVar(self, var, value, thresholds, desc): "Setl the status string according to the usage threshold" if (value < thresholds[0]): indigo.variable.updateValue(var, desc[0]) elif (value < thresholds[1]): indigo.variable.updateValue(var, desc[1]) elif (value < thresholds[2]): indigo.variable.updateValue(var, desc[2]) else: indigo.variable.updateValue(var, desc[3]) return def checkElectric(self, action): "Get current electric usage values and update status" props = action.props clamp1Dev = props[u'clamp1Dev'] clamp2Dev = props[u'clamp2Dev'] thresh1 = int(props[u'thresh1']) thresh2 = int(props[u'thresh2']) thresh3 = int(props[u'thresh3']) thresh4 = int(props[u'thresh4']) thresholds = [thresh1, thresh2, thresh3, thresh4] descriptions = ["minimal", "normal", "High", "VERY HIGH"] clamp1 = indigo.devices[clamp1Dev] clamp2 = indigo.devices[clamp2Dev] c1Val = clamp1.displayStateValRaw c2Val = clamp2.displayStateValRaw c1Var = indigo.variables["Clamp1"] c2Var = indigo.variables["Clamp2"] indigo.variable.updateValue(c1Var, str(c1Val)) indigo.variable.updateValue(c2Var, str(c2Val)) e1Var = indigo.variables["ElecUsage1Status"] e2Var = indigo.variables["ElecUsage2Status"] self.logger.debug("Setting clamp1 var to %s, clamp2 to %s" % (c1Val, c2Val)) self.updateElecUsageVar(e1Var, c1Val, thresholds, descriptions) self.updateElecUsageVar(e2Var, c2Val, thresholds, descriptions) # indigo.server.log(str(e1Var)) def hasHeartbeat(self, deviceName, withinSecs=180, withinMinutes=0, withinHours=0, withinDays=0): device = indigo.devices[deviceName] now = datetime.datetime.now() lastChanged = device.lastChanged if False: self.logger.debug("Device heartbeat at: %s, seconds since=%d" % \ (lastChanged.strftime("%m/%d/%Y %H:%M:%S"), \ (lastChanged - now).total_seconds())) isResponding = True delta = now - lastChanged threshold = withinSecs + \ (withinMinutes * 60) + \ (withinHours * 60 * 60) + \ (withinDays * 24 * 60 * 60) self.logger.debug("Threshold seconds=%d)" % threshold) if delta.total_seconds() > threshold: isResponding = False statusVarName = deviceName + "_responding" # Variable names can't have spaces statusVarName = statusVarName.replace(" ", "_") statusVarName = statusVarName.replace("/", "-") statusVar = None # Create folders or variables if they have been somehow deleted. if 'DeviceUpdate' not in indigo.variables.folders: indigo.variables.folder.create('DeviceUpdate') if statusVarName not in indigo.variables: indigo.variable.create(statusVarName, '', folder='DeviceUpdate') statusVar = indigo.variables[statusVarName] indigo.variable.updateValue(statusVar, str(isResponding)) def checkDeviceHeartbeat(self, action): "See if the device has responded to Indigo recently" props = action.props deviceName = props[u'deviceName'] withinSecs = int(props[u'withinSecs']) withinMinutes = int(props[u'withinMinutes']) withinHours = int(props[u'withinHours']) withinDays = int(props[u'withinDays']) self.hasHeartbeat(deviceName, withinSecs, withinMinutes, withinHours, withinDays) def flowMeterUpdate(self, action): "Update the latest flow meter readings" props = action.props deviceName = props[u'deviceName'] # test to see if flow stats folder exists by Name if not (FLW_FOLDER_NAME in indigo.variables.folders): indigo.server.log("folder named '%s' exists" % FLW_FOLDER_NAME) newFolder = indigo.variables.folder.create(FLW_FOLDER_NAME) if FLW_NAM_LAST_READING not in indigo.variables: indigo.variable.create(FLW_NAM_LAST_READING, '0', folder=FLW_FOLDER_NAME) readingVar = indigo.variables[FLW_NAM_LAST_READING] lastValue = float(readingVar.value) device = indigo.devices[deviceName] sensorValue = device.sensorValue indigo.variable.updateValue(readingVar, str(sensorValue)) currentUsage = sensorValue - lastValue if FLW_NAM_CURRENT_USAGE not in indigo.variables: indigo.variable.create(FLW_NAM_CURRENT_USAGE, '0', folder=FLW_FOLDER_NAME) currentUsageVar = indigo.variables[FLW_NAM_CURRENT_USAGE] indigo.variable.updateValue(currentUsageVar, str(currentUsage)) now = datetime.datetime.now() nowStr = now.strftime("%m/%d/%Y %H:%M:%S") if FLW_NAM_UPDATED_AT not in indigo.variables: indigo.variable.create(FLW_NAM_UPDATED_AT, '0', folder=FLW_FOLDER_NAME) updatedAtVar = indigo.variables[FLW_NAM_UPDATED_AT] indigo.variable.updateValue(updatedAtVar, nowStr)
class Plugin(indigo.PluginBase): def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.updater = GitHubPluginUpdater(self) self.apiVersion = "2.0" self.localAddress = "" # create empty device list self.deviceList = {} def __del__(self): indigo.PluginBase.__del__(self) ################################################################### # Plugin ################################################################### def deviceStartComm(self, device): self.debugLog(u"Started device: " + device.name) device.stateListOrDisplayStateIdChanged() self.addDeviceToList(device) def deviceStopComm(self, device): if device.id in self.deviceList: self.debugLog("Stoping device: " + device.name) self.deleteDeviceFromList(device) def deviceCreated(self, device): self.debugLog(u'Created device "' + device.name) pass def addDeviceToList(self, device): if device: if device.id not in self.deviceList: propsAddress = device.pluginProps["address"] propsAddress = propsAddress.strip() propsAddress = propsAddress.replace(' ', '') pingNextTime = datetime.datetime.now() - datetime.timedelta( seconds=10) pingInterval = device.pluginProps["pingInterval"] self.deviceList[device.id] = { 'ref': device, 'address': propsAddress, 'pingInterval': pingInterval, 'pingNextTime': pingNextTime } def deleteDeviceFromList(self, device): if device: if device.id in self.deviceList: del self.deviceList[device.id] def startup(self): self.loadPluginPrefs() self.debugLog(u"startup called") self.updater.checkForUpdate() def shutdown(self): self.debugLog(u"shutdown called") def getDeviceConfigUiValues(self, pluginProps, typeId, devId): valuesDict = pluginProps errorMsgDict = indigo.Dict() if "pingInterval" not in valuesDict: valuesDict["pingInterval"] = 300 return (valuesDict, errorMsgDict) def validateDeviceConfigUi(self, valuesDict, typeId, devId): self.debugLog(u"validating device Prefs called") self.debugLog(u"validating IP Address") ipAdr = valuesDict[u'address'] if ipAdr.count('.') != 3: errorMsgDict = indigo.Dict() errorMsgDict[u'address'] = u"This needs to be a valid IP address." return (False, valuesDict, errorMsgDict) if self.validateAddress(ipAdr) == False: errorMsgDict = indigo.Dict() errorMsgDict[u'address'] = u"This needs to be a valid IP address." return (False, valuesDict, errorMsgDict) pingInterval = valuesDict[u'pingInterval'] try: iInterval = int(pingInterval) if iInterval < 1: errorMsgDict = indigo.Dict() errorMsgDict[u'pingInterval'] = u"This needs to be > 0." return False except Exception, e: errorMsgDict = indigo.Dict() errorMsgDict[u'pingInterval'] = u"This needs to be a valid number." return False return (True, valuesDict)
def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = pluginPrefs.get('debug', False) self.updater = GitHubPluginUpdater(self)
class Plugin(indigo.PluginBase): ######################################## # Main Plugin methods ######################################## def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = self.pluginPrefs.get(u"showDebugInfo", False) self.debugLog(u"Debugging enabled") self.apiData = { "chamberlain" : { "service" : "https://myqexternal.myqdevice.com", # "appID" : "Vj8pQggXLhLy0WHahglCD4N1nAkkXQtGYpq2HrHD7H1nvmbT55KqtN6RSF4ILB%2fi" "appID" : "Vj8pQggXLhLy0WHahglCD4N1nAkkXQtGYpq2HrHD7H1nvmbT55KqtN6RSF4ILB/i" }, "craftsman" : { "service" : "https://craftexternal.myqdevice.com", "appID" : "eU97d99kMG4t3STJZO/Mu2wt69yTQwM0WXZA5oZ74/ascQ2xQrLD/yjeVhEQccBZ" }, "liftmaster" : { "service" : "https://myqexternal.myqdevice.com", # "appID" : "Vj8pQggXLhLy0WHahglCD4N1nAkkXQtGYpq2HrHD7H1nvmbT55KqtN6RSF4ILB%2fi" "appID" : "Vj8pQggXLhLy0WHahglCD4N1nAkkXQtGYpq2HrHD7H1nvmbT55KqtN6RSF4ILB/i" }, } self.triggers = { } def __del__(self): indigo.PluginBase.__del__(self) def startup(self): indigo.server.log(u"Starting MyQ") self.updater = GitHubPluginUpdater(self) self.updateFrequency = float(self.pluginPrefs.get('updateFrequency', "24")) * 60.0 * 60.0 if self.updateFrequency > 0: self.next_update_check = time.time() self.statusFrequency = float(self.pluginPrefs.get('statusFrequency', "10")) * 60.0 if self.statusFrequency > 0: self.next_status_check = time.time() def shutdown(self): indigo.server.log(u"Shutting down MyQ") def runConcurrentThread(self): try: while True: if self.updateFrequency > 0: if time.time() > self.next_update_check: self.updater.checkForUpdate() self.next_update_check = time.time() + self.updateFrequency if self.statusFrequency > 0: if time.time() > self.next_status_check: self.getDevices() self.next_status_check = time.time() + self.statusFrequency self.sleep(1.0) except self.stopThread: pass #################### def triggerStartProcessing(self, trigger): self.debugLog("Adding Trigger %s (%d) - %s" % (trigger.name, trigger.id, trigger.pluginTypeId)) assert trigger.id not in self.triggers self.triggers[trigger.id] = trigger def triggerStopProcessing(self, trigger): self.debugLog("Removing Trigger %s (%d)" % (trigger.name, trigger.id)) assert trigger.id in self.triggers del self.triggers[trigger.id] def triggerCheck(self, device): for triggerId, trigger in sorted(self.triggers.iteritems()): self.debugLog("\tChecking Trigger %s (%s), Type: %s" % (trigger.name, trigger.id, trigger.pluginTypeId)) #################### # def deviceStartComm(self, device): # self.debugLog(u'Called deviceStartComm(self, device): %s (%s)' % (device.name, device.id)) # instanceVers = int(device.pluginProps.get('devVersCount', 0)) # self.debugLog(device.name + u": Device Current Version = " + str(instanceVers)) # if instanceVers >= kCurDevVersCount: # self.debugLog(device.name + u": Device Version is up to date") # elif instanceVers < kCurDevVersCount: # newProps = device.pluginProps # else: # self.errorLog(u"Unknown device version: " + str(instanceVers) + " for device " + device.name) # def deviceStopComm(self, device): # self.debugLog(u'Called deviceStopComm(self, device): %s (%s)' % (device.name, device.id)) ######################################## # Menu Methods ######################################## def toggleDebugging(self): self.debug = not self.debug self.pluginPrefs["debugEnabled"] = self.debug indigo.server.log("Debug set to: " + str(self.debug)) def checkForUpdates(self): self.updater.checkForUpdate() def updatePlugin(self): self.updater.update() def forceUpdate(self): self.updater.update(currentVersion='0.0.0') ######################################## # ConfigUI methods ######################################## def validatePrefsConfigUi(self, valuesDict): self.debugLog(u"validatePrefsConfigUi called") errorDict = indigo.Dict() if len(valuesDict['myqLogin']) < 5: errorDict['myqLogin'] = u"Enter your MyQ login name (email address)" if len(valuesDict['myqPassword']) < 1: errorDict['myqPassword'] = u"Enter your MyQ login password" statusFrequency = int(valuesDict['statusFrequency']) if (statusFrequency < 5) or (statusFrequency > (24 * 60)): errorDict['statusFrequency'] = u"Status frequency must be at least 5 min and less than 24 hours" updateFrequency = int(valuesDict['updateFrequency']) if (updateFrequency < 0) or (updateFrequency > 24): errorDict['updateFrequency'] = u"Update frequency is invalid - enter a valid number (between 0 and 24)" if len(errorDict) > 0: return (False, valuesDict, errorDict) return (True, valuesDict) def closedPrefsConfigUi(self, valuesDict, userCancelled): if not userCancelled: self.debug = valuesDict.get("showDebugInfo", False) if self.debug: self.debugLog(u"Debug logging enabled") else: self.debugLog(u"Debug logging disabled") # def validateDeviceConfigUi(self, valuesDict, typeId, devId): # self.debugLog(u'Called validateDeviceConfigUi, valuesDict = %s, typeId = %s, devId = %s' % (str(valuesDict), typeId, devId)) # errorsDict = indigo.Dict() # if int(valuesDict["address"]) < 1: # errorDict['address'] = u"Invalid Device ID Number" # if len(errorsDict) > 0: # return (False, valuesDict, errorsDict) # return (True, valuesDict) # def validateActionConfigUi(self, valuesDict, typeId, devId): # self.debugLog(u'Called validateActionConfigUi, valuesDict = %s, typeId = %s, devId = %s' % (str(valuesDict), typeId, devId)) # errorsDict = indigo.Dict() # try: # pass # except: # pass # if len(errorsDict) > 0: # return (False, valuesDict, errorsDict) # return (True, valuesDict) ######################################## def actionControlDimmerRelay(self, action, dev): if action.deviceAction == indigo.kDeviceAction.TurnOn: self.debugLog(u"actionControlDimmerRelay: \"%s\" On" % dev.name) self.changeDevice(dev, kDoorOpen) elif action.deviceAction == indigo.kDeviceAction.TurnOff: self.debugLog(u"actionControlDimmerRelay: \"%s\" Off" % dev.name) self.changeDevice(dev, kDoorClosed) elif action.deviceAction == indigo.kDeviceAction.Toggle: self.debugLog(u"actionControlDimmerRelay: \"%s\" Toggle" % dev.name) if dev.isOn: self.changeDevice(dev, kDoorClosed) else: self.changeDevice(dev, kDoorOpen) elif action.deviceAction == indigo.kDeviceAction.RequestStatus: self.debugLog(u"actionControlDimmerRelay: \"%s\" Request Status" % dev.name) self.getDevices() ######################################## def myqLogin(self): self.username = self.pluginPrefs.get('myqLogin', None) self.password = self.pluginPrefs.get('myqPassword', None) self.brand = self.pluginPrefs.get('openerBrand', None) if (self.brand): self.service = self.apiData[self.brand]["service"] self.appID = self.apiData[self.brand]["appID"] # self.logger.debug(u"myqLogin Info, username = %s, password length = %d, brand = %s, service = %s, appID = %s" % (self.username, len(self.password), self.brand, self.service, self.appID)) # url = self.service + '/Membership/ValidateUserWithCulture?appid=' + self.appID + '&securityToken=null&username='******'&password='******'&culture=en' payload = {'appId': self.appID, 'securityToken': 'null', 'username': self.username, 'password': self.password, 'culture': 'en'} login_url = self.service + '/Membership/ValidateUserWithCulture' headers = {'User-Agent': userAgent} try: # response = requests.get(url) response = requests.get(login_url, params=payload, headers=headers) self.logger.debug(u"myqLogin: response = " + str(response)) self.logger.debug(u"myqLogin: content = " + str(response.text)) except requests.exceptions.RequestException as err: self.logger.debug(u"myqLogin failure: RequestException: " + str(err)) self.securityToken = "" return try: data = response.json() except ValueError as err: self.logger.debug(u"myqLogin failure: JSON Decode Error: " + str(err)) self.securityToken = "" return if data['ReturnCode'] != '0': self.debugLog(u"myqLogin failure: Bad return code: " + data['ErrorMessage']) self.securityToken = "" return self.securityToken = data['SecurityToken'] self.debugLog(u"myqLogin: Success, SecurityToken = %s" % (self.securityToken)) ######################################## def getDevices(self): self.myqLogin() if not self.securityToken: return url = self.service + '/api/UserDeviceDetails' params = {'appId':self.appID, 'securityToken':self.securityToken} headers = {'User-Agent': userAgent } try: response = requests.get(url, params=params, headers=headers) except requests.exceptions.RequestException as err: self.debugLog(u"getDevices: RequestException: " + str(err)) return data = response.json() if data['ReturnCode'] != '0': self.debugLog(u"getDevices: Bad return code: " + data['ErrorMessage']) return self.debugLog(u"getDevices: %d Devices" % len(data['Devices'])) for device in data['Devices']: self.debugLog(u"getDevices: MyQDeviceTypeId = %s, DeviceId = %s" % (device['MyQDeviceTypeId'], device['DeviceId'])) if (device['MyQDeviceTypeId'] == 2) or (device['MyQDeviceTypeId'] == 5) or (device['MyQDeviceTypeId'] == 7): # MyQDeviceTypeId Door == 2, Gate == 5, Door? == 7 myqID = device['DeviceId'] name = self.getDeviceName(myqID) state = self.getDeviceState(myqID) if state > 7: self.errorLog(u"getDevices: Opener %s (%s), state out of range: %i" % (name, myqID, state)) state = 0 # unknown high states else: self.debugLog(u"getDevices: Opener %s (%s), state = %i" % (name, myqID, state)) # look for this opener device in the existing devices for this plugin. If it's not there (by id), then create it iterator = indigo.devices.iter(filter="com.flyingdiver.indigoplugin.myq") for dev in iterator: if dev.address == myqID: dev.updateStateOnServer(key="doorStatus", value=doorStateNames[int(state)]) if state == 2: dev.updateStateOnServer(key="onOffState", value=False) # closed is off else: dev.updateStateOnServer(key="onOffState", value=True) # anything other than closed is "on" break else: # Python syntax weirdness - this else belongs to the for loop! newdev = indigo.device.create(protocol=indigo.kProtocol.Plugin, address=myqID, description = "Opener Device auto-created by MyQ plugin from gateway information", deviceTypeId='myqOpener', name=name) newdev.updateStateOnServer(key="doorStatus", value=doorStateNames[int(state)]) self.debugLog(u'Created New Opener Device: %s (%s)' % (newdev.name, newdev.address)) elif device['MyQDeviceTypeId'] == 3: # Switch == 3? myqID = device['DeviceId'] name = self.getDeviceName(myqID) state = self.getDeviceState(myqID) # self.debugLog(u"getDevices: Switch = %s (%s), data = %s" % (name, myqID, str(device))) # look for this opener device in the existing devices for this plugin. If it's not there (by id), then create it iterator = indigo.devices.iter(filter="com.flyingdiver.indigoplugin.myq") for dev in iterator: if dev.address == myqID: break else: # Python syntax weirdness - this else belongs to the for loop! newdev = indigo.device.create(protocol=indigo.kProtocol.Plugin, address=myqID, description = "Switch Device auto-created by MyQ plugin from gateway information", deviceTypeId='myqSwitch', name=name) # newdev.updateStateOnServer(key="doorStatus", value=doorStateNames[int(state)]) self.debugLog(u'Created New Switch Device: %s (%s)' % (newdev.name, newdev.address)) def getDeviceName(self, doorID): url = self.service + '/Device/getDeviceAttribute' params = {'appId': self.appID, 'securityToken': self.securityToken, 'devId': doorID, 'name':'desc'} headers = {'User-Agent': userAgent} try: response = requests.get(url, params=params, headers=headers) except requests.exceptions.RequestException as err: self.debugLog(u"getDeviceName: RequestException: " + str(err)) return "" data = response.json() if data['ReturnCode'] != '0': self.debugLog(u"getDeviceName: Bad return code: " + data['ErrorMessage']) return "" return data['AttributeValue'] def getDeviceState(self, doorID): url = self.service + '/Device/getDeviceAttribute' params = {'appID': self.appID, 'securityToken': self.securityToken, 'devId': doorID, 'name':'doorstate'} headers = {'User-Agent': userAgent} try: response = requests.get(url, params=params, headers=headers) except requests.exceptions.RequestException as err: self.debugLog(u"getDeviceState: RequestException: " + str(err)) return 0 data = response.json() if data['ReturnCode'] != '0': self.debugLog(u"getDeviceState: Bad return code: " + data['ErrorMessage']) return 0 return int(data['AttributeValue']) ######################################## def changeDeviceAction(self, pluginAction): if pluginAction != None: myqDevice = indigo.devices[pluginAction.deviceId] myqActionId = pluginAction.pluginTypeId if myqActionId == "openDoor": self.changeDevice(myqDevice, kDoorOpen) elif myqActionId == "closeDoor": self.changeDevice(myqDevice, kDoorClosed) elif myqActionId == "switchOn": self.changeDevice(myqDevice, kSwitchOn) elif myqActionId == "switchOff": self.changeDevice(myqDevice, kSwitchOff) else: self.debugLog(u"changeDeviceAction, unknown myqActionId = %s" % myqActionId) def changeDevice(self, device, state): self.debugLog(u"changeDevice: %s, state = %d" % (device.name, state)) self.myqLogin() payload = { 'ApplicationId': self.appID, 'AttributeName': 'desireddoorstate', 'DeviceId': device.address, 'AttributeValue': state, 'SecurityToken': self.securityToken } url = self.service + '/api/deviceattribute/putdeviceattribute' headers = {'User-Agent': userAgent} try: response = requests.put(url, data=payload, headers=headers) except requests.exceptions.RequestException as err: self.debugLog(u"changeDevice: RequestException: " + str(err)) return data = response.json() if data['ReturnCode'] != '0': self.debugLog(u"changeDevice: Bad return code: " + data['ErrorMessage']) # schedule an update to check on the movement self.next_status_check = time.time() + 30.0
def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = pluginPrefs.get('debug', False) self.updater = GitHubPluginUpdater('jheddings', 'indigo-ghpu', self)
class Plugin(indigo.PluginBase): # --------------------------------------------------------------------------- def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = pluginPrefs.get("debug", False) self.updater = GitHubPluginUpdater(self) # --------------------------------------------------------------------------- def __del__(self): indigo.PluginBase.__del__(self) # --------------------------------------------------------------------------- def checkForUpdates(self): self.updater.checkForUpdate() # --------------------------------------------------------------------------- def updatePlugin(self): self.updater.update() # --------------------------------------------------------------------------- def toggleDebugging(self): self.debug = not self.debug self.pluginPrefs["debug"] = self.debug # --------------------------------------------------------------------------- def validatePrefsConfigUi(self, values): errors = indigo.Dict() # application name is required... appname = values.get("appname", "") if len(appname) == 0: errors["appname"] = "You must provide an application name" # an API key is required and must be valid... apikey = values.get("apikey", "") if len(apikey) == 0: errors["apikey"] = "You must provide your Prowl API key" elif not self.prowlVerify(apikey): errors["apikey"] = "Invalid API key" return ((len(errors) == 0), values, errors) # --------------------------------------------------------------------------- def closedPrefsConfigUi(self, values, canceled): if not canceled: self.debug = values.get("debug", False) # --------------------------------------------------------------------------- def validateActionConfigUi(self, values, typeId, devId): errors = indigo.Dict() # building a description for the Indigio UI... priority = values["priority"] header = "Prowl [" + priority + "]: " # the title is not required, but check substitutions if it is there... title = values.get("title", "") if len(title) > 0: subst = self.substitute(title, validateOnly=True) if subst[0]: header += title + "-" else: errors["title"] = subst[1] # a message is required, and we'll verify substitutions message = values.get("message", "") if len(message) == 0: errors["message"] = "You must provide a message" else: subst = self.substitute(message, validateOnly=True) if not subst[0]: errors["message"] = subst[1] # create the description for Indigo's UI values["description"] = header + message return ((len(errors) == 0), values, errors) # --------------------------------------------------------------------------- def notify(self, action): # perform substitution on the title and message title = self.substitute(action.props.get("title", "")) message = self.substitute(action.props.get("message", "")) # construct the API call body params = urllib.urlencode( { "apikey": self.pluginPrefs.get("apikey", None), "priority": action.props.get("priority", "0"), "event": title, "description": message, "application": self.pluginPrefs.get("appname", "Indigo"), } ) self.debugLog("notify: %s" % params) # Prowl won't accept the POST unless it carries the right content type headers = {"Content-type": "application/x-www-form-urlencoded"} try: conn = httplib.HTTPSConnection("api.prowlapp.com") conn.request("POST", "/publicapi/add", params, headers) resp = conn.getresponse() # so we can see the results in the log... self.processStdResponse(resp) except Exception as e: self.errorLog(str(e)) # --------------------------------------------------------------------------- # verify the given API key is valid with Prowl def prowlVerify(self, apikey): params = urllib.urlencode({"apikey": apikey}) self.debugLog("verify: %s" % params) verified = False try: conn = httplib.HTTPConnection("api.prowlapp.com") conn.request("GET", "/publicapi/verify?" + params) resp = conn.getresponse() verified = self.processStdResponse(resp) except Exception as e: self.errorLog(str(e)) return verified # --------------------------------------------------------------------------- # returns True if the response represents success, False otherwise def processStdResponse(self, resp): self.debugLog("HTTP %d %s" % (resp.status, resp.reason)) root = ElementTree.fromstring(resp.read()) content = root[0] if content.tag == "success": remain = int(content.attrib["remaining"]) self.debugLog("success: %d calls remaining" % remain) elif content.tag == "error": self.errorLog("error: %s" % content.text) else: # just in case something strange comes along... raise Exception("unknown response", content.tag) return resp.status == 200
class Plugin(indigo.PluginBase): #--------------------------------------------------------------------------- def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = pluginPrefs.get('debug', False) self.updater = GitHubPluginUpdater(self) #--------------------------------------------------------------------------- def __del__(self): indigo.PluginBase.__del__(self) #--------------------------------------------------------------------------- def selfInstall(self): self.updater.install() #--------------------------------------------------------------------------- def forceUpdate(self): self.updater.update(currentVersion='0.0.0') #--------------------------------------------------------------------------- def updatePlugin(self): self.updater.update() #--------------------------------------------------------------------------- def checkForUpdates(self): self.updater.checkForUpdate() #--------------------------------------------------------------------------- def checkRateLimit(self): limiter = self.updater.getRateLimit() indigo.server.log('RateLimit {limit:%d remaining:%d resetAt:%d}' % limiter) #--------------------------------------------------------------------------- def testUpdateCheck(self): indigo.server.log('-- BEGIN testUpdateCheck --') self.updater.checkForUpdate() self.updater.checkForUpdate('0.0.0') emptyUpdater = GitHubPluginUpdater() emptyUpdater.checkForUpdate() emptyUpdater.checkForUpdate('0.0.0') emptyUpdater.checkForUpdate(str(self.pluginVersion)) indigo.server.log('-- END testUpdateCheck --') #--------------------------------------------------------------------------- def toggleDebugging(self): self.debug = not self.debug self.pluginPrefs['debug'] = self.debug #--------------------------------------------------------------------------- def closedPrefsConfigUi(self, values, canceled): if (not canceled): self.debug = values.get('debug', False) #--------------------------------------------------------------------------- def runConcurrentThread(self): while True: # this checks for any updates on a regular interval self.updater.checkForUpdate() # we are checking every 300 seconds (5 minutes) here as an example # in practice, this should not be less than 3600 seconds (1 hour) self.sleep(300)
class Plugin(indigo.PluginBase): def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.updater = GitHubPluginUpdater(self) #'tenallero', 'Indigo-XBMC', self) # Port self.listenPortDef = 8189 self.listenPort = 0 self.apiVersion = "2.0" self.localAddress = "" # Pooling self.pollingInterval = 0 self.requestID = 0 # Flag buttonRequest is processing self.reqRunning = 0 # create empty device list self.deviceList = {} self.sock = None self.socketBufferSize = 512 self.socketStop = False def __del__(self): indigo.PluginBase.__del__(self) ################################################################### # Plugin ################################################################### def deviceStartComm(self, device): self.debugLog(device.name + ": Starting device") device.stateListOrDisplayStateIdChanged() self.addDeviceToList (device) def addDeviceToList(self,device): if device: if device.id not in self.deviceList: propsAddress = '' propsAddress = device.pluginProps["address"] propsAddress = propsAddress.strip() propsAddress = propsAddress.replace (' ','') self.deviceList[device.id] = {'ref':device,'address':propsAddress, 'lastTimeAlive':datetime.datetime.now()} def deleteDeviceFromList(self, device): if device: if device.id in self.deviceList: del self.deviceList[device.id] def deviceStopComm(self,device): if device.id in self.deviceList: self.debugLog(device.name + ": Stoping device") self.deleteDeviceFromList(device) def startup(self): self.loadPluginPrefs() self.debugLog(u"startup called") self.requestID = 0 # Obtain local address. # This will identify a XBMC device running in same machine than Indigo s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("gmail.com",80)) self.localAddress = s.getsockname()[0] s.close() self.debugLog("Local IP address: " + self.localAddress) self.updater.checkForUpdate() def shutdown(self): self.debugLog(u"shutdown called") def deviceCreated(self, device): self.debugLog(u"Created device of type \"%s\"" % device.deviceTypeId) def validateDeviceConfigUi(self, valuesDict, typeId, devId): self.debugLog(u"validating device Prefs called") ipAdr = valuesDict[u'address'] if ipAdr.count('.') != 3: errorMsgDict = indigo.Dict() errorMsgDict[u'address'] = u"This needs to be a valid IP address." return (False, valuesDict, errorMsgDict) if self.validateAddress (ipAdr) == False: errorMsgDict = indigo.Dict() errorMsgDict[u'address'] = u"This needs to be a valid IP address." return (False, valuesDict, errorMsgDict) tcpPort = valuesDict[u'port'] try: iPort = int(tcpPort) if iPort <= 0: errorMsgDict = indigo.Dict() errorMsgDict[u'port'] = u"This needs to be a valid TCP port." return (False, valuesDict, errorMsgDict) except Exception, e: errorMsgDict = indigo.Dict() errorMsgDict[u'port'] = u"This needs to be a valid TCP port." return (False, valuesDict, errorMsgDict) if (valuesDict[u'useAuthentication']): if not(valuesDict[u'username']>""): errorMsgDict = indigo.Dict() errorMsgDict[u'username'] = u"Must be filled." return (False, valuesDict, errorMsgDict) if not(valuesDict[u'password']>""): errorMsgDict = indigo.Dict() errorMsgDict[u'password'] = u"Must be filled." return (False, valuesDict, errorMsgDict) return (True, valuesDict)
def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.updater = GitHubPluginUpdater(self)
def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): super(Plugin, self).__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = False self.updater = GitHubPluginUpdater(self)
class Plugin(indigo.PluginBase): ######################################## # Main Plugin methods ######################################## def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs) self.debug = self.pluginPrefs.get(u"showDebugInfo", False) self.debugLog(u"Debugging enabled") self.apiData = { "chamberlain" : { "service" : "https://myqexternal.myqdevice.com", "appID" : "Vj8pQggXLhLy0WHahglCD4N1nAkkXQtGYpq2HrHD7H1nvmbT55KqtN6RSF4ILB/i" }, "craftsman" : { "service" : "https://craftexternal.myqdevice.com", "appID" : "eU97d99kMG4t3STJZO/Mu2wt69yTQwM0WXZA5oZ74/ascQ2xQrLD/yjeVhEQccBZ" }, "liftmaster" : { "service" : "https://myqexternal.myqdevice.com", "appID" : "Vj8pQggXLhLy0WHahglCD4N1nAkkXQtGYpq2HrHD7H1nvmbT55KqtN6RSF4ILB/i" }, } self.triggers = { } def __del__(self): indigo.PluginBase.__del__(self) def startup(self): indigo.server.log(u"Starting MyQ") self.updater = GitHubPluginUpdater(self) self.updateFrequency = float(self.pluginPrefs.get('updateFrequency', "24")) * 60.0 * 60.0 if self.updateFrequency > 0: self.next_update_check = time.time() self.statusFrequency = float(self.pluginPrefs.get('statusFrequency', "10")) * 60.0 if self.statusFrequency > 0: self.next_status_check = time.time() def shutdown(self): indigo.server.log(u"Shutting down MyQ") def runConcurrentThread(self): try: while True: if self.updateFrequency > 0: if time.time() > self.next_update_check: self.updater.checkForUpdate() self.next_update_check = time.time() + self.updateFrequency if self.statusFrequency > 0: if time.time() > self.next_status_check: self.getDevices() self.next_status_check = time.time() + self.statusFrequency self.sleep(1.0) except self.stopThread: pass #################### def triggerStartProcessing(self, trigger): self.debugLog("Adding Trigger %s (%d) - %s" % (trigger.name, trigger.id, trigger.pluginTypeId)) assert trigger.id not in self.triggers self.triggers[trigger.id] = trigger def triggerStopProcessing(self, trigger): self.debugLog("Removing Trigger %s (%d)" % (trigger.name, trigger.id)) assert trigger.id in self.triggers del self.triggers[trigger.id] def triggerCheck(self, device): for triggerId, trigger in sorted(self.triggers.iteritems()): self.debugLog("\tChecking Trigger %s (%s), Type: %s" % (trigger.name, trigger.id, trigger.pluginTypeId)) #################### # def deviceStartComm(self, device): # self.debugLog(u'Called deviceStartComm(self, device): %s (%s)' % (device.name, device.id)) # instanceVers = int(device.pluginProps.get('devVersCount', 0)) # self.debugLog(device.name + u": Device Current Version = " + str(instanceVers)) # if instanceVers >= kCurDevVersCount: # self.debugLog(device.name + u": Device Version is up to date") # elif instanceVers < kCurDevVersCount: # newProps = device.pluginProps # else: # self.errorLog(u"Unknown device version: " + str(instanceVers) + " for device " + device.name) # def deviceStopComm(self, device): # self.debugLog(u'Called deviceStopComm(self, device): %s (%s)' % (device.name, device.id)) ######################################## # Menu Methods ######################################## def toggleDebugging(self): self.debug = not self.debug self.pluginPrefs["debugEnabled"] = self.debug indigo.server.log("Debug set to: " + str(self.debug)) def checkForUpdates(self): self.updater.checkForUpdate() def updatePlugin(self): self.updater.update() def forceUpdate(self): self.updater.update(currentVersion='0.0.0') ######################################## # ConfigUI methods ######################################## def validatePrefsConfigUi(self, valuesDict): self.debugLog(u"validatePrefsConfigUi called") errorDict = indigo.Dict() if len(valuesDict['myqLogin']) < 5: errorDict['myqLogin'] = u"Enter your MyQ login name (email address)" if len(valuesDict['myqPassword']) < 1: errorDict['myqPassword'] = u"Enter your MyQ login password" statusFrequency = int(valuesDict['statusFrequency']) if (statusFrequency < 5) or (statusFrequency > (24 * 60)): errorDict['statusFrequency'] = u"Status frequency must be at least 5 min and less than 24 hours" updateFrequency = int(valuesDict['updateFrequency']) if (updateFrequency < 0) or (updateFrequency > 24): errorDict['updateFrequency'] = u"Update frequency is invalid - enter a valid number (between 0 and 24)" if len(errorDict) > 0: return (False, valuesDict, errorDict) return (True, valuesDict) def closedPrefsConfigUi(self, valuesDict, userCancelled): if not userCancelled: self.debug = valuesDict.get("showDebugInfo", False) if self.debug: self.debugLog(u"Debug logging enabled") else: self.debugLog(u"Debug logging disabled") # def validateDeviceConfigUi(self, valuesDict, typeId, devId): # self.debugLog(u'Called validateDeviceConfigUi, valuesDict = %s, typeId = %s, devId = %s' % (str(valuesDict), typeId, devId)) # errorsDict = indigo.Dict() # if int(valuesDict["address"]) < 1: # errorDict['address'] = u"Invalid Device ID Number" # if len(errorsDict) > 0: # return (False, valuesDict, errorsDict) # return (True, valuesDict) # def validateActionConfigUi(self, valuesDict, typeId, devId): # self.debugLog(u'Called validateActionConfigUi, valuesDict = %s, typeId = %s, devId = %s' % (str(valuesDict), typeId, devId)) # errorsDict = indigo.Dict() # try: # pass # except: # pass # if len(errorsDict) > 0: # return (False, valuesDict, errorsDict) # return (True, valuesDict) ######################################## def actionControlDimmerRelay(self, action, dev): if action.deviceAction == indigo.kDeviceAction.TurnOn: self.debugLog(u"actionControlDimmerRelay: \"%s\" On" % dev.name) self.changeDevice(dev, kDoorOpen) elif action.deviceAction == indigo.kDeviceAction.TurnOff: self.debugLog(u"actionControlDimmerRelay: \"%s\" Off" % dev.name) self.changeDevice(dev, kDoorClosed) elif action.deviceAction == indigo.kDeviceAction.Toggle: self.debugLog(u"actionControlDimmerRelay: \"%s\" Toggle" % dev.name) if dev.isOn: self.changeDevice(dev, kDoorClosed) else: self.changeDevice(dev, kDoorOpen) elif action.deviceAction == indigo.kDeviceAction.RequestStatus: self.debugLog(u"actionControlDimmerRelay: \"%s\" Request Status" % dev.name) self.getDevices() ######################################## def myqLogin(self): self.username = self.pluginPrefs.get('myqLogin', None) self.password = self.pluginPrefs.get('myqPassword', None) self.brand = self.pluginPrefs.get('openerBrand', None) if (self.brand): self.service = self.apiData[self.brand]["service"] self.appID = self.apiData[self.brand]["appID"] payload = {'appId': self.appID, 'securityToken': 'null', 'username': self.username, 'password': self.password, 'culture': 'en'} login_url = self.service + '/Membership/ValidateUserWithCulture' headers = {'User-Agent': userAgent} try: response = requests.get(login_url, params=payload, headers=headers) self.logger.debug(u"myqLogin: response = " + str(response)) self.logger.debug(u"myqLogin: content = " + str(response.text)) except requests.exceptions.RequestException as err: self.logger.debug(u"myqLogin failure: RequestException: " + str(err)) self.securityToken = "" return try: data = response.json() except ValueError as err: self.logger.debug(u"myqLogin failure: JSON Decode Error: " + str(err)) self.securityToken = "" return if data['ReturnCode'] != '0': self.debugLog(u"myqLogin failure: Bad return code: " + data['ErrorMessage']) self.securityToken = "" return self.securityToken = data['SecurityToken'] self.debugLog(u"myqLogin: Success, SecurityToken = %s" % (self.securityToken)) ######################################## def getDevices(self): self.myqLogin() if not self.securityToken: return url = self.service + '/api/UserDeviceDetails' params = {'appId':self.appID, 'securityToken':self.securityToken} headers = {'User-Agent': userAgent } try: response = requests.get(url, params=params, headers=headers) except requests.exceptions.RequestException as err: self.debugLog(u"getDevices: RequestException: " + str(err)) return data = response.json() if data['ReturnCode'] != '0': self.debugLog(u"getDevices: Bad return code: " + data['ErrorMessage']) return self.debugLog(u"getDevices: %d Devices" % len(data['Devices'])) for device in data['Devices']: self.debugLog(u"getDevices: MyQDeviceTypeId = %s, DeviceId = %s" % (device['MyQDeviceTypeId'], device['DeviceId'])) if (device['MyQDeviceTypeId'] == 2) or (device['MyQDeviceTypeId'] == 5) or (device['MyQDeviceTypeId'] == 7): # MyQDeviceTypeId Door == 2, Gate == 5, Door? == 7 myqID = device['DeviceId'] name = self.getDeviceName(myqID) state = self.getDeviceState(myqID) if state > 7: self.errorLog(u"getDevices: Opener %s (%s), state out of range: %i" % (name, myqID, state)) state = 0 # unknown high states else: self.debugLog(u"getDevices: Opener %s (%s), state = %i" % (name, myqID, state)) # look for this opener device in the existing devices for this plugin. If it's not there (by id), then create it iterator = indigo.devices.iter(filter="com.flyingdiver.indigoplugin.myq") for dev in iterator: if dev.address == myqID: dev.updateStateOnServer(key="doorStatus", value=doorStateNames[int(state)]) if state == 2: dev.updateStateOnServer(key="onOffState", value=False) # closed is off else: dev.updateStateOnServer(key="onOffState", value=True) # anything other than closed is "on" break else: # Python syntax weirdness - this else belongs to the for loop! newdev = indigo.device.create(protocol=indigo.kProtocol.Plugin, address=myqID, description = "Opener Device auto-created by MyQ plugin from gateway information", deviceTypeId='myqOpener', name=name) newdev.updateStateOnServer(key="doorStatus", value=doorStateNames[int(state)]) self.debugLog(u'Created New Opener Device: %s (%s)' % (newdev.name, newdev.address)) elif device['MyQDeviceTypeId'] == 3: # Switch == 3? myqID = device['DeviceId'] name = self.getDeviceName(myqID) state = self.getDeviceState(myqID) # self.debugLog(u"getDevices: Switch = %s (%s), data = %s" % (name, myqID, str(device))) # look for this opener device in the existing devices for this plugin. If it's not there (by id), then create it iterator = indigo.devices.iter(filter="com.flyingdiver.indigoplugin.myq") for dev in iterator: if dev.address == myqID: break else: # Python syntax weirdness - this else belongs to the for loop! newdev = indigo.device.create(protocol=indigo.kProtocol.Plugin, address=myqID, description = "Switch Device auto-created by MyQ plugin from gateway information", deviceTypeId='myqSwitch', name=name) # newdev.updateStateOnServer(key="doorStatus", value=doorStateNames[int(state)]) self.debugLog(u'Created New Switch Device: %s (%s)' % (newdev.name, newdev.address)) def getDeviceName(self, doorID): url = self.service + '/Device/getDeviceAttribute' params = {'appId': self.appID, 'securityToken': self.securityToken, 'devId': doorID, 'name':'desc'} headers = {'User-Agent': userAgent} try: response = requests.get(url, params=params, headers=headers) except requests.exceptions.RequestException as err: self.debugLog(u"getDeviceName: RequestException: " + str(err)) return "" data = response.json() if data['ReturnCode'] != '0': self.debugLog(u"getDeviceName: Bad return code: " + data['ErrorMessage']) return "" return data['AttributeValue'] def getDeviceState(self, doorID): url = self.service + '/Device/getDeviceAttribute' params = {'appID': self.appID, 'securityToken': self.securityToken, 'devId': doorID, 'name':'doorstate'} headers = {'User-Agent': userAgent} try: response = requests.get(url, params=params, headers=headers) except requests.exceptions.RequestException as err: self.debugLog(u"getDeviceState: RequestException: " + str(err)) return 0 data = response.json() if data['ReturnCode'] != '0': self.debugLog(u"getDeviceState: Bad return code: " + data['ErrorMessage']) return 0 return int(data['AttributeValue']) ######################################## def changeDeviceAction(self, pluginAction): if pluginAction != None: myqDevice = indigo.devices[pluginAction.deviceId] myqActionId = pluginAction.pluginTypeId if myqActionId == "openDoor": self.changeDevice(myqDevice, kDoorOpen) elif myqActionId == "closeDoor": self.changeDevice(myqDevice, kDoorClosed) elif myqActionId == "switchOn": self.changeDevice(myqDevice, kSwitchOn) elif myqActionId == "switchOff": self.changeDevice(myqDevice, kSwitchOff) else: self.debugLog(u"changeDeviceAction, unknown myqActionId = %s" % myqActionId) def changeDevice(self, device, state): self.debugLog(u"changeDevice: %s, state = %d" % (device.name, state)) self.myqLogin() payload = { 'ApplicationId': self.appID, 'AttributeName': 'desireddoorstate', 'DeviceId': device.address, 'AttributeValue': state, 'SecurityToken': self.securityToken } url = self.service + '/api/deviceattribute/putdeviceattribute' headers = {'User-Agent': userAgent} try: response = requests.put(url, data=payload, headers=headers) except requests.exceptions.RequestException as err: self.debugLog(u"changeDevice: RequestException: " + str(err)) return data = response.json() if data['ReturnCode'] != '0': self.debugLog(u"changeDevice: Bad return code: " + data['ErrorMessage']) # schedule an update to check on the movement self.next_status_check = time.time() + 30.0