110 lines
3.8 KiB
Rust
110 lines
3.8 KiB
Rust
use std::thread;
|
|
|
|
use tokio::select;
|
|
use tokio::sync::broadcast;
|
|
use tokio::task::LocalSet;
|
|
|
|
use deckster_mode::shared::handler_communication::{HandlerCommand, HandlerEvent, HandlerInitializationError, InitialHandlerMessage, KeyEvent};
|
|
use deckster_mode::shared::path::KeyPath;
|
|
use deckster_mode::{send_command, DecksterHandler};
|
|
|
|
use crate::config::{GlobalConfig, KeyConfig, KeyMode};
|
|
use crate::ha_client::{HaClient, StateUpdate};
|
|
|
|
pub struct Handler {
|
|
events_sender: broadcast::Sender<HandlerEvent>,
|
|
}
|
|
|
|
impl Handler {
|
|
pub fn new(data: InitialHandlerMessage<GlobalConfig, KeyConfig, ()>) -> Result<Self, HandlerInitializationError> {
|
|
let events_sender = broadcast::Sender::<HandlerEvent>::new(5);
|
|
let mut subscribed_entity_ids = Vec::new();
|
|
|
|
for c in data.key_configs.values() {
|
|
subscribed_entity_ids.push(c.mode.state_entity_id().clone())
|
|
}
|
|
|
|
thread::spawn({
|
|
let events_sender = events_sender.clone();
|
|
|
|
move || {
|
|
let runtime = tokio::runtime::Builder::new_current_thread().enable_time().enable_io().build().unwrap();
|
|
let task_set = LocalSet::new();
|
|
|
|
let ha_client = task_set.block_on(
|
|
&runtime,
|
|
HaClient::new(data.global_config.base_url, data.global_config.token, subscribed_entity_ids),
|
|
);
|
|
|
|
for (path, config) in data.key_configs {
|
|
task_set.spawn_local(manage_key(events_sender.subscribe(), ha_client.clone(), path, config));
|
|
}
|
|
|
|
runtime.block_on(task_set)
|
|
}
|
|
});
|
|
|
|
Ok(Handler { events_sender })
|
|
}
|
|
}
|
|
|
|
impl DecksterHandler for Handler {
|
|
fn handle(&mut self, event: HandlerEvent) {
|
|
// No receivers being available can be ignored.
|
|
_ = self.events_sender.send(event);
|
|
}
|
|
}
|
|
|
|
async fn manage_key(mut events: broadcast::Receiver<HandlerEvent>, ha_client: HaClient, path: KeyPath, config: KeyConfig) {
|
|
let state_entity_id = config.mode.state_entity_id();
|
|
|
|
if let Some(state) = &config.disconnected_state {
|
|
send_command(HandlerCommand::SetKeyStyle {
|
|
path: path.clone(),
|
|
value: config.style.get(state).cloned(),
|
|
})
|
|
}
|
|
|
|
let mut state_updates = ha_client.subscribe_to_state_updates();
|
|
|
|
loop {
|
|
select! {
|
|
Ok(update) = state_updates.recv() => {
|
|
match update {
|
|
StateUpdate::Disconnected => {
|
|
if let Some(state) = &config.disconnected_state {
|
|
send_command(HandlerCommand::SetKeyStyle {
|
|
path: path.clone(),
|
|
value: config.style.get(state).cloned()
|
|
})
|
|
}
|
|
}
|
|
StateUpdate::Actual(update) => {
|
|
if &update.entity_id == state_entity_id {
|
|
send_command(HandlerCommand::SetKeyStyle {
|
|
path: path.clone(),
|
|
value: config.style.get(&update.state).cloned()
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Ok(HandlerEvent::Key { path: p, event }) = events.recv() => {
|
|
if p != path {
|
|
continue
|
|
}
|
|
|
|
if let KeyEvent::Press = event {
|
|
match &config.mode {
|
|
KeyMode::Toggle { entity_id } => {
|
|
ha_client.toggle_entity(entity_id).await;
|
|
}
|
|
KeyMode::Button { button_entity_id, .. } => {
|
|
ha_client.press_button_entity(button_entity_id).await;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|