diff --git a/Cargo.lock b/Cargo.lock index 3a473b6..9b0d71b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,6 +38,7 @@ dependencies = [ "serde", "serde_json", "tokio", + "toml", "warp", ] @@ -1258,6 +1259,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +dependencies = [ + "serde", +] + [[package]] name = "tower-service" version = "0.3.2" diff --git a/Cargo.toml b/Cargo.toml index cce90a6..43a58d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ edition = "2021" rumqttc = "0.18" serde = { version ="1.0.149", features = ["derive"] } serde_json = "1.0.89" -dotenv = "0.15.0" impl_cast = {path = "./impl_cast"} google-home = {path = "./google-home"} paste = "1.0.10" @@ -18,6 +17,8 @@ warp = "0.3" log = "0.4" env_logger = "0.10" pollster = "0.2.5" +toml = "0.5.10" +dotenv = "0.15.0" [profile.release] lto=true diff --git a/config/config.example.toml b/config/config.example.toml new file mode 100644 index 0000000..40f5ec7 --- /dev/null +++ b/config/config.example.toml @@ -0,0 +1,5 @@ +[mqtt] +host="example.com" +port=1234 +username="username" +password="password" diff --git a/config/zeus_dev.toml b/config/zeus_dev.toml new file mode 100644 index 0000000..09adba5 --- /dev/null +++ b/config/zeus_dev.toml @@ -0,0 +1,4 @@ +[mqtt] +host="olympus.lan.huizinga.dev" +port=8883 +username="mqtt" diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..c0e3629 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,29 @@ +use std::{fs, error::Error}; + +use log::debug; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct Config { + pub mqtt: MQTT, +} + +#[derive(Debug, Deserialize)] +pub struct MQTT { + pub host: String, + pub port: u16, + pub username: String, + pub password: Option, +} + +impl Config { + pub fn build(filename: &str) -> Result> { + debug!("Loading config: {filename}"); + let file = fs::read_to_string(filename)?; + let mut config: Self = toml::from_str(&file)?; + + config.mqtt.password = Some(std::env::var("MQTT_PASSWORD").or(config.mqtt.password.ok_or("MQTT password needs to be set in either config or the environment!"))?); + + Ok(config) + } +} diff --git a/src/main.rs b/src/main.rs index 032880f..a8d0397 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,34 +1,32 @@ -use std::{time::Duration, sync::{Arc, RwLock}, process::exit, net::SocketAddr}; +mod config; +use std::{time::Duration, sync::{Arc, RwLock}, process, net::SocketAddr}; + +use config::Config; +use dotenv::dotenv; use warp::Filter; use rumqttc::{MqttOptions, Transport, AsyncClient}; -use dotenv::dotenv; use env_logger::Builder; use log::{error, info, LevelFilter}; use automation::{devices::{Devices, IkeaOutlet, TestOutlet}, zigbee::Zigbee, mqtt::Notifier}; use google_home::{GoogleHome, Request}; -fn get_required_env(name: &str) -> String { - match std::env::var(name) { - Ok(value) => value, - _ => { - error!("Environment variable ${name} is not set!"); - exit(-1); - } - } -} - #[tokio::main] async fn main() { + dotenv().ok(); + // Setup logger Builder::new() .filter_module("automation", LevelFilter::Info) .parse_default_env() .init(); - // Load dotfiles - dotenv().ok(); + let config = std::env::var("AUTOMATION_CONFIG").unwrap_or("./config/config.toml".to_owned()); + let config = Config::build(&config).unwrap_or_else(|err| { + error!("Failed to load config: {err}"); + process::exit(1); + }); info!("Starting automation_rs..."); @@ -37,8 +35,8 @@ async fn main() { let devices = Arc::new(RwLock::new(Devices::new())); // Setup MQTT - let mut mqttoptions = MqttOptions::new("rust-test", get_required_env("MQTT_HOST"), 8883); - mqttoptions.set_credentials(get_required_env("MQTT_USERNAME"), get_required_env("MQTT_PASSWORD")); + let mut mqttoptions = MqttOptions::new("rust-test", config.mqtt.host, config.mqtt.port); + mqttoptions.set_credentials(config.mqtt.username, config.mqtt.password.unwrap()); mqttoptions.set_keep_alive(Duration::from_secs(5)); mqttoptions.set_transport(Transport::tls_with_default_config());