Пример #1
0
    def __init__(self, configNode):
        """    Configuration of an object in Linknx. """

        self.id = configNode.getAttribute('id')
        self.xml = configNode
        self.type = configNode.getAttribute('type')
        self.gad = configNode.getAttribute('gad')
        # self.callback = configNode.getAttribute('pyknxcallback')
        self.init = configNode.getAttribute('init') if configNode.hasAttribute(
            'init') else 'request'
        self.flags = configNode.getAttribute(
            'flags') if configNode.hasAttribute('flags') else 'cwtu'
        self.caption = ObjectConfig.getTextInElement(
            configNode, mustFind=False).strip('\n\t ')
        firstTypeDigit = self.type[0:self.type.find('.')]
        if firstTypeDigit == '1':
            self.typeCategory = 'bool'
        elif firstTypeDigit in ['5', '6', '7', '8', '9', '12', '13', '29']:
            if self.type in ('5.001', '5.003') or firstTypeDigit == '9':
                self.typeCategory = 'float'
            else:
                self.typeCategory = 'int'
        elif firstTypeDigit == '14':
            self.typeCategory = 'float'
        elif firstTypeDigit in ('4', '16', '28'):
            self.typeCategory = 'string'
        elif firstTypeDigit == '10':
            self.typeCategory = 'time'
        elif firstTypeDigit == '11':
            self.typeCategory = 'date'
        else:
            logger.reportWarning('Object ' + self.id +
                                 ' has an unsupported type ' + self.type)
            self.typeCategory = 'unknown'
Пример #2
0
    def addCallbackForObject(self, objectId, callbackName,
                             callbackDestination):
        if objectId == None or objectId == '':
            logger.reportWarning(
                '{0} is not defined, skipping callback.'.format(
                    callbackDestination))
            return

        # Search object in config.
        found = False
        callbackAttributeName = self.callbackAttributeName

        for objectXmlConfig in self.config.getElementsByTagName('object'):
            if objectXmlConfig.getAttribute('id') == objectId:
                if found:
                    raise Exception(
                        'Two objects with id {id} found.'.format(id=objectId))
                found = True
                objectXmlConfig.setAttribute(callbackAttributeName,
                                             callbackName)
                logger.reportInfo('Added callback {0} for {1}'.format(
                    callbackName, objectId))
        if not found:
            raise Exception(
                'Object {id} not found in linknx configuration'.format(
                    id=objectId))
Пример #3
0
 def _executeUserCallback(self, callbackName, context, isOptional=False):
     try:
         if hasattr(self._userModule, callbackName):
             logger.reportDebug('Calling user callback {0} with context {1}'.format(callbackName, context))
             callback = getattr(self._userModule, callbackName)
             res = callback(context)
             logger.reportDebug('Callback {0} returned {1}'.format(callbackName, res))
             return res
         else:
             message='No function {0} defined in {1}'.format(callbackName, self._userFile)
             if isOptional:
                 logger.reportInfo(message + ', skipping')
             else:
                 logger.reportWarning(message)
     except Exception as e:
         logger.reportException('User code execution failed.')
Пример #4
0
    def __init__(self, communicator, args={}):
        # if not args is None and args.has_key('objectId'):
            # self._object = linknx.getObject(args['objectId'])
        # else:
            # self._object = None
        self._communicator = communicator
        self._args = args

        # Create members for easy access.
        if args != None:
            exp = re.compile('[^0-9a-zA-Z_]')
            for argName, argValue in args.items():
                # Rename args to comply with Python naming rules.
                changedName = re.sub(exp, '_', argName)
                if changedName != argName:
                    logger.reportWarning('Argument {0} renamed to {1} to comply with naming rules.'.format(argName, changedName))

                # Create argument.
                vars(self)[changedName] = argValue

        if 'objectId' in vars(self):
            self._object = self.linknx.getObject(self.objectId)
        else:
            self._object = None
