+150
@@ -0,0 +1,150 @@
|
||||
use std::fs;
|
||||
use std::io::{Seek, Write};
|
||||
use std::path::Path;
|
||||
|
||||
use chrono::{DateTime, Datelike, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use gps_parser;
|
||||
use ina3221;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct Sample {
|
||||
value: f64,
|
||||
unit: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct CvsData {
|
||||
lat: f64,
|
||||
lon: f64,
|
||||
timestamp: String,
|
||||
speed: Sample,
|
||||
rpm: Sample,
|
||||
current: Sample,
|
||||
voltage: Sample,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct Opts {
|
||||
log_path: String,
|
||||
i2c_dev: String,
|
||||
i2c_slave_address: u16,
|
||||
gps_dev: String,
|
||||
shunt_resistor: f64,
|
||||
}
|
||||
|
||||
fn read_opts(path: &str) -> Opts {
|
||||
let opts_str = fs::read_to_string(path).expect("Unable to read log file");
|
||||
return serde_json::from_str(&opts_str).unwrap();
|
||||
}
|
||||
|
||||
fn update_date(datetime: DateTime<Utc>, year: i32, month: u32, day: u32) -> DateTime<Utc> {
|
||||
let mut res = datetime;
|
||||
|
||||
res = match res.with_year(year) {
|
||||
Some(value) => value,
|
||||
_none => datetime,
|
||||
};
|
||||
res = match res.with_month(month) {
|
||||
Some(value) => value,
|
||||
_none => datetime,
|
||||
};
|
||||
res = match res.with_day(day) {
|
||||
Some(value) => value,
|
||||
_none => datetime,
|
||||
};
|
||||
return res;
|
||||
}
|
||||
|
||||
fn log_sample(log_path: &str, sample: CvsData) {
|
||||
let path = Path::new(log_path);
|
||||
let mut log_json: Vec<CvsData> = Vec::new();
|
||||
let mut file: fs::File;
|
||||
if path.exists() {
|
||||
file = fs::OpenOptions::new().read(true).write(true).create(true).truncate(false).append(false).open(log_path).unwrap();
|
||||
let log_str = fs::read_to_string(path).expect("Unable to read log file");
|
||||
log_json = serde_json::from_str(&log_str).unwrap();
|
||||
file.set_len(0).unwrap();
|
||||
file.rewind().unwrap();
|
||||
} else {
|
||||
file = fs::File::create(log_path).expect("Unable to create file");
|
||||
}
|
||||
log_json.push(sample);
|
||||
let j = match serde_json::to_string(&log_json) {
|
||||
Ok(value) => value,
|
||||
Err(error) => panic!("Unable to make JSON from struct {:?}", error),
|
||||
};
|
||||
file.write_all(j.as_bytes()).expect("Unable to write JSON string to file");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let opts = read_opts("/etc/cvs-monitor/config.json");
|
||||
let path = Path::new(&opts.log_path);
|
||||
if !path.exists() {
|
||||
match fs::create_dir(&opts.log_path) {
|
||||
Ok(()) => {},
|
||||
Err(err) => panic!("Can't create dir \"{}\" ({})", opts.log_path, err),
|
||||
};
|
||||
}
|
||||
let now = Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
|
||||
let log_file: String = opts.log_path + &now + ".json";
|
||||
|
||||
let mut gps_parser = gps_parser::GpsParser::new(&opts.gps_dev);
|
||||
let mut ina = ina3221::Ina3221::new(opts.i2c_slave_address, &opts.i2c_dev, opts.shunt_resistor);
|
||||
|
||||
|
||||
loop {
|
||||
let speed = Sample {
|
||||
value: 0.0,
|
||||
unit: "km/h".to_string(),
|
||||
};
|
||||
let rpm = Sample {
|
||||
value: 0.0,
|
||||
unit: "T/min".to_string(),
|
||||
};
|
||||
let current = Sample {
|
||||
value: 0.0,
|
||||
unit: "A".to_string(),
|
||||
};
|
||||
let voltage = Sample {
|
||||
value: 0.0,
|
||||
unit: "V".to_string(),
|
||||
};
|
||||
|
||||
let mut sample = CvsData {
|
||||
lat: 0.0,
|
||||
lon: 0.0,
|
||||
timestamp: Utc::now().to_rfc3339(),
|
||||
speed,
|
||||
rpm,
|
||||
current,
|
||||
voltage,
|
||||
};
|
||||
|
||||
let gps = match gps_parser.parse_nmea() {
|
||||
Ok(value) => value,
|
||||
Err(_) => continue
|
||||
};
|
||||
sample.lat = gps.lat;
|
||||
sample.lon = gps.lon;
|
||||
sample.speed.value = gps.speed;
|
||||
sample.rpm.value = sample.speed.value * 1000.0 / (60.0 * 2.2);
|
||||
|
||||
let mut tmp = gps.timestamp;
|
||||
tmp = update_date(tmp, Utc::now().year(), Utc::now().month(), Utc::now().day());
|
||||
sample.timestamp = tmp.to_rfc3339();
|
||||
let current = match ina.current(ina3221::Channel::One) {
|
||||
Ok(value) => value,
|
||||
Err(_error) => 0.0,
|
||||
};
|
||||
sample.current.value = current;
|
||||
let voltage = match ina.bus_voltage(ina3221::Channel::One) {
|
||||
Ok(value) => value,
|
||||
Err(_error) => 0.0,
|
||||
};
|
||||
sample.voltage.value = voltage;
|
||||
|
||||
log_sample(&log_file, sample);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user