use std::str::FromStr; use crate::task::Task; use crate::events::*; #[derive(Debug, PartialEq, Eq, Clone)] struct Scene { name: &'static str, patterns: Vec<&'static str>, trigger: Trigger } #[derive(Debug, PartialEq, Eq, Clone)] enum Trigger { Startup, PropertyEquals(&'static str, Variant) } pub struct Sequencer { scenes: Vec, cur_scene: String } impl Sequencer { pub fn new() -> Self { Sequencer { cur_scene: String::new(), scenes: vec![ Scene { name: "Start", patterns: vec!["Idle"], trigger: Trigger::Startup }, Scene { name: "Online", patterns: vec!["Idle"], trigger: Trigger::PropertyEquals("system.network.online", Variant::Boolean(true)) } ] } } fn get_scene(&self, name: &String) -> Option<&Scene> { for scene in self.scenes.iter() { if scene.name == name { return Some(scene); } } return None; } fn apply_scene(&mut self, name: &String, bus: &mut EventBus) { if let Some(dst_tasks) = self.get_scene(name) { if let Some(src_tasks) = self.get_scene(&self.cur_scene) { let stop_queue = src_tasks.patterns.iter().filter(|i| !dst_tasks.patterns.contains(i)); let start_queue = dst_tasks.patterns.iter().filter(|i| !src_tasks.patterns.contains(i)); log::info!("Switching scene from {} to {}", self.cur_scene, name); for stop in stop_queue { bus.push(Event::new_stop_thing(stop)); } for start in start_queue { bus.push(Event::new_start_thing(start)); } } else { log::info!("Starting new scene {}", name); log::info!("start={:?}", dst_tasks.patterns); for start in dst_tasks.patterns.iter() { bus.push(Event::new_start_thing(start)); } } self.cur_scene = name.clone(); } else { panic!("Could not apply scene {:?} scenes={:?}", name, self.scenes); } } } impl Task for Sequencer { fn start(&mut self, bus: &mut EventBus) { log::info!("Starting sequencer!!!"); let startup_scene = self.scenes.iter().filter(|i| { i.trigger == Trigger::Startup }).next().unwrap(); bus.push(Event::new_property_change("scenes.current", startup_scene.name)); } fn on_property_change(&mut self, key: &'static str, value: &Variant, bus: &mut EventBus) { match (key, value) { ("scenes.current", Variant::String(scene_name)) => { log::info!("Applying scene"); self.apply_scene(scene_name, bus); }, (key, value) => { for scene in self.scenes.iter() { match scene.trigger { Trigger::PropertyEquals(trigger_key, ref trigger_value) => { if trigger_key == key && trigger_value == value { log::info!("Triggering scene {}", scene.name); bus.push(Event::new_property_change("scenes.current", scene.name)) } }, _ => () } } } _ => () } } }