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()
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
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
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)
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)
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)
def test_nonstring(self): with self.assertRaises(AssertionError): passcode(5)
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")
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
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()