Пример #5
0
def handleRequest(requestType, doc):
    logger.initLogger(None, logging.INFO, usesDetailedLogging=False)

    parser = argparse.ArgumentParser(description=doc)
    parser.add_argument(
        '-s',
        '--server',
        dest='host',
        help=
        'Hostname of the machine running the linknx daemon. Default is localhost.',
        default='localhost')
    parser.add_argument('-p',
                        '--port',
                        dest='port',
                        help='Port linknx listens on. Default is 1028.',
                        default=1028)
    if requestType == 'read':
        parser.add_argument(
            'objectIds',
            help='ID represents the identifier of the object to read.',
            metavar='ID',
            nargs='+')
        parser.add_argument(
            '-R',
            '--regex',
            action='store_true',
            help=
            'ID in the "object" argument is interpreted as a regex and used to find objects to read. The pattern must comply with the \'re\' python module.'
        )
        parser.add_argument(
            '--value-only',
            action='store_true',
            help=
            'Output the value of the queried object but do not prefix it with the object\'s id.'
        )
        parser.add_argument(
            '--expected-value',
            help=
            'Expected value of the object. This script will exit with a non-zero return code if the value is not the expected one. This is useful when using this script in a "if" test of a shell script.'
        )
    elif requestType == 'write':
        parser.add_argument(
            'object',
            help='ID represents the identifier of the object to write to.',
            metavar='ID')
        parser.add_argument(
            'value',
            help='Assigns VALUE to the object identified by ID.',
            metavar='VALUE')
    elif requestType == 'execute':
        parser.add_argument(
            '--action',
            help=
            'use the ACTION string as the XML representation of the action to execute rather than reading it from standard input.',
            metavar='ACTION')
    else:
        raise Exception('Unsupported request type "{0}".'.format(requestType))
    parser.add_argument(
        '-v',
        '--verbose',
        dest='verbosityLevel',
        help='Set verbosity level. Default is "error".',
        metavar='LEVEL',
        choices=[l.lower() for l in logger.getLevelsToString()],
        default='error')
    args = parser.parse_args()

    # Configure logger.
    logger.initLogger(None, args.verbosityLevel.upper())

    # Start linknx.
    linknx = Linknx(args.host, int(args.port))
    try:
        if requestType == 'read':
            objects = linknx.getObjects(
                objectIds=args.objectIds
            ) if not args.regex else linknx.getObjects(patterns=args.objectIds)

            # No object.
            if not objects:
                logger.reportWarning('No such object.')
                sys.exit(10)

            # Count tabs to align columns.
            report = objects.getValues()
            longestId = max([len(obj) for obj in report.keys()])
            succeeds = True
            for o in sorted(report):
                v = report[o]
                spaceCount = longestId - len(o)
                spaces = ''
                while spaceCount > 0:
                    spaces += ' '
                    spaceCount -= 1
                if args.value_only:
                    print('{0}'.format(v))
                else:
                    print('{0} {2} {1}'.format(o, v, spaces))

                if args.expected_value != None:
                    obj = linknx.getObject(o)
                    convertedExpectedValue = obj.convertValueToString(
                        args.expected_value)
                    convertedObjectValue = obj.convertValueToString(v)
                    succeeds = succeeds and convertedExpectedValue == convertedObjectValue

            if not succeeds: exit(100)

        elif requestType == 'write':
            linknx.getObject(args.object).value = args.value
        elif requestType == 'execute':
            if args.action == None:
                action = ''.join(sys.stdin.readlines())
            else:
                action = args.action
            linknx.executeAction(action)
        else:
            raise Exception('Unsupported request type.')

    except Exception as e:
        logger.reportException()
        sys.exit(3)
