Esempio n. 1
0
 def handleBeacon(self, raw_message, timestamp=None, date=None):
     try:
         beacon = parse(raw_message, timestamp)
         self.logger.debug(
             'Receive beacon {aprs_type}, raw data: {raw_message}'.format(
                 **beacon))
         handlers = {
             'position': self.handlePosition,
             'status': self.handleStatus,
             'comment': self.handleComment,
             'server': self.handleServer,
             'position_weather': self.handleWeather,
         }
         func = handlers.get(
             beacon.get('aprs_type'),
             lambda beacon, date: self.logger.warning('aprs type ' + beacon[
                 'aprs_type'] + ' is unknown, beacon not handle.'))
         func(beacon, date)
     except ParseError as parsingError:
         # self.logger.error("Exception occurred", exc_info=True)
         self.logger.info(parsingError)
     except KeyboardInterrupt:
         self.logger.error('Keyboard interrupt')
         raise (KeyboardInterrupt)
     except:
         self.logger.exception(
             'Unexpected error when handling following aprs beacon {raw_message}'
             .format(**beacon))
Esempio n. 2
0
def process_beacon(raw_message, reference_date=None):
    from ogn.parser import parse, ParseError
    if raw_message[0] != '#':
        try:
            message = parse(raw_message, reference_date)
        except NotImplementedError as e:
            print('Received message: {}'.format(raw_message))
            print(e)
            return None
        except ParseError as e:
            print('Received message: {}'.format(raw_message))
            print('Drop packet, {}'.format(e.message))
            return None
        except TypeError as e:
            print('TypeError: {}'.format(raw_message))
            return None
        except Exception as e:
            print(raw_message)
            print(e)
            return None

        if message['aprs_type'] == 'status' or message[
                'beacon_type'] == 'receiver_beacon':
            return None
        else:
            subset_message = {
                k: message[k]
                for k in message.keys() & {
                    'name', 'address', 'timestamp', 'latitude', 'longitude',
                    'altitude', 'track', 'ground_speed', 'climb_rate',
                    'turn_rate'
                }
            }
            return subset_message
Esempio n. 3
0
def process_beacon(raw_message):
    # print("RAW:", raw_message)

    # accept only supported types of messages:
    if raw_message[:3] in ['OGN', 'FLR', 'ICA']:
        bp.enqueueForProcessing(raw_message)

    elif DEBUG:
        try:
            if raw_message[:3] in [
                    'PAW', 'RND'
            ]:  # # PAW (PilotAWare), RND(?) (not decided if they are worth processing yet)
                return

            beacon = parse(raw_message)
            if 'beacon_type' in beacon:
                bType = beacon['beacon_type']
                if bType in ['aprs_aircraft']:  # still an aircraft, right?
                    print('## ACFT BCN:', beacon)

                elif bType not in ('unknown', 'receiver', 'fanet',
                                   'aprs_receiver', 'pilot_aware',
                                   'flymaster'):
                    print('## TYPE:', bType, '\t\t', beacon)

        except AprsParseError:
            pass
