class WebsocketClientModule(ModuleProcess):

    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

        # Configs
        self.moduleConfig = configLoader.load(self.loggingQueue, __name__)

        # Constants
        self._port = self.moduleConfig['WebsocketPort']
        self._host = self.moduleConfig['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 %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 callback fired, message: %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)
        # Could put message on the out queue here to handle incoming coms

    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 %s"%__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.topic.upper()=="SHUTDOWN" and
                            message.sender_id.lower()=="main"):
                            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)
Esempio n. 2
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)
Esempio n. 3
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['AbandonedClientTimeout'] / 1000)

        for udid in self.rClients:
            regClient = self.rClients[udid]

            if regClient.lastRegisteredTime < currentExpireTime:
                clientsToBeRemoved.append(regClient)

        for client in clientsToBeRemoved:
            self.logger.debug("Client 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
class BtleClient(object):
    def __init__(self, detectionData, collectionPointConfig, loggingQueue):
        self.loggingQueue = loggingQueue
        self.logger = ThreadsafeLogger(loggingQueue, "BtleRegisteredClient")
        
        # Counters and variables
        self.clientInRangeTrigerCount = 1
        self.prevClientInMsgTime = None
        self.prevClientOutMsgTime = None
        self.numClientInRange=0
        self.numClientOutRange=0
        self.timeInCollectionPointInMilliseconds = 0
        self.firstRegisteredTime = datetime.now()
        self.collectionPointConfig = collectionPointConfig
        self.filter = Filter(detectionData.extraData['rssi'])
        try:
            self.uidMap = UIDMap()
        except Exception as e:
            self.logger.warning('cant instantiate uid map: %s '%e)

        # Constants
        self._proximityEventInterval = self.collectionPointConfig['ProximityEventInterval']
        self._outClientThreshold = self.collectionPointConfig['BtleClientOutCountThreshold']

        self._gatewayType = self.collectionPointConfig['GatewayType']

        self._rssiClientInThresh = self.collectionPointConfig['BtleRssiClientInThreshold']
        self._rssiErrorVar = self.collectionPointConfig['BtleRssiErrorVariance']
        self.__clientOutThresholdMin = int(
            self._rssiClientInThresh + 
            (self._rssiClientInThresh * self._rssiErrorVar)
            )
        self._clientInThreshType = self.collectionPointConfig['BtleRssiClientInThresholdType']
        self._debugEventManager = self.collectionPointConfig['EventManagerDebug']

        # Initiate event when client is detected
        self.handleNewDetectedClientEvent(detectionData)

    def updateWithNewDetectedClientData(self, detectionData):
        """
        updateWithNewDetectedClientData
        part of interface for Registered Client
        """
        self.timeInCollectionPointInMilliseconds = (datetime.now() - self.firstRegisteredTime).total_seconds()*1000
        # standard shared methods when we see a detected client
        self.handleNewDetectedClientEvent(detectionData)

    # Common methods are handled here for updateWithNewDetectedClientData and init
    def handleNewDetectedClientEvent(self, detectionData):
        self.lastRegisteredTime = datetime.now()
        self.detectionData = detectionData
        self.txPower = detectionData.extraData['tx']
        self.beaconId = detectionData.extraData['udid']
        self.filter.update(self.detectionData.extraData['rssi'])
        self.incrementInternalClientEventCounts(detectionData)

    def incrementInternalClientEventCounts(self, detectionData):
        if self._gatewayType == 'proximity':
            if self._clientInThreshType == 'rssi':
                # Are they in or are they out of range 
                # Increment internal count, used to normalize events.
                if (self.detectionData.extraData['rssi'] >= self._rssiClientInThresh):
                    self.numClientInRange += 1
                    self.numClientOutRange = 0
                    self.logClientRange("CLIENTIN")
                elif (self.detectionData.extraData['rssi'] < self.__clientOutThresholdMin):
                    self.numClientOutRange += 1
                    self.numClientInRange = 0
                    self.logClientRange("CLIENTOUT")

    #part of interface for Registered Client
    def shouldSendClientInEvent(self):
        if self._gatewayType == 'proximity':
            if (self.prevClientInMsgTime == None or 
                (self.prevClientOutMsgTime != None and 
                    (self.prevClientOutMsgTime-self.prevClientInMsgTime).total_seconds() > 0) or
                (datetime.now() - self.prevClientInMsgTime).total_seconds()*1000 >= self._proximityEventInterval):
                    if self.numClientInRange > self.clientInRangeTrigerCount:
                        # self.logClientEventSend(" ClientIN event sent to controller ")
                        self.zeroEventRangeCounters()
                        return True

        #TODO add in other types of gateway types
        # self.logger.debug("NOT SENDING CLIENT IN")
        return False

    #part of interface for Registered Client
    def shouldSendClientOutEvent(self):
        if self._gatewayType == 'proximity':
            #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.prevClientInMsgTime:
                #have we sent a client out since the last client in?  if so we dont need to throw another
                if (self.prevClientOutMsgTime == None or self.prevClientOutMsgTime < self.prevClientInMsgTime):
                    #do we have enought qualifying out events. we dont want to throw one too soon
                    if (self.numClientOutRange >= self._outClientThreshold):
                        # self.logClientEventSend("ClientOUT event a sent to controller")
                        self.logger.debug("out case B: client %s"%self.detectionData.extraData["beaconMac"])
                        self.zeroEventRangeCounters()
                        return True
                elif (self.prevClientOutMsgTime != None and 
                    self.prevClientOutMsgTime > self.prevClientInMsgTime):
                        return False

                #check timing on last event sent
                if (self.prevClientOutMsgTime is not None and
                    (datetime.now() - self.prevClientOutMsgTime).total_seconds()*1000 > self._proximityEventInterval):
                        # self.logClientEventSend("ClientOUT event b sent to controller")
                        self.logger.debug("out case A: client %s"%self.detectionData.extraData["beaconMac"])
                        self.zeroEventRangeCounters()
                        return True
                elif self.prevClientOutMsgTime is not None:
                    return False
            elif self.numClientOutRange > self._outClientThreshold:
                # self.logger.debug("Client out count "+
                #    "%i is past max.  Resetting." %self.numClientOutRange)
                self.numClientOutRange = 0

        #TODO add in other types of gateway types
        return False

    #part of interface for Registered Client
    def sweepShouldSendClientOutEvent(self):
        self.logger.debug("trace 1")
        if self._gatewayType == 'proximity':
            # has an in event been sent yet? if not, no sweep needed
            self.logger.debug("trace 2")
            if self.prevClientInMsgTime:
                self.logger.debug("trace 3")
                # sweep old clients, so check most recent message sent
                # if no message has been sent in the past proximityEventInterval*3 milliseconds
                # sweep the client because it is probably gone
                if (self.prevClientOutMsgTime is None or 
                    (self.prevClientInMsgTime>self.prevClientOutMsgTime and
                    (datetime.now() - self.prevClientOutMsgTime).total_seconds()*1000 > 
                        self._proximityEventInterval*3)):
                            self.logger.debug("trace 4")
                            self.logger.debug("sweep: client %s"%self.detectionData.extraData["beaconMac"])
                            # self.logClientEventSend("Sweep case a is sending ClientOUT on")
                            self.zeroEventRangeCounters()
                            return True
                else:
                    self.logger.debug("trace 5")
                    return False
            else:
                self.logger.debug("trace 6")
                return False
        #TODO add in other types of gateway types
        self.logger.debug("trace 7")
        return False

    #part of interface for Registered Client
    def getMac(self):
        return self.detectionData.extraData["beaconMac"]

    def getTxPower(self):
        return self.txPower

    #zero out the BTLE event counters
    def zeroEventRangeCounters(self):
        self.numClientOutRange = 0
        self.numClientInRange = 0

    def logClientEventSend(self,message):
        if self._debugEventManager:
            self.logger.debug("")
            self.logger.debug("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
            self.logger.debug("%%%%%%%%%%%%%%%%%% %s %%%%%%%%%%%%%%%%%%" %message)
            self.logger.debug("    MAC is %s " %self.getMac())
            self.logger.debug("    Beacon ID is %s " %self.beaconId)
            self.logger.debug("    filtered RSSI %i" %self.filter.state)
            self.logger.debug("    RSSI %i" %self.detectionData.extraData['rssi'])
            self.logger.debug("    Major %i" %self.detectionData.extraData['majorNumber'])
            self.logger.debug("    Minor %i" %self.detectionData.extraData['minorNumber'])
            self.logger.debug("    BTLE RSSI client in threshold %i" %self.collectionPointConfig['BtleRssiClientInThreshold'])
            self.logger.debug("    BTLE RSSI client out threshold %i" %self.__clientOutThresholdMin)
            self.logger.debug("    inCount %i : outCount %i" %(self.numClientInRange,self.numClientOutRange))
            self.logger.debug("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
            self.logger.debug("")
        return


    def logClientRange(self,eventType):
        if self.collectionPointConfig['ShowClientRangeDebug']:

            if eventType.upper() == "CLIENTIN":
                self.logger.debug("<<<<<<<<<<<<<<<<< IN RANGE <<<<<<<<<<<<<<<<<")
            else:
                self.logger.debug(">>>>>>>>>>>>>>>>> OUT OF RANGE >>>>>>>>>>>>>>>>>")

            self.logger.debug("    MAC is %s " %self.getMac())
            self.logger.debug("    Beacon ID is %s " %self.beaconId)
            self.logger.debug("    RSSI %i" %self.detectionData.extraData['rssi'])
            self.logger.debug("    Major %i" %self.detectionData.extraData['majorNumber'])
            self.logger.debug("    Minor %i" %self.detectionData.extraData['minorNumber'])
            self.logger.debug("    BTLE RSSI client in threshold %i" %self.collectionPointConfig['BtleRssiClientInThreshold'])
            self.logger.debug("    BTLE RSSI client out threshold %i" %self.__clientOutThresholdMin)
            self.logger.debug("    inCount %i : outCount %i" %(self.numClientInRange,self.numClientOutRange))

            if eventType.upper() == "CLIENTIN":
                self.logger.debug("<<<<<<<<<<<<<<<<< IN RANGE END <<<<<<<<<<<<<<<<<")
            else:
                self.logger.debug(">>>>>>>>>>>>>>>>> OUT OF RANGE END >>>>>>>>>>>>>>>>>")

            self.logger.debug("")
        return

    #part of interface for Registered Client
    def getExtendedDataForEvent(self):
        extraData = {}
        extraData['gatewayType'] = self.collectionPointConfig['GatewayType']
        extraData['lastRegisteredTime'] = self.lastRegisteredTime if self.lastRegisteredTime==None else self.lastRegisteredTime.isoformat() 
        extraData['firstRegisteredTime'] = self.firstRegisteredTime if self.firstRegisteredTime==None else self.firstRegisteredTime.isoformat() 
        extraData['prevClientInMsgTime'] = self.prevClientInMsgTime if self.prevClientInMsgTime==None else self.prevClientInMsgTime.isoformat()
        extraData['prevClientOutMsgTime'] = self.prevClientOutMsgTime if self.prevClientOutMsgTime==None else self.prevClientOutMsgTime.isoformat()
        extraData['timeInCollectionPointInMilliseconds'] = self.timeInCollectionPointInMilliseconds
        extraData['rssi'] = self.detectionData.extraData['rssi']
        extraData['averageRssi'] = self.detectionData.extraData['rssi']
        extraData['filteredRssi'] = self.filter.state
        extraData['txPower'] = self.getTxPower()
        extraData['beaconId'] = self.beaconId
        extraData['beaconMac'] = self.detectionData.extraData["beaconMac"]
        extraData['major'] = self.detectionData.extraData["majorNumber"]
        extraData['minor'] = self.detectionData.extraData["minorNumber"]
        if self.collectionPointConfig['CecData']:
            extraData['industry'] = self.uidMap.get(self.beaconId)

        return extraData
       
    def getExtendedDataForUpdateEvent(self):
        extraData = {}
        extraData['rssi'] = self.detectionData.extraData['rssi']
        extraData['filteredRssi'] = self.filter.state
        extraData['beaconId'] = self.beaconId
        extraData['beaconMac'] = self.detectionData.extraData["beaconMac"]
        extraData['major'] = self.detectionData.extraData["majorNumber"]
        extraData['minor'] = self.detectionData.extraData["minorNumber"]
        if self.collectionPointConfig['CecData']:
            extraData['industry'] = self.uidMap.get(self.beaconId)

        return extraData

    #part of interface for Registered Client
    def setClientInMessageSentToController(self):
        self.logger.debug('set client in message sent')
        self.prevClientInMsgTime = datetime.now()
        self.numClientInRange = 0

    #part of interface for Registered Client
    def setClientOutMessageSentToController(self):
        self.logger.debug('set client out message sent')
        self.prevClientOutMsgTime = datetime.now()
        self.numClientOutRange = 0
class BtleCollectionPoint(ModuleProcess):
    def __init__(self, baseConfig, pInBoundQueue, pOutBoundQueue,
                 loggingQueue):
        """ Initialize new CamCollectionPoint instance.
        Setup queues, variables, configs, constants and loggers.
        """
        super(BtleCollectionPoint, self).__init__()
        self.loggingQueue = loggingQueue
        self.logger = ThreadsafeLogger(loggingQueue, __name__)

        # Queues
        self.outQueue = pOutBoundQueue  # Messages from this thread to the main process
        self.inQueue = pInBoundQueue
        self.queueBLE = mp.Queue()

        # Configs
        self.moduleConfig = configLoader.load(self.loggingQueue)
        self.config = baseConfig

        # Variables and objects
        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

        # Constants
        self._cleanupInterval = self.moduleConfig[
            'AbandonedClientCleanupInterval']

    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")

        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()

        # Setup repeat task to run the sweep every X interval
        self.repeatTimerSweepClients = RepeatedTimer(
            (self._cleanupInterval / 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()

        #read the queue
        while self.alive:
            if not self.queueBLE.empty():
                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.topic == "SHUTDOWN"
                                and message.sender_id == 'main'):
                            self.logger.info("SHUTDOWN command handled on %s" %
                                             __name__)
                            self.shutdown()
                        else:
                            self.handleMessage(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)

    def __handleBtleClientEvents(self, 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 handleMessage(self, msg):
        # Handle incoming messages, eg. from other collection points
        pass

    def shutdown(self):
        self.logger.info("Shutting down")
        self.repeatTimerSweepClients.stop()
        self.btleThread.stop()
        self.alive = False
        time.sleep(1)
        self.exit = True
Esempio n. 6
0
class ClientRegistry(object):
    onClientRemoved = RegistryEvent()
    onClientAdded = RegistryEvent()
    onClientUpdated = RegistryEvent()
    onSweepComplete = RegistryEvent()

    def __init__(self,collectionPointConfig,loggingQueue):
        # Logger
        self.loggingQueue = loggingQueue
        self.logger = ThreadsafeLogger(loggingQueue, __name__)

        self.rClients = {}  #registered clients
        self.collectionPointConfig = collectionPointConfig

    def getAll(self, thresh=-68):
        """
        Get registered clients as dict
        Only return clients above thresh RSSI
        """
        toret = {}
        for k, v in self.rClients.items():
            xdata = v.getExtendedDataForEvent()
            if xdata['rssi']>thresh:
                toret[k] = xdata
        return toret

    def getUpdateData(self, thresh=-68):
        return {'nearby': self.getAll(thresh)}

    def getClient(self,mac):
        """
        Get an existing registered client by mac 
        and if its found return it. 
        If no existing registered client is found 
        return None.
        """
        try:
            eClient = self.rClients[mac]
        except KeyError:
            eClient = None

        return eClient

    def sweepOldClients(self):
        """
        Look at the registry and look for expired
        and 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

        clientTimeout = self.collectionPointConfig['AbandonedClientTimeout']
        now = datetime.now()

        for mac in self.rClients:
            regClient = self.rClients[mac]

            # self.logger.debug('now-regClient.lastRegisteredTime ---- clientTimeout >0 : %s ---- %s'%(((now-regClient.lastRegisteredTime).total_seconds()*1000), clientTimeout))
            # if regClient.sweepShouldSendClientOutEvent():
            if (now-regClient.lastRegisteredTime).total_seconds()*1000-clientTimeout>0:
                clientsToBeRemoved.append(regClient)

        for client in clientsToBeRemoved:
            # self.logger.debug("Client sweep removing mac %s"%client.getMac())
            self.removeClient(client)

        self.logger.debug("*** End of sweeping tags existing count "+
            "%s***"%len(self.rClients))

        self.onSweepComplete(clientsToBeRemoved)

        return clientsToBeRemoved

    def addClient(self,client):
        #self.logger.debug("in addNewRegisteredClient with %s"%client.getUdid())
        self.rClients[client.getMac()] = client
        self.onClientAdded(client)

    def updateClient(self,client):
        #self.logger.debug("in updateRegisteredClient with %s"%client.getUdid())
        self.rClients[client.getMac()] = client
        self.onClientUpdated(client)

    def removeClient(self,client):
        #self.logger.debug("in removeRegisteredClient with %s"%client.getUdid())
        self.logger.info('length before remove: %s'%len(self.rClients))
        self.rClients.pop(client.getMac())
        self.logger.info('length after remove: %s'%len(self.rClients))
        self.onClientRemoved(client)
class EventManager(object):
    def __init__(self, collectionPointConfig, pOutBoundQueue,
                 registeredClientRegistry, loggingQueue):
        self.loggingQueue = loggingQueue
        self.logger = ThreadsafeLogger(loggingQueue, __name__)

        self.__stats_totalRemoveEvents = 0
        self.__stats_totalNewEvents = 0
        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("New client with MAC %s found." %
                              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.updateWithNewDetectedClientData(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 = Message(
            topic=eventType,
            sender_id=self.collectionPointConfig['CollectionPointId'],
            sender_type=self.collectionPointConfig['GatewayType'],
            extended_data=registeredClient.getExtendedDataForEvent(),
            timestamp=registeredClient.lastRegisteredTime)

        if eventType == 'clientIn':
            registeredClient.setClientInMessageSentToController()
        elif eventType == 'clientOut':
            registeredClient.setClientOutMessageSentToController()

        #update reg
        self.registeredClientRegistry.updateRegisteredClient(registeredClient)

        self.outBoundEventQueue.put(eventMessage)
Esempio n. 8
0
class DeviceThread(Thread):
    """
    Controller thread, manage the instance of BluegigaDevice.
    """
    def __init__(self, callbacks, btleConfig, loggingQueue, debugMode=False):
        super().__init__()
        # Logger
        self.loggingQueue = loggingQueue
        self.logger = ThreadsafeLogger(loggingQueue, __name__)
        self.alive = True
        self.callbacks = self.sanitizeCallbacks(callbacks)
        self.btleConfig = btleConfig

        # consts
        self._majorMin = self.btleConfig['BtleAdvertisingMajorMin']
        self._majorMax = self.btleConfig['BtleAdvertisingMajorMax']
        self._minorMin = self.btleConfig['BtleAdvertisingMinorMin']
        self._minorMax = self.btleConfig['BtleAdvertisingMinorMax']
        self._uuidFocusList = self.btleConfig['BtleUuidFocusList']

        if ('any' in self._uuidFocusList or 
            'all' in self._uuidFocusList or
            len(self._uuidFocusList)==0):
            self.filterOnUuid = False
        else:
            self.filterOnUuid = True

        # self.queue = queue
        self.device = BluegigaDevice(
            self.scanCallback,
            self.btleConfig,
            self.loggingQueue)

    def run(self):
        """
        Main thread entry point.
        Repeatedly call scan() method on
        device controller BluegigaDevice.

        Send results or failures back to main
        thread via callbacks.
        """
        try:
            self.device.start()
        except Exception as e:
            self.logger.error("Unable to connect to BTLE device: %s"%e)
            self.sendFailureNotice("Unable to connect to BTLE device")
            self.stop()

        while self.alive:
            # try:
            self.device.scan()
            # except Exception as e:
            #     self.logger.error("Unable to scan BTLE device: %s"%e)
            #     self.sendFailureNotice("Unable to connect to BTLE device to perform a scan")
            #     self.stop()

            # don't burden the CPU
            time.sleep(0.01)

    def scanCallback(self,sender,args):
        """
        Callback for the scan event on the device controller.
        Prints the event in a formatted way for tuning purposes.
        """
        #check to make sure there is enough data to be a beacon
        if len(args["data"]) > 15:
            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

            try:
                udid = "%s" % ''.join(['%02X' % b for b in args["data"][9:25]])
            except:
                pass

            if (self.filterOnUuid and udid not in self._uuidFocusList):
                return

            if (not (self._majorMin <= majorNumber <= self._majorMax) or 
                not (self._minorMin <= minorNumber <= self._minorMax)):
                    return

            rssi = args["rssi"]
            beaconMac = "%s" % ''.join(['%02X' % b for b in args["sender"][::-1]])

            if len(args["data"]) > 29:
                rawTxPower = args["data"][29]
            else:
                rawTxPower = 0

            if rawTxPower <= 127:
                txPower = rawTxPower
            else:
                txPower = rawTxPower - 256

            if self.btleConfig['BtleTestMode']:
                self.logger.debug("=============================== eventScanResponse START ===============================")
                #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")
                self.logger.debug("Major=%s"%majorNumber)
                self.logger.debug("Minor=%s"%minorNumber)
                self.logger.debug("UDID=%s"%udid)
                self.logger.debug("rssi=%s"%rssi)
                self.logger.debug("beaconMac=%s"%beaconMac)
                self.logger.debug("txPower=%i"%txPower)
                self.logger.debug("rawTxPower=%i"%rawTxPower)
                self.logger.debug("================================= eventScanResponse END =================================")

            #package it up for sending to the queue
            detectionData = DetectionData(
                'btle',
                udid=udid,
                beaconMac=beaconMac,
                majorNumber=majorNumber,
                minorNumber=minorNumber,
                tx=txPower,
                rssi=rssi)
            
            #put it on the queue for the event manager to pick up
            self.callbacks[_ON_SCAN](detectionData)

    def sanitizeCallbacks(self, cbs):
        """
        Make sure required callbacks are included and callable.
        Return only the required callbacks.
        """
        assert(callable(cbs[_ON_SCAN]))
        if len(cbs) > 1:
            return [cbs[_ON_SCAN]]
        return cbs

    def stop(self):
        self.alive = False

    def sendFailureNotice(self, msg):
        if len(self.btleConfig['SlackChannelWebhookUrl']) > 10:
            myMsg = ("Help, I've fallen and can't get up! "+
                "\n %s. \nSent from %s"%(msg,platform.node()))
            payload = {'text': myMsg}
            r = requests.post(
                self.btleConfig['SlackChannelWebhookUrl'], 
                data = json.dumps(payload))
class WebsocketServerModule(ModuleProcess):
    def __init__(self, baseConfig, pInBoundQueue, pOutBoundQueue,
                 loggingQueue):

        # super(WebsocketServerModule, self).__init__()
        ModuleProcess.__init__(self, baseConfig, pInBoundQueue, pOutBoundQueue,
                               loggingQueue)
        self.alive = False
        self.config = baseConfig
        self.inQueue = pInBoundQueue  # inQueue are messages from the main process to websocket clients
        self.outQueue = pOutBoundQueue  # outQueue are messages from clients to main process
        self.websocketServer = None
        self.loggingQueue = loggingQueue
        self.threadProcessQueue = None

        # Configs
        self.moduleConfig = configLoader.load(self.loggingQueue, __name__)

        # Constants
        self._port = self.moduleConfig['WebsocketPort']
        self._host = self.moduleConfig['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 server")
        self.alive = True
        self.listen()

        self.websocketServer = WebsocketServer(self._port, host=self._host)
        self.websocketServer.set_fn_new_client(self.new_websocket_client)
        self.websocketServer.set_fn_message_received(
            self.websocket_message_received)
        self.websocketServer.run_forever()

    def new_websocket_client(self, client, server):
        """ Client joined callback - called whenever a new client joins. """

        self.logger.debug("Client joined")

    def websocket_message_received(self, client, server, message):
        """ Message received callback - called whenever a new message is received. """

        self.logger.debug('Message received: %s' % message)
        message = json.loads(message)
        self.logger.info("message jsond: %s" % message)
        _msg = Message(topic=message['topic'], sender_id=message['sender_id'])
        if 'sender_type' in message:
            _msg.sender_type = message['sender_type']
        if 'recipients' in message:
            _msg.recipients = message['recipients']
        if 'extended_data' in message:
            _msg.extended_data = message['extended_data']

        self.put_message(_msg)

    def listen(self):
        self.threadProcessQueue = Thread(target=self.process_queue)
        self.threadProcessQueue.setDaemon(True)
        self.threadProcessQueue.start()

    def shutdown(self):
        """ Handle shutdown message. 
        Close and shutdown websocket server.
        Join queue processing thread.
        """

        self.logger.info("Shutting down websocket server")

        try:
            self.logger.info("Closing websocket")
            self.websocketServer.server_close()
        except Exception as e:
            self.logger.error("Websocket close error : %s " % e)

        try:
            self.logger.info("Shutdown websocket")
            self.websocketServer.shutdown()
        except Exception as e:
            self.logger.error("Websocket shutdown error : %s " % e)

        self.alive = False

        self.threadProcessQueue.join()

        time.sleep(1)
        self.exit = True

    def handle_message(self, message):
        """ Send message to listening clients. """
        self.websocketServer.send_message_to_all(json.dumps(message.__dict__))

    def process_queue(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.topic.upper() == "SHUTDOWN"
                                and message.sender_id.lower() == 'main'):
                            self.logger.debug("SHUTDOWN handled")
                            self.shutdown()
                        else:
                            self.handle_message(message)
                except Exception as e:
                    self.logger.error("Websocket unable to read queue : %s " %
                                      e)
            else:
                time.sleep(.25)
class MQTTClientModule(ModuleProcess):
    """ 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

        # Module config
        self.moduleConfig = configLoader.load(self.loggingQueue, __name__)

        # Constants
        self._keepAlive = self.moduleConfig['MqttKeepAlive']
        self._feedName = self.moduleConfig['MqttFeedName']
        self._username = self.moduleConfig['MqttUsername']
        self._key = self.moduleConfig['MqttKey']
        self._host = self.moduleConfig['MqttHost']
        self._port = self.moduleConfig['MqttPort']
        self._publishJson = self.moduleConfig['MqttPublishJson']

        # 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 = self._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 = self._feedName
        self._client.publish('{0}/feeds/{1}'.format(self._username, feed),
                             payload=value)

    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 0
        return val

    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):
        """ Process incoming messages. """

        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.topic.upper() == "SHUTDOWN"
                                and message.sender_id.lower() == 'main'):
                            self.logger.debug("SHUTDOWN command handled")
                            self.shutdown()
                        else:
                            # Send message as string or split into channels
                            if self._publishJson:
                                self.publishJsonMessage(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")
        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()
Esempio n. 11
0
class BtleRegisteredClient(object):
    def __init__(self, detectedClient, collectionPointConfig, loggingQueue):
        self.loggingQueue = loggingQueue
        self.logger = ThreadsafeLogger(loggingQueue, __name__)

        # Counters and variables
        self.clientInRangeTrigerCount = 2
        self.prevClientInMsgTime = -1
        self.prevClientOutMsgTime = -1
        self.numClientInRange = 0
        self.numClientOutRange = 0
        self.timeInCollectionPointInMilliseconds = 0
        self.firstRegisteredTime = time.time()
        self.collectionPointConfig = collectionPointConfig
        try:
            self.uidMap = UIDMap()
        except Exception as e:
            print('cant instantiate uid map: %s ' % e)
        # Constants
        self._rssiClientInThresh = self.collectionPointConfig[
            'BtleRssiClientInThreshold']
        self._rssiErrorVar = self.collectionPointConfig[
            'BtleRssiErrorVariance']
        self.__clientOutThresholdMin = int(self._rssiClientInThresh +
                                           (self._rssiClientInThresh *
                                            self._rssiErrorVar))

        # Initiate event when client is detected
        self.handleNewDetectedClientEvent(detectedClient)

    # part of interface for Registered Client
    def updateWithNewDetectedClientData(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 updateWithNewDetectedClientData and init
    def handleNewDetectedClientEvent(self, detectedClient):
        self.lastRegisteredTime = time.time()
        self.detectedClient = detectedClient
        self.txPower = detectedClient.extraData['tx']
        self.beaconId = detectedClient.extraData['udid']
        self.incrementInternalClientEventCounts(detectedClient)

    def incrementInternalClientEventCounts(self, detectedClient):
        if self.collectionPointConfig['GatewayType'] == 'proximity':
            if self.collectionPointConfig[
                    'BtleRssiClientInThresholdType'] == 'rssi':
                # Are they in or are they out of range
                # Increment internal count, used to normalize events.
                if self.detectedClient.extraData[
                        'rssi'] >= self.collectionPointConfig[
                            'BtleRssiClientInThreshold']:
                    self.numClientInRange = self.numClientInRange + 1
                    self.numClientOutRange = 0
                    self.logger.debug("CLIENT IN RANGE>>>>>>>>>>>")

                elif self.detectedClient.extraData[
                        'rssi'] < self.__clientOutThresholdMin:
                    self.numClientOutRange = self.numClientOutRange + 1
                    #self.numClientInRange = 0
                    self.logger.debug("CLIENT OUT OF RANGE<<<<<<<<<<<")

    #part of interface for Registered Client
    def shouldSendClientInEvent(self):
        if self.collectionPointConfig['GatewayType'] == 'proximity':
            #e compare on seconds so we need to adjust this to seconds
            proximityEventIntervalInSeconds = (
                self.collectionPointConfig['ProximityEventInterval'] / 1000)

            timeDiff = math.trunc(time.time() - self.prevClientInMsgTime)
            # self.logger.debug("shouldSendClientInEvent timeDiff %f > %s" %(timeDiff,proximityEventIntervalInSeconds) )

            if timeDiff > proximityEventIntervalInSeconds:
                if self.numClientInRange > 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['ProximityEventInterval'] / 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.prevClientInMsgTime > 0:
                #check timing on last event sent
                #self.logger.debug("shouldSendClientOutEvent prevClientOutMsgTime=%f"%self.prevClientOutMsgTime)
                timeDiff = time.time() - self.prevClientOutMsgTime

                #have we sent a client out since the last client in?  if so we dont need to throw another
                if self.prevClientOutMsgTime < self.prevClientInMsgTime:
                    #do we have enought qualifying out events. we dont want to throw one too soon
                    if self.numClientOutRange >= 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.numClientOutRange > self.collectionPointConfig[
                            'BtleClientOutCountThreshold']:
                        # self.logger.debug("Client out count %i is past max.  Resetting." %self.numClientOutRange)
                        self.numClientOutRange = 0

            else:
                #lets check to see if we need to clean up the out count --- not sure this is the best idea
                if self.numClientOutRange > self.collectionPointConfig[
                        'BtleClientOutCountThreshold']:
                    # self.logger.debug("Client out count %i is past max.  Resetting." %self.numClientOutRange)
                    self.numClientOutRange = 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.prevClientOutMsgTime > 0:
                #was there a in event sent after the last out?
                if self.prevClientInMsgTime > self.prevClientOutMsgTime:
                    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.numClientOutRange = 0
        self.numClientInRange = 0

    def logClientEventSend(self, message):
        return
        # self.logger.debug("")
        # self.logger.debug("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
        # self.logger.debug("%%%%%%%%%%%%%%%%%% %s %%%%%%%%%%%%%%%%%%" %message)
        # self.logger.debug("UDID is %s " %self.getUdid())
        # self.logger.debug("Beacon ID is %s " %self.beaconId)
        # self.logger.debug("RSSI %i" %self.detectedClient.extraData['rssi'])
        # self.logger.debug("BTLE RSSI client in threshold %i" %self.collectionPointConfig['BtleRssiClientInThreshold'])
        # self.logger.debug("BTLE RSSI client out threshold %i" %self.__clientOutThresholdMin)
        # self.logger.debug("inCount %i : outCount %i" %(self.numClientInRange,self.numClientOutRange))
        # self.logger.debug("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
        # self.logger.debug("")

    #part of interface for Registered Client
    def getExtendedDataForEvent(self):
        extraData = {}
        extraData['lastRegisteredTime'] = self.lastRegisteredTime
        extraData['firstRegisteredTime'] = self.firstRegisteredTime
        extraData['prevClientInMsgTime'] = self.prevClientInMsgTime
        extraData['prevClientOutMsgTime'] = self.prevClientOutMsgTime
        extraData[
            'timeInCollectionPointInMilliseconds'] = self.timeInCollectionPointInMilliseconds
        extraData['rssi'] = self.detectedClient.extraData['rssi']
        extraData['averageRssi'] = self.detectedClient.extraData['rssi']
        extraData['txPower'] = self.getTxPower()
        extraData['beaconId'] = self.beaconId
        extraData['beaconMac'] = self.detectedClient.extraData["beaconMac"]
        extraData['industry'] = self.uidMap.get(self.beaconId)

        return extraData

    #part of interface for Registered Client
    def setClientInMessageSentToController(self):
        self.prevClientInMsgTime = time.time()
        self.numClientInRange = 0

    #part of interface for Registered Client
    def setClientOutMessageSentToController(self):
        self.prevClientOutMsgTime = time.time()
        self.numClientOutRange = 0