Compare commits

..

No commits in common. "50085de7dba57de380a8798ae091943729aa7c8d" and "acdee84d3ebad6f26a503ea89e9caa373bdcb6bb" have entirely different histories.

7 changed files with 56 additions and 78 deletions

View File

@ -4,7 +4,6 @@ from datetime import date, timedelta
import configparser import configparser
import csv import csv
import datetime import datetime
import timeago
import ast import ast
import glob import glob
import json, operator import json, operator
@ -21,6 +20,34 @@ def read_config():
config.read('config.ini') config.read('config.ini')
return config return config
def read_logs(log_folder):
# Read some log files
# UTC time, so let's look at tomorrow, today, and yesterday.
today = date.today()
yesterday = today - timedelta(days = 1)
tomorrow = today + timedelta(days = 1)
file_list = glob.glob(log_folder+str(yesterday)+"*") + \
glob.glob(log_folder+str(today)+"*") + \
glob.glob(log_folder+str(tomorrow)+"*")
# https://stackoverflow.com/a/66071962
json_array = []
for file in file_list:
with open(file, encoding='utf-8') as csvf:
csvReader = csv.DictReader(csvf)
for row in csvReader:
#add this python dict to json array
json_array.append(row)
# Add the call and location of this station to the packet info
config = read_config()
for item in json_array:
item['station_name'] = config['Settings']['station_call']
item['station_lat'] = config['Settings']['station_lat']
item['station_lon'] = config['Settings']['station_lon']
return(json_array)
def dict_factory(cursor, row): def dict_factory(cursor, row):
d = {} d = {}
for idx, col in enumerate(cursor.description): for idx, col in enumerate(cursor.description):
@ -91,33 +118,23 @@ def index():
# Get list of recent packets using API # Get list of recent packets using API
# TODO use relative path # TODO use relative path
#frames = json.loads(requests.get(url_for("packets", _external=True)).text)['data'] response = json.loads(requests.get("https://digi.w1cdn.net/aprs_api/packets").text)['data']
#frames = json.loads(requests.get("https://digi.w1cdn.net/aprs_api/packets").text)['data']
frames = json.loads(requests.get(config['Settings']['base_url']+"/packets").text)['data']
for frame in frames:
if frame['created'] != None:
frame['time_ago'] = timeago.format(frame['created_unix'], datetime.datetime.now())
# Play with function to create station list # Play with function to create station list
#stations = select_all_stations(get_db_connection()) #stations = select_all_stations(get_db_connection())
#print(url_for("static", filename="test.txt", _external=True)) #print(url_for("static", filename="test.txt", _external=True))
# this should work: stations = json.loads(requests.get(url_for("stations", _external=True)).text)['data'] # this should work: stations = json.loads(requests.get(url_for("stations", _external=True)).text)['data']
#stations = json.loads(requests.get(url_for("stations", _external=True)).text)['data'] stations = json.loads(requests.get("https://digi.w1cdn.net/aprs_api/stations").text)['data']
#stations = json.loads(requests.get("https://digi.w1cdn.net/aprs_api/stations").text)['data']
stations = json.loads(requests.get(config['Settings']['base_url']+"/stations").text)['data']
# Convert unix time to datetime on the fly because I'm lazy right now # Convert unix time to datetime on the fly because I'm lazy right now
for station in stations: for station in stations:
if station['last_heard_unix'] != None: if station['last_heard_unix'] != None:
station['last_heard'] = datetime.datetime.utcfromtimestamp(station['last_heard_unix']) station['last_heard'] = datetime.datetime.utcfromtimestamp(station['last_heard_unix'])
station['time_ago'] = timeago.format(station['last_heard_unix'], datetime.datetime.now())
return render_template('index.html', return render_template('index.html',
station_call = config['Settings']['station_call'], station_call = config['Settings']['station_call'],
station_lat = config['Settings']['station_lat'], station_lat = config['Settings']['station_lat'],
station_lon = config['Settings']['station_lon'], station_lon = config['Settings']['station_lon'],
frames = frames, frames = response,
stations = stations) stations = stations)
class Packets(Resource): class Packets(Resource):
@ -152,6 +169,7 @@ class Stations(Resource):
# Read config # Read config
config = read_config() config = read_config()
log_folder = config['Settings']['log_folder']
# Start subprocess to watch KISS connection # Start subprocess to watch KISS connection
import subprocess import subprocess

View File

@ -1,12 +1,13 @@
[Settings] [Settings]
# Path to direwolf log folder, include trailing slash
log_folder = logs/
#log_folder = /home/pi/logs/direwolf/
# Name and location of this station, for inclusion in the API # Name and location of this station, for inclusion in the API
station_call = W1CDN-1 station_call = W1CDN-1
station_lat = 47.941500 station_lat = 47.941500
station_lon = -97.027000 station_lon = -97.027000
# Base URL for application (no trailing slash)
base_url = https://digi.w1cdn.net/aprs_api
# How long to keep packets (frames) e.g., "2 days", "5 minutes" # How long to keep packets (frames) e.g., "2 days", "5 minutes"
keep_time = "2 days" keep_time = "2 days"

