eq3_max_cube_rs/
lib.rs

1#![crate_name = "eq3_max_cube_rs"]
2
3use anyhow::{anyhow, Result};
4use async_std::io::BufReader;
5use async_std::net::{TcpStream, ToSocketAddrs};
6use async_std::prelude::*;
7use log::debug;
8
9pub mod messages;
10
11use messages::{from_message_m, Device, DeviceConfig, DeviceMode, Devices, Rooms};
12use serde::Serialize;
13
14use crate::messages::from_message_l;
15
16/// MaxCube represtents a MAX! Cube Gateway.
17/// All operations to the devices shall be triggert from hier.
18#[derive(Debug, Serialize)]
19pub struct MaxCube {
20    /// Socket connection to Cube. The connection will be kept alive.
21    #[serde(skip_serializing)]
22    stream: TcpStream,
23
24    /// A list to all rooms (groups)
25    pub rooms: Rooms,
26
27    /// A list to all devices
28    pub devices: Devices,
29}
30
31impl MaxCube {
32    /// starts a connection to MAX! Cube gateway.
33    /// The connection will be kept alive.
34    /// After successful connection, the cube will send back the meta data and status data of the whole system
35    /// immediately. The data will be decoded and stored in this structure.
36    /// # Examples
37    ///
38    /// ```
39    /// use std::net::SocketAddr;
40    ///
41    /// let cube = MaxCube::new(&SocketAddr::from(([172, 22, 51, 191], 62910))).await.unwrap();
42    /// println!("{:?}", cube);
43    /// ```
44    pub async fn new<A>(addr: A) -> Result<Self>
45    where
46        A: ToSocketAddrs,
47    {
48        let stream = TcpStream::connect(addr).await?;
49
50        let mut cube = MaxCube {
51            stream,
52            rooms: Rooms::new(),
53            devices: Devices::new(),
54        };
55
56        // Sequence:
57        // Receive: H-Message, M-Message (multiple), C-Message (multiple), F-Message, L-Message
58        // Only M- and L-Message will be proceed.
59        // All the content after L-Message will be ignored.
60
61        // the Max Cube will reply with meta data and status data immediately after connection
62        let mut reader = BufReader::new(&cube.stream);
63
64        loop {
65            let mut received = String::new();
66            reader.read_line(&mut received).await?;
67            let received = received.replace("\r\n", "");
68            debug!("{:?}", received);
69
70            if received.starts_with('L') {
71                from_message_l(&received, &mut cube.devices)?;
72                break;
73            } else if received.starts_with('M') {
74                (cube.rooms, cube.devices) = from_message_m(&received)?;
75            }
76        }
77
78        Ok(cube)
79    }
80
81    /// sets the thermostat with the rf_address to the manual mode and the given temperature.
82    /// # Examples
83    ///
84    /// ```
85    /// let mut cube = MaxCube::new(&SocketAddr::from(([172, 22, 51, 191], 62910))).await.unwrap();
86    /// cube.set_temperature(1763839, 21.0).await.unwrap();
87    /// ```
88    pub async fn set_temperature(&mut self, rf_address: u32, temperature: f64) -> Result<()> {
89        // the room id must be set, if the room id = 0, all thermostats will be set
90        // to the temperature.
91
92        let mut dev_conf = DeviceConfig::new();
93
94        let mut dev_it = self.devices.iter().filter(|e| {
95            if let Device::HeaterThermostat(ts) = e {
96                ts.rf_address == rf_address
97            } else {
98                false
99            }
100        });
101
102        if let Some(dev) = dev_it.next() {
103            if let Device::HeaterThermostat(ts) = dev {
104                dev_conf = dev_conf.set_room_id(ts.room_id);
105            } else {
106                return Err(anyhow!("Device type not supported."));
107            }
108        } else {
109            return Err(anyhow!("Device with RF address {} not found.", rf_address));
110        }
111
112        let cmd = dev_conf
113            .set_address(rf_address)
114            .set_mode(DeviceMode::Manual)
115            .set_temperature(temperature)
116            .build();
117
118        self.stream.write_all(cmd.as_bytes()).await?;
119        self.stream.flush().await?;
120
121        let mut resp = "".to_string();
122        let mut reader = BufReader::new(&self.stream);
123        reader.read_line(&mut resp).await?;
124
125        let resp_code = resp
126            .split(',')
127            .into_iter()
128            .collect::<Vec<_>>()
129            .get(1)
130            .ok_or(anyhow!("Response not well-formatted."))?
131            .parse::<u8>()?;
132
133        if resp_code == 0 {
134            Ok(())
135        } else {
136            Err(anyhow!("Device configuration failed."))
137        }
138    }
139}