Skip to content

Instantly share code, notes, and snippets.

@ryanbateman
Forked from wiseman/main.py
Last active April 12, 2024 08:14
Show Gist options
  • Save ryanbateman/62f29afb2aedecbe1f10e013c5a5446e to your computer and use it in GitHub Desktop.
Save ryanbateman/62f29afb2aedecbe1f10e013c5a5446e to your computer and use it in GitHub Desktop.
Print the 10 closest spacecraft/satellites.
import requests
import requests_cache
import math
import ephem
import os
import json
import paho.mqtt.client as mqtt
import datetime
observer = ephem.Observer()
observer.lat = 52.4906405
observer.lon = 13.3768005
observer.elevation = 0
def haversine(lat1, lon1, lat2, lon2):
R = 6378 # Earth's radius in km
dlat = math.radians(lat2 - lat1)
dlon = math.radians(lon2 - lon1)
a = math.sin(dlat / 2)**2 + math.cos(math.radians(lat1)) \
* math.cos(math.radians(lat2)) * math.sin(dlon / 2)**2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
distance = R * c
return distance
# Enable cache with a TTL of 60 minutes
requests_cache.install_cache('satellites', expire_after=3600)
url = "https://www.celestrak.com/NORAD/elements/active.txt" # URL for the TLE data source
response = requests.get(url)
tles = response.text.split("\n")[:-1] # Split the response text by newline characters and remove the last empty element
objs_dists = []
for i in range(0, len(tles), 3):
line1 = tles[i]
line2 = tles[i+1]
line3 = tles[i+2]
name = line1.strip()
sat = ephem.readtle(name, line2, line3)
sat.compute()
distance = haversine(observer.lat, observer.lon, math.degrees(sat.sublat), math.degrees(sat.sublong))
objs_dists.append((name, distance, sat.catalog_number, math.degrees(sat.sublat), math.degrees(sat.sublong), line2, line3))
# Print a nicely formatted table of the 10 closest objects, just to see.
for obj_dist in sorted(objs_dists, key=lambda x: x[1])[0:10]:
print(f"{obj_dist[0]:<20} {obj_dist[1]:>10.2f}km {'https://www.n2yo.com/satellite/?s='+str(obj_dist[2]):>45}")
# Sort the objects by distance and select the closest satellite.
sorted_objs_dists = sorted(objs_dists, key=lambda x: x[1])[0]
# Generate a set of coordinates for the satellite's path
sat = ephem.readtle(sorted_objs_dists[0], sorted_objs_dists[5], sorted_objs_dists[6])
end_time = datetime.datetime.utcnow()
start_time = end_time - datetime.timedelta(seconds=30)
# Calculate satellite path and store in a list
positions = []
while start_time < end_time:
observer.date = start_time
sat.compute(observer)
positions.append((sat.sublong, sat.sublat))
start_time += datetime.timedelta(seconds=1)
# Format path line for the Google Maps Static API. For the moment we just send this part and assemble the full URL elsewhere. This should change.
path_line = 'path=color:0xff0000ff|weight:5'
for pos in positions:
path_line += '|{},{}'.format(pos[1] * 180 / ephem.pi, pos[0] * 180 / ephem.pi)
# Create a dictionary for satellite with its name, distance, catalog number, latitude, longitude, and path line.
sorted_objs_dict = []
sorted_objs_dict.append({'satellite_name': sorted_objs_dists[0], 'distance': sorted_objs_dists[1], 'catalog_number': sorted_objs_dists[2], 'latitude': sorted_objs_dists[3], 'longitude': sorted_objs_dists[4], 'path_line': path_line})
# Convert the dictionary to a JSON string.
json_payload = json.dumps(sorted_objs_dict[0])
# Send the JSON payload via MQTT.
client = mqtt.Client()
client.connect(os.environ['MQTT_BROKER_HOST'], 1883)
client.publish('satellite', json_payload, retain=True)
client.disconnect()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment