Exemple #1
0
    def test_unicode(self):
        _unicode = str if sys.version_info[0] >= 3 else unicode

        # 7bit ascii
        result = parse("A>B:>status")

        self.assertIsInstance(result['status'], _unicode)
        self.assertEqual(result['status'], _u("status"))

        # string with degree sign
        result = parse("A>B:>status\xb0")

        self.assertIsInstance(result['status'], _unicode)
        self.assertEqual(result['status'], _u("status\xb0", 'latin-1'))

        # str with utf8
        result = parse("A>B:>статус")

        self.assertIsInstance(result['status'], _unicode)
        self.assertEqual(result['status'], _u("статус"))

        # unicode input
        result = parse(_u("A>B:>статус"))

        self.assertIsInstance(result['status'], _unicode)
        self.assertEqual(result['status'], _u("статус"))
Exemple #2
0
    def test_unicode(self):
        _unicode = str if sys.version_info[0] >= 3 else unicode

        # 7bit ascii
        result = parse("A>B:>status")

        self.assertIsInstance(result['status'], _unicode)
        self.assertEqual(result['status'], _u("status"))

        # string with degree sign
        result = parse("A>B:>status\xb0")

        self.assertIsInstance(result['status'], _unicode)
        self.assertEqual(result['status'], _u("status\xb0", 'latin-1'))

        # str with utf8
        result = parse("A>B:>статус")

        self.assertIsInstance(result['status'], _unicode)
        self.assertEqual(result['status'], _u("статус"))

        # unicode input
        result = parse(_u("A>B:>статус"))

        self.assertIsInstance(result['status'], _unicode)
        self.assertEqual(result['status'], _u("статус"))
Exemple #3
0
    def test_empty_body_of_format_that_is_not_status(self):
        self.assertRaises(ParseError, parse, "A>B:!")

        try:
            parse("A>B:>")
        except:
            self.fail("empty status packet shouldn't raise exception")
Exemple #4
0
    def test_empty_body_of_format_that_is_not_status(self):
        self.assertRaises(ParseError, parse, "A>B:!")

        try:
            parse("A>B:>")
        except:
            self.fail("empty status packet shouldn't raise exception")
Exemple #5
0
    def test_message_format_branch(self):
        self.m.StubOutWithMock(parsing, "parse_message")
        parsing.parse_message("test").AndReturn(('', {'format': ''}))
        self.m.ReplayAll()

        parse("A>B::test")

        self.m.VerifyAll()
Exemple #6
0
    def test_message_format_branch(self):
        self.m.StubOutWithMock(parsing, "_parse_message")
        parsing._parse_message("test").AndReturn(('', {'format': ''}))
        self.m.ReplayAll()

        parse("A>B::test")

        self.m.VerifyAll()
Exemple #7
0
    def test_unsupported_formats_raising(self):
        with self.assertRaises(UnknownFormat):
            for packet_type in '#$%)*,<?T[_{':
                packet = "A>B:%saaa" % packet_type

                try:
                    parse(packet)
                except UnknownFormat as exp:
                    self.assertEqual(exp.packet, packet)
                    raise
Exemple #8
0
    def test_mice_format_branch(self):
        self.m.StubOutWithMock(parsing, "_parse_mice")
        parsing._parse_mice("B", "test").AndReturn(('', {'format': ''}))
        parsing._parse_mice("D", "test").AndReturn(('', {'format': ''}))
        self.m.ReplayAll()

        parse("A>B:`test")
        parse("C>D:'test")

        self.m.VerifyAll()
Exemple #9
0
    def test_unsupported_formats_raising(self):
        with self.assertRaises(UnknownFormat):
            for packet_type in '#$%)*,<?T[_{}':
                packet = "A>B:%saaa" % packet_type

                try:
                    parse(packet)
                except UnknownFormat as exp:
                    self.assertEqual(exp.packet, packet)
                    raise
Exemple #10
0
    def test_mice_format_branch(self):
        self.m.StubOutWithMock(parsing, "parse_mice")
        parsing.parse_mice("B", "test").AndReturn(('', {'format': ''}))
        parsing.parse_mice("D", "test").AndReturn(('', {'format': ''}))
        self.m.ReplayAll()

        parse("A>B:`test")
        parse("C>D:'test")

        self.m.VerifyAll()
Exemple #11
0
    def to_readable_output(self, serialized_packet):
        """Converts the decoded, but serialized packet to a clean, readable
        output. Intended for human readability.

        Args:
            serialized_packet: The raw, decoded APRS packet string.
        """
        try:
            packet = aprslib.parse(serialized_packet)

            table_data = [[
                "From     ", "To       ", "Lat     ", "Long    ", "Alt     ",
                "Comment                    ", "Text                       "
            ],
                          [
                              self.__get_formatted(packet, 'from', 9),
                              self.__get_formatted(packet, 'to', 9),
                              self.__get_formatted(packet, 'latitude', 8),
                              self.__get_formatted(packet, 'longitude', 8),
                              self.__get_formatted(packet, 'altitude', 8),
                              self.__get_formatted(packet, 'comment', 27),
                              self.__get_formatted(packet, 'text', 27),
                          ]]
            table_instance = AsciiTable(table_data, ' Packet ')
            table_instance.inner_heading_row_border = False
            table_instance.inner_row_border = True
            return '\n' + table_instance.table
        except (aprslib.ParseError, aprslib.UnknownFormat):
            return serialized_packet
 def checkPacket(self, packet):
     if packet.decode('latin-1')[0] == '#':
         # Client Banner
         self.logger.info("FWD:  %s (station status)" %
                          packet.decode('latin-1'))
         return True
     else:
         try:
             parsed = parse(packet)
             if parsed['from'] in self.trackable:
                 self.logger.info("FWD:  %s" % packet.decode('utf-8'))
                 return True
             else:
                 self.logger.info("DROP: %s (noTrack)" %
                                  packet.decode('utf-8'))
                 return False
         except ParseError:
             if packet.startswith(b'user'):
                 # Login phrase detected
                 callsign = packet.split(b' ')[1].decode('latin-1')
                 self.logger.info("Detected own callsign: %s" % callsign)
                 self.callsigns.append(callsign)
                 self.trackable.append(callsign)
                 return True
             else:
                 self.logger.info("DROP: %s (invalid packet)" %
                                  packet.decode('utf-8'))
                 return False
