1use std::{
2 fmt::Display,
3 rc::{Rc, Weak},
4};
5
6use super::*;
7
8#[derive(Debug, serde::Deserialize)]
15#[serde(rename_all = "camelCase")]
16pub struct Device {
17 device_id: String,
18 device_name: String,
19 #[serde(default)]
20 device_type: String,
21 #[serde(default)]
22 remote_type: String,
23 hub_device_id: String,
24
25 #[serde(skip)]
26 service: Weak<SwitchBotService>,
27}
28
29impl Device {
30 pub fn device_id(&self) -> &str {
32 &self.device_id
33 }
34
35 pub fn device_name(&self) -> &str {
38 &self.device_name
39 }
40
41 pub fn is_remote(&self) -> bool {
43 !self.remote_type.is_empty()
44 }
45
46 pub fn device_type(&self) -> &str {
49 &self.device_type
50 }
51
52 pub fn remote_type(&self) -> &str {
54 &self.remote_type
55 }
56
57 pub fn hub_device_id(&self) -> &str {
59 &self.hub_device_id
60 }
61
62 fn service(&self) -> anyhow::Result<Rc<SwitchBotService>> {
63 self.service
64 .upgrade()
65 .ok_or_else(|| anyhow::anyhow!("The service is dropped"))
66 }
67
68 pub(crate) fn set_service(&mut self, service: &Rc<SwitchBotService>) {
69 self.service = Rc::downgrade(service);
70 }
71
72 pub async fn command(&self, command: &CommandRequest) -> anyhow::Result<()> {
78 self.service()?.command(self.device_id(), command).await
79 }
80}
81
82impl Display for Device {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 if f.alternate() {
85 writeln!(f, "Name: {}", self.device_name())?;
86 writeln!(f, "ID: {}", self.device_id())?;
87 if self.is_remote() {
88 write!(f, "Remote Type: {}", self.remote_type())?;
89 } else {
90 write!(f, "Type: {}", self.device_type())?;
91 }
92 return Ok(());
93 }
94 write!(
95 f,
96 "{} ({}, ID:{})",
97 self.device_name,
98 if self.is_remote() {
99 self.remote_type()
100 } else {
101 self.device_type()
102 },
103 self.device_id
104 )
105 }
106}