Esempio n. 4
0
def string_to_message(raw_string, reference_date):
    global receivers

    try:
        message = parse(raw_string, reference_date)
    except NotImplementedError as e:
        app.logger.error(
            "No parser implemented for message: {}".format(raw_string))
        return None
    except ParseError as e:
        app.logger.error("Parsing error with message: {}".format(raw_string))
        return None
    except TypeError as e:
        app.logger.error("TypeError with message: {}".format(raw_string))
        return None
    except Exception as e:
        app.logger.error("Other Exception with string: {}".format(raw_string))
        return None

    # update reference receivers and distance to the receiver
    if message["aprs_type"] == "position":
        if message[
                "beacon_type"] in AIRCRAFT_BEACON_TYPES + RECEIVER_BEACON_TYPES:
            latitude = message["latitude"]
            longitude = message["longitude"]

            location = Location(longitude, latitude)
            message["location"] = location.to_wkt()
            location_mgrs = myMGRS.toMGRS(latitude, longitude).decode("utf-8")
            message["location_mgrs"] = location_mgrs
            message["location_mgrs_short"] = location_mgrs[
                0:5] + location_mgrs[5:7] + location_mgrs[10:12]

        if message[
                "beacon_type"] in AIRCRAFT_BEACON_TYPES and "gps_quality" in message:
            if message["gps_quality"] is not None and "horizontal" in message[
                    "gps_quality"]:
                message["gps_quality_horizontal"] = message["gps_quality"][
                    "horizontal"]
                message["gps_quality_vertical"] = message["gps_quality"][
                    "vertical"]
            del message["gps_quality"]

    # TODO: Fix python-ogn-client 0.91
    if "senders_messages" in message and message[
            "senders_messages"] is not None:
        message["senders_messages"] = int(message["senders_messages"])
    if "good_senders" in message and message["good_senders"] is not None:
        message["good_senders"] = int(message["good_senders"])
    if "good_and_bad_senders" in message and message[
            "good_and_bad_senders"] is not None:
        message["good_and_bad_senders"] = int(message["good_and_bad_senders"])

    return message
 def process_message(raw_message):
     if raw_message[0] == '#':
         return
     try:
         message = parse(raw_message)
         print("{}: {}".format(message['beacon_type'], raw_message))
     except NotImplementedError as e:
         print("{}: {}".format(e, raw_message))
         return
     if self.remaining_messages > 0:
         self.remaining_messages -= 1
     else:
         raise KeyboardInterrupt
 def process_message(raw_message):
     if raw_message[0] == '#':
         return
     try:
         message = parse(raw_message)
         print("{}: {}".format(message['beacon_type'], raw_message))
     except NotImplementedError as e:
         print("{}: {}".format(e, raw_message))
         return
     if self.remaining_messages > 0:
         self.remaining_messages -= 1
     else:
         raise KeyboardInterrupt
Esempio n. 7
0
def process_beacon(raw_message):
    global db
    db_check_connect()
    try:
        beacon = parse(raw_message)
        if beacon['aprs_type']=='position' and beacon['beacon_type']=='aprs_aircraft':
            beacon['timestamp'] = calendar.timegm(beacon['timestamp'].timetuple())
            beacon['reference_timestamp'] = calendar.timegm(beacon['reference_timestamp'].timetuple())

            print(beacon)
            db.execute("INSERT INTO positions VALUES (null, :name, :timestamp, :reference_timestamp, :latitude, :longitude, :climb_rate, :turn_rate, :ground_speed, :altitude)", beacon)
            db_commit()

    except Exception as e:
        print('Error, {}'.format(e))
Esempio n. 8
0
def initial_file_scan(file):
    """Scan file and get rowcount and first server timestamp."""

    row_count = 0
    timestamp = None

    for row in file:
        row_count += 1
        if timestamp is None and row[0] == '#':
            message = parse(row)
            if message['aprs_type'] == 'server':
                timestamp = message['timestamp']

    file.seek(0)
    return row_count, timestamp
