From a54c2d7020400bbd6a86a1099fa527ddf0b04f74 Mon Sep 17 00:00:00 2001
From: Volkor <me@volkor.me>
Date: Sun, 2 Feb 2025 01:39:03 +1100
Subject: [PATCH] better ui, meshpacket logging

Although I might want to redo some meshpackets into their own tables (for stuff like telemetry and such)
---
 Cargo.lock                     |  81 +++++++++++++--
 Cargo.toml                     |   6 +-
 README.md                      |   4 +
 config.toml                    |   8 +-
 db/migrations/0001_initial.sql |  29 ++++++
 src/config.rs                  |  18 +++-
 src/db.rs                      | 173 ++++++++++++++++++++++++++++++++-
 src/gui.rs                     | 118 +++++++++++++++++++---
 src/packets.rs                 |  26 +++--
 yamm.db                        | Bin 139264 -> 176128 bytes
 10 files changed, 427 insertions(+), 36 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 9dcb688..4fa3848 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -186,6 +186,12 @@ version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
 
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
 [[package]]
 name = "android_system_properties"
 version = "0.1.5"
@@ -832,6 +838,29 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "chrono"
+version = "0.4.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "js-sys",
+ "num-traits",
+ "wasm-bindgen",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "chrono-humanize"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "799627e6b4d27827a814e837b9d8a504832086081806d45b1afa34dc982b023b"
+dependencies = [
+ "chrono",
+]
+
 [[package]]
 name = "clipboard-win"
 version = "5.4.0"
@@ -2026,12 +2055,6 @@ version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
 
-[[package]]
-name = "humantime"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
-
 [[package]]
 name = "hyper"
 version = "0.14.32"
@@ -2070,6 +2093,29 @@ dependencies = [
  "tokio-rustls",
 ]
 
+[[package]]
+name = "iana-time-zone"
+version = "0.1.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows-core 0.52.0",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
 [[package]]
 name = "icu_collections"
 version = "1.5.0"
@@ -2550,6 +2596,16 @@ version = "0.4.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 
+[[package]]
+name = "longitude"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "287771e9700a56b8ee1c12188e67e551daf66980b9fde697e9551d74db19cc0e"
+dependencies = [
+ "lazy_static",
+ "libm",
+]
+
 [[package]]
 name = "loop9"
 version = "0.1.5"
@@ -5493,6 +5549,15 @@ dependencies = [
  "windows-targets 0.53.0",
 ]
 
+[[package]]
+name = "windows-core"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
 [[package]]
 name = "windows-core"
 version = "0.57.0"
@@ -6094,15 +6159,17 @@ name = "yamm"
 version = "0.1.0"
 dependencies = [
  "bincode",
+ "chrono",
+ "chrono-humanize",
  "eframe",
  "egui",
  "egui_extras",
  "fern",
  "figment",
- "humantime",
  "image",
  "lazy_static",
  "log",
+ "longitude",
  "meshtastic",
  "rusqlite",
  "rusqlite_migration",
diff --git a/Cargo.toml b/Cargo.toml
index 185eca2..54b538c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,7 +5,6 @@ edition = "2021"
 
 [dependencies]
 fern = "0.7.1"
-humantime = "2.1.0"
 log = "0.4.22"
 meshtastic = "0.1.6"
 tokio = "1.42.0"
@@ -17,10 +16,13 @@ lazy_static = "1.5.0"
 figment =  {version = "0.10.19", features = ["toml", "env"]}
 serde = "1.0.217"
 bincode = "1.3.3"
+chrono-humanize = "0.2.3"
 
 # gui
 eframe = { version = "0.30.0", features = ["wgpu"] }
 egui = "0.30.0"
 walkers = "0.33.0"
 egui_extras = { version = "0.30.0", features = ["all_loaders"] }
-image = { version = "0.25", features = ["jpeg", "png", "webp"] }
\ No newline at end of file
+image = { version = "0.25", features = ["jpeg", "png", "webp"] }
+chrono = "0.4.39"
+longitude = "0.2.1"
diff --git a/README.md b/README.md
index e59b673..5faa14c 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,9 @@ Rough order of how much I want to add support.
 
 - [ ] Shows Historical Data as a nice graph
   - [ ] SNR (both individual neighbours and overall)
+    - RSSI is done per packet, instead of in nodeinfo. this seems... clunky.
+    - We're gonna have to log packets coming directly from neighbours, and store the rssi. it seems like that might be the only way to actually get neighbours?
+    - potentially show helpful guides on why each node is bad quality. (https://sensing-labs.com/f-a-q/a-good-radio-level/) ?
   - [ ] Messages per day?
   - [ ] Number of Nodes seen
   - [ ] Channel Util
@@ -41,6 +44,7 @@ Rough order of how much I want to add support.
   - [ ] Can we show the potential nodes that don't have GPS?
   - [ ] Can we use heard traceroutes to map out neighbours in the mesh?
     - Can we send out some traceroutes every few hours to map it if we don't? (some people don't like meshsense for this reason)
+- [ ] calculate distance to 'collector node'
 - [ ] Generates a nice public dashboard (static http, once every hour?)
 - Supports anything other than TCP Connection.
   - [ ] Bluetooth (how? wtf? i hate bluetooth!)
diff --git a/config.toml b/config.toml
index 5f3fd30..f9a5b73 100644
--- a/config.toml
+++ b/config.toml
@@ -17,4 +17,10 @@ serial_port = "Set this from whatever 'available ports' says."
 
 ## If connection_type is TCP or MQTT, use this ip & port combo to connect
 ip = "192.168.1.11"
-port = 4403
\ No newline at end of file
+port = 4403
+
+
+[gui]
+# Should we show units in metric, or idiot american?
+# Supported: Centimeters, Meters, Kilometers, Inches, Feet, Yards, Miles,
+units = "Kilometers"
\ No newline at end of file
diff --git a/db/migrations/0001_initial.sql b/db/migrations/0001_initial.sql
index 468616b..cb045e8 100644
--- a/db/migrations/0001_initial.sql
+++ b/db/migrations/0001_initial.sql
@@ -342,4 +342,33 @@ CREATE TABLE DetectionSensorConfig (
 CREATE TABLE PaxcounterConfig (
     enabled INTEGER,
     paxcounter_update_interval INTEGER
+);
+
+-- MeshPacket tables
+-- This table stores every single MeshPacket sent over the radio.
+-- Since this can contain a Payload_variant, we need to handle all of the following types
+-- https://docs.rs/meshtastic/latest/meshtastic/protobufs/enum.PortNum.html
+CREATE TABLE MeshPacket (
+    primary_id INTEGER PRIMARY KEY AUTOINCREMENT,   -- internal db packet number
+    packet_from INTEGER,                            -- sending node number
+    packet_to INTEGER,                              -- the (immediate) destination
+    channel INTEGER,                                -- what channel was this sent on, however it's a device specific set
+    id INTEGER,                                     -- 'unique' id for the packet, only unique per sender, and for ~10 mins
+    rx_time INTEGER,                                -- unixtime packet was received, not sent over radio
+    rx_snr INTEGER,                                 -- radio quality @ time of rx, not sent over radio
+    hop_limt INTEGER,                               -- n hops allowed, 0 is direct neighbours only
+    want_ack INTEGER,                               -- does the sender want ack on arrival of destination?
+    priority INTEGER,                               -- how important it is in the network
+    rx_rssi INTEGER,                                -- rssi of packet, not sent over radio
+    via_mqtt INTEGER,                               -- did it pass over mqtt at any point?
+    hop_start INTEGER,                              -- what was the hop limit at tx?
+    pv_status INTEGER,                              -- NULL = No payload, 1 = decoded, 2 = encrypted
+    pv_portnum INTEGER,                             -- what type of data we're sending
+    pv_data BLOB,                                   -- the data we're sending.
+    pv_want_response INTEGER,                       -- ask the reipient to respond
+    pv_dest INTEGER,                                -- the addr of the destination
+    pv_source INTEGER,                              -- the original sender node, only used for reliable multihop pkt
+    pv_request_id INTEGER,                          -- used for routing or responses, original msg id
+    pv_reply_id INTEGER,                            -- is the payload a reply to a previous message?
+    pv_emoji INTEGER                                -- is the payload an emoji?
 );
\ No newline at end of file
diff --git a/src/config.rs b/src/config.rs
index 5edec01..1ec1691 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,3 +1,4 @@
+use longitude::DistanceUnit;
 use serde::Deserialize;
 
 /// Holds the individual config segments.
@@ -7,6 +8,7 @@ pub struct AppConfig {
     pub database: DatabaseConfig,
     pub logging: LoggingConfig,
     pub meshconfig: MeshConfig,
+    pub gui: GuiConfig,
 }
 
 #[derive(Debug, Clone, Deserialize)]
@@ -46,6 +48,12 @@ pub enum ConnectionType {
 }
 
 
+/// Holds the config for the GUI
+#[derive(Debug, Clone, Deserialize)]
+pub struct GuiConfig {
+    pub units: String
+}
+
 // Defaults
 
 impl Default for ServerConfig {
@@ -82,4 +90,12 @@ impl Default for MeshConfig {
             port: 4403,
         }
     }
-}
\ No newline at end of file
+}
+
+impl Default for GuiConfig {
+    fn default() -> Self {
+        Self {
+            units: "Kilometers".to_string()
+        }
+    }
+}
diff --git a/src/db.rs b/src/db.rs
index 4851ec0..0acdbed 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -9,7 +9,7 @@ use rusqlite_migration::{Migrations, M};
 use serde::{Deserialize, Serialize};
 use tracing::{debug, error, info};
 use lazy_static::lazy_static;
