Skip to content

Commit

Permalink
Update WebChat
Browse files Browse the repository at this point in the history
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".
  • Loading branch information
hemna committed Nov 20, 2024
1 parent d42638e commit 9f7d169
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 73 deletions.
65 changes: 17 additions & 48 deletions aprsd/cmds/webchat.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import datetime
import json
import logging
import math
import signal
import sys
import threading
Expand All @@ -14,13 +13,14 @@
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
Expand Down Expand Up @@ -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
Expand All @@ -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


Expand All @@ -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}",
}


Expand Down
25 changes: 20 additions & 5 deletions aprsd/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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) - (
Expand Down
31 changes: 15 additions & 16 deletions aprsd/web/chat/static/js/send-message.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'] + "&nbsp;Lon " + msg['lon'];
loc += "@" + msg['course'] + "°";
loc += "&nbsp;" + msg['compass_bearing'];
//loc += "&nbsp;Distance " + msg['distance'] + " km";
loc += "&nbsp;" + dt.toLocaleString();
//loc += "&nbsp;" + dt.toLocaleString();
loc += "&nbsp;" + msg['timeago'];
return loc;
}

Expand Down Expand Up @@ -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 += '&nbsp;<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 += '&nbsp;<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>';
Expand Down
2 changes: 1 addition & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ tzlocal
update_checker
wrapt
pytz
timeago
7 changes: 4 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 9f7d169

Please sign in to comment.