Example #1
0
def main():
    """Main function of aprs2influxdb

    Reads in configuration values and starts connection to APRS-IS with aprslib.
    Then two threads are started, one to monitor for APRS-IS packets and
    another to periodically send status packets to APRS-IS in order to keep
    the connection alive.
    """
    # Create logger, must be global for functions and threads
    global logger

    # Create telemetry dictionary
    global telemetryDictionary
    telemetryDictionary = {}

    # Log to sys.prefix + aprs2influxdb.log
    log = os.path.join(sys.prefix, "aprs2influxdb.log")
    logger = createLog(log, args.debug)

    # Start login for APRS-IS
    logger.info("Logging into APRS-IS as {0} on port {1}".format(
        args.callsign, args.port))
    if args.callsign == "nocall":
        logger.warning("APRS-IS ignores the callsign \"nocall\"!")

    # Open APRS-IS connection
    passcode = aprslib.passcode(args.callsign)
    AIS = aprslib.IS(args.callsign, passwd=passcode, port=args.port)

    # Set aprslib logger equal to aprs2influxdb logger
    AIS.logger = logger

    # Connect to APRS-IS servers
    try:
        AIS.connect()

    except aprslib.exceptions.LoginError:
        # An error occured
        logger.error('An aprslib LoginError occured', exc_info=True)

    except aprslib.exceptions.ConnectionError:
        # An error occured
        logger.error('An aprslib ConnectionError occured', exc_info=True)

    # Create heartbeat
    t1 = threading.Thread(target=heartbeat,
                          args=(AIS, args.callsign, args.interval))

    # Create consumer
    t2 = threading.Thread(target=consumer, args=(AIS, ))

    # Start threads
    t1.start()
    t2.start()
Example #2
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
Example #3
0
def main() -> int:
    # Handle program arguments
    ap = argparse.ArgumentParser(prog='', description='')
    ap.add_argument("port", help="Serial port", default="/dev/ttyACM0")
    ap.add_argument("-b",
                    "--baud-rate",
                    help="Serial baud",
                    default=9600,
                    type=int)
    ap.add_argument("-c", "--callsign", help="APRS callsign", required=True)
    args = ap.parse_args()

    # Open serial connection
    ser = serial.Serial(args.port, args.baud_rate, timeout=.1)

    # Open APRS-IS connection
    AIS = aprslib.IS(args.callsign,
                     passwd=aprslib.passcode(args.callsign),
                     port=14580)
    AIS.connect()

    # Handle incoming data
    try:
        while True:
            # Serial line
            line = str(ser.readline().decode().strip('\r\n'))
            if not line:
                continue

            # Ignore debug data
            if line[0] == "#":
                continue

            # Log
            print(line)

            # Send
            AIS.sendall(line)

    except KeyboardInterrupt as e:
        pass

    return 0
Example #4
0
    def __init__(self):
        parser = ConfigParser()
        parser.read_file(StringIO(CONFIG_DEFAULT))

        self._passcode = ""
        self._call = "NOCALL-1"
        self._longitude = 0.0
        self._latitude = 0.0
        self._sleep = 900
        self._symbol = "n"
        self._symbol_table = "/"

        if not os.path.exists(CONFIG_FILE):
            logging.info('Using default config')
        else:
            try:
                logging.info('Reading config file')
                with open(CONFIG_FILE, 'r') as fdc:
                    parser.readfp(fdc)
                logging.info('Config file %s read', CONFIG_FILE)
            except (IOError, SystemError):
                raise SystemError('No [APRS] section configured')

        self.call = parser.get('APRS', 'call')
        self.sleep = parser.get('APRS', 'sleep')
        self.symbol_table = parser.get('APRS', 'symbol_table')
        self.symbol = parser.get('APRS', 'symbol')

        lat, lon = [
            float(parser.get('APRS', c)) for c in ('latitude', 'longitude')
        ]
        if not lat or not lon:
            self.latitude, self.longitude = get_coordinates()
        else:
            self.latitude, self.longitude = lat, lon

        if parser.has_option('APRS', 'passcode'):
            self.passcode = parser.get('APRS', 'passcode')
        else:
            logging.warning('Generating passcode')
            self.passcode = aprslib.passcode(self.call)
