switchbot_api/
device.rs

1use std::{
2    fmt::Display,
3    rc::{Rc, Weak},
4};
5
6use super::*;
7
8/// Represents a device.
9///
10/// For the details of fields, please refer to the [devices] section
11/// of the API documentation.
12///
13/// [devices]: https://github.com/OpenWonderLabs/SwitchBotAPI?tab=readme-ov-file#devices
14#[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    /// The device ID.
31    pub fn device_id(&self) -> &str {
32        &self.device_id
33    }
34
35    /// The device name.
36    /// This is the name configured in the SwitchBot app.
37    pub fn device_name(&self) -> &str {
38        &self.device_name
39    }
40
41    /// True if this device is an infrared remote device.
42    pub fn is_remote(&self) -> bool {
43        !self.remote_type.is_empty()
44    }
45
46    /// The device type.
47    /// This is empty if this is an infrared remote device.
48    pub fn device_type(&self) -> &str {
49        &self.device_type
50    }
51
52    /// The device type for an infrared remote device.
53    pub fn remote_type(&self) -> &str {
54        &self.remote_type
55    }
56
57    /// The parent Hub ID.
58    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    /// Send the `command` to the [SwitchBot API].
73    ///
74    /// Please also see the [`CommandRequest`].
75    ///
76    /// [SwitchBot API]: https://github.com/OpenWonderLabs/SwitchBotAPI
77    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}