From 2aa7ffb0e89b4b1f6425052339c62144ece8bec6 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 13:35:16 -0800 Subject: [PATCH 1/8] packet debugging --- mesh_bot.py | 8 ++++---- pong_bot.py | 8 ++++---- 2 files changed, 8 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/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 35c6232b0c87fb542bf044384d1e53c917235a8d Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 13:40:48 -0800 Subject: [PATCH 2/8] enhance --- install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/install.sh b/install.sh index c4f4f78..d8b683d 100755 --- a/install.sh +++ b/install.sh @@ -118,6 +118,7 @@ if [[ "$program_path" != "/opt/meshing-around" ]]; then if [[ $(echo "$move" | grep -i "^y") ]]; then sudo mv "$program_path" /opt/meshing-around cd /opt/meshing-around + sudo git config --global --add safe.directory /opt/meshing-around printf "\nProject moved to /opt/meshing-around.\n" printf "Please re-run the installer from the new location.\n" exit 0 From 79348be644f9f6a63ec1f4f859d56a4b00745449 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 14:12:55 -0800 Subject: [PATCH 3/8] debug --- modules/system.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/system.py b/modules/system.py index 7e7d7ed..cf3350c 100644 --- a/modules/system.py +++ b/modules/system.py @@ -425,6 +425,7 @@ def build_channel_cache(force_refresh: bool = False): # try to use the node-provided channel/hash table if available try: ch_hash_table = node.get_channels_with_hash() + print(f"System: Device{i} Channel Hash Table: {ch_hash_table}") except Exception: logger.warning(f"System: update meshtastic API 2.7.4 +") ch_hash_table = {} From 179113e83a25650ac60681db9f7a00265cde4e76 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 14:46:51 -0800 Subject: [PATCH 4/8] Update system.py --- modules/system.py | 75 ++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 47 deletions(-) diff --git a/modules/system.py b/modules/system.py index cf3350c..a8fc9f5 100644 --- a/modules/system.py +++ b/modules/system.py @@ -4,6 +4,7 @@ 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 @@ -331,24 +332,6 @@ if ble_count > 1: logger.critical(f"System: Multiple BLE interfaces detected. Only one BLE interface is allowed. Exiting") exit() -def xor_hash(data: bytes) -> int: - """Compute an XOR hash from bytes.""" - result = 0 - for char in data: - result ^= char - return result - -def generate_hash(name: str, key: str) -> int: - """generate the channel number by hashing the channel name and psk""" - if key == "AQ==": - key = "1PG7OiApB1nwvP+rz05pAQ==" - replaced_key = key.replace("-", "+").replace("_", "/") - key_bytes = base64.b64decode(replaced_key.encode("utf-8")) - h_name = xor_hash(bytes(name, "utf-8")) - h_key = xor_hash(key_bytes) - result: int = h_name ^ h_key - return result - # Initialize interfaces logger.debug(f"System: Initializing Interfaces") interface1 = interface2 = interface3 = interface4 = interface5 = interface6 = interface7 = interface8 = interface9 = None @@ -419,17 +402,31 @@ def build_channel_cache(force_refresh: bool = False): if not globals().get(f'interface{i}') or not globals().get(f'interface{i}_enabled'): continue try: - # lightweight call to fetch local node and its channels once node = globals()[f'interface{i}'].getNode('^local') channels = getattr(node, "channels", []) or [] - # try to use the node-provided channel/hash table if available + # Try to use the node-provided channel/hash table if available try: - ch_hash_table = node.get_channels_with_hash() - print(f"System: Device{i} Channel Hash Table: {ch_hash_table}") + ch_hash_table_raw = node.get_channels_with_hash() + print(f"System: Device{i} Channel Hash Table: {ch_hash_table_raw}") + # Convert list of dicts to lookup dict by name and index + ch_hash_table = {} + if isinstance(ch_hash_table_raw, list): + for entry in ch_hash_table_raw: + name = entry.get("name", "").strip() + idx = entry.get("index") + hash_val = entry.get("hash") + if name: + ch_hash_table[name] = hash_val + if idx is not None: + ch_hash_table[idx] = hash_val + elif isinstance(ch_hash_table_raw, dict): + ch_hash_table = ch_hash_table_raw + else: + ch_hash_table = {} except Exception: logger.warning(f"System: update meshtastic API 2.7.4 +") ch_hash_table = {} - + channel_dict = {} for channel in channels: if getattr(channel, "role", False): @@ -439,31 +436,15 @@ def build_channel_cache(force_refresh: bool = False): continue ch_hash = None - # ch_hash_table may map by name or by index; try both defensively - if isinstance(ch_hash_table, dict): - # by name - if channel_name in ch_hash_table: - entry = ch_hash_table[channel_name] - if isinstance(entry, dict): - ch_hash = entry.get("hash") or entry.get("pskHash") or entry.get("hashValue") - elif isinstance(entry, (list, tuple)) and len(entry) >= 2: - ch_hash = entry[1] - else: - ch_hash = entry - # by index - elif channel_number in ch_hash_table: - entry = ch_hash_table[channel_number] - if isinstance(entry, dict): - ch_hash = entry.get("hash") or entry.get("pskHash") or entry.get("hashValue") - elif isinstance(entry, (list, tuple)) and len(entry) >= 2: - ch_hash = entry[1] - else: - ch_hash = entry - - # fallback to generate_hash with default PSK if no table/hash available + # Lookup hash by name or index + if channel_name in ch_hash_table: + ch_hash = ch_hash_table[channel_name] + elif channel_number in ch_hash_table: + ch_hash = ch_hash_table[channel_number] + # Fallback to generate_channel_hash if not found if ch_hash is None: try: - ch_hash = generate_hash(channel_name, "AQ==") + ch_hash = generate_channel_hash(channel_name, "AQ==") except Exception: ch_hash = 0 @@ -474,7 +455,6 @@ def build_channel_cache(force_refresh: bool = False): except Exception as e: logger.debug(f"System: Error fetching channel list from Device{i}: {e}") - # hashes are attached above using node.get_channels_with_hash() when available _channel_cache = cache return _channel_cache @@ -483,6 +463,7 @@ def refresh_channel_cache(): return build_channel_cache(force_refresh=True) channel_list = build_channel_cache() +print(f"System: Initial Channel List: {channel_list}") #### FUN-ctions #### def resolve_channel_name(channel_number, rxNode=1, interface_obj=None): From fe2110ca2bfc2f88e61c6bc08db36d14f93f9ceb Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 16:30:56 -0800 Subject: [PATCH 5/8] Update system.py --- modules/system.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/system.py b/modules/system.py index a8fc9f5..dab293f 100644 --- a/modules/system.py +++ b/modules/system.py @@ -429,12 +429,11 @@ def build_channel_cache(force_refresh: bool = False): channel_dict = {} for channel in channels: - if getattr(channel, "role", False): + if getattr(channel, "role", "") in ("PRIMARY", "SECONDARY"): channel_name = getattr(channel.settings, "name", "").strip() channel_number = getattr(channel, "index", 0) if not channel_name: continue - ch_hash = None # Lookup hash by name or index if channel_name in ch_hash_table: @@ -447,7 +446,7 @@ def build_channel_cache(force_refresh: bool = False): ch_hash = generate_channel_hash(channel_name, "AQ==") except Exception: ch_hash = 0 - + channel_dict[channel_name] = {"number": channel_number, "hash": ch_hash} if channel_dict: cache.append({"interface_id": i, "channels": channel_dict}) From fc7ca37184c022034f65877c0be3d1f618cc2309 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 16:35:16 -0800 Subject: [PATCH 6/8] Update system.py --- modules/system.py | 54 ++++++++++++++--------------------------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/modules/system.py b/modules/system.py index dab293f..01dd165 100644 --- a/modules/system.py +++ b/modules/system.py @@ -391,7 +391,6 @@ _channel_cache = None def build_channel_cache(force_refresh: bool = False): """ Build and cache channel_list from interfaces once (or when forced). - Returns cached list of dicts: [{"interface_id": i, "channels": {name: {number:, hash:}}}, ...] """ global _channel_cache if _channel_cache is not None and not force_refresh: @@ -403,51 +402,30 @@ def build_channel_cache(force_refresh: bool = False): continue try: node = globals()[f'interface{i}'].getNode('^local') - channels = getattr(node, "channels", []) or [] # Try to use the node-provided channel/hash table if available try: ch_hash_table_raw = node.get_channels_with_hash() print(f"System: Device{i} Channel Hash Table: {ch_hash_table_raw}") - # Convert list of dicts to lookup dict by name and index - ch_hash_table = {} - if isinstance(ch_hash_table_raw, list): - for entry in ch_hash_table_raw: - name = entry.get("name", "").strip() - idx = entry.get("index") - hash_val = entry.get("hash") - if name: - ch_hash_table[name] = hash_val - if idx is not None: - ch_hash_table[idx] = hash_val - elif isinstance(ch_hash_table_raw, dict): - ch_hash_table = ch_hash_table_raw - else: - ch_hash_table = {} except Exception: logger.warning(f"System: update meshtastic API 2.7.4 +") - ch_hash_table = {} + ch_hash_table_raw = [] channel_dict = {} - for channel in channels: - if getattr(channel, "role", "") in ("PRIMARY", "SECONDARY"): - channel_name = getattr(channel.settings, "name", "").strip() - channel_number = getattr(channel, "index", 0) - if not channel_name: - continue - ch_hash = None - # Lookup hash by name or index - if channel_name in ch_hash_table: - ch_hash = ch_hash_table[channel_name] - elif channel_number in ch_hash_table: - ch_hash = ch_hash_table[channel_number] - # Fallback to generate_channel_hash if not found - if ch_hash is None: - try: - ch_hash = generate_channel_hash(channel_name, "AQ==") - except Exception: - ch_hash = 0 - - channel_dict[channel_name] = {"number": channel_number, "hash": ch_hash} + # Use the hash table as the source of truth for channels + if isinstance(ch_hash_table_raw, list): + for entry in ch_hash_table_raw: + channel_name = entry.get("name", "").strip() + channel_number = entry.get("index") + ch_hash = entry.get("hash") + role = entry.get("role", "") + if channel_name and role in ("PRIMARY", "SECONDARY"): + channel_dict[channel_name] = {"number": channel_number, "hash": ch_hash} + elif isinstance(ch_hash_table_raw, dict): + # If it's a dict, try to iterate over its items + for channel_name, ch_hash in ch_hash_table_raw.items(): + # You may need to adapt this if dict structure is different + channel_dict[channel_name] = {"number": None, "hash": ch_hash} + # Only add if we found any channels if channel_dict: cache.append({"interface_id": i, "channels": channel_dict}) logger.debug(f"System: Fetched Channel List from Device{i} (cached)") From 1778cb6feba5c236521818ca7cc78523fffaf57b Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 16:38:13 -0800 Subject: [PATCH 7/8] Update system.py --- modules/system.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/modules/system.py b/modules/system.py index 01dd165..45684c3 100644 --- a/modules/system.py +++ b/modules/system.py @@ -418,16 +418,17 @@ def build_channel_cache(force_refresh: bool = False): channel_number = entry.get("index") ch_hash = entry.get("hash") role = entry.get("role", "") - if channel_name and role in ("PRIMARY", "SECONDARY"): - channel_dict[channel_name] = {"number": channel_number, "hash": ch_hash} + # Always add PRIMARY/SECONDARY channels, even if name is empty + if role in ("PRIMARY", "SECONDARY"): + channel_dict[channel_name if channel_name else f"Channel{channel_number}"] = { + "number": channel_number, + "hash": ch_hash + } elif isinstance(ch_hash_table_raw, dict): - # If it's a dict, try to iterate over its items for channel_name, ch_hash in ch_hash_table_raw.items(): - # You may need to adapt this if dict structure is different channel_dict[channel_name] = {"number": None, "hash": ch_hash} - # Only add if we found any channels - if channel_dict: - cache.append({"interface_id": i, "channels": channel_dict}) + # Always add the interface, even if no named channels + cache.append({"interface_id": i, "channels": channel_dict}) logger.debug(f"System: Fetched Channel List from Device{i} (cached)") except Exception as e: logger.debug(f"System: Error fetching channel list from Device{i}: {e}") From fd114301f63e1094dac57875200c7b95d5a87b77 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 16:43:52 -0800 Subject: [PATCH 8/8] logs --- mesh_bot.py | 8 ++++---- modules/system.py | 3 +-- pong_bot.py | 8 ++++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/mesh_bot.py b/mesh_bot.py index b67ae2a..18c1a06 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 45684c3..965551b 100644 --- a/modules/system.py +++ b/modules/system.py @@ -405,7 +405,7 @@ def build_channel_cache(force_refresh: bool = False): # Try to use the node-provided channel/hash table if available try: ch_hash_table_raw = node.get_channels_with_hash() - print(f"System: Device{i} Channel Hash Table: {ch_hash_table_raw}") + #print(f"System: Device{i} Channel Hash Table: {ch_hash_table_raw}") except Exception: logger.warning(f"System: update meshtastic API 2.7.4 +") ch_hash_table_raw = [] @@ -441,7 +441,6 @@ def refresh_channel_cache(): return build_channel_cache(force_refresh=True) channel_list = build_channel_cache() -print(f"System: Initial Channel List: {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 efbe942..d77372d 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)