#![warn(clippy::all)] #![warn(clippy::print_stdout)] mod database; mod model; mod mqtt_interface; mod option_future; mod program_runner; mod schedule; mod section_interface; mod section_runner; mod section_runner_json; #[cfg(test)] mod trace_listeners; mod update_listener; use eyre::Result; use std::sync::Arc; use tracing::{debug, info}; use tracing_subscriber::EnvFilter; use update_listener::UpdateListener; #[tokio::main] async fn main() -> Result<()> { tracing_subscriber::fmt() .with_ansi(true) .with_env_filter( EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")), ) .init(); info!("Starting sprinklers_rs..."); color_eyre::install()?; let conn = database::setup_db()?; let sections = database::query_sections(&conn)?; for sec in sections.values() { debug!(section = debug(&sec), "read section"); } // TODO: Section interface which actual does something. Preferrably selectable somehow let section_interface: Arc<_> = section_interface::MockSectionInterface::new(6).into(); let mut section_runner = section_runner::SectionRunner::new(section_interface); let mut program_runner = program_runner::ProgramRunner::new(section_runner.clone()); let mut programs = database::query_programs(&conn)?; // TEMP: just so the program runs right away if let Some(prog) = programs.get_mut(&1) { let prog_mut = Arc::make_mut(prog); if let Some(first_time) = prog_mut.schedule.times.get_mut(0) { *first_time = chrono::Local::now().time() + chrono::Duration::seconds(5); } } for prog in programs.values() { debug!(program = debug(&prog), "read program"); } let mqtt_options = mqtt_interface::Options { broker_host: "localhost".into(), broker_port: 1883, device_id: "sprinklers_rs-0001".into(), client_id: "sprinklers_rs-0001".into(), }; let mut mqtt_interface = mqtt_interface::MqttInterfaceTask::start(mqtt_options).await?; let update_listener = { let section_events = section_runner.subscribe().await?; let program_events = program_runner.subscribe().await?; let sec_runner_state = section_runner.state_receiver(); UpdateListener::start( section_events, program_events, sec_runner_state, mqtt_interface.clone(), ) }; program_runner.update_sections(sections.clone()).await?; mqtt_interface.publish_sections(§ions).await?; for section_id in sections.keys() { mqtt_interface .publish_section_state(*section_id, false) .await?; } program_runner.update_programs(programs.clone()).await?; for program_id in programs.keys() { mqtt_interface .publish_program_running(*program_id, false) .await?; } mqtt_interface.publish_programs(&programs).await?; info!("sprinklers_rs initialized"); tokio::signal::ctrl_c().await?; info!("Interrupt received, shutting down"); update_listener.quit().await?; mqtt_interface.quit().await?; program_runner.quit().await?; section_runner.quit().await?; tokio::task::yield_now().await; Ok(()) }