View File

@ -3,7 +3,6 @@ db_frames_fields = ("id",
"addresse", "addresse",
"alive", "alive",
"altitude", "altitude",
"body",
"comment", "comment",
"course", "course",
"created", "created",
@ -12,7 +11,6 @@ db_frames_fields = ("id",
"frame", "frame",
"from", "from",
"gpsfixstatus", "gpsfixstatus",
"id",
"latitude", "latitude",
"longitude", "longitude",
"mbits", "mbits",
@ -46,7 +44,6 @@ db_frames_fields = ("id",
"tEQNS", "tEQNS",
"tPARM", "tPARM",
"tUNIT", "tUNIT",
"type",
"via", "via",
"weather", "weather",
"wx_raw_timestamp") "wx_raw_timestamp")

View File

@ -7,8 +7,6 @@ import aprslib
import configparser import configparser
import time import time
import logging import logging
from apscheduler.schedulers.asyncio import AsyncIOScheduler
import time
def read_config(): def read_config():
config = configparser.ConfigParser() config = configparser.ConfigParser()
@ -20,15 +18,6 @@ def get_db_connection():
conn.row_factory = sqlite3.Row conn.row_factory = sqlite3.Row
return conn 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(): def main():
# Add the call and location of this station to the packet info # Add the call and location of this station to the packet info
@ -39,45 +28,34 @@ def main():
logging.basicConfig(filename=config['Settings']['log_path'], level=logging.DEBUG, \ logging.basicConfig(filename=config['Settings']['log_path'], level=logging.DEBUG, \
format='%(asctime)s - %(message)s') 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 = aprs.TCPKISS(host=config['Settings']['kiss_host'], port=int(config['Settings']['kiss_port']))
ki.start() ki.start()
#scheduler = AsyncIOScheduler()
#scheduler.add_job(refresh_kiss_connection, 'interval', hours = 1, args = [ki])
#scheduler.start()
# Make a simple frame and send it # Make a simple frame and send it
# frame = aprs.APRSFrame.ui( frame = aprs.APRSFrame.ui(
# destination="APZ001", destination="APZ001",
# source=config['Settings']['mycall'], source=config['Settings']['mycall'],
# path=["WIDE1-1"], path=["WIDE1-1"],
# info=b">Hello World!", info=b">Hello World!",
# ) )
#ki.write(frame) #ki.write(frame)
# Watch for new packets to come in # Watch for new packets to come in
while True: while True:
conn = get_db_connection() conn = get_db_connection()
for frame in ki.read(min_frames=1): for frame in ki.read(min_frames=1):
logging.debug("New packet, trying to parse")
logging.debug(str(frame))
try: try:
try: a = aprslib.parse(str(frame))
a = aprslib.parse(str(frame))
except Exception as error:
logging.error("Error with aprslib:", error)
a['station_call'] = config['Settings']['station_call'] a['station_call'] = config['Settings']['station_call']
a['station_lat'] = config['Settings']['station_lat'] a['station_lat'] = config['Settings']['station_lat']
a['station_lon'] = config['Settings']['station_lon'] a['station_lon'] = config['Settings']['station_lon']
a['created_unix'] = int(time.time()) a['created_unix'] = int(time.time())
print(a)
# Make this a string and deal with it later (probably a mistake) # Make this a string and deal with it later (probably a mistake)
a['path'] = str(a['path']) a['path'] = str(a['path'])
if 'subpacket' in a:
a['subpacket'] = str(a['subpacket'])
#logging.debug(a['path'])
# Store true/false as 1/0 # Store true/false as 1/0
if 'alive' in a: if 'alive' in a:
if a['alive'] == True: if a['alive'] == True:
@ -87,15 +65,14 @@ def main():
# Build an INSERT statement based on the fields we have from the frame # Build an INSERT statement based on the fields we have from the frame
attrib_names = ', '.join('"%s"' % w for w in a.keys()) attrib_names = ', '.join('"%s"' % w for w in a.keys())
attrib_values = ", ".join("?" * len(a.keys())) attrib_values = ", ".join("?" * len(a.keys()))
logging.debug(attrib_names)
logging.debug(a.values())
logging.debug("Inserting into database")
try: try:
# Insert data # Insert data
sql = "INSERT INTO frames ("+attrib_names+") VALUES ("+attrib_values+")" sql = "INSERT INTO frames ("+attrib_names+") VALUES ("+attrib_values+")"
logging.debug(sql)
conn.execute(sql, list(a.values())) conn.execute(sql, list(a.values()))
logging.debug("Frames table updated")
# TODO update stations table here # TODO update stations table here
# Original intent was to include the id from the frames table, # Original intent was to include the id from the frames table,
# but that would mean making another query. # but that would mean making another query.
@ -110,9 +87,11 @@ def main():
ON CONFLICT([from]) \ ON CONFLICT([from]) \
DO UPDATE SET count = count + 1,\ DO UPDATE SET count = count + 1,\
last_heard_unix = excluded.last_heard_unix;" last_heard_unix = excluded.last_heard_unix;"
#print(query3)
logging.debug(query3)
# Insert/update data # Insert/update data
conn.execute(query3) conn.execute(query3)
logging.debug("Station table updated")
conn.commit() conn.commit()
#except: #except:
# print("Stations table couldn't be updated.") # print("Stations table couldn't be updated.")
@ -124,9 +103,9 @@ def main():
except: except:
#print("Error with SQLite!") #print("Error with SQLite!")
logging.error("Error with SQLite!") logging.error("Error with SQLite!")
except Exception as error: except:
#print("Frame could not be parsed.") #print("Frame could not be parsed.")
logging.error("Frame could not be parsed:", error) logging.error("Frame could not be parsed.")
conn.close() conn.close()

View File

@ -6,4 +6,3 @@ kiss
aprslib aprslib
sqlite3 sqlite3
json json
timeago

View File

@ -12,10 +12,7 @@
</head> </head>
<body> <body>
<h1>{{station_call}} Status</h1> <h1>{{station_call}} Status</h1>
Station location: {{station_lat}}, {{station_lon}} {{station_lat}}, {{station_lon}}
<h2> About </h2>
This is a work in progress. See <a href="https://amiok.net/gitea/W1CDN/aprs_tool">https://amiok.net/gitea/W1CDN/aprs_tool</a> for usage.
<h2> Recent RF Packets </h2> <h2> Recent RF Packets </h2>
<table> <table>
@ -24,7 +21,6 @@ This is a work in progress. See <a href="https://amiok.net/gitea/W1CDN/aprs_tool
<th> object_name </th> <th> object_name </th>
<th> raw </th> <th> raw </th>
<th> created (utc) </th> <th> created (utc) </th>
<th> relative </th>
<th> more </th> <th> more </th>
</tr> </tr>
{% for i in frames %} {% for i in frames %}
@ -33,7 +29,6 @@ This is a work in progress. See <a href="https://amiok.net/gitea/W1CDN/aprs_tool
<td> {{ i['object_name'] }} </td> <td> {{ i['object_name'] }} </td>
<td> {{ i['raw'] }} </td> <td> {{ i['raw'] }} </td>
<td> {{ i['created'] }} </td> <td> {{ i['created'] }} </td>
<td> {{ i['time_ago'] }} </td>
<td> <a href="https://digi.w1cdn.net/aprs_api/packets?id={{ i['id'] }}">query</a>, <td> <a href="https://digi.w1cdn.net/aprs_api/packets?id={{ i['id'] }}">query</a>,
<a href="https://aprs.fi/#!mt=roadmap&z=12&call=a%2F{{ i['from'] }}">aprs.fi</a></td> <a href="https://aprs.fi/#!mt=roadmap&z=12&call=a%2F{{ i['from'] }}">aprs.fi</a></td>
</tr> </tr>
@ -45,7 +40,6 @@ This is a work in progress. See <a href="https://amiok.net/gitea/W1CDN/aprs_tool
<tr> <tr>
<th> from </th> <th> from </th>
<th> last heard (utc) </th> <th> last heard (utc) </th>
<th> relative </th>
<th> count </th> <th> count </th>
<th> more </th> <th> more </th>
</tr> </tr>
@ -53,12 +47,13 @@ This is a work in progress. See <a href="https://amiok.net/gitea/W1CDN/aprs_tool
<tr> <tr>
<td> <a href="https://digi.w1cdn.net/aprs_api/packets?from={{ i['from'] }}">{{ i['from'] }}</a> </td> <td> <a href="https://digi.w1cdn.net/aprs_api/packets?from={{ i['from'] }}">{{ i['from'] }}</a> </td>
<td> {{ i['last_heard'] }} </td> <td> {{ i['last_heard'] }} </td>
<td> {{ i['time_ago'] }} </td>
<td> {{ i['count']}} </td> <td> {{ i['count']}} </td>
<td> <a href="https://aprs.fi/#!mt=roadmap&z=12&call=a%2F{{ i['from'] }}">aprs.fi</a></td> <td> <a href="https://aprs.fi/#!mt=roadmap&z=12&call=a%2F{{ i['from'] }}">aprs.fi</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
<h2> Help </h2>
This is a work in progress. See <a href="https://amiok.net/gitea/W1CDN/aprs_tool">https://amiok.net/gitea/W1CDN/aprs_tool</a> for usage.
</body> </body>
</html> </html>

View File

@ -1,11 +0,0 @@
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())