1#[derive(Debug, Clone)]
13pub struct Appartement {
14 inner: std::sync::Arc<std::sync::Mutex<InnerAppartement>>,
15}
16
17impl Appartement {
18 pub fn connect<S>(host: S, user: S, password: S) -> Result<Appartement>
21 where
22 S: Into<String>,
23 {
24 let appt = Appartement {
26 inner: std::sync::Arc::new(std::sync::Mutex::new(InnerAppartement {
27 api: RawApi::connect(host, user, password)?,
28 zones: vec![],
29 thread: std::sync::Arc::new(std::sync::Mutex::new(false)),
30 })),
31 };
32
33 appt.inner.lock()?.update_structure()?;
35
36 Ok(appt)
37 }
38
39 pub fn get_zones(&self) -> Result<Vec<Zone>> {
45 Ok(self.inner.lock()?.zones.clone())
46 }
47
48 pub fn update_all(&self) -> Result<Vec<Zone>> {
54 self.inner.lock()?.update_structure()?;
55 Ok(self.inner.lock()?.zones.clone())
56 }
57
58 pub fn set_value(&self, zone: usize, group: Option<usize>, value: Value) -> Result<()> {
59 self.inner.lock()?.set_value(zone, group, value)
60 }
61
62 pub fn event_channel(&self) -> Result<std::sync::mpsc::Receiver<Event>> {
68 if *self.inner.lock()?.thread.lock()? == true {
70 *self.inner.lock()?.thread.lock()? = false;
71 }
72
73 let (recv, status) = self.inner.lock()?.api.new_event_channel()?;
75
76 let (inp, out) = std::sync::mpsc::channel();
78
79 let internal_status = status.clone();
81 let appr = self.inner.clone();
82
83 std::thread::spawn(move || loop {
84 let event = match recv.recv() {
86 Ok(e) => e,
87 Err(_) => break,
88 };
89
90 if *internal_status.lock().unwrap() == false {
92 break;
93 }
94
95 let events = appr.lock().unwrap().expand_value(event).unwrap();
97
98 for event in events {
99 let event = appr.lock().unwrap().update_event_value(event).unwrap();
101
102 appr.lock().unwrap().zones.iter_mut().for_each(|z| {
104 if z.id == event.zone {
106 z.groups.iter_mut().for_each(|g| {
107 if g.typ == event.typ && g.id == event.group {
109 g.status = event.value.clone();
110 }
111 });
112 }
113 });
114
115 match inp.send(event) {
117 Ok(_) => {}
118 Err(_) => break,
119 }
120 }
121 });
122
123 self.inner.lock()?.thread = status;
125 Ok(out)
126 }
127}
128
129#[derive(Debug)]
130struct InnerAppartement {
131 api: RawApi,
132 zones: Vec<Zone>,
133 thread: std::sync::Arc<std::sync::Mutex<bool>>,
134}
135
136impl InnerAppartement {
137 fn set_value(&mut self, zone: usize, group: Option<usize>, value: Value) -> Result<()> {
138 if let Some(grp) = group {
140 match value {
141 Value::Light(light) => {
143 if light < 0.5 {
144 self.api.call_action(zone, Action::LightOff(grp))?;
145 } else {
146 self.api.call_action(zone, Action::LightOn(grp))?;
147 }
148 }
149 Value::Shadow(open, angle) => {
151 if open <= 0.1 {
152 self.api.call_action(zone, Action::ShadowUp(grp))?;
153 }
154 if open >= 0.9 && angle <= 0.1 {
155 self.api.call_action(zone, Action::ShadowDown(grp))?;
156 } else {
157 let devices = self
160 .zones
161 .iter()
162 .find(|z| z.id == zone)
163 .ok_or("Not a valid zone id given")?
164 .groups
165 .iter()
166 .find(|g| g.id == grp)
167 .ok_or("Not a valid group given")?
168 .devices
169 .iter()
170 .filter(|d| d.device_type == DeviceType::Shadow)
171 .clone();
172
173 for dev in devices {
174 self.api.set_shadow_device_open(dev.id.clone(), open)?;
175 self.api.set_shadow_device_angle(dev.id.clone(), angle)?;
176 }
177
178 self.zones
180 .iter_mut()
181 .find(|z| z.id == zone)
182 .ok_or("No valid zone given")?
183 .groups
184 .iter_mut()
185 .find(|g| g.id == grp)
186 .ok_or("Not a valid group given")?
187 .status = value;
188 }
189 }
190 Value::Unknown => (),
191 }
192 }
193 else {
195 match value {
196 Value::Light(light) => {
198 if light < 0.5 {
199 self.api.call_action(zone, Action::AllLightOff)?;
200 } else {
201 self.api.call_action(zone, Action::AllLightOn)?;
202 }
203 }
204 Value::Shadow(open, angle) => {
206 if open <= 0.1 {
207 self.api.call_action(zone, Action::AllShadowUp)?;
208 }
209 if open >= 0.9 && angle <= 0.1 {
210 self.api.call_action(zone, Action::AllShadowDown)?;
211 } else {
212 let devices = self
216 .zones
217 .iter()
218 .find(|z| z.id == zone)
219 .ok_or("Not a valid zone id given")?
220 .groups
221 .iter()
222 .map(|g| g.devices.clone())
223 .flatten()
224 .collect::<Vec<Device>>()
225 .into_iter()
226 .filter(|d| d.device_type == DeviceType::Shadow);
227
228 for dev in devices {
229 self.api.set_shadow_device_open(dev.id.clone(), open)?;
230 self.api.set_shadow_device_angle(dev.id.clone(), angle)?;
231 }
232
233 self.zones
235 .iter_mut()
236 .find(|z| z.id == zone)
237 .ok_or("Not a valid zone id given")?
238 .groups
239 .iter_mut()
240 .filter(|g| g.typ == Type::Shadow)
241 .for_each(|g| g.status = value.clone());
242 }
243 }
244 Value::Unknown => (),
245 }
246 }
247
248 Ok(())
249 }
250
251 fn expand_value(&self, event: Event) -> Result<Vec<Event>> {
252 if event.typ == Type::Shadow
256 && (event.action == Action::ShadowStepOpen || event.action == Action::ShadowStepClose)
257 {
258 let groups: Vec<usize> = self
260 .zones
261 .iter()
262 .find(|z| z.id == event.zone)
263 .ok_or("No matching zone available")?
264 .groups
265 .iter()
266 .filter(|g| g.typ == Type::Shadow)
267 .map(|g| g.id)
268 .collect();
269
270 return Ok(groups
272 .iter()
273 .map(|g| {
274 let mut e = event.clone();
275 e.group = *g;
276 e
277 })
278 .collect());
279 }
280
281 Ok(vec![event])
282 }
283
284 fn update_event_value(&self, event: Event) -> Result<Event> {
285 let mut event = event;
287
288 event.value = self.update_value(event.value, &event.typ, event.zone, event.group)?;
290 Ok(event)
291 }
292
293 fn update_value(&self, value: Value, typ: &Type, zone: usize, group: usize) -> Result<Value> {
294 if value != Value::Unknown {
296 return Ok(value);
297 }
298
299 if typ == &Type::Shadow {
301 let device = self
303 .zones
304 .iter()
305 .find(|z| z.id == zone)
306 .ok_or("No matching zone found")?
307 .groups
308 .iter()
309 .find(|g| g.id == group && g.typ == Type::Shadow)
310 .ok_or("No matching group found")?
311 .devices
312 .get(0)
313 .ok_or("No devices available")?;
314
315 let open = self.api.get_shadow_device_open(&device.id)?;
317 let angle = self.api.get_shadow_device_angle(&device.id)?;
318
319 return Ok(Value::Shadow(open, angle));
321 }
322
323 Ok(value)
324 }
325
326 fn update_structure(&mut self) -> Result<()> {
327 let devices = self.api.get_devices()?;
328 let mut zones: Vec<Zone> = self
329 .api
330 .get_zones()?
331 .into_iter()
332 .filter(|z| z.id != 0 && z.id != 65534)
333 .collect();
334
335 for zone in &mut zones {
336 for typ in &zone.types {
338 let scenes = self.api.get_scenes(zone.id, typ.clone())?;
340
341 let mut scene_groups = Group::from_scenes(&scenes, zone.id, &typ);
343
344 let action;
347 if typ == &Type::Shadow {
348 action = Action::Unknown;
349 } else {
350 let lcs = self.api.get_last_called_scene(zone.id, typ.clone())?;
352 action = Action::new(typ.clone(), lcs);
354 }
355
356 scene_groups
358 .iter_mut()
359 .for_each(|g| g.status = Value::from_action(action.clone(), g.id));
360
361 zone.groups.append(&mut scene_groups);
363 }
364
365 for group in &mut zone.groups {
367 for device in devices.iter().filter(|d| {
370 d.device_type == DeviceType::Light || d.device_type == DeviceType::Shadow
371 }) {
372 if group.id == 0
374 && device.zone_id == group.zone_id
375 && group.typ == device.button_type
376 {
377 group.devices.push(device.clone());
378 }
379 else if device.zone_id == group.zone_id && group.typ == device.button_type {
381 let _ = self
383 .api
384 .get_device_scene_mode(device.id.clone(), group.id)
385 .and_then(|dsm| {
386 if !dsm.dont_care {
388 group.devices.push(device.clone());
389 }
390 Ok(())
391 });
392 }
393 }
394 }
395 }
396
397 self.zones = zones.clone();
398
399 for zone in &mut zones {
400 for group in zone.groups.iter_mut().filter(|g| g.typ == Type::Shadow) {
402 let status = self.update_value(group.status.clone(), &group.typ, zone.id, group.id);
404
405 match status {
407 Ok(v) => group.status = v,
408 Err(_) => continue,
409 }
410 }
411 }
412
413 self.zones = zones;
414
415 Ok(())
416 }
417}
418
419impl Drop for InnerAppartement {
420 fn drop(&mut self) {
421 #[allow(unused_must_use)]
423 {
424 self.thread.lock().map(|mut v| *v = false);
425 }
426 }
427}
428
429#[derive(Debug, Clone)]
433pub struct RawApi {
434 host: String,
435 user: String,
436 password: String,
437 token: String,
438}
439
440impl RawApi {
441 pub fn connect<S>(host: S, user: S, password: S) -> Result<Self>
443 where
444 S: Into<String>,
445 {
446 let mut api = RawApi {
447 host: host.into(),
448 user: user.into(),
449 password: password.into(),
450 token: String::from(""),
451 };
452
453 api.login()?;
454
455 Ok(api)
456 }
457
458 fn login(&mut self) -> Result<()> {
459 let client = reqwest::Client::builder()
461 .danger_accept_invalid_certs(true)
462 .build()?;
463
464 let mut response = client
466 .get(&format!("https://{}:8080/json/system/login", self.host))
467 .query(&[("user", &self.user), ("password", &self.password)])
468 .send()?;
469
470 let json: serde_json::Value = response.json()?;
472
473 self.token = json
475 .get("result")
476 .ok_or("No result in Json response")?
477 .get("token")
478 .ok_or("No token in Json response")?
479 .as_str()
480 .ok_or("Token is not a String")?
481 .to_string();
482
483 Ok(())
484 }
485
486 pub fn generic_request<S>(
491 &self,
492 request: S,
493 parameter: Option<Vec<(&str, &str)>>,
494 ) -> Result<serde_json::Value>
495 where
496 S: Into<String>,
497 {
498 let parameter = match parameter {
500 None => vec![("token", self.token.as_str())],
501 Some(mut p) => {
502 p.push(("token", &self.token));
503 p
504 }
505 };
506
507 let client = reqwest::Client::builder()
509 .danger_accept_invalid_certs(true)
510 .timeout(None)
511 .build()?;
512
513 let mut response = client
515 .get(&format!(
516 "https://{}:8080/json/{}",
517 self.host,
518 request.into()
519 ))
520 .query(¶meter)
521 .send()?;
522
523 let mut json: serde_json::Value = response.json()?;
524
525 if !json
527 .get("ok")
528 .ok_or("No ok in Json response")?
529 .as_bool()
530 .ok_or("No boolean ok code")?
531 {
532 return Err("Request failed, no ok code received".into());
533 }
534
535 match json.get_mut("result") {
537 None => Ok(serde_json::json!(null)),
538 Some(j) => Ok(j.take()),
539 }
540 }
541
542 pub fn new_event_channel(
544 &self,
545 ) -> Result<(
546 std::sync::mpsc::Receiver<Event>,
547 std::sync::Arc<std::sync::Mutex<bool>>,
548 )> {
549 let thread_status = std::sync::Arc::new(std::sync::Mutex::new(true));
551
552 self.generic_request(
554 "event/subscribe",
555 Some(vec![("name", "callScene"), ("subscriptionID", "911")]),
556 )?;
557
558 let (send, recv) = std::sync::mpsc::channel();
560
561 let this = self.clone();
563 let ts = thread_status.clone();
564 std::thread::spawn(move || loop {
565 let res = this.generic_request(
567 "event/get",
568 Some(vec![("timeout", "3000"), ("subscriptionID", "911")]),
569 );
570
571 if *ts.lock().unwrap() == false {
573 break;
574 }
575
576 #[allow(unused_must_use)]
578 {
579 send.send(res);
581 }
582 });
583
584 let (inp, out) = std::sync::mpsc::channel();
586
587 let this = self.clone();
589 let ts = thread_status.clone();
590 std::thread::spawn(move || loop {
591 #[allow(unused_must_use)]
593 {
594 let res = recv.recv();
596
597 if *ts.lock().unwrap() == false {
599 break;
600 }
601
602 res.and_then(|res| {
603 res.and_then(|mut v| {
605 this.extract_events(&mut v).and_then(|es| {
607 es.into_iter().for_each(|e| {
609 let _tmp = inp.send(e);
610 });
611 Ok(())
612 });
613 Ok(())
614 });
615 Ok(())
616 });
617 }
618 });
619
620 Ok((out, thread_status))
621 }
622
623 fn extract_events(&self, json: &mut serde_json::Value) -> Result<Vec<Event>> {
624 let events = json
625 .get_mut("events")
626 .ok_or("No events available")?
627 .as_array_mut()
628 .take()
629 .ok_or("Events not in array")?;
630
631 let mut out = vec![];
632
633 for e in events {
634 let name = e
635 .get("name")
636 .ok_or("No name for event")?
637 .as_str()
638 .ok_or("Event name not a string")?
639 .to_string();
640 let props = e
641 .get_mut("properties")
642 .ok_or("No properties in event")?
643 .take();
644
645 let mut event: Event = serde_json::from_value(props)?;
646 event.name = name;
647
648 event.action = Action::from(event.clone());
649
650 event.group = Group::group_id_from_scene_id(event.scene);
651
652 event.value = Value::from_action(event.action.clone(), event.group);
653
654 out.push(event);
655 }
656
657 Ok(out)
658 }
659
660 pub fn get_appartement_name(&self) -> Result<String> {
662 Ok(self
664 .generic_request("apartment/getName", None)?
665 .get("result")
666 .ok_or("No result in Json response")?
667 .get("name")
668 .ok_or("No name in Json response")?
669 .as_str()
670 .ok_or("Name is not a String")?
671 .to_string())
672 }
673
674 pub fn set_appartement_name<S>(&self, new_name: S) -> Result<bool>
676 where
677 S: Into<String>,
678 {
679 Ok(self
681 .generic_request(
682 "apartment/getName",
683 Some(vec![("newName", &new_name.into())]),
684 )?
685 .get("ok")
686 .ok_or("No ok in Json response")?
687 .as_bool()
688 .ok_or("No boolean ok code")?)
689 }
690
691 pub fn get_zones(&self) -> Result<Vec<Zone>> {
693 let mut json = self.generic_request("apartment/getReachableGroups", None)?;
694
695 let json = json
697 .get_mut("zones")
698 .ok_or("No zones in Json response")?
699 .take();
700
701 Ok(serde_json::from_value(json)?)
703 }
704
705 pub fn get_zone_name(&self, id: usize) -> Result<String> {
707 let res = self.generic_request("zone/getName", Some(vec![("id", &id.to_string())]))?;
708
709 let name = res
711 .get("name")
712 .ok_or("No name returned")?
713 .as_str()
714 .ok_or("No String value available")?;
715
716 Ok(name.to_string())
717 }
718
719 pub fn get_devices(&self) -> Result<Vec<Device>> {
721 let res = self.generic_request("apartment/getDevices", None)?;
722
723 Ok(serde_json::from_value(res)?)
724 }
725
726 pub fn get_device_scene_mode<S>(&self, device: S, scene_id: usize) -> Result<SceneMode>
728 where
729 S: Into<String>,
730 {
731 let json = self.generic_request(
732 "device/getSceneMode",
733 Some(vec![
734 ("dsid", &device.into()),
735 ("sceneID", &scene_id.to_string()),
736 ]),
737 )?;
738
739 Ok(serde_json::from_value(json)?)
741 }
742
743 pub fn get_circuits(&self) -> Result<Vec<Circut>> {
745 let mut res = self.generic_request("apartment/getCircuits", None)?;
746
747 let res = res
748 .get_mut("circuits")
749 .ok_or("No circuits available")?
750 .take();
751
752 Ok(serde_json::from_value(res)?)
753 }
754
755 pub fn get_scenes(&self, zone: usize, typ: Type) -> Result<Vec<usize>> {
757 let typ = typ as usize;
759
760 let mut json = self.generic_request(
761 "zone/getReachableScenes",
762 Some(vec![
763 ("id", &zone.to_string()),
764 ("groupID", &typ.to_string()),
765 ]),
766 )?;
767
768 let json = json
770 .get_mut("reachableScenes")
771 .ok_or("No scenes returned")?
772 .take();
773
774 Ok(serde_json::from_value(json)?)
776 }
777
778 pub fn get_last_called_scene(&self, zone: usize, typ: Type) -> Result<usize> {
780 let typ = typ as usize;
782
783 let res = self.generic_request(
784 "zone/getLastCalledScene",
785 Some(vec![
786 ("id", &zone.to_string()),
787 ("groupID", &typ.to_string()),
788 ]),
789 )?;
790
791 let number = res
793 .get("scene")
794 .ok_or("No scene returned")?
795 .as_u64()
796 .ok_or("No scene number available")?;
797
798 Ok(number as usize)
799 }
800
801 pub fn call_scene(&self, zone: usize, typ: Type, scene: usize) -> Result<()> {
803 let typ = typ as usize;
805
806 self.generic_request(
807 "zone/callScene",
808 Some(vec![
809 ("id", &zone.to_string()),
810 ("groupID", &typ.to_string()),
811 ("sceneNumber", &scene.to_string()),
812 ]),
813 )?;
814
815 Ok(())
816 }
817
818 pub fn call_action(&self, zone: usize, action: Action) -> Result<()> {
820 let (typ, scene) = action
822 .to_scene_type()
823 .ok_or("Action can't be transformed to scene command")?;
824 self.call_scene(zone, typ, scene)
825 }
826
827 pub fn get_shadow_device_open<S>(&self, device: S) -> Result<f32>
829 where
830 S: Into<String>,
831 {
832 let res = self.generic_request(
834 "device/getOutputValue",
835 Some(vec![("dsid", &device.into()), ("offset", "2")]),
836 )?;
837
838 if res
840 .get("offset")
841 .ok_or("No offset returnes")?
842 .as_u64()
843 .ok_or("The offset is not a number")?
844 != 2
845 {
846 return Err(Error::from("Wrong offset returned"));
847 }
848
849 let value = res
851 .get("value")
852 .ok_or("No value returnes")?
853 .as_u64()
854 .ok_or("The value is not a number")?;
855
856 let value = (value as f32) / 65535.0;
858
859 Ok(1.0 - value)
861 }
862
863 pub fn set_shadow_device_open<S>(&self, device: S, value: f32) -> Result<()>
865 where
866 S: Into<String>,
867 {
868 let value = value.max(0.0);
870
871 let value = value.min(1.0);
873
874 let value = 1.0 - value;
876
877 let value = (65535.0 * value) as usize;
879
880 self.generic_request(
882 "device/setOutputValue",
883 Some(vec![
884 ("dsid", &device.into()),
885 ("value", &format!("{}", value)),
886 ("offset", "2"),
887 ]),
888 )?;
889
890 Ok(())
891 }
892
893 pub fn get_shadow_device_angle<S>(&self, device: S) -> Result<f32>
895 where
896 S: Into<String>,
897 {
898 let res = self.generic_request(
900 "device/getOutputValue",
901 Some(vec![("dsid", &device.into()), ("offset", "4")]),
902 )?;
903
904 if res
906 .get("offset")
907 .ok_or("No offset returnes")?
908 .as_u64()
909 .ok_or("The offset is not a number")?
910 != 4
911 {
912 return Err(Error::from("Wrong offset returned"));
913 }
914
915 let value = res
917 .get("value")
918 .ok_or("No value returnes")?
919 .as_u64()
920 .ok_or("The value is not a number")?;
921
922 let value = (value as f32) / 65535.0;
924
925 Ok(value)
926 }
927
928 pub fn set_shadow_device_angle<S>(&self, device: S, value: f32) -> Result<()>
930 where
931 S: Into<String>,
932 {
933 let value = value.max(0.0);
935
936 let value = value.min(1.0);
938
939 let value = (255.0 * value) as usize;
941
942 self.generic_request(
944 "device/setOutputValue",
945 Some(vec![
946 ("dsid", &device.into()),
947 ("value", &format!("{}", value)),
948 ("offset", "4"),
949 ]),
950 )?;
951
952 Ok(())
953 }
954}
955
956fn from_str<'de, T, D>(deserializer: D) -> std::result::Result<T, D::Error>
959where
960 T: std::str::FromStr,
961 T::Err: std::fmt::Display,
962 D: serde::Deserializer<'de>,
963{
964 use serde::Deserialize;
965
966 let s = String::deserialize(deserializer)?;
967 T::from_str(&s).map_err(serde::de::Error::custom)
968}
969
970#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
977pub struct Event {
978 #[serde(default)]
979 pub name: String,
980
981 #[serde(alias = "zoneID", deserialize_with = "from_str")]
982 pub zone: usize,
983
984 #[serde(alias = "groupID", deserialize_with = "from_str")]
985 pub typ: Type,
986
987 #[serde(alias = "sceneID", deserialize_with = "from_str")]
988 pub scene: usize,
989
990 #[serde(alias = "originToken")]
991 pub token: String,
992
993 #[serde(alias = "originDSUID")]
994 pub dsuid: String,
995
996 #[serde(alias = "callOrigin")]
997 pub origin: String,
998
999 #[serde(default)]
1000 pub action: Action,
1001
1002 #[serde(default)]
1003 pub value: Value,
1004
1005 #[serde(default)]
1006 pub group: usize,
1007}
1008
1009#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1012pub struct Zone {
1013 #[serde(alias = "zoneID")]
1014 pub id: usize,
1015 pub name: String,
1016 #[serde(alias = "groups")]
1017 pub types: Vec<Type>,
1018 #[serde(default)]
1019 pub groups: Vec<Group>,
1020}
1021
1022#[derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr, PartialEq, Debug, Clone)]
1024#[repr(u8)]
1025pub enum Type {
1026 Unknown = 0,
1027 Light = 1,
1028 Shadow = 2,
1029 Heating = 3,
1030 Audio = 4,
1031 Video = 5,
1032 Joker = 8,
1033 Cooling = 9,
1034 Ventilation = 10,
1035 Window = 11,
1036 AirRecirculation = 12,
1037 TemperatureControl = 48,
1038 ApartmentVentilation = 64,
1039}
1040
1041impl From<u8> for Type {
1042 fn from(u: u8) -> Self {
1044 match u {
1045 1 => Type::Light,
1046 2 => Type::Shadow,
1047 3 => Type::Heating,
1048 4 => Type::Audio,
1049 5 => Type::Video,
1050 8 => Type::Joker,
1051 9 => Type::Cooling,
1052 10 => Type::Ventilation,
1053 11 => Type::Window,
1054 12 => Type::AirRecirculation,
1055 48 => Type::TemperatureControl,
1056 64 => Type::ApartmentVentilation,
1057 _ => Type::Unknown,
1058 }
1059 }
1060}
1061
1062impl std::str::FromStr for Type {
1064 type Err = std::num::ParseIntError;
1065
1066 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1067 let u = u8::from_str(s)?;
1068 Ok(Type::from(u))
1069 }
1070}
1071
1072#[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug, Clone)]
1074pub enum Action {
1075 AllLightOn,
1076 AllLightOff,
1077 LightOn(usize),
1078 LightOff(usize),
1079 AllShadowUp,
1080 AllShadowDown,
1081 ShadowUp(usize),
1082 ShadowDown(usize),
1083 AllShadowStop,
1084 ShadowStop(usize),
1085 ShadowStepOpen,
1086 ShadowStepClose,
1087 AllShadowSpecial1,
1088 AllShadowSpecial2,
1089 Unknown,
1090}
1091
1092impl Action {
1093 fn new(typ: Type, scene: usize) -> Action {
1094 if typ == Type::Light && scene == 0 {
1095 return Action::AllLightOff;
1096 }
1097
1098 if typ == Type::Light && scene == 5 {
1099 return Action::AllLightOn;
1100 }
1101
1102 if typ == Type::Shadow && scene == 0 {
1103 return Action::AllShadowDown;
1104 }
1105
1106 if typ == Type::Shadow && scene == 5 {
1107 return Action::AllShadowUp;
1108 }
1109
1110 if scene > 0 && scene < 5 {
1111 if typ == Type::Light {
1112 return Action::LightOff(scene);
1113 } else if typ == Type::Shadow {
1114 return Action::ShadowDown(scene);
1115 }
1116 }
1117
1118 if scene > 5 && scene < 9 {
1119 if typ == Type::Light {
1120 return Action::LightOn(scene - 5);
1121 } else if typ == Type::Shadow {
1122 return Action::ShadowUp(scene - 5);
1123 }
1124 }
1125
1126 if typ == Type::Shadow && scene == 55 {
1127 return Action::AllShadowStop;
1128 }
1129
1130 if typ == Type::Shadow && scene > 50 && scene < 55 {
1131 return Action::ShadowStop(scene - 51);
1132 }
1133
1134 if typ == Type::Shadow && scene == 42 {
1135 return Action::ShadowStepClose;
1136 }
1137
1138 if typ == Type::Shadow && scene == 43 {
1139 return Action::ShadowStepOpen;
1140 }
1141
1142 if typ == Type::Shadow && scene == 17 {
1143 return Action::AllShadowUp;
1144 }
1145
1146 if typ == Type::Shadow && scene == 18 {
1147 return Action::AllShadowSpecial1;
1148 }
1149
1150 if typ == Type::Shadow && scene == 19 {
1151 return Action::AllShadowSpecial2;
1152 }
1153
1154 Action::Unknown
1155 }
1156
1157 fn to_scene_type(&self) -> Option<(Type, usize)> {
1158 match self {
1159 Action::AllLightOff => Some((Type::Light, 0)),
1160 Action::AllLightOn => Some((Type::Light, 5)),
1161 Action::LightOff(v) => Some((Type::Light, *v)),
1162 Action::LightOn(v) => Some((Type::Light, v + 5)),
1163
1164 Action::AllShadowDown => Some((Type::Shadow, 0)),
1165 Action::AllShadowUp => Some((Type::Shadow, 5)),
1166 Action::AllShadowStop => Some((Type::Shadow, 55)),
1167 Action::AllShadowSpecial1 => Some((Type::Shadow, 18)),
1168 Action::AllShadowSpecial2 => Some((Type::Shadow, 19)),
1169
1170 Action::ShadowDown(v) => Some((Type::Shadow, *v)),
1171 Action::ShadowUp(v) => Some((Type::Shadow, v + 5)),
1172 Action::ShadowStop(v) => Some((Type::Shadow, v + 51)),
1173 Action::ShadowStepClose => Some((Type::Shadow, 42)),
1174 Action::ShadowStepOpen => Some((Type::Shadow, 43)),
1175
1176 Action::Unknown => None,
1177 }
1178 }
1179}
1180
1181impl Default for Action {
1182 fn default() -> Self {
1183 Action::Unknown
1184 }
1185}
1186
1187impl From<Event> for Action {
1188 fn from(e: Event) -> Self {
1189 Action::new(e.typ, e.scene)
1190 }
1191}
1192
1193#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
1196pub enum Value {
1197 Light(f32),
1198 Shadow(f32, f32),
1199 Unknown,
1200}
1201
1202impl Value {
1203 pub fn from_action(action: Action, _id: usize) -> Self {
1204 match action {
1205 Action::AllLightOn => Value::Light(1.0),
1206 Action::LightOn(_id) => Value::Light(1.0),
1207 Action::AllLightOff => Value::Light(0.0),
1208 Action::LightOff(_id) => Value::Light(0.0),
1209 Action::AllShadowUp => Value::Shadow(0.0, 1.0),
1210 Action::AllShadowDown => Value::Shadow(1.0, 0.0),
1211 Action::ShadowDown(_id) => Value::Shadow(1.0, 0.0),
1212 Action::ShadowUp(_id) => Value::Shadow(0.0, 1.0),
1213 _ => Value::Unknown,
1214 }
1215 }
1216}
1217
1218impl Default for Value {
1219 fn default() -> Self {
1220 Value::Unknown
1221 }
1222}
1223
1224#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1226pub struct Device {
1227 pub id: String,
1228 pub name: String,
1229 #[serde(alias = "zoneID")]
1230 pub zone_id: usize,
1231 #[serde(alias = "isPresent")]
1232 pub present: bool,
1233 #[serde(alias = "outputMode")]
1234 pub device_type: DeviceType,
1235 #[serde(alias = "groups")]
1236 pub types: Vec<Type>,
1237 #[serde(alias = "buttonActiveGroup")]
1238 pub button_type: Type,
1239}
1240
1241#[derive(Debug, Clone, serde::Serialize, PartialEq)]
1243pub enum DeviceType {
1244 Switch,
1245 Light,
1246 Tv,
1247 Shadow,
1248 Unknown,
1249}
1250
1251impl From<usize> for DeviceType {
1252 fn from(num: usize) -> Self {
1253 match num {
1254 0 => DeviceType::Switch,
1255 16 | 22 | 35 => DeviceType::Light,
1256 33 => DeviceType::Shadow,
1257 39 => DeviceType::Tv,
1258 _ => DeviceType::Unknown,
1259 }
1260 }
1261}
1262
1263impl<'de> serde::Deserialize<'de> for DeviceType {
1264 fn deserialize<D>(deserializer: D) -> std::result::Result<DeviceType, D::Error>
1265 where
1266 D: serde::Deserializer<'de>,
1267 {
1268 Ok(DeviceType::from(usize::deserialize(deserializer)?))
1269 }
1270}
1271
1272#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1274pub struct Circut {
1275 #[serde(alias = "dsid")]
1276 pub id: String,
1277 pub name: String,
1278 #[serde(alias = "isPresent")]
1279 pub present: bool,
1280 #[serde(alias = "isValid")]
1281 pub valid: bool,
1282}
1283
1284#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1286pub struct SceneMode {
1287 #[serde(alias = "sceneID")]
1288 pub scene: usize,
1289 #[serde(alias = "dontCare")]
1290 pub dont_care: bool,
1291 #[serde(alias = "localPrio")]
1292 pub local_prio: bool,
1293 #[serde(alias = "specialMode")]
1294 pub special_mode: bool,
1295 #[serde(alias = "flashMode")]
1296 pub flash_mode: bool,
1297 #[serde(alias = "ledconIndex")]
1298 pub led_con_index: usize,
1299}
1300
1301#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1303pub struct Group {
1304 id: usize,
1305 zone_id: usize,
1306 typ: Type,
1307 status: Value,
1308 devices: Vec<Device>,
1309}
1310
1311impl Group {
1312 pub fn new(id: usize, zone_id: usize, typ: Type) -> Self {
1313 Group {
1314 id,
1315 zone_id: zone_id,
1316 typ,
1317 devices: vec![],
1318 status: Value::default(),
1319 }
1320 }
1321
1322 pub fn group_id_from_scene_id(scene: usize) -> usize {
1323 if scene > 0 && scene < 5 {
1324 return scene;
1325 }
1326
1327 if scene > 5 && scene < 9 {
1328 return scene - 5;
1329 }
1330
1331 if scene > 50 && scene < 55 {
1332 return scene - 51;
1333 }
1334
1335 0
1336 }
1337
1338 pub fn from_scene(scene: usize, zone_id: usize, typ: &Type) -> Option<Group> {
1339 for x in 1..4 {
1341 if scene == x {
1342 return Some(Group::new(x, zone_id, typ.clone()));
1343 }
1344 }
1345
1346 if scene == 0 {
1348 return Some(Group::new(0, zone_id, typ.clone()));
1349 }
1350
1351 None
1352 }
1353
1354 pub fn from_scenes(scenes: &[usize], zone_id: usize, typ: &Type) -> Vec<Group> {
1355 let groups: Vec<Group> = scenes
1356 .iter()
1357 .filter_map(|s| Group::from_scene(*s, zone_id, typ))
1358 .collect();
1359
1360 if groups.len() > 1 {
1361 return groups.into_iter().filter(|g| g.id > 0).collect();
1362 }
1363
1364 return groups;
1365 }
1366}
1367
1368impl Default for Group {
1369 fn default() -> Self {
1370 Group {
1371 id: 0,
1372 zone_id: 0,
1373 typ: Type::Unknown,
1374 devices: vec![],
1375 status: Value::default(),
1376 }
1377 }
1378}
1379
1380#[derive(Debug)]
1382pub enum Error {
1383 Error(String),
1384 SerdeJson(serde_json::Error),
1385 Reqwest(reqwest::Error),
1386}
1387
1388type Result<T> = std::result::Result<T, Error>;
1390
1391impl std::fmt::Display for Error {
1392 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1393 match self {
1394 Error::Error(s) => write!(f, "{}", s),
1395 Error::SerdeJson(ref e) => e.fmt(f),
1396 Error::Reqwest(ref e) => e.fmt(f),
1397 }
1398 }
1399}
1400
1401impl std::error::Error for Error {
1402 fn cause(&self) -> Option<&dyn std::error::Error> {
1403 match self {
1404 Error::Error(_) => None,
1405 Error::SerdeJson(ref e) => Some(e),
1406 Error::Reqwest(ref e) => Some(e),
1407 }
1408 }
1409}
1410
1411impl From<&str> for Error {
1413 fn from(err: &str) -> Self {
1414 Error::Error(err.into())
1415 }
1416}
1417
1418impl From<serde_json::Error> for Error {
1420 fn from(err: serde_json::Error) -> Self {
1421 Error::SerdeJson(err)
1422 }
1423}
1424
1425impl From<reqwest::Error> for Error {
1427 fn from(err: reqwest::Error) -> Self {
1428 Error::Reqwest(err)
1429 }
1430}
1431
1432impl<T> From<std::sync::PoisonError<T>> for Error {
1434 fn from(_err: std::sync::PoisonError<T>) -> Self {
1435 Error::from("Poison error")
1436 }
1437}