use std::net::Ipv4Addr;
use packed_struct::PackedStructSlice;
use phf::phf_map;
use crate::{
constants,
network::{
util::reverse_mac, AirCondInfo, AirCondState, DiscoveryResponse, HvacDataCommand,
HvacDataMessage,
},
Device, DeviceInfo,
};
pub const HVAC_CODES: phf::Map<u16, &'static str> = phf_map! {
0x4E2Au16 => "Licensed manufacturer",
};
#[derive(Debug, Clone)]
pub struct HvacDevice {
pub info: DeviceInfo,
}
impl HvacDevice {
pub fn new(name: &str, addr: Ipv4Addr, response: DiscoveryResponse) -> HvacDevice {
let friendly_model: String = HVAC_CODES
.get(&response.model_code)
.unwrap_or(&"Unknown")
.to_string();
return Self {
info: DeviceInfo {
address: addr,
mac: reverse_mac(response.mac),
model_code: response.model_code,
friendly_type: "HVAC".into(),
friendly_model: friendly_model,
name: name.into(),
auth_id: 0, key: constants::INITIAL_KEY,
is_locked: response.is_locked,
},
};
}
pub fn get_info(&self) -> Result<AirCondInfo, String> {
let data = self
.send_command(&[], HvacDataCommand::GetAcInfo)
.map_err(|e| format!("Could not obtain AC info from device! {}", e))?;
let info = AirCondInfo::unpack_from_slice(&data)
.map_err(|e| format!("Could not unpack command from bytes! {}", e))?;
return Ok(info);
}
pub fn get_state(&self) -> Result<AirCondState, String> {
let data = self
.send_command(&[], HvacDataCommand::GetState)
.map_err(|e| format!("Could not obtain AC state from device! {}", e))?;
let state = AirCondState::unpack_from_slice(&data)
.map_err(|e| format!("Could not unpack command from bytes! {}", e))?;
return Ok(state);
}
pub fn set_state(&self, state: &mut AirCondState) -> Result<Vec<u8>, String> {
let payload = state
.prepare_and_pack()
.map_err(|e| format!("Could not pack message! {}", e))?;
let response = self.send_command(&payload, HvacDataCommand::SetState)?;
return Ok(response);
}
pub fn send_command(
&self,
payload: &[u8],
command: HvacDataCommand,
) -> Result<Vec<u8>, String> {
let generic_device = Device::Hvac { hvac: self.clone() };
let msg = HvacDataMessage::new(command);
let packed = msg
.pack_with_payload(&payload)
.map_err(|e| format!("Could not pack HVAC data message! {}", e))?;
let response = generic_device
.send_command::<HvacDataMessage>(&packed)
.map_err(|e| format!("Could not send command! {}", e))?;
return HvacDataMessage::unpack_with_payload(&response);
}
}