diff --git a/config.ini.example b/config.ini.example index 84c5ee4..a805082 100644 --- a/config.ini.example +++ b/config.ini.example @@ -248,6 +248,8 @@ companion_min_inactive_days = 30 # {rssi} - Received signal strength indicator in dBm # {timestamp} - Message timestamp in HH:MM:SS format # {path} - Message routing path (e.g., "01,5f (2 hops)") +# {hops} - Total hop count only (e.g., "2" or "0"); same value as in path/connection_info, for use without the path string +# {hops_label} - Same as hops with word "hop"/"hops" and pluralization (e.g., "1 hop", "2 hops", or "?" when unknown) # {path_distance} - Total distance between all hops in path with locations (e.g., "123.4km (3 segs, 1 no-loc)") # {firstlast_distance} - Distance between first and last repeater in path (e.g., "45.6km" or empty if locations missing) # {elapsed} - Elapsed time (e.g. 1234ms) or "Sync Device Clock" when device clock is invalid (use {elapsed} only; do not append ms) diff --git a/modules/core.py b/modules/core.py index 40165b5..f99fad7 100644 --- a/modules/core.py +++ b/modules/core.py @@ -543,6 +543,8 @@ admin_commands = repeater # {rssi}: Received signal strength indicator in dBm # {timestamp}: Message timestamp in HH:MM:SS format # {path}: Message routing path (e.g., "01,5f (2 hops)") +# {hops}: Total hop count only (e.g., "2" or "0"); same value as in path/connection_info +# {hops_label}: Same as hops with "hop"/"hops" and pluralization (e.g., "1 hop", "2 hops") # {path_distance}: Total distance between all hops in path with locations (e.g., "123.4km (3 segs, 1 no-loc)") # {firstlast_distance}: Distance between first and last repeater in path (e.g., "45.6km" or empty if locations missing) test = "ack [@{sender}]{phrase_part} | {connection_info} | Received at: {timestamp}" diff --git a/modules/utils.py b/modules/utils.py index 3ed6f45..e6094a6 100644 --- a/modules/utils.py +++ b/modules/utils.py @@ -2099,6 +2099,27 @@ def format_keyword_response_with_placeholders( time_str = "Unknown" replacements['timestamp'] = time_str + + # Total hops: use message.hops when set, else parse from path string (e.g. "01,5f (2 hops)") + hops_val = getattr(message, 'hops', None) + if hops_val is not None and isinstance(hops_val, int): + replacements['hops'] = str(hops_val) + else: + path_str = message.path or "" + hop_match = re.search(r'\((\d+)\s*hops?', path_str, re.IGNORECASE) + if hop_match: + replacements['hops'] = hop_match.group(1) + elif re.search(r'\bdirect\b|\b0\s*hops?\b', path_str, re.IGNORECASE): + replacements['hops'] = "0" + else: + replacements['hops'] = "?" + # Pluralized label: "1 hop", "2 hops", or "?" when unknown + h = replacements['hops'] + if h == "?": + replacements['hops_label'] = "?" + else: + n = int(h) + replacements['hops_label'] = "1 hop" if n == 1 else f"{n} hops" else: # No message - use defaults for message-based placeholders replacements['sender'] = "Unknown" @@ -2110,6 +2131,8 @@ def format_keyword_response_with_placeholders( replacements['path_distance'] = "" replacements['firstlast_distance'] = "" replacements['timestamp'] = "Unknown" + replacements['hops'] = "?" + replacements['hops_label'] = "?" # Mesh-info-based placeholders (from scheduled messages) if mesh_info: