use std::collections::HashMap; use common::{BulbPrefs, ClientMessage, ScriptId, ServerMessage}; use lighter_lib::BulbId; use lighter_manager::manager::{BulbCommand, BulbManager, BulbSelector}; use lighter_manager::provider::mqtt::BulbsMqtt; use serde::{Deserialize, Serialize}; use tokio::select; use crate::persistence::PersistenceFile; use crate::State; use self::scripts::{LightScript, Party, Waker}; pub mod scripts; #[derive(Default, Clone, PartialEq, Eq, Serialize, Deserialize)] struct LightsState { script_prefs: HashMap>, } pub async fn lights_task(state: &State) { let config = &state.config; let server_message = &state.server_message; let mut client_message = state.client_message.subscribe(); let mut lights_state: PersistenceFile = state .persistence .open("lights".into()) .await .expect("Failed to open lights config"); let provider = BulbsMqtt::new(config.bulbs.clone(), config.mqtt.clone()); let manager = BulbManager::launch(config.bulbs.clone(), provider) .await .expect("Failed to launch bulb manager"); let mut scripts: HashMap> = Default::default(); scripts.insert( "waker".to_string(), Box::new(Waker::create(manager.clone())), ); scripts.insert( "party".to_string(), Box::new(Party::create(manager.clone())), ); for (script, prefs) in &lights_state.get().script_prefs { let Some(script) = scripts.get_mut(script) else { continue; }; for (bulb, prefs) in prefs { for (name, value) in &prefs.kvs { script.set_param(bulb, name, value.clone()) } } } loop { select! { _ = manager.notify_on_change() => { for (id, mode) in manager.bulbs().await.clone().into_iter() { let prefs = scripts.iter_mut() .map(|(script, prefs)| (script.clone(), prefs.get_params(&id))) .collect(); let msg = ServerMessage::BulbState { id, mode, prefs }; if let Err(e) = server_message.send(msg) { error!("broadcast channel error: {e}"); return; } } } request = client_message.recv() => { let request = match request { Ok(r) => r, Err(_) => continue, }; match request.message { ClientMessage::SetBulbColor { id, color } => { manager.send_command(BulbCommand::SetColor(BulbSelector::Id(id), color)).await; } ClientMessage::SetBulbPower { id, power } => { manager.send_command(BulbCommand::SetPower(BulbSelector::Id(id), power)).await; } ClientMessage::GetBulbs => { if let Err(e) = request.response.send(ServerMessage::BulbMap(config.bulb_map.clone())).await { error!("GetBulbs response channel error: {e}"); return; } for (id, mode) in manager.bulbs().await.clone().into_iter() { let prefs = scripts.iter_mut() .map(|(script, prefs)| (script.clone(), prefs.get_params(&id))) .collect(); let msg = ServerMessage::BulbState { id, mode, prefs }; if let Err(e) = request.response.send(msg).await { error!("GetBulbs response channel error: {e}"); return; } } } ClientMessage::SetBulbPref { bulb, script, name, value } => { let Some(s) = scripts.get_mut(&script) else { continue; }; s.set_param(&bulb, &name, value.clone()); // TODO handle error lights_state.update(move |state| { state.script_prefs .entry(script).or_default() .entry(bulb).or_default() .kvs.insert(name, value); }).await.expect("failed to persist lights state"); } _ => {} } } } } }