-use meshtastic::protobufs::{Channel, DeviceMetrics, MyNodeInfo, NodeInfo, Position, User};
+use meshtastic::protobufs::{Channel, Data, DeviceMetrics, MeshPacket, MyNodeInfo, NodeInfo, Position, User};
 
 use crate::CONFIG;
 
@@ -828,4 +828,175 @@ impl Database {
         nodes
     }
 
+    pub fn read_home_node() -> Result<NodeInfo, rusqlite::Error> {
+        let db = Database::open().expect("Failure to open database for reading");
+
+        let mut stmt = db.conn.prepare("SELECT num, user_id, user_lname, user_sname, 
+                                        hw_model, is_licensed, role, battery_level, 
+                                        voltage, latitude_i, longitude_i, altitude, 
+                                        location_source, gps_timestamp, altitude_source, 
+                                        pdop, hdop, vdop, gps_accuracy, ground_speed, 
+                                        ground_track, fix_quality, fix_type, sats_in_view, 
+                                        sensor_id, next_update, seq_number, precision_bits, 
+                                        snr, last_heard, channel_utilization, air_util_tx, 
+                                        channel, via_mqtt, hops_away 
+                                        FROM Node
+                                        WHERE num = (SELECT my_node_num FROM MyNodeInfo)")?;
+
+        
+
+        // If needed, handle the result using pattern matching or further processing
+        stmt.query_row([], |row| {
+            Ok(NodeInfo {
+                num: row.get(0)?,
+                user: Some(User {
+                    id: row.get(1).unwrap_or("NULL".to_owned()),
+                    long_name: row.get(2).unwrap_or("NULL".to_owned()),
+                    short_name: row.get(3).unwrap_or("NULL".to_owned()),
+                    macaddr: vec![],
+                    hw_model: row.get(4).unwrap_or_default(),
+                    is_licensed: row.get(5).unwrap_or(false),
+                    role: row.get(6).unwrap_or_default(),
+                }),
+                position: Some(Position {
+                    latitude_i: row.get(9).unwrap_or(0),
+                    longitude_i: row.get(10).unwrap_or(0),
+                    altitude: row.get(11).unwrap_or(0),
+                    time: 0,
+                    location_source: row.get(12).unwrap_or_default(),
+                    altitude_source: row.get(14).unwrap_or_default(),
+                    timestamp: row.get(13).unwrap_or(0),
+                    timestamp_millis_adjust: 0,
+                    altitude_hae: 0,
+                    altitude_geoidal_separation: 0,
+                    pdop: row.get(15).unwrap_or(0),
+                    hdop: row.get(16).unwrap_or(0),
+                    vdop: row.get(17).unwrap_or(0),
+                    gps_accuracy: row.get(18).unwrap_or(0),
+                    ground_speed: row.get(19).unwrap_or(0),
+                    ground_track: row.get(20).unwrap_or(0),
+                    fix_quality: row.get(21).unwrap_or(0),
+                    fix_type: row.get(22).unwrap_or(0),
+                    sats_in_view: row.get(23).unwrap_or(0),
+                    sensor_id: row.get(24).unwrap_or(0),
+                    next_update: row.get(25).unwrap_or(0),
+                    seq_number: row.get(26).unwrap_or(0),
+                    precision_bits: row.get(27).unwrap_or(0),
+                }),
+                snr: row.get(28)?,
+                last_heard: row.get(29)?,
+                device_metrics: Some(DeviceMetrics {
+                    battery_level: row.get(7).unwrap_or(101),
+                    voltage: row.get(8).unwrap_or(0.0),
+                    channel_utilization: row.get(30).unwrap_or(0.0),
+                    air_util_tx: row.get(31).unwrap_or(0.0),
+                }),
+                channel: row.get(32)?,
+                via_mqtt: row.get(33)?,
+                hops_away: row.get(34)?,
+            })
+        })
+    }
+
+    /// Check for the existence of a MeshPacket with the same data
+    pub fn check_meshpacket_dupe(pv_data: &Option<Vec<u8>>) -> Result<bool> {
+        let db = Database::open().expect("Failure to open database");
+        let mut stmt = db.conn.prepare("SELECT COUNT(1)
+                                        FROM MeshPacket
+                                        WHERE data = ?1")?;
+        let exists = stmt.query_row([&pv_data], |row| row.get::<_, i64>(0))? > 0;
+        Ok(exists)
+    }
+
+    /// Add a new meshpacket entry into the db.
+    pub fn add_meshpacket(packet: &MeshPacket) -> Result<bool> {
+        let db = Database::open().expect("Failure to open database");
+
+        // Initialise default pv's
+        let mut pv_status: Option<i32> = None;
+        let mut pv_portnum: Option<i32> = None;
+        let mut pv_data: Option<Vec<u8>> = None;
+        let mut pv_want_response: Option<bool> = None;
+        let mut pv_dest: Option<u32> = None;
+        let mut pv_source: Option<u32> = None;
+        let mut pv_request_id: Option<u32> = None;
+        let mut pv_reply_id: Option<u32> = None;
+        let mut pv_emoji: Option<u32> = None;
+
+        // Can we handle the payload variant? is it empty? encrypted? decoded?
+        if packet.payload_variant.is_none() {
+            // if None, use defaults we set above!
+        }
+
+        if packet.payload_variant.is_some() {
+            match packet.payload_variant.clone().unwrap() {
+                meshtastic::protobufs::mesh_packet::PayloadVariant::Decoded(data) => {
+                    // decoded packet, update pv values
+                    pv_status = Some(1);
+                    pv_portnum = Some(data.portnum);
+                    pv_data = Some(data.payload);
+                    pv_want_response = Some(data.want_response);
+                    pv_dest = Some(data.dest);
+                    pv_source = Some(data.source);
+                    pv_request_id = Some(data.request_id);
+                    pv_reply_id = Some(data.reply_id);
+                    pv_emoji = Some(data.emoji);
+                },
+                meshtastic::protobufs::mesh_packet::PayloadVariant::Encrypted(items) => {
+                    // encrypted packet, update some pv values
+                    pv_status = Some(2);
+                    pv_data = Some(items);
+                },
+            }
+        }
+
+        // WAIT! hold on! have we heard this packet before?
+        // Unfortunately there's no "original sender" thing that I can see, so fuck it
+        // check the db for duplicate pv_data's
+        if Self::check_meshpacket_dupe(&pv_data).unwrap_or(false) {
+            // Packet is a duplicate, lets skip it!
+            debug!("Skipping duplicate MeshPacket {}", packet.from);
+            Ok(false)
+        } else {
+            // Add MeshPacket
+            db.conn.execute(
+                "INSERT INTO MeshPacket (
+                    packet_from, packet_to, channel, id, 
+                    rx_time, rx_snr, hop_limt, want_ack, 
+                    priority, rx_rssi, via_mqtt, hop_start, 
+                    pv_status, pv_portnum, pv_data, pv_want_response, 
+                    pv_dest, pv_source, pv_request_id, pv_reply_id, 
+                    pv_emoji             
+                ) VALUES (
+                    ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, 
+                    ?15, ?16, ?17, ?18, ?19, ?20, ?21
+                )",
+                rusqlite::params![
+                    packet.from,
+                    packet.to,          // 4294967295 = 0xFFFFFFFF = Everyone / Unknown
+                    packet.channel,
+                    packet.id,
+                    packet.rx_time,
+                    packet.rx_snr,
+                    packet.hop_limit,
+                    packet.want_ack,
+                    packet.priority,
+                    packet.rx_rssi,
+                    packet.via_mqtt,
+                    packet.hop_start,
+                    pv_status,
+                    pv_portnum,
+                    pv_data,
+                    pv_want_response,
+                    pv_dest,
+                    pv_source,
+                    pv_request_id,
+                    pv_reply_id,
+                    pv_emoji
+                ]
+            )?;
+            debug!("Added new MeshPacket from {}", packet.from);
+            Ok(true)
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/gui.rs b/src/gui.rs
index a19f7d2..38824fc 100644
--- a/src/gui.rs
+++ b/src/gui.rs
@@ -1,7 +1,40 @@
+use std::str::FromStr;
+
+use chrono::DateTime;
 use egui_extras::{Column, TableBuilder};
+use meshtastic::protobufs::{config::device_config::Role, HardwareModel};
 use tracing::debug;
+use chrono_humanize::{self, HumanTime};
+use longitude::{Distance, DistanceUnit, Location};
+use meshtastic::protobufs::Position;
+
+use crate::{db::Database, CONFIG};
 
-use crate::db::Database;
+/// Calculates the distance betwen 2 coordinate points.
+fn calc_distance_to_node(away: Position) -> Option<f64> {
+    let home_pos = Database::read_home_node().expect("Failed to find Home Node").position.unwrap();
+
+    let distance = Location {
+        // Home Base
+        latitude: home_pos.latitude_i as f64 * 1e-7,
+        longitude: home_pos.longitude_i as f64 * 1e-7,
+    }.distance(&Location {
+        // Away
+        latitude: away.latitude_i as f64 * 1e-7,
+        longitude: away.longitude_i as f64 * 1e-7,
+    });
+    // convert to the right distance depending on settings
+    match CONFIG.gui.units.as_ref() {
+        "Centimeters" => Some(distance.in_unit(DistanceUnit::Centimeters)),
+        "Meters" => Some(distance.in_unit(DistanceUnit::Meters)),
+        "Kilometers" => Some(distance.in_unit(DistanceUnit::Kilometers)),
+        "Inches" => Some(distance.in_unit(DistanceUnit::Inches)),
+        "Feet" => Some(distance.in_unit(DistanceUnit::Feet)),
+        "Yards" => Some(distance.in_unit(DistanceUnit::Yards)),
+        "Miles" => Some(distance.in_unit(DistanceUnit::Miles)),
+        _ => Some(distance.in_unit(DistanceUnit::Kilometers)), // if you can't type, force km.
+    }
+}
 
 pub(crate) async fn run_gui() {
     debug!("Running in GUI Mode!");
@@ -14,16 +47,28 @@ pub(crate) async fn run_gui() {
             // Table Panel, showing nodes in a list.
             egui::CentralPanel::default().show(ctx, |ui| {
                 // Get nodes from DB
-                let nodes = Database::read_node_list().expect("Failed to read nodes");
+                let mut nodes = Database::read_node_list().expect("Failed to read nodes");
+
+                // Sort nodes by `last_heard` in descending order
+                nodes.sort_by(|a, b| b.last_heard.cmp(&a.last_heard));
+
                 TableBuilder::new(ui)
-                    .column(Column::auto().resizable(true))
-                    .column(Column::remainder())
-                    .column(Column::remainder())
-                    .column(Column::remainder())
-                    .column(Column::remainder())
-                    .column(Column::remainder())
-                    .column(Column::remainder())
-                    .header(20.0, |mut header| {
+                // TODO for the table:
+                // - Clickable Table Sorting
+                // - Add more info
+                // - Auto hide/show scrollbar on smaller devices
+                // - Add to a panel that we can move around / shitty windowing.
+                    .column(Column::remainder())            // node id
+                    .column(Column::remainder().clip(true)) // node name
+                    .column(Column::remainder())            // snr
+                    .column(Column::remainder())            // dist
+                    .column(Column::remainder())            // hops
+                    .column(Column::remainder().clip(true))            // hw model
+                    .column(Column::remainder())            // role
+                    .column(Column::remainder())            // battery
+                    .column(Column::remainder().clip(true))            // last heard
+                    .striped(true)
+                    .header(15.0, |mut header| {
                         header.col(|ui| {
                             ui.heading("Node ID");
                         });
@@ -33,6 +78,22 @@ pub(crate) async fn run_gui() {
                         header.col(|ui| {
                             ui.heading("SNR");
                         });
+                        header.col(|ui| {
+
+                            // Get distance units
+                            let unit = match CONFIG.gui.units.as_ref() {
+                                "Centimeters" => "cm",
+                                "Meters" => "m",
+                                "Kilometers" => "km",
+                                "Inches" => "in",
+                                "Feet" => "ft",
+                                "Yards" => "yd",
+                                "Miles" => "mi",
+                                _ => "km", // Default to km if no match found.
+                            };
+
+                            ui.heading(format!("Distance ({})", unit));
+                        });
                         header.col(|ui| {
                             ui.heading("Hops Away");
                         });
@@ -43,14 +104,27 @@ pub(crate) async fn run_gui() {
                             ui.heading("Role");
                         });
                         header.col(|ui| {
-                            ui.heading("Battery Level");
+                            ui.heading("Battery");
+                        });
+                        header.col(|ui| {
+                            ui.heading("Last Heard");
                         });
                     })
                     .body(|mut body| {
                         for node in nodes {
                             let user = node.user.unwrap();
                             let device = node.device_metrics.unwrap();
-                            body.row(10.0, |mut row| {
+                            // Convert the last heard to a time, then make it nice to read.
+                            let now = chrono::Local::now().to_utc();
+                            let humanised = if node.last_heard == 0 {
+                                String::from("Unknown")
+                            } else {
+                                let last_heard = DateTime::from_timestamp(node.last_heard.into(), 0).unwrap();
+                                let duration = last_heard - now;
+                                HumanTime::from(duration).to_string()
+                            };
+
+                            body.row(15.0, |mut row| {
                                 row.col(|ui| {
                                     ui.label(user.id);
                                 });
@@ -60,18 +134,34 @@ pub(crate) async fn run_gui() {
                                 row.col(|ui| {
                                     ui.label(node.snr.to_string());
                                 });
+                                row.col(|ui| {
+                                    if let Some(distance) = calc_distance_to_node(node.position.unwrap()) {
+                                        if distance.is_nan() {
+                                            ui.label("-");
+                                        } else {
+                                            ui.label(format!("{:.2}", distance));
+                                        }
+                                    } else {
+                                        ui.label("-");
+                                    }
+                                });
                                 row.col(|ui| {
                                     ui.label(node.hops_away.to_string());
                                 });
                                 row.col(|ui| {
-                                    ui.label(user.hw_model.to_string());
+                                    // Convert the i32 to a HardwareModel object, then convert to string
+                                    ui.label(HardwareModel::from_i32(user.hw_model).unwrap_or_default().as_str_name());
                                 });
                                 row.col(|ui| {
-                                    ui.label(user.role.to_string());
+                                    // Convert the i32 to a Role object, convert to string.
+                                    ui.label(Role::from_i32(user.role).unwrap_or_default().as_str_name());
                                 });
                                 row.col(|ui| {
                                     ui.label(device.battery_level.to_string());
                                 });
+                                row.col(|ui| {
+                                    ui.label(humanised);
+                                });
                             });
                         }
                     });
diff --git a/src/packets.rs b/src/packets.rs
index a12c4b4..d5fd3a0 100644
--- a/src/packets.rs
+++ b/src/packets.rs
@@ -2,7 +2,8 @@ use std::path::Path;
 
 use config::device_config;
 use from_radio::PayloadVariant;
-use meshtastic::protobufs::*;
+use log::info;
+use meshtastic::protobufs::{config::device_config::Role, *};
 use tracing::{debug, error};
 
 use crate::db::Database;
@@ -15,8 +16,8 @@ pub fn parse(message: &FromRadio) -> bool {
     match message.payload_variant {
         // A normal message
         Some(PayloadVariant::Packet(ref packet)) => {
-            debug!("New Message Packet!");
-            parse_packet(packet);
+            debug!("New MeshPacket!");
+            parse_meshpacket(packet);
         },
         // Information about the local node
         Some(PayloadVariant::MyInfo(ref info)) => {
@@ -59,14 +60,19 @@ pub fn parse(message: &FromRadio) -> bool {
     true
 }
 
-fn parse_packet(packet: &MeshPacket) {
+fn parse_meshpacket(packet: &MeshPacket) {
     // Handle packet data
-    error!("Unhandled MeshPacket Packet: {:#?}", &packet);
-    
+    debug!("Parsing MeshPacket Packet: {:?}", &packet);
+    let _ = Database::add_meshpacket(packet);
+
+    // I don't think we can, but imagine if meshtastic added the "last hop node"
+    // so we can figure out at least who im actively receiving from, and figure out their
+    // signal strength without brute forcing and sending/waiting for other packets.
+    // because I'd love to be able to update 0 hop nodes snr/rssi from here, but I have to let it g
 }
 
 fn parse_myinfo(packet: &MyNodeInfo) {
-    debug!("Parsing MyNodeInfo Packet: {:#?}", &packet);
+    debug!("Parsing MyNodeInfo Packet: {:?}", &packet);
     let _ = Database::update_mynodeinfo(packet);
 }
 
@@ -82,7 +88,7 @@ fn parse_nodeinfo(node_info: &NodeInfo) {
 
 fn parse_config(config: &Config) {
     // Handle Config data
-    debug!("Parsing Config Packet: {:#?}", &config);
+    debug!("Parsing Config Packet: {:?}", &config);
     
     // Match and destructure the payload_variant
     if let Some(payload_variant) = config.payload_variant.clone() {
@@ -113,7 +119,7 @@ fn parse_config(config: &Config) {
 }
 
 fn parse_module_config(module_config: &ModuleConfig) {
-    debug!("Parsing Module Packet: {:#?}", &module_config);
+    debug!("Parsing Module Packet: {:?}", &module_config);
     // Handle ModuleConfig data
     // Match and destructure the payload_variant
     if let Some(payload_variant) = module_config.payload_variant.clone() {
@@ -162,7 +168,7 @@ fn parse_module_config(module_config: &ModuleConfig) {
 }
 
 fn parse_channel_info(channel_info: &Channel) {
-    debug!("Parsing Channel Packet: {:#?}", &channel_info);
+    debug!("Parsing Channel Packet: {:?}", &channel_info);
     // Handle ChannelInfo data
     let _ = Database::update_channel(channel_info);
 }
diff --git a/yamm.db b/yamm.db
index ba450ab0817c9ed872df41b1eae021433714cba9..f77f5dcf23bda7fb3a2dd839ba13f9be42b95f22 100644
GIT binary patch
literal 176128
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

delta 8325
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
G<UavT8X!Xe

-- 
GitLab