Пример #6
0
    def generateConfig(self):
        # Read xml to get pyknx special attributes.
        config = self.config
        doc = config.ownerDocument
        rulesNode = self._getOrAddConfigElement(config, 'rules')

        # Generate a rule for each object that has a callback in the user file.
        objectNodes = config.getElementsByTagName('objects')[0]
        configuredAtLeastOne = False
        definesLegacyCallbackAttribute = False
        callbackAttributeName = self.callbackAttributeName
        for objectNode in objectNodes.getElementsByTagName('object'):
            objectConfig = ObjectConfig(objectNode)
            objectId = objectConfig.id
            callback = objectNode.getAttribute(callbackAttributeName)
            if callback == None or callback == '':
                if objectNode.getAttribute('pyknxcallback'):
                    logger.reportError('pyknxcallback found on {0}'.format(objectNode.toxml()))
                    definesLegacyCallbackAttribute = True
                logger.reportDebug('No callback found for object ' + objectConfig.id + ' (no {0} attribute for this object)'.format(callbackAttributeName))
                continue

            configuredAtLeastOne = True
            ruleNode = doc.createElement('rule')
            ruleId = '{0}{1}'.format(self._communicatorName, objectId)
            logger.reportInfo('Generating rule {0}'.format(ruleId))
            ruleNode.setAttribute('id', ruleId)
            ruleNode.setAttribute('init', 'false')
            conditionNode = doc.createElement('condition')
            conditionNode.setAttribute('type', 'object')
            conditionNode.setAttribute('id', objectId)
            # conditionNode.setAttribute('value', objectConfig.defaultValue)
            conditionNode.setAttribute('trigger', 'true')
            ruleNode.appendChild(conditionNode)
            actionListNode = doc.createElement('actionlist')
            actionListNode.setAttribute('type', 'if-true')
            ruleNode.appendChild(actionListNode)
            actionNode = self.createActionNode(callback, {'objectId' : objectId})
            actionListNode.appendChild(actionNode)
            # actionListIfFalseNode = actionListNode.cloneNode(True)
            # actionListIfFalseNode.setAttribute('type', 'on-false')
            # # ruleNode.appendChild(actionListIfFalseNode)
            rulesNode.appendChild(ruleNode)

        if not configuredAtLeastOne:
            logger.reportInfo('Nothing to do. None of the objects does define a callback attribute.')
            if definesLegacyCallbackAttribute:
                logger.reportWarning('There is at least one pyknxcallback attribute in the config file. These attributes were recognized by Pyknx before version 2.2. Did you forget to rename them to {0}?'.format(callbackAttributeName))
        else:
            # Add an ioport service for the communicator.
            servicesNode = self._getOrAddConfigElement(config, 'services')
            ioportsNode = self._getOrAddConfigElement(servicesNode, 'ioports')
            ioportNode = doc.createElement('ioport')
            ioportNode.setAttribute('id', self._communicatorName)
            try:
                hostIP = socket.gethostbyname(self._address[0])
            except:
                logger.reportWarning('Could not check that {0} is a valid ip address. Please check the output configuration. Linknx does not support hostnames, it requires IP address.'.format(self._address[0]))
                hostIP = self._address[0]
            ioportNode.setAttribute('host', hostIP) #gethostbyname converts the hostname into an ip. Linknx does not support ioport hostnames.
            ioportNode.setAttribute('port', str(self._address[1]))
            ioportNode.setAttribute('type', 'tcp')
            ioportsNode.appendChild(ioportNode)
Пример #7
0
    # Start linknx.
    linknx = Linknx(host, int(port))
    try:
        if reads:
            report = {}
            if not isRegex:
                for objId in objectIds:
                    report[objId] = linknx.getObject(objId).value
            else:
                for obj in linknx.getObjects(objectIds[0]):
                    report[obj.id] = obj.value

            # No object.
            if not report:
                logger.reportWarning('No object of given id.')
                sys.exit(10)

            # Count tabs to align columns.
            longestId = max([len(id) for id in report.keys()])
            for o, v in report.items():
                spaceCount = longestId - len(o)
                spaces = ''
                while spaceCount > 0:
                    spaces += ' '
                    spaceCount -= 1
                print('{0} {2} {1}'.format(o, v, spaces))
        elif writes:
            linknx.getObject(objectIds[0]).value = valueToWrite
    except Exception as e:
        if verbosity == logging.DEBUG: