-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from manio/hvac-support
Add HVAC/Air Conditioner support
- Loading branch information
Showing
6 changed files
with
434 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
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, | ||
}; | ||
|
||
/// A mapping of hvac device codes to their friendly model equivalent. | ||
pub const HVAC_CODES: phf::Map<u16, &'static str> = phf_map! { | ||
0x4E2Au16 => "Licensed manufacturer", | ||
}; | ||
|
||
/// A broadlink HVAC/Air Conditioner device. | ||
#[derive(Debug, Clone)] | ||
pub struct HvacDevice { | ||
/// Base information about the device. | ||
pub info: DeviceInfo, | ||
} | ||
|
||
impl HvacDevice { | ||
/// Create a new HvacDevice. | ||
/// | ||
/// Note: This should not be called directly. Please use [Device::from_ip] or | ||
/// [Device::list] instead. | ||
pub fn new(name: &str, addr: Ipv4Addr, response: DiscoveryResponse) -> HvacDevice { | ||
// Get the name of air conditioner | ||
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, // This will be populated when authenticated. | ||
key: constants::INITIAL_KEY, | ||
is_locked: response.is_locked, | ||
}, | ||
}; | ||
} | ||
|
||
/// Get basic information from the air conditioner. | ||
pub fn get_info(&self) -> Result<AirCondInfo, String> { | ||
let data = self | ||
.send_command(&[], HvacDataCommand::GetAcInfo) | ||
.expect("Could not obtain AC info from device!"); | ||
let info = | ||
AirCondInfo::unpack_from_slice(&data).expect("Could not unpack command from bytes!"); | ||
|
||
return Ok(info); | ||
} | ||
|
||
/// Get current air conditioner state into AirCondState structure. | ||
pub fn get_state(&self) -> Result<AirCondState, String> { | ||
let data = self | ||
.send_command(&[], HvacDataCommand::GetState) | ||
.expect("Could not obtain AC state from device!"); | ||
let state = | ||
AirCondState::unpack_from_slice(&data).expect("Could not unpack command from bytes!"); | ||
|
||
return Ok(state); | ||
} | ||
|
||
/// Set new air conditioner state based on passed structure. | ||
pub fn set_state(&self, state: &mut AirCondState) -> Result<Vec<u8>, String> { | ||
let payload = state.prepare_and_pack().expect("Could not pack message"); | ||
let response = self | ||
.send_command(&payload, HvacDataCommand::SetState) | ||
.unwrap(); | ||
|
||
return Ok(response); | ||
} | ||
|
||
/// Sends a raw command to the device. | ||
/// Note: Try to avoid using this method in favor of [HvacDevice::get_info], [HvacDevice::set_state], etc. | ||
pub fn send_command( | ||
&self, | ||
payload: &[u8], | ||
command: HvacDataCommand, | ||
) -> Result<Vec<u8>, String> { | ||
// We cast this object to a generic device in order to make use of the shared | ||
// helper utilities. | ||
let generic_device = Device::Hvac { hvac: self.clone() }; | ||
|
||
// Construct the data message | ||
let msg = HvacDataMessage::new(command); | ||
let packed = msg | ||
.pack_with_payload(&payload) | ||
.expect("Could not pack HVAC data message!"); | ||
|
||
let response = generic_device | ||
.send_command::<HvacDataMessage>(&packed) | ||
.expect("Could not send command!"); | ||
|
||
// TODO: check if there is some relation between | ||
// msg.command and the same return field from the response | ||
|
||
return HvacDataMessage::unpack_with_payload(&response); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.