xplane-datamonitor

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

lib.rs (4806B)


      1 #[deny(unused_imports)]
      2 #[deny(missing_docs)]
      3 use influxdb_client::{Client, Point, Precision, TimestampOptions};
      4 use std::{
      5     sync::Arc,
      6     time::{Duration, Instant, SystemTime, UNIX_EPOCH},
      7 };
      8 use tokio::runtime::{self, Runtime};
      9 use xplm::{
     10     debug,
     11     flight_loop::{FlightLoop, FlightLoopCallback},
     12     plugin::{Plugin, PluginInfo},
     13     xplane_plugin,
     14 };
     15 
     16 use crate::location::Location;
     17 use crate::{energy::Energy, error::Error};
     18 
     19 mod energy;
     20 mod error;
     21 mod location;
     22 
     23 struct DataMonitorPlugin {
     24     loophandler: LoopHandler,
     25     flightloop: Option<FlightLoop>,
     26 }
     27 
     28 #[derive(Clone)]
     29 struct LoopHandler {
     30     location: Location,
     31     energy: Energy,
     32     last_run: Instant,
     33     start_time: SystemTime,
     34     leg_started: bool,
     35     influx: Arc<influxdb_client::Client>,
     36     rt: Arc<Runtime>,
     37 }
     38 
     39 impl FlightLoopCallback for LoopHandler {
     40     fn flight_loop(&mut self, state: &mut xplm::flight_loop::LoopState) {
     41         let battery_on = self.energy.battery_on();
     42         let gpu_on = self.energy.gpu_on();
     43         let apu_on = self.energy.apu_on();
     44         if (battery_on || gpu_on || apu_on) && !self.leg_started {
     45             // TODO reset on FP change
     46             self.leg_started = true;
     47         }
     48         if self.last_run.elapsed() >= Duration::from_secs(1) && self.leg_started {
     49             let latitude = self.location.lat();
     50             let longitude = self.location.lon();
     51             let altitude = self.location.alt();
     52             let timestamp = self
     53                 .start_time
     54                 .duration_since(UNIX_EPOCH)
     55                 .expect("Time went backwards")
     56                 .as_secs() as i64;
     57 
     58             let client = self.influx.clone();
     59             self.rt.spawn(async move {
     60                 let location_point = Point::new("location")
     61                     .tag("start_time", timestamp)
     62                     .field("latitude", latitude)
     63                     .field("longitude", longitude)
     64                     .field("altitude_feet", altitude);
     65                 let status_point = Point::new("status")
     66                     .tag("start_time", timestamp)
     67                     .field("battery_on", battery_on)
     68                     .field("gpu_on", gpu_on)
     69                     .field("apu_on", apu_on);
     70                 let points = vec![&location_point, &status_point];
     71                 if let Err(e) = client.insert_points(points, TimestampOptions::None).await {
     72                     debug(format!("[DATAMONITOR][ERROR] Sending Points: {:#?}\n", e));
     73                 };
     74             });
     75             self.last_run = Instant::now();
     76         }
     77         state.call_next_loop()
     78     }
     79 }
     80 
     81 impl DataMonitorPlugin {
     82     pub(crate) fn start(&mut self) {
     83         debug("[DATAMONITOR] starting\n");
     84         let mut flight_loop = FlightLoop::new(self.loophandler.clone());
     85         flight_loop.schedule_immediate();
     86         self.flightloop = Some(flight_loop);
     87         debug("[DATAMONITOR] started\n");
     88     }
     89 }
     90 
     91 impl Plugin for DataMonitorPlugin {
     92     type Error = Error;
     93 
     94     fn start() -> Result<Self, Self::Error> {
     95         let location = Location::new();
     96         if let Err(ref e) = location {
     97             debug(format!("[DATAMONITOR][ERROR] Location init: {:?}\n", e));
     98         }
     99         let energy = Energy::new();
    100         if let Err(ref e) = energy {
    101             debug(format!("[DATAMONITOR][ERROR] Energy init: {:?}\n", e));
    102         }
    103 
    104         let influx_client = Client::new("http://10.0.0.1:8086", 
    105         "wuL5_5sg_zlaQdkDWhmiFZ9r-Fx1rWgNR407czXOeQmYU1PHlp0nwpmjjW270PzEgEctx0AqD_K7K-h9Ein6Pg==")
    106         .with_org("Nordgedanken")
    107     .with_bucket("flightdata")
    108     .with_precision(Precision::MS);
    109 
    110         let rt = runtime::Runtime::new();
    111         if let Err(ref e) = rt {
    112             debug(format!("[DATAMONITOR][ERROR] Creating runtime: {:#?}\n", e));
    113         }
    114 
    115         let loophandler = LoopHandler {
    116             location: location.unwrap(),
    117             energy: energy.unwrap(),
    118             last_run: Instant::now(),
    119             influx: Arc::new(influx_client),
    120             start_time: SystemTime::now(),
    121             leg_started: false,
    122             rt: Arc::new(rt.unwrap()),
    123         };
    124         let plugin = DataMonitorPlugin {
    125             loophandler,
    126             flightloop: None,
    127         };
    128         Ok(plugin)
    129     }
    130     fn enable(&mut self) -> Result<(), Self::Error> {
    131         self.start();
    132         Ok(())
    133     }
    134     fn disable(&mut self) {
    135         debug("[DATAMONITOR][INFO] Stopping threads\n");
    136     }
    137 
    138     fn info(&self) -> xplm::plugin::PluginInfo {
    139         PluginInfo {
    140             name: String::from("Datamonitor"),
    141             signature: String::from("dev.nordgedanken.datamonitor"),
    142             description: String::from(
    143                 "Gets certain datarefs to display in a grafana for review of flights.",
    144             ),
    145         }
    146     }
    147 }
    148 
    149 xplane_plugin!(DataMonitorPlugin);