From fd653f82342adda716253d74dbb43f24c00b08a2 Mon Sep 17 00:00:00 2001 From: Pablo Revilla Date: Mon, 1 Dec 2025 09:38:08 -0800 Subject: [PATCH] Fixed Sort nodes by firmware in nodelist.html --- meshview/static/api-config.html | 100 ---------- meshview/static/api-edges.html | 109 ----------- meshview/static/api-nodes.html | 134 ------------- meshview/static/api-packets.html | 167 ---------------- meshview/static/api-stats.html | 210 -------------------- meshview/static/api.html | 326 ++++++++++++++++++++++++------- meshview/static/kiosk.html | 51 +++-- meshview/static/live-map.html | 209 -------------------- meshview/templates/node.html | 2 +- meshview/web.py | 44 ++--- 10 files changed, 308 insertions(+), 1044 deletions(-) delete mode 100644 meshview/static/api-config.html delete mode 100644 meshview/static/api-edges.html delete mode 100644 meshview/static/api-nodes.html delete mode 100644 meshview/static/api-packets.html delete mode 100644 meshview/static/api-stats.html delete mode 100644 meshview/static/live-map.html diff --git a/meshview/static/api-config.html b/meshview/static/api-config.html deleted file mode 100644 index 48175b8..0000000 --- a/meshview/static/api-config.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - API Documentation - Config - - - - -
- - - - - diff --git a/meshview/static/api-edges.html b/meshview/static/api-edges.html deleted file mode 100644 index e1fcec2..0000000 --- a/meshview/static/api-edges.html +++ /dev/null @@ -1,109 +0,0 @@ - - - - - API Documentation - Edges - - - - -
- - - - - diff --git a/meshview/static/api-nodes.html b/meshview/static/api-nodes.html deleted file mode 100644 index 9dc7d11..0000000 --- a/meshview/static/api-nodes.html +++ /dev/null @@ -1,134 +0,0 @@ - - - - - API Documentation - Nodes - - - - -
- - - - - diff --git a/meshview/static/api-packets.html b/meshview/static/api-packets.html deleted file mode 100644 index df9e627..0000000 --- a/meshview/static/api-packets.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - - API Documentation - Packets - - - - -
- - - - - diff --git a/meshview/static/api-stats.html b/meshview/static/api-stats.html deleted file mode 100644 index bc884b0..0000000 --- a/meshview/static/api-stats.html +++ /dev/null @@ -1,210 +0,0 @@ - - - - - API Documentation - Packet Stats - - - - -
- - - - - diff --git a/meshview/static/api.html b/meshview/static/api.html index 5e97b38..4ff9148 100644 --- a/meshview/static/api.html +++ b/meshview/static/api.html @@ -1,91 +1,273 @@ - + - - - API Index - + + -
- API Index -
+

Meshview API Documentation

+

This page describes all REST endpoints provided by Meshview.

-
- + + +

/api/nodes

+ +
+ GET + /api/nodes +

Returns a list of mesh nodes.

+ +

Query Parameters

+ + + + + + +
ParameterDescription
roleFilter by node role
channelFilter by channel
hw_modelHardware model filter
days_activeOnly nodes seen within X days
+ +
+ Example:
+ /api/nodes?days_active=3 +
+ + +

/api/packets

+ +
+ GET + /api/packets +

Fetch packets with many filters. Returns decoded packet data.

+ +

Query Parameters

+ + + + + + + + + + +
ParameterDescription
packet_idReturn exactly one packet
limitMax number of results (1–100)
sinceOnly packets newer than import_time_us
from_node_idFilter by sender node
to_node_idFilter by destination node
node_idLegacy: match either from or to
portnumFilter by port number
containsSubstring filter for payload
+ +
+ Example:
+ /api/packets?from_node_id=123&limit=100 +
+
+ + + +

/api/packets_seen/{packet_id}

+ +
+ GET + /api/packets_seen/<packet_id> +

Returns list of gateways that heard the packet (RSSI/SNR/hops).

+ +
+ Example:
+ /api/packets_seen/3314808102 +
+
+ + + +

/api/stats

+ +
+ GET + /api/stats +

Returns aggregated packet statistics for a node or globally.

+ +

Query Parameters

+ + + + + + + + + +
ParameterDescription
period_type"hour" or "day"
lengthHow many hours/days
nodeNode ID for combined sent+seen stats
from_nodeFilter by sender
to_nodeFilter by receiver
portnumFilter by port
channelFilter by channel
+ +
+ Example:
+ /api/stats?node=1128180332&period_type=day&length=1 +
+
+ + + +

/api/stats/count

+ +
+ GET + /api/stats/count +

+ Returns total packets and total packet_seen entries. + When no filters are provided, it returns global totals. + When filters are specified, they narrow the time, channel, + direction, or specific packet. +

+ +

Query Parameters

+ + + + + + + + +
ParameterDescription
period_type"hour" or "day"
lengthNumber of hours or days (depends on period_type)
channelFilter by channel
from_nodeOnly packets sent by this node
to_nodeOnly packets received by this node
packet_idFilter seen counts for specific packet_id
+ +
+ Example:
+ /api/stats/count?from_node=1128180332&period_type=day&length=1 +
+
+ + + + +

/api/edges

+ +
+ GET + /api/edges +

Returns traceroute and/or neighbor edges for graph rendering.

+ +

Query Parameters

+ + + +
ParameterDescription
type"traceroute", "neighbor", or omitted for both
+ +
+ Example:
+ /api/edges?type=neighbor +
+
+ + + +

