diff --git a/meshtastic/mesh_interface.py b/meshtastic/mesh_interface.py index d6bbe0f..23c5fac 100644 --- a/meshtastic/mesh_interface.py +++ b/meshtastic/mesh_interface.py @@ -548,17 +548,46 @@ class MeshInterface: # pylint: disable=R0902 def onResponseTraceRoute(self, p: dict): """on response for trace route""" + UNK_SNR = -128 # Value representing unknown SNR + routeDiscovery = mesh_pb2.RouteDiscovery() routeDiscovery.ParseFromString(p["decoded"]["payload"]) asDict = google.protobuf.json_format.MessageToDict(routeDiscovery) - print("Route traced:") - routeStr = self._nodeNumToId(p["to"]) or f"{p['to']:08x}" - if "route" in asDict: - for nodeNum in asDict["route"]: - routeStr += " --> " + (self._nodeNumToId(nodeNum) or f"{nodeNum:08x}") - routeStr += " --> " + (self._nodeNumToId(p["from"]) or f"{p['from']:08x}") - print(routeStr) + print("Route traced towards destination:") + routeStr = self._nodeNumToId(p["to"], False) or f"{p['to']:08x}" # Start with destination of response + + # SNR list should have one more entry than the route, as the final destination adds its SNR also + lenTowards = 0 if "route" not in asDict else len(asDict["route"]) + snrTowardsValid = "snrTowards" in asDict and len(asDict["snrTowards"]) == lenTowards + 1 + if lenTowards > 0: # Loop through hops in route and add SNR if available + for idx, nodeNum in enumerate(asDict["route"]): + routeStr += " --> " + (self._nodeNumToId(nodeNum, False) or f"{nodeNum:08x}") \ + + " (" + (str(asDict["snrTowards"][idx] / 4) if snrTowardsValid and asDict["snrTowards"][idx] != UNK_SNR else "?") + "dB)" + + # End with origin of response + routeStr += " --> " + (self._nodeNumToId(p["from"], False) or f"{p['from']:08x}") \ + + " (" + (str(asDict["snrTowards"][-1] / 4) if snrTowardsValid and asDict["snrTowards"][-1] != UNK_SNR else "?") + "dB)" + + print(routeStr) # Print the route towards destination + + # Only if there is an SNR entry (for the origin) it's valid, even though route might be empty (direct connection) + lenBack = 0 if "routeBack" not in asDict else len(asDict["routeBack"]) + backValid = "snrBack" in asDict and len(asDict["snrBack"]) == lenBack + 1 + if backValid: + print("Route traced back to us:") + routeStr = self._nodeNumToId(p["from"], False) or f"{p['from']:08x}" # Start with origin of response + + if lenBack > 0: # Loop through hops in routeBack and add SNR if available + for idx, nodeNum in enumerate(asDict["routeBack"]): + routeStr += " --> " + (self._nodeNumToId(nodeNum, False) or f"{nodeNum:08x}") \ + + " (" + (str(asDict["snrBack"][idx] / 4) if asDict["snrBack"][idx] != UNK_SNR else "?") + "dB)" + + # End with destination of response (us) + routeStr += " --> " + (self._nodeNumToId(p["to"], False) or f"{p['to']:08x}") \ + + " (" + (str(asDict["snrBack"][-1] / 4) if asDict["snrBack"][-1] != UNK_SNR else "?") + "dB)" + + print(routeStr) # Print the route back to us self._acknowledgment.receivedTraceRoute = True @@ -1143,17 +1172,21 @@ class MeshInterface: # pylint: disable=R0902 position["longitude"] = float(position["longitudeI"] * Decimal("1e-7")) return position - def _nodeNumToId(self, num: int) -> Optional[str]: + def _nodeNumToId(self, num: int, isDest = True) -> Optional[str]: """Map a node node number to a node ID Arguments: num {int} -- Node number + isDest {bool} -- True if the node number is a destination (to show broadcast address or unknown node) Returns: string -- Node ID """ if num == BROADCAST_NUM: - return BROADCAST_ADDR + if isDest: + return BROADCAST_ADDR + else: + return "Unknown" try: return self.nodesByNum[num]["user"]["id"] # type: ignore[index] @@ -1226,7 +1259,7 @@ class MeshInterface: # pylint: disable=R0902 # /add fromId and toId fields based on the node ID try: - asDict["fromId"] = self._nodeNumToId(asDict["from"]) + asDict["fromId"] = self._nodeNumToId(asDict["from"], False) except Exception as ex: logging.warning(f"Not populating fromId {ex}") try: