From a7e30b0bedb51d38f2730535d141a078d7cc9315 Mon Sep 17 00:00:00 2001 From: Hemna Date: Mon, 19 Feb 2024 20:15:56 -0500 Subject: [PATCH] Added location for callsign tabs in webchat This patch adds the new feature of trying to fetch the location distance and bearing for each callsign in the webchat tabs. This is handy when out on the go, you can get a general idea where the other callsign is when chatting with them. First aprsd webchat tries to fetch the location with aprs.fi REST api call. This assumes internet access. If this fails, then webchat will send a special message to REPEAT to ask it for the location information for the callsign. This will send over the air. --- aprsd/cmds/webchat.py | 24 ++++- aprsd/web/chat/static/js/send-message.js | 116 ++++++++++++++++------- aprsd/web/chat/templates/index.html | 2 +- 3 files changed, 102 insertions(+), 40 deletions(-) diff --git a/aprsd/cmds/webchat.py b/aprsd/cmds/webchat.py index 9f1bbb4..b60556f 100644 --- a/aprsd/cmds/webchat.py +++ b/aprsd/cmds/webchat.py @@ -282,9 +282,10 @@ def populate_callsign_location(callsign, data=None): except Exception: alt = 0 location_data = { + 'callsign': callsign, 'lat': lat, - 'long': lon, - 'alt': alt, + 'lon': lon, + 'altitude': alt, 'lasttime': int(aprs_data["entries"][0]["lasttime"]), 'course': float(aprs_data["entries"][0].get("course", 0)), 'speed': float(aprs_data["entries"][0].get("speed", 0)), @@ -295,6 +296,7 @@ def populate_callsign_location(callsign, data=None): return except Exception as ex: LOG.error(f"Failed to fetch aprs.fi '{ex}'") + LOG.error(ex) fallback = True if fallback: @@ -347,8 +349,10 @@ class WebChatProcessPacketThread(rx.APRSDProcessPacketThread): callsign_locations[callsign] = location_data send_location_data_to_browser(location_data) return - elif (from_call not in callsign_locations - and from_call not in callsign_no_track): + elif ( + from_call not in callsign_locations + and from_call not in callsign_no_track + ): # We have to ask aprs for the location for the callsign # We send a message packet to wb4bor-11 asking for location. populate_callsign_location(from_call) @@ -403,6 +407,12 @@ def _get_transport(stats): return transport, aprs_connection +@flask_app.route("/location/", methods=["POST"]) +def location(callsign): + LOG.debug(f"Fetch location for callsign {callsign}") + populate_callsign_location(callsign) + + @auth.login_required @flask_app.route("/") def index(): @@ -438,7 +448,7 @@ def index(): @auth.login_required -@flask_app.route("//send-message-status") +@flask_app.route("/send-message-status") def send_message_status(): LOG.debug(request) msgs = SentMessages() @@ -553,6 +563,10 @@ class SendMessageNamespace(Namespace): def handle_json(self, data): LOG.debug(f"WS json {data}") + def on_get_callsign_location(self, data): + LOG.debug(f"on_callsign_location {data}") + populate_callsign_location(data["callsign"]) + def setup_logging(flask_app, loglevel, quiet): flask_log = logging.getLogger("werkzeug") diff --git a/aprsd/web/chat/static/js/send-message.js b/aprsd/web/chat/static/js/send-message.js index 3c0a986..f39152f 100644 --- a/aprsd/web/chat/static/js/send-message.js +++ b/aprsd/web/chat/static/js/send-message.js @@ -17,8 +17,6 @@ function reload_popovers() { } function build_location_string(msg) { - console.log("Building location string"); - console.log(msg); dt = new Date(parseInt(msg['lasttime']) * 1000); loc = "Last Location Update: " + dt.toLocaleString(); loc += "
Latitude: " + msg['lat'] + "
Longitude: " + msg['lon']; @@ -29,6 +27,18 @@ function build_location_string(msg) { return loc; } +function build_location_string_small(msg) { + + dt = new Date(parseInt(msg['lasttime']) * 1000); + + loc = "" + msg['distance'] + "km"; + //loc += "Lat " + msg['lat'] + " Lon " + msg['lon']; + loc += "@" + msg['course'] + "°"; + //loc += " Distance " + msg['distance'] + " km"; + loc += " " + dt.toLocaleString(); + return loc; +} + function size_dict(d){c=0; for (i in d) ++c; return c} function raise_error(msg) { @@ -51,8 +61,6 @@ function init_chat() { }); socket.on("sent", function(msg) { - console.log("SENT: "); - console.log(msg); if (cleared === false) { var msgsdiv = $("#msgsTabsDiv"); msgsdiv.html(''); @@ -63,8 +71,6 @@ function init_chat() { }); socket.on("ack", function(msg) { - console.log("ACK"); - console.log(msg); msg["type"] = MSG_TYPE_ACK; ack_msg(msg); }); @@ -82,14 +88,14 @@ function init_chat() { socket.on("callsign_location", function(msg) { console.log("CALLSIGN Location!"); console.log(msg); + now = new Date(); + msg['last_updated'] = now; callsign_location[msg['callsign']] = msg; - popover_id = callsign_location_popover(msg['callsign'], true); - location_string = build_location_string(msg); - console.log(location_string); - $(popover_id).attr('data-bs-content', location_string); - $(popover_id).removeClass('visually-hidden'); - reload_popovers(); + location_id = callsign_location_content(msg['callsign'], true); + location_string = build_location_string_small(msg); + $(location_id).html(location_string); + $(location_id+"Spinner").addClass('d-none'); save_data(); }); @@ -162,6 +168,10 @@ function callsign_location_popover(callsign, id=false) { return tab_string(callsign, id)+"Location"; } +function callsign_location_content(callsign, id=false) { + return tab_string(callsign, id)+"LocationContent"; +} + function bubble_msg_id(msg, id=false) { // The id of the div that contains a specific message name = msg["from_call"] + "_" + msg["msgNo"]; @@ -299,24 +309,10 @@ function create_callsign_tab(callsign, active=false) { active_str = ""; } - location_str = 'No Location Information'; - location_class = 'visually-hidden'; - if (callsign in callsign_location) { - location_str = build_location_string(callsign_location[callsign]); - location_class = ''; - } - item_html = '' @@ -335,7 +331,22 @@ function create_callsign_tab_content(callsign, active=false) { active_str = ''; } + location_str = "Unknown Location" + if (callsign in callsign_location) { + location_str = build_location_string_small(callsign_location[callsign]); + location_class = ''; + } + + location_id = callsign_location_content(callsign); + item_html = '
'; + item_html += '
'; + item_html += '
'; + item_html += '
'; + item_html += ''; + item_html += ' '+location_str+'
'; + item_html += '
'; item_html += '
'; item_html += '
'; callsignTabsContent.append(item_html); @@ -375,10 +386,9 @@ function add_callsign(callsign, msg) { return true; } -function update_callsign_path(callsign, path) { +function update_callsign_path(callsign, msg) { //Get the selected path to save for this callsign path = msg['path'] - console.log("Path is " + path); $('#pkt_path').val(path); callsign_list[callsign] = path; @@ -387,7 +397,6 @@ function update_callsign_path(callsign, path) { function append_message(callsign, msg, msg_html) { new_callsign = false if (!message_list.hasOwnProperty(callsign)) { - //message_list[callsign] = new Array(); message_list[callsign] = {}; } ts_id = message_ts_id(msg); @@ -406,10 +415,11 @@ function append_message(callsign, msg, msg_html) { // Find the right div to place the html new_callsign = add_callsign(callsign, msg); - update_callsign_path(callsign, msg['path']); + update_callsign_path(callsign, msg); append_message_html(callsign, msg_html, new_callsign); - if (new_callsign) { - //Now click the tab + len = Object.keys(callsign_list).length; + if (new_callsign && len == 1) { + //Now click the tab if and only if there is only one tab callsign_tab_id = callsign_tab(callsign); $(callsign_tab_id).click(); callsign_select(callsign); @@ -502,12 +512,11 @@ function from_msg(msg) { if (msg["msgNo"] in from_msg_list[msg["from_call"]]) { // We already have this message - console.log("We already have this message msgNo=" + msg["msgNo"]); + //console.log("We already have this message msgNo=" + msg["msgNo"]); // Do some flashy thing? flash_message(msg); return false } else { - console.log("Adding message " + msg["msgNo"] + " to " + msg["from_call"]); from_msg_list[msg["from_call"]][msg["msgNo"]] = msg } info = time_ack_from_msg(msg); @@ -564,3 +573,42 @@ function callsign_select(callsign) { // Now update the path $('#pkt_path').val(callsign_list[callsign]); } + +function call_callsign_location(callsign) { + msg = {'callsign': callsign}; + socket.emit("get_callsign_location", msg); + location_id = callsign_location_content(callsign, true)+"Spinner"; + $(location_id).removeClass('d-none'); +} + +function checkcallsign_locations() { + console.log("Checking callsign locations"); + for (callsign in callsign_list) { + console.log("Checking location for " + callsign); + console.log(callsign_location[callsign]); + if (!callsign_location.hasOwnProperty(callsign)) { + console.log("Requesting location for " + callsign); + msg = {'callsign': callsign}; + socket.emit("get_callsign_location", msg); + } else { + console.log("Already have location for " + callsign); + date = new Date(parseInt(callsign_location[callsign]['lasttime']) * 1000); + then = callsign_location[callsign]['last_updated']; + if (!callsign_location[callsign].hasOwnProperty('last_updated')) { + console.log("missing last_updated. fetching new location") + msg = {'callsign': callsign}; + socket.emit("get_callsign_location", msg); + } else { + timeout = 1000*60*1; + now = new Date(); + if (now - then > timeout) { + console.log("Location is old, requesting location for " + callsign); + call_callsign_location(callsign); + } + } + + } + + } + +} diff --git a/aprsd/web/chat/templates/index.html b/aprsd/web/chat/templates/index.html index b7d911a..637879d 100644 --- a/aprsd/web/chat/templates/index.html +++ b/aprsd/web/chat/templates/index.html @@ -99,7 +99,7 @@