xplane-datamonitor

A WIP tool to show data inside grafana
git clone git://archive.git.mtrnord.blog/MTRNord/xplane-datamonitor.git
Log | Files | Refs

commit 6088c11940f34735146be3bd2f044faa31b7522b
parent 24940929b64b27b5f7970e23792819449ae3aa7c
Author: MTRNord <mtrnord1@gmail.com>
Date:   Thu,  5 Aug 2021 15:03:32 +0200

add multiple datarefs

Diffstat:
MCargo.toml | 12+++++++++---
Msrc/energy.rs | 13++++++++++---
Msrc/lib.rs | 80++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/location.rs | 12+++++++++---
4 files changed, 89 insertions(+), 28 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -1,4 +1,4 @@ -cargo-features = ["edition2021"] +cargo-features = ["edition2021","strip"] [package] name = "xplane-datamonitor" @@ -14,6 +14,12 @@ crate-type = ["cdylib"] xplm = "0.3.1" anyhow = "1.0.42" thiserror = "1.0.26" +influxdb-client = "0.1.4" +tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] } [profile.release] -lto = true -\ No newline at end of file +codegen-units = 1 +opt-level = 'z' +lto = true +strip = true +panic = 'abort' +\ No newline at end of file diff --git a/src/energy.rs b/src/energy.rs @@ -7,6 +7,7 @@ use crate::error::Error; pub(crate) struct EnergyRefs { pub(crate) gpu_on: DataRef<bool, ReadWrite>, pub(crate) battery: DataRef<[i32], ReadWrite>, + pub(crate) apu_on: DataRef<bool, ReadWrite>, } #[derive(Clone)] @@ -20,6 +21,7 @@ impl Energy { inner: Rc::new(EnergyRefs { gpu_on: DataRef::find("sim/cockpit/electrical/gpu_on")?.writeable()?, battery: DataRef::find("sim/cockpit2/electrical/battery_on")?.writeable()?, + apu_on: DataRef::find("sim/cockpit2/electrical/APU_generator_on")?.writeable()?, }), }) } @@ -31,15 +33,20 @@ impl Energy { pub(crate) fn battery_on(&self) -> bool { self.inner.battery.as_vec().contains(&1) } + + pub(crate) fn apu_on(&self) -> bool { + self.inner.apu_on.get() + } } impl Display for Energy { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "GPU enabled: {}, Battery enabled: {}", - self.inner.gpu_on.get(), - self.inner.battery.as_vec().contains(&1), + "GPU enabled: {}, Battery enabled: {}, APU Gen enabled: {}", + self.gpu_on(), + self.battery_on(), + self.apu_on(), ) } } diff --git a/src/lib.rs b/src/lib.rs @@ -1,7 +1,11 @@ #[deny(unused_imports)] #[deny(missing_docs)] -use std::thread; -use std::time::{Duration, SystemTime}; +use influxdb_client::{Client, Point, Precision, TimestampOptions}; +use std::{ + sync::Arc, + time::{Duration, Instant, SystemTime, UNIX_EPOCH}, +}; +use tokio::runtime::{self, Runtime}; use xplm::{ debug, flight_loop::{FlightLoop, FlightLoopCallback}, @@ -25,27 +29,50 @@ struct DataMonitorPlugin { struct LoopHandler { location: Location, energy: Energy, - last_run: SystemTime, + last_run: Instant, + start_time: SystemTime, + leg_started: bool, + influx: Arc<influxdb_client::Client>, + rt: Arc<Runtime>, } impl FlightLoopCallback for LoopHandler { fn flight_loop(&mut self, state: &mut xplm::flight_loop::LoopState) { - if self.last_run.elapsed().unwrap() >= Duration::from_secs(5) { - let battery_on = self.energy.battery_on(); - let gpu_on = self.energy.gpu_on(); - let location = self.location.to_string(); - let energy = self.energy.to_string(); - let thread = thread::spawn(move || { - // Do stuff with location - if battery_on || gpu_on { - debug(format!("[DATAMONITOR] {}\n", location)); - debug(format!("[DATAMONITOR] {}\n", energy)); - } + let battery_on = self.energy.battery_on(); + let gpu_on = self.energy.gpu_on(); + let apu_on = self.energy.apu_on(); + if (battery_on || gpu_on || apu_on) && !self.leg_started { + // TODO reset on FP change + self.leg_started = true; + } + if self.last_run.elapsed() >= Duration::from_secs(1) && self.leg_started { + let latitude = self.location.lat(); + let longitude = self.location.lon(); + let altitude = self.location.alt(); + let timestamp = self + .start_time + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_secs() as i64; + + let client = self.influx.clone(); + self.rt.spawn(async move { + let location_point = Point::new("location") + .tag("start_time", timestamp) + .field("latitude", latitude) + .field("longitude", longitude) + .field("altitude_feet", altitude); + let status_point = Point::new("status") + .tag("start_time", timestamp) + .field("battery_on", battery_on) + .field("gpu_on", gpu_on) + .field("apu_on", apu_on); + let points = vec![&location_point, &status_point]; + if let Err(e) = client.insert_points(points, TimestampOptions::None).await { + debug(format!("[DATAMONITOR][ERROR] Sending Points: {:#?}\n", e)); + }; }); - if let Err(e) = thread.join() { - debug(format!("[DATAMONITOR][ERROR] {:?}\n", e)); - } - self.last_run = SystemTime::now(); + self.last_run = Instant::now(); } state.call_next_loop() } @@ -74,10 +101,25 @@ impl Plugin for DataMonitorPlugin { debug(format!("[DATAMONITOR][ERROR] Energy init: {:?}\n", e)); } + let influx_client = Client::new("http://10.0.0.1:8086", + "wuL5_5sg_zlaQdkDWhmiFZ9r-Fx1rWgNR407czXOeQmYU1PHlp0nwpmjjW270PzEgEctx0AqD_K7K-h9Ein6Pg==") + .with_org("Nordgedanken") + .with_bucket("flightdata") + .with_precision(Precision::MS); + + let rt = runtime::Runtime::new(); + if let Err(ref e) = rt { + debug(format!("[DATAMONITOR][ERROR] Creating runtime: {:#?}\n", e)); + } + let loophandler = LoopHandler { location: location.unwrap(), energy: energy.unwrap(), - last_run: SystemTime::now(), + last_run: Instant::now(), + influx: Arc::new(influx_client), + start_time: SystemTime::now(), + leg_started: false, + rt: Arc::new(rt.unwrap()), }; let plugin = DataMonitorPlugin { loophandler, diff --git a/src/location.rs b/src/location.rs @@ -7,6 +7,7 @@ use crate::error::Error; pub(crate) struct LocationRefs { pub(crate) latitude: DataRef<f64, ReadOnly>, pub(crate) longitude: DataRef<f64, ReadOnly>, + pub(crate) altitude: DataRef<f32, ReadOnly>, } #[derive(Clone)] @@ -20,6 +21,7 @@ impl Location { inner: Rc::new(LocationRefs { latitude: DataRef::find("sim/flightmodel/position/latitude")?, longitude: DataRef::find("sim/flightmodel/position/longitude")?, + altitude: DataRef::find("sim/cockpit2/gauges/indicators/altitude_ft_pilot")?, }), }) } @@ -30,15 +32,19 @@ impl Location { pub(crate) fn lon(&self) -> f64 { self.inner.longitude.get() } + pub(crate) fn alt(&self) -> f64 { + self.inner.altitude.get() as f64 + } } impl Display for Location { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "Latitude: {}, Longitude: {}", - self.inner.latitude.get(), - self.inner.longitude.get() + "Latitude: {}, Longitude: {}, Altitude: {}", + self.lat(), + self.lon(), + self.alt() ) } }