Implementation of firmware for a sprinklers system using async Rust, Tokio, Actix, MQTT and more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

101 lines
3.0 KiB

#![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;
#[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...");
5 years ago
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");
}
5 years ago
// 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?;
UpdateListener::start(section_events, program_events, mqtt_interface.clone())
};
program_runner.update_sections(sections.clone()).await?;
mqtt_interface.publish_sections(&sections).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?;
}
4 years ago
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;
5 years ago
Ok(())
}