mirror of
https://github.com/pablorevilla-meshtastic/meshview.git
synced 2026-10-31 03:01:58 +01:00
A completed traceroute is observed as a response packet, whose from/to are reversed with respect to the path being traced: `to` is the node that started the traceroute and `from` is the node that answered. Meshview assembled paths as [from, *route, to], so both endpoint-adjacent edges were wrong for every completed traceroute with at least one intermediate hop. Because the false edges always attach to the endpoints, a busy initiator or gateway accumulated false direct links to every remote target it ever traced. Confirmed against TraceRouteModule::alterReceivedProtobuf, which renders a response as printRoute(r, p.to, p.from, false), against the meshtastic python CLI, which starts the forward path at p["to"] and the return path at p["from"], and against real recorded traceroutes where a request's route[] is a prefix of the matching response's route[]. Add meshview/traceroute.py and use it from /api/edges, /api/traceroute and graph_traceroute, which had three separate copies of this logic that had all drifted. /api/traceroute also gains initiator/target so the traceroute page stops re-deriving the endpoints itself, which is where a fourth copy lived. While in /api/edges, skip the NODENUM_BROADCAST placeholders that insertUnknownHops() writes into route[] (they became a pseudo-node hub in the graph) and guard against the (gateway, gateway) self edge that graph_traceroute already guarded against.
449 lines
10 KiB
Markdown
449 lines
10 KiB
Markdown
# API Documentation
|
|
|
|
Base URL: `http(s)://<host>`
|
|
|
|
All endpoints return JSON. Timestamps are either ISO 8601 strings or `*_us` values in
|
|
microseconds since epoch.
|
|
|
|
## 1. Nodes API
|
|
|
|
### GET `/api/nodes`
|
|
Returns a list of nodes, with optional filtering.
|
|
|
|
Query Parameters
|
|
- `node_id` (optional, int): Exact node ID.
|
|
- `role` (optional, string): Node role.
|
|
- `channel` (optional, string): Channel name.
|
|
- `hw_model` (optional, string): Hardware model.
|
|
- `days_active` (optional, int): Nodes seen within the last N days.
|
|
|
|
Response Example
|
|
```json
|
|
{
|
|
"nodes": [
|
|
{
|
|
"id": 42,
|
|
"node_id": 1234,
|
|
"long_name": "Alice",
|
|
"short_name": "A",
|
|
"hw_model": "T-Beam",
|
|
"firmware": "1.2.3",
|
|
"role": "client",
|
|
"last_lat": 377749000,
|
|
"last_long": -1224194000,
|
|
"channel": "main",
|
|
"last_seen_us": 1736370123456789
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Packets API
|
|
|
|
### GET `/api/packets`
|
|
Returns packets with optional filters.
|
|
|
|
Query Parameters
|
|
- `packet_id` (optional, int): Return exactly one packet (overrides other filters).
|
|
- `limit` (optional, int): Max packets to return, clamped 1-1000. Default: `50`.
|
|
- `since` (optional, int): Only packets imported after this microsecond timestamp.
|
|
- `portnum` (optional, int): Filter by port number.
|
|
- `contains` (optional, string): Payload substring filter.
|
|
- `from_node_id` (optional, int): Filter by sender node ID.
|
|
- `to_node_id` (optional, int): Filter by recipient node ID.
|
|
- `node_id` (optional, int): Legacy filter matching either from or to node ID.
|
|
|
|
Response Example
|
|
```json
|
|
{
|
|
"packets": [
|
|
{
|
|
"id": 123,
|
|
"import_time_us": 1736370123456789,
|
|
"channel": "main",
|
|
"from_node_id": 5678,
|
|
"to_node_id": 91011,
|
|
"portnum": 1,
|
|
"long_name": "Alice",
|
|
"payload": "Hello, Bob!",
|
|
"to_long_name": "Bob",
|
|
"reply_id": 122
|
|
}
|
|
],
|
|
"latest_import_time": 1736370123456789
|
|
}
|
|
```
|
|
|
|
Notes
|
|
- For `portnum=1` (text messages), packets are filtered to remove sequence-only payloads.
|
|
- `latest_import_time` is returned when available for incremental polling (microseconds).
|
|
|
|
---
|
|
|
|
## 3. Channels API
|
|
|
|
### GET `/api/channels`
|
|
Returns channels seen in a time period.
|
|
|
|
Query Parameters
|
|
- `period_type` (optional, string): `hour` or `day`. Default: `hour`.
|
|
- `length` (optional, int): Number of periods to look back. Default: `24`.
|
|
|
|
Response Example
|
|
```json
|
|
{
|
|
"channels": ["LongFast", "MediumFast", "ShortFast"]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Stats API
|
|
|
|
### GET `/api/stats`
|
|
Returns packet statistics aggregated by time periods, with optional filtering.
|
|
|
|
Query Parameters
|
|
- `period_type` (optional, string): `hour` or `day`. Default: `hour`.
|
|
- `length` (optional, int): Number of periods to include. Default: `24`.
|
|
- `channel` (optional, string): Filter by channel (case-insensitive).
|
|
- `portnum` (optional, int): Filter by port number.
|
|
- `to_node` (optional, int): Filter by destination node ID.
|
|
- `from_node` (optional, int): Filter by source node ID.
|
|
- `node` (optional, int): If provided, return combined `sent` and `seen` totals for that node.
|
|
|
|
Response Example (series)
|
|
```json
|
|
{
|
|
"period_type": "hour",
|
|
"length": 24,
|
|
"channel": "LongFast",
|
|
"portnum": 1,
|
|
"to_node": 12345678,
|
|
"from_node": 87654321,
|
|
"data": [
|
|
{ "period": "2025-08-08 14:00", "count": 10 },
|
|
{ "period": "2025-08-08 15:00", "count": 7 }
|
|
]
|
|
}
|
|
```
|
|
|
|
Response Example (`node` totals)
|
|
```json
|
|
{
|
|
"node_id": 12345678,
|
|
"period_type": "hour",
|
|
"length": 24,
|
|
"sent": 42,
|
|
"seen": 58
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### GET `/api/stats/count`
|
|
Returns total packet counts, optionally filtered.
|
|
|
|
Query Parameters
|
|
- `packet_id` (optional, int): Filter packet_seen by packet ID.
|
|
- `period_type` (optional, string): `hour` or `day`.
|
|
- `length` (optional, int): Number of periods to include.
|
|
- `channel` (optional, string): Filter by channel.
|
|
- `from_node` (optional, int): Filter by source node ID.
|
|
- `to_node` (optional, int): Filter by destination node ID.
|
|
|
|
Response Example
|
|
```json
|
|
{
|
|
"total_packets": 12345,
|
|
"total_seen": 67890
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### GET `/api/stats/top`
|
|
Returns nodes sorted by packets seen, with pagination.
|
|
|
|
Query Parameters
|
|
- `period_type` (optional, string): `hour` or `day`. Default: `day`.
|
|
- `length` (optional, int): Number of periods to include. Default: `1`.
|
|
- `channel` (optional, string): Filter by channel.
|
|
- `limit` (optional, int): Max nodes to return. Default: `20`, max `100`.
|
|
- `offset` (optional, int): Pagination offset. Default: `0`.
|
|
|
|
Response Example
|
|
```json
|
|
{
|
|
"total": 250,
|
|
"limit": 20,
|
|
"offset": 0,
|
|
"nodes": [
|
|
{
|
|
"node_id": 1234,
|
|
"long_name": "Alice",
|
|
"short_name": "A",
|
|
"channel": "main",
|
|
"sent": 100,
|
|
"seen": 240,
|
|
"avg": 2.4
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Edges API
|
|
|
|
### GET `/api/edges`
|
|
Returns network edges (connections between nodes) based on traceroutes and neighbor info.
|
|
Traceroute edges are collected over the last 12 hours. Neighbor edges are based on
|
|
port 71 packets.
|
|
|
|
A completed traceroute is observed as a response packet, whose `from`/`to` are reversed
|
|
with respect to the traced path, so edges are built as `to -> route[] -> from`. Unknown
|
|
hop placeholders (`0xFFFFFFFF`) are skipped.
|
|
|
|
Query Parameters
|
|
- `type` (optional, string): `traceroute` or `neighbor`. If omitted, returns both.
|
|
- `node_id` (optional, int): Filter edges to only those touching a node.
|
|
|
|
Response Example
|
|
```json
|
|
{
|
|
"edges": [
|
|
{ "from": 12345678, "to": 87654321, "type": "traceroute" },
|
|
{ "from": 11111111, "to": 22222222, "type": "neighbor" }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Config API
|
|
|
|
### GET `/api/config`
|
|
Returns a safe subset of server configuration.
|
|
|
|
Response Example
|
|
```json
|
|
{
|
|
"site": {
|
|
"domain": "example.com",
|
|
"language": "en",
|
|
"title": "Meshview",
|
|
"message": "",
|
|
"starting": "/chat",
|
|
"nodes": "true",
|
|
"chat": "true",
|
|
"everything": "true",
|
|
"graphs": "true",
|
|
"stats": "true",
|
|
"net": "true",
|
|
"map": "true",
|
|
"top": "true",
|
|
"map_top_left_lat": 39.0,
|
|
"map_top_left_lon": -123.0,
|
|
"map_bottom_right_lat": 36.0,
|
|
"map_bottom_right_lon": -121.0,
|
|
"map_interval": 3,
|
|
"firehose_interval": 3,
|
|
"weekly_net_message": "Weekly Mesh check-in message.",
|
|
"net_tag": "#BayMeshNet",
|
|
"version": "3.0.0"
|
|
},
|
|
"mqtt": {
|
|
"server": "mqtt.example.com",
|
|
"topics": ["msh/region/#"]
|
|
},
|
|
"cleanup": {
|
|
"enabled": "false",
|
|
"days_to_keep": "14",
|
|
"hour": "2",
|
|
"minute": "0",
|
|
"vacuum": "false"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Language API
|
|
|
|
### GET `/api/lang`
|
|
Returns translation strings.
|
|
|
|
Query Parameters
|
|
- `lang` (optional, string): Language code (e.g., `en`, `es`). Default from config or `en`.
|
|
- `section` (optional, string): Return only one section (e.g., `nodelist`, `firehose`).
|
|
|
|
Response Example
|
|
```json
|
|
{
|
|
"title": "Meshview",
|
|
"search_placeholder": "Search..."
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Packets Seen API
|
|
|
|
### GET `/api/packets_seen/{packet_id}`
|
|
Returns packet_seen entries for a packet.
|
|
|
|
Path Parameters
|
|
- `packet_id` (required, int): Packet ID.
|
|
|
|
Response Example
|
|
```json
|
|
{
|
|
"seen": [
|
|
{
|
|
"packet_id": 123,
|
|
"node_id": 456,
|
|
"rx_time": "2025-07-22T12:45:00",
|
|
"hop_limit": 7,
|
|
"hop_start": 0,
|
|
"channel": "main",
|
|
"rx_snr": 5.0,
|
|
"rx_rssi": -90,
|
|
"topic": "msh/region/#",
|
|
"import_time_us": 1736370123456789
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Traceroute API
|
|
|
|
### GET `/api/traceroute/{packet_id}`
|
|
Returns traceroute details and derived paths for a packet.
|
|
|
|
Path Parameters
|
|
- `packet_id` (required, int): Packet ID.
|
|
|
|
A completed traceroute is observed as a response packet, whose `from`/`to` are reversed
|
|
with respect to the traced path. `initiator` and `target` resolve this: the forward path
|
|
runs `initiator -> forward_hops -> target` and the return path runs
|
|
`target -> reverse_hops -> initiator`, in both directions of travel. `forward_hops` and
|
|
`reverse_hops` contain only the intermediate hops, never the endpoints.
|
|
|
|
Response Example
|
|
```json
|
|
{
|
|
"packet": {
|
|
"id": 123,
|
|
"from": 222,
|
|
"to": 111,
|
|
"initiator": 111,
|
|
"target": 222,
|
|
"channel": "main"
|
|
},
|
|
"traceroute_packets": [
|
|
{
|
|
"index": 0,
|
|
"gateway_node_id": 333,
|
|
"done": true,
|
|
"forward_hops": [444, 555],
|
|
"reverse_hops": [555, 444]
|
|
}
|
|
],
|
|
"unique_forward_paths": [
|
|
{ "path": [444, 555], "count": 2 }
|
|
],
|
|
"unique_reverse_paths": [
|
|
[555, 444]
|
|
],
|
|
"winning_paths": {
|
|
"forward": [[111, 444, 555, 222]],
|
|
"reverse": [[222, 555, 444, 111]]
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 10. Health API
|
|
|
|
### GET `/health`
|
|
Returns service health and database status.
|
|
|
|
Response Example
|
|
```json
|
|
{
|
|
"status": "healthy",
|
|
"timestamp": "2025-07-22T12:45:00+00:00",
|
|
"version": "3.0.3",
|
|
"git_revision": "abc1234",
|
|
"cleanup": {
|
|
"enabled": true,
|
|
"days_to_keep": 14,
|
|
"scheduled_time": "02:00",
|
|
"vacuum": false,
|
|
"status": "ok",
|
|
"status_file": "dbcleanup.status.json",
|
|
"last_run": {
|
|
"status": "ok",
|
|
"started_at": "2026-06-04T09:00:00+00:00",
|
|
"completed_at": "2026-06-04T09:00:03+00:00",
|
|
"cutoff_at": "2026-05-21T09:00:00+00:00",
|
|
"days_to_keep": 14,
|
|
"vacuum_requested": false,
|
|
"vacuum_completed": false,
|
|
"rows_deleted": {
|
|
"packet": 1200,
|
|
"packet_seen": 3400,
|
|
"traceroute": 42,
|
|
"node": 3
|
|
},
|
|
"error": null
|
|
}
|
|
},
|
|
"backup": {
|
|
"enabled": true,
|
|
"backup_dir": "./backups",
|
|
"scheduled_time": "02:00",
|
|
"status": "ok",
|
|
"status_file": "dbbackup.status.json",
|
|
"last_run": {
|
|
"status": "ok",
|
|
"started_at": "2026-06-04T09:00:00+00:00",
|
|
"completed_at": "2026-06-04T09:00:02+00:00",
|
|
"backup_dir": "./backups",
|
|
"database_path": "packets.db",
|
|
"backup_file": "backups/packets_backup_20260604_090000.db.gz",
|
|
"original_size_bytes": 12939444,
|
|
"compressed_size_bytes": 4211560,
|
|
"compression_percent": 67.5,
|
|
"error": null
|
|
}
|
|
},
|
|
"database": "connected",
|
|
"database_size": "12.34 MB",
|
|
"database_size_bytes": 12939444
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 11. Version API
|
|
|
|
### GET `/version`
|
|
Returns version metadata.
|
|
|
|
Response Example
|
|
```json
|
|
{
|
|
"version": "3.0.3",
|
|
"release_date": "2026-1-15",
|
|
"git_revision": "abc1234",
|
|
"git_revision_short": "abc1234"
|
|
}
|
|
```
|