Example #1
0
def test_time_to_ground():
    packet_1 = APRSPacket.from_frame(
        "W3EAX-13>APRS,N3KTX-10*,WIDE1,WIDE2-1,qAR,N3TJJ-11:!/:J..:sh'O   /A=053614|!g|  /W3EAX,313,0,21'C,"
        "nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 36, 16),
    )
    packet_2 = APRSPacket.from_frame(
        "W3EAX-13>APRS,WIDE1-1,WIDE2-1,qAR,W4TTU:!/:JAe:tn8O   /A=046255|!i|  /W3EAX,322,0,20'C,nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 38, 23),
    )
    packet_3 = APRSPacket.from_frame(
        "W3EAX-13>APRS,N3KTX-10*,WIDE1,WIDE2-1,qAR,N3TJJ-11:!/:J..:sh'O   /A=063614|!g|  /W3EAX,313,0,21'C,"
        "nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 39, 28),
    )
    packet_4 = APRSPacket.from_frame(
        "W3EAX-13>APRS,KC3FIT-1,WIDE1*,WIDE2-1,qAR,KC3AWP-10:!/:JL2:u4wO   /A=043080|!j|  /W3EAX,326,0,20'C,"
        "nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 41, 50),
    )
    packet_5 = APRSPacket.from_frame(
        "W3EAX-13>APRS,N3KTX-10*,WIDE1,WIDE2-1,qAR,N3TJJ-11:!/:J..:sh'O   /A=063614|!g|  /W3EAX,313,0,21'C,"
        "nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 42, 34),
    )

    track = APRSTrack(callsign="W3EAX-13")

    track.append(packet_1)

    assert not track.falling
    assert track.time_to_ground == timedelta(seconds=-1)

    track.append(packet_2)

    assert track.falling
    assert track.time_to_ground == timedelta(seconds=1603.148748)

    track.append(packet_3)

    assert not track.falling
    assert track.time_to_ground == timedelta(seconds=-1)

    track.append(packet_4)
    track.append(packet_5)

    assert not track.falling
    assert track.time_to_ground == timedelta(seconds=297.913704)
Example #2
0
def packet_track():
    return APRSTrack(
        packets=[
            APRSPacket.from_frame(
                "W3EAX-8>APRS,WIDE1-1,WIDE2-1,qAR,K3DO-11:!/:Gh=:j)#O   /A=026909|!Q|  /W3EAX,262,0,18'C,http://www.umd.edu",
                packet_time=pytz.timezone("America/New_York").localize(
                    datetime(2018, 11, 11, 10, 20, 13)
                ),
            ),
            APRSPacket.from_frame(
                "W3EAX-8>APRS,N3TJJ-12,WIDE1*,WIDE2-1,qAR,N3FYI-2:!/:GiD:jcwO   /A=028365|!R|  /W3EAX,267,0,18'C,"
                "http://www.umd.edu",
                packet_time=pytz.timezone("America/New_York").localize(
                    datetime(2018, 11, 11, 10, 21, 24)
                ),
            ),
            APRSPacket.from_frame(
                "W3EAX-8>APRS,KC3FIT-1,WIDE1*,WIDE2-1,qAR,KC3AWP-10:!/:JL2:u4wO   /A=043080|!j|  /W3EAX,326,0,20'C,"
                "nearspace.umd.edu",
                packet_time=pytz.timezone("America/New_York").localize(
                    datetime(2019, 2, 3, 14, 39, 28)
                ),
            ),
        ],
        callsign="W3EAX-8",
    )
Example #3
0
def test_index():
    packet_1 = APRSPacket.from_frame(
        "W3EAX-13>APRS,N3KTX-10*,WIDE1,WIDE2-1,qAR,N3TJJ-11:!/:J..:sh'O   /A=053614|!g|  /W3EAX,313,0,21'C,"
        "nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 36, 16),
    )
    packet_2 = APRSPacket.from_frame(
        "W3EAX-13>APRS,WIDE1-1,WIDE2-1,qAR,W4TTU:!/:JAe:tn8O   /A=046255|!i|  /W3EAX,322,0,20'C,nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 38, 23),
    )
    packet_3 = APRSPacket.from_frame(
        "W3EAX-13>APRS,KC3FIT-1,WIDE1*,WIDE2-1,qAR,KC3AWP-10:!/:JL2:u4wO   /A=043080|!j|  /W3EAX,326,0,20'C,"
        "nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 39, 28),
    )

    track = APRSTrack(packets=[packet_1, packet_2, packet_3],
                      callsign="W3EAX-13")

    assert track[0] == packet_1
    assert track[0] is packet_1
    assert track[datetime(2019, 2, 3, 14, 36, 16)] == packet_1
    assert track["2019-02-03 14:36:16"] == packet_1

    assert track["2019-02-03 14:38:00"] == packet_2

    with pytest.raises(IndexError):
        track["2019-02-03 14:30:00"]
Example #4
0
def test_read_geojson():
    reference_directory = REFERENCE_DIRECTORY / "test_write_geojson"

    tracks = LocationPacketTrack.from_file(reference_directory / "tracks.geojson")
    aprs_tracks = APRSTrack.from_file(reference_directory / "tracks.geojson")

    assert tracks[0].attributes["callsign"] == "W3EAX-8"
    assert aprs_tracks[0].callsign == "W3EAX-8"
Example #5
0
def test_append():
    packet_1 = APRSPacket.from_frame(
        "W3EAX-13>APRS,N3KTX-10*,WIDE1,WIDE2-1,qAR,N3TJJ-11:!/:J..:sh'O   /A=053614|!g|  /W3EAX,313,0,21'C,"
        "nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 36, 16),
    )
    packet_2 = APRSPacket.from_frame(
        "W3EAX-13>APRS,WIDE1-1,WIDE2-1,qAR,W4TTU:!/:JAe:tn8O   /A=046255|!i|  /W3EAX,322,0,20'C,nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 38, 23),
    )
    packet_3 = APRSPacket.from_frame(
        "W3EAX-8>APRS,WIDE1-1,WIDE2-1,qAR,K3DO-11:!/:Gh=:j)#O   /A=026909|!Q|  /W3EAX,262,0,18'C,http://www.umd.edu"
    )

    track = APRSTrack(callsign="W3EAX-13")

    track.append(packet_1)
    track.append(packet_2)
    with pytest.raises(ValueError):
        track.append(packet_3)

    assert track[0] is packet_1
    assert track[1] is packet_2
    assert track[-1] is packet_2
    assert track[:] == track
    assert track[1:] == APRSTrack(packets=track.packets[1:],
                                  callsign=track.callsign,
                                  crs=track.crs)
Example #6
0
def test_values():
    packet_1 = APRSPacket.from_frame(
        "W3EAX-13>APRS,N3KTX-10*,WIDE1,WIDE2-1,qAR,N3TJJ-11:!/:J..:sh'O   /A=053614|!g|  /W3EAX,313,0,21'C,"
        "nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 36, 16),
    )

    track = APRSTrack(packets=[packet_1], callsign="W3EAX-13")

    assert numpy.all(track.coordinates[-1] == packet_1.coordinates)
Example #7
0
def test_sorting():
    packet_1 = APRSPacket.from_frame(
        "W3EAX-13>APRS,N3KTX-10*,WIDE1,WIDE2-1,qAR,N3TJJ-11:!/:J..:sh'O   /A=053614|!g|  /W3EAX,313,0,21'C,"
        "nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 36, 16),
    )
    packet_2 = APRSPacket.from_frame(
        "W3EAX-13>APRS,WIDE1-1,WIDE2-1,qAR,W4TTU:!/:JAe:tn8O   /A=046255|!i|  /W3EAX,322,0,20'C,nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 38, 23),
    )
    packet_3 = APRSPacket.from_frame(
        "W3EAX-13>APRS,KC3FIT-1,WIDE1*,WIDE2-1,qAR,KC3AWP-10:!/:JL2:u4wO   /A=043080|!j|  /W3EAX,326,0,20'C,"
        "nearspace.umd.edu",
        packet_time=datetime(2019, 2, 3, 14, 39, 28),
    )

    track = APRSTrack(packets=[packet_2, packet_1, packet_3],
                      callsign="W3EAX-13")

    assert sorted(track) == [packet_1, packet_2, packet_3]
