Further device communication work

This commit is contained in:
hodasemi 2023-09-28 20:28:56 +02:00
parent ce87e28c11
commit 3d37654850
5 changed files with 179 additions and 33 deletions

View file

@ -67,6 +67,10 @@ impl CommandQuerySubtype {
), ),
} }
} }
pub fn request(self) -> CommandRequest {
self.command
}
} }
impl Deref for CommandQuerySubtype { impl Deref for CommandQuerySubtype {
@ -87,6 +91,10 @@ impl CommandQueryCustom {
command: CommandRequest::new(0, device_type, message_type, body), command: CommandRequest::new(0, device_type, message_type, body),
} }
} }
pub fn request(self) -> CommandRequest {
self.command
}
} }
impl Deref for CommandQueryCustom { impl Deref for CommandQueryCustom {

View file

@ -10,7 +10,7 @@ use anyhow::{bail, Context, Error, Result};
use serde_json::to_string; use serde_json::to_string;
use crate::{ use crate::{
command::{Command, CommandRequest, MessageType}, command::{CommandQuerySubtype, CommandRequest, CommandSubtypeResponse, MessageType},
devices::{e1::E1, DeviceBackend}, devices::{e1::E1, DeviceBackend},
hex, hex,
packet_builder::PacketBuilder, packet_builder::PacketBuilder,
@ -32,7 +32,8 @@ pub struct Device {
device_backend: Box<dyn DeviceBackend>, device_backend: Box<dyn DeviceBackend>,
buffer: Vec<u8>, buffer: Vec<u8>,
sub_type: Option<String>, sub_type: u16,
device_protocol_version: u8,
updates: Vec<Box<dyn Fn(&[u8]) -> Result<()>>>, updates: Vec<Box<dyn Fn(&[u8]) -> Result<()>>>,
@ -70,7 +71,8 @@ impl Device {
security: Security::default(), security: Security::default(),
buffer: Vec::new(), buffer: Vec::new(),
sub_type: None, sub_type: 0,
device_protocol_version: 0,
updates: Vec::new(), updates: Vec::new(),
@ -114,8 +116,8 @@ impl Device {
pub fn refresh_status(&mut self) -> Result<()> { pub fn refresh_status(&mut self) -> Result<()> {
let mut cmds = vec![self.device_backend.build_query()]; let mut cmds = vec![self.device_backend.build_query()];
if self.sub_type.is_none() { if self.sub_type == 0 {
cmds.insert(0, Command::sub_type(self.info.device_type)); cmds.insert(0, CommandQuerySubtype::new(self.info.device_type).request());
} }
for cmd in cmds { for cmd in cmds {
@ -173,7 +175,7 @@ impl Device {
Security::aes_decrypt(crypt); Security::aes_decrypt(crypt);
if self.pre_process_message(crypt)? { if self.pre_process_message(crypt) {
let status = self.device_backend.process_message(crypt)?; let status = self.device_backend.process_message(crypt)?;
if status.len() > 0 { if status.len() > 0 {
@ -188,13 +190,16 @@ impl Device {
Ok(ParseMessage::Success) Ok(ParseMessage::Success)
} }
fn pre_process_message(&self, msg: &[u8]) -> Result<bool> { fn pre_process_message(&mut self, msg: &[u8]) -> bool {
if msg[9] == MessageType::QuerySubtype as u8 { 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 { } else {
Ok(true) true
} }
} }

View file

@ -1,4 +1,7 @@
use std::{collections::HashMap, ops::Deref}; use std::{
collections::HashMap,
ops::{Deref, DerefMut},
};
use anyhow::Result; use anyhow::Result;
@ -7,7 +10,7 @@ use crate::command::*;
use super::DeviceBackend; use super::DeviceBackend;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum DeviceAttributes { pub enum DeviceAttributes {
Power, Power,
Status, Status,
Mode, Mode,
@ -96,7 +99,7 @@ impl DeviceAttributes {
} }
} }
enum AttributeValue { pub enum AttributeValue {
String(Option<String>), String(Option<String>),
Bool(bool), Bool(bool),
Int(u8), Int(u8),
@ -106,6 +109,8 @@ impl AttributeValue {
pub fn set(&mut self, value: impl Into<Self>) { pub fn set(&mut self, value: impl Into<Self>) {
match (self, value.into()) { match (self, value.into()) {
(Self::String(current), Self::String(new)) => *current = new, (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::Bool(current), Self::Bool(new)) => *current = new,
(Self::Int(current), Self::Int(new)) => *current = new, (Self::Int(current), Self::Int(new)) => *current = new,
@ -165,6 +170,8 @@ pub struct E1 {
status: [&'static str; 5], status: [&'static str; 5],
progress: [&'static str; 6], progress: [&'static str; 6],
device_protocol_version: u8,
} }
impl E1 { impl E1 {
@ -243,17 +250,20 @@ impl E1 {
attributes, attributes,
status, status,
progress, progress,
device_protocol_version: 0,
}) })
} }
} }
impl DeviceBackend for E1 { impl DeviceBackend for E1 {
fn build_query(&self, device_protocol_version: u32) -> CommandRequest { fn build_query(&self) -> CommandRequest {
// Ok(vec![CommandQuery::new(device_protocol_version)]) CommandQuery::new(self.device_protocol_version).request()
todo!()
} }
fn process_message(&self, msg: &[u8]) -> Result<Vec<u8>> { fn process_message(&self, msg: &[u8]) -> Result<Vec<u8>> {
let cmd = CommandE1Response::new(msg);
todo!() 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 { pub struct CommandPower {
command: CommandE1Base, command: CommandE1Base,
} }
@ -318,7 +334,11 @@ impl CommandPower {
} }
pub fn set_power(&mut self, power: bool) { 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) { 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) { 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 { pub struct CommandE1Response {
@ -428,7 +460,10 @@ impl CommandE1Response {
} }
} }
pub fn update_attributes(&self, attributes: &mut HashMap<DeviceAttributes, AttributeValue>) { pub fn update_attributes(
&mut self,
attributes: &mut HashMap<DeviceAttributes, AttributeValue>,
) {
let message_type = self.command.header().message_type(); let message_type = self.command.header().message_type();
let body = self.command.body(); let body = self.command.body();
let body_type = self.command.body().body_type(); let body_type = self.command.body().body_type();
@ -437,19 +472,40 @@ impl CommandE1Response {
|| ((message_type == MessageType::Query || message_type == MessageType::Notify1) || ((message_type == MessageType::Query || message_type == MessageType::Notify1)
&& body_type == 0) && body_type == 0)
{ {
attributes[&DeviceAttributes::Power].set(body[1] > 0); attributes
attributes[&DeviceAttributes::Status].set(body[1]); .get_mut(&DeviceAttributes::Power)
attributes[&DeviceAttributes::Mode].set(body[2]); .unwrap()
attributes[&DeviceAttributes::Additional].set(body[3]); .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 // 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 // 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 // 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; let start_pause = (body[5] & 0x08) > 0;
@ -461,9 +517,86 @@ impl CommandE1Response {
self.start = false; self.start = false;
} }
attributes[&DeviceAttributes::ChildLock].set((body[5] & 0x10) > 0); attributes
attributes[&DeviceAttributes::UV].set((body[4] & 0x2) > 0); .get_mut(&DeviceAttributes::ChildLock)
attributes[&DeviceAttributes::Dry].set((body[4] & 0x10) > 0); .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)
});
} }
} }
} }

View file

@ -5,7 +5,7 @@ use crate::command::CommandRequest;
pub mod e1; pub mod e1;
pub trait DeviceBackend { pub trait DeviceBackend {
fn build_query(&self, device_protocol_version: u32) -> CommandRequest; fn build_query(&self) -> CommandRequest;
fn process_message(&self, msg: &[u8]) -> Result<Vec<u8>>; fn process_message(&self, msg: &[u8]) -> Result<Vec<u8>>;
fn set_attribute(&self, attribute: &str, value: &str) -> (); fn set_attribute(&self, attribute: &str, value: &str) -> ();
} }

View file

@ -15,7 +15,7 @@ pub struct DeviceInfo {
pub model: String, pub model: String,
pub sn: String, pub sn: String,
pub protocol: u8, pub protocol: u8,
pub device_type: u32, pub device_type: u8,
pub addr: SocketAddr, pub addr: SocketAddr,
} }
@ -79,7 +79,7 @@ impl Startup {
let upper = start + encrypt_data[40] as usize; let upper = start + encrypt_data[40] as usize;
let ssid = from_utf8(&encrypt_data[start..upper])?; 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 model = from_utf8(&encrypt_data[17..25])?;
let sn = from_utf8(&encrypt_data[8..40])?; let sn = from_utf8(&encrypt_data[8..40])?;
let port = Self::bytes_to_port(&encrypt_data[4..8]); let port = Self::bytes_to_port(&encrypt_data[4..8]);