mirror of
https://github.com/pablorevilla-meshtastic/meshview.git
synced 2026-03-04 23:27:46 +01:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b19b51d6a6 | ||
|
|
414beaaab0 |
@@ -3,7 +3,7 @@ from datetime import datetime
|
|||||||
from sqlalchemy.orm import DeclarativeBase, foreign
|
from sqlalchemy.orm import DeclarativeBase, foreign
|
||||||
from sqlalchemy.ext.asyncio import AsyncAttrs
|
from sqlalchemy.ext.asyncio import AsyncAttrs
|
||||||
from sqlalchemy.orm import mapped_column, relationship, Mapped
|
from sqlalchemy.orm import mapped_column, relationship, Mapped
|
||||||
from sqlalchemy import ForeignKey, BigInteger
|
from sqlalchemy import ForeignKey, BigInteger, DateTime
|
||||||
|
|
||||||
|
|
||||||
class Base(AsyncAttrs, DeclarativeBase):
|
class Base(AsyncAttrs, DeclarativeBase):
|
||||||
@@ -23,7 +23,8 @@ class Node(Base):
|
|||||||
|
|
||||||
class Packet(Base):
|
class Packet(Base):
|
||||||
__tablename__ = "packet"
|
__tablename__ = "packet"
|
||||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
|
pk: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger)
|
||||||
portnum: Mapped[int]
|
portnum: Mapped[int]
|
||||||
from_node_id: Mapped[int] = mapped_column(BigInteger)
|
from_node_id: Mapped[int] = mapped_column(BigInteger)
|
||||||
from_node: Mapped["Node"] = relationship(
|
from_node: Mapped["Node"] = relationship(
|
||||||
@@ -34,17 +35,18 @@ class Packet(Base):
|
|||||||
primaryjoin="Packet.to_node_id == foreign(Node.node_id)", lazy="joined"
|
primaryjoin="Packet.to_node_id == foreign(Node.node_id)", lazy="joined"
|
||||||
)
|
)
|
||||||
payload: Mapped[bytes]
|
payload: Mapped[bytes]
|
||||||
import_time: Mapped[datetime]
|
import_time = mapped_column(DateTime)
|
||||||
|
|
||||||
|
|
||||||
class PacketSeen(Base):
|
class PacketSeen(Base):
|
||||||
__tablename__ = "packet_seen"
|
__tablename__ = "packet_seen"
|
||||||
packet_id = mapped_column(ForeignKey("packet.id"), primary_key=True)
|
pk: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||||
node_id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
|
packet_id = mapped_column(ForeignKey("packet.id"))
|
||||||
|
node_id: Mapped[int] = mapped_column(BigInteger)
|
||||||
node: Mapped["Node"] = relationship(
|
node: Mapped["Node"] = relationship(
|
||||||
lazy="joined", primaryjoin="PacketSeen.node_id == foreign(Node.node_id)"
|
lazy="joined", primaryjoin="PacketSeen.node_id == foreign(Node.node_id)"
|
||||||
)
|
)
|
||||||
rx_time: Mapped[int] = mapped_column(BigInteger, primary_key=True)
|
rx_time: Mapped[int] = mapped_column(BigInteger)
|
||||||
hop_limit: Mapped[int]
|
hop_limit: Mapped[int]
|
||||||
channel: Mapped[str]
|
channel: Mapped[str]
|
||||||
rx_snr: Mapped[float] = mapped_column(nullable=True)
|
rx_snr: Mapped[float] = mapped_column(nullable=True)
|
||||||
@@ -60,4 +62,4 @@ class Traceroute(Base):
|
|||||||
gateway_node_id: Mapped[int] = mapped_column(BigInteger)
|
gateway_node_id: Mapped[int] = mapped_column(BigInteger)
|
||||||
done: Mapped[bool]
|
done: Mapped[bool]
|
||||||
route: Mapped[bytes]
|
route: Mapped[bytes]
|
||||||
|
import_time: Mapped[datetime]
|
||||||
|
|||||||
@@ -30,13 +30,14 @@ async def get_topic_envelopes(topics):
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
async with aiomqtt.Client(
|
async with aiomqtt.Client(
|
||||||
"mqtt.meshtastic.org", username="meshdev", password="large4cats"
|
"192.168.10.52"
|
||||||
) as client:
|
) as client:
|
||||||
for topic in topics:
|
for topic in topics:
|
||||||
await client.subscribe(topic)
|
await client.subscribe(topic)
|
||||||
async for msg in client.messages:
|
async for msg in client.messages:
|
||||||
try:
|
try:
|
||||||
envelope = ServiceEnvelope.FromString(msg.payload)
|
envelope = ServiceEnvelope.FromString(msg.payload)
|
||||||
|
print(envelope)
|
||||||
except DecodeError:
|
except DecodeError:
|
||||||
continue
|
continue
|
||||||
decrypt(envelope.packet)
|
decrypt(envelope.packet)
|
||||||
|
|||||||
@@ -17,40 +17,40 @@ async def process_envelope(topic, env):
|
|||||||
async with database.async_session() as session:
|
async with database.async_session() as session:
|
||||||
result = await session.execute(select(Packet).where(Packet.id == env.packet.id))
|
result = await session.execute(select(Packet).where(Packet.id == env.packet.id))
|
||||||
new_packet = False
|
new_packet = False
|
||||||
packet = result.scalar_one_or_none()
|
#packet = result.scalar_one_or_none()
|
||||||
if not packet:
|
#if not packet:
|
||||||
new_packet = True
|
new_packet = True
|
||||||
packet = Packet(
|
packet = Packet(
|
||||||
id=env.packet.id,
|
id=env.packet.id,
|
||||||
portnum=env.packet.decoded.portnum,
|
portnum=env.packet.decoded.portnum,
|
||||||
from_node_id=getattr(env.packet, "from"),
|
from_node_id=getattr(env.packet, "from"),
|
||||||
to_node_id=env.packet.to,
|
to_node_id=env.packet.to,
|
||||||
payload=env.packet.SerializeToString(),
|
payload=env.packet.SerializeToString(),
|
||||||
import_time=datetime.datetime.utcnow(),
|
import_time=datetime.datetime.utcnow(),
|
||||||
)
|
|
||||||
session.add(packet)
|
|
||||||
|
|
||||||
result = await session.execute(
|
|
||||||
select(PacketSeen).where(
|
|
||||||
PacketSeen.packet_id == env.packet.id,
|
|
||||||
PacketSeen.node_id == int(env.gateway_id[1:], 16),
|
|
||||||
PacketSeen.rx_time == env.packet.rx_time,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
seen = None
|
session.add(packet)
|
||||||
if not result.scalar_one_or_none():
|
|
||||||
seen = PacketSeen(
|
#result = await session.execute(
|
||||||
packet_id=env.packet.id,
|
# select(PacketSeen).where(
|
||||||
node_id=int(env.gateway_id[1:], 16),
|
# PacketSeen.packet_id == env.packet.id,
|
||||||
channel=env.channel_id,
|
# PacketSeen.node_id == int(env.gateway_id[1:], 16),
|
||||||
rx_time=env.packet.rx_time,
|
# PacketSeen.rx_time == env.packet.rx_time,
|
||||||
rx_snr=env.packet.rx_snr,
|
# )
|
||||||
rx_rssi=env.packet.rx_rssi,
|
#)
|
||||||
hop_limit=env.packet.hop_limit,
|
#seen = None
|
||||||
topic=topic,
|
#if not result.scalar_one_or_none():
|
||||||
import_time=datetime.datetime.utcnow(),
|
seen = PacketSeen(
|
||||||
)
|
packet_id=env.packet.id,
|
||||||
session.add(seen)
|
node_id=int(env.gateway_id[1:], 16),
|
||||||
|
channel=env.channel_id,
|
||||||
|
rx_time=env.packet.rx_time,
|
||||||
|
rx_snr=env.packet.rx_snr,
|
||||||
|
rx_rssi=env.packet.rx_rssi,
|
||||||
|
hop_limit=env.packet.hop_limit,
|
||||||
|
topic=topic,
|
||||||
|
import_time=datetime.datetime.utcnow(),
|
||||||
|
)
|
||||||
|
session.add(seen)
|
||||||
|
|
||||||
if env.packet.decoded.portnum == PortNum.NODEINFO_APP:
|
if env.packet.decoded.portnum == PortNum.NODEINFO_APP:
|
||||||
user = decode_payload.decode_payload(
|
user = decode_payload.decode_payload(
|
||||||
@@ -109,6 +109,7 @@ async def process_envelope(topic, env):
|
|||||||
route=env.packet.decoded.payload,
|
route=env.packet.decoded.payload,
|
||||||
done=not env.packet.decoded.want_response,
|
done=not env.packet.decoded.want_response,
|
||||||
gateway_node_id=int(env.gateway_id[1:], 16),
|
gateway_node_id=int(env.gateway_id[1:], 16),
|
||||||
|
import_time=datetime.datetime.utcnow(),
|
||||||
))
|
))
|
||||||
|
|
||||||
await session.commit()
|
await session.commit()
|
||||||
@@ -169,7 +170,7 @@ async def get_packets_from(node_id=None, portnum=None, limit=500):
|
|||||||
|
|
||||||
async def get_packet(packet_id):
|
async def get_packet(packet_id):
|
||||||
async with database.async_session() as session:
|
async with database.async_session() as session:
|
||||||
q = select(Packet).where(Packet.id == packet_id)
|
q = select(Packet).where(Packet.id == packet_id).limit(1)
|
||||||
result = await session.execute(q)
|
result = await session.execute(q)
|
||||||
return result.scalar_one_or_none()
|
return result.scalar_one_or_none()
|
||||||
|
|
||||||
@@ -207,5 +208,6 @@ async def get_traceroute(packet_id):
|
|||||||
result = await session.execute(
|
result = await session.execute(
|
||||||
select(Traceroute)
|
select(Traceroute)
|
||||||
.where(Traceroute.packet_id == packet_id)
|
.where(Traceroute.packet_id == packet_id)
|
||||||
|
.order_by(Traceroute.import_time)
|
||||||
)
|
)
|
||||||
return result.scalars()
|
return result.scalars()
|
||||||
|
|||||||
@@ -557,6 +557,7 @@ async def graph_traceroute(request):
|
|||||||
mqtt_nodes = set()
|
mqtt_nodes = set()
|
||||||
saw_reply = set()
|
saw_reply = set()
|
||||||
dest = None
|
dest = None
|
||||||
|
node_seen_time = {}
|
||||||
for tr in traceroutes:
|
for tr in traceroutes:
|
||||||
if tr.done:
|
if tr.done:
|
||||||
saw_reply.add(tr.gateway_node_id)
|
saw_reply.add(tr.gateway_node_id)
|
||||||
@@ -571,6 +572,13 @@ async def graph_traceroute(request):
|
|||||||
elif path[-1] != tr.gateway_node_id:
|
elif path[-1] != tr.gateway_node_id:
|
||||||
# It seems some nodes add them self to the list before uplinking
|
# It seems some nodes add them self to the list before uplinking
|
||||||
path.append(tr.gateway_node_id)
|
path.append(tr.gateway_node_id)
|
||||||
|
|
||||||
|
if not tr.done:
|
||||||
|
for node_id in path[-2:]:
|
||||||
|
if node_id not in node_seen_time:
|
||||||
|
if tr.import_time:
|
||||||
|
node_seen_time[node_id] = tr.import_time
|
||||||
|
|
||||||
mqtt_nodes.add(tr.gateway_node_id)
|
mqtt_nodes.add(tr.gateway_node_id)
|
||||||
node_color[path[-1]] = '#' + hex(hash(tuple(path)))[3:9]
|
node_color[path[-1]] = '#' + hex(hash(tuple(path)))[3:9]
|
||||||
paths.add(tuple(path))
|
paths.add(tuple(path))
|
||||||
@@ -579,12 +587,21 @@ async def graph_traceroute(request):
|
|||||||
for path in paths:
|
for path in paths:
|
||||||
used_nodes.update(path)
|
used_nodes.update(path)
|
||||||
|
|
||||||
|
import_times = [tr.import_time for tr in traceroutes if tr.import_time]
|
||||||
|
if import_times:
|
||||||
|
first_time = min(import_times)
|
||||||
|
else:
|
||||||
|
first_time = 0
|
||||||
|
|
||||||
for node_id in used_nodes:
|
for node_id in used_nodes:
|
||||||
node = await nodes[node_id]
|
node = await nodes[node_id]
|
||||||
if not node:
|
if not node:
|
||||||
node_name = node_id_to_hex(node_id)
|
node_name = node_id_to_hex(node_id)
|
||||||
else:
|
else:
|
||||||
node_name = f'[{node.short_name}] {node.long_name} - {node_id_to_hex(node_id)}'
|
node_name = f'[{node.short_name}] {node.long_name} - {node_id_to_hex(node_id)}'
|
||||||
|
if node_id in node_seen_time:
|
||||||
|
ms = (node_seen_time[node_id] - first_time).total_seconds() * 1000
|
||||||
|
node_name += f'\n {ms:.2f}ms'
|
||||||
style = 'dashed'
|
style = 'dashed'
|
||||||
if node_id == dest:
|
if node_id == dest:
|
||||||
style = 'filled'
|
style = 'filled'
|
||||||
|
|||||||
Reference in New Issue
Block a user