Initial commit

Signed-off-by: Thomas Klaehn <thomas.klaehn@perinet.io>
This commit is contained in:
Thomas Klaehn
2025-01-20 16:18:28 +01:00
commit d16bd7e7f8
9 changed files with 837 additions and 0 deletions
+150
View File
@@ -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);
}
}