Files
L'électron rare 39d8739f4c feat(data-feeds): 5 nouvelles sources data-only
Ajoute 5 feeds open-data sans cle, branches sur le profil
config.data-only.toml :

- openmeteo : meteo locale (temp, vent, humidite, pression, pluie)
  via api.open-meteo.com, poll 10 min, lat/lon configurables
- openaq : qualite de l'air autour d'une position (PM2.5, PM10,
  NO2, O3) via openaq.org v3, poll 15 min, radius configurable
- iss : position ISS temps reel via wheretheiss.at, poll 5 s,
  emet aussi un event /pass quand la station entre dans un
  rayon configurable autour de l'observateur
- volcano : eruptions actives 7-jours via volcano.si.edu (GVP),
  poll 1 h, dedup par eventid, emet /eruption + /active count
- social_buzz : Reddit /r/all hot + HackerNews top, poll 1 min,
  emet score/comments moyens par source + /pulse normalise

Tous les feeds suivent le pattern Context.send(sub, *args).
2026-05-13 14:44:50 +02:00

62 lines
2.0 KiB
Python

"""ISS position via wheretheiss.at (json).
Renvoie position lat/lon + altitude + velocity. Polling 5s par defaut.
Egalement emet l'event 'pass' (1.0) lorsque la station franchit une
zone d'observation autour de l'observateur (configurable lat/lon/radius).
OSC out :
/data/iss/pos lat lon alt_km vel_kmh
/data/iss/pass 1 (transient, quand iss enter dans le radius)
"""
from __future__ import annotations
import asyncio
import logging
import math
import httpx
LOG = logging.getLogger("feed.iss")
URL = "https://api.wheretheiss.at/v1/satellites/25544"
def _great_circle_km(lat1: float, lon1: float,
lat2: float, lon2: float) -> float:
r = 6371.0
p1 = math.radians(lat1)
p2 = math.radians(lat2)
dp = math.radians(lat2 - lat1)
dl = math.radians(lon2 - lon1)
a = (math.sin(dp / 2) ** 2
+ math.cos(p1) * math.cos(p2) * math.sin(dl / 2) ** 2)
return 2 * r * math.asin(math.sqrt(a))
async def run(ctx) -> None:
cfg = ctx.cfg
period = float(cfg.get("poll_seconds", 5.0))
obs_lat = float(cfg.get("lat", 48.8566))
obs_lon = float(cfg.get("lon", 2.3522))
pass_radius = float(cfg.get("pass_radius_km", 1500.0))
inside_prev = False
async with httpx.AsyncClient(timeout=10.0) as cli:
while True:
try:
r = await cli.get(URL)
r.raise_for_status()
j = r.json()
lat = float(j.get("latitude", 0.0))
lon = float(j.get("longitude", 0.0))
alt = float(j.get("altitude", 0.0))
vel = float(j.get("velocity", 0.0))
ctx.send("pos", lat, lon, alt, vel)
dist = _great_circle_km(obs_lat, obs_lon, lat, lon)
inside_now = dist < pass_radius
if inside_now and not inside_prev:
ctx.send("pass", 1.0, dist)
inside_prev = inside_now
except Exception as e: # noqa: BLE001
LOG.warning("iss fetch failed: %s", e)
await asyncio.sleep(period)