Example #8
0
def retrieve_packets(
    connections: List[PacketSource],
    packet_tracks: List[LocationPacketTrack],
    database: PacketDatabaseTable = None,
    start_date: datetime = None,
    end_date: datetime = None,
) -> Dict[str, APRSPacket]:
    logging.debug(f"receiving packets from {len(connections)} source(s)")
    current_time = datetime.now()

    parsed_packets = []
    for connection in connections:
        try:
            connection_packets = connection.packets
            parsed_packets.extend(connection_packets)
        except ConnectionError as error:
            logging.error(f"{connection.__class__.__name__} - {error}")
        except TimeIntervalError:
            pass

    logging.debug(f"received {len(parsed_packets)} packets")

    new_packets = {}
    if len(parsed_packets) > 0:
        updated_callsigns = set()
        for parsed_packet in parsed_packets:
            callsign = parsed_packet["callsign"]

            start_date = ensure_datetime_timezone(start_date)
            end_date = ensure_datetime_timezone(end_date)
            parsed_packet.time = ensure_datetime_timezone(parsed_packet.time)

            if start_date is not None and parsed_packet.time < start_date:
                continue
            if end_date is not None and parsed_packet.time > end_date:
                continue

            if callsign not in packet_tracks:
                packet_tracks[callsign] = APRSTrack(packets=[parsed_packet],
                                                    callsign=callsign)
                logging.debug(f"started tracking callsign {callsign:8}")
            else:
                packet_track = packet_tracks[callsign]
                if parsed_packet not in packet_track:
                    packet_track.append(parsed_packet)
                else:
                    if database is None or parsed_packet.source != database.location:
                        logging.debug(
                            f"skipping duplicate packet: {parsed_packet}")
                    continue

            if parsed_packet.source not in new_packets:
                new_packets[parsed_packet.source] = []
            new_packets[parsed_packet.source].append(parsed_packet)
            if callsign not in updated_callsigns:
                updated_callsigns.add(callsign)

        for source in new_packets:
            new_packets[source] = list(sorted(new_packets[source]))

        for source, packets in new_packets.items():
            logging.info(
                f"received {len(packets)} new packet(s) from {source}")

        if database is not None:
            for packets in new_packets.values():
                database.send(packet for packet in packets
                              if packet.source != database.location)

        updated_callsigns = sorted(updated_callsigns)
        for callsign in updated_callsigns:
            packet_track = packet_tracks[callsign]
            packet_time = datetime.utcfromtimestamp(
                (packet_track.times[-1] -
                 numpy.datetime64("1970-01-01T00:00:00")) /
                numpy.timedelta64(1, "s"))
            packet_track.sort(inplace=True)
            try:
                coordinate_string = ", ".join(
                    f"{coordinate:.3f}°"
                    for coordinate in packet_track.coordinates[-1, :2])
                logging.info(
                    f"{callsign:9} - packet #{len(packet_track):<3} - ({coordinate_string}, {packet_track.coordinates[-1, 2]:9.2f}m)"
                    f'; packet time is {packet_time} ({humanize.naturaltime(current_time - packet_time)}, {packet_track.intervals[-1] / numpy.timedelta64(1, "s"):6.1f} s interval)'
                    f"; traveled {packet_track.overground_distances[-1]:6.1f} m ({packet_track.ground_speeds[-1]:5.1f} m/s) over the ground"
                    f", and {packet_track.ascents[-1]:6.1f} m ({packet_track.ascent_rates[-1]:5.1f} m/s) vertically, since the previous packet"
                )
            except Exception as error:
                logging.exception(f"{error.__class__.__name__} - {error}")

        for callsign in updated_callsigns:
            packet_track = packet_tracks[callsign]
            packet_time = datetime.utcfromtimestamp(
                (packet_track.times[-1] -
                 numpy.datetime64("1970-01-01T00:00:00")) /
                numpy.timedelta64(1, "s"))
            try:
                ascent_rates = packet_track.ascent_rates[
                    packet_track.ascent_rates >= 0]
                if len(ascent_rates) > 0:
                    mean_ascent_rate = numpy.nanmean(ascent_rates)
                else:
                    mean_ascent_rate = 0

                descent_rates = packet_track.ascent_rates[
                    packet_track.ascent_rates < 0]
                if len(descent_rates) > 0:
                    mean_descent_rate = numpy.nanmean(descent_rates)
                else:
                    mean_descent_rate = 0

                if len(packet_track.ground_speeds) > 0:
                    mean_ground_speed = numpy.nanmean(
                        packet_track.ground_speeds)
                else:
                    mean_ground_speed = 0

                if len(packet_track.intervals) > 0:
                    mean_interval = numpy.nanmean(packet_track.intervals /
                                                  numpy.timedelta64(1, "s"))
                else:
                    mean_interval = 0

                message = (f"{callsign:9} - "
                           f"altitude: {packet_track.altitudes[-1]:6.1f} m"
                           f"; avg. ascent rate: {mean_ascent_rate:5.1f} m/s"
                           f"; avg. descent rate: {mean_descent_rate:5.1f} m/s"
                           f"; avg. ground speed: {mean_ground_speed:5.1f} m/s"
                           f"; avg. packet interval: {mean_interval:6.1f} s")

                if packet_track.time_to_ground >= timedelta(seconds=0):
                    landing_time = packet_time + packet_track.time_to_ground
                    time_to_ground = current_time - landing_time
                    message += (
                        f"; estimated landing: {landing_time:%Y-%m-%d %H:%M:%S} ({humanize.naturaltime(time_to_ground)})"
                        f"; max altitude: {packet_track.coordinates[:, 2].max():.2f} m"
                    )

                logging.info(message)

            except Exception as error:
                logging.exception(f"{error.__class__.__name__} - {error}")

    return new_packets