Example #5
0
    def test_valid_input(self):
        testData = [
            ['TESTCALL', 31742],
            ['testcall', 31742],
            ['tEsTcAlL', 31742],
            ['tEsTcAlL', 31742],
            ['TESTCALL-', 31742],
            ['TESTCALL-12', 31742],
            ['TESTCALL-0', 31742],
            ['N0CALL', 13023],
            ['SUCHCALL', 27890],
            ['MUCHSIGN', 27128],
            ['WOW', 29613],
            ]

        results = []

        for callsign, x in testData:
            results.append([callsign, passcode(callsign)])

        self.assertEqual(testData, results)
Example #6
0
    def send(self, packets: List[APRSPacket]):
        if not isinstance(packets, Sequence) or isinstance(packets, str):
            packets = [packets]
        packets = [
            packet
            if not isinstance(packet, str) else APRSPacket.from_frame(packet)
            for packet in packets
        ]

        if len(self.__send_buffer) > 0:
            packets.extend(self.__send_buffer)
            self.__send_buffer.clear()

        callsigns = {packet.from_callsign for packet in packets}
        packets = {
            callsign:
            [packet for packet in packets if packet.from_callsign == callsign]
            for callsign in callsigns
        }

        if len(packets) > 0:
            logging.info(
                f"sending {len(packets)} packet(s) to {self.location}: {packets}"
            )
            for callsign, callsign_packets in packets.items():
                try:
                    frames = [packet.frame for packet in callsign_packets]
                    aprs_is = aprslib.IS(callsign, aprslib.passcode(callsign),
                                         self.hostname, self.port)
                    aprs_is.connect()
                    if len(frames) > 0:
                        aprs_is.sendall(r"\rn".join(frames))
                    aprs_is.close()
                except ConnectionError as error:
                    logging.info(
                        f"could not send packet(s) ({error}); reattempting on next iteration",
                    )
                    self.__send_buffer.extend(packets)
Example #7
0
 def test_nonstring(self):
     with self.assertRaises(AssertionError):
         passcode(5)
Example #8
0
from geopy.geocoders import Nominatim
from aprslib.util import latitude_to_ddm, longitude_to_ddm 
from time import sleep
from os import system

##### Define Variables
# Misc Variables
degree_sign= u'\N{DEGREE SIGN}'
linefeed = "\r\n"
startup = 0
# URL/File Variables
aprsfi_url = "https://api.aprs.fi/api/get"
owm_base_url = "http://api.openweathermap.org/data/2.5/weather"
# APRS-IS Variables
port = 14580
passcode = aprslib.passcode(config.aprsbot_callsign)
icon = "/$" # First character is the table index and second is the table code. Some lists show this reversed (code first and then table index).
# Telebot Variables
BOT_TOKEN = config.telegramkeys["my_bot_token"]
BOT_INTERVAL = 3
BOT_TIMEOUT = 30
bot = None
## Configure Objects
geolocator = Nominatim(user_agent="aprstweet")
AIS = aprslib.IS(config.aprsbot_callsign, passwd = passcode, port=port)
AIS.connect() # APRS-IS Connection Opened

## Define Functions
def bot_polling():
    global bot
    print("Starting bot polling now")