def test_underscore(header):
    logger.info(u"Test: test_underscore")
    failures = list()
    test_fields = list([u"Humidity", u"Pressure", u'Rain_1H', u"Rain_24H", u"Rain_Since_Midnight",
                        u"Temperature", u"Wind_Direction", u"Wind_Gust", u"Wind_Speed"])

    value_fields = list()
    value_fields.append([64, 1016.0, 0, 21.844, 0.0, 30.0, 359, 0.0, 0.0])
    value_fields.append([99, 1018.2, 0.0, 21.844, 8.89, 23.8, 359, 0, 0])

    test_message = list()
    test_message.append(u"_05311550c359s000g000t086r000p086P000h64b10160tU2k")
    test_message.append(u"_05312040c359s000g000t075r000p086P035h99b10182tU2k")

    for m, footer in enumerate(test_message):
        logger.debug(u"Footer         : .{}.".format(footer))
        logger.debug(u"Header         : .{}.".format(header))

        header_fields, aprs_addresses = parse_aprs_header(header, footer)
        logger.debug(u"header_fields  : .{}.".format(header_fields))
        logger.debug(u"aprs_addresses : .{}.".format(aprs_addresses))

        fields = aprslib.parse(aprs_addresses)
        fields[u"Message_Type"] = u"_"
        fields.update(header_fields)

        nf = {k.title(): v for k, v in fields[u"weather"].items()}
        del fields[u"weather"]
        nfa = {k.title(): v for k, v in nf.items()}
        cf = check_fields(value_fields[m], nfa)

        assert cf is True
 def checkPacket(self, packet):
     if packet.decode('latin-1')[0] == '#':
         # Client Banner
         self.logger.info("FWD:  %s (station status)" % packet.decode('latin-1'))
         return True
     else:
         try:
             parsed = parse(packet)
             if parsed['from'] in self.trackable:
                 self.logger.info("FWD:  %s" % packet.decode('utf-8'))
                 return True
             else:
                 self.logger.info("DROP: %s (noTrack)" % packet.decode('utf-8'))
                 return False
         except ParseError:
             if packet.startswith(b'user'):
                 # Login phrase detected
                 callsign = packet.split(b' ')[1].decode('latin-1')
                 self.logger.info("Detected own callsign: %s" % callsign)
                 self.callsigns.append(callsign)
                 self.trackable.append(callsign)
                 return True
             else:
                 self.logger.info("DROP: %s (invalid packet)" % packet.decode('utf-8'))
                 return False
Exemple #15
0
def callback(packet):
  global thread_pool

  msg = aprslib.parse(packet)
  #print "Receive:"
  #print msg
  callfrom = msg['from'] + "      "
  callfrom = callfrom[0:9]
  if msg['format'] == 'message':
    m = re.search(r'ack(\d+)',msg['message_text'])
    if m :
      if callfrom in thread_pool:
        (th,ackl) = thread_pool[callfrom]
        thread_pool.update({callfrom:(th,ackl + [int(m.group(1))])})
        #print "thread pool ack" + m.group(1)
      return
    else:
      if 'msgNo' in msg :
        #print "send ack"
        send_ack(callfrom,msg['msgNo'])
      if callfrom in thread_pool:
        #print "thread exist"
        #print thread_pool
        return
      else:
        th = Send_spot(callfrom,AIS)
        th.start()
        thread_pool.update({callfrom:(th,[])})
Exemple #16
0
    def parse(self, content):
        soup = BeautifulSoup(content, 'html.parser')
        results = soup.get_text().rstrip().splitlines()[-1]
        aprsData = aprslib.parse(results)
        weatherData = aprsData['weather']
        weatherData.update({
            'measure_time':
            datetime.datetime.fromtimestamp(int(
                aprsData['timestamp'])).strftime('%H:%M')
        })
        weatherData.update({
            'measure_date':
            datetime.datetime.fromtimestamp(int(
                aprsData['timestamp'])).strftime('%d/%m/%Y')
        })
        dew = (float(weatherData['humidity']) / 100)**(1.0 / 8.0) * (
            112.0 + 0.9 * float(weatherData['temperature'])) + 0.1 * float(
                weatherData['temperature']) - 112
        weatherData.update({'dew_point': dew})

        data = {}
        for k, i in self.data_map.iteritems():
            value = str(weatherData[k])
            value = self._clean(value, i[1])
            data[i[0]] = value
        return data
def get_aprs_json(filename):

    if not os.path.exists(filename):
        return None

    aprs_json = []
    # Foreach line
    for line in open(filename):
        if not "[Duplicate" in line: # strip duplicates

        # Extract time and packet
            match = time_packet.match(line)
            if match is not None:
                time = match.group(1)
                packet = match.group(2)

                # Process time
                dt = datetime.strptime(time, '%Y-%m-%d %H:%M:%S')

                # Process packet
                pkt = aprslib.parse(packet)

                if 'latitude' in pkt and 'longitude' in pkt and 'altitude' in pkt: # valid position packet
                    # construct data
                    data = {
                        'date': dt.strftime("%y%m%d"),
                        'time': dt.strftime("%H:%M:%S"),
                        'latitude': pkt['latitude'],
                        'longitude': pkt['longitude'],
                        'altitude': pkt['altitude'],
                        '_parsed': {
                            'time_parsed': time
                        },
                    }

                    path_index = 1
                    rx_call = pkt['path'][-path_index]
                    while rx_call.startswith('T2'):
                        path_index = path_index + 1
                        rx_call = pkt['path'][-path_index]

                    # construct receivers
                    receivers = {
                        rx_call: {}
                    }

                    # construct doc
                    doc = {
                        'data': data,
                        'receivers': receivers,
                    }

                    aprs_json.append({
                        'doc': doc
                    })
                else:           # not a valid position packet. ignore for now
                    False

    return aprs_json
