def sendEventWrapper(self, type, id, data, deviceAttributes=None): device = '%s-%s' % (type,id) config = self.devices.get(device) if not deviceAttributes: deviceAttributes = {} if config: if config.get('suppress'): log.debug('Config says suppress event: %s' % device) return if config.get('id'): device = config.get('id') if config.get('name'): deviceAttributes['name'] = config.get('name') if config.get('location'): deviceAttributes['location'] = config.get('location') # todo: infer these from telldus types instead (done for sensor, todo for device) if not deviceAttributes.get('type') and config.get('type'): deviceAttributes['type'] = config.get('type') if not deviceAttributes.get('type') and type == 'device': deviceAttributes['type'] = 'lamp' elif self.suppressUnconfigured: return deviceAttributes['device'] = device self.sendEvent('change', data, deviceAttributes)
def close(self, closeConnection=False): if self.ch: if self.consumeKeys: for key in self.consumeKeys: try: self.ch.queue_unbind(self.queueName, self.exchange, key) except Exception as e: # don't pollute log if is not found isNotFound = False try: if e.args[0] == 404: isNotFound = True except: pass if not isNotFound: log.info( 'Ignore fail to unbind queue %s from %s for %s: %s' % (self.queueName, self.exchange, key, e)) try: self.ch.queue_delete(queue=self.queueName) except Exception as e: log.debug('Ignore fail to delete queue: %s' % e) try: self.ch.close() except Exception as e: log.info('Ignore fail to close channel object: %s' % e) self.ch = None if self.conn: if closeConnection: try: self.conn.close() except Exception as e: log.info('Ignore fail to close connection: %s' % e)
def close(self, closeConnection=False): if self.ch: if self.consumeKeys: for key in self.consumeKeys: try: self.ch.queue_unbind(self.queueName, self.exchange, key) except Exception as e: # don't pollute log if is not found isNotFound = False try: if e.args[0] == 404: isNotFound = True except: pass if not isNotFound: log.info('Ignore fail to unbind queue %s from %s for %s: %s' % (self.queueName, self.exchange, key, e)) try: self.ch.queue_delete(queue=self.queueName) except Exception as e: log.debug('Ignore fail to delete queue: %s' % e) try: self.ch.close() except Exception as e: log.info('Ignore fail to close channel object: %s' % e) self.ch = None if self.conn: if closeConnection: try: self.conn.close() except Exception as e: log.info('Ignore fail to close connection: %s' % e)
def call(self, key, data=None, timeout=5, block=None): log.debug('RPC-CALL: execute %s = %s' % (key, data)) if block is None: block = True # @todo: remove consume again afterwards! if not timeout: # tuba - no_ack=True is also an option self.consumerTag = self.ch.basic_consume(self.queue, callback=self._callback) self.response = None self.correlationId = getUuid() # str(uuid.uuid4()) msg = amqp.Message( json.encode(data), content_type='text/json', correlation_id=self.correlationId, # reply_to = self.queue ) self.ch.basic_publish( msg, self.exchange, key, # reply_to = self.queue, # correlation_id = self.correlationId ) if not block: return log.notice('RPC-CALL: wait response') startTime = time.time() while self.response is None: if timeout: msg = self.ch.basic_get(self.queue) if msg: if self._callback(msg): break else: time.sleep(0.01) if (time.time() - startTime) >= timeout: raise TimeoutException('Waited %s sec for rpc call %s' % (timeout, key)) else: self.ch.wait() log.notice('RPC-CALL: finished waiting') try: body = json.decode(self.response.body) except Exception as e: raise Exception("json decoding error: %s - for raw response: %s" % (e, self.response.body)) tmp = self.response.routing_key.split('.') if tmp[0][1] == 'x': # todo: use constants if tmp[0][0] == 'o': d = 'orchestrator' # here too elif tmp[0][0] == 's': d = 'service' elif tmp[0][0] == 'r': d = 'reactor' elif tmp[0][0] == 'm': d = 'manager' e = RemoteException('Error in %s %s when calling %s' % (d,tmp[1],tmp[2])) e.setResponse(body) raise e log.debug('RPC-CALL: respone %s = %s' % (self.response.routing_key, body)) return body
def sendEventWrapper(self, type, id, data, deviceAttributes=None): device = '%s-%s' % (type, id) config = self.devices.get(device) if not deviceAttributes: deviceAttributes = {} if config: if config.get('suppress'): log.debug('Config says suppress event: %s' % device) return if config.get('id'): device = config.get('id') if config.get('name'): deviceAttributes['name'] = config.get('name') if config.get('location'): deviceAttributes['location'] = config.get('location') # todo: infer these from telldus types instead (done for sensor, todo for device) if not deviceAttributes.get('type') and config.get('type'): deviceAttributes['type'] = config.get('type') if not deviceAttributes.get('type') and type == 'device': deviceAttributes['type'] = 'lamp' elif self.suppressUnconfigured: return deviceAttributes['device'] = device self.sendEvent('change', data, deviceAttributes)
def ping(self, host): cmd = [self.pingBinary, '-c', '%s' % self.count, '-w', '%s' % self.timeout, '-n', host] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() ec = proc.wait() if ec == 0: log.debug('ping up (%s): %s : %s' % (ec, host, cmd)) return True else: log.debug('ping down (%s): %s : %s' % (ec, host, cmd)) return False
def onStart(self): while not self._shutdown: now = time.time() for plot in self.plots: if plot.isDue(): value = self.getPlotValue(plot) log.info('Plot %s = %s @ %s' % (plot.id, value, now)) plot.plot(value, now) else: log.debug('Plot %s is not due yet @ %s' % (plot.id, now)) time.sleep(self.interval)
def onMessage(self, topic, data, correlationId): self.aggregated['total_messages'] += 1 if topic.startswith('se.') and not topic.endswith('.online'): # aggregation: update the total number of events from this service and class cursrv = topic.split('.')[1] if cursrv in self.aggregated['service_events']: self.aggregated['service_events'][cursrv] += 1 else: self.aggregated['service_events'][cursrv] = 1 if 'class' in data: if data['class'] in self.aggregated['class_events']: self.aggregated['class_events'][data['class']] += 1 else: self.aggregated['class_events'][data['class']] = 1 # Ignore is in config ignoreclasses or ignore is set for the service if 'class' in data: if data['class'] in self.ignoreclasses: return if 'ignore' in data: if data['ignore'] in [True, 'True', 'true', 'Yes', 'yes', 'y']: return # start picking out data to report measures = [] tags = {} for tag in data: if tag in self.known_tags: if tag == 'key': tags.update({'event': data[tag]}) else: tagValue = data[tag] if type(tagValue) == types.UnicodeType: tagValue = tagValue.encode('utf-8') tags.update({tag: tagValue}) for measure in data['data']: if 'value' in data['data'][measure]: curval = data['data'][measure]['value'] if isinstance(curval, numbers.Number): measures.append(self.ix.data_template(measure, tags, {'value': curval})) # log.info('field: %s: %s' % (measure, str(curval))) # log.info('tags: %s' % str(tags)) elif curval in [True, 'True', 'true', 'On', 'on', 'Yes', 'yes']: measures.append(self.ix.data_template(measure, tags, {'value': True})) elif curval in [False, 'False', 'false', 'Off', 'off', 'No', 'no']: measures.append(self.ix.data_template(measure, tags, {'value': False})) else: # log.info('Skipping because value is not a number:') # log.info("topic: " + str(topic)) # log.info("data: " + str(data)) pass log.debug('insert measures: %s' % measures) try: self.ix.insert(measures) except Exception, e: log.error('Failed inserting measures in influxdb: %s\nAttempted insert was: %s' % (utils.e2str(e), measures))
def sendActionError(self, key, data, correlationId=None): if isinstance(data, Exception): resp = {'errorMessage': data.message, 'errorDetails': utils.e2str(data), 'remoteError': None} if isinstance(data, RemoteException): resp['remoteError'] = data.getResponse() else: resp = data resp['error'] = True resp['source'] = '%s.%s.%s' % (self.type, self.id, key) topic = '%s.%s.%s' % (self.getActionErrorPrefix(), self.id, key) log.debug('sendActionError: %s = %s' % (topic, resp)) self.producer.put(topic, resp, correlationId)
def handleDaemonItem(self, type, id): # If item is already offline, do nothing - but (re)start if applicable item = self.orchestrator.data[type][id] if item['online'] == False: if type == 'service': if not item.has_key('offlineTimer'): item['offlineTimer'] = time.time() if item['main'].get('autostart'): if item.get('manuallyStopped'): log.debug('Do not auto-start service %s since manually stopped' % id) else: timeSinceOffline = time.time() - item['offlineTimer'] if timeSinceOffline > self.orchestrator.startInterval: self.orchestrator.data[type][id]['offlineTimer'] = time.time() try: #self.orchestrator.action_startService(id) serviceId, managerId = self.orchestrator.parseServiceParam(id) if self.orchestrator.isOnline('manager', managerId): log.info('Auto-start service %s @ %s after %s secs offline' % (serviceId, managerId, timeSinceOffline)) self.orchestrator.startService(managerId, serviceId) else: log.debug('Do not auto-start service %s since manager %s is offline' % (id,managerId)) except Exception, e: log.error('Error trying to autostart service %s: %s' % (id,e)) else: log.debug('Do not auto-start service %s since %s secs offline is less than startinterval %s' % (id,timeSinceOffline,self.orchestrator.startInterval)) else: log.debug('Do not auto-start service %s since autostart not set in config' % (id,))
def call(self, key, data=None, timeout=5, block=None): log.debug('RPC-CALL: execute %s = %s' % (key, data)) if block == None: block = True # @todo: remove consume again afterwards! if not timeout: # tuba - no_ack=True is also an option self.consumerTag = self.ch.basic_consume(self.queue, callback=self._callback) self.response = None self.correlationId = getUuid() #str(uuid.uuid4()) msg = amqp.Message( json.encode(data), content_type='text/json', correlation_id = self.correlationId, #reply_to = self.queue ) self.ch.basic_publish( msg, self.exchange, key, #reply_to = self.queue, #correlation_id = self.correlationId ) if not block: return log.notice('RPC-CALL: wait response') startTime = time.time() while self.response is None: if timeout: msg = self.ch.basic_get(self.queue) if msg: if self._callback(msg): break else: time.sleep(0.01) if (time.time()-startTime) >= timeout: raise TimeoutException('Waited %s sec for rpc call %s' % (timeout, key)) else: self.ch.wait() log.notice('RPC-CALL: finished waiting') try: body = json.decode(self.response.body) except Exception, e: raise Exception("json decoding error: %s - for raw response: %s" % (e, self.response.body))
def shutdown(self): if self._shutdown: log.info('Not shutting down (again) since shutdown already in progress') return log.info('Shutting down') self._shutdown = True try: self.sendShutdownAction() log.debug('Added _shutdown action to queue. Waiting for shutdown') # todo: investigate this. possibly switch amqp lib? except AttributeError: # AttributeError: 'NoneType' object has no attribute 'method_writer' # This happens sometimes and is probably because of a bug in amqplib? # Hopefully it means that channel is already shut down? log.info('Ignoring AttributeError about no method_writer, caused by bug in amqplib(?)')
def sendActionError(self, key, data, correlationId=None): if isinstance(data, Exception): resp = { 'errorMessage': data.message, 'errorDetails': utils.e2str(data), 'remoteError': None } if isinstance(data, RemoteException): resp['remoteError'] = data.getResponse() else: resp = data resp['error'] = True resp['source'] = '%s.%s.%s' % (self.type, self.id, key) topic = '%s.%s.%s' % (self.getActionErrorPrefix(), self.id, key) log.debug('sendActionError: %s = %s' % (topic, resp)) self.producer.put(topic, resp, correlationId)
def ping(self, host): cmd = [ self.pingBinary, '-c', '%s' % self.count, '-w', '%s' % self.timeout, '-n', host ] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() ec = proc.wait() if ec == 0: log.debug('ping up (%s): %s : %s' % (ec, host, cmd)) return True else: log.debug('ping down (%s): %s : %s' % (ec, host, cmd)) return False
def shutdown(self): if self._shutdown: log.info( 'Not shutting down (again) since shutdown already in progress') return log.info('Shutting down') self._shutdown = True try: self.sendShutdownAction() log.debug('Added _shutdown action to queue. Waiting for shutdown') # todo: investigate this. possibly switch amqp lib? except AttributeError: # AttributeError: 'NoneType' object has no attribute 'method_writer' # This happens sometimes and is probably because of a bug in amqplib? # Hopefully it means that channel is already shut down? log.info( 'Ignoring AttributeError about no method_writer, caused by bug in amqplib(?)' )
def runAction(self, cmd, args): if cmd == 'setOutput': # arg 1 is f.ex. o2, we only want 2, as an int, not a string args[0] = int(args[0][1:]) # arg 2 is 0 or 1, as int. but be forgiving (bint) if len(args) < 2: args.append(0) args[1] = bint(args[1]) #log.info("setOutput ARGS: %s" % (args,)) res = self.dev.setOutputState(args[0], args[1]) log.debug("ifkit.setOutputState: %s, %s = %s" % (args[0], args[1], res)) else: if cmd in self.pmethods: args2 = [] for a in args: try: a = int(a) except: pass args2.append(a) fun = getattr(self.dev, cmd) if fun: return fun(*args2) raise Exception('Unknown command: %s' % cmd)
def getPlotValue(self, plot): reactorId = self.config.get('reactor') #'skallemann' # todo: config, with sensible default (ie. same host or get auto if one) source = plot.source.split('.') service = source.pop(0) key = source.pop(0) stateKey = '%s.%s.data.%s' % (service, key, '.'.join(source)) log.debug("getPlotValue.RPC request: ra.%s.getState( %s )" % (reactorId, stateKey)) conn = amqp.Connection() rpc = conn.rpc() result = rpc.call('ra.%s.getState' % reactorId, [stateKey]) log.debug("getPlotValue.RPC result: %s" % (result,)) if not result: return 0 return float(result)
def getPlotValue(self, plot): reactorId = self.config.get( 'reactor' ) #'skallemann' # todo: config, with sensible default (ie. same host or get auto if one) source = plot.source.split('.') service = source.pop(0) key = source.pop(0) stateKey = '%s.%s.data.%s' % (service, key, '.'.join(source)) log.debug("getPlotValue.RPC request: ra.%s.getState( %s )" % (reactorId, stateKey)) conn = amqp.Connection() rpc = conn.rpc() result = rpc.call('ra.%s.getState' % reactorId, [stateKey]) log.debug("getPlotValue.RPC result: %s" % (result, )) if not result: return 0 return float(result)
def getBluetoothServices(self): log.debug('Getting bluetooth services') result = [] if self.config.getBool('discover'): log.debug('Using services_discover() to find services') try: for addr in bluetooth.discover_services(flush_cache=True): log.debug('Found service: %s' % addr) result.append(addr) # This happens from time to time, and we don't want to die because of it: # BluetoothError: error communicating with local bluetooth adapter except bluetooth.btcommon.BluetoothError,e: log.warn('BluetoothError ignored: %s' % e)
def getBluetoothServices(self): log.debug('Getting bluetooth services') result = [] if self.config.getBool('discover'): log.debug('Using services_discover() to find services') try: for addr in bluetooth.discover_services(flush_cache=True): log.debug('Found service: %s' % addr) result.append(addr) # This happens from time to time, and we don't want to die because of it: # BluetoothError: error communicating with local bluetooth adapter except bluetooth.btcommon.BluetoothError, e: log.warn('BluetoothError ignored: %s' % e)
def onDetach(self, e): log.debug("InterfaceKit attached: %i" % (e.service.getSerialNum())) self.sendEvent('status', {'value': 'detached'}) return 0
def getBluetoothServices(self): log.debug('Getting bluetooth services') result = [] if self.config.getBool('discover'): log.debug('Using services_discover() to find services') try: for addr in bluetooth.discover_services(flush_cache=True): log.debug('Found service: %s' % addr) result.append(addr) # This happens from time to time, and we don't want to die because of it: # BluetoothError: error communicating with local bluetooth adapter except bluetooth.btcommon.BluetoothError,e: log.warn('BluetoothError ignored: %s' % e) else: log.debug('Not configured to use services_discover() to find services') if self.config.getBool('lookup'): log.debug('Using lookup_name() to find services') try: for addr in self.guests: name = bluetooth.lookup_name(addr) if name: log.debug('Found service: %s' % addr) result.append(addr) else: log.debug('Did not find service: %s' % addr) # This happens from time to time, and we don't want to die because of it: # BluetoothError: error communicating with local bluetooth adapter except bluetooth.btcommon.BluetoothError,e: log.warn('BluetoothError ignored: %s' % e)
def getBluetoothServices(self): log.debug('Getting bluetooth services') result = [] if self.config.getBool('discover'): log.debug('Using services_discover() to find services') try: for addr in bluetooth.discover_services(flush_cache=True): log.debug('Found service: %s' % addr) result.append(addr) # This happens from time to time, and we don't want to die because of it: # BluetoothError: error communicating with local bluetooth adapter except bluetooth.btcommon.BluetoothError, e: log.warn('BluetoothError ignored: %s' % e) else: log.debug( 'Not configured to use services_discover() to find services') if self.config.getBool('lookup'): log.debug('Using lookup_name() to find services') try: for addr in self.guests: name = bluetooth.lookup_name(addr) if name: log.debug('Found service: %s' % addr) result.append(addr) else: log.debug('Did not find service: %s' % addr) # This happens from time to time, and we don't want to die because of it: # BluetoothError: error communicating with local bluetooth adapter except bluetooth.btcommon.BluetoothError, e: log.warn('BluetoothError ignored: %s' % e)
def debug(self, msg, data=None): log.debug("RuleRunner: #%s: %s" % (self.id, msg), data)
def debug(self, msg, data=None): msg = "RuleInstances: #%s: %s" % (self.id, msg) if data: log.debug(msg, data) else: log.debug(msg)
def sendActionResponse(self, key, data, correlationId): topic = '%s.%s.%s' % (self.getActionResponsePrefix(), self.id, key) log.debug('sendActionResponse: %s = %s' % (topic, data)) self.producer.put(topic, data, correlationId)
def onMessage(self, topic, data, correlationId): self.aggregated['total_messages'] += 1 if topic.startswith('se.') and not topic.endswith('.online'): # aggregation: update the total number of events from this service and class cursrv = topic.split('.')[1] if cursrv in self.aggregated['service_events']: self.aggregated['service_events'][cursrv] += 1 else: self.aggregated['service_events'][cursrv] = 1 if 'class' in data: if data['class'] in self.aggregated['class_events']: self.aggregated['class_events'][data['class']] += 1 else: self.aggregated['class_events'][data['class']] = 1 # Ignore is in config ignoreclasses or ignore is set for the service if 'class' in data: if data['class'] in self.ignoreclasses: return if 'ignore' in data: if data['ignore'] in [True, 'True', 'true', 'Yes', 'yes', 'y']: return # start picking out data to report measures = [] tags = {} for tag in data: if tag in self.known_tags: if tag == 'key': tags.update({'event': data[tag]}) else: tagValue = data[tag] if type(tagValue) == types.UnicodeType: tagValue = tagValue.encode('utf-8') tags.update({tag: tagValue}) for measure in data['data']: if 'value' in data['data'][measure]: curval = data['data'][measure]['value'] if isinstance(curval, numbers.Number): measures.append( self.ix.data_template(measure, tags, {'value': curval})) # log.info('field: %s: %s' % (measure, str(curval))) # log.info('tags: %s' % str(tags)) elif curval in [ True, 'True', 'true', 'On', 'on', 'Yes', 'yes' ]: measures.append( self.ix.data_template(measure, tags, {'value': True})) elif curval in [ False, 'False', 'false', 'Off', 'off', 'No', 'no' ]: measures.append( self.ix.data_template(measure, tags, {'value': False})) else: # log.info('Skipping because value is not a number:') # log.info("topic: " + str(topic)) # log.info("data: " + str(data)) pass log.debug('insert measures: %s' % measures) try: self.ix.insert(measures) except Exception, e: log.error( 'Failed inserting measures in influxdb: %s\nAttempted insert was: %s' % (utils.e2str(e), measures))
def call(self, key, data=None, timeout=5, block=None): log.debug('RPC-CALL: execute %s = %s' % (key, data)) if block is None: block = True # @todo: remove consume again afterwards! if not timeout: # tuba - no_ack=True is also an option self.consumerTag = self.ch.basic_consume(self.queue, callback=self._callback) self.response = None self.correlationId = getUuid() # str(uuid.uuid4()) msg = amqp.Message( json.encode(data), content_type='text/json', correlation_id=self.correlationId, # reply_to = self.queue ) self.ch.basic_publish( msg, self.exchange, key, # reply_to = self.queue, # correlation_id = self.correlationId ) if not block: return log.notice('RPC-CALL: wait response') startTime = time.time() while self.response is None: if timeout: msg = self.ch.basic_get(self.queue) if msg: if self._callback(msg): break else: time.sleep(0.01) if (time.time() - startTime) >= timeout: raise TimeoutException( 'Waited %s sec for rpc call %s' % (timeout, key)) else: self.ch.wait() log.notice('RPC-CALL: finished waiting') try: body = json.decode(self.response.body) except Exception as e: raise Exception("json decoding error: %s - for raw response: %s" % (e, self.response.body)) tmp = self.response.routing_key.split('.') if tmp[0][1] == 'x': # todo: use constants if tmp[0][0] == 'o': d = 'orchestrator' # here too elif tmp[0][0] == 's': d = 'service' elif tmp[0][0] == 'r': d = 'reactor' elif tmp[0][0] == 'm': d = 'manager' e = RemoteException('Error in %s %s when calling %s' % (d, tmp[1], tmp[2])) e.setResponse(body) raise e log.debug('RPC-CALL: respone %s = %s' % (self.response.routing_key, body)) return body