Files
isolated-switches/src/main.rs
T

193 lines
5.9 KiB
Rust

use rppal::gpio::{Gpio, OutputPin};
use serde::{Deserialize};
use serde_json;
use sqlite;
use std::env;
use std::fs::File;
use std::path::Path;
use std::thread;
use std::time::Duration;
use chrono;
// Gpio uses BCM pin numbering. BCM GPIO 23 is tied to physical pin 16.
const GPIO_SWITCH: u8 = 24;
// set duration of pin switching test
#[derive(Deserialize)]
struct Config{
database: String,
device_name_voltage: String,
mode: String,
test_duration_seconds: u64,
time_on: String,
time_off: String,
time_use: bool,
voltage_off: f32,
voltage_recover: f32,
}
#[derive(Deserialize)]
#[allow(non_snake_case)]
struct DbData{
V: String,
}
//fn main() {
fn main () {
let home_dir = env::home_dir().expect("Could not determine home directory");
let mut config_file_path: &str = &(home_dir.to_string_lossy() + "/.isolated-switches/config.json");
// read and parse command line parameters
let args: Vec<String> = env::args().collect();
for n in 1..args.len() {
match args[n].as_str() {
"on" => {
pin_switch_on();
return;
},
"off" => {
pin_switch_off();
return;
},
"status" => {
println!("Inverter status: {}" , if pin_status() == 0 { "off" } else { "on" });
return;
},
"test" => {
pin_test(config_file_path);
return;
},
"config" => {
if args.len() > n + 1 { config_file_path = args[n + 1].as_str(); }
},
_ => ()
}
}
// read and parse configuration file
let config: Config = read_config(&config_file_path);
match config.mode.as_str() {
"auto" => {
println!("Running in automatic mode");
let pin_status_cur = pin_status();
let voltage = get_current_voltage(&config);
// turn inverter off based on time of day settings
if config.time_use {
let time_off = chrono::NaiveTime::parse_from_str(&config.time_off, "%H:%M").unwrap();
let time_on = chrono::NaiveTime::parse_from_str(&config.time_on, "%H:%M").unwrap();
let time_now = chrono::Local::now().time();
if time_off > time_on { // switch off at the same day
if time_now < time_on || time_now > time_off {
if pin_status() > 0 {
println!("Off-time!");
pin_switch_off();
}
return;
}
}
else if time_off < time_on { // switch off the next day
if time_now < time_on && time_now > time_off {
if pin_status() > 0 {
println!("Off-time!");
pin_switch_off();
}
return;
}
}
}
if voltage < config.voltage_off && pin_status_cur > 0 {
println!("Low voltage!");
pin_switch_off();
}
else if voltage >= config.voltage_recover && pin_status_cur == 0 {
println!("Voltage recovered!");
pin_switch_on();
}
else {
// no change in status needed
let pin_status_text = if pin_status_cur == 0 { "off" } else { "on" };
println!("No change in inverter status. Current status: {}", pin_status_text);
}
},
"on" => {
println!("Running in manual mode ON");
if pin_status() == 0 {
pin_switch_on();
}
return;
},
"off" => {
println!("Running in manual mode OFF");
if pin_status() > 0 {
pin_switch_off();
}
return;
},
_ => ()
}
//end program with OK status
}
// read and parse configuration file
fn read_config(config_file_path: &str) -> Config {
let config_file = File::open(config_file_path)
.expect(&("Could not read config file ".to_owned() + config_file_path ));
let config: Config = serde_json::from_reader(config_file)
.expect("file should be proper JSON");
config
}
fn pin_status () -> u8 {
let pin_level: u8 = Gpio::new().unwrap().get(GPIO_SWITCH).unwrap().read() as u8;
return pin_level;
}
fn pin_switch_on () {
let mut pin: OutputPin = Gpio::new().unwrap().get(GPIO_SWITCH).unwrap().into_output();
pin.set_reset_on_drop(false);
pin.set_high();
println!("Inverter switched on.");
}
fn pin_switch_off () {
let mut pin: OutputPin = Gpio::new().unwrap().get(GPIO_SWITCH).unwrap().into_output();
pin.set_reset_on_drop(false);
pin.set_low();
println!("Inverter switched off.");
}
fn pin_test (config_path: &str) {
let config: Config = read_config(&config_path);
pin_switch_on();
thread::sleep(Duration::from_millis(config.test_duration_seconds * 1000));
pin_switch_off();
}
fn get_current_voltage (config: &Config) -> f32 {
let mut voltage: f32 = 0.0;
if !Path::new(&config.database).exists() {
return voltage;
}
let db_connection = sqlite::open(&config.database).unwrap();
let query = format!("SELECT data FROM '{device}' ORDER BY date DESC, time DESC LIMIT 1;", device = config.device_name_voltage);
let _ = db_connection.iterate(query, |pairs | {
let data = pairs.get(0).unwrap().1.unwrap();
let test_parse: DbData = serde_json::from_str(data).expect("no proper JSON data found on database");
let raw_value = match test_parse.V.parse::<i32>() {
Ok(v) => v,
Err(_) => return true
};
voltage = raw_value as f32 / 1000.0;
true
});
return voltage;
}