Esempio n. 9
0
    def _processMessage(self, raw_message: str):
        beacon = None
        try:
            beacon = parse(raw_message)
            if not beacon or 'beacon_type' not in beacon.keys(
            ) or beacon['beacon_type'] != 'aprs_aircraft':
                return

        except ParseError as e:
            # print('[ERROR] when parsing a beacon: {}'.format(e.message))
            # print("Failed BEACON:", raw_message)
            return

        except Exception as e:
            # print('[ERROR] {}'.format(e))
            # if beacon:
            #     print("Failed BEACON:", beacon)
            return

        self.numProcessed += 1

        # we are not interested in para, baloons, uavs and other crazy flying stuff:
        aircraftType = beacon['aircraft_type']
        if aircraftType not in [1, 2, 6, 8, 9]:
            return

        dt = beacon['timestamp'].replace(tzinfo=pytz.UTC)
        ts = round(dt.timestamp())  # [s]
        now = datetime.utcnow().replace(tzinfo=pytz.UTC)
        if ts - now.timestamp(
        ) > 30:  # timestamp from the future? We'll 30s time offset at most..
            print(f"[WARN] Timestamp from the future: {dt}, now is {now}")
            return

        address = beacon['address']
        lat = beacon['latitude']
        lon = beacon['longitude']
        altitude = int(beacon['altitude'])
        groundSpeed = beacon['ground_speed']
        verticalSpeed = beacon['climb_rate']
        turnRate = beacon['turn_rate']
        if not turnRate:
            turnRate = 0

        # get altitude above ground level (AGL):
        agl = self._getAgl(lat, lon, altitude)

        # insert into influx:
        # pos ~ position, vs = vertical speed, tr = turn rate
        if groundSpeed >= 10 and 0 <= agl < 128000:  # 10 km/h threshold
            q = f"pos,addr={address} lat={lat:.6f},lon={lon:.6f},alt={altitude:.0f},gs={groundSpeed:.2f},vs={verticalSpeed:.2f},tr={turnRate:.2f},agl={agl:.0f} {ts}000000000"
            self.influxDb.addStatement(q)

        prevStatus: Status = None
        statusKey = f"{address}-status"
        ps = self._getFromRedis(statusKey)
        if ps:
            try:
                prevStatus = Status.parse(ps)
            except ValueError as e:
                print('[ERROR] when parsing prev. status: ', e)

        gsKey = f"{address}-gs"

        if not prevStatus:  # we have no prior information
            self._saveToRedis(statusKey, Status(
                s=0, ts=ts))  # 0 = on ground, 1 = airborne, -1 = unknown
            self._saveToRedis(gsKey, 0, 120)  # gs = 0
            return

        prevGroundSpeed = float(self._getFromRedis(gsKey, 0))

        # filter speed change a bit (sometimes there are glitches in speed with badly placed gps antenna):
        groundSpeed = groundSpeed * 0.6 + prevGroundSpeed * 0.4
        self._saveToRedis(gsKey, groundSpeed, 3600)

        currentStatus: Status = Status(
            ts=ts,
            s=0 if
            groundSpeed < getGroundSpeedThreshold(aircraftType, forEvent='T')
            else 1)  # 0 = on ground, 1 = airborne, -1 = unknown

        if prevStatus.s == 0:  # 0 = on ground, 1 = airborne, -1 = unknown
            currentStatus.s = 1 if groundSpeed > getGroundSpeedThreshold(
                aircraftType, forEvent='T') else 0
        else:  # when airborne
            currentStatus.s = 0 if groundSpeed < getGroundSpeedThreshold(
                aircraftType, forEvent='L') else 1

        if currentStatus.s != prevStatus.s:
            addressType = beacon['address_type']
            addressTypeStr = self.ADDRESS_TYPES.get(addressType, 'X')

            event = 'L' if currentStatus.s == 0 else 'T'  # L = landing, T = take-off
            flightTime = 0

            if event == 'L':
                flightTime = currentStatus.ts - prevStatus.ts  # [s]
                if flightTime < 120:  # [s]
                    return

                if flightTime > 12 * 3600:  # some relic from the previous day
                    self.redis.delete(statusKey)
                    self.redis.delete(gsKey)
                    return

                # check altitude above ground level:
                if agl and agl > 150:  # [m]
                    return  # most likely a false detection

            # if event == 'T':
            #     # check altitude above ground level:
            #     agl = self._getAgl(lat, lon, altitude)
            #     if agl and agl < 50:  # [m]
            #         return  # most likely a false detection

            icaoLocation = self.airfieldManager.getNearest(lat, lon)

            dt = datetime.fromtimestamp(ts)
            dtStr = dt.strftime('%H:%M:%S')
            print(
                f"[INFO] event: {dtStr}; {icaoLocation}; [{addressTypeStr}] {address}; {event}; {flightTime}"
            )

            icaoLocation = f"'{icaoLocation}'" if icaoLocation else 'null'

            strSql = f"INSERT INTO logbook_events " \
                f"(ts, address, address_type, aircraft_type, event, lat, lon, location_icao, flight_time) " \
                f"VALUES " \
                f"({ts}, '{address}', {addressType}, '{aircraftType}', " \
                f"'{event}', {lat:.5f}, {lon:.5f}, {icaoLocation}, {flightTime});"

            # print('strSql:', strSql)

            self.dbThread.addStatement(strSql)

        self._saveToRedis(
            statusKey, currentStatus
        )  # even if the status is the same - do not let the key to expire(!)
