mirror of
https://github.com/craigerl/aprsd.git
synced 2024-12-03 05:25:22 -05:00
Update WebChat
This patch changes the location string to include Compass rose instead of bearing degrees. Also adds the time timeago package for calculating how much time since the beacon to format to something like "12 days ago".
This commit is contained in:
parent
d42638efe3
commit
9f7d169c18
@ -1,7 +1,6 @@
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import math
|
||||
import signal
|
||||
import sys
|
||||
import threading
|
||||
@ -14,13 +13,14 @@ from flask_httpauth import HTTPBasicAuth
|
||||
from flask_socketio import Namespace, SocketIO
|
||||
from geopy.distance import geodesic
|
||||
from oslo_config import cfg
|
||||
import timeago
|
||||
from werkzeug.security import check_password_hash, generate_password_hash
|
||||
import wrapt
|
||||
|
||||
import aprsd
|
||||
from aprsd import (
|
||||
cli_helper, client, packets, plugin_utils, stats, threads, utils,
|
||||
)
|
||||
from aprsd import cli_helper, client, packets, plugin_utils, stats, threads
|
||||
from aprsd import utils
|
||||
from aprsd import utils as aprsd_utils
|
||||
from aprsd.client import client_factory, kiss
|
||||
from aprsd.main import cli
|
||||
from aprsd.threads import aprsd as aprsd_threads
|
||||
@ -131,47 +131,6 @@ def verify_password(username, password):
|
||||
return username
|
||||
|
||||
|
||||
def calculate_initial_compass_bearing(point_a, point_b):
|
||||
"""
|
||||
Calculates the bearing between two points.
|
||||
The formulae used is the following:
|
||||
θ = atan2(sin(Δlong).cos(lat2),
|
||||
cos(lat1).sin(lat2) − sin(lat1).cos(lat2).cos(Δlong))
|
||||
:Parameters:
|
||||
- `pointA: The tuple representing the latitude/longitude for the
|
||||
first point. Latitude and longitude must be in decimal degrees
|
||||
- `pointB: The tuple representing the latitude/longitude for the
|
||||
second point. Latitude and longitude must be in decimal degrees
|
||||
:Returns:
|
||||
The bearing in degrees
|
||||
:Returns Type:
|
||||
float
|
||||
"""
|
||||
if (type(point_a) is not tuple) or (type(point_b) is not tuple):
|
||||
raise TypeError("Only tuples are supported as arguments")
|
||||
|
||||
lat1 = math.radians(point_a[0])
|
||||
lat2 = math.radians(point_b[0])
|
||||
|
||||
diff_long = math.radians(point_b[1] - point_a[1])
|
||||
|
||||
x = math.sin(diff_long) * math.cos(lat2)
|
||||
y = math.cos(lat1) * math.sin(lat2) - (
|
||||
math.sin(lat1)
|
||||
* math.cos(lat2) * math.cos(diff_long)
|
||||
)
|
||||
|
||||
initial_bearing = math.atan2(x, y)
|
||||
|
||||
# Now we have the initial bearing but math.atan2 return values
|
||||
# from -180° to + 180° which is not what we want for a compass bearing
|
||||
# The solution is to normalize the initial bearing as shown below
|
||||
initial_bearing = math.degrees(initial_bearing)
|
||||
compass_bearing = (initial_bearing + 360) % 360
|
||||
|
||||
return compass_bearing
|
||||
|
||||
|
||||
def _build_location_from_repeat(message):
|
||||
# This is a location message Format is
|
||||
# ^ld^callsign:latitude,longitude,altitude,course,speed,timestamp
|
||||
@ -188,16 +147,19 @@ def _build_location_from_repeat(message):
|
||||
course = float(b[3])
|
||||
speed = float(b[4])
|
||||
time = int(b[5])
|
||||
compass_bearing = aprsd_utils.degrees_to_cardinal(course)
|
||||
data = {
|
||||
"callsign": callsign,
|
||||
"lat": lat,
|
||||
"lon": lon,
|
||||
"altitude": alt,
|
||||
"course": course,
|
||||
"compass_bearing": compass_bearing,
|
||||
"speed": speed,
|
||||
"lasttime": time,
|
||||
"timeago": timeago.format(time),
|
||||
}
|
||||
LOG.warning(f"Location data from REPEAT {data}")
|
||||
LOG.debug(f"Location data from REPEAT {data}")
|
||||
return data
|
||||
|
||||
|
||||
@ -208,25 +170,32 @@ def _calculate_location_data(location_data):
|
||||
alt = location_data["altitude"]
|
||||
speed = location_data["speed"]
|
||||
lasttime = location_data["lasttime"]
|
||||
timeago_str = location_data.get(
|
||||
"timeago",
|
||||
timeago.format(lasttime),
|
||||
)
|
||||
# now calculate distance from our own location
|
||||
distance = 0
|
||||
if CONF.webchat.latitude and CONF.webchat.longitude:
|
||||
our_lat = float(CONF.webchat.latitude)
|
||||
our_lon = float(CONF.webchat.longitude)
|
||||
distance = geodesic((our_lat, our_lon), (lat, lon)).kilometers
|
||||
bearing = calculate_initial_compass_bearing(
|
||||
bearing = aprsd_utils.calculate_initial_compass_bearing(
|
||||
(our_lat, our_lon),
|
||||
(lat, lon),
|
||||
)
|
||||
compass_bearing = aprsd_utils.degrees_to_cardinal(bearing)
|
||||
return {
|
||||
"callsign": location_data["callsign"],
|
||||
"lat": lat,
|
||||
"lon": lon,
|
||||
"altitude": alt,
|
||||
"course": f"{bearing:0.1f}",
|
||||
"compass_bearing": compass_bearing,
|
||||
"speed": speed,
|
||||
"lasttime": lasttime,
|
||||
"distance": f"{distance:0.3f}",
|
||||
"timeago": timeago_str,
|
||||
"distance": f"{distance:0.1f}",
|
||||
}
|
||||
|
||||
|
||||
|
@ -174,14 +174,29 @@ def load_entry_points(group):
|
||||
print(traceback.format_exc(), file=sys.stderr)
|
||||
|
||||
|
||||
def calculate_initial_compass_bearing(start, end):
|
||||
if (type(start) != tuple) or (type(end) != tuple): # noqa: E721
|
||||
def calculate_initial_compass_bearing(point_a, point_b):
|
||||
"""
|
||||
Calculates the bearing between two points.
|
||||
The formulae used is the following:
|
||||
θ = atan2(sin(Δlong).cos(lat2),
|
||||
cos(lat1).sin(lat2) − sin(lat1).cos(lat2).cos(Δlong))
|
||||
:Parameters:
|
||||
- `pointA: The tuple representing the latitude/longitude for the
|
||||
first point. Latitude and longitude must be in decimal degrees
|
||||
- `pointB: The tuple representing the latitude/longitude for the
|
||||
second point. Latitude and longitude must be in decimal degrees
|
||||
:Returns:
|
||||
The bearing in degrees
|
||||
:Returns Type:
|
||||
float
|
||||
"""
|
||||
if (type(point_a) != tuple) or (type(point_b) != tuple): # noqa: E721
|
||||
raise TypeError("Only tuples are supported as arguments")
|
||||
|
||||
lat1 = math.radians(float(start[0]))
|
||||
lat2 = math.radians(float(end[0]))
|
||||
lat1 = math.radians(float(point_a[0]))
|
||||
lat2 = math.radians(float(point_b[0]))
|
||||
|
||||
diff_long = math.radians(float(end[1]) - float(start[1]))
|
||||
diff_long = math.radians(float(point_b[1]) - float(point_a[1]))
|
||||
|
||||
x = math.sin(diff_long) * math.cos(lat2)
|
||||
y = math.cos(lat1) * math.sin(lat2) - (
|
||||
|
@ -17,25 +17,24 @@ function reload_popovers() {
|
||||
}
|
||||
|
||||
function build_location_string(msg) {
|
||||
dt = new Date(parseInt(msg['lasttime']) * 1000);
|
||||
loc = "Last Location Update: " + dt.toLocaleString();
|
||||
loc += "<br>Latitude: " + msg['lat'] + "<br>Longitude: " + msg['lon'];
|
||||
loc += "<br>" + "Altitude: " + msg['altitude'] + " m";
|
||||
loc += "<br>" + "Speed: " + msg['speed'] + " kph";
|
||||
loc += "<br>" + "Bearing: " + msg['course'] + "°";
|
||||
loc += "<br>" + "distance: " + msg['distance'] + " km";
|
||||
return loc;
|
||||
dt = new Date(parseInt(msg['lasttime']) * 1000);
|
||||
loc = "Last Location Update: " + dt.toLocaleString();
|
||||
loc += "<br>Latitude: " + msg['lat'] + "<br>Longitude: " + msg['lon'];
|
||||
loc += "<br>" + "Altitude: " + msg['altitude'] + " m";
|
||||
loc += "<br>" + "Speed: " + msg['speed'] + " kph";
|
||||
loc += "<br>" + "Bearing: " + msg['compass_bearing'];
|
||||
loc += "<br>" + "distance: " + msg['distance'] + " km";
|
||||
return loc;
|
||||
}
|
||||
|
||||
function build_location_string_small(msg) {
|
||||
|
||||
dt = new Date(parseInt(msg['lasttime']) * 1000);
|
||||
|
||||
dt = new Date(parseInt(msg['lasttime']) * 1000);
|
||||
loc = "" + msg['distance'] + "km";
|
||||
//loc += "Lat " + msg['lat'] + " Lon " + msg['lon'];
|
||||
loc += "@" + msg['course'] + "°";
|
||||
loc += " " + msg['compass_bearing'];
|
||||
//loc += " Distance " + msg['distance'] + " km";
|
||||
loc += " " + dt.toLocaleString();
|
||||
//loc += " " + dt.toLocaleString();
|
||||
loc += " " + msg['timeago'];
|
||||
return loc;
|
||||
}
|
||||
|
||||
@ -346,9 +345,9 @@ function create_callsign_tab_content(callsign, active=false) {
|
||||
item_html += '<div class="" style="border: 1px solid #999999;background-color:#aaaaaa;">';
|
||||
item_html += '<div class="row" style="padding-top:4px;padding-bottom:4px;background-color:#aaaaaa;margin:0px;">';
|
||||
item_html += '<div class="d-flex col-md-10 justify-content-left" style="padding:0px;margin:0px;">';
|
||||
item_html += '<button onclick="call_callsign_location(\''+callsign+'\');" style="margin-left:2px;padding: 0px 4px 0px 4px;" type="button" class="btn btn-primary">';
|
||||
item_html += '<span id="'+location_id+'Spinner" class="d-none spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>Update</button>';
|
||||
item_html += ' <span id="'+location_id+'">'+location_str+'</span></div>';
|
||||
item_html += '<button onclick="call_callsign_location(\''+callsign+'\');" style="margin-left:2px;padding: 0px 4px 0px 4px;font-size: .9rem" type="button" class="btn btn-primary">';
|
||||
item_html += '<span id="'+location_id+'Spinner" class="d-none spinner-border spinner-border-sm" role="status" aria-hidden="true" style="font-size: .9rem"></span>Update</button>';
|
||||
item_html += ' <span id="'+location_id+'" style="font-size: .9rem">'+location_str+'</span></div>';
|
||||
item_html += '</div>';
|
||||
item_html += '<div class="speech-wrapper" id="'+wrapper_id+'"></div>';
|
||||
item_html += '</div>';
|
||||
|
@ -34,7 +34,7 @@ imagesize==1.4.1 # via sphinx
|
||||
iniconfig==2.0.0 # via pytest
|
||||
isort==5.13.2 # via -r requirements-dev.in, gray
|
||||
jinja2==3.1.4 # via sphinx
|
||||
libcst==1.5.0 # via fixit
|
||||
libcst==1.5.1 # via fixit
|
||||
m2r==0.3.1 # via -r requirements-dev.in
|
||||
markupsafe==3.0.2 # via jinja2
|
||||
mccabe==0.7.0 # via flake8
|
||||
|
@ -27,3 +27,4 @@ tzlocal
|
||||
update_checker
|
||||
wrapt
|
||||
pytz
|
||||
timeago
|
||||
|
@ -37,8 +37,8 @@ markupsafe==3.0.2 # via jinja2, werkzeug
|
||||
marshmallow==3.23.1 # via dataclasses-json
|
||||
mypy-extensions==1.0.0 # via typing-inspect
|
||||
netaddr==1.3.0 # via oslo-config
|
||||
oslo-config==9.6.0 # via -r requirements.in
|
||||
oslo-i18n==6.4.0 # via oslo-config
|
||||
oslo-config==9.7.0 # via -r requirements.in
|
||||
oslo-i18n==6.5.0 # via oslo-config
|
||||
packaging==24.2 # via marshmallow
|
||||
pbr==6.1.0 # via oslo-i18n, stevedore
|
||||
pluggy==1.5.0 # via -r requirements.in
|
||||
@ -57,9 +57,10 @@ shellingham==1.5.4 # via -r requirements.in
|
||||
simple-websocket==1.1.0 # via python-engineio
|
||||
six==1.16.0 # via -r requirements.in
|
||||
soupsieve==2.6 # via beautifulsoup4
|
||||
stevedore==5.3.0 # via oslo-config
|
||||
stevedore==5.4.0 # via oslo-config
|
||||
tabulate==0.9.0 # via -r requirements.in
|
||||
thesmuggler==1.0.1 # via -r requirements.in
|
||||
timeago==1.0.16 # via -r requirements.in
|
||||
typing-extensions==4.12.2 # via typing-inspect
|
||||
typing-inspect==0.9.0 # via dataclasses-json
|
||||
tzlocal==5.2 # via -r requirements.in
|
||||
|
Loading…
Reference in New Issue
Block a user