From 678fde7b2cdbfe93c7b7062390d481a94d76229c Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 16:45:29 -0800 Subject: [PATCH 01/12] logs --- mesh_bot.py | 8 ++++---- modules/system.py | 1 + pong_bot.py | 8 ++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/mesh_bot.py b/mesh_bot.py index 18c1a06..b67ae2a 100755 --- a/mesh_bot.py +++ b/mesh_bot.py @@ -1921,10 +1921,10 @@ def onReceive(packet, interface): logger.debug(f"System: channel resolution error: {e}") #debug channel info - # if "unknown" in str(channel_name): - # logger.debug(f"System: Received Packet on Channel:{channel_number} on Interface:{rxNode}") - # else: - # logger.debug(f"System: Received Packet on Channel:{channel_number} Name:{channel_name} on Interface:{rxNode}") + if "unknown" in str(channel_name): + logger.debug(f"System: Received Packet on Channel:{channel_number} on Interface:{rxNode}") + else: + logger.debug(f"System: Received Packet on Channel:{channel_number} Name:{channel_name} on Interface:{rxNode}") # check if the packet has a simulator flag simulator_flag = packet.get('decoded', {}).get('simulator', False) diff --git a/modules/system.py b/modules/system.py index 965551b..41aa379 100644 --- a/modules/system.py +++ b/modules/system.py @@ -441,6 +441,7 @@ def refresh_channel_cache(): return build_channel_cache(force_refresh=True) channel_list = build_channel_cache() +print(f"System: Channel Cache Built: {channel_list}") #### FUN-ctions #### def resolve_channel_name(channel_number, rxNode=1, interface_obj=None): diff --git a/pong_bot.py b/pong_bot.py index d77372d..efbe942 100755 --- a/pong_bot.py +++ b/pong_bot.py @@ -291,10 +291,10 @@ def onReceive(packet, interface): logger.debug(f"System: channel resolution error: {e}") #debug channel info - # if "unknown" in str(channel_name): - # logger.debug(f"System: Received Packet on Channel:{channel_number} on Interface:{rxNode}") - # else: - # logger.debug(f"System: Received Packet on Channel:{channel_number} Name:{channel_name} on Interface:{rxNode}") + if "unknown" in str(channel_name): + logger.debug(f"System: Received Packet on Channel:{channel_number} on Interface:{rxNode}") + else: + logger.debug(f"System: Received Packet on Channel:{channel_number} Name:{channel_name} on Interface:{rxNode}") # check if the packet has a simulator flag simulator_flag = packet.get('decoded', {}).get('simulator', False) From 2863a64ec88b47934463c92fcfcbb84b2715e502 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 16:57:30 -0800 Subject: [PATCH 02/12] Update mesh_bot.py --- mesh_bot.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/mesh_bot.py b/mesh_bot.py index b67ae2a..2bc41b4 100755 --- a/mesh_bot.py +++ b/mesh_bot.py @@ -1917,15 +1917,31 @@ def onReceive(packet, interface): channel_name, _ = res except Exception: channel_name = "unknown" + else: + # Search all interfaces for this channel + cache = build_channel_cache() + found_on_other = None + for device in cache: + for chan_name, info in device.get("channels", {}).items(): + if str(info.get('number')) == str(channel_number) or str(info.get('hash')) == str(channel_number): + found_on_other = device.get("interface_id") + found_chan_name = chan_name + break + if found_on_other: + break + if found_on_other and found_on_other != rxNode: + logger.debug( + f"System: Received Packet on Channel:{channel_number} ({found_chan_name}) on Interface:{rxNode}, but this channel is configured on Interface:{found_on_other}" + ) except Exception as e: logger.debug(f"System: channel resolution error: {e}") - + #debug channel info if "unknown" in str(channel_name): logger.debug(f"System: Received Packet on Channel:{channel_number} on Interface:{rxNode}") else: logger.debug(f"System: Received Packet on Channel:{channel_number} Name:{channel_name} on Interface:{rxNode}") - + # check if the packet has a simulator flag simulator_flag = packet.get('decoded', {}).get('simulator', False) if isinstance(simulator_flag, dict): From a5322867e326ecde43d53df039bd0c47d147c57e Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 16:58:19 -0800 Subject: [PATCH 03/12] Update pong_bot.py --- pong_bot.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pong_bot.py b/pong_bot.py index efbe942..18fcde0 100755 --- a/pong_bot.py +++ b/pong_bot.py @@ -287,6 +287,22 @@ def onReceive(packet, interface): channel_name, _ = res except Exception: channel_name = "unknown" + else: + # Search all interfaces for this channel + cache = build_channel_cache() + found_on_other = None + for device in cache: + for chan_name, info in device.get("channels", {}).items(): + if str(info.get('number')) == str(channel_number) or str(info.get('hash')) == str(channel_number): + found_on_other = device.get("interface_id") + found_chan_name = chan_name + break + if found_on_other: + break + if found_on_other and found_on_other != rxNode: + logger.debug( + f"System: Received Packet on Channel:{channel_number} ({found_chan_name}) on Interface:{rxNode}, but this channel is configured on Interface:{found_on_other}" + ) except Exception as e: logger.debug(f"System: channel resolution error: {e}") From 21e614ab8e8546e682aaeffe3730e2dbdaa6162b Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 19:39:04 -0800 Subject: [PATCH 04/12] enhance solar with NOAA radio weather --- mesh_bot.py | 2 +- modules/space.py | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) 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() From 93031010cb3866eac85d1144b02c6bd3d04f57d8 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 21:05:58 -0800 Subject: [PATCH 05/12] enhance output data for solar report --- modules/space.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/space.py b/modules/space.py index 8b6ac12..e1986b5 100644 --- a/modules/space.py +++ b/modules/space.py @@ -117,10 +117,15 @@ def get_noaa_scales_summary(): 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')})") + + # Only show storm if it's happening + if s.get("Text") and s.get("Text") != "none": + parts.append(f"Currently: {s.get('Text')} (S:{s.get('Scale', 'N/A')})") + + # Only show blackout if it's not "none" or scale is not 0 + if r.get("Text") and r.get("Text") != "none" and r.get("Scale") not in [None, "0", 0]: + parts.append(f"Blackout: {r.get('Text')} (R:{r.get('Scale', 'N/A')})") + return " | ".join(parts) output = [] From e1def5422abf714785c50894e2627720dac3e3ef Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 21:13:41 -0800 Subject: [PATCH 06/12] cleanup --- modules/space.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/space.py b/modules/space.py index e1986b5..870b804 100644 --- a/modules/space.py +++ b/modules/space.py @@ -120,18 +120,18 @@ def get_noaa_scales_summary(): # Only show storm if it's happening if s.get("Text") and s.get("Text") != "none": - parts.append(f"Currently: {s.get('Text')} (S:{s.get('Scale', 'N/A')})") + parts.append(f"Currently:{s.get('Text')} (S:{s.get('Scale', 'N/A')})") # Only show blackout if it's not "none" or scale is not 0 if r.get("Text") and r.get("Text") != "none" and r.get("Scale") not in [None, "0", 0]: - parts.append(f"Blackout: {r.get('Text')} (R:{r.get('Scale', 'N/A')})") + parts.append(f"RF Blackout:{r.get('Text')} (R:{r.get('Scale', 'N/A')})") - return " | ".join(parts) + return "\n".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)) + output.append(format_entry("24hrMax:", max_g_today)) + output.append(format_entry("Predicted:", predicted_g)) return "\n".join(output) else: logger.error("Error fetching NOAA scales") From 38ff05fd4082d0163850c369bf754efc7abe1ee6 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 21:22:28 -0800 Subject: [PATCH 07/12] logs --- modules/space.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/space.py b/modules/space.py index 870b804..61bf4b0 100644 --- a/modules/space.py +++ b/modules/space.py @@ -134,11 +134,10 @@ def get_noaa_scales_summary(): output.append(format_entry("Predicted:", predicted_g)) return "\n".join(output) else: - logger.error("Error fetching NOAA scales") - return None + return NO_ALERTS except Exception as e: - logger.error(f"Error fetching NOAA scales: {e}") - return None + logger.warning(f"Error fetching services.swpc.noaa.gov: {e}") + return ERROR_FETCHING_DATA def get_sun(lat=0, lon=0): # get sunrise and sunset times using callers location or default From 5baee422c23dd39b9543d774057eb2b8e53aef27 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 22:18:22 -0800 Subject: [PATCH 08/12] Update system.py --- modules/system.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/system.py b/modules/system.py index 41aa379..03946ea 100644 --- a/modules/system.py +++ b/modules/system.py @@ -4,7 +4,6 @@ import meshtastic.serial_interface #pip install meshtastic or use launch.sh for venv import meshtastic.tcp_interface import meshtastic.ble_interface -from meshtastic.util import generate_channel_hash import time import asyncio import random From 0bfe908391029256fdc33f3bf7bf42c6e59a04c5 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 22:21:14 -0800 Subject: [PATCH 09/12] Update system.py --- modules/system.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/system.py b/modules/system.py index 03946ea..b3dafda 100644 --- a/modules/system.py +++ b/modules/system.py @@ -406,7 +406,7 @@ def build_channel_cache(force_refresh: bool = False): ch_hash_table_raw = node.get_channels_with_hash() #print(f"System: Device{i} Channel Hash Table: {ch_hash_table_raw}") except Exception: - logger.warning(f"System: update meshtastic API 2.7.4 +") + logger.warning(f"System: API version error update API `pip install --upgrade meshtastic`") ch_hash_table_raw = [] channel_dict = {} From 13b9b75f86bb810106021f82422956ebd7654da3 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 22:24:44 -0800 Subject: [PATCH 10/12] Update system.py --- modules/system.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/system.py b/modules/system.py index b3dafda..77b4141 100644 --- a/modules/system.py +++ b/modules/system.py @@ -406,7 +406,7 @@ def build_channel_cache(force_refresh: bool = False): ch_hash_table_raw = node.get_channels_with_hash() #print(f"System: Device{i} Channel Hash Table: {ch_hash_table_raw}") except Exception: - logger.warning(f"System: API version error update API `pip install --upgrade meshtastic`") + logger.warning(f"System: API version error update API `pip3 install --upgrade "meshtastic[cli]"`") ch_hash_table_raw = [] channel_dict = {} From e29573ebc02794c97c1326f0819a890e2a9b0237 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 22:24:52 -0800 Subject: [PATCH 11/12] Update system.py --- modules/system.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/system.py b/modules/system.py index 77b4141..3d7eaee 100644 --- a/modules/system.py +++ b/modules/system.py @@ -406,7 +406,7 @@ def build_channel_cache(force_refresh: bool = False): ch_hash_table_raw = node.get_channels_with_hash() #print(f"System: Device{i} Channel Hash Table: {ch_hash_table_raw}") except Exception: - logger.warning(f"System: API version error update API `pip3 install --upgrade "meshtastic[cli]"`") + logger.warning(f"System: API version error update API `pip3 install --upgrade meshtastic[cli]`") ch_hash_table_raw = [] channel_dict = {} From 69df48957e81a4fd5320312660ba6d28a22effd2 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 23:54:17 -0800 Subject: [PATCH 12/12] clear Logs --- mesh_bot.py | 8 ++++---- modules/system.py | 2 +- pong_bot.py | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mesh_bot.py b/mesh_bot.py index 24a83cd..97ed95a 100755 --- a/mesh_bot.py +++ b/mesh_bot.py @@ -1937,10 +1937,10 @@ def onReceive(packet, interface): logger.debug(f"System: channel resolution error: {e}") #debug channel info - if "unknown" in str(channel_name): - logger.debug(f"System: Received Packet on Channel:{channel_number} on Interface:{rxNode}") - else: - logger.debug(f"System: Received Packet on Channel:{channel_number} Name:{channel_name} on Interface:{rxNode}") + # if "unknown" in str(channel_name): + # logger.debug(f"System: Received Packet on Channel:{channel_number} on Interface:{rxNode}") + # else: + # logger.debug(f"System: Received Packet on Channel:{channel_number} Name:{channel_name} on Interface:{rxNode}") # check if the packet has a simulator flag simulator_flag = packet.get('decoded', {}).get('simulator', False) diff --git a/modules/system.py b/modules/system.py index 3d7eaee..c29a603 100644 --- a/modules/system.py +++ b/modules/system.py @@ -440,7 +440,7 @@ def refresh_channel_cache(): return build_channel_cache(force_refresh=True) channel_list = build_channel_cache() -print(f"System: Channel Cache Built: {channel_list}") +#print(f"System: Channel Cache Built: {channel_list}") #### FUN-ctions #### def resolve_channel_name(channel_number, rxNode=1, interface_obj=None): diff --git a/pong_bot.py b/pong_bot.py index 18fcde0..8fcc404 100755 --- a/pong_bot.py +++ b/pong_bot.py @@ -307,10 +307,10 @@ def onReceive(packet, interface): logger.debug(f"System: channel resolution error: {e}") #debug channel info - if "unknown" in str(channel_name): - logger.debug(f"System: Received Packet on Channel:{channel_number} on Interface:{rxNode}") - else: - logger.debug(f"System: Received Packet on Channel:{channel_number} Name:{channel_name} on Interface:{rxNode}") + # if "unknown" in str(channel_name): + # logger.debug(f"System: Received Packet on Channel:{channel_number} on Interface:{rxNode}") + # else: + # logger.debug(f"System: Received Packet on Channel:{channel_number} Name:{channel_name} on Interface:{rxNode}") # check if the packet has a simulator flag simulator_flag = packet.get('decoded', {}).get('simulator', False)