diff --git a/meshview/templates/node.html b/meshview/templates/node.html
index 046dfa1..7d0389a 100644
--- a/meshview/templates/node.html
+++ b/meshview/templates/node.html
@@ -51,7 +51,7 @@
{% endif %}
{% if neighbors %}
-
+
{% endif %}
{% else %}
diff --git a/meshview/web.py b/meshview/web.py
index bd9a19b..eea0042 100644
--- a/meshview/web.py
+++ b/meshview/web.py
@@ -10,6 +10,7 @@ import re
import pydot
from pandas import DataFrame
+import plotly.express as px
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
@@ -529,6 +530,48 @@ async def graph_neighbors(request):
content_type="image/png",
)
+@routes.get("/graph/neighbors2/{node_id}")
+async def graph_neighbors2(request):
+ oldest = datetime.datetime.utcnow() - datetime.timedelta(days=30)
+
+ data = []
+ node_ids = set()
+ for p in await store.get_packets_from(int(request.match_info['node_id']), PortNum.NEIGHBORINFO_APP):
+ _, payload = decode_payload.decode(p)
+ if not payload:
+ continue
+ if p.import_time < oldest:
+ break
+
+ for n in payload.neighbors:
+ node_ids.add(n.node_id)
+ data.append({
+ 'time': p.import_time,
+ 'snr': n.snr,
+ 'node_id': n.node_id,
+ })
+
+ nodes = {}
+ async with asyncio.TaskGroup() as tg:
+ for node_id in node_ids:
+ nodes[node_id] = tg.create_task(store.get_node(node_id))
+
+ for d in data:
+ node = await nodes[d['node_id']]
+ if node:
+ d['node_name'] = node.short_name
+ else:
+ d['node_name'] = node_id_to_hex(node_id)
+
+ df = DataFrame(data)
+ print(df, flush=True)
+ fig = px.line(df, x="time", y="snr", color="node_name", markers=True)
+ html = fig.to_html(full_html=True, include_plotlyjs='cdn')
+ return web.Response(
+ text=html,
+ content_type="text/html",
+ )
+
@routes.get("/graph/traceroute/{packet_id}")
async def graph_traceroute(request):
diff --git a/requirements.txt b/requirements.txt
index f6f308a..e064e6a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -10,3 +10,4 @@ aiohttp-sse
asyncpg
seaborn
pydot
+plotly