use crc16::MODBUS;
use crate::{messaging::MessageType, states};
#[derive(Debug, Clone, Copy)]
pub struct ACControlMessage {
pub unit_number: u8,
pub fan_speed: Option<states::ACFanSpeed>,
pub mode: states::SetACMode,
pub power: states::SetACPowerState,
pub setpoint_temp: states::SetACSetpoint,
}
impl ACControlMessage {
pub fn new(
unit_number: u8,
power: states::SetACPowerState,
mode: states::SetACMode,
fan_speed: Option<states::ACFanSpeed>,
setpoint_temp: states::SetACSetpoint,
) -> Self {
Self {
unit_number,
fan_speed,
mode,
power,
setpoint_temp,
}
}
pub fn set_off(unit: u8) -> Self {
Self::new(
unit,
states::SetACPowerState::Off,
states::SetACMode::Maintain,
None,
states::SetACSetpoint::Maintain,
)
}
pub fn build(&self) -> [u8; 14] {
assert!(self.unit_number <= 3);
let power: u8 = match self.power {
states::SetACPowerState::Maintain => 0,
states::SetACPowerState::Toggle => 1,
states::SetACPowerState::Off => 0b10,
states::SetACPowerState::On => 0b11,
};
let byte1 = (power << 6) | self.unit_number;
let ac_mode: u8 = match self.mode {
states::SetACMode::Auto => 0,
states::SetACMode::Heat => 0b1,
states::SetACMode::Dry => 0b10,
states::SetACMode::Fan => 0b11,
states::SetACMode::Cool => 0b100,
states::SetACMode::Maintain => 0b1111,
};
let fan_speed: u8 = match self.fan_speed {
Some(m) => match m {
states::ACFanSpeed::Auto => 0,
states::ACFanSpeed::Quiet => 0b1,
states::ACFanSpeed::Low => 0b10,
states::ACFanSpeed::Medium => 0b11,
states::ACFanSpeed::High => 0b100,
states::ACFanSpeed::Powerful => 0b101,
states::ACFanSpeed::Turbo => 0b110,
},
None => 0b1111,
};
let byte2 = (ac_mode << 4) | fan_speed;
let mut setpoint_value: u8 = 0;
let setpoint_control_type = match self.setpoint_temp {
states::SetACSetpoint::Maintain => 0,
states::SetACSetpoint::Value(v) => {
setpoint_value = v;
0b01
}
states::SetACSetpoint::Decrease => 0b10,
states::SetACSetpoint::Increase => 0b11,
};
let byte3 = (setpoint_control_type << 6) | setpoint_value;
let crc = crc16::State::<MODBUS>::calculate(&[
0x80,
0xb0,
0x01,
MessageType::AC_CONTROL_MESSAGE,
0x00,
0x04,
byte1,
byte2,
byte3,
0,
]);
return [
0x55,
0x55,
0x80,
0xb0,
0x01,
MessageType::AC_CONTROL_MESSAGE,
0x00,
0x04,
byte1,
byte2,
byte3,
0,
(crc >> 8) as u8,
(crc & 0xff) as u8,
];
}
}
#[cfg(test)]
mod test {
use super::ACControlMessage;
use crate::states;
#[test]
fn test_create_ac_control_packet() {
let packet = ACControlMessage::new(
1,
states::SetACPowerState::Off,
states::SetACMode::Maintain,
None,
states::SetACSetpoint::Maintain,
)
.build();
assert_eq!(
packet,
[0x55, 0x55, 0x80, 0xb0, 0x01, 0x2c, 0x00, 0x04, 0x81, 0xff, 0x00, 0x00, 0xea, 0x87]
)
}
}