/api/config

+ +
+ GET + /api/config +

Returns Meshview configuration (site, MQTT, cleanup, etc.).

+ +
+ /api/config +
+
+ + + +

/api/lang

+ +
+ GET + /api/lang +

Returns translated text for the UI.

+ +

Parameters

+ + + +
langLanguage code (e.g. "en")
sectionOptional UI section (firehose, map, top...)
+ +
+ /api/lang?lang=en§ion=firehose +
+
+ + + +

/health

+ +
+ GET + /health +

Returns API + database status.

+
+ + + +

/version

+ +
+ GET + /version +

Returns Meshview version and Git revision.

+
+ + +

+
+

Meshview API — generated documentation

+ diff --git a/meshview/static/kiosk.html b/meshview/static/kiosk.html index 0c2bfa0..002d0f3 100644 --- a/meshview/static/kiosk.html +++ b/meshview/static/kiosk.html @@ -190,32 +190,51 @@ body { margin: 0; font-family: monospace; background: #121212; color: #eee; } activeBlinks.set(marker,interval); } - let lastImportTime=null; + let lastImportTimeUs = null; + async function fetchLatestPacket(){ try{ - const res=await fetch(`/api/packets?limit=1`); - const data=await res.json(); - lastImportTime=data.packets?.[0]?.import_time || new Date().toISOString(); - }catch(err){ console.error(err); } + const res = await fetch(`/api/packets?limit=1`); + const data = await res.json(); + lastImportTimeUs = data.packets?.[0]?.import_time_us || 0; + }catch(err){ + console.error(err); + } } async function fetchNewPackets(){ - if(!lastImportTime) return; + if (!lastImportTimeUs) return; + try{ - const res=await fetch(`/api/packets?since=${lastImportTime}`); - const data=await res.json(); + const res = await fetch(`/api/packets?since=${lastImportTimeUs}`); + const data = await res.json(); if(!data.packets || !data.packets.length) return; - let latest=lastImportTime; - data.packets.forEach(packet=>{ - if(packet.import_time && packet.import_time>latest) latest=packet.import_time; - const marker=markerById[packet.from_node_id]; - const nodeData=nodeMap.get(packet.from_node_id); - if(marker && nodeData) blinkNode(marker,nodeData.long_name,packet.portnum); + + let latest = lastImportTimeUs; + + data.packets.forEach(packet => { + + // Track newest microsecond timestamp + if (packet.import_time_us && packet.import_time_us > latest) { + latest = packet.import_time_us; + } + + // Look up marker and blink it + const marker = markerById[packet.from_node_id]; + const nodeData = nodeMap.get(packet.from_node_id); + if (marker && nodeData) { + blinkNode(marker, nodeData.long_name, packet.portnum); + } }); - lastImportTime=latest; - }catch(err){ console.error(err); } + + lastImportTimeUs = latest; + + }catch(err){ + console.error(err); + } } + if(mapInterval>0){ fetchLatestPacket(); setInterval(fetchNewPackets,mapInterval*1000); } })(); diff --git a/meshview/static/live-map.html b/meshview/static/live-map.html deleted file mode 100644 index 0e6e2b8..0000000 --- a/meshview/static/live-map.html +++ /dev/null @@ -1,209 +0,0 @@ - - - - -Mesh Nodes Live Map - - - - -
-
- - - - - diff --git a/meshview/templates/node.html b/meshview/templates/node.html index f84f31e..9277a2a 100644 --- a/meshview/templates/node.html +++ b/meshview/templates/node.html @@ -882,4 +882,4 @@ document.addEventListener("DOMContentLoaded", async () => { }); }); -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/meshview/web.py b/meshview/web.py index 3f47415..a4f3a34 100644 --- a/meshview/web.py +++ b/meshview/web.py @@ -12,7 +12,7 @@ from google.protobuf import text_format from google.protobuf.message import Message from jinja2 import Environment, PackageLoader, Undefined, select_autoescape from markupsafe import Markup - +import pathlib from meshtastic.protobuf.portnums_pb2 import PortNum from meshview import config, database, decode_payload, migrations, models, store from meshview.__version__ import ( @@ -200,6 +200,23 @@ async def redirect_packet_list(request): packet_id = request.match_info["packet_id"] raise web.HTTPFound(location=f"/node/{packet_id}") +# Generic static HTML route +@routes.get("/{page}") +async def serve_page(request): + page = request.match_info["page"] + + # default to index.html if no extension + if not page.endswith(".html"): + page = f"{page}.html" + + html_file = pathlib.Path(__file__).parent / "static" / page + if not html_file.exists(): + raise web.HTTPNotFound(text=f"Page '{page}' not found") + + content = html_file.read_text(encoding="utf-8") + return web.Response(text=content, content_type="text/html") + + @routes.get("/net") async def net(request): @@ -394,31 +411,6 @@ async def graph_traceroute(request): ) -''' -@routes.get("/stats") -async def stats(request): - try: - total_packets = await store.get_total_packet_count() - total_nodes = await store.get_total_node_count() - total_packets_seen = await store.get_total_packet_seen_count() - template = env.get_template("stats.html") - return web.Response( - text=template.render( - total_packets=total_packets, - total_nodes=total_nodes, - total_packets_seen=total_packets_seen, - ), - content_type="text/html", - ) - except Exception as e: - return web.Response( - text=f"An error occurred: {str(e)}", - status=500, - content_type="text/plain", - ) -''' - - async def run_server(): # Wait for database migrations to complete before starting web server logger.info("Checking database schema status...")