use serde_json::json; use std::sync::{Arc, RwLock, Weak}; use std::{thread, time}; use uuid::Uuid; use webthing::{ Action, BaseAction, BaseEvent, BaseProperty, BaseThing, Thing, ThingsType, WebThingServer, }; use webthing::server::ActionGenerator; pub struct FadeAction(BaseAction); impl FadeAction { fn new( input: Option>, thing: Weak>>, ) -> FadeAction { FadeAction(BaseAction::new( Uuid::new_v4().to_string(), "fade".to_owned(), input, thing, )) } } impl Action for FadeAction { fn set_href_prefix(&mut self, prefix: String) { self.0.set_href_prefix(prefix) } fn get_id(&self) -> String { self.0.get_id() } fn get_name(&self) -> String { self.0.get_name() } fn get_href(&self) -> String { self.0.get_href() } fn get_status(&self) -> String { self.0.get_status() } fn get_time_requested(&self) -> String { self.0.get_time_requested() } fn get_time_completed(&self) -> Option { self.0.get_time_completed() } fn get_input(&self) -> Option> { self.0.get_input() } fn get_thing(&self) -> Option>>> { self.0.get_thing() } fn set_status(&mut self, status: String) { self.0.set_status(status) } fn start(&mut self) { self.0.start() } fn perform_action(&mut self) { let thing = self.get_thing(); if thing.is_none() { return; } let thing = thing.unwrap(); let input = self.get_input().unwrap(); let name = self.get_name(); let id = self.get_id(); thread::spawn(move || { thread::sleep(time::Duration::from_millis( input.get("duration").unwrap().as_u64().unwrap(), )); let thing = thing.clone(); let mut thing = thing.write().unwrap(); let _ = thing.set_property( "brightness".to_owned(), input.get("brightness").unwrap().clone(), ); thing.add_event(Box::new(BaseEvent::new( "overheated".to_owned(), Some(json!(102)), ))); thing.finish_action(name, id); }); } fn cancel(&mut self) { self.0.cancel() } fn finish(&mut self) { self.0.finish() } } struct Generator; impl ActionGenerator for Generator { fn generate( &self, thing: Weak>>, name: String, input: Option<&serde_json::Value>, ) -> Option> { let input = match input { Some(v) => v.as_object().cloned(), None => None, }; let name: &str = &name; match name { "fade" => Some(Box::new(FadeAction::new(input, thing))), _ => None, } } } fn make_thing() -> Arc>> { let mut thing = BaseThing::new( "urn:dev:ops:my-lamp-1234".to_owned(), "My Lamp".to_owned(), Some(vec!["OnOffSwitch".to_owned(), "Light".to_owned()]), Some("A web connected lamp".to_owned()), ); let on_description = json!({ "@type": "OnOffProperty", "title": "On/Off", "type": "boolean", "description": "Whether the lamp is turned on" }); let on_description = on_description.as_object().unwrap().clone(); thing.add_property(Box::new(BaseProperty::new( "on".to_owned(), json!(true), None, Some(on_description), ))); let brightness_description = json!({ "@type": "BrightnessProperty", "title": "Brightness", "type": "integer", "description": "The level of light from 0-100", "minimum": 0, "maximum": 100, "unit": "percent" }); let brightness_description = brightness_description.as_object().unwrap().clone(); thing.add_property(Box::new(BaseProperty::new( "brightness".to_owned(), json!(50), None, Some(brightness_description), ))); let fade_metadata = json!({ "title": "Fade", "description": "Fade the lamp to a given level", "input": { "type": "object", "required": [ "brightness", "duration" ], "properties": { "brightness": { "type": "integer", "minimum": 0, "maximum": 100, "unit": "percent" }, "duration": { "type": "integer", "minimum": 1, "unit": "milliseconds" } } } }); let fade_metadata = fade_metadata.as_object().unwrap().clone(); thing.add_available_action("fade".to_owned(), fade_metadata); let overheated_metadata = json!({ "description": "The lamp has exceeded its safe operating temperature", "type": "number", "unit": "degree celsius" }); let overheated_metadata = overheated_metadata.as_object().unwrap().clone(); thing.add_available_event("overheated".to_owned(), overheated_metadata); Arc::new(RwLock::new(Box::new(thing))) } #[actix_rt::main] async fn main() -> std::io::Result<()> { env_logger::init(); let thing = make_thing(); // If adding more than one thing, use ThingsType::Multiple() with a name. // In the single thing case, the thing's name will be broadcast. let mut server = WebThingServer::new( ThingsType::Single(thing), Some(8888), None, None, Box::new(Generator), None, None, ); server.start(None).await }