use crate::task::Task; use crate::events::*; use crate::properties::*; use paste::paste; #[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(PropertyID, 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(prop_id!(System::NetworkOnline), 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); } } } pub mod props { use crate::property_namespace; property_namespace!( Scenes, Current => "", All => Vec::new() ); } use crate::scenes::props::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.set_property(Scenes::Current, startup_scene.name); let mut scene_list = Vec::new(); for scene in self.scenes.iter() { scene_list.push(Variant::String(scene.name.to_string())); } bus.set_property(Scenes::All, scene_list); } fn on_property_change(&mut self, key: PropertyID, value: &Variant, bus: &mut EventBus) { match (key, value) { (prop_id!(Scenes::Current), Variant::String(ref 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(Scenes::Current.new_property_change(scene.name)) } }, _ => () } }*/ } } } } use crate::prop_id;