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'
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))
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.')
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
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)
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)
# 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: