⬅ Retour à Challenges · 🏠 Accueil du repo
First Contact — Misc (Very Easy)¶
| Catégorie | Misc |
| Difficulté | Very Easy |
| Récompense | 130 XP |
Scénario¶
A software update knocked the ground station's automated pass prediction system offline just before a scheduled communications window. The operations team still has the satellite's latest TLEs and the station's coordinates, but they need you to manually determine when the satellite will be above the horizon and visible from the ground station. Calculate the visibility windows so contact can be re-established before the next scheduled transmission is missed.
Le service envoie des TLEs et des coordonnées de station sol. Il faut calculer les fenêtres de visibilité du satellite (élévation > 30°) pour les prochaines 24h et répondre en temps réel, pour plusieurs satellites successifs.
Flux de résolution¶
flowchart LR
A["nc host port"] --> B["Réception TLE + coordonnées station"]
B --> C["Calcul orbital avec skyfield\nfind_events(altitude_degrees=30)"]
C --> D["Extraction rise/set pairs"]
D --> E["Envoi timestamps formatés\n2026-10-11T11:43:33Z 2026-10-11T11:45:56Z"]
E --> F{"Correct ?"}
F -->|"Oui"| G["Satellite suivant"]
F -->|"Non"| H["Ajuster t0 = now()"]
G --> B
G -->|"Tous corrects"| I["HTB{s4tell1735_4r3_4_d15h_b357_53rv3d_c0ld!}"]
Solution¶
Analyse du service¶
Le service TCP envoie des paires TLE + coordonnées station sol pour plusieurs satellites consécutifs. Il faut répondre avec les fenêtres de visibilité sous forme de timestamps UTC espacés (rise set rise set ...). Le service timeout rapidement — impossible de calculer manuellement à temps.
Pièges rencontrés¶
- Coller le script Python dans le terminal nc → le nc le prend comme input et répond
Invalid isoformat string t0hardcodé à minuit → les timestamps calculés ne correspondent pas à la fenêtre couranteday + 1pour calculer t1 → débordement de mois/an, timestamps dans le désordrefind_eventspeut retourner un set sans rise précédent si le satellite est déjà au-dessus de l'horizon au démarrage → filtrer les paires incomplètes
Script final (automatisé)¶
import socket
import re
from skyfield.api import EarthSatellite, Topos, load
from datetime import datetime, timezone, timedelta
ts = load.timescale()
def calc_windows(line1, line2, lat, lon):
sat = EarthSatellite(line1, line2, "DIGITWIN HTB", ts)
station = Topos(latitude_degrees=lat, longitude_degrees=lon)
now = datetime.now(timezone.utc)
t0 = ts.from_datetime(now)
t1 = ts.from_datetime(now + timedelta(hours=24))
times, events = sat.find_events(station, t0, t1, altitude_degrees=30)
windows = []
current_rise = None
for ti, event in zip(times, events):
if event == 0:
current_rise = ti.utc_iso()
elif event == 2 and current_rise is not None:
windows.append(f"{current_rise} {ti.utc_iso()}")
current_rise = None
return " ".join(windows)
s = socket.socket()
s.connect(("154.57.164.78", 32341))
s.settimeout(15)
data = b""
while True:
try:
chunk = s.recv(4096)
if not chunk:
break
data += chunk
print(chunk.decode(errors="ignore"), end="")
text = data.decode(errors="ignore")
tle_match = re.search(r"(1 \d{5}U.*)\n(2 \d{5}.*)", text)
loc_match = re.search(r"\(Lat,Long\):\s*([-\d.]+),([-\d.]+)", text)
if tle_match and loc_match and "When will it be visible" in text:
line1 = tle_match.group(1).strip()
line2 = tle_match.group(2).strip()
lat = float(loc_match.group(1))
lon = float(loc_match.group(2))
answer = calc_windows(line1, line2, lat, lon)
print(f"\n>>> Sending: {answer}")
s.sendall((answer + "\n").encode())
data = b""
except socket.timeout:
print("\n[timeout]")
break
s.close()
Points clés¶
skyfield— bibliothèque Python de mécanique orbitale, gère les TLEs nativementfind_events(altitude_degrees=30)— retourne les événements rise (0), culmination (1), set (2) pour un seuil d'élévation donnét0 = ts.from_datetime(now)— fenêtre glissante depuis l'instant présent, pas depuis minuit- Paires rise/set reconstruites manuellement pour éviter les sets orphelins en début de fenêtre
- Connexion TCP automatisée avec
socketpour éviter le timeout du service