예제 #1
0
    def configure(self, data=None):
        if data is not None:
            self.config.update(data)

        self.paramParser = ParamParser(self.config, self.use_numeric_key)
        self.connectionDescription = (self.config.get('hostName', '') + ':' +
                                      str(self.config.get('port', 0)))
예제 #2
0
    def __init__(self, config, logger, use_numeric_key=False):
        super(WebOS, self).__init__("ws://" + config['hostName'] + ':' +
                                    str(config['port']),
                                    exclude_headers=["Origin"])
        self.config = config
        self.connected = False
        self.connectEvent = Event()
        self.curID = 0
        self.callbacks = {}
        self.clientKey = None
        self.logger = logger
        self.paramParser = ParamParser(config, use_numeric_key)
        try:
            with open(config['clientKeyFile'], 'r') as clientKeyInput:
                self.clientKey = yaml.load(clientKeyInput)
        except:
            pass

        try:
            with open(config['macFile'], 'r') as macInput:
                self.config.update(yaml.load(macInput))
        except:
            pass

        self.sock.settimeout(5)
        try:
            self.connect()
        except:
            logger.debug('Websocket timeout. Possibly device is off')

        logger.info('Loaded %s driver', __name__)
예제 #3
0
 def __init__(self, config, logger, use_numeric_key=False):
     self.config = config
     self.executable = config['executable']
     self.logger = logger
     self.paramParser = ParamParser(config, use_numeric_key)
     self.connectStr = self.config['hostName'] + ':' + str(
         self.config['port'])
     self.connected = False
     logger.info('Loaded %s driver', __name__)
예제 #4
0
    def create(self):
        # Write controller labels
        self.nlsData.append('# controller labels')
        self.nlsData.append('')
        self.nlsData.append(
            self.NODE_NAME.format(
                'controller',
                self.config['controller']['name'] + ' Controller'))
        self.nlsData.append(
            self.NODE_ICON.format(
                'controller',
                self.config['controller'].get('icon', 'GenericCtl')))
        self.nlsData.append('')
        self.nlsData.append(
            self.COMMAND_NAME.format('ctl-DISCOVER', 'Re-Discover'))
        self.nlsData.append(
            self.STATUS_NAME.format(
                'ctl', 'ST', self.config['controller']['name'] + ' Online'))
        self.nlsData.append('')

        # Write controller node
        nodeDef = ET.SubElement(self.nodeTree,
                                'nodeDef',
                                id='controller',
                                nls='ctl')
        sts = ET.SubElement(nodeDef, 'sts')
        ET.SubElement(sts, 'st', id='ST', editor='bool')
        cmds = ET.SubElement(nodeDef, 'cmds')
        ET.SubElement(cmds, 'sends')
        accepts = ET.SubElement(cmds, 'accepts')
        ET.SubElement(accepts, 'cmd', id='DISCOVER')

        # Write primary devices
        for driverName, driverData in self.config['drivers'].items():
            polyCommandsData = self.config['poly']['drivers'].get(
                driverName, {}).get('commands', {})
            paramParser = ParamParser(driverData, True)
            nodeDesc = driverData.get('description',
                                      utils.name_to_desc(driverName))
            nlsName = utils.name_to_nls(driverName)
            nlsData = [
                self.STATUS_NAME.format(nlsName, 'ST', nodeDesc + ' Online')
            ]
            states = self.write_node_info(polyCommandsData, paramParser,
                                          driverName, nodeDesc, nlsName,
                                          driverData, nlsData)
            ET.SubElement(states, 'st', id='ST', editor='bool')
            # Write sub devices
            for groupName, groupData in driverData.get('commandGroups',
                                                       {}).items():
                polyGroupData = self.config['poly']['commandGroups'].get(
                    groupName)
                if polyGroupData:
                    self.write_node_info(
                        polyCommandsData, paramParser,
                        driverName + '_' + groupName,
                        nodeDesc + ' ' + utils.name_to_desc(groupName),
                        utils.name_to_nls(driverName +
                                          polyGroupData.get('nls', groupName)),
                        groupData)
예제 #5
0
def ISYExport(config, destination, output, input, host, temp):
    configData = yaml.load(config)
    configData['host'] = host

    if input:
        print("Extracting existing resources from", input.name)
        with ZipFile(input) as inputFile:
            inputFile.extractall(destination)

    global curResourceID
    resources = {}
    commands = {}
    maxResourceID = 0
    outputFileName = os.path.join(destination, ISY_CONF_FOLDER, ISY_NET_FOLDER,
        'RES.CFG')
    try:
        with open(outputFileName, 'r') as resourceFile:
            resourceTree = ET.parse(resourceFile).getroot()
            for resource in resourceTree:
                curResourceID = 0
                for id in resource.iter('id'):
                    curResourceID = int(id.text)
                    if maxResourceID < curResourceID:
                        maxResourceID = curResourceID
                for name in resource.iter('name'):
                    resources[name.text] = resource
    except:
        resourceTree = ET.Element('NetConfig')

    print('Found', maxResourceID, 'existing resources')
    curResourceID = maxResourceID + 1

    print("Exporting ISY network resources from", config.name, "to", destination)

    for deviceName, deviceData in configData['devices'].items():
        deviceData.update(configData['drivers'][deviceData['driver']])
        paramParser = ParamParser(deviceData)
        utils.flatten_commands(deviceData)
        for commandName, commandData in deviceData['commands'].items():
            if not commandData.get('result'):
                simpleCommand = True
                resourceName = deviceName + '.' + commandName
                command = deviceName + '/' + commandName
                if commandData.get('acceptsNumber'):
                    print('Create state variable for', resourceName)
                    resourceID = addResource(configData, resources, resourceTree,
                        resourceName)
                    commands[resourceID] = command + STATE_VAR_MESSAGE
                    simpleCommand = False

                if 'value_set' in commandData:
                    for value in paramParser.value_sets[commandData['value_set']].keys():
                        resourceID = addResource(configData, resources,
                            resourceTree, resourceName + '/' + value)
                        commands[resourceID] = command + '/' + value
                    simpleCommand = False

                if simpleCommand:
                    resourceID = addResource(configData, resources, resourceTree,
                        resourceName)
                    commands[resourceID] = command

    outputFileName = os.path.join(destination, ISY_CONF_FOLDER, ISY_NET_FOLDER,
        'RES.CFG')
    if not os.path.exists(os.path.dirname(outputFileName)):
        try:
            os.makedirs(os.path.dirname(outputFileName))
        except OSError as error:
            if error.errno != errno.EEXIST:
                raise

    with ZipFile(os.path.join(destination, output), 'w') as outputFile:

        with open(outputFileName, 'w') as output:
            output.write(ET.tostring(resourceTree).decode())

        # Add main resources file to zip
        outputFile.write(outputFileName,
            os.path.relpath(outputFileName, destination))

        # Add RES files to zip
        for resourceID in range(1, curResourceID):
            command = commands.get(resourceID)
            outputFileName = os.path.join(destination, ISY_CONF_FOLDER,
                ISY_NET_FOLDER, str(resourceID) + '.RES')
            if command:
                with open(outputFileName, 'w') as output:
                    output.write(REQUEST.format(DEFAULT_METHOD, command,
                        configData['host'], configData['port']))

            outputFile.write(outputFileName,
                os.path.relpath(outputFileName, destination))

    if not temp:
        shutil.rmtree(os.path.join(destination, ISY_CONF_FOLDER))
