liamcottle / meshtastic-map

A map of all Meshtastic nodes heard via MQTT.
https://meshtastic.liamcottle.net
MIT License
97 stars 25 forks source link

Neighbor info over LoRa deprecation, code for decoding traceroute as links (oriented graph) from this project db. #84

Open VigibotDev opened 2 weeks ago

VigibotDev commented 2 weeks ago

Because neighbor info propagation on LoRa is deprecated on Meshtastic now (but still available via MQTT for direct neighbors), we must use Traceroute request frames to build the network graph topology.

Here’s my PHP code to use on the project database to get all links with SNR. The limitation is the last hop, as it’s from the receiver’s perspective.

This is the backend code I use on my network topology grapher (https://www.serveurperso.com/) – sharing it here in case it can help anyone port it to JavaScript. I added comments in English to clarify functionality. This code works in real-world scenarios.

$links = [];

// Query to fetch traceroute data with various metrics
$result = $MYSQLI->query(
    "SELECT UNIX_TIMESTAMP(updated_at) AS updated_at, `from`, `to`, route, route_back, snr_towards, snr_back, want_response FROM traceroutes ORDER BY updated_at ASC"
);

if ($result) {
    while ($row = $result->fetch_assoc()) {
        // Check if the entry is older than 168 hours (7 days), skip if so
        $updatedat = (int)$row["updated_at"];
        if ($now - $updatedat > 168 * 3600) {
            continue;
        }

        // Skip entries where 'want_response' indicates this is a request packet
        $wantresponse = (int)$row["want_response"];
        if ($wantresponse == 1) {
            continue;
        }

        // Retrieve 'from' and 'to' node IDs and confirm they are valid nodes in the filtered set
        $to = (int)$row["from"];
        $from = (int)$row["to"];
        if (!isset($filterednodes[$from]) || !isset($filterednodes[$to])) {
            continue;
        }

        // Decode route and SNR data
        $route = json_decode($row["route"], true);
        $route_back = json_decode($row["route_back"], true);
        $snr_towards = json_decode($row["snr_towards"], true);
        $snr_back = json_decode($row["snr_back"], true);

        // Case 1: Direct link without intermediate hops
        if (empty($route) && isset($snr_towards[0]) && $snr_towards[0] != -128) {
            // Remove any existing duplicate link and add a direct link with SNR
            foreach ($links as $key => $link) {
                if ($link["source"] == $from && $link["target"] == $to) {
                    unset($links[$key]);
                    break;
                }
            }
            $links[] = [
                "source" => $from,
                "target" => $to,
                "snr" => $snr_towards[0] / 4
            ];
        }

        // Case 2: Multi-hop route with forward SNR values
        if (!empty($route)) {
            $previousnode = $from;
            foreach ($route as $i => $nextnode) {
                if (!isset($filterednodes[$previousnode]) || !isset($filterednodes[$nextnode])) {
                    continue;
                }

                // Remove any existing duplicate link and add new link
                foreach ($links as $key => $link) {
                    if ($link["source"] == $previousnode && $link["target"] == $nextnode) {
                        unset($links[$key]);
                        break;
                    }
                }

                if (isset($snr_towards[$i]) && $snr_towards[$i] != -128) {
                    $links[] = [
                        "source" => $previousnode,
                        "target" => $nextnode,
                        "snr" => $snr_towards[$i] / 4
                    ];
                }

                $previousnode = $nextnode;
            }

            // Add final link to the destination if SNR is available
            if (isset($filterednodes[$previousnode]) && isset($filterednodes[$to]) && isset($snr_towards[count($route)]) && $snr_towards[count($route)] != -128) {
                foreach ($links as $key => $link) {
                    if ($link["source"] == $previousnode && $link["target"] == $to) {
                        unset($links[$key]);
                        break;
                    }
                }
                $links[] = [
                    "source" => $previousnode,
                    "target" => $to,
                    "snr" => $snr_towards[count($route)] / 4
                ];
            }
        }

        // Case 3: Multi-hop route with backward SNR values (route_back)
        if (!empty($route_back)) {
            $previousnode = $to;
            foreach ($route_back as $i => $nextnode) {
                if (!isset($filterednodes[$previousnode]) || !isset($filterednodes[$nextnode])) {
                    continue;
                }

                // Remove any existing duplicate link and add backward link
                foreach ($links as $key => $link) {
                    if ($link["source"] == $previousnode && $link["target"] == $nextnode) {
                        unset($links[$key]);
                        break;
                    }
                }

                if (isset($snr_back[$i]) && $snr_back[$i] != -128) {
                    $links[] = [
                        "source" => $previousnode,
                        "target" => $nextnode,
                        "snr" => $snr_back[$i] / 4
                    ];
                }

                $previousnode = $nextnode;
            }
        }
    }
    $result->free();
}