diff --git a/src/command/request.rs b/src/command/request.rs index 5d148eb..5ae9282 100644 --- a/src/command/request.rs +++ b/src/command/request.rs @@ -67,6 +67,10 @@ impl CommandQuerySubtype { ), } } + + pub fn request(self) -> CommandRequest { + self.command + } } impl Deref for CommandQuerySubtype { @@ -87,6 +91,10 @@ impl CommandQueryCustom { command: CommandRequest::new(0, device_type, message_type, body), } } + + pub fn request(self) -> CommandRequest { + self.command + } } impl Deref for CommandQueryCustom { diff --git a/src/device.rs b/src/device.rs index 01fe286..223449b 100644 --- a/src/device.rs +++ b/src/device.rs @@ -10,7 +10,7 @@ use anyhow::{bail, Context, Error, Result}; use serde_json::to_string; use crate::{ - command::{Command, CommandRequest, MessageType}, + command::{CommandQuerySubtype, CommandRequest, CommandSubtypeResponse, MessageType}, devices::{e1::E1, DeviceBackend}, hex, packet_builder::PacketBuilder, @@ -32,7 +32,8 @@ pub struct Device { device_backend: Box, buffer: Vec, - sub_type: Option, + sub_type: u16, + device_protocol_version: u8, updates: Vec Result<()>>>, @@ -70,7 +71,8 @@ impl Device { security: Security::default(), buffer: Vec::new(), - sub_type: None, + sub_type: 0, + device_protocol_version: 0, updates: Vec::new(), @@ -114,8 +116,8 @@ impl Device { pub fn refresh_status(&mut self) -> Result<()> { let mut cmds = vec![self.device_backend.build_query()]; - if self.sub_type.is_none() { - cmds.insert(0, Command::sub_type(self.info.device_type)); + if self.sub_type == 0 { + cmds.insert(0, CommandQuerySubtype::new(self.info.device_type).request()); } for cmd in cmds { @@ -173,7 +175,7 @@ impl Device { Security::aes_decrypt(crypt); - if self.pre_process_message(crypt)? { + if self.pre_process_message(crypt) { let status = self.device_backend.process_message(crypt)?; if status.len() > 0 { @@ -188,13 +190,16 @@ impl Device { Ok(ParseMessage::Success) } - fn pre_process_message(&self, msg: &[u8]) -> Result { + fn pre_process_message(&mut self, msg: &[u8]) -> bool { if msg[9] == MessageType::QuerySubtype as u8 { - let message = todo!(); + let message = CommandSubtypeResponse::new(msg); - Ok(false) + self.sub_type = message.sub_type; + self.device_protocol_version = message.header().device_protocol_version(); + + false } else { - Ok(true) + true } } diff --git a/src/devices/e1.rs b/src/devices/e1.rs index 31c12f3..6e35b69 100644 --- a/src/devices/e1.rs +++ b/src/devices/e1.rs @@ -1,4 +1,7 @@ -use std::{collections::HashMap, ops::Deref}; +use std::{ + collections::HashMap, + ops::{Deref, DerefMut}, +}; use anyhow::Result; @@ -7,7 +10,7 @@ use crate::command::*; use super::DeviceBackend; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -enum DeviceAttributes { +pub enum DeviceAttributes { Power, Status, Mode, @@ -96,7 +99,7 @@ impl DeviceAttributes { } } -enum AttributeValue { +pub enum AttributeValue { String(Option), Bool(bool), Int(u8), @@ -106,6 +109,8 @@ impl AttributeValue { pub fn set(&mut self, value: impl Into) { match (self, value.into()) { (Self::String(current), Self::String(new)) => *current = new, + (Self::String(current), Self::Bool(new)) => *current = Some(new.to_string()), + (Self::String(current), Self::Int(new)) => *current = Some(new.to_string()), (Self::Bool(current), Self::Bool(new)) => *current = new, (Self::Int(current), Self::Int(new)) => *current = new, @@ -165,6 +170,8 @@ pub struct E1 { status: [&'static str; 5], progress: [&'static str; 6], + + device_protocol_version: u8, } impl E1 { @@ -243,17 +250,20 @@ impl E1 { attributes, status, progress, + + device_protocol_version: 0, }) } } impl DeviceBackend for E1 { - fn build_query(&self, device_protocol_version: u32) -> CommandRequest { - // Ok(vec![CommandQuery::new(device_protocol_version)]) - todo!() + fn build_query(&self) -> CommandRequest { + CommandQuery::new(self.device_protocol_version).request() } fn process_message(&self, msg: &[u8]) -> Result> { + let cmd = CommandE1Response::new(msg); + todo!() } @@ -298,6 +308,12 @@ impl Deref for CommandE1Base { } } +impl DerefMut for CommandE1Base { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.command + } +} + pub struct CommandPower { command: CommandE1Base, } @@ -318,7 +334,11 @@ impl CommandPower { } pub fn set_power(&mut self, power: bool) { - self.body()[1] = if power { 0x01 } else { 0x00 }; + self.command.body_mut()[1] = if power { 0x01 } else { 0x00 }; + } + + pub fn request(self) -> CommandRequest { + self.command.command } } @@ -350,7 +370,11 @@ impl CommandLock { } pub fn set_lock(&mut self, lock: bool) { - self.body()[1] = if lock { 0x03 } else { 0x04 } + self.command.body_mut()[1] = if lock { 0x03 } else { 0x04 } + } + + pub fn request(self) -> CommandRequest { + self.command.command } } @@ -385,7 +409,11 @@ impl CommandStorage { } pub fn set_storage(&mut self, storage: bool) { - self.body()[4] = if storage { 0x01 } else { 0x00 } + self.command.body_mut()[4] = if storage { 0x01 } else { 0x00 } + } + + pub fn request(self) -> CommandRequest { + self.command.command } } @@ -411,6 +439,10 @@ impl CommandQuery { ), } } + + pub fn request(self) -> CommandRequest { + self.command.command + } } pub struct CommandE1Response { @@ -428,7 +460,10 @@ impl CommandE1Response { } } - pub fn update_attributes(&self, attributes: &mut HashMap) { + pub fn update_attributes( + &mut self, + attributes: &mut HashMap, + ) { let message_type = self.command.header().message_type(); let body = self.command.body(); let body_type = self.command.body().body_type(); @@ -437,19 +472,40 @@ impl CommandE1Response { || ((message_type == MessageType::Query || message_type == MessageType::Notify1) && body_type == 0) { - attributes[&DeviceAttributes::Power].set(body[1] > 0); - attributes[&DeviceAttributes::Status].set(body[1]); - attributes[&DeviceAttributes::Mode].set(body[2]); - attributes[&DeviceAttributes::Additional].set(body[3]); + attributes + .get_mut(&DeviceAttributes::Power) + .unwrap() + .set(body[1] > 0); + attributes + .get_mut(&DeviceAttributes::Status) + .unwrap() + .set(body[1]); + attributes + .get_mut(&DeviceAttributes::Mode) + .unwrap() + .set(body[2]); + attributes + .get_mut(&DeviceAttributes::Additional) + .unwrap() + .set(body[3]); // 0 - open, 1 - close - attributes[&DeviceAttributes::Door].set((body[5] & 0x01) == 0); + attributes + .get_mut(&DeviceAttributes::Door) + .unwrap() + .set((body[5] & 0x01) == 0); // 0 - enough, 1 - shortage - attributes[&DeviceAttributes::RinseAid].set((body[5] & 0x02) > 0); + attributes + .get_mut(&DeviceAttributes::RinseAid) + .unwrap() + .set((body[5] & 0x02) > 0); // e - enough, 1 - shortage - attributes[&DeviceAttributes::Salt].set((body[5] & 0x04) > 0); + attributes + .get_mut(&DeviceAttributes::Salt) + .unwrap() + .set((body[5] & 0x04) > 0); let start_pause = (body[5] & 0x08) > 0; @@ -461,9 +517,86 @@ impl CommandE1Response { self.start = false; } - attributes[&DeviceAttributes::ChildLock].set((body[5] & 0x10) > 0); - attributes[&DeviceAttributes::UV].set((body[4] & 0x2) > 0); - attributes[&DeviceAttributes::Dry].set((body[4] & 0x10) > 0); + attributes + .get_mut(&DeviceAttributes::ChildLock) + .unwrap() + .set((body[5] & 0x10) > 0); + attributes + .get_mut(&DeviceAttributes::UV) + .unwrap() + .set((body[4] & 0x02) > 0); + attributes + .get_mut(&DeviceAttributes::Dry) + .unwrap() + .set((body[4] & 0x10) > 0); + attributes + .get_mut(&DeviceAttributes::DryStatus) + .unwrap() + .set((body[4] & 0x20) > 0); + attributes + .get_mut(&DeviceAttributes::Status) + .unwrap() + .set((body[5] & 0x20) > 0); + attributes + .get_mut(&DeviceAttributes::StorageStatus) + .unwrap() + .set((body[5] & 0x40) > 0); + attributes + .get_mut(&DeviceAttributes::TimeRemaining) + .unwrap() + .set(body[6]); + attributes + .get_mut(&DeviceAttributes::Progress) + .unwrap() + .set(body[9]); + attributes + .get_mut(&DeviceAttributes::StorageRemaining) + .unwrap() + .set(if body.len() > 18 { + body[11] + } else { + false.into() + }); + attributes + .get_mut(&DeviceAttributes::Temperature) + .unwrap() + .set(body[11]); + attributes + .get_mut(&DeviceAttributes::Humidity) + .unwrap() + .set(if body.len() > 33 { + body[33].into() + } else { + AttributeValue::from(None) + }); + attributes + .get_mut(&DeviceAttributes::Waterswitch) + .unwrap() + .set((body[4] & 0x04) > 0); + attributes + .get_mut(&DeviceAttributes::WaterLack) + .unwrap() + .set((body[5] & 0x80) > 0); + attributes + .get_mut(&DeviceAttributes::ErrorCode) + .unwrap() + .set(body[10]); + attributes + .get_mut(&DeviceAttributes::Softwater) + .unwrap() + .set(body[13]); + attributes + .get_mut(&DeviceAttributes::WrongOperation) + .unwrap() + .set(body[16]); + attributes + .get_mut(&DeviceAttributes::Bright) + .unwrap() + .set(if body.len() > 24 { + body[24].into() + } else { + AttributeValue::from(None) + }); } } } diff --git a/src/devices/mod.rs b/src/devices/mod.rs index 94b43d3..6ae1ccd 100644 --- a/src/devices/mod.rs +++ b/src/devices/mod.rs @@ -5,7 +5,7 @@ use crate::command::CommandRequest; pub mod e1; pub trait DeviceBackend { - fn build_query(&self, device_protocol_version: u32) -> CommandRequest; + fn build_query(&self) -> CommandRequest; fn process_message(&self, msg: &[u8]) -> Result>; fn set_attribute(&self, attribute: &str, value: &str) -> (); } diff --git a/src/discover.rs b/src/discover.rs index 6bb66a9..82e83fe 100644 --- a/src/discover.rs +++ b/src/discover.rs @@ -15,7 +15,7 @@ pub struct DeviceInfo { pub model: String, pub sn: String, pub protocol: u8, - pub device_type: u32, + pub device_type: u8, pub addr: SocketAddr, } @@ -79,7 +79,7 @@ impl Startup { let upper = start + encrypt_data[40] as usize; let ssid = from_utf8(&encrypt_data[start..upper])?; - let device_type = u32::from_str_radix(ssid.split('_').nth(1).unwrap(), 16)?; + let device_type = u8::from_str_radix(ssid.split('_').nth(1).unwrap(), 16)?; let model = from_utf8(&encrypt_data[17..25])?; let sn = from_utf8(&encrypt_data[8..40])?; let port = Self::bytes_to_port(&encrypt_data[4..8]);