예제 #6
0
class BaseDriver(object):
    def __init__(self, config, logger, use_numeric_key=False):
        self.config = config
        self.use_numeric_key = use_numeric_key
        self.connected = False
        self.logger = logger
        self.configure()

    def configure(self, data=None):
        if data is not None:
            self.config.update(data)

        self.paramParser = ParamParser(self.config, self.use_numeric_key)
        self.connectionDescription = (self.config.get('hostName', '') + ':' +
                                      str(self.config.get('port', 0)))

    def start(self):
        try:
            if not self.connected:
                self.connect()
        except:
            self.logger.exception('Connection to %s failed',
                                  self.connectionDescription)

    def connect(self):
        pass

    def is_connected(self):
        try:
            if not self.connected:
                self.connect()
        except:
            pass

        return self.connected

    def hasCommand(self, commandName):
        return commandName in self.config['commands']

    def getCommand(self, commandName):
        return self.config['commands'].get(commandName)

    def getData(self, commandName, args=None):
        if commandName == 'commands':
            commandList = []
            for commandName, command in self.config['commands'].items():
                commandList.append({
                    'name':
                    commandName,
                    'method':
                    'GET' if command.get('result', False) else 'PUT'
                })
            return {'driver': self.__class__.__name__, 'commands': commandList}

        command = self.config['commands'][commandName]
        if not command.get('result'):
            raise Exception('Invalid command for ' + __name__ +
                            ' and method: ' + commandName)

        result = {
            'driver': self.__class__.__name__,
            'command': commandName,
        }

        try:
            result['output'] = self.sendCommandRaw(commandName, command)
            self.process_result(commandName, command, result)
        except:
            self.connected = False
            raise
        return result

    def sendCommandRaw(self, commandName, command, args=None):
        pass

    def executeCommand(self, commandName, args=None):
        command = self.config['commands'][commandName]

        if args is not None:
            args = self.paramParser.translate_param(command, str(args))

            if command.get('acceptsBool') and type(args) is not bool:
                args = args == 'true' or args == 'on'
            elif command.get('acceptsNumber'):
                args = str(int(args))
            elif command.get('acceptsPct'):
                args = float(args) / 100
            elif command.get('acceptsFloat'):
                args = '{0:g}'.format(float(args))
            elif command.get('acceptsHex'):
                args = hex(int(args))[2:].upper()

        result = {
            'driver': __name__,
            'command': commandName,
        }

        try:
            result['output'] = self.sendCommandRaw(commandName, command, args)
            self.process_result(commandName, command, result)
        except:
            self.connected = False
            raise

        if args is not None:
            result['args'] = args

        return result

    def process_result(self, commandName, command, result):
        output = None
        try:
            if command.get('acceptsNumber'):
                output = int(result['output'])
            elif command.get('acceptsFloat'):
                output = float(result['output'])
            elif command.get('acceptsPct'):
                output = int(float(result['output']) * 100)
            elif command.get('acceptsHex'):
                output = int(result['output'], 16)
            else:
                output = self.paramParser.translate_param(
                    command, result['output'], None, False)
        except:
            pass

        if output is not None:
            result['result'] = output

    @staticmethod
    def processParams(config, param):
        return False

    @staticmethod
    def discoverDevices(config):
        return None
예제 #7
0
class Android(object):

    ACTIVITY_RECORD = 'ActivityRecord'

    def __init__(self, config, logger, use_numeric_key=False):
        self.config = config
        self.executable = config['executable']
        self.logger = logger
        self.paramParser = ParamParser(config, use_numeric_key)
        self.connectStr = self.config['hostName'] + ':' + str(
            self.config['port'])
        self.connected = False
        logger.info('Loaded %s driver', __name__)

    def start(self):
        try:
            self.connect()
        except:
            self.logger.exception('Error connecting to ' + self.connectStr)

    def connect(self):
        self.logger.debug(
            'ADB status %s',
            subprocess.check_output(
                [self.executable, 'connect', self.connectStr]).decode())
        self.logger.debug(
            'ADB status %s',
            subprocess.check_output(
                [self.executable, 'connect', self.connectStr]).decode())
        output = subprocess.check_output([self.executable,
                                          'devices']).decode().split('\n')
        for line in output:
            if line.startswith(self.connectStr):
                if line.split('\t')[1] == 'device':
                    self.connected = True
                    return

        raise IOError('Connection to ' + self.connectStr +
                      ' failed. If device is accessible, try restarting it')

    def is_connected(self):
        return self.connected

    def getData(self, commandName, args=None):
        output = None

        if commandName == 'commands':
            commandList = []
            for commandName, commandData in self.config['commands'].items():
                commandList.append({
                    'name':
                    commandName,
                    'method':
                    'GET' if commandData.get('result') else 'PUT'
                })
            output = {'driver': __name__, 'commands': commandList}
        elif commandName == 'get_app_list':
            output = {
                'driver': __name__,
                'command': 'get_app_list',
                'output': self.getCommandList()
            }
        elif commandName == 'get_current_activity':
            output = {
                'driver': __name__,
                'command': 'get_current_activity',
                'output': self.getCurrentActivity()
            }

        if output:
            output['result'] = self.paramParser.translate_param(
                self.config['commands'][commandName], output['output'], '')

            return output

        raise Exception('Invalid command for ' + __name__ + ': ' + commandName)

    def executeCommand(self, commandName, args=None):
        if not self.connected:
            self.connect()

        if commandName == 'start_app':
            args = self.paramParser.translate_param(
                self.config['commands'][commandName], args)
            output = subprocess.check_output(
                [self.executable, 'shell', 'am', 'start', '-n',
                 args]).decode()
        else:
            output = subprocess.check_output([
                self.executable, 'shell', 'input', 'keyevent',
                str(self.config['commands'][commandName]['code'])
            ]).decode()

        result = {'driver': __name__, 'command': commandName, 'output': output}

        if args:
            result['args'] = args

        return result

    def process_result(self, commandName, command, result):
        if 'argKey' in command:
            param = result['output']['payload'][command['argKey']]
            result['result'] = self.paramParser.translate_param(command, param)

    def getCurrentActivity(self):
        output = subprocess.check_output(
            [self.executable, 'shell', 'dumpsys', 'window',
             'windows']).decode().split('\n')
        for line in output:
            pos = line.find('mFocusedApp')
            if pos > 0:
                pos = line.find(Android.ACTIVITY_RECORD)
                if pos > 0:
                    values = line[pos +
                                  len(Android.ACTIVITY_RECORD):].split(' ')
                    return values[2].split('/')[0]

        return ''

    def getCommandList(self):
        if not self.connected:
            self.connect()

        output = subprocess.check_output(
            [self.executable, 'shell', 'pm', 'list', 'packages',
             '-f']).decode().split('\n')
        appList = []
        for line in output:
            pos = line.find('=')
            if pos > 0:
                appList.append({'appName': line[pos + 1:], 'activity': []})

        for appInfo in appList:
            self.logger.debug("Processing %s app", appInfo['appName'])
            output = subprocess.check_output(
                [self.executable, 'shell', 'pm', 'dump',
                 appInfo['appName']]).decode().split('\n')
            for index, line in enumerate(output):
                if line.find('MAIN') > 0:
                    activityLine = output[index - 1]
                    pos = activityLine.find(appInfo['appName'] + '/')
                    if pos > 0:
                        appInfo['activity'].append(
                            activityLine[activityLine.find('/', pos) +
                                         1:activityLine.find(' ', pos)])

        return appList
