diff --git a/Cargo.lock b/Cargo.lock index 9dcb6883a8bdfb93df357a2659d1a04eb01b7d59..4fa384863d98fdaffe027264f6fbd1a632fd7555 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 185eca251a1f5ca36ef9f815de9d4b7209814fb9..54b538ce9fcf20b2587f0a1b71ec4b985fa3af66 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 e59b673450313347ac402aaf2242826e0c318f5d..5faa14cfdccc4433f5d9001a1f87b81ef6daf601 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 5f3fd30bdad01fc5032667ee95cce755e29627e6..f9a5b735e53ecca5066c3d4966933e6bf62d3c70 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 468616ba348d01bebd383542a8eea7416bb2ebe5..cb045e81b60c7a72ef5a6b2dfa16c96d56acbcef 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 5edec01335ab8de88ae8f27c5a792aa5aba734b3..1ec16916530e651dca3a66119aae1288234f6f31 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 4851ec06b734d2972880a87dc60db6f4bac59269..0acdbed01a6f8a07f544c551d9842eb47e757531 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 a19f7d2c9ed730f38bae9e2d50b6e83ce348551b..38824fca44e2028ea274f534be0abce9b8eac3aa 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 a12c4b4662acf0916fea0edf8d36f593408bd412..d5fd3a0c1f3b51ed9530ea6b56a5e209b1bc18ed 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 Binary files a/yamm.db and b/yamm.db differ