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 {
@ -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 {

View file

@ -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<dyn DeviceBackend>,
buffer: Vec<u8>,
sub_type: Option<String>,
sub_type: u16,
device_protocol_version: u8,
updates: Vec<Box<dyn Fn(&[u8]) -> 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<bool> {
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
}
}

View file

@ -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<String>),
Bool(bool),
Int(u8),
@ -106,6 +109,8 @@ impl AttributeValue {
pub fn set(&mut self, value: impl Into<Self>) {
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<Vec<u8>> {
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<DeviceAttributes, AttributeValue>) {
pub fn update_attributes(
&mut self,
attributes: &mut HashMap<DeviceAttributes, AttributeValue>,
) {
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)
});
}
}
}

View file

@ -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<Vec<u8>>;
fn set_attribute(&self, attribute: &str, value: &str) -> ();
}

View file

@ -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]);