diff --git a/meshview/models.py b/meshview/models.py index be6992a..ab62e2e 100644 --- a/meshview/models.py +++ b/meshview/models.py @@ -17,6 +17,8 @@ class Node(Base): long_name: Mapped[str] short_name: Mapped[str] hw_model: Mapped[str] + last_lat: Mapped[int] = mapped_column(BigInteger, nullable=True) + last_long: Mapped[int] = mapped_column(BigInteger, nullable=True) class Packet(Base): diff --git a/meshview/store.py b/meshview/store.py index fe5d389..fc1dca0 100644 --- a/meshview/store.py +++ b/meshview/store.py @@ -87,6 +87,18 @@ async def process_envelope(topic, env): ) session.add(node) + if env.packet.decoded.portnum == PortNum.POSITION_APP: + position = decode_payload.decode_payload( + PortNum.POSITION_APP, env.packet.decoded.payload + ) + if position.latitude_i and position.longitude_i: + from_node_id = getattr(env.packet, 'from') + node = (await session.execute(select(Node).where(Node.node_id == from_node_id))).scalar_one_or_none() + if node: + node.last_lat = position.latitude_i + node.last_long = position.longitude_i + session.add(node) + await session.commit() if new_packet: await packet.awaitable_attrs.to_node @@ -129,7 +141,7 @@ async def get_packets(node_id=None, portnum=None): return result.scalars() -async def get_packets_from(node_id=None, portnum=None): +async def get_packets_from(node_id=None, portnum=None, limit=500): async with database.async_session() as session: q = select(Packet) @@ -139,7 +151,7 @@ async def get_packets_from(node_id=None, portnum=None): ) if portnum: q = q.where(Packet.portnum == portnum) - result = await session.execute(q.limit(500).order_by(Packet.import_time.desc())) + result = await session.execute(q.limit(limit).order_by(Packet.import_time.desc())) return result.scalars() diff --git a/meshview/templates/node.html b/meshview/templates/node.html index d73edc3..d44040d 100644 --- a/meshview/templates/node.html +++ b/meshview/templates/node.html @@ -77,6 +77,10 @@ }).addTo(map); L.polyline(trace).addTo(map); L.marker(trace[0]).addTo(map); + {% for n in neighbors %} + L.circleMarker({{n | tojson}}).addTo(map); + L.polyline([trace[0], {{n | tojson}}], {color: 'red'}).addTo(map); + {% endfor %} {% endif %} diff --git a/meshview/templates/packet.html b/meshview/templates/packet.html index e20c0df..ede0b53 100644 --- a/meshview/templates/packet.html +++ b/meshview/templates/packet.html @@ -44,7 +44,6 @@
{{packet.payload}}
-

diff --git a/meshview/web.py b/meshview/web.py index d2c3103..04b513b 100644 --- a/meshview/web.py +++ b/meshview/web.py @@ -35,6 +35,23 @@ async def build_trace(node_id): return trace +async def build_neighbors(node_id): + packet = (await store.get_packets_from(node_id, PortNum.NEIGHBORINFO_APP, 1)).first() + if not packet: + return [] + _, payload = decode_payload.decode(packet) + neighbors = [] + async with asyncio.TaskGroup() as tg: + for n in payload.neighbors: + neighbors.append(tg.create_task(store.get_node(n.node_id))) + + result = [] + for node in [n.result() for n in neighbors]: + if node.last_lat and node.last_long: + result.append((node.last_lat * 1e-7, node.last_long * 1e-7)) + return result + + def node_id_to_hex(node_id): if node_id == 4294967295: return "^all" @@ -176,6 +193,7 @@ async def node_search(request): node_task = tg.create_task(store.get_node(node_id)) packets_task = tg.create_task(store.get_packets(node_id, portnum=portnum)) trace_task = tg.create_task(build_trace(node_id)) + neighbors_task = tg.create_task(build_neighbors(node_id)) else: loop = asyncio.get_running_loop() node_task = loop.create_future() @@ -184,6 +202,8 @@ async def node_search(request): packets_task.set_result(()) trace_task = loop.create_future() trace_task.set_result([]) + neighbors_task = loop.create_future() + neighbors_task.set_result([]) node_options_task = tg.create_task(store.get_fuzzy_nodes(raw_node_id)) @@ -201,6 +221,7 @@ async def node_search(request): node_options=options, portnum=portnum, trace=trace_task.result(), + neighbors=neighbors_task.result(), ), content_type="text/html", )