class WebsocketClientModule(Thread): def __init__(self, baseConfig, pInBoundEventQueue, pOutBoundEventQueue, loggingQueue): super(WebsocketClientModule, self).__init__() self.alive = True self.config = baseConfig self.inQueue = pInBoundEventQueue # inQueue are messages from the main process to websocket clients self.outQueue = pOutBoundEventQueue # outQueue are messages from clients to main process self.websocketClient = None self.loggingQueue = loggingQueue self.threadProcessQueue = None # Constants self._port = self.config['WebsocketPort'] self._host = self.config['WebsocketHost'] # logging setup self.logger = ThreadsafeLogger(loggingQueue, __name__) def run(self): """ Main thread entry point. Sets up websocket server and event callbacks. Starts thread to monitor inbound message queue. """ self.logger.info("Starting websocket %s" % __name__) self.connect() def listen(self): self.threadProcessQueue = Thread(target=self.processQueue) self.threadProcessQueue.setDaemon(True) self.threadProcessQueue.start() def connect(self): #websocket.enableTrace(True) ws = websocket.WebSocketApp("ws://%s:%s" % (self._host, self._port), on_message=self.onMessage, on_error=self.onError, on_close=self.onClose) ws.on_open = self.onOpen ws.run_forever() def onError(self, ws, message): self.logger.error("Error from websocket client: %s" % message) def onClose(self, ws): if self.alive: self.logger.warn("Closed") self.alive = False # TODO: reconnect timer else: self.logger.info("Closed") def onMessage(self, ws, message): self.logger.info("Message from websocket server: %s" % message) def onOpen(self, ws): self.alive = True self.websocketClient = ws self.listen() def shutdown(self): """ Handle shutdown message. Close and shutdown websocket server. Join queue processing thread. """ self.logger.info("Shutting down websocket server %s" % (multiprocessing.current_process().name)) try: self.logger.info("Closing websocket") self.websocketClient.close() except Exception as e: self.logger.error("Websocket close error : %s " % e) self.alive = False self.threadProcessQueue.join() time.sleep(1) self.exit = True def sendOutMessage(self, message): """ Send message to server """ self.websocketClient.send(json.dumps(message.__dict__)) def processQueue(self): """ Monitor queue of messages from main process to this thread. """ while self.alive: if (self.inQueue.empty() == False): try: message = self.inQueue.get(block=False, timeout=1) if message is not None: if message == "SHUTDOWN": self.logger.debug("SHUTDOWN handled") self.shutdown() else: self.sendOutMessage(message) except Exception as e: self.logger.error("Websocket unable to read queue : %s " % e) else: time.sleep(.25)
class BtleCollectionPoint(Thread): def __init__(self, baseConfig, pInBoundQueue, pOutBoundQueue, loggingQueue): """ Initialize new CamCollectionPoint instance. Setup queues, variables, configs, constants and loggers. """ super(BtleCollectionPoint, self).__init__() # Queues self.outQueue = pOutBoundQueue #messages from this thread to the main process self.inQueue = pInBoundQueue self.loggingQueue = loggingQueue self.queueBLE = mp.Queue() # Configs self.moduleConfig = configLoader.load( self.loggingQueue) #Get the config for this module self.config = baseConfig # Logger self.logger = ThreadsafeLogger(loggingQueue, __name__) # Variables self.registeredClientRegistry = RegisteredClientRegistry( self.moduleConfig, self.loggingQueue) self.eventManager = EventManager(self.moduleConfig, pOutBoundQueue, self.registeredClientRegistry, self.loggingQueue) self.alive = True self.btleThread = None self.BLEThread = None self.repeatTimerSweepClients = None # main start method def run(self): ###Pausing Startup to wait for things to start after a system restart self.logger.info( "Pausing execution 15 seconds waiting for other system services to start" ) time.sleep(15) self.logger.info( "Done with our nap. Time to start looking for clients") ######### setup global client registry start ######### # self.registeredClientRegistry = RegisteredClientRegistry(self.moduleConfig, self.loggingQueue) ######### setup global client registry end ######### self.logger.info('here 1') self.btleThread = BlueGigaBtleCollectionPointThread( self.queueBLE, self.moduleConfig, self.loggingQueue) self.BLEThread = Thread(target=self.btleThread.bleDetect, args=(__name__, 10)) self.BLEThread.daemon = True self.BLEThread.start() self.logger.info('here 2') #Setup repeat task to run the sweep every X interval self.repeatTimerSweepClients = RepeatedTimer( (self.moduleConfig['AbandonedClientCleanupIntervalInMilliseconds'] / 1000), self.registeredClientRegistry.sweepOldClients) # Process queue from main thread for shutdown messages self.threadProcessQueue = Thread(target=self.processQueue) self.threadProcessQueue.setDaemon(True) self.threadProcessQueue.start() self.logger.info('here 3') #read the queue while self.alive: if not self.queueBLE.empty(): self.logger.info( 'got a thing here herhehrehfhve!~ ~ ~@~@~!#~ ~ #~ #@@~ ~@# @~#' ) result = self.queueBLE.get(block=False, timeout=1) self.__handleBtleClientEvents(result) def processQueue(self): self.logger.info( "Starting to watch collection point inbound message queue") while self.alive: if not self.inQueue.empty(): self.logger.info("Queue size is %s" % self.inQueue.qsize()) try: message = self.inQueue.get(block=False, timeout=1) if message is not None: if message == "SHUTDOWN": self.logger.info("SHUTDOWN command handled on %s" % __name__) self.shutdown() else: self.sendOutMessage(message) except Exception as e: self.logger.error("Unable to read queue, error: %s " % e) self.shutdown() self.logger.info("Queue size is %s after" % self.inQueue.qsize()) else: time.sleep(.25) #handle btle reads def __handleBtleClientEvents(self, detectedClients): self.logger.debug("doing handleBtleClientEvents: %s" % detectedClients) for client in detectedClients: self.logger.debug("--- Found client ---") self.logger.debug(vars(client)) self.logger.debug("--- Found client end ---") self.eventManager.registerDetectedClient(client) def shutdown(self): self.logger.info("Shutting down") # self.threadProcessQueue.join() self.repeatTimerSweepClients.stop() self.btleThread.stop() self.alive = False time.sleep(1) self.exit = True
class BlueGigaBtleCollectionPointThread(Thread): def __init__(self, queue, btleConfig, loggingQueue, debugMode=False): Thread.__init__(self) # Logger self.loggingQueue = loggingQueue self.logger = ThreadsafeLogger(loggingQueue, __name__) self.alive = True self.btleConfig = btleConfig self.queue = queue self.btleCollectionPoint = BtleThreadCollectionPoint(self.eventScanResponse,self.btleConfig,self.loggingQueue) def bleDetect(self,__name__,repeatcount=10): try: self.btleCollectionPoint.start() except Exception as e: self.logger.error("[btleThread] Unable to connect to BTLE device: %s"%e) self.sendFailureNotice("Unable to connect to BTLE device") quit() while self.alive: try: self.btleCollectionPoint.scan() except Exception as e: self.logger.error("[btleThread] Unable to scan BTLE device: %s"%e) self.sendFailureNotice("Unable to connect to BTLE device to perform a scan") quit() # don't burden the CPU time.sleep(0.01) # handler to print scan responses with a timestamp def eventScanResponse(self,sender,args): #check to make sure there is enough data to be a beacon if len(args["data"]) > 15: # self.logger.debug("=============================== eventScanResponse START ===============================") try: majorNumber = args["data"][26] | (args["data"][25] << 8) # self.logger.debug("majorNumber=%i"%majorNumber) except: majorNumber = 0 try: minorNumber = args["data"][28] | (args["data"][27] << 8) # self.logger.debug("minorNumber=%i"%minorNumber) except: minorNumber = 0 if self.btleConfig['BtleAdvertisingMajor'] == majorNumber and self.btleConfig['BtleAdvertisingMinor'] == minorNumber: self.logger.debug("self.btleConfig['BtleAdvertisingMinor'] == %i and self.btleConfig['BtleAdvertisingMinor'] == %i "%(majorNumber,minorNumber)) self.logger.debug("yep, we care about this major and minor so lets create a detected client and pass it to the event manager") udid = "%s" % ''.join(['%02X' % b for b in args["data"][9:25]]) self.logger.debug("UDID=%s"%udid) rssi = args["rssi"] self.logger.debug("rssi=%s"%rssi) beaconMac = "%s" % ''.join(['%02X' % b for b in args["sender"][::-1]]) self.logger.debug("beaconMac=%s"%beaconMac) rawTxPower = args["data"][29] self.logger.debug("rawTxPower=%i"%rawTxPower) if rawTxPower <= 127: txPower = rawTxPower else: txPower = rawTxPower - 256 self.logger.debug("txPower=%i"%txPower) arrayDetectedClients = [] #we send an array to the event queue, we used to process bacthes of responses #package it up for sending to the queue detectedClient = DetectedClient('btle',udid=udid,beaconMac=beaconMac,majorNumber=majorNumber,minorNumber=minorNumber,tx=txPower,rssi=rssi) arrayDetectedClients.append(detectedClient) #put it on the queue for the event manager to pick up self.queue.put(arrayDetectedClients) self.logger.debug("================================= eventScanResponse END =================================") def stop(self): self.alive = False def sendFailureNotice(self,msg): if len(self.btleConfig['SlackChannelWebhookUrl']) > 10: myMsg = 'Help I have fallen and can not get back up! \n %s. \nSent from %s'%(msg,platform.node()) payload = {'text': myMsg} r = requests.post(self.btleConfig['SlackChannelWebhookUrl'], data = json.dumps(payload))
class BtleRegisteredClient: #part of interface for Registered Client def __init__(self, detectedClient, collectionPointConfig, loggingQueue): # Logger self.loggingQueue = loggingQueue self.logger = ThreadsafeLogger(loggingQueue, __name__) self.logger = logging.getLogger( 'btleRegisteredClient.BtleRegisteredClient') self.clientEventLogger = logging.getLogger( 'btleRegisteredClient.BtleEventTesting') self.clientEventSendLogger = logging.getLogger('eventSend') self.clientInRangeTrigerCount = 2 self.lastTimeMessageClientInWasSentToController = -1 self.lastTimeMessageClientOutWasSentToController = -1 self.__countClientInRange = 0 self.__countClientOutOfRange = 0 self.timeInCollectionPointInMilliseconds = 0 self.firstRegisteredTime = time.time() self.collectionPointConfig = collectionPointConfig self.__clientOutThresholdMin = int( self.collectionPointConfig['BtleRssiClientInThreshold'] + (self.collectionPointConfig['BtleRssiClientInThreshold'] * self.collectionPointConfig['BtleRssiErrorVariance'])) self.handleNewDetectedClientEvent( detectedClient ) #standard shared methods when we see a detected client #part of interface for Registered Client def updateWithNewDectedClientData(self, detectedClient): self.timeInCollectionPointInMilliseconds = time.time( ) - self.firstRegisteredTime self.handleNewDetectedClientEvent( detectedClient ) #standard shared methods when we see a detected client #Common methods are handled here for updateWithNewDectedClientData and init def handleNewDetectedClientEvent(self, detectedClient): self.lastRegisteredTime = time.time() self.detectedClient = detectedClient self.txPower = detectedClient.extraData['tx'] self.beaconId = detectedClient.extraData['udid'] #TODO HACK FIX self.incrementInternalClientEventCounts(detectedClient) def incrementInternalClientEventCounts(self, detectedClient): self.clientEventLogger.debug( "==================================== EVENT COUNTS DATA START ====================================" ) self.clientEventLogger.debug( "Counts before inCount %i : outCount %i" % (self.__countClientInRange, self.__countClientOutOfRange)) #self.clientEventLogger.debug("rssi types") #self.clientEventLogger.debug("type of self.detectedClient.extraData['rssi'] = %s" %type(self.detectedClient.extraData['rssi'])) #self.clientEventLogger.debug("type of self.detectedClient.extraData['rssi'] = %s" %type(self.detectedClient.extraData['rssi'])) #self.clientEventLogger.debug("type of self.collectionPointConfig['btleRssiClientInThreshold'] = %s " %type(self.collectionPointConfig['btleRssiClientInThreshold'])) #self.clientEventLogger.debug("type of self.__clientOutThresholdMin = %s " %type(self.__clientOutThresholdMin)) if self.collectionPointConfig['gatewayType'] == 'proximity': #check threshold type if self.collectionPointConfig[ 'btleRssiClientInThresholdType'] == 'rssi': #are they in or are they out of range --- increament internal count. we use the count to normalize the events even more #self.logger.debug("rssi average %i > btleRssi threshold %i: %s" %(self.getRssiAverage(),self.collectionPointConfig['btleRssiClientInThreshold'],self.getRssiAverage() > self.collectionPointConfig['btleRssiClientInThreshold'])) self.clientEventLogger.debug("Registered Client Event") self.clientEventLogger.debug("UDID is %s " % self.getUdid()) self.clientEventLogger.debug("Beacon ID is %s " % self.beaconId) self.clientEventLogger.debug( "RSSI %i" % self.detectedClient.extraData['rssi']) self.clientEventLogger.debug( "BTLE RSSI client in threshold %i" % self.collectionPointConfig['BtleRssiClientInThreshold']) self.clientEventLogger.debug( "BTLE RSSI client out threshold %i" % self.__clientOutThresholdMin) if self.detectedClient.extraData[ 'rssi'] >= self.collectionPointConfig[ 'BtleRssiClientInThreshold']: self.__countClientInRange = self.__countClientInRange + 1 self.__countClientOutOfRange = 0 self.clientEventLogger.debug("CLIENT IN RANGE>>>>>>>>>>>") else: if self.detectedClient.extraData[ 'rssi'] <= self.__clientOutThresholdMin: self.__countClientOutOfRange = self.__countClientOutOfRange + 1 #self.__countClientInRange = 0 self.clientEventLogger.debug( "CLIENT OUT OF RANGE<<<<<<<<<<<") else: self.clientEventLogger.debug( "CLIENT IN BUFFER AREA==========") self.clientEventLogger.debug( "Counts after inCount %i : outCount %i" % (self.__countClientInRange, self.__countClientOutOfRange)) self.clientEventLogger.debug( "==================================== EVENT COUNTS DATA END ====================================" ) self.clientEventLogger.debug("") #part of interface for Registered Client def shouldSendClientInEvent(self): if self.collectionPointConfig['gatewayType'] == 'proximity': #we compare on seconds so we need to adjust this to seconds proximityEventIntervalInSeconds = ( self. collectionPointConfig['ProximityEventIntervalInMilliseconds'] / 1000) timeDiff = math.trunc( time.time() - self.lastTimeMessageClientInWasSentToController) self.logger.debug("shouldSendClientInEvent timeDiff %f > %s" % (timeDiff, proximityEventIntervalInSeconds)) if timeDiff > proximityEventIntervalInSeconds: if self.__countClientInRange > self.clientInRangeTrigerCount: self.logClientEventSend( "SHOULD ClientIN event to controller for") self.zeroEventRangeCounters() return True #TODO add in other types of gateway types return False #part of interface for Registered Client def shouldSendClientOutEvent(self): if self.collectionPointConfig['gatewayType'] == 'proximity': #we compare on seconds so we need to adjust this to seconds proximityEventIntervalInSeconds = ( self. collectionPointConfig['ProximityEventIntervalInMilliseconds'] / 1000) #check the time to see if we need to send a message #have we ever sent an IN event? if not we dont need to send an out event if self.lastTimeMessageClientInWasSentToController > 0: #check timing on last event sent #self.logger.debug("shouldSendClientOutEvent lastTimeMessageClientOutWasSentToController=%f"%self.lastTimeMessageClientOutWasSentToController) timeDiff = time.time( ) - self.lastTimeMessageClientOutWasSentToController #have we sent a client out since the last client in? if so we dont need to throw another if self.lastTimeMessageClientOutWasSentToController < self.lastTimeMessageClientInWasSentToController: #do we have enought qualifying out events. we dont want to throw one too soon if self.__countClientOutOfRange >= self.collectionPointConfig[ 'BtleClientOutCountThreshold']: self.logClientEventSend( "SHOULD ClientOUT event to controller for") self.zeroEventRangeCounters() return True #lets check to see if we need to clean up the out count --- not sure this is the best idea else: if self.__countClientOutOfRange > self.collectionPointConfig[ 'BtleClientOutCountThreshold']: self.clientEventLogger.debug( "Client out count %i is past max. Resetting." % self.__countClientOutOfRange) self.__countClientOutOfRange = 0 else: #lets check to see if we need to clean up the out count --- not sure this is the best idea if self.__countClientOutOfRange > self.collectionPointConfig[ 'BtleClientOutCountThreshold']: self.clientEventLogger.debug( "Client out count %i is past max. Resetting." % self.__countClientOutOfRange) self.__countClientOutOfRange = 0 #TODO add in other types of gateway types return False #part of interface for Registered Client def sweepShouldSendClientOutEvent(self): if self.collectionPointConfig['gatewayType'] == 'proximity': #has an out event already been sent? if so we dont need to throw another on sweep if self.lastTimeMessageClientOutWasSentToController > 0: #was there a in event sent after the last out? if self.lastTimeMessageClientInWasSentToController > self.lastTimeMessageClientOutWasSentToController: self.logClientEventSend( "Sweep case a is sending ClientOUT on") self.zeroEventRangeCounters() return True else: return False else: self.logClientEventSend("Sweep case b is sending ClientOUT on") self.zeroEventRangeCounters() return True #TODO add in other types of gateway types return True #part of interface for Registered Client def getUdid(self): return self.detectedClient.extraData["beaconMac"] def getTxPower(self): return self.txPower #zero out the BTLE event counters def zeroEventRangeCounters(self): self.__countClientOutOfRange = 0 self.__countClientInRange = 0 def logClientEventSend(self, message): self.clientEventSendLogger.debug("") self.clientEventSendLogger.debug( "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" ) self.clientEventSendLogger.debug( "%%%%%%%%%%%%%%%%%% %s %%%%%%%%%%%%%%%%%%" % message) self.clientEventSendLogger.debug("UDID is %s " % self.getUdid()) self.clientEventSendLogger.debug("Beacon ID is %s " % self.beaconId) self.clientEventSendLogger.debug("RSSI %i" % self.detectedClient.extraData['rssi']) self.clientEventSendLogger.debug( "BTLE RSSI client in threshold %i" % self.collectionPointConfig['BtleRssiClientInThreshold']) self.clientEventSendLogger.debug("BTLE RSSI client out threshold %i" % self.__clientOutThresholdMin) self.clientEventSendLogger.debug( "inCount %i : outCount %i" % (self.__countClientInRange, self.__countClientOutOfRange)) self.clientEventSendLogger.debug( "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" ) self.clientEventSendLogger.debug("") #part of interface for Registered Client def getExtenedDataForEvent(self): extraData = {} extraData['lastRegisteredTime'] = self.lastRegisteredTime extraData['firstRegisteredTime'] = self.firstRegisteredTime extraData[ 'lastTimeMessageClientInWasSentToController'] = self.lastTimeMessageClientInWasSentToController extraData[ 'lastTimeMessageClientOutWasSentToController'] = self.lastTimeMessageClientOutWasSentToController extraData[ 'timeInCollectionPointInMilliseconds'] = self.timeInCollectionPointInMilliseconds extraData['rssi'] = self.detectedClient.extraData['rssi'] extraData['averageRssi'] = self.detectedClient.extraData['rssi'] extraData['txPower'] = self.getTxPower() #TODO INSTALL FIX extraData['beaconId'] = self.beaconId return extraData #part of interface for Registered Client def setClientInMessageSentToController(self): self.lastTimeMessageClientInWasSentToController = time.time() self.__countClientInRange = 0 #part of interface for Registered Client def setClientOutMessageSentToController(self): self.lastTimeMessageClientOutWasSentToController = time.time() self.__countClientOutOfRange = 0
class MQTTClientModule(Thread): """ Threaded MQTT client for processing and publishing outbound messages""" def __init__(self, baseConfig, pInBoundEventQueue, pOutBoundEventQueue, loggingQueue): super(MQTTClientModule, self).__init__() self.config = baseConfig self.alive = True self.inQueue = pInBoundEventQueue # Constants self._keepAlive = self.config['MqttKeepAlive'] self._feedName = self.config['MqttFeedName'] self._username = self.config['MqttUsername'] self._key = self.config['MqttKey'] self._host = self.config['MqttHost'] self._port = self.config['MqttPort'] self._publishJson = self.config['MqttPublishJson'] self._publishFaceValues = self.config['MqttPublishFaceValues'] # MQTT setup self._client = mqtt.Client() self._client.username_pw_set(self._username, self._key) self._client.on_connect = self.onConnect self._client.on_disconnect = self.onDisconnect self._client.on_message = self.onMessage self.mqttConnected = False # Logging setup self.logger = ThreadsafeLogger(loggingQueue, "MQTT") def onConnect(self, client, userdata, flags, rc): self.logger.debug('MQTT onConnect called') # Result code 0 is success if rc == 0: self.mqttConnected = True # Subscribe to feed here else: self.logger.error('MQTT failed to connect: %s' % rc) raise RuntimeError('MQTT failed to connect: %s' % rc) def onDisconnect(self, client, userdata, rc): self.logger.debug('MQTT onDisconnect called') self.mqttConnected = False if rc != 0: self.logger.debug('MQTT disconnected unexpectedly: %s' % rc) self.handleReconnect(rc) def onMessage(self, client, userdata, msg): self.logger.debug('MQTT onMessage called for client: %s' % client) def connect(self): """ Connect to MQTT broker Skip calling connect if already connected. """ if self.mqttConnected: return self._client.connect(self._host, port=self._port, keepalive=self._keepAlive) def disconnect(self): """ Check if connected""" if self.mqttConnected: self._client.disconnect() def subscribe(self, feed=False): """Subscribe to feed, defaults to feed specified in config""" if not feed: feed = _feedName self._client.subscribe('{0}/feeds/{1}'.format(self._username, feed)) def publish(self, value, feed=False): """Publish a value to a feed""" if not feed: feed = _feedName self._client.publish('{0}/feeds/{1}'.format(self._username, feed), payload=value) def publishFaceValues(self, message): """ Publish face detection values to individual MQTT feeds Parses _extendedData.predictions.faceAttributes property Works with Azure face API responses and """ try: for face in message._extendedData['predictions']: faceAttrs = face['faceAttributes'] for key in faceAttrs: if type(faceAttrs[key]) is dict: val = self.flattenDict(faceAttrs[key]) print('val: ', val) else: val = faceAttrs[key] self.publish(val, key) except Exception as e: self.logger.error('Error publishing values: %s' % e) def flattenDict(self, aDict): """ Get average of simple dictionary of numerical values """ try: val = float(sum(aDict[key] for key in aDict)) / len(aDict) except Exception as e: self.logger.error('Error flattening dict, returning 0: %s' % e) return val or 0 def publishJsonMessage(self, message): msg_str = self.stringifyMessage(message) self.publish(msg_str) def stringifyMessage(self, message): """ Dump into JSON string """ return json.dumps(message.__dict__).encode('utf8') def processQueue(self): self.logger.info('Processing queue') while self.alive: # Pump the loop self._client.loop(timeout=1) if (self.inQueue.empty() == False): try: message = self.inQueue.get(block=False, timeout=1) if message is not None and self.mqttConnected: if message == "SHUTDOWN": self.logger.debug("SHUTDOWN command handled") self.shutdown() else: # Send message as string or split into channels if self._publishJson: self.publishJsonMessage(message) elif self._publishFaceData: self.publishFaceValues(message) else: self.publishValues(message) except Exception as e: self.logger.error("MQTT unable to read queue : %s " % e) else: time.sleep(.25) def shutdown(self): self.logger.info("Shutting down MQTT %s" % (mp.current_process().name)) self.alive = False time.sleep(1) self.exit = True def run(self): """ Thread start method""" self.logger.info("Running MQTT") self.connect() self.alive = True # Start queue loop self.processQueue()
class AzureImagePrediction(AbstractImagePrediction): def __init__(self, moduleConfig=None, loggingQueue=None): """ Initialize new AzureImagePrediction instance. Set parameters required by Azure Face API. """ logging.basicConfig(level=logging.CRITICAL) self.logger = ThreadsafeLogger( loggingQueue, "AzureImagePrediction") # Setup logging queue self.config = moduleConfig # Constants self._subscriptionKey = self.config['Azure']['SubscriptionKey'] self._uriBase = self.config['Azure']['UriBase'] self._headers = { 'Content-Type': 'application/octet-stream', 'Ocp-Apim-Subscription-Key': self.config['Azure']['SubscriptionKey'], } self._params = urllib.parse.urlencode({ "returnFaceId": "true", "returnFaceLandmarks": "false", "returnFaceAttributes": "age,gender,glasses,facialHair" }) def getPrediction(self, imageBytes): """ Get prediction results from Azure Face API. Returns object with either a predictions array property or an error property. """ resultData = {} try: tempResult = self.__getPrediction(imageBytes) resultData['predictions'] = tempResult except Exception as e: self.logger.error('Error getting prediction: %s' % e) resultData['error'] = str(e) return resultData def __getPrediction(self, imageBytes): """ Execute REST API call and return result """ if len(self._subscriptionKey) < 10: raise EnvironmentError( 'Azure subscription key - %s - is not valid' % self._subscriptionKey) else: try: api_url = "https://%s/face/v1.0/detect?%s" % (self._uriBase, self._params) r = requests.post(api_url, headers=self._headers, data=imageBytes) if r.status_code != 200: raise ValueError( 'Request to Azure returned an error %s, the response is:\n%s' % (r.status_code, r.text)) jsonResult = r.json() self.logger.debug("Got azure data %s" % jsonResult) return jsonResult except Exception as e: self.logger.error(e)
for moduleName in _collectionModuleNames: try: sys.path.append('./collection_modules/%s' % moduleName) _collectionModules[moduleName] = import_module( 'collection_modules.%s' % moduleName) queues[moduleName] = {} # queues[moduleName]['in'] = mp.Queue() queues[moduleName]['out'] = mp.Queue() except Exception as e: logger.error('Error importing %s: %s' % (moduleName, e)) # For each collection module, import, initialize, and create an in/out queue for moduleName in _communicationModuleNames: try: logger.debug('importing %s' % (moduleName)) sys.path.append('./communication_modules/%s' % moduleName) _communicationModules[moduleName] = import_module( 'communication_modules.%s' % moduleName) queues[moduleName] = {} queues[moduleName]['in'] = mp.Queue() queues[moduleName]['out'] = mp.Queue() except Exception as e: logger.error('Error importing %s: %s' % (moduleName, e)) alive = True def sendOutboundEventMessage(msg): """ Put outbound message onto queues of all active communication channel threads.
class Tracker(): def __init__(self, bbox, frame, kind, moduleConfig, loggingQueue): """ Create and initialize a new Tracker. Set up constants and parameters. """ if kind in ["KCF", "MIL", "MEDIANFLOW", "GOTURN", "TLD", "BOOSTING"]: self.tracker = cv2.Tracker_create(kind) self.tracker.init(frame, (bbox['x'], bbox['y'], bbox['w'], bbox['h'])) self.created = time() self.bbox = (bbox['x'], bbox['y'], bbox['w'], bbox['h']) self.velocity = (0, 0) self.updateTime = self.created self.config = moduleConfig # Constants self._useVelocity = self.config['UseVelocity'] self._horizontalVelocityBuffer = self.config[ 'HorizontalVelocityBuffer'] self._verticalVelocityBuffer = self.config[ 'VerticalVelocityBuffer'] # Setup logging queue self.logger = ThreadsafeLogger(loggingQueue, __name__) else: self.logger.error("Type %s not supported by mTracker" % kind) def getCreated(self): """ Get created time """ return self.created def right(self): """ Get right bound of tracker """ return self.bbox[0] + self.bbox[2] def top(self): """ Get top bound of tracker """ return self.bbox[1] + self.bbox[3] def bottom(self): """ Get bottom bound of tracker """ return self.bbox[1] def left(self): """ Get left bound of tracker """ return self.bbox[0] def area(self): """ Get area of tracker bounding box """ return abs(self.right() - self.left()) * abs(self.top() - self.bottom()) def update(self, frame): """ Update tracker. If velocity hack is being used, calculate the new velocity of the midpoint. """ ok, bbox = self.tracker.update(frame) if self._useVelocity: # Set velocity (pixels/sec) deltaT = time() - self.updateTime centreNow = ((bbox[0] + bbox[2] / 2), (bbox[1] + bbox[3] / 2)) centreLast = ((self.bbox[0] + self.bbox[2] / 2), (self.bbox[1] + self.bbox[3] / 2)) Vx = (centreNow[0] - centreLast[0]) / deltaT Vy = (centreNow[1] - centreLast[1]) / deltaT self.velocity = (Vx, Vy) self.logger.debug('New velocity: %s' % str(self.velocity[0]) + ', ' + str(self.velocity[1])) self.updateTime = time() self.bbox = bbox return ok, bbox def getProjectedLocation(self, time): """ Get the estimated location of the bounding box, based on previous velocity. """ deltaT = max((time - self.updateTime), 1) centreNow = ((self.bbox[0] + self.bbox[2] / 2), (self.bbox[1] + self.bbox[3] / 2)) projectedX = centreNow[0] + (self.velocity[0] * deltaT) projectedY = centreNow[1] + (self.velocity[1] * deltaT) return (projectedX, projectedY) def getVelocityBuffer(self): ''' Another hack to improve low frame rate tracking. "Spread" out the bounding box based on velocity. ''' return (abs(self.velocity[0]) * self._horizontalVelocityBuffer, abs(self.velocity[1]) * self._verticalVelocityBuffer)
class EventManager(object): def __init__(self, collectionPointConfig, pOutBoundQueue, registeredClientRegistry, loggingQueue): # Logger self.loggingQueue = loggingQueue self.logger = ThreadsafeLogger(loggingQueue, __name__) self.__stats_totalRemoveEvents = 0 self.__stats_totalNewEvents = 0 self.logger.debug("in constructor") self.registeredClientRegistry = registeredClientRegistry self.registeredClientRegistry.eventRegisteredClientAdded += self.__newClientRegistered self.registeredClientRegistry.eventRegisteredClientRemoved += self.__removedRegisteredClient self.collectionPointConfig = collectionPointConfig self.outBoundEventQueue = pOutBoundQueue def registerDetectedClient(self, detectedClient): self.logger.debug("Registering detected client %s" % detectedClient.extraData["beaconMac"]) eClient = self.registeredClientRegistry.getRegisteredClient( detectedClient.extraData["beaconMac"]) #check for existing if eClient == None: #Newly found client if self.collectionPointConfig['InterfaceType'] == 'btle': rClient = BtleRegisteredClient(detectedClient, self.collectionPointConfig, self.loggingQueue) self.logger.debug( "client %s not found in the existing clients. NEW CLIENT! " % detectedClient.extraData["beaconMac"]) if rClient.shouldSendClientInEvent(): self.__sendEventToController(rClient, "clientIn") elif rClient.shouldSendClientOutEvent(): self.logger.debug( "########################################## SENDING CLIENT OUT eClient ##########################################" ) self.__sendEventToController(rClient, "clientOut") self.registeredClientRegistry.addNewRegisteredClient(rClient) else: eClient.updateWithNewDectedClientData(detectedClient) if eClient.shouldSendClientInEvent(): #self.logger.debug("########################################## SENDING CLIENT IN ##########################################") self.__sendEventToController(eClient, "clientIn") elif eClient.shouldSendClientOutEvent(): self.logger.debug( "########################################## SENDING CLIENT OUT rClient ##########################################" ) self.__sendEventToController(eClient, "clientOut") self.registeredClientRegistry.updateRegisteredClient(eClient) def registerClients(self, detectedClients): for detectedClient in detectedClients: self.registerDetectedClient(detectedClient) def getEventAuditData(self): """Returns a dict with the total New and Remove events the engine has seen since startup""" return { 'NewEvents': self.__stats_totalNewEvents, 'RemoveEvents': self.__stats_totalRemoveEvents } def __newClientRegistered(self, sender, registeredClient): self.logger.debug( "######### NEW CLIENT REGISTERED %s #########" % registeredClient.detectedClient.extraData["beaconMac"]) #we dont need to count for ever and eat up all the memory if self.__stats_totalNewEvents > 1000000: self.__stats_totalNewEvents = 0 else: self.__stats_totalNewEvents += 1 def __removedRegisteredClient(self, sender, registeredClient): self.logger.debug( "######### REGISTERED REMOVED %s #########" % registeredClient.detectedClient.extraData["beaconMac"]) if registeredClient.sweepShouldSendClientOutEvent(): self.__sendEventToController(registeredClient, "clientOut") #we dont need to count for ever and eat up all the memory if self.__stats_totalRemoveEvents > 1000000: self.__stats_totalRemoveEvents = 0 else: self.__stats_totalRemoveEvents += 1 def __sendEventToController(self, registeredClient, eventType): eventMessage = CollectionPointEvent( self.collectionPointConfig['collectionPointId'], registeredClient.lastRegisteredTime, registeredClient.detectedClient.extraData["beaconMac"], self.collectionPointConfig['gatewayType'], eventType, registeredClient.getExtenedDataForEvent()) if eventType == 'clientIn': registeredClient.setClientInMessageSentToController() elif eventType == 'clientOut': registeredClient.setClientOutMessageSentToController() #update reg self.registeredClientRegistry.updateRegisteredClient(registeredClient) self.outBoundEventQueue.put(eventMessage)
class RegisteredClientRegistry(object): eventRegisteredClientRemoved = RegistryEvent() eventRegisteredClientAdded = RegistryEvent() eventRegisteredClientUpdated = RegistryEvent() eventSweepComplete = RegistryEvent() def __init__(self, collectionPointConfig, loggingQueue): # Logger self.loggingQueue = loggingQueue self.logger = ThreadsafeLogger(loggingQueue, __name__) self.rClients = {} #registered clients self.collectionPointConfig = collectionPointConfig #collection point config def getRegisteredClient(self, udid): """Get an existing registered client by udid and if its found return it. If no existing registered client is found return None.""" try: eClient = self.rClients[udid] except KeyError: eClient = None return eClient def sweepOldClients(self): """look at the registry and look for expired inactive clients. Returns a list of removed clients""" self.logger.debug("*** Sweeping clients existing count %s***" % len(self.rClients)) clientsToBeRemoved = [] #list of clients to be cleaned up currentExpireTime = time.time() - ( self.collectionPointConfig['AbandonedClientTimeoutInMilliseconds'] / 1000) #converted to seconds for compare self.logger.debug( "Current time is %s. abandonedClientTimeoutInMilliseconds seconds is %s. Giving us expire time of %s." % (time.time(), (self.collectionPointConfig['LeaveTimeInMilliseconds'] / 1000), currentExpireTime)) for udid in self.rClients: regClient = self.rClients[udid] self.logger.debug( "checking if registerd tag last registered %s < current expire time %s" % (regClient.lastRegisteredTime, currentExpireTime)) if regClient.lastRegisteredTime < currentExpireTime: self.logger.debug( "************************* SWEEP adding registered client to be removed %s" % udid) clientsToBeRemoved.append(regClient) #had to do the remove outside the loop becuase you cant alter the object as you try to loop over it for client in clientsToBeRemoved: self.logger.debug( "************************* SWEEP removing udid %s *************************" % client.getUdid()) self.removeRegisteredClient(client) self.logger.debug("*** End of sweeping tags existing count %s***" % len(self.rClients)) self.eventSweepComplete(clientsToBeRemoved) return clientsToBeRemoved def addNewRegisteredClient(self, registeredClient): self.logger.debug("in addNewRegisteredClient with %s" % registeredClient.getUdid()) self.rClients[registeredClient.getUdid()] = registeredClient self.eventRegisteredClientAdded(registeredClient) #throw event def updateRegisteredClient(self, registeredClient): self.logger.debug("in updateRegisteredClient with %s" % registeredClient.getUdid()) self.rClients[registeredClient.getUdid()] = registeredClient self.eventRegisteredClientUpdated(registeredClient) #throw event def removeRegisteredClient(self, registeredClient): self.logger.debug("in removeRegisteredClient with %s" % registeredClient.getUdid()) self.rClients.pop(registeredClient.getUdid()) self.eventRegisteredClientRemoved(registeredClient) #throw event