|
|
|
#![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(())
|
|
|
|
}
|