diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..29d7f1e1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.idea +*.pyc \ No newline at end of file diff --git a/findmyplane_plugin.py b/findmyplane_plugin.py new file mode 100644 index 00000000..ca0301fc --- /dev/null +++ b/findmyplane_plugin.py @@ -0,0 +1,107 @@ +# +# This plugin can be used in your projects to add functionality related to Find My Plane +# It is a simple wrapper for the Find My Plane API, the full docs of which are available at http://findmyplane.live/api +# +# Example workflow is available in example.py +# + + +import requests + +server_url = "https://findmyplane.live/" +api_url = server_url + "api" + +connected_to_instance = False +ident_public_key = None +ident_private_key = None + +first_datapoint = True + + +def set_keys(ident_public_key_to_set, ident_private_key_to_set): + global ident_public_key + global ident_private_key + global connected_to_instance + global first_datapoint + + ident_public_key = ident_public_key_to_set + ident_private_key = ident_private_key_to_set + first_datapoint = True + connected_to_instance = True + + +def request_new_plane_instance(plane_title=None, atc_id=None, client=None): + + endpoint_url = "/create_new_plane" + url = api_url + endpoint_url + + values = {'title': plane_title, + 'atc_id': atc_id, + 'client': client} + + try: + r = requests.post(url, json=values) + plane_object = r.json() + set_keys(plane_object['ident_public_key'], plane_object['ident_private_key']) + except: + plane_object = {'status': 'error'} + + return {'status': 'success'} + + +def disconnect_from_plane_instance(): + global ident_public_key + global ident_private_key + global connected_to_instance + global first_datapoint + + ident_public_key = None + ident_private_key = None + connected_to_instance = False + first_datapoint = True + + +def set_plane_location(current_latitude, current_longitude, current_compass, current_altitude, current_speed=None, title=None, atc_id=None): + + if connection_status() != "connected": + return "error: not connected" + + global first_datapoint + + endpoint_url = "/update_plane_location" + url = api_url + endpoint_url + + values = {'ident_public_key': ident_public_key, + 'ident_private_key': ident_private_key, + 'current_latitude': current_latitude, + 'current_longitude': current_longitude, + 'current_compass': current_compass, + 'current_altitude': current_altitude, + 'title': title, + 'atc_id': atc_id} + + if current_speed is not None: values['current_speed'] = current_speed + + try: + r = requests.post(url, json=values) + if first_datapoint: + r = requests.post(url, json=values) + first_datapoint = False + except: + return "error: request failed" + + return "success" + + +def connection_status(): + if connected_to_instance: + return "connected" + else: + return "disconnected" + + +def url_to_view(): + if connection_status() == "connected": + return server_url + "view/" + ident_public_key + else: + return "no url set as not connected to instance" diff --git a/glass_server.py b/glass_server.py index 01784b55..48053bb6 100644 --- a/glass_server.py +++ b/glass_server.py @@ -8,6 +8,7 @@ import asyncio from threading import Thread import datetime +import findmyplane_plugin print (socket.gethostbyname(socket.gethostname())) @@ -34,6 +35,19 @@ def flask_thread_func(threadname): def output_ui_variables(): # Initialise dictionaru ui_friendly_dictionary["STATUS"] = "success" + + # Find my plane addition - send if activated + if findmyplane_plugin.connection_status() == "connected": + findmyplane_plugin.set_plane_location( + current_latitude = ui_friendly_dictionary["LATITUDE"], + current_longitude = ui_friendly_dictionary["LONGITUDE"], + current_compass = ui_friendly_dictionary["MAGNETIC_COMPASS"], + current_altitude = ui_friendly_dictionary["INDICATED_ALTITUDE"], + current_speed = ui_friendly_dictionary["AIRSPEED_INDICATED"], + title = ui_friendly_dictionary["TITLE"], + atc_id = ui_friendly_dictionary["ATC_ID"] + ) + return jsonify(ui_friendly_dictionary) @app.route('/') @@ -108,10 +122,46 @@ def trigger_event_endpoint(event_name): status = trigger_event(event_name, value_to_use) return jsonify(status) - - - - app.run(host='0.0.0.0', port=4000, debug=False) + + + # START: Find my plane routes + + @app.route('/findmyplane/status/check', endpoint="check") + @app.route('/findmyplane/status/set/', endpoint="set") + # This route allows the front end to query and set the connection status + def findmyplane_status(status_to_set = "check"): + + if request.endpoint == "check": + return jsonify({'status': findmyplane_plugin.connection_status(), + 'ident_public_key': findmyplane_plugin.ident_public_key, + 'ident_private_key': findmyplane_plugin.ident_private_key, + 'url_to_view': findmyplane_plugin.url_to_view() + }) + + # Allows the front end to set the connection status. Passing "connected" will create a new plane instance. + # Passing "disconnected" will disconnect from the instance, which will prompt the server to delete it in due + # course if it doesn't receive more data. + if status_to_set.lower() == "disconnected": + findmyplane_plugin.disconnect_from_plane_instance() + return jsonify({'status': 'disconnected'}) + + if status_to_set.lower() == "connected": + findmyplane_connection_attempt = findmyplane_plugin.request_new_plane_instance(client="Mobile Companion App") #Let me know if you are happy with this client description + if findmyplane_connection_attempt['status'] == "success": + return jsonify({ + 'status': 'connected', + 'ident_public_key': findmyplane_plugin.ident_public_key, + 'ident_private_key': findmyplane_plugin.ident_private_key, + 'url_to_view': findmyplane_plugin.url_to_view() + }) + else: + return jsonify({'status': 'error'}) + + return jsonify({'status': 'error', 'reason': 'no valid command passed'}) + + # END: Find my plane routes + + app.run(host='0.0.0.0', port=4000, debug=False, use_reloader=False) # SimConnect App def simconnect_thread_func(threadname): @@ -121,7 +171,7 @@ def simconnect_thread_func(threadname): global value_to_use global sm global ae - + while True: try: sm = SimConnect() @@ -282,8 +332,28 @@ async def ui_dictionary(ui_friendly_dictionary, previous_alt, landing_t1, landin #ui_friendly_dictionary["PANEL_ANTI_ICE_SWITCH"] = await aq.get("PANEL_ANTI_ICE_SWITCH") # Sim Rate ui_friendly_dictionary["SIMULATION_RATE"] = await aq.get("SIMULATION_RATE") - - + + # Get aircraft details + plane_title = await aq.get("TITLE") + atc_id = await aq.get("ATC_ID") + + # This is necessary because this data is returned in binary form and needs to be converted to text before it can be jsonified + try: + ui_friendly_dictionary["TITLE"] = plane_title.decode("utf-8") + ui_friendly_dictionary["ATC_ID"] = atc_id.decode("utf-8") + except: + pass + + # The custom variables for findmyplane, all behind nonsimvar_ key to make sure they don't get in the way + if findmyplane_plugin.connected_to_instance == True: + ui_friendly_dictionary['nonsimvar_findmyplane_connection_status'] = 1 + else: + ui_friendly_dictionary['nonsimvar_findmyplane_connection_status'] = 0 + + ui_friendly_dictionary['nonsimvar_findmyplane_ident_public_key'] = findmyplane_plugin.ident_public_key + ui_friendly_dictionary['nonsimvar_findmyplane_url_to_view'] = findmyplane_plugin.url_to_view() + + # Current altitude current_alt = await aq.get("INDICATED_ALTITUDE") if current_alt > -300: @@ -330,7 +400,7 @@ async def ui_dictionary(ui_friendly_dictionary, previous_alt, landing_t1, landin ui_friendly_dictionary["LANDING_T2"] = landing_t2 ui_friendly_dictionary["LANDING_VS3"] = landing_vs3 ui_friendly_dictionary["LANDING_T3"] = landing_t3 - + while True: asyncio.run(ui_dictionary(ui_friendly_dictionary, previous_alt, ui_friendly_dictionary["LANDING_T1"], ui_friendly_dictionary["LANDING_VS1"], ui_friendly_dictionary["LANDING_T2"], ui_friendly_dictionary["LANDING_VS2"], ui_friendly_dictionary["LANDING_T3"], ui_friendly_dictionary["LANDING_VS3"])) #sleep(0.3) diff --git a/static/js/custom/findMyPlane.js b/static/js/custom/findMyPlane.js new file mode 100644 index 00000000..efc9acb0 --- /dev/null +++ b/static/js/custom/findMyPlane.js @@ -0,0 +1,56 @@ +let findmyplaneConnectionStatus; +let findmyplaneIdentPublicKey; +let findmyplaneUrlToView; + +findmyplaneConnectionStatus = 0; +startFindmyplaneTracking(); + + +function findmyplaneUpdateDisplay() { + + console.log (findmyplaneConnectionStatus) + if (findmyplaneConnectionStatus === 1) { + $("#findmyplaneMaster").removeClass("btn-danger").addClass("btn-success").html("Connected to Find My Plane"); + $("#findmyplaneMenuButton").removeClass("btn-danger").addClass("btn-success"); + $("#findmyplaneConnectionStatusLabel").text("Connected to Find My Plane"); + $("#findmyplaneIdentLabel").text(findmyplaneIdentPublicKey).attr('style', 'color: green'); + $("#findmyplaneFollowingUrlButton").show(); + $("#findmyplaneFollowingUrlLabel").html(findmyplaneUrlToView); + } else { + $("#findmyplaneMaster").addClass("btn-danger").removeClass("btn-success").html("Disconnected - click to connect"); + $("#findmyplaneMenuButton").addClass("btn-danger").removeClass("btn-success") + $("#findmyplaneConnectionStatusLabel").text("Disconnected from Find My Plane"); + $("#findmyplaneIdentLabel").text("N/A").attr('style', 'color: red'); + $("#findmyplaneFollowingUrlLabel").html("N/A"); + $("#findmyplaneFollowingUrlButton").hide(); + + } + +} + +function toggleFindmyplaneTracking() { + + console.log("Change triggered") + if (findmyplaneConnectionStatus === 0) { + startFindmyplaneTracking() + } else { + stopFindmyplaneTracking() + } + +} + + +function startFindmyplaneTracking() { + $.getJSON($SCRIPT_ROOT + '/findmyplane/status/set/connected', {}, function(data) {}); +} + + +function stopFindmyplaneTracking() { + $.getJSON($SCRIPT_ROOT + '/findmyplane/status/set/disconnected', {}, function(data) {}); +} + +function goToTrackingUrl() { + + window.open(findmyplaneUrlToView,"blank") + +} \ No newline at end of file diff --git a/static/js/custom/getSimData.js b/static/js/custom/getSimData.js index 17623379..af7feb5e 100644 --- a/static/js/custom/getSimData.js +++ b/static/js/custom/getSimData.js @@ -683,6 +683,11 @@ function getSimulatorData() { landing_vs3 = data.LANDING_VS3; landing_t3 = data.LANDING_T3; sim_rate = data.SIMULATION_RATE; + + //FindMyPlane + findmyplaneConnectionStatus = data.nonsimvar_findmyplane_connection_status; + findmyplaneIdentPublicKey = data.nonsimvar_findmyplane_ident_public_key; + findmyplaneUrlToView = data.nonsimvar_findmyplane_url_to_view; }); return false; } @@ -758,6 +763,10 @@ function displayData() { $("#landing-vs3").text(landing_vs3); $("#landing-t3").text(landing_t3); $("#sim-rate").text(sim_rate); + + //Findmyplane + findmyplaneUpdateDisplay() + } function checkAndUpdateButton(buttonName, variableToCheck, onText="On", offText="Off") { diff --git a/templates/glass.html b/templates/glass.html index 52ae2392..7a83f791 100644 --- a/templates/glass.html +++ b/templates/glass.html @@ -90,7 +90,8 @@ - + +    @@ -111,6 +112,9 @@ {% include 'menu_panel.html' %} + + {% include 'menu_findmyplane.html' %} + {% include 'menu_other.html' %} @@ -246,8 +250,10 @@ + +