Browse Source

added SNR lines for neighborInfo and direct routes in map

pull/457/head
Jamon Terrell 1 year ago
committed by Jamon Terrell
parent
commit
d1ed474362
  1. 20
      src/core/stores/deviceStore.ts
  2. 6
      src/core/subscriptions.ts
  3. 120
      src/pages/Map/index.tsx

20
src/core/stores/deviceStore.ts

@ -38,6 +38,8 @@ export interface Device {
activePage: Page;
activeNode: number;
waypoints: Protobuf.Mesh.Waypoint[];
neighborInfo: Map<number, Protobuf.Mesh.NeighborInfo>;
// currentMetrics: Protobuf.DeviceMetrics;
pendingSettingsChanges: boolean;
messageDraft: string;
unreadCounts: Map<number, number>;
@ -66,6 +68,10 @@ export interface Device {
setActivePage: (page: Page) => void;
setActiveNode: (node: number) => void;
setPendingSettingsChanges: (state: boolean) => void;
setNeighborInfo: (
nodeId: number,
neighborInfo: Protobuf.Mesh.NeighborInfo,
) => void;
addChannel: (channel: Protobuf.Channel.Channel) => void;
addWaypoint: (waypoint: Protobuf.Mesh.Waypoint) => void;
addNodeInfo: (nodeInfo: Protobuf.Mesh.NodeInfo) => void;
@ -145,6 +151,20 @@ export const useDeviceStore = createStore<PrivateDeviceState>((set, get) => ({
},
pendingSettingsChanges: false,
messageDraft: "",
neighborInfo: new Map<number, Protobuf.Mesh.NeighborInfo>(),
setNeighborInfo: (
nodeId: number,
neighborInfo: Protobuf.Mesh.NeighborInfo,
) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
device.neighborInfo.set(nodeId, neighborInfo);
}
}),
);
},
nodeErrors: new Map(),
unreadCounts: new Map(),
nodesMap: new Map(),

6
src/core/subscriptions.ts

@ -9,6 +9,7 @@ export const subscribeAll = (
connection: MeshDevice,
messageStore: MessageStore,
) => {
// Set device as a global variable for debugging
let myNodeNum = 0;
connection.events.onDeviceMetadataPacket.subscribe((metadataPacket) => {
@ -97,6 +98,7 @@ export const subscribeAll = (
});
connection.events.onTraceRoutePacket.subscribe((traceRoutePacket) => {
console.log("Trace Route Packet", traceRoutePacket);
device.addTraceRoute({
...traceRoutePacket,
});
@ -142,4 +144,8 @@ export const subscribeAll = (
}
}
});
connection.events.onNeighborInfoPacket.subscribe((neighborInfo) => {
device.setNeighborInfo(neighborInfo.from, neighborInfo.data);
});
};

120
src/pages/Map/index.tsx

@ -11,16 +11,37 @@ import { useCallback, useEffect, useMemo, useState } from "react";
import {
AttributionControl,
GeolocateControl,
Layer,
Marker,
NavigationControl,
Popup,
ScaleControl,
Source,
useMap,
} from "react-map-gl/maplibre";
import MapGl from "react-map-gl/maplibre";
import { useNodeFilters } from "@core/hooks/useNodeFilters.ts";
import { FilterControl } from "@pages/Map/FilterControl.tsx";
// taken from android client these probably should be moved into a shared file
const SNR_GOOD_THRESHOLD = -7;
const SNR_FAIR_THRESHOLD = -15;
const RSSI_GOOD_THRESHOLD = -115;
const RSSI_FAIR_THRESHOLD = -126;
const LINE_GOOD_COLOR = "#00ff00";
const LINE_FAIR_COLOR = "#ffe600";
const LINE_BAD_COLOR = "#f7931a";
const getSignalColor = (snr: number, rssi?: number) => {
if (snr > SNR_GOOD_THRESHOLD && (rssi == null || rssi > RSSI_GOOD_THRESHOLD))
return LINE_GOOD_COLOR;
if (snr > SNR_FAIR_THRESHOLD && (rssi == null || rssi > RSSI_FAIR_THRESHOLD))
return LINE_FAIR_COLOR;
return LINE_BAD_COLOR;
};
const DIRECT_NODE_TIMEOUT = 60 * 20; // 60 seconds * ? minutes
type NodePosition = {
latitude: number;
longitude: number;
@ -34,8 +55,72 @@ const convertToLatLng = (position: {
longitude: (position.longitudeI ?? 0) / 1e7,
});
const generateNeighborLines = (
nodes: {
node: Protobuf.Mesh.NodeInfo;
neighborInfo: Protobuf.Mesh.NeighborInfo;
}[],
) => {
const features = [];
for (const { node, neighborInfo } of nodes) {
const start = convertToLatLng(node.position);
if (!neighborInfo) continue;
for (const neighbor of neighborInfo.neighbors) {
const toNode = nodes.find((n) => n.node.num === neighbor.nodeId)?.node;
if (!toNode) continue;
const end = convertToLatLng(toNode.position);
features.push({
type: "Feature",
geometry: {
type: "LineString",
coordinates: [
[start.longitude, start.latitude],
[end.longitude, end.latitude],
],
},
properties: {
color: getSignalColor(neighbor.snr),
},
});
}
}
return {
type: "FeatureCollection",
features,
};
};
const generateDirectLines = (nodes: Protobuf.Mesh.NodeInfo[]) => {
const features = [];
for (const node of nodes) {
if (!node.position) continue;
if (node.hopsAway > 0) continue;
if (Date.now() / 1000 - node.lastHeard > DIRECT_NODE_TIMEOUT) continue;
const start = convertToLatLng(node.position);
const selfNode = nodes.find((n) => n.isFavorite);
const end = convertToLatLng(selfNode.position);
features.push({
type: "Feature",
geometry: {
type: "LineString",
coordinates: [
[start.longitude, start.latitude],
[end.longitude, end.latitude],
],
},
properties: {
color: getSignalColor(node.snr),
},
});
}
return {
type: "FeatureCollection",
features,
};
};
const MapPage = () => {
const { getNodes, waypoints } = useDevice();
const { getNodes, waypoints, neighborInfo } = useDevice();
const { theme } = useTheme();
const { default: map } = useMap();
@ -153,6 +238,19 @@ const MapPage = () => {
[filteredNodes, handleMarkerClick],
);
const neighborLines = useMemo(() => {
return generateNeighborLines(
validNodes.map((vn) => ({
node: vn,
neighborInfo: neighborInfo.get(vn.num),
})),
);
}, [validNodes, neighborInfo]);
const directLines = useMemo(
() => generateDirectLines(validNodes),
[validNodes],
);
useEffect(() => {
map?.on("load", () => {
getMapBounds();
@ -205,6 +303,26 @@ const MapPage = () => {
</Marker>
))}
{markers}
<Source id="neighbor-lines" type="geojson" data={neighborLines}>
<Layer
id="neighborLineLayer"
type="line"
paint={{
"line-color": ["get", "color"],
"line-width": 2,
}}
/>
</Source>
<Source id="direct-lines" type="geojson" data={directLines}>
<Layer
id="directLineLayer"
type="line"
paint={{
"line-color": ["get", "color"],
"line-width": 4,
}}
/>
</Source>
{selectedNode
? (
<Popup

Loading…
Cancel
Save