collect rssi, snr and link quality for announces and add snr to announces ui

This commit is contained in:
liamcottle 2024-12-23 03:36:01 +13:00
commit 5a1bd889b7
4 changed files with 52 additions and 13 deletions

View file

@ -3,7 +3,7 @@ from datetime import datetime, timezone
from peewee import *
from playhouse.migrate import migrate as migrate_database, SqliteMigrator
latest_version = 4 # increment each time new database migrations are added
latest_version = 5 # increment each time new database migrations are added
database = DatabaseProxy() # use a proxy object, as we will init real db client inside meshchat.py
migrator = SqliteMigrator(database)
@ -32,6 +32,14 @@ def migrate(current_version):
migrator.add_column("lxmf_messages", 'method', LxmfMessage.method),
)
# migrate to version 5
if current_version < 5:
migrate_database(
migrator.add_column("announces", 'rssi', Announce.rssi),
migrator.add_column("announces", 'snr', Announce.snr),
migrator.add_column("announces", 'quality', Announce.quality),
)
return latest_version
@ -61,6 +69,9 @@ class Announce(BaseModel):
identity_hash = CharField(index=True) # identity hash that announced the destination
identity_public_key = CharField() # base64 encoded public key, incase we want to recreate the identity manually
app_data = TextField(null=True) # base64 encoded app data bytes
rssi = IntegerField(null=True)
snr = FloatField(null=True)
quality = FloatField(null=True)
created_at = DateTimeField(default=lambda: datetime.now(timezone.utc))
updated_at = DateTimeField(default=lambda: datetime.now(timezone.utc))

View file

@ -2019,6 +2019,9 @@ class ReticulumMeshChat:
"background_colour": db_lxmf_user_icon.background_colour,
}
# get current hops away
hops = RNS.Transport.hops_to(bytes.fromhex(announce.destination_hash))
return {
"id": announce.id,
"destination_hash": announce.destination_hash,
@ -2026,6 +2029,10 @@ class ReticulumMeshChat:
"identity_hash": announce.identity_hash,
"identity_public_key": announce.identity_public_key,
"app_data": announce.app_data,
"hops": hops,
"rssi": announce.rssi,
"snr": announce.snr,
"quality": announce.quality,
"display_name": display_name,
"custom_display_name": self.get_custom_destination_display_name(announce.destination_hash),
"lxmf_user_icon": lxmf_user_icon,
@ -2186,7 +2193,12 @@ class ReticulumMeshChat:
query.execute()
# upserts the provided announce to the database
def db_upsert_announce(self, identity: RNS.Identity, destination_hash: bytes, aspect: str, app_data: bytes):
def db_upsert_announce(self, identity: RNS.Identity, destination_hash: bytes, aspect: str, app_data: bytes, announce_packet_hash: bytes):
# get rssi, snr and signal quality if available
rssi = self.reticulum.get_packet_rssi(announce_packet_hash)
snr = self.reticulum.get_packet_snr(announce_packet_hash)
quality = self.reticulum.get_packet_q(announce_packet_hash)
# prepare data to insert or update
data = {
@ -2194,6 +2206,9 @@ class ReticulumMeshChat:
"aspect": aspect,
"identity_hash": identity.hash.hex(),
"identity_public_key": base64.b64encode(identity.get_public_key()).decode("utf-8"),
"rssi": rssi,
"snr": snr,
"quality": quality,
"updated_at": datetime.now(timezone.utc),
}
@ -2377,13 +2392,13 @@ class ReticulumMeshChat:
# handle an announce received from reticulum, for an audio call address
# NOTE: cant be async, as Reticulum doesn't await it
def on_audio_call_announce_received(self, aspect, destination_hash, announced_identity, app_data):
def on_audio_call_announce_received(self, aspect, destination_hash, announced_identity, app_data, announce_packet_hash):
# log received announce
print("Received an announce from " + RNS.prettyhexrep(destination_hash) + " for [call.audio]")
# upsert announce to database
self.db_upsert_announce(announced_identity, destination_hash, aspect, app_data)
self.db_upsert_announce(announced_identity, destination_hash, aspect, app_data, announce_packet_hash)
# find announce from database
announce = database.Announce.get_or_none(database.Announce.destination_hash == destination_hash.hex())
@ -2398,13 +2413,13 @@ class ReticulumMeshChat:
# handle an announce received from reticulum, for an lxmf address
# NOTE: cant be async, as Reticulum doesn't await it
def on_lxmf_announce_received(self, aspect, destination_hash, announced_identity, app_data):
def on_lxmf_announce_received(self, aspect, destination_hash, announced_identity, app_data, announce_packet_hash):
# log received announce
print("Received an announce from " + RNS.prettyhexrep(destination_hash) + " for [lxmf.delivery]")
# upsert announce to database
self.db_upsert_announce(announced_identity, destination_hash, aspect, app_data)
self.db_upsert_announce(announced_identity, destination_hash, aspect, app_data, announce_packet_hash)
# find announce from database
announce = database.Announce.get_or_none(database.Announce.destination_hash == destination_hash.hex())
@ -2423,13 +2438,13 @@ class ReticulumMeshChat:
# handle an announce received from reticulum, for an lxmf propagation node address
# NOTE: cant be async, as Reticulum doesn't await it
def on_lxmf_propagation_announce_received(self, aspect, destination_hash, announced_identity, app_data):
def on_lxmf_propagation_announce_received(self, aspect, destination_hash, announced_identity, app_data, announce_packet_hash):
# log received announce
print("Received an announce from " + RNS.prettyhexrep(destination_hash) + " for [lxmf.propagation]")
# upsert announce to database
self.db_upsert_announce(announced_identity, destination_hash, aspect, app_data)
self.db_upsert_announce(announced_identity, destination_hash, aspect, app_data, announce_packet_hash)
# find announce from database
announce = database.Announce.get_or_none(database.Announce.destination_hash == destination_hash.hex())
@ -2507,13 +2522,13 @@ class ReticulumMeshChat:
# handle an announce received from reticulum, for a nomadnet node
# NOTE: cant be async, as Reticulum doesn't await it
def on_nomadnet_node_announce_received(self, aspect, destination_hash, announced_identity, app_data):
def on_nomadnet_node_announce_received(self, aspect, destination_hash, announced_identity, app_data, announce_packet_hash):
# log received announce
print("Received an announce from " + RNS.prettyhexrep(destination_hash) + " for [nomadnetwork.node]")
# upsert announce to database
self.db_upsert_announce(announced_identity, destination_hash, aspect, app_data)
self.db_upsert_announce(announced_identity, destination_hash, aspect, app_data, announce_packet_hash)
# find announce from database
announce = database.Announce.get_or_none(database.Announce.destination_hash == destination_hash.hex())

View file

@ -7,10 +7,10 @@ class AnnounceHandler:
self.received_announce_callback = received_announce_callback
# we will just pass the received announce back to the provided callback
def received_announce(self, destination_hash, announced_identity, app_data):
def received_announce(self, destination_hash, announced_identity, app_data, announce_packet_hash):
try:
# handle received announce
self.received_announce_callback(self.aspect_filter, destination_hash, announced_identity, app_data)
self.received_announce_callback(self.aspect_filter, destination_hash, announced_identity, app_data, announce_packet_hash)
except:
# ignore failure to handle received announce
pass

View file

@ -90,7 +90,20 @@
</div>
<div>
<div class="text-gray-900 dark:text-gray-100">{{ peer.custom_display_name ?? peer.display_name }}</div>
<div class="text-gray-500 dark:text-gray-400 text-sm">{{ formatTimeAgo(peer.updated_at) }}</div>
<div class="flex space-x-1 text-gray-500 dark:text-gray-400 text-sm">
<!-- time ago -->
<span class="flex my-auto space-x-1">
{{ formatTimeAgo(peer.updated_at) }}
</span>
<!-- snr (only shown for peers directly heard on rf) -->
<span v-if="peer.snr != null && (peer.hops === 0 || peer.hops === 1)" class="flex my-auto space-x-1">
<span></span>
<span>SNR {{ peer.snr }}dB</span>
</span>
</div>
</div>
</div>
</div>