use std::str::FromStr;
use compact_str::CompactString;
use serde::{Deserialize, Serialize};
use serde_with::{DeserializeFromStr, DisplayFromStr, serde_as};
use crate::error::InvalidGatewayKind;
#[derive(Debug, Clone, Copy)]
pub enum TemperatureUnit {
Fahrenheit,
Celsius,
}
impl TemperatureUnit {
pub(crate) fn as_cookie_str(self) -> &'static str {
match self {
Self::Fahrenheit => "temp_unit=f",
Self::Celsius => "temp_unit=c",
}
}
}
impl FromStr for TemperatureUnit {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"F" | "f" => Ok(Self::Fahrenheit),
"C" | "c" => Ok(Self::Celsius),
_ => Err("Invalid tempearture unit; must be F or C"),
}
}
}
#[derive(Debug, Serialize)]
pub(crate) struct LoginRequest<'a> {
op: &'static str,
redirect: &'static str,
emailaddress: &'a str,
password: &'a str,
}
impl<'a> LoginRequest<'a> {
#[inline]
pub(crate) fn new(email: &'a str, password: &'a str) -> Self {
Self { op: "login", redirect: "/", emailaddress: email, password }
}
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct User {
pub emailaddress: CompactString,
pub name: CompactString,
pub awl_user_key: u32,
pub contact_user_key: u16,
pub custkey: CompactString,
pub has_portal_permissions: bool,
pub customer_mode: bool,
pub is_dealer: bool,
pub is_distributor: bool,
pub has_devices: bool,
#[serde(rename = "type")]
pub kind: u8,
pub is_registered: bool,
pub country: isocountry::CountryCode,
}
#[derive(Debug, Serialize)]
pub(crate) struct GetLocationRequest {
pub(crate) awluserkey: u32,
}
#[derive(Debug, Deserialize)]
pub struct Gateway {
pub gwid: CompactString,
pub description: CompactString,
#[serde(rename = "type")]
pub kind: GatewayKind,
pub gwkey: u32,
}
#[derive(Debug, Clone, Copy, DeserializeFromStr)]
pub enum GatewayKind {
AuroraWebLink,
}
impl FromStr for GatewayKind {
type Err = InvalidGatewayKind;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"AWL" => Ok(Self::AuroraWebLink),
_ => Err(InvalidGatewayKind),
}
}
}
#[serde_as]
#[derive(Debug, Deserialize)]
pub struct Location {
pub description: CompactString,
pub locationkey: u32,
#[serde_as(as = "DisplayFromStr")]
pub latitude: f64,
#[serde_as(as = "DisplayFromStr")]
pub longitude: f64,
pub custkey: CompactString,
pub gateways: Vec<Gateway>,
}
#[derive(Debug, Deserialize)]
pub(crate) struct LocationResponse {
pub(crate) data: Vec<Location>,
}
#[derive(Debug, Serialize)]
pub(crate) struct WsLoginRequest<'a> {
pub(crate) cmd: &'static str,
pub(crate) tid: u8,
pub(crate) source: &'static str,
pub(crate) sessionid: &'a str,
}
#[derive(Debug, Serialize)]
pub(crate) struct DataRequest<'a> {
pub(crate) cmd: &'static str,
pub(crate) tid: u8,
pub(crate) awlid: &'a str,
pub(crate) zone: u8,
pub(crate) rlist: &'static [&'static str],
pub(crate) source: &'static str,
}
#[derive(Debug, Deserialize)]
pub(crate) struct DataResponse {
rsp: CompactString,
awlid: CompactString,
tid: u8,
err: CompactString,
compressorpower: u16,
zone: u8,
fanpower: u16,
auxpower: u16,
looppumppower: u16,
totalunitpower: u16,
awlabctype: u8,
modeofoperation: u8, actualcompressorspeed: u8,
airflowcurrentspeed: u8, auroraoutputeh1: u8,
auroraoutputeh2: u8,
auroraoutputcc: u8, auroraoutputcc2: u8, tstatdehumidsetpoint: u8,
tstatrelativehumidity: u8,
leavingairtemp: f64, tstatroomtemp: f64, enteringwatertemp: f64, aocenteringwatertemp: f64,
auroraoutputrv: u8,
awltstattype: u8,
humidity_offset_settings: HumidityOffsetSettings,
iz2_humidity_offset_settings: HumidityOffsetSettings,
dehumid_humid_sp: DehumidificationSettings,
iz2_dehumid_humid_sp: DehumidificationSettings,
lockoutstatus: LockoutStatus,
lastfault: u8,
lastlockout: LastLockout,
homeautomationalarm1: u8,
homeautomationalarm2: u8,
roomtemp: u8,
activesettings: ActiveSettings,
tstatactivesetpoint: u8,
tstatmode: u8,
tstatheatingsetpoint: u8,
tstatcoolingsetpoint: u8,
}
#[derive(Debug, Deserialize)]
struct HumidityOffsetSettings {
humidity_offset: u8,
#[serde(rename = "humdity_control_option")]
humidity_control_option: u8,
dehumidification_mode: u8,
humidification_mode: u8,
}
#[derive(Debug, Deserialize)]
struct DehumidificationSettings {
dehumidification: u8,
humidification: u8,
}
#[derive(Debug, Deserialize)]
struct LockoutStatus {
lockoutstatuscode: u8,
lockedout: u8,
}
#[derive(Debug, Deserialize)]
struct LastLockout {
lockoutstatuslast: u8,
}
#[derive(Debug, Deserialize)]
struct ActiveSettings {
temporaryoverride: u8,
permanenthold: u8,
vacationhold: u8,
onpeakhold: u8,
superboost: u8,
tstatmode: u8,
activemode: u8, heatingsp_read: u8,
coolingsp_read: u8,
fanmode_read: u8,
intertimeon_read: u8,
intertimeoff_read: u8,
}
#[derive(Debug)]
pub struct GatewayData {
pub zone: u8,
pub total_power: u16,
pub compressor_power: u16,
pub fan_power: u16,
pub loop_pump_power: u16,
pub aux_heat_power: u16,
pub compressor_stage: u8,
pub aux_heat_stage: u8,
pub fan_speed_setting: u8,
pub dehumidify_setpoint: u8,
pub relative_humidity: u8,
pub room_temp: u8,
pub supply_air_temp: f64,
pub return_air_temp: f64,
pub return_water_temp: f64,
pub heating_setpoint: u8,
pub cooling_setpoint: u8,
pub active_setpoint: u8,
pub mode: Option<ThermostatMode>,
pub fan_mode: Option<FanMode>,
}
impl From<DataResponse> for GatewayData {
fn from(raw: DataResponse) -> Self {
Self {
zone: raw.zone,
total_power: raw.totalunitpower,
compressor_power: raw.compressorpower,
fan_power: raw.fanpower,
loop_pump_power: raw.looppumppower,
aux_heat_power: raw.auxpower,
compressor_stage: raw.auroraoutputcc + raw.auroraoutputcc2,
aux_heat_stage: raw.auroraoutputeh1 + raw.auroraoutputeh2,
fan_speed_setting: raw.airflowcurrentspeed,
dehumidify_setpoint: raw.tstatdehumidsetpoint,
relative_humidity: raw.tstatrelativehumidity,
room_temp: raw.roomtemp,
supply_air_temp: raw.leavingairtemp,
return_air_temp: raw.tstatroomtemp,
return_water_temp: raw.enteringwatertemp,
heating_setpoint: raw.tstatheatingsetpoint,
cooling_setpoint: raw.tstatcoolingsetpoint,
active_setpoint: raw.tstatactivesetpoint,
mode: match raw.activesettings.activemode {
0 => Some(ThermostatMode::Off),
1 => Some(ThermostatMode::Auto),
2 => Some(ThermostatMode::Cool),
3 => Some(ThermostatMode::Heat),
4 => Some(ThermostatMode::EmergencyHeat),
_ => None,
},
fan_mode: match raw.activesettings.fanmode_read {
0 => Some(FanMode::Auto),
1 => Some(FanMode::Continuous),
2 => Some(FanMode::Intermittent { off: raw.activesettings.intertimeoff_read, on: raw.activesettings.intertimeon_read }),
_ => None,
},
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum ThermostatMode {
Off, Auto, Cool, Heat, EmergencyHeat, }
impl ThermostatMode {
pub fn as_u8(self) -> u8 {
match self {
Self::Off => 0,
Self::Auto => 1,
Self::Cool => 2,
Self::Heat => 3,
Self::EmergencyHeat => 4,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum FanMode {
Auto, Continuous, Intermittent { off: u8, on: u8 }, }
impl FanMode {
pub fn as_u8(self) -> u8 {
match self {
Self::Auto => 0,
Self::Continuous => 1,
Self::Intermittent { .. } => 2,
}
}
}