Example #9
0
def main():
    # Handle program arguments
    ap = argparse.ArgumentParser(
        prog='aprsbcn',
        description='Command-line tool for sending out APRS-IS beacons')
    ap.add_argument("-c", "--callsign", help="Callsign", required=True)
    ap.add_argument("--ssid", help="APRS SSID", default="-10")
    ap.add_argument("--symbol", help="APRS Symbol", default="0")
    ap.add_argument(
        "--latlong",
        help="Comma-seperated lat and long of the station (defaults to geoip)",
        default=None)
    ap.add_argument("--message", help="APRS message", default="APRS-BCN")
    ap.add_argument("--wx-mode", help="Run in WX mode", action="store_true")
    ap.add_argument("--dry-run",
                    help="Run without actually sending the packet",
                    action="store_true")
    args = ap.parse_args()

    # Determine station location
    location = args.latlong
    if not location:
        print("Using geoip-supplied location")
        location = fetch_geoip_location()
    else:
        print("Using user-supplied location")

    # Convert the location to a useful format
    lat_fmt = float(location.split(",")[0])
    long_fmt = float(location.split(",")[1])
    lat_ddm = aprslib.util.latitude_to_ddm(lat_fmt)
    long_ddm = aprslib.util.longitude_to_ddm(long_fmt)

    # Get the location weather
    wx_json = requests.get(
        "http://wttr.in/{lat_fmt},{long_fmt}?format=j1".format(
            lat_fmt=lat_fmt, long_fmt=long_fmt)).json()
    temperature_f = wx_json["current_condition"][0]["temp_F"].zfill(3)
    wind_direction = wx_json["current_condition"][0]["winddirDegree"].zfill(3)
    wind_speed = wx_json["current_condition"][0]["windspeedMiles"].zfill(3)
    humidity_percent = wx_json["weather"][0]["hourly"][0]["humidity"].zfill(3)
    pressure = wx_json["weather"][0]["hourly"][0]["pressure"] + "0"

    # Construct packet
    packet_header = "" + args.callsign.upper() + args.ssid + ">APRS:!"
    packet_position = "" + lat_ddm + "/" + long_ddm
    packet_wx_data = "" + wind_direction + "/" + wind_speed + "t" + \
        temperature_f + "h" + humidity_percent + "b" + pressure
    wx_packet = "" + packet_header + packet_position + \
        "_" + packet_wx_data + args.message
    info_packet = "" + packet_header + packet_position + args.symbol + args.message

    if args.wx_mode:
        packet = wx_packet
    else:
        packet = info_packet

    # Send
    print("Sending packet: " + packet)
    if not args.dry_run:
        AIS = aprslib.IS(args.callsign,
                         passwd=aprslib.passcode(args.callsign),
                         port=14580)
        AIS.connect()
        AIS.sendall(packet)
    else:
        print("--dry-run mode enabled. Not actually sending packet")

    return 0
Example #10
0
def main():
    # Create logger, must be global for functions and threads
    global logger

    # Create telemetry dictionary
    global telemetryDictionary
    telemetryDictionary = {}

    # Connect to Database
    global dbc
    global db
    # Open database connection
    db = pymysql.connect(args.dbhost, args.dbuser, args.dbpass, args.db)
    # prepare a cursor object using cursor() method
    dbc = db.cursor()
    sql = "SHOW TABLES"
    try:
        # Execute the SQL command
        dbc.execute(sql)
    except:
        logger.error("Error: unable to fetch data", exc_info=True)

    # Log to sys.prefix + aprs2influxdb.log
    if args.logfile != "":
        log = args.logfile
    else:
        log = os.path.join(sys.prefix, "aprs2db.log")
    logger = createLog(log, args.debug)

    # Start login for APRS-IS
    logger.info("Logging into APRS-IS as {0} on {1}:{2}".format(
        args.callsign, args.host, args.port))
    if args.callsign == "nocall":
        logger.warning("APRS-IS ignores the callsign \"nocall\"!")

    # Open APRS-IS connection
    passcode = aprslib.passcode(args.callsign)
    AIS = aprslib.IS(args.callsign,
                     passwd=passcode,
                     host=args.host,
                     port=args.port)

    # Set aprslib logger equal to aprs2influxdb logger
    AIS.logger = logger

    # Connect to APRS-IS servers
    try:
        AIS.connect()

    except aprslib.exceptions.LoginError:
        # An error occured
        logger.error('An aprslib LoginError occured', exc_info=True)

    except aprslib.exceptions.ConnectionError:
        # An error occured
        logger.error('An aprslib ConnectionError occured', exc_info=True)

    # Create heartbeat
    t1 = threading.Thread(target=heartbeat,
                          args=(AIS, args.callsign, args.interval))

    # Create consumer
    t2 = threading.Thread(target=consumer, args=(AIS, ))

    # Start threads
    t1.start()
    t2.start()