From 50476b3accac3f912f706ce05f1b9bebca2ad28c Mon Sep 17 00:00:00 2001 From: hodasemi Date: Fri, 22 Sep 2023 10:07:45 +0200 Subject: [PATCH] Start midea discover function --- .gitignore | 1 + .vscode/settings.json | 7 ++ Cargo.toml | 2 + __pycache__/discover.cpython-311.pyc | Bin 10318 -> 10681 bytes discover.py | 5 ++ src/discover.rs | 130 +++++++++++++++++++++++++++ src/lib.rs | 1 + src/main.rs | 3 - 8 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 src/discover.rs create mode 100644 src/lib.rs delete mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore index ea8c4bf..869df07 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +Cargo.lock \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..ab9d94d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "workbench.colorCustomizations": { + "activityBar.background": "#1C3310", + "titleBar.activeBackground": "#274816", + "titleBar.activeForeground": "#F6FBF4" + } +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 39f9e6f..8e3f4a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = { version = "1.0.75", features = ["backtrace"] } +if-addrs = "0.10.1" \ No newline at end of file diff --git a/__pycache__/discover.cpython-311.pyc b/__pycache__/discover.cpython-311.pyc index 30dcaf926ea451a452d8c9dd18b00c1a09a77a2e..f32412ddb8a92152c793ed47a0e10c4abc129f93 100644 GIT binary patch delta 1214 zcmZvaO-vM59Kh$zFz)Qv?68z^mo5Pj*xA~+rUetgLTNF!X@f>XkP{u4DIHmu&6@$i z?v{RprtP62eO1?}$?BnEH4!tHHof-H*kX63d zXKo()@rZaS91bw_-8c}|-)p)q{>HIuLFX=4W;qrcWNq6Ll?s*pBA zbo)P`pu|Sspd4@7{+edqNhkPI2IXr;>r1Gg%H|>21!@wJpU*c zr1tI52-@Lw9|*6aHu6unrMY&xb_RFlV|MgOkK#_qAa2iA7siF;*8{-}~5{`9NQAIS2&68i%OmDD^5DNTtoJowih49k(nkJ!;}< zE2~cG=@~=Q)wE_sAl1v8y9j zgV!S8N6Jc1Md>Nay%o8)EcI2SzLL~;&$;2%h`{ETMnl}45IcWts_6=fc+MO+0n21ZVhLSz zE+q0CnjqecqVV$Bit$47D&Fe+8N1W<=FAtXtO8 z<3EK&0C9eAJ;$LHl4*Y#eL~K(_wHVSdLd&@s+nQk#$Qv@+D74Rzq$T2wK3p3f;w)c zFH$YV4iBfATwlhVnt~NINcn-n^&8pEH82OxFA3MV7v)KB=fNTGc3JRV1Hdn|aU1Uz s-i^IoVb)~^!yxZ~kA!_QrZ$(+`*GP>@ARSA5rpFRnP-?G|0X9M1Lqw*KmY&$ delta 974 zcmZXQTSyd97{}-AxURFiGvj?-H81Nu!%Zv^uU({szyez=gk*H5+FW;+Gvj4zZ7m8) zGKEtnUBHb(BM@aCqL+Hbk%P9(zv`5;ZoBij z+{8JOGPl+1hpiIj8C`4b*?fK?KbEDIkmL5f&ZdOJFlymH=MwVJeo}1Nb|M_Du=3TY zjnwlG%;AWQ>UG|Oij402g#}bhz6*t9L$H%9F%`MMH#6Sd>S59<9zk8&gcwJtl=P%M zEoFTHRkxnT!NK0XuqrD$2SLJE3hNfI&&s1(ZMuX?YTUt)>Q*FG>Qxl4yE}*nl#tXf zyE}q|a+i#UWlWYb9M*gEsikx)wPYpZXL7T-e$&*X#WPuiK5GrxW$d951m=0f*q!mD z9Ayu^{EBUNbhR+A^Y^FG@W$Q2(Xi5Zz(m7pi|9#Z*8~BWztdx5KiJHkRPB-T9g0S1 zF&+bi0T%&LfC?A_3EV6>K%U1R8KtYjoXb(G>YuwhN7ur1Hj^DQfE} z{$Ri4@03+MNu`oZVT|x+h5@QEAV&PD?a`H%nr diff --git a/discover.py b/discover.py index ddf3db8..df604fb 100644 --- a/discover.py +++ b/discover.py @@ -64,6 +64,11 @@ def discover(discover_type=None, ip_address=None): data = data[8:-16] else: continue + + print(data[20:26]) + print(data[20:26].hex()) + print(bytearray.fromhex(data[20:26].hex())) + device_id = int.from_bytes(bytearray.fromhex(data[20:26].hex()), "little") if device_id in found_devices: continue diff --git a/src/discover.rs b/src/discover.rs new file mode 100644 index 0000000..cc56c65 --- /dev/null +++ b/src/discover.rs @@ -0,0 +1,130 @@ +use std::{ + collections::HashMap, + net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket}, + num::ParseIntError, + time::Duration, +}; + +use anyhow::Result; + +pub struct Startup {} + +impl Startup { + const BROADCAST_MSG: &'static [u8] = &[ + 0x5a, 0x5a, 0x01, 0x11, 0x48, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x75, 0xbd, 0x6b, 0x3e, + 0x4f, 0x8b, 0x76, 0x2e, 0x84, 0x9c, 0x6e, 0x57, 0x8d, 0x65, 0x90, 0x03, 0x6e, 0x9d, 0x43, + 0x42, 0xa5, 0x0f, 0x1f, 0x56, 0x9e, 0xb8, 0xec, 0x91, 0x8e, 0x92, 0xe5, + ]; + + const DEVICE_INFO_MSG: &'static [u8] = &[ + 0x5a, 0x5a, 0x15, 0x00, 0x00, 0x38, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x33, + 0x05, 0x13, 0x06, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x8d, 0x9b, 0xf9, 0xa0, + 0x30, 0x1a, 0xe3, 0xb7, 0xe4, 0x2d, 0x53, 0x49, 0x47, 0x62, 0xbe, + ]; + + const NUM_RETRIES: u8 = 5; + + pub fn discover() -> Result { + let socket = UdpSocket::bind("0.0.0.0:0")?; + socket.set_broadcast(true)?; + socket.set_read_timeout(Some(Duration::from_secs(2)))?; + + let mut devices = HashMap::new(); + + for addr in Self::broadcast_addresses() { + for _ in 0..Self::NUM_RETRIES { + socket.send_to(Self::BROADCAST_MSG, (addr, 6445))?; + socket.send_to(Self::BROADCAST_MSG, (addr, 20086))?; + + let mut buffer = [0; 1024]; + if let Ok((bytes_read, addr)) = socket.recv_from(&mut buffer) { + let mut bytes = buffer[0..bytes_read].to_vec(); + + let protocol = if bytes[..2] == Self::hex("5a5a")? { + 2 + } else if bytes[..2] == Self::hex("8370")? { + if bytes[8..10] == Self::hex("5a5a")? { + bytes = bytes[8..(bytes.len() - 16)].to_vec(); + } + + 3 + } else { + continue; + }; + + let mut tmp: Vec = bytes[20..26].to_vec(); + tmp.push(0); + tmp.push(0); + + let device_id = u64::from_le_bytes(tmp.try_into().unwrap()); + + if !devices.contains_key(&device_id) { + devices.insert(device_id, (addr, bytes.to_vec(), protocol)); + } + } + } + } + + println!("{devices:#?}"); + + Ok(Self {}) + } +} + +impl Startup { + fn broadcast_addresses() -> Vec { + use if_addrs::*; + + let mut addresses = Vec::new(); + + if let Some(interfaces) = get_if_addrs().ok() { + for interface in interfaces { + match interface.addr { + IfAddr::V4(v4) => { + let ip = v4.ip; + let octets = ip.octets(); + + if ip.is_private() { + addresses.push(IpAddr::V4(Ipv4Addr::new( + octets[0], + octets[1], + octets[2], + u8::MAX, + ))) + } + } + IfAddr::V6(_v6) => { + // TODO + // addresses.push(IpAddr::V6(v6.ip)); + } + } + } + } + + addresses + } + + fn hex(s: &str) -> Result, ParseIntError> { + (0..s.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16)) + .collect() + } +} + +#[cfg(test)] +mod test { + use anyhow::Result; + + use super::Startup; + + #[test] + fn discover() -> Result<()> { + Startup::discover()?; + + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..28ff0e0 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +mod discover; diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -}