예제 #1
0
    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
예제 #2
0
    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
예제 #3
0
    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()
예제 #4
0
	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()
예제 #5
0
    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 = {}
예제 #6
0
    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()
예제 #7
0
    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 = []
예제 #8
0
    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 = {}
예제 #9
0
    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 = {}
예제 #10
0
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
예제 #11
0
    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 --')
예제 #12
0
 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
예제 #13
0
	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 = { }
예제 #14
0
    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()
예제 #15
0
 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))
예제 #16
0
    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 --')
예제 #17
0
    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)
예제 #18
0
	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 = { }
예제 #19
0
    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
예제 #20
0
    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
예제 #21
0
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)
예제 #22
0
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')
예제 #23
0
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")
예제 #24
0
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')
예제 #25
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)
예제 #26
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 = {}
        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    
예제 #27
0
파일: plugin.py 프로젝트: six50joe/Indigo
	def startup(self):
		self.logger.debug(u"startup called")

		self.logger.debug(u'Getting plugin updater')
		self.updater = GitHubPluginUpdater(self)
예제 #28
0
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')
예제 #29
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)
예제 #30
0
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)
예제 #31
0
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
예제 #32
0
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
예제 #33
0
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)
예제 #34
0
    def startup(self):
        if self.debugextra:
            self.debugLog(u"Starting Plugin. startup() method called.")

        self.updater = GitHubPluginUpdater(self)
예제 #35
0
파일: plugin.py 프로젝트: six50joe/Indigo
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)
예제 #36
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)
예제 #37
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(self)
예제 #38
0
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
예제 #39
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)
예제 #40
0
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
예제 #41
0
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)
예제 #42
0
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)
예제 #43
0
	def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs):
		indigo.PluginBase.__init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs)
		self.updater = GitHubPluginUpdater(self)		
예제 #44
0
 def __init__(self, pluginId, pluginDisplayName, pluginVersion,
              pluginPrefs):
     super(Plugin, self).__init__(pluginId, pluginDisplayName,
                                  pluginVersion, pluginPrefs)
     self.debug = False
     self.updater = GitHubPluginUpdater(self)
예제 #45
0
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