Godstrument/workers/world_sun.py
monsterrobotparty 8deb65b4fe Godstrument: a multi-modal sensor-fusion instrument
Everything — your hand, the room, a satellite, the markets, the sky — becomes an
OSC control signal fused through a modulation matrix. Includes:
- hub + normalize (One-Euro) + matrix (curves/gates/quantize) + transform (tweaks/groups)
- 20+ workers: sim sensors, 8 keyless world feeds, ephemeris/almanac/clock (computed),
  time-warp replay (quakes/weather/db), and the dealgod market warehouse feed
- planetary orbital LFOs, SQLite recorder, city targeting
- live browser console: mute, group macros, drag-to-patch, inspector, Web MIDI

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 02:13:05 +10:00

68 lines
2.3 KiB
Python

#!/usr/bin/env python3
"""The actual solar wind hitting Earth right now, opening the master filter — playing the sun.
NOAA SWPC reports live proton speed (km/s) of the solar wind stream; a faster gust is a
brighter, more open sound. The star's mood becomes the master filter cutoff."""
import argparse
import json
import time
import urllib.request
from pythonosc.udp_client import SimpleUDPClient
NAME = "world_sun"
URL = "https://services.swpc.noaa.gov/products/summary/solar-wind-speed.json"
POLL_INTERVAL = 60.0 # seconds between API polls (be kind to NOAA)
REEMIT_INTERVAL = 5.0 # re-fire last known value this often
UA = "Godstrument/1.0 (world_sun worker; +https://github.com/godstrument)"
def fetch_speed():
"""Fetch current solar-wind proton speed (km/s). Returns float or None on failure."""
req = urllib.request.Request(URL, headers={"User-Agent": UA})
with urllib.request.urlopen(req, timeout=15) as resp:
data = json.load(resp)
# Response is a JSON list; take [0]["proton_speed"].
return float(data[0]["proton_speed"])
def main():
ap = argparse.ArgumentParser(description="Emit live solar-wind speed as OSC.")
ap.add_argument("--host", default="127.0.0.1")
ap.add_argument("--port", type=int, default=9000)
args = ap.parse_args()
client = SimpleUDPClient(args.host, args.port)
print(f"[{NAME}] emitting /gs/sun/speed every {int(REEMIT_INTERVAL)}s")
last_value = None
last_poll = 0.0
backoff = 5.0
while True:
now = time.monotonic()
# Poll the API at most once per POLL_INTERVAL.
if now - last_poll >= POLL_INTERVAL or last_value is None:
try:
last_value = fetch_speed()
last_poll = now
backoff = 5.0 # reset backoff on success
except Exception as e:
print(f"[{NAME}] fetch failed: {e}; retrying in {backoff:.0f}s")
time.sleep(backoff)
backoff = min(backoff * 2, 120.0)
continue
# Re-emit last known value.
try:
client.send_message("/gs/sun/speed", float(last_value))
except Exception as e:
print(f"[{NAME}] send failed: {e}")
time.sleep(REEMIT_INTERVAL)
if __name__ == "__main__":
main()