diff --git a/mesh_bot.py b/mesh_bot.py index 2bc41b4..24a83cd 100755 --- a/mesh_bot.py +++ b/mesh_bot.py @@ -109,7 +109,7 @@ def auto_response(message, snr, rssi, hop, pkiStatus, message_from_id, channel_n "setsms": lambda: handle_sms( message_from_id, message), "sitrep": lambda: handle_lheard(message, message_from_id, deviceID, isDM), "sms:": lambda: handle_sms(message_from_id, message), - "solar": lambda: drap_xray_conditions() + "\n" + solar_conditions(), + "solar": lambda: drap_xray_conditions() + "\n" + solar_conditions() + "\n" + get_noaa_scales_summary(), "sun": lambda: handle_sun(message_from_id, deviceID, channel_number), "survey": lambda: surveyHandler(message, message_from_id, deviceID), "s:": lambda: surveyHandler(message, message_from_id, deviceID), diff --git a/modules/space.py b/modules/space.py index 9be8402..8b6ac12 100644 --- a/modules/space.py +++ b/modules/space.py @@ -68,6 +68,73 @@ def drap_xray_conditions(): xray_flux = ERROR_FETCHING_DATA return xray_flux +def get_noaa_scales_summary(): + """ + Show latest observed, 24-hour max, and predicted geomagnetic, storm, and blackout data. + """ + try: + response = requests.get("https://services.swpc.noaa.gov/products/noaa-scales.json", timeout=urlTimeoutSeconds) + if response.ok: + data = response.json() + today = datetime.utcnow().date() + latest_entry = None + latest_dt = None + max_g_today = None + max_g_scale = -1 + predicted_g = None + predicted_g_scale = -1 + + # Find latest observed and 24-hour max for today + for entry in data.values(): + date_str = entry.get("DateStamp") + time_str = entry.get("TimeStamp") + if date_str and time_str: + try: + dt = datetime.strptime(f"{date_str} {time_str}", "%Y-%m-%d %H:%M:%S") + g = entry.get("G", {}) + g_scale = int(g.get("Scale", -1)) if g.get("Scale") else -1 + # Latest observed for today + if dt.date() == today: + if latest_dt is None or dt > latest_dt: + latest_dt = dt + latest_entry = entry + # 24-hour max for today + if g_scale > max_g_scale: + max_g_scale = g_scale + max_g_today = entry + # Predicted (future) + elif dt.date() > today: + if g_scale > predicted_g_scale: + predicted_g_scale = g_scale + predicted_g = entry + except Exception: + continue + + def format_entry(label, entry): + if not entry: + return f"{label}: No data" + g = entry.get("G", {}) + s = entry.get("S", {}) + r = entry.get("R", {}) + parts = [f"{label} {g.get('Text', 'N/A')} (G:{g.get('Scale', 'N/A')})"] + if s.get("Text") or s.get("Scale"): + parts.append(f"{s.get('Text', 'N/A')} (S:{s.get('Scale', 'N/A')})") + if r.get("Text") or r.get("Scale"): + parts.append(f"{r.get('Text', 'N/A')} (R:{r.get('Scale', 'N/A')})") + return " | ".join(parts) + + output = [] + #output.append(format_entry("Latest Observed", latest_entry)) + output.append(format_entry("24hr Max", max_g_today)) + output.append(format_entry("Predicted", predicted_g)) + return "\n".join(output) + else: + logger.error("Error fetching NOAA scales") + return None + except Exception as e: + logger.error(f"Error fetching NOAA scales: {e}") + return None + def get_sun(lat=0, lon=0): # get sunrise and sunset times using callers location or default obs = ephem.Observer()