예제 #8
0
class WebOS(WebSocketClient):
    def __init__(self, config, logger, use_numeric_key=False):
        super(WebOS, self).__init__("ws://" + config['hostName'] + ':' +
                                    str(config['port']),
                                    exclude_headers=["Origin"])
        self.config = config
        self.connected = False
        self.connectEvent = Event()
        self.curID = 0
        self.callbacks = {}
        self.clientKey = None
        self.logger = logger
        self.paramParser = ParamParser(config, use_numeric_key)
        try:
            with open(config['clientKeyFile'], 'r') as clientKeyInput:
                self.clientKey = yaml.load(clientKeyInput)
        except:
            pass

        try:
            with open(config['macFile'], 'r') as macInput:
                self.config.update(yaml.load(macInput))
        except:
            pass

        self.sock.settimeout(5)
        try:
            self.connect()
        except:
            logger.debug('Websocket timeout. Possibly device is off')

        logger.info('Loaded %s driver', __name__)

    def start(self):
        pass

    def saveClientKey(self):
        with open(self.config['clientKeyFile'], 'w') as clientKeyOutput:
            yaml.safe_dump(self.clientKey,
                           clientKeyOutput,
                           allow_unicode=True,
                           encoding='utf-8')
            clientKeyOutput.close()

    def opened(self):
        self.connected = True
        if self.clientKey:
            self.config['registerCommand'].update(self.clientKey)
        self.sendCommand('register', 'register', None,
                         self.config['registerCommand'], False)

    def closed(self, code, reason=None):
        self.connected = False
        self.connectEvent.clear()
        self.logger.warn('LG TV Connection closed %s, %s', code, reason)

    def received_message(self, data):
        message = json.loads(str(data))
        if message['id'] == 'register0':
            if message['type'] == 'error':
                self.logger.error('Connection issue %s', message['error'])
            elif message['type'] == 'registered':
                if not self.clientKey:
                    self.clientKey = message['payload']
                    self.saveClientKey()
                self.connectEvent.set()
        callback = self.callbacks.get(message['id'])
        if callback:
            callback['data'] = message
            callback['event'].set()

    def is_connected(self):
        if not self.connected:
            try:
                self.connect()
                self.connectEvent.wait(self.config['timeout'] if self.clientKey
                                       else self.config['promptTimeout'])
            except:
                pass

        return self.connected

    def sendCommand(self, prefix, type, uri, payload=None, shouldWait=True):
        if not self.connected:
            try:
                self.connect()
                self.connectEvent.wait(self.config['timeout'] if self.clientKey
                                       else self.config['promptTimeout'])
            except:
                raise Exception('Driver ' + __name__ +
                                ' cannot connect to device')

        id = prefix + str(self.curID)
        message = {'type': type, 'id': id}

        if payload:
            message['payload'] = payload

        if uri:
            message['uri'] = 'ssap://' + uri

        self.send(json.dumps(message))
        self.curID += 1
        event = Event()
        callback = {'event': event, 'data': {}}

        self.callbacks[id] = callback

        if shouldWait:
            event.wait(self.config['timeout'])
            return callback['data']

        return ''

    def getData(self, commandName, args=None):
        if commandName == 'commands':
            commandList = []
            for commandName, command in self.config['commands'].items():
                commandList.append({
                    'name':
                    commandName,
                    'method':
                    'GET' if command.get('result', False) else 'PUT'
                })
            return {'driver': __name__, 'commands': commandList}

        command = self.config['commands'][commandName]
        if not command.get('result'):
            raise Exception('Invalid command for ' + __name__ +
                            ' and method: ' + commandName)

        result = {
            'driver': __name__,
            'command': commandName,
            'output': self.sendCommand('', 'request', command['uri'])
        }

        self.process_result(commandName, command, result)

        return result

    def executeCommand(self, commandName, args=None):
        if commandName == 'toggle_mute':
            output = self.getData('status')

            if 'error' in output['output']:
                return output

            return self.executeCommand(
                'mute', 'off' if output['output']['payload']['mute'] else 'on')
        elif commandName == 'power_on':
            self.logger.debug('Sending wake up command to %s',
                              self.config['mac'])
            wakeonlan.send_magic_packet(self.config['mac'])
            return {'driver': __name__, 'command': commandName, 'output': ''}

        command = self.config['commands'][commandName]
        if command.get('result'):
            raise Exception('Invalid command for ' + __name__ +
                            ' and method: ' + commandName)

        argKey = command.get('argKey')
        argData = None
        if args:
            if not argKey:
                raise Exception('Command in ' + __name__ + ': ' + commandName +
                                ' isn'
                                't configured for arguments')

            args = self.paramParser.translate_param(command, args)

            argData = {argKey: args}

            if command.get('acceptsBool') and type(args) is not bool:
                argData[argKey] = args == 'true' or args == 'on'
            elif command.get('acceptsNumber'):
                try:
                    argData[argKey] = int(args)
                except ValueError:
                    pass
        elif argKey:
            raise Exception('Command in ' + __name__ + ': ' + commandName +
                            ' expects for arguments')

        result = {
            'driver': __name__,
            'command': commandName,
            'output': self.sendCommand('', 'request', command['uri'], argData),
            'args': argData
        }

        return result

    def process_result(self, commandName, command, result):
        if 'argKey' in command:
            param = result['output']['payload'][command['argKey']]
            result['result'] = self.paramParser.translate_param(command, param)
예제 #9
0
    def __init__(self, config, logger, use_numeric_key=False):
        self.config = config
        self.logger = logger
        self.paramParser = ParamParser(config, use_numeric_key)

        logger.info('Loaded %s driver', __name__)
예제 #10
0
class TivoIP(object):
    def __init__(self, config, logger, use_numeric_key=False):
        self.config = config
        self.logger = logger
        self.paramParser = ParamParser(config, use_numeric_key)

        logger.info('Loaded %s driver', __name__)

    def start(self):
        pass

    def getData(self, commandName, args=None):
        if commandName == 'commands':
            commandList = []
            for commandName in self.config['commands'].keys():
                commandList.append({'name': commandName, 'method': 'PUT'})

            return {'driver': __name__, 'commands': commandList}

        raise Exception('Invalid command for ' + __name__ + ': ' + commandName)

    def is_connected(self):
        try:
            conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            conn.connect((self.config['hostName'], self.config['port']))
            conn.settimeout(self.config['timeout'])
            conn.close()
            return True
        except:
            pass

        return False

    def sendCommand(self, command, args=None):
        result = ''
        conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            conn.connect((self.config['hostName'], self.config['port']))
            conn.settimeout(self.config['timeout'])
            conn.send(command['code'].encode())
            if (command.get('argument') or 'value_set' in command) and args:
                conn.send(
                    self.paramParser.translate_param(command, args).encode())
            conn.send('\r\n'.encode())
            if command.get('response', False):
                result = conn.recv(1024).decode()
            delay = command.get('delay')
            if delay:
                time.sleep(delay)
        except socket.timeout:
            pass
        conn.close()
        return result

    def executeCommand(self, commandName, args=None):
        self.logger.debug('Driver %s executing command %s', __name__,
                          commandName)
        output = []
        command = self.config['commands'][commandName]
        if 'commands' in command:
            for item in command['commands']:
                output.append(self.sendCommand(item, args))
        else:
            output.append(self.sendCommand(command, args))

        result = {'driver': __name__, 'command': commandName, 'output': output}

        if args:
            result['args'] = args

        return result