diff --git a/constants.py b/constants.py index 8689d11..7ade087 100644 --- a/constants.py +++ b/constants.py @@ -3,6 +3,7 @@ db_frames_fields = ("id", "addresse", "alive", "altitude", +"body", "comment", "course", "created", @@ -11,6 +12,7 @@ db_frames_fields = ("id", "frame", "from", "gpsfixstatus", +"header_raw", "latitude", "longitude", "mbits", @@ -44,6 +46,7 @@ db_frames_fields = ("id", "tEQNS", "tPARM", "tUNIT", +"type", "via", "weather", "wx_raw_timestamp") diff --git a/kiss_and_db.py b/kiss_and_db.py index c799a70..9d74bfa 100644 --- a/kiss_and_db.py +++ b/kiss_and_db.py @@ -7,6 +7,8 @@ import aprslib import configparser import time import logging +from apscheduler.schedulers.asyncio import AsyncIOScheduler +import time def read_config(): config = configparser.ConfigParser() @@ -18,6 +20,15 @@ def get_db_connection(): conn.row_factory = sqlite3.Row return conn +def refresh_kiss_connection(kiss_conn): + logging.debug("Restarting KISS connection on schedule") + logging.debug("Stopping current connection") + kiss_conn.stop() + #logging.debug("Waiting 5 seconds") + #time.sleep(5) + logging.debug("Starting new connection") + kiss_conn.start() + def main(): # Add the call and location of this station to the packet info @@ -28,81 +39,95 @@ def main(): logging.basicConfig(filename=config['Settings']['log_path'], level=logging.DEBUG, \ format='%(asctime)s - %(message)s') - logging.debug('kiss_and_db.py running') + logging.debug('============= kiss_and_db.py running =============') ki = aprs.TCPKISS(host=config['Settings']['kiss_host'], port=int(config['Settings']['kiss_port'])) ki.start() + #scheduler = AsyncIOScheduler() + #scheduler.add_job(refresh_kiss_connection, 'interval', hours = 1, args = [ki]) + #scheduler.start() # Make a simple frame and send it - frame = aprs.APRSFrame.ui( - destination="APZ001", - source=config['Settings']['mycall'], - path=["WIDE1-1"], - info=b">Hello World!", - ) +# frame = aprs.APRSFrame.ui( +# destination="APZ001", +# source=config['Settings']['mycall'], +# path=["WIDE1-1"], +# info=b">Hello World!", +# ) #ki.write(frame) # Watch for new packets to come in while True: conn = get_db_connection() for frame in ki.read(min_frames=1): + logging.debug("New packet, trying to parse") + logging.debug(str(frame)) try: - a = aprslib.parse(str(frame)) - a['station_call'] = config['Settings']['station_call'] - a['station_lat'] = config['Settings']['station_lat'] - a['station_lon'] = config['Settings']['station_lon'] - a['created_unix'] = int(time.time()) - print(a) - # Make this a string and deal with it later (probably a mistake) - a['path'] = str(a['path']) - # Store true/false as 1/0 - if 'alive' in a: - if a['alive'] == True: - a['alive'] = 1 - else: - a['alive'] = 0 - # Build an INSERT statement based on the fields we have from the frame - attrib_names = ', '.join('"%s"' % w for w in a.keys()) - attrib_values = ", ".join("?" * len(a.keys())) - - try: - # Insert data - sql = "INSERT INTO frames ("+attrib_names+") VALUES ("+attrib_values+")" - conn.execute(sql, list(a.values())) - logging.debug("Frames table updated") - # TODO update stations table here - # Original intent was to include the id from the frames table, - # but that would mean making another query. - # It's not immediately needed, so I'm skipping it. - # Build query - # "from" is wrappedin [] because it is a reserved word and using '' doesn't work. - # https://www.sqlite.org/lang_keywords.html - #try: - station_update = "'"+a['from'] +"', '"+ str(a['created_unix']) +"', '1'" - query3 = "INSERT INTO stations ([from], last_heard_unix, count) \ - VALUES("+station_update+") \ - ON CONFLICT([from]) \ - DO UPDATE SET count = count + 1,\ - last_heard_unix = excluded.last_heard_unix;" - # Insert/update data - conn.execute(query3) - logging.debug("Station table updated") - conn.commit() - #except: - # print("Stations table couldn't be updated.") + a = aprslib.parse(str(frame)) + except Exception as error: + logging.error("Error with aprslib:", exc_info = error) + else: + a['station_call'] = config['Settings']['station_call'] + a['station_lat'] = config['Settings']['station_lat'] + a['station_lon'] = config['Settings']['station_lon'] + a['created_unix'] = int(time.time()) - # TODO remove packets that are older ('created') than a limit set in config.ini - # "5 minutes" also works - #conn.execute("DELETE FROM frames WHERE created < DATETIME('now', '"+config['Settings']['keep_time']+"')") - #conn.commit() - except: - #print("Error with SQLite!") - logging.error("Error with SQLite!") - except: + # Make this a string and deal with it later (probably a mistake) + a['path'] = str(a['path']) + if 'subpacket' in a: + a['subpacket'] = str(a['subpacket']) + #logging.debug(a['path']) + # Store true/false as 1/0 + if 'alive' in a: + if a['alive'] == True: + a['alive'] = 1 + else: + a['alive'] = 0 + # Build an INSERT statement based on the fields we have from the frame + attrib_names = ', '.join('"%s"' % w for w in a.keys()) + attrib_values = ", ".join("?" * len(a.keys())) + logging.debug(attrib_names) + logging.debug(a.values()) + + logging.debug("Inserting into database") + try: + # Insert data + sql = "INSERT INTO frames ("+attrib_names+") VALUES ("+attrib_values+")" + conn.execute(sql, list(a.values())) + logging.debug("Frames table updated") + # TODO update stations table here + # Original intent was to include the id from the frames table, + # but that would mean making another query. + # It's not immediately needed, so I'm skipping it. + # Build query + # "from" is wrappedin [] because it is a reserved word and using '' doesn't work. + # https://www.sqlite.org/lang_keywords.html + #try: + station_update = "'"+a['from'] +"', '"+ str(a['created_unix']) +"', '1'" + query3 = "INSERT INTO stations ([from], last_heard_unix, count) \ + VALUES("+station_update+") \ + ON CONFLICT([from]) \ + DO UPDATE SET count = count + 1,\ + last_heard_unix = excluded.last_heard_unix;" + # Insert/update data + conn.execute(query3) + logging.debug("Station table updated") + conn.commit() + #except: + # print("Stations table couldn't be updated.") + + # TODO remove packets that are older ('created') than a limit set in config.ini + # "5 minutes" also works + #conn.execute("DELETE FROM frames WHERE created < DATETIME('now', '"+config['Settings']['keep_time']+"')") + #conn.commit() + except Exception as error: + #print("Error with SQLite!") + logging.error("Error with SQLite!", exc_info = error) + except Exception as error: #print("Frame could not be parsed.") - logging.error("Frame could not be parsed.") + logging.error("Frame could not be parsed:", exc_info = error) conn.close() diff --git a/schema.sql b/schema.sql index a4a1cb9..c6fe23d 100644 --- a/schema.sql +++ b/schema.sql @@ -5,6 +5,7 @@ CREATE TABLE frames ( addresse TEXT, alive INT, altitude REAL, + body TEXT, comment TEXT, course REAL, created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, @@ -13,6 +14,7 @@ CREATE TABLE frames ( frame TEXT, "from" TEXT, gpsfixstatus TEXT, + header_raw TEXT, latitude REAL, longitude REAL, mbits INT, @@ -46,6 +48,7 @@ CREATE TABLE frames ( tEQNS TEXT, tPARM TEXT, tUNIT TEXT, + type TEXT, via TEXT, weather TEXT, wx_raw_timestamp TIMESTAMP diff --git a/test_async.py b/test_async.py new file mode 100644 index 0000000..62a9a6a --- /dev/null +++ b/test_async.py @@ -0,0 +1,11 @@ +import asyncio +import aprs + +async def main(): + transport, protocol = await aprs.create_tcp_connection("192.168.0.30", 8001) + + async for frame in protocol.read(): + print(frame) + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file