Files
hemma/backend/src/tasks/lights.rs
2023-12-03 17:52:38 +01:00

126 lines
4.7 KiB
Rust

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<ScriptId, HashMap<BulbId, BulbPrefs>>,
}
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<LightsState> = 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<ScriptId, Box<dyn LightScript + Send>> = 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");
}
_ => {}
}
}
}
}
}