Esempio n. 10
0
        ix = packet_str.find('>')
        cc = packet_str[0:ix]
        packet_str = cc.upper() + packet_str[
            ix:]  # convert the ID to uppercase
        msg = {}

        # if not a heartbeat from the server
        if len(packet_str) > 0 and packet_str[0] != "#" and packet_str[
                ix + 1:ix + 7] != "OGNFNT":
            #########################################################################################
            # deal with a normal APRS message
            s = packet_str
            ph = s.find(":>")
            hora = s[ph + 2:ph + 9]  # get the hora as: hhmmssh
            try:
                beacon = parse(s)  # parse the APRS message
            except Exception as e:
                print("DLY: parse error >>>>", e, s, "<<<<\n", file=sys.stderr)
                continue  # nothing else to do !!

                # check if it is a OGN tracker status messagea
            #if beacon["dstcall"] == "OGNTTN":
            #print ("\n\nBBB", beacon, "\n\n")

            if beacon["aprs_type"] == "status" and (
                    beacon["beacon_type"] == "tracker" or beacon["beacon_type"]
                    == "unknown") and (beacon["dstcall"] == "OGNTRK"
                                       or beacon["dstcall"] == "OGTTN2"
                                       or beacon['dstcall'] == "OGOBS"):
                comment = s[ph + 10:]  # get the comment where it is the data
                #print ("CCC:", comment.rstrip(" \n\r"), ":", len(comment), s)
Esempio n. 11
0
    def _processMessage(self, raw_message: str):
        beacon = None
        try:
            beacon = parse(raw_message)
            if not beacon or 'aprs_type' not in beacon.keys() or (beacon.get(
                    'aprs_type', None) != 'position'):
                # print('[WARN] cannot process:', raw_message)
                # print('bt:', beacon.get('beacon_type', None), str(beacon))
                return

        except ParseError as e:
            # print(f'[ERROR] when parsing a beacon: {str(e)}', raw_message, file=sys.stderr)
            return

        except Exception as e:
            # print(f'[ERROR] Some other error in _processMessage() {str(e)}', raw_message, file=sys.stderr)
            return

        self.numProcessed += 1

        addressType = beacon.get('address_type',
                                 1)  # 1 = icao, 2 = flarm, 3 = ogn
        addressTypeStr = ADDRESS_TYPES.get(addressType, 'X')
        aircraftType = beacon.get(
            'aircraft_type', 8)  # icao-crafts are often 'powered aircraft's

        if 'address' not in beacon:
            address = beacon['name'][3:]
            beacon['address_type'] = 1
        else:
            address = beacon['address']

        # we are not interested in para, baloons, uavs and other crazy flying stuff:
        if aircraftType not in [1, 2, 6, 8, 9, 10]:
            return

        dt = beacon['timestamp'].replace(tzinfo=pytz.UTC)
        ts = round(dt.timestamp())  # UTC [s]
        now = datetime.utcnow().replace(tzinfo=pytz.UTC)
        if ts - now.timestamp(
        ) > 30:  # timestamp from the future? We'll 30s time offset at most..
            # print(f"[WARN] Timestamp from the future: {dt}, now is {now}")
            return

        lat = beacon.get('latitude') or None  # [deg]
        lon = beacon.get('longitude') or None  # [deg]
        altitude = int(beacon.get('altitude')) or 0  # [m]
        groundSpeed = beacon.get('ground_speed') or 0  # [km/h]
        verticalSpeed = beacon.get('climb_rate') or 0  # [m/s]
        turnRate = beacon.get('turn_rate') or 0  # [deg/s]

        if addressType == 1 and groundSpeed > 400:  # ignore fast (icao) airliners and jets
            return

        # get altitude above ground level (AGL):
        agl = self._getAgl(lat, lon, altitude)  # [m]

        # insert into influx:
        # pos ~ position, vs = vertical speed, tr = turn rate
        if agl is None or agl < 128000:  # groundSpeed > 0 and
            aglStr = 0 if agl is None else f"{agl:.0f}"
            q = f"pos,addr={ADDRESS_TYPE_PREFIX[addressType]}{address} lat={lat:.6f},lon={lon:.6f},alt={altitude:.0f},gs={groundSpeed:.2f},vs={verticalSpeed:.2f},tr={turnRate:.2f},agl={aglStr} {ts}000000000"
            self.influxDb.addStatement(q)

        prevStatus: Status = None
        statusKey = f"{addressTypeStr}{address}-status"
        ps = self._getFromRedis(statusKey)
        if ps:
            try:
                prevStatus = Status.parse(ps)
            except ValueError as e:
                print('[ERROR] when parsing prev. status: ', e)

        gsKey = f"{addressTypeStr}{address}-gs"

        if not prevStatus:  # we have no prior information
            self._saveToRedis(statusKey, Status(
                s=0, ts=ts))  # 0 = on ground, 1 = airborne, -1 = unknown
            self._saveToRedis(gsKey, 0, 120)  # gs = 0
            return

        prevGroundSpeed = float(self._getFromRedis(gsKey, 0))
        if prevGroundSpeed > 0:
            # filter speed change a bit (sometimes there are glitches in speed with badly placed gps antenna):
            groundSpeed = groundSpeed * 0.7 + prevGroundSpeed * 0.3

        self._saveToRedis(gsKey, groundSpeed, 3600)

        currentStatus: Status = Status(
            ts=ts, s=-1)  # 0 = on ground, 1 = airborne, -1 = unknown

        if prevStatus.s == 0:  # 0 = on ground, 1 = airborne, -1 = unknown
            currentStatus.s = 1 if groundSpeed >= getGroundSpeedThreshold(
                aircraftType, forEvent='T') else 0
        else:  # when airborne
            currentStatus.s = 0 if groundSpeed <= getGroundSpeedThreshold(
                aircraftType, forEvent='L') else 1

        if currentStatus.s != prevStatus.s:
            event = 'L' if currentStatus.s == 0 else 'T'  # L = landing, T = take-off
            flightTime = 0

            if event == 'L':
                flightTime = currentStatus.ts - prevStatus.ts  # [s]
                if flightTime < 120:  # [s]
                    return

                if flightTime > 12 * 3600:  # some relic from the previous day
                    self.redis.delete(statusKey)
                    self.redis.delete(gsKey)
                    return

                # check altitude above ground level:
                if agl and agl > AGL_LANDING_LIMIT:  # [m]
                    return  # most likely a false detection

            elif event == 'T':
                # check altitude above ground level:
                if agl is not None and agl < 50:  # [m]
                    return  # most likely a false detection

            self._saveToRedis(statusKey, currentStatus)

            icaoLocation = self.airfieldManager.getNearest(lat, lon)

            dt = datetime.fromtimestamp(ts)
            dtStr = dt.strftime('%H:%M:%S')
            print(
                f"[INFO] event: {dtStr}; {icaoLocation}; [{addressTypeStr}] {address}; {event}; {flightTime}"
            )

            icaoLocation = f"'{icaoLocation}'" if icaoLocation else 'null'

            strSql = f"INSERT INTO logbook_events " \
                f"(ts, address, address_type, aircraft_type, event, lat, lon, location_icao, flight_time) " \
                f"VALUES " \
                f"({ts}, '{address}', '{addressTypeStr}', '{aircraftType}', " \
                f"'{event}', {lat:.5f}, {lon:.5f}, {icaoLocation}, {flightTime});"

            # print('strSql:', strSql)

            self.dbThread.addStatement(strSql)
Esempio n. 12
0
    def _processMessage(self, raw_message: str):
        beacon = None
        try:
            beacon = parse(raw_message)
            if not beacon or 'beacon_type' not in beacon.keys(
            ) or beacon['beacon_type'] != 'aprs_aircraft':
                return

        except ParseError as e:
            # print('[ERROR] when parsing a beacon: {}'.format(e.message))
            # print("Failed BEACON:", raw_message)
            return

        except Exception as e:
            # print('[ERROR] {}'.format(e))
            # if beacon:
            #     print("Failed BEACON:", beacon)
            return

        # we are not interested in para, baloons, uavs, static stuff and others:
        aircraftType = beacon['aircraft_type']
        if aircraftType in [4, 6, 7, 13, 11, 15, 16]:
            return

        address = beacon['address']
        groundSpeed = beacon['ground_speed']
        ts = round(beacon['timestamp'].timestamp())  # [s]
        # print(f"[INFO] {address} gs: {groundSpeed:.0f}")

        # print('[DEBUG] Gps H:', beacon['gps_quality']['horizontal'])

        currentStatus: Status = Status(ts=ts)
        currentStatus.s = 0 if groundSpeed < SPEED_THRESHOLD else 1  # 0 = on ground, 1 = airborne, -1 = unknown
        # TODO add AGL check (?)
        # TODO threshold by aircraftType

        prevStatus: Status = None
        statusKey = f"{address}-status"
        ps = self.redis.get(statusKey)
        if ps:
            try:
                prevStatus = Status.parse(ps)
            except ValueError as e:
                print('[ERROR] when parsing prev. status: ', e)

        if not prevStatus:  # we have no prior information
            self._saveToRedis(statusKey, currentStatus)
            return

        if currentStatus.s != prevStatus.s:
            addressType = beacon['address_type']
            aircraftType = beacon['aircraft_type']
            lat = beacon['latitude']
            lon = beacon['longitude']

            icaoLocation = AirfieldManager().getNearest(lat, lon)
            if not icaoLocation:
                return

            event = 'L' if currentStatus.s == 0 else 'T'  # L = landing, T = take-off
            flightTime = 0
            if event == 'L':
                flightTime = currentStatus.ts - prevStatus.ts  # [s]
                if flightTime < 60:
                    return

            self._saveToRedis(statusKey, currentStatus)

            dt = datetime.fromtimestamp(ts)
            dtStr = dt.strftime('%H:%M:%S')
            print(
                f"[INFO] {dtStr}; {icaoLocation}; {address}; {event}; {flightTime}"
            )

            strSql = f"INSERT INTO logbook_events " \
                f"(ts, address, address_type, aircraft_type, event, lat, lon, location_icao, flight_time) " \
                f"VALUES " \
                f"({ts}, '{address}', {addressType}, '{aircraftType}', " \
                f"'{event}', {lat:.5f}, {lon:.5f}, '{icaoLocation}', {flightTime});"

            # print('strSql:', strSql)

            self.dbThread.addStatement(strSql)
