From 58244bff0953a0dcc6f436508f25d4ae042334ae Mon Sep 17 00:00:00 2001 From: Pablo Revilla Date: Wed, 22 Oct 2025 08:54:18 -0700 Subject: [PATCH] worked on making map and base all API driven --- meshview/templates/firehose.html | 334 ++++++++++++++++++++++++------- meshview/web.py | 23 ++- 2 files changed, 277 insertions(+), 80 deletions(-) diff --git a/meshview/templates/firehose.html b/meshview/templates/firehose.html index e2d637c..2266e9a 100644 --- a/meshview/templates/firehose.html +++ b/meshview/templates/firehose.html @@ -1,101 +1,297 @@ {% extends "base.html" %} {% block css %} - .container { - max-width: 900px; - margin: 0 auto; - } +.container { + max-width: 900px; + margin: 0 auto; + padding: 10px; +} +#pause-button { + white-space: nowrap; + padding: 4px 10px; + font-size: 0.9rem; + border-radius: 6px; +} - #pause-button { - white-space: nowrap; - padding: 2px 8px; - font-size: 0.85rem; - } +.packet-table { + width: 100%; + border-collapse: collapse; + font-size: 0.85rem; + color: #e4e9ee; +} +.packet-table th, .packet-table td { + border: 1px solid #3a3f44; + padding: 6px 10px; + text-align: left; +} +.packet-table th { + background-color: #1f2226; + font-weight: bold; +} +.packet-table tr:nth-of-type(odd) { background-color: #272b2f; } +.packet-table tr:nth-of-type(even) { background-color: #212529; } +.port-tag { + display: inline-block; + padding: 1px 6px; + border-radius: 6px; + font-size: 0.75rem; + font-weight: 500; + color: #fff; +} + +/* --- Color-coded port labels --- */ +.port-0 { background-color: #6c757d; } +.port-1 { background-color: #007bff; } +.port-3 { background-color: #28a745; } +.port-4 { background-color: #ffc107; color: #000; } +.port-5 { background-color: #dc3545; } +.port-6 { background-color: #20c997; } +.port-65 { background-color: #ff66b3; } +.port-67 { background-color: #17a2b8; } +.port-70 { background-color: #6f42c1; } +.port-71 { background-color: #fd7e14; } + +.to-mqtt { + font-style: italic; + color: #aaa; +} + +/* --- Payload rows --- */ +.payload-row { + display: none; + background-color: #1b1e22; +} +.payload-cell { + padding: 8px 12px; + font-family: monospace; + white-space: pre-wrap; + color: #b0bec5; + border-top: none; +} +.packet-table tr.expanded + .payload-row { + display: table-row; +} +.toggle-btn { + cursor: pointer; + color: #aaa; + margin-right: 6px; + font-weight: bold; +} +.toggle-btn:hover { + color: #fff; +} {% endblock %} {% block body %}
-
- {% set options = { - 1: "Text Message", - 3: "Position", - 4: "Node Info", - 67: "Telemetry", - 71: "Neighbor Info", - 70: "Trace Route", - } - %} + +
📡 Live Feed
-
-
- {% for packet in packets %} - {% include 'packet.html' %} - {% else %} - No packets found. - {% endfor %} -
-
+ + + + + + + + + + + +
IDFromToPortLinks
- {% endblock %} diff --git a/meshview/web.py b/meshview/web.py index 67dc249..0b24c97 100644 --- a/meshview/web.py +++ b/meshview/web.py @@ -1550,6 +1550,7 @@ async def api_nodes(request): return web.json_response({"error": "Failed to fetch nodes"}, status=500) + @routes.get("/api/packets") async def api_packets(request): try: @@ -1558,29 +1559,29 @@ async def api_packets(request): since_str = request.query.get("since") since_time = None - # Parse 'since' timestamp if provided if since_str: try: - since_time = datetime.datetime.fromisoformat(since_str) + # Robust ISO 8601 parsing (handles 'Z' for UTC) + since_time = datetime.datetime.fromisoformat(since_str.replace("Z", "+00:00")) except Exception as e: logger.error(f"Failed to parse 'since' timestamp '{since_str}': {e}") - # Fetch last N packets + # Fetch packets from the store packets = await store.get_packets(limit=limit, after=since_time) packets = [Packet.from_model(p) for p in packets] - # Build JSON response (no raw_payload) - packets_json = [ - { + packets_json = [] + for p in packets: + payload = (p.payload or "").strip() + + packets_json.append({ "id": p.id, "from_node_id": p.from_node_id, "to_node_id": p.to_node_id, - "portnum": int(p.portnum), + "portnum": int(p.portnum) if p.portnum is not None else None, "import_time": p.import_time.isoformat(), - "payload": p.payload, - } - for p in packets - ] + "payload": payload, + }) return web.json_response({"packets": packets_json})