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)
Пример #2
0
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
Пример #3
0
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))
Пример #4
0
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
Пример #5
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()
Пример #6
0
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)
Пример #7
0
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.
Пример #8
0
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)
Пример #9
0
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)
Пример #10
0
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