Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions meshtastic/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -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='Custom'):
# Convert name like MODEM_PRESET to ModemPreset
return ''.join(word.capitalize() for word in name.split('_'))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't quite correct, because not every preset uses the full name for this. You can see what names firmware uses at https://github.com/meshtastic/firmware/blob/7212fb9caa15119c500edb3a074a5bc6b956605d/src/DisplayFormatters.cpp#L3-L41

Primarily it's just LONG_MODERATE though, and that the name Custom is used if a modem preset isn't in use.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this too bulky? or should be in util?

MODEM_PRESET_DISPLAY_NAMES = {
    "SHORT_TURBO": ("ShortTurbo", "ShortT"),
    "SHORT_SLOW": ("ShortSlow", "ShortS"),
    "SHORT_FAST": ("ShortFast", "ShortF"),
    "MEDIUM_SLOW": ("MediumSlow", "MedS"),
    "MEDIUM_FAST": ("MediumFast", "MedF"),
    "LONG_SLOW": ("LongSlow", "LongS"),
    "LONG_FAST": ("LongFast", "LongF"),
    "LONG_MODERATE": ("LongMod", "LongM"),
}

def format_preset_name(name=None, use_short_name=False):
    # Returns a user-friendly display name for a given preset.
    if name is None:
        return "Custom"
    # Normalize input: extract the preset part from full enum string
    if isinstance(name, str):
        parts = name.split('_')
        # Find the preset part (e.g., LONG_FAST)
        for i in range(len(parts)):
            key = '_'.join(parts[i:])
            if key in MODEM_PRESET_DISPLAY_NAMES:
                names = MODEM_PRESET_DISPLAY_NAMES[key]
                return names[1] if use_short_name else names[0]
    return "Invalid"


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 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