Exemple #18
0
    def parseString(self):

        try:
            self.aprsDat = aprslib.parse(self.aprsString)

        except (aprslib.ParseError, aprslib.UnknownFormat) as exp:
            logging.error(exp)
            return False
Exemple #19
0
def parse_aprs_packet(packet, callsign):
    """Parses APRS packets and returns desired info."""
    parsed = aprslib.parse(packet)
    lat = parsed['latitude']
    lon = parsed['longitude']
    alt = parsed['altitude']
    timestamp = parsed['timestamp']
    print(lat, lon, alt, timestamp)
    return(lat, lon, alt, timestamp)
Exemple #20
0
def parse_aprs_packet(packet, callsign):
    """Parses APRS packets and returns desired info."""
    parsed = aprslib.parse(packet)
    lat = parsed['latitude']
    lon = parsed['longitude']
    alt = parsed['altitude']
    timestamp = parsed['timestamp']
    print(lat, lon, alt, timestamp)
    return (lat, lon, alt, timestamp)
Exemple #21
0
    def parse_packet(self, packet):
        parsed_packet = None
        f_packet = self.reformat_packet(packet)

        try:
            parsed_packet = aprslib.parse(f_packet)
        except (aprslib.exceptions.UnknownFormat):
            # print('INFO: Undecodable Message: {}'.format(f_packet))
            pass
        return parsed_packet
Exemple #22
0
def callback(packet):
    try:
        decodiert = aprslib.parse(packet)
        stn = (decodiert['latitude'], decodiert['longitude'])
        print(time.strftime('%H:%M:%S'), decodiert['from'], "\t",
              round(distance.distance(home, stn).km, 1), "km")
    except (KeyError, UnicodeDecodeError, aprslib.ParseError,
            aprslib.UnknownFormat
            ) as e:  # UnknownFormat("format is not supported")
        print("cant parse:", e, " mit ->", packet, "<-")
        pass
def test_MicE(header, footer, rows=100):
    header_fields, aprs_addresses = parse_aprs_header(header, footer)

    try:
        logger.info(u"10 eMic Format")
        fields = aprslib.parse(aprs_addresses)
        fields[u"Message_Type"] = u"MicE"
        fields[u"longitude"] = u"{:6.2f}W".format(fields[u"longitude"])
        fields[u"latitude"] = u"{:6.2f}N".format(fields[u"latitude"])
        fields.update(header_fields)

    except Exception, msg:
        logger.error(u"Parse Error: {}".format(msg))
Exemple #24
0
    def parse(self, aprs_packet):
        """
        Takes in a raw APRS packet and returns a parsed APRS data

        :param aprs_packet:  Raw APRS data (str)
        :return: Parsed APRS data (dict)
        """

        try:
            return aprslib.parse(aprs_packet.strip())
        except (aprslib.ParseError, aprslib.UnknownFormat) as error:
            self.error_log.error(traceback.format_exc())
            traceback.print_exc(file=sys.stdout)
Exemple #25
0
    def decode_packet(self, *args, **kwargs):
        """We get a frame, which has to be decoded."""
        frame = kwargs["frame"]
        LOG.debug(f"Got an APRS Frame '{frame}'")
        # try and nuke the * from the fromcall sign.
        frame.header._source._ch = False
        payload = str(frame.payload.decode())
        msg = f"{str(frame.header)}:{payload}"
        # msg = frame.tnc2
        LOG.debug(f"Decoding {msg}")

        packet = aprslib.parse(msg)
        return packet
Exemple #26
0
def aprs_parse(packet, settings):
    #    print "aprs_parse called: ", packet
    try:
        p_dict = aprslib.parse(packet)
        res = check_parse(p_dict, settings)
        if res == False:
            return False
    except ParseError as msg:
        print "aprs_parse failed: ", packet
        return False


#    print "aprs_parse worked"
    return res
Exemple #27
0
def callback(packet):
    try:
        obj = aprslib.parse(packet)
        print(obj)
        if obj['format'] == 'message' and obj['addresse'] == callsign:
            spec = obj['message_text'].split('{')
            if len(spec) == 2:
                line = callsign + '>' + dst + ',TCPIP*::' + antitrim(obj['from'], ' ', 9) + ':ack'\
                       + spec[-1].replace('}', '')
                AIS.sendall(line)
            obj['message_text'] = spec[0]
            respond(obj)
    except aprslib.ParseError as exp:
        print(packet)
Exemple #28
0
	def filter_callsigns(self, packet, packet_i = -1):
		if self.verbose:
			print('raw packet : ', packet)
		if len(packet) == 0:
			return
		try:
			ppac = aprslib.parse(packet)
			if _DEBUG or _LOG_ALL:
				with open(os.path.join(tempfile.gettempdir(), 'aprs2gpaero_all_packet.log'), 'a') as f:
					# termination chosen so that i can use the file for debugging 
					f.write(packet+'\r\n')
			if self.verbose:
				print 'parsed :\n', ppac
			# the form below is useful for debuggging, but in reality we need exact matches since we need to translate to IMEI values.
			if any([ppac['from'].startswith(x) for x in self.ids_to_be_tracked.keys()]):
				# we should drop duplicate packets, or those that are too frequent to be real.
				# ideally, the packets should have a time stamp; tinytrak has this, and likely others, but it's optional.
				# check if we've seen this packet recently, and if so, drop it
				# however, we can't look at the raw packet, since we could have gotten it from a different source, which is what we're trying to deduplicate.
				# i can't gaurantee that we had an independent time stamp, so we'll just use the location information;
				# this of couse is not guaranteed unitque, but i'm willing to accept the potential loss if one of the last few packets match exactly.
				short_packet_data = '{:} {:} {:}'.format(ppac['longitude'], ppac['latitude'], ppac.get('altitude', 0))
				# get timestamp from packet, if included - not common.
				timestamp = ppac.get('timestamp', time.time())
				if short_packet_data in self.recent_packets.get(ppac['from'], []):
					self.packet_stats[ppac['from']]['duplicate'] += 1
					logging.warning('Dropping duplicate of recent packet - %s' % packet)
				elif timestamp - self.last_packet_time.get(ppac['from'], 0) < self.min_packet_dt:
					logging.warning('Got new packet too soon - %0.1f sec after last one, < %0.1f sec : %s' % (timestamp - self.last_packet_time.get(ppac['from'], 0), self.min_packet_dt, packet))
					self.packet_stats[ppac['from']]['rate_limit'] += 1
				else:
					self.packet_stats[ppac['from']]['good'] += 1
					# only count valid packet for rate limiting.
					self.last_packet_time[ppac['from']] = timestamp
					logging.info('Adding packet : {:}'.format(ppac))
					self.locations.append({'srccall' : ppac['from'],
								'lng' : ppac['longitude'],
								'lat' : ppac['latitude'],
								'altitude' : ppac.get('altitude', 0),  # exception, mostly for debugging, but i'm willing to accept trackers configured without altitude.
								'time' : timestamp}) 
					if _DEBUG or self.verbose:
						print 'after adding\n', self.locations
				# adding this packet to the recent ones held for the id, regardless of validity
				self.recent_packets[ppac['from']].append(short_packet_data)
				
			elif self.verbose:
				print 'from {:}, skip'.format(ppac['from'])
		except Exception as e: #(aprslib.UnknownFormat, aprslib.ParseError:) as e:
			logging.debug('filter_callsigns - i = {:0d} failed due to {:} raw packet *{:}*'.format(packet_i, e, packet))
Exemple #29
0
    def load(self, obj):
        if not isinstance(obj, dict):
            if self.format == 'raw':
                header, self.body = obj.split(":", 1)
                obj = parse_header(header)
            else:
                obj = parse(obj)

        for k, v in obj.items():
            if k == 'format':
                continue
            if k == 'to' or k == 'from':
                k += 'call'

            if hasattr(self, k):
                setattr(self, k, v)
Exemple #30
0
def callback(packet):
    decodiert = aprslib.parse(packet)
    try:
        if decodiert['format'] == a_format:
            print(strftime("%H:%M:%S"), "Von: ", decodiert['from'], " An: ",
                  decodiert['addresse'], "\033[31m", decodiert['message_text'],
                  "\033[0m.")
            print("RAW: ", decodiert['raw'])
            if decodiert['addresse'] == meinemsgid and not decodiert[
                    'message_text'].find(":ack") >= 1:
                #                print("Sende ACK an ", decodiert['from'])
                ack_senden(decodiert['from'], str(decodiert['msgNo']))
    except KeyError:
        print('Wohl ein <ack> ... ?')
        print(decodiert['raw'])
        pass
Exemple #31
0
    def load(self, obj):
        if not isinstance(obj, dict):
            if self.format == 'raw':
                header, self.body = obj.split(":", 1)
                obj = parse_header(header)
            else:
                obj = parse(obj)

        for k, v in obj.items():
            if k == 'format':
                continue
            if k == 'to' or k == 'from':
                k += 'call'

            if hasattr(self, k):
                setattr(self, k, v)
 def test_valid_thirdparty_msg(self):
     packet = "A-1>APRS,B-2,WIDE1*:}C>APU25N,TCPIP,A-1*::DEF      :ack56"
     result = parse(packet)
     self.assertEqual(result['via'], '')
     self.assertEqual(result['to'], 'APRS')
     self.assertEqual(result['from'], 'A-1')
     self.assertEqual(result['format'], 'thirdparty')
     self.assertEqual(result['raw'], packet)
     self.assertEqual(result['path'], ['B-2', 'WIDE1*'])
     self.assertEqual(result['subpacket']['raw'], packet[21:])
     self.assertEqual(result['subpacket']['via'], '')
     self.assertEqual(result['subpacket']['msgNo'], '56')
     self.assertEqual(result['subpacket']['from'], 'C')
     self.assertEqual(result['subpacket']['path'], ['TCPIP', 'A-1*'])
     self.assertEqual(result['subpacket']['response'], 'ack')
     self.assertEqual(result['subpacket']['format'], 'message')
     self.assertEqual(result['subpacket']['to'], 'APU25N')
     self.assertEqual(result['subpacket']['addressee'], 'DEF')
Exemple #33
0
def aprs_decode(udp_packet):
    k = {}
    aprs_data = udp_packet.split("\n")
    if len(aprs_data) > 1:
        aa = aprs_data[0].split(" ")
        try:
            if aa[3] == str(aprslib.passcode(aa[1].encode("UTF-8"))):
                try:
                    packet = aprslib.parse(aprs_data[1])
                except (aprslib.ParseError, aprslib.UnknownFormat) as exp:
                    print("Aprs parse error %s" % exp)
                    print("Aprs packet %s " % udp_packet)
                    packet = None
                else:
                    k['id'] = packet['from'].upper()
                    try:
                        k['lat'] = packet['latitude']
                    except:
                        k['lat'] = 0
                    try:
                        k['lon'] = packet['longitude']
                    except:
                        k['lon'] = 0
                    try:
                        k['speed'] = packet['speed']
                    except:
                        k['speed'] = 0
                    try:
                        k['hdop'] = packet['course']
                    except:
                        k['hdop'] = 0
                    try:
                        k['timestamp'] = packet['']
                    except:
                        k['timestamp'] = int(time.time())
                    try:
                        k['altitude'] = packet['altitude']
                    except:
                        k['altitude'] = 0
        except:
            print("Aprs split : %s " % aa)
    else:
        print("Aprs packet : %s " % udp_packet)
    return k
Exemple #34
0
def process_packet(packet, conn, rxtime=None, is_subpacket=False):
    """
    Load an unparsed APRS packet into the database
    packet: APRS packet string
    conn: psycopg2 database connection
    rxtime: time packet was received, as seconds since epoch (1/1/1970); if omitted or wrong format, uses system clock
    is_subpacket: boolean flag for whether this is a sub-packet
    returns packet_id (positive bigint) if successful, negative integer if not
    """
    # Check for reasonable timestamp
    if (type(rxtime) is not float and type(rxtime) is not int
            or (rxtime is None)):
        rxtime = time.time()

    try:  # Parse it
        parsed = aprslib.parse(packet)
    except aprslib.exceptions.ParseError as pe:
        try:  # Salvage what data we can from the header of an unparseable packet
            parsed = pe.parsed
            parsed['format'] = "parseerror"
        except:  # Couldn't salvage anything
            print("Unable to partially parse packet: '" + packet +
                  "' at time " + str(rxtime))  # DEBUG
            return (-6)  # Unable to partially parse packet

    except aprslib.exceptions.UnknownFormat as uf:
        # Save what headers we can if the format is unknown
        parsed = uf.parsed
        parsed['format'] = "unknown"
    except:
        # Something else went wrong
        print("Unable to parse packet")  # DEBUG
        raise
        return (-5)  # Unable to parse packet

    # Add the receiving station metadata to the parsed data
    parsed.update({
        'rxtime': rxtime,
        'rxsession': session_id,
        'is_subpacket': is_subpacket
    })

    # Send the parsed data on for further processing
    return (process_parsed(parsed, conn, rxtime, is_subpacket))
Exemple #35
0
    def test_status_format_branch(self):
        def _u(text, c='utf8'):
            if sys.version_info[0] >= 3:
                return text
            else:
                return text.decode(c)

        expected = {
            'status': 'test',
            'raw': _u('A>B:>test'),
            'via': '',
            'from': _u('A'),
            'to': _u('B'),
            'path': [],
            'format': 'status'
        }
        result = parse("A>B:>test")

        self.assertEqual(result, expected)
Exemple #36
0
    def test_status_format_branch(self):
        def _u(text, c='utf8'):
            if sys.version_info[0] >= 3:
                return text
            else:
                return text.decode(c)

        expected = {
            'status': 'test',
            'raw': _u('A>B:>test'),
            'via': '',
            'from': _u('A'),
            'to': _u('B'),
            'path': [],
            'format': 'status'
        }
        result = parse("A>B:>test")

        self.assertEqual(result, expected)
Exemple #37
0
    def process_frame(self, frame):
        """
        Process an incoming frame according to configured options.
        """

        frame_dict = {}

        # If we're in debug mode...
        if self.__debug:
            print("Incoming frame:")
            self.hexdump(frame)
            print("")

        frame_base64 = "%s" % base64.standard_b64encode(frame).decode()
        frame_dict.update({'frame_base64': frame_base64})

        try:
            aprs_parsed = "%s" % aprs.parse_frame(frame)
            frame_dict.update(aprslib.parse(aprs_parsed))

        except ValueError:
            frame_dict.update({'parse_error_message': "ValueError"})

        except aprslib.exceptions.ParseError:
            frame_dict.update({'parse_error_message': "ParseError"})

        except aprslib.exceptions.UnknownFormat:
            frame_dict.update({'parse_error_message': "UnknownFormat"})

        # Ugly AF, we really don't want to be doing this.
        try:
            self.__m.publish(self.__mqtt_rx_topic, json.dumps(frame_dict))

        except (KeyboardInterrupt, SystemExit):
            raise

        except:
            print(traceback.format_exc())
            self.__mqtt_connect()
Exemple #38
0
    def test_status_format_branch(self):
        self.m.StubOutWithMock(parsing, "_parse_timestamp")
        parsing._parse_timestamp(mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(("test", {}))
        self.m.ReplayAll()

        def _u(text, c='utf8'):
            if sys.version_info[0] >= 3:
                return text
            else:
                return text.decode(c)

        expected = {
            'status': 'test',
            'raw': _u('A>B:>test'),
            'via': '',
            'from': _u('A'),
            'to': _u('B'),
            'path': [],
            'format': 'status'
        }
        result = parse("A>B:>test")

        self.assertEqual(result, expected)
        self.m.VerifyAll()
Exemple #39
0
    def decode_aprs_messages(self, msgs):
        """
        Decode APRS Messages
        :param msgs:
        :return:
        """

        header = None
        footer = None

        for n, message in enumerate(msgs):

            try:
                header = message[0].lstrip()
                footer = message[1].lstrip()

                header_fields, aprs_addresses = parse_aprs_header(header, footer, n=n)

                logger.debug(u"%3d [%s]" % (n, header[10:]))
                logger.debug(u"    [%s]" % footer)

                # 1 $ULTW
                if re.match(r"^\$ULTW.*", footer, re.M | re.I):

                    # # __________________________________________________________________________________
                    # $ indicates a Ultimeter 2000
                    # $ULTW 0000 0000 01FF 0004 27C7 0002 CCD3 0001 026E 003A 050F 0004 0000
                    u"""
                    Field #1,  0000 = Wind Speed Peak over last 5 min. ( reported as 0.1 kph increments)
                    Field #2,  0000 = Wind Direction of Wind Speed Peak (0-255)
                    Field #3,  01FF = Current Outdoor Temp (reported as 0.1 deg F increments)
                    Field #4,  0004 = Rain Long Term Total (reported in 0.01 in. increments)
                    Field #5,  27C7 = Current Barometer (reported in 0.1 mbar increments)
                    Field #6,  0002 = Barometer Delta Value(reported in 0.1 mbar increments)
                    Field #7,  CCD3 = Barometer Corr. Factor(LSW)
                    Field #8,  0001 = Barometer Corr. Factor(MSW)
                    Field #9,  026E = Current Outdoor Humidity (reported in 0.1% increments)
                    Field #10, 003A = Date (day of year since January 1)
                    Field #11, 050F = Time (minute of day)
                    Field #12, 0004 = Today's Rain Total (reported as 0.01 inch increments)
                    Field #13, 0000 = 1 Minute Wind Speed Average (reported in 0.1kph increments)
                    """
                    #        1    2    3    4      5     6    7      8    9     10   11   12   13
                    # $ULTW 0138 0005 02B3 CEF8  27CC   FFEF 8782   0001 0142  003D 0370 0000 00CE
                    # $ULTW 0018 0060 02D8 8214  27C4   0003 8702   0001 03E8  0099 0050 0000 0001
                    # $ULTW 0000 0000 02D3 670F  27BC   FFFD 8765   0001 03E8  0099 0046 0001 0000
                    # $ULTW 00B0 0042 02D3 25ED  27C2   0010 8935   0001 03E8  0098 050A 0037 006A
                    # $ULTW 0064 00AB 030C 1821  2784   0001 85E5   0001 0323  009B 058C 0000 0026
                    #        1.7 66   72.3 97.09 1017.8 1.6  35125  1    100.0 152  1290 0.55 10.6
                    #
                    rem0 = u"^\$ULTW[0-9a-fA-F]{52}"
                    if re.match(rem0, footer):
                        try:
                            logger.debug(u"1 Ultimeter 2000")
                            message_bytes = (5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0)
                            fields = parse_aprs_footer(footer, message_bytes)
                            fields[u"Message_Type"] = u"$ULTW"
                            fields.update(header_fields)
                            if fields[u"Wind Direction"] == 0:
                                fields[u"Wind Direction"] = u"N"
                            self.queue_display(fields, header=header, footer=footer)

                        except Exception as e:
                            logger.warn(u"{} {} {}".format(sys.exc_info()[-1].tb_lineno, type(e), e))

                # 2 aprslib _
                elif re.match(r"^_.*", footer, re.M | re.I):
                    # __________________________________________________________________________________
                    # Positionless Weather Report Positionless Weather Data
                    # _ 0731 1701 c189 s004 g006 t094 r000 p000 P000 h00 b1016 5wDAV
                    # _ Message
                    # 0731 Month Day
                    # 1701 Time
                    # c189 Wind Direction
                    # s004 Wind Speed
                    # g006 Wind Gust in the last five minutes
                    # t094 Temperature
                    # r000 Rainfall in the last hour
                    # p000 Rainfall in the last 24 hours
                    # P000 Rainfall since midnight
                    # h00  Humidity
                    # b1016 Barometric Pressure
                    # 5     APRS Software
                    # wDAV  WX Unit -  WinAPRS
                    #           1           2            3           4          5         6
                    # 123456789 0123 4567 8901 2345 6789 0123 4567 890 123456 78901234567890123456789
                    # _01241225 c257 s001 g008 t066 r000 p002 P000 h51 b10219 tU2k
                    # _05311550 c359 s000 g000 t086 r000 p086 P000 h64 b10160 tU2k
                    # _05312040 c359 s000 g000 t075 r000 p086 P035 h99 b10182 tU2k
                    # _06051349 c359 s000 g000 t081 r000 p037 P023 h89 b10084 tU2k
                    # _01241225 c257 s001 g008 t066 r000 p002 P000 h51 b10219 tU2k
                    # rem = u"^_\d{8}c\d{3}s\d{3}g\d{3}t\d{3}r\d{3}p\d{3}P\d{3}h\d{2}b\d{5}.*"
                    try:  # This seems to fail alot
                        rem0 = u"^_\d{8}c\d{3}s\d{3}g\d{3}t\d{3}r\d{3}p\d{3}P\d{3}h\d{2}b\d{5}.*"
                        if re.match(rem0, footer, re.M):
                            logger.info(u"_2a Raw Weather Report")
                            fields = aprslib.parse(aprs_addresses)
                            fields[u"Message_Type"] = u"_a"
                            fields.update(header_fields)
                            nf = {k.title(): v for k, v in fields[u"weather"].items()}
                            del fields[u"weather"]
                            nfa = {k.title(): v for k, v in nf.items()}
                            self.queue_display(nfa, header=header, footer=footer)

                    except Exception, msg:
                        try:
                            # MDHM
                            logger.info(u"_2b Positionless Weather Report")
                            message_bytes = (1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 6, 1, 3, 0)
                            fields = parse_aprs_footer(footer, message_bytes)
                            fields[u"Message_Type"] = u"_b"
                            fields.update(header_fields)
                            self.queue_display(fields, header=header, footer=footer)

                        except Exception, msg:
                            logger.info(u"_2c Positionless Weather Report")
                            message_bytes = (1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 5, 1, 4, 0)
                            fields = parse_aprs_footer(footer, message_bytes)
                            fields[u"Message_Type"] = u"_c"
                            fields.update(header_fields)
                            self.queue_display(fields, header=header, footer=footer)

                # 3 aprslib !
                elif re.match(r"^!.*", footer, re.M | re.I):
                    # __________________________________________________________________________________
                    # Raw Weather Report - Ultimeter
                    # !2749.10N S 08215.39W # PHG56304/W3,FLn Riverview, FL www.ni4ce.org (wind @ 810ft AGL)
                    # !         Message
                    # 2749.10N  Latitude
                    # S         Symbol Table ID
                    # 08215.39W Longitude
                    # #
                    # PHG56304/W3,FLn Riverview, FL www.ni4ce.org (wind @ 810ft AGL)
                    # !2818.17N/08209.50W#Dade City
                    rem0 = u"^!\d{4}\.\d{2}(N|S)(_|S|P)\d{5}\.\d{2}(E|W)(#|_)(.|,|/| \(\@).+"
                    rem1 = u"^!\d{4}\.\d{2}(N|S)(_|S|P)\d{5}\.\d{2}(E|W).+"
                    rem2 = u"^!\d{4}\.\d{2}(N|S)/\d{5}\.\d{2}(W|E)(#|_|).+"
                    if re.match(rem0, footer):
                        try:
                            logger.info(u"!3a Raw Weather Report")
                            fields = aprslib.parse(aprs_addresses)
                            fields[u"Message_Type"] = u"!a"
                            fields[u"longitude"] = u"{:6.2f}W".format(fields[u"longitude"])
                            fields[u"latitude"] = u"{:6.2f}N".format(fields[u"latitude"])
                            fields.update(header_fields)
                            self.queue_display(fields, header=header, footer=footer)
                        except Exception as e:
                            logger.warn(
                                u"decode_aprs_messages {} {} {}".format(sys.exc_info()[-1].tb_lineno, type(e), e))

                    elif re.match(rem1, footer):
                        try:
                            logger.info(u"!3b Raw Weather Report")
                            message_bytes = (1, 8, 1, 9, 1, 0)
                            fields = parse_aprs_footer(footer, message_bytes)
                            fields[u"Message_Type"] = u"!b"
                            fields[u"longitude"] = u"{:6.2f}".format(fields[u"longitude"])
                            fields[u"latitude"] = u"{:6.2f}".format(fields[u"latitude"])
                            fields.update(header_fields)
                            self.queue_display(fields, header=header, footer=footer)
                        except Exception as e:
                            logger.warn(
                                u"decode_aprs_messages {} {} {}".format(sys.exc_info()[-1].tb_lineno, type(e), e))
Exemple #40
0
                            pass
                    except Exception, msg:
                        try:
                            logger.warn(u"4a %s" % msg)
                            logger.info(u"=4b Complete Weather Report")
                            message_bytes = (1, 1, 4, 4, 1, 2, 1, 4, 4, 4, 4, 4, 4, 3, 6, 0)
                            fields = parse_aprs_footer(footer, message_bytes)
                            fields.update(header_fields)
                            fields[u"Message_Type"] = u"=b"
                            self.queue_display(fields, header=header, footer=footer)

                        except Exception, msg:
                            try:
                                logger.warn(u"4 %s" % msg)
                                logger.info(u"4 Complete Weather Report")
                                fields = aprslib.parse(aprs_addresses)
                                fields.update(header_fields)
                                fields[u"Message_Type"] = u"=c"
                                self.queue_display(fields, header=header, footer=footer)

                            except Exception as e:
                                logger.warn(
                                    u"decode_aprs_messages {} {} {}".format(sys.exc_info()[-1].tb_lineno, type(e), e))

                # 5 aprslib @
                elif re.match(r"^@.*", footer, re.M | re.I):
                    fields = dict()
                    fields[u"Message_Type"] = u"@"
                    fields[u"header"] = header
                    fields[u"footer"] = footer
Exemple #41
0
#!/bin/env python
import aprslib, pprint

# Put the output from the APRS message into "message" and hope it works

message = "VE3YCA-4>APRS-0,DIGI2-1,DIGI1-1:/092231h4437.28N/07930.57Ws000/000/A=000897/Comment"

packet = aprslib.parse(message)

pprint.pprint(packet)
    "Message received on default handler, destined to " + m.channel + ": " + m.
    as_string() + "\n\n")
emitter.on_error = lambda e: print("Error received: " + str(e) + "\n\n")
emitter.on_me = lambda me: print("Information about Me received: " + str(me) +
                                 "\n\n")
emitter.on_keyban = lambda kb: print("Keyban message received: " + str(kb) +
                                     "\n\n")
emitter.loop_start()

while True:
    data, addr = axudpsocket.recvfrom(RECV_BUFFER_LENGTH)

    isaprs, metadata = axtostr(data)
    metadata = {k: int(v) for k, v in metadata.items()}
    try:
        aprsdict = aprslib.parse(isaprs)
        aprsdict.update(metadata)
        aprsdict.mode = AXUDP_MODE
        aprsjson = json.dumps(aprsdict)

        if connected:
            if "latitude" in aprsdict and "longitude" in aprsdict:
                emitter.publish(
                    MQTT_KEY,
                    f'/{MQTT_TOPIC}/point/{math.floor(aprsdict["latitude"])}/{math.floor(aprsdict["longitude"])}/{aprsdict["from"]}',
                    aprsjson, {})

            emitter.publish(MQTT_KEY,
                            f'{MQTT_TOPIC}/message/{aprsdict["from"]}',
                            aprsjson, {})
    except (aprslib.ParseError, aprslib.UnknownFormat) as exp:
Exemple #43
0
def list_loop():
    call = "null"
    # position cursor in -1 slot, as the first thing the loop does is increment slot
    y = padding + title_bar_height - font.getsize("ABCJQ")[1]
    x = padding
    max_lines = (height - title_bar_height - padding) // line_height
    max_cols = (width // max_line_width)
    line_count = 0
    col_count = 0

    while True:
        line = f.stdout.readline().decode("utf-8", errors="ignore")

        # watch for regular packet
        search = re.search("^\[\d\.\d\] (.*)", line)
        if search is not None:
            packetstring = search.group(1)
            packetstring = packetstring.replace('<0x0d>', '\x0d').replace(
                '<0x1c>', '\x1c').replace('<0x1e>', '\x1e').replace(
                    '<0x1f>', '\0x1f').replace('<0x0a>', '\0x0a')
        else:
            continue

        lastcall = call

        try:  #   aprslib has trouble parsing all packets
            packet = aprslib.parse(packetstring)
            call = packet['from']
            if 'symbol' in packet:
                symbol = packet['symbol']
                symbol_table = packet['symbol_table']
            else:
                symbol = '/'
                symbol_table = '/'
        except:  #   if it fails, let's just snag the callsign
            #print("aprslib failed to parse.")
            search = re.search("^\[\d\.\d\] ([a-zA-Z0-9-]*)", line)
            if search is not None:
                call = search.group(1)
                symbol = '/'
                symbol_table = '/'
            else:
                continue

        offset = ord(symbol) - 33
        row = offset // 16
        col = offset % 16

        if call == lastcall:  # blink duplicates
            time.sleep(0.5)
            draw.text(
                (x + symbol_dimension + (symbol_dimension // 8), y),
                call,
                font=font,
                fill="#000000")  # start text after symbol, relative padding
            with display_lock:
                disp.image(image)
            time.sleep(0.1)
            draw.text(
                (x + symbol_dimension + (symbol_dimension // 8), y),
                call,
                font=font,
                fill="#AAAAAA")  # start text after symbol, relative padding
            with display_lock:
                disp.image(image)
        else:
            y += line_height
            if line_count == max_lines:  # about to write off bottom edge of screen
                col_count += 1
                x = col_count * max_line_width
                y = padding + title_bar_height
                line_count = 0
            if col_count == max_cols:  # about to write off right edge of screen
                x = padding
                y = padding + title_bar_height
                draw.rectangle((0, title_bar_height + 1, width, height),
                               outline=0,
                               fill="#000000")  # erase lines
                line_count = 0
                col_count = 0
                time.sleep(2.0)
            crop_area = (col * symbol_dimension, row * symbol_dimension,
                         col * symbol_dimension + symbol_dimension,
                         row * symbol_dimension + symbol_dimension)
            if symbol_table == '/':
                symbolimage = symbol_chart0x64.crop(crop_area)
            else:
                symbolimage = symbol_chart1x64.crop(crop_area)
            image.paste(symbolimage, (x, y), symbolimage)
            draw.text(
                (x + symbol_dimension + (symbol_dimension // 8), y),
                call,
                font=font,
                fill="#AAAAAA")  # start text after symbol, relative padding
            line_count += 1
            with display_lock:
                disp.image(image)
Exemple #44
0
def single_loop():
    symbol_chart0x64 = Image.open("aprs-symbols-64-0.png")
    symbol_chart1x64 = Image.open("aprs-symbols-64-1.png")

    # we try to get callsign, symbol and four relevant info lines from every packet
    while True:
        info1 = info2 = info3 = info4 = ''  # sane defaults

        line = f.stdout.readline().decode("utf-8", errors="ignore")

        search = re.search(
            "^\[\d\.\d\] (.*)",
            line)  # see if logfile line is an incoming packet over RF
        if search is not None:
            packetstring = search.group(1)
            packetstring = packetstring.replace('<0x0d>', '\x0d').replace(
                '<0x1c>', '\x1c').replace('<0x1e>', '\x1e').replace(
                    '<0x1f>', '\0x1f').replace('<0x0a>', '\0x0a')
        else:
            continue

        try:
            packet = aprslib.parse(packetstring)  # parse packet
            #print(packet)
            call = packet['from']
            supported_packet = True
        except Exception as e:  # aprslib doesn't support all packet types
            #print("Exception: aprslib: ", str(e), ": ", packetstring)
            supported_packet = False
            packet = {}
            search = re.search("^\[\d\.\d\] ([a-zA-Z0-9-]*)",
                               line)  # snag callsign from unsupported packet
            if search is not None:
                call = search.group(1)
                symbol = '/'  # unsupported packet symbol set to red ball
                symbol_table = '/'
            else:
                continue

        try:
            if supported_packet:
                if 'symbol' in packet:  # get symbol from valid packet or use red ball
                    symbol = packet['symbol']
                    symbol_table = packet['symbol_table']
                else:
                    symbol = '/'
                    symbol_table = '/'
                    # extract relevant info lines
            if not supported_packet:
                info1 = info2 = info3 = info4 = ''  # no info in unsupported packet
            elif 'weather' in packet:  # weather (often contained in compressed/uncompressed type packets)
                info1 = round(packet['weather']['temperature'])
                info1 = str(int(info1) * 1.8 + 32) + 'F'
                #print(info1)
                info2 = str(
                    packet['weather']['rain_since_midnight']) + '\" rain'
                #print(info2)
                info3 = str(round(packet['weather']['wind_speed'])) + ' m/h'
                info3 = info3 + ' ' + str(
                    packet['weather']['wind_direction']) + '\''
                #print(info3)
                info4 = str(packet['comment'])
                #print(info4)                                                # position packet
            elif packet['format'] == 'mic-e' or packet[
                    'format'] == 'compressed' or packet[
                        'format'] == 'uncompressed' or packet[
                            'format'] == 'object':
                info4 = packet[
                    'comment']  # fixme: comment is jibberish in all compressed packets
            elif 'status' in packet:  # status packet
                info4 = packet['status']
        except Exception as e:
            print("Malformed/missing data: ", str(e), ": ", packetstring)

        symbol_dimension = 64
        offset = ord(symbol) - 33
        row = offset // 16
        col = offset % 16
        y = height // 3
        x = width // 3
        draw.rectangle((0, title_bar_height, width, height),
                       outline=0,
                       fill="#000000")  # erase most of screen
        crop_area = (col * symbol_dimension, row * symbol_dimension,
                     col * symbol_dimension + symbol_dimension,
                     row * symbol_dimension + symbol_dimension)
        if symbol_table == '/':
            symbolimage = symbol_chart0x64.crop(crop_area)
        else:
            symbolimage = symbol_chart1x64.crop(crop_area)
        symbolimage = symbolimage.resize((height // 2, height // 2),
                                         Image.NEAREST)
        #image.paste(symbolimage, (0, 36), symbolimage)
        image.paste(symbolimage, (0, title_bar_height), symbolimage)
        draw.text((120, 50), str(info1), font=font_small, fill="#AAAAAA")
        draw.text((120, 70), str(info2), font=font_small, fill="#AAAAAA")
        draw.text((120, 90), str(info3), font=font_small, fill="#AAAAAA")
        draw.text((5, 144), str(info4), font=font_small, fill="#AAAAAA")
        draw.text((5, height - font_epic.getsize("X")[1] - 3),
                  call,
                  font=font_epic,
                  fill="#AAAAAA")  # text up from bottom edge

        with display_lock:
            disp.image(image)
        time.sleep(1)
Exemple #45
0
timestamps = []

# populate timestamps with first value in every line (ended by a colon) before actual APRS packet
for packet_index in range(0, len(aprs_packets)):
    current_line = aprs_packets[packet_index].split(': ')
    timestamps.append(current_line[0])
    aprs_packets[packet_index] = current_line[1]

# open output and write header, then write parsed APRS data
with open(output_filename, "w") as output_file:
    output_file.write('timestamp,' + ','.join(desired_fields) + '\n')

    # for each line in the input data, parse the APRS data using aprslib and extract the desired fields
    for packet_index in range(0, len(aprs_packets)):
        # parse data and append timestamp to front
        current_aprs_packet = aprslib.parse(aprs_packets[packet_index])
        current_output_data = [str(timestamps[packet_index])]

        # extract and append desired fields, preserving CSV format by replacing commas with semicolons
        for field_index in range(0, len(desired_fields)):
            # get current field name
            field = desired_fields[field_index]

            # check if field exists in current packet
            if field in current_aprs_packet:
                # replace commas in data with semicolons to preserve CSV format
                current_output_data.append(
                    str(current_aprs_packet[field]).replace(',', ';'))
            else:
                # if the field is not in the current APRS packet, append the null data value instead
                current_output_data.append(null_data_string)
Exemple #46
0
def process(package):
    if myCall in package:
        try:
            interpret(aprslib.parse(package))
        except (aprslib.ParseError, aprslib.UnknownFormat) as exp:
            pass