Esempio n. 13
0
    def add(self, raw_string):
        try:
            message = parse(raw_string,
                            reference_timestamp=self.reference_timestamp)
        except NotImplementedError as e:
            current_app.logger.error(
                "No parser implemented for message: {}".format(raw_string))
            return
        except ParseError as e:
            current_app.logger.error(
                "Parsing error with message: {}".format(raw_string))
            return
        except TypeError as e:
            current_app.logger.error(
                "TypeError with message: {}".format(raw_string))
            return
        except Exception as e:
            current_app.logger.error(
                "Other Exception with string: {}".format(raw_string))
            return

        if message['aprs_type'] not in ('server', 'position'):
            return

        elif message[
                'aprs_type'] == 'server' and self.auto_update_timestamp is True:
            self.reference_timestamp = message['timestamp']
            return

        elif message['aprs_type'] == 'position':
            latitude = message["latitude"]
            longitude = message["longitude"]

            location = Location(longitude, latitude)
            message["location"] = location.to_wkt()

            location_mgrs = self.mgrs.toMGRS(latitude,
                                             longitude).decode("utf-8")
            message["location_mgrs"] = location_mgrs
            message["location_mgrs_short"] = location_mgrs[
                0:5] + location_mgrs[5:7] + location_mgrs[10:12]

            if "aircraft_type" in message:
                message["aircraft_type"] = AircraftType(
                    message["aircraft_type"]
                ).name if message["aircraft_type"] in AircraftType.list(
                ) else AircraftType.UNKNOWN.name

            if "gps_quality" in message:
                if message[
                        "gps_quality"] is not None and "horizontal" in message[
                            "gps_quality"]:
                    message["gps_quality_horizontal"] = message["gps_quality"][
                        "horizontal"]
                    message["gps_quality_vertical"] = message["gps_quality"][
                        "vertical"]
                del message["gps_quality"]

        if message["beacon_type"] in RECEIVER_BEACON_TYPES:
            complete_message = ",".join([
                str(message[k])
                if k in message and message[k] is not None else "\\N"
                for k in BEACON_KEY_FIELDS + RECEIVER_BEACON_FIELDS
            ])
            self.receiver_buffer.write(complete_message)
            self.receiver_buffer.write("\n")
        elif message["beacon_type"] in AIRCRAFT_BEACON_TYPES:
            complete_message = ",".join([
                str(message[k])
                if k in message and message[k] is not None else "\\N"
                for k in BEACON_KEY_FIELDS + AIRCRAFT_BEACON_FIELDS
            ])
            self.aircraft_buffer.write(complete_message)
            self.aircraft_buffer.write("\n")
        else:
            current_app.logger.error("Ignore beacon_type: {}".format(
                message["beacon_type"]))
            return

        if datetime.utcnow() - self.last_flush >= timedelta(seconds=5):
            self._flush()
            self.last_flush = datetime.utcnow()