From a979e24b4067d093fe0dccbcf830d7dccebdc5ab Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Tue, 11 Nov 2025 16:42:02 -0800 Subject: [PATCH 1/3] Enhance get_channels_with_hash() To set the index 0 name to the preset name from localConfig.lora.modem_prese and compute hash so the output will not have bad index0 name or hash, also removes all disabled for clarity. this outputs `Device1 Channel Hash Table: [{'index': 0, 'role': 'PRIMARY', 'name': 'LongFast', 'hash': 8}` for a LongFast --- meshtastic/node.py | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/meshtastic/node.py b/meshtastic/node.py index 1b89881b..66135aae 100644 --- a/meshtastic/node.py +++ b/meshtastic/node.py @@ -1023,16 +1023,35 @@ def ensureSessionKey(self): def get_channels_with_hash(self): """Return a list of dicts with channel info and hash.""" result = [] + def format_preset_name(name): + # Convert name like MODEM_PRESET to ModemPreset + return ''.join(word.capitalize() for word in name.split('_')) + if self.channels: for c in self.channels: - if c.settings and hasattr(c.settings, "name") and hasattr(c.settings, "psk"): - hash_val = generate_channel_hash(c.settings.name, c.settings.psk) - else: - hash_val = None - result.append({ - "index": c.index, - "role": channel_pb2.Channel.Role.Name(c.role), - "name": c.settings.name if c.settings and hasattr(c.settings, "name") else "", + # Ignore DISABLED channels + if channel_pb2.Channel.Role.Name(getattr(c, "role", 0)) == "DISABLED": + continue + hash_val = None + name = "" + if getattr(c, "settings", None) is not None: + if hasattr(c.settings, "name") and hasattr(c.settings, "psk"): + hash_val = generate_channel_hash(c.settings.name, c.settings.psk) + name = getattr(c.settings, "name", "") + # If PRIMARY and name is empty, use formatted preset name from localConfig.lora.modem_preset + if c.role == channel_pb2.Channel.Role.PRIMARY and not name: + modem_preset_enum = getattr(getattr(self.localConfig, "lora", None), "modem_preset", None) + if modem_preset_enum is not None: + modem_preset_string = self.localConfig.lora.DESCRIPTOR.fields_by_name["modem_preset"].enum_type.values_by_number[modem_preset_enum].name + name = format_preset_name(modem_preset_string) + # Recompute hash with new name and key "AQ==" + hash_val = generate_channel_hash(name, "AQ==") + channel_info = { + "index": getattr(c, "index", None), + "role": channel_pb2.Channel.Role.Name(getattr(c, "role", 0)), + "name": name, "hash": hash_val, - }) + } + result.append(channel_info) return result + From 5838c4db6b4e6d1edb7e0cb6b9fe5bf80bb9b41f Mon Sep 17 00:00:00 2001 From: Kelly Date: Wed, 12 Nov 2025 10:21:56 -0800 Subject: [PATCH 2/3] Update meshtastic/node.py Co-authored-by: Ian McEwen --- meshtastic/node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshtastic/node.py b/meshtastic/node.py index 66135aae..7839ad20 100644 --- a/meshtastic/node.py +++ b/meshtastic/node.py @@ -1039,7 +1039,7 @@ def format_preset_name(name): hash_val = generate_channel_hash(c.settings.name, c.settings.psk) name = getattr(c.settings, "name", "") # If PRIMARY and name is empty, use formatted preset name from localConfig.lora.modem_preset - if c.role == channel_pb2.Channel.Role.PRIMARY and not name: + if not name: modem_preset_enum = getattr(getattr(self.localConfig, "lora", None), "modem_preset", None) if modem_preset_enum is not None: modem_preset_string = self.localConfig.lora.DESCRIPTOR.fields_by_name["modem_preset"].enum_type.values_by_number[modem_preset_enum].name From adfa51d3a271899caa5c3b67134157b34d342f74 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Wed, 12 Nov 2025 10:23:34 -0800 Subject: [PATCH 3/3] set default channel to Custom modem preset is set to none, the name used should be Custom --- meshtastic/node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshtastic/node.py b/meshtastic/node.py index 7839ad20..0e8cf71f 100644 --- a/meshtastic/node.py +++ b/meshtastic/node.py @@ -1023,7 +1023,7 @@ def ensureSessionKey(self): def get_channels_with_hash(self): """Return a list of dicts with channel info and hash.""" result = [] - def format_preset_name(name): + def format_preset_name(name='Custom'): # Convert name like MODEM_PRESET to ModemPreset return ''.join(word.capitalize() for word in name.split('_'))