From 2eca5f644a87e4d4ec00cc2bda93c9d845114cca Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Wed, 10 Sep 2025 18:58:33 -0700 Subject: [PATCH] add aircraft lookup to highFlying info @Cisien for the idea --- config.template | 2 ++ modules/locationdata.py | 58 ++++++++++++++++++++++++++++++++++++++++- modules/settings.py | 1 + modules/system.py | 12 +++++++-- 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/config.template b/config.template index 54a6a98..22df78a 100644 --- a/config.template +++ b/config.template @@ -119,6 +119,8 @@ sentryIgnoreList = highFlyingAlert = True # Altitude in meters to trigger the alert highFlyingAlertAltitude = 2000 +# check with OpenSkyNetwork if highfly detected for aircraft +highfly_openskynetwork = True # Channel to send Alert when the high flying node is detected highFlyingAlertInterface = 1 highFlyingAlertChannel = 2 diff --git a/modules/locationdata.py b/modules/locationdata.py index b3cffef..fdb8434 100644 --- a/modules/locationdata.py +++ b/modules/locationdata.py @@ -957,4 +957,60 @@ def distance(lat=0,lon=0,nodeID=0, reset=False): if not dupe: howfarDB[nodeID].append({'lat': lat, 'lon': lon, 'time': datetime.now()}) - return msg \ No newline at end of file + return msg + +def get_openskynetwork(lat=0, lon=0): + # get the latest aircraft data from OpenSky Network in the area + if lat == 0 and lon == 0: + return NO_ALERTS + # setup a bounding box of 50km around the lat/lon + box_size = 0.45 # approx 50km + # return limits for aircraft search + search_limit = 5 + lamin = lat - box_size + lamax = lat + box_size + lomin = lon - box_size + lomax = lon + box_size + + # fetch the aircraft data from OpenSky Network + opensky_url = f"https://opensky-network.org/api/states/all?lamin={lamin}&lomin={lomin}&lamax={lamax}&lomax={lomax}" + try: + aircraft_data = requests.get(opensky_url, timeout=urlTimeoutSeconds) + if not aircraft_data.ok: + logger.warning("Location:Error fetching aircraft data from OpenSky Network") + return ERROR_FETCHING_DATA + except (requests.exceptions.RequestException): + logger.warning("Location:Error fetching aircraft data from OpenSky Network") + return ERROR_FETCHING_DATA + aircraft_json = aircraft_data.json() + if 'states' not in aircraft_json or not aircraft_json['states']: + return NO_ALERTS + aircraft_list = aircraft_json['states'] + aircraft_report = "" + for aircraft in aircraft_list: + if len(aircraft_report.split("\n")) >= search_limit: + break + # extract values from JSON + try: + callsign = aircraft[1].strip() if aircraft[1] else "N/A" + origin_country = aircraft[2] + velocity = aircraft[9] + true_track = aircraft[10] + vertical_rate = aircraft[11] + sensors = aircraft[12] + geo_altitude = aircraft[13] + squawk = aircraft[14] if len(aircraft) > 14 else "N/A" + except Exception as e: + logger.debug("Location:Error extracting aircraft data from OpenSky Network") + continue + + # format the aircraft data + aircraft_report += f"✈️{callsign} Alt:{int(geo_altitude) if geo_altitude else 'N/A'}m Vel:{int(velocity) if velocity else 'N/A'}m/s Heading:{int(true_track) if true_track else 'N/A'}°\n" + + # remove last newline + if aircraft_report.endswith("\n"): + aircraft_report = aircraft_report[:-1] + aircraft_report = abbreviate_noaa(aircraft_report) + return aircraft_report if aircraft_report else NO_ALERTS + + diff --git a/modules/settings.py b/modules/settings.py index 19df687..0d19680 100644 --- a/modules/settings.py +++ b/modules/settings.py @@ -244,6 +244,7 @@ try: highfly_channel = config['sentry'].getint('highFlyingAlertChannel', 2) # default 2 highfly_interface = config['sentry'].getint('highFlyingAlertInterface', 1) # default 1 highfly_ignoreList = config['sentry'].get('highFlyingIgnoreList', '').split(',') # default empty + highfly_check_openskynetwork = config['sentry'].getboolean('highfly_openskynetwork', True) # default True check with OpenSkyNetwork if highfly detected # location location_enabled = config['location'].getboolean('enabled', True) diff --git a/modules/system.py b/modules/system.py index a1780f2..644bd9d 100644 --- a/modules/system.py +++ b/modules/system.py @@ -1004,11 +1004,19 @@ def consumeMetadata(packet, rxNode=0): for key in keys: positionMetadata[nodeID][key] = position_data.get(key, 0) - # if altitude is over 2000 send a log and message for high-flying nodes and not in highfly_ignoreList + # if altitude is over highfly_altitude send a log and message for high-flying nodes and not in highfly_ignoreList if position_data.get('altitude', 0) > highfly_altitude and highfly_enabled and str(nodeID) not in highfly_ignoreList: logger.info(f"System: High Altitude {position_data['altitude']}m on Device: {rxNode} NodeID: {nodeID}") altFeet = round(position_data['altitude'] * 3.28084, 2) - send_message(f"High Altitude {altFeet}ft ({position_data['altitude']}m) on Device:{rxNode} Node:{get_name_from_number(nodeID,'short',rxNode)}", highfly_channel, 0, highfly_interface) + msg = f"🚀 High Altitude Detected! NodeID:{nodeID} Alt:{position_data['altitude']}m/{altFeet}ft" + + if highfly_check_openskynetwork: + # check get_openskynetwork to see if the node is an aircraft + flight_info = get_openskynetwork(position_data.get('latitude', 0), position_data.get('longitude', 0), position_data.get('altitude', 0)) + if flight_info and NO_ALERTS not in flight_info and ERROR_FETCHING_DATA not in flight_info: + msg += f"\n✈️Detected near: {flight_info}" + + send_message(msg, highfly_channel, 0, highfly_interface) time.sleep(responseDelay) # Keep the positionMetadata dictionary at a maximum size of 20