#![allow(clippy::too_many_arguments)]
use crate::tlv;
use anyhow;
use serde_json;
use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum ACCapacityFormat {
Btuh = 0,
}
impl ACCapacityFormat {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(ACCapacityFormat::Btuh),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<ACCapacityFormat> for u8 {
fn from(val: ACCapacityFormat) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum ACCompressorType {
Unknown = 0,
T1 = 1,
T2 = 2,
T3 = 3,
}
impl ACCompressorType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(ACCompressorType::Unknown),
1 => Some(ACCompressorType::T1),
2 => Some(ACCompressorType::T2),
3 => Some(ACCompressorType::T3),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<ACCompressorType> for u8 {
fn from(val: ACCompressorType) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum ACLouverPosition {
Closed = 1,
Open = 2,
Quarter = 3,
Half = 4,
Threequarters = 5,
}
impl ACLouverPosition {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
1 => Some(ACLouverPosition::Closed),
2 => Some(ACLouverPosition::Open),
3 => Some(ACLouverPosition::Quarter),
4 => Some(ACLouverPosition::Half),
5 => Some(ACLouverPosition::Threequarters),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<ACLouverPosition> for u8 {
fn from(val: ACLouverPosition) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum ACRefrigerantType {
Unknown = 0,
R22 = 1,
R410a = 2,
R407c = 3,
}
impl ACRefrigerantType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(ACRefrigerantType::Unknown),
1 => Some(ACRefrigerantType::R22),
2 => Some(ACRefrigerantType::R410a),
3 => Some(ACRefrigerantType::R407c),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<ACRefrigerantType> for u8 {
fn from(val: ACRefrigerantType) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum ACType {
Unknown = 0,
Coolingfixed = 1,
Heatpumpfixed = 2,
Coolinginverter = 3,
Heatpumpinverter = 4,
}
impl ACType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(ACType::Unknown),
1 => Some(ACType::Coolingfixed),
2 => Some(ACType::Heatpumpfixed),
3 => Some(ACType::Coolinginverter),
4 => Some(ACType::Heatpumpinverter),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<ACType> for u8 {
fn from(val: ACType) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum ControlSequenceOfOperation {
Coolingonly = 0,
Coolingwithreheat = 1,
Heatingonly = 2,
Heatingwithreheat = 3,
Coolingandheating = 4,
Coolingandheatingwithreheat = 5,
}
impl ControlSequenceOfOperation {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(ControlSequenceOfOperation::Coolingonly),
1 => Some(ControlSequenceOfOperation::Coolingwithreheat),
2 => Some(ControlSequenceOfOperation::Heatingonly),
3 => Some(ControlSequenceOfOperation::Heatingwithreheat),
4 => Some(ControlSequenceOfOperation::Coolingandheating),
5 => Some(ControlSequenceOfOperation::Coolingandheatingwithreheat),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<ControlSequenceOfOperation> for u8 {
fn from(val: ControlSequenceOfOperation) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum PresetScenario {
Occupied = 1,
Unoccupied = 2,
Sleep = 3,
Wake = 4,
Vacation = 5,
Goingtosleep = 6,
Userdefined = 254,
}
impl PresetScenario {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
1 => Some(PresetScenario::Occupied),
2 => Some(PresetScenario::Unoccupied),
3 => Some(PresetScenario::Sleep),
4 => Some(PresetScenario::Wake),
5 => Some(PresetScenario::Vacation),
6 => Some(PresetScenario::Goingtosleep),
254 => Some(PresetScenario::Userdefined),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<PresetScenario> for u8 {
fn from(val: PresetScenario) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum SetpointChangeSource {
Manual = 0,
Schedule = 1,
External = 2,
}
impl SetpointChangeSource {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(SetpointChangeSource::Manual),
1 => Some(SetpointChangeSource::Schedule),
2 => Some(SetpointChangeSource::External),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<SetpointChangeSource> for u8 {
fn from(val: SetpointChangeSource) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum SetpointRaiseLowerMode {
Heat = 0,
Cool = 1,
Both = 2,
}
impl SetpointRaiseLowerMode {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(SetpointRaiseLowerMode::Heat),
1 => Some(SetpointRaiseLowerMode::Cool),
2 => Some(SetpointRaiseLowerMode::Both),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<SetpointRaiseLowerMode> for u8 {
fn from(val: SetpointRaiseLowerMode) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum StartOfWeek {
Sunday = 0,
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 6,
}
impl StartOfWeek {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(StartOfWeek::Sunday),
1 => Some(StartOfWeek::Monday),
2 => Some(StartOfWeek::Tuesday),
3 => Some(StartOfWeek::Wednesday),
4 => Some(StartOfWeek::Thursday),
5 => Some(StartOfWeek::Friday),
6 => Some(StartOfWeek::Saturday),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<StartOfWeek> for u8 {
fn from(val: StartOfWeek) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum SystemMode {
Off = 0,
Auto = 1,
Cool = 3,
Heat = 4,
Emergencyheat = 5,
Precooling = 6,
Fanonly = 7,
Dry = 8,
Sleep = 9,
}
impl SystemMode {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(SystemMode::Off),
1 => Some(SystemMode::Auto),
3 => Some(SystemMode::Cool),
4 => Some(SystemMode::Heat),
5 => Some(SystemMode::Emergencyheat),
6 => Some(SystemMode::Precooling),
7 => Some(SystemMode::Fanonly),
8 => Some(SystemMode::Dry),
9 => Some(SystemMode::Sleep),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<SystemMode> for u8 {
fn from(val: SystemMode) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum TemperatureSetpointHold {
Setpointholdoff = 0,
Setpointholdon = 1,
}
impl TemperatureSetpointHold {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(TemperatureSetpointHold::Setpointholdoff),
1 => Some(TemperatureSetpointHold::Setpointholdon),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<TemperatureSetpointHold> for u8 {
fn from(val: TemperatureSetpointHold) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum ThermostatRunningMode {
Off = 0,
Cool = 3,
Heat = 4,
}
impl ThermostatRunningMode {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(ThermostatRunningMode::Off),
3 => Some(ThermostatRunningMode::Cool),
4 => Some(ThermostatRunningMode::Heat),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<ThermostatRunningMode> for u8 {
fn from(val: ThermostatRunningMode) -> Self {
val as u8
}
}
pub type ACErrorCode = u8;
pub mod acerrorcode {
pub const COMPRESSOR_FAIL: u8 = 0x01;
pub const ROOM_SENSOR_FAIL: u8 = 0x02;
pub const OUTDOOR_SENSOR_FAIL: u8 = 0x04;
pub const COIL_SENSOR_FAIL: u8 = 0x08;
pub const FAN_FAIL: u8 = 0x10;
}
pub type Occupancy = u8;
pub mod occupancy {
pub const OCCUPIED: u8 = 0x01;
}
pub type PresetTypeFeatures = u8;
pub mod presettypefeatures {
pub const AUTOMATIC: u8 = 0x01;
pub const SUPPORTS_NAMES: u8 = 0x02;
}
pub type ProgrammingOperationMode = u8;
pub mod programmingoperationmode {
pub const SCHEDULE_ACTIVE: u8 = 0x01;
pub const AUTO_RECOVERY: u8 = 0x02;
pub const ECONOMY: u8 = 0x04;
}
pub type RelayState = u8;
pub mod relaystate {
pub const HEAT: u8 = 0x01;
pub const COOL: u8 = 0x02;
pub const FAN: u8 = 0x04;
pub const HEAT_STAGE2: u8 = 0x08;
pub const COOL_STAGE2: u8 = 0x10;
pub const FAN_STAGE2: u8 = 0x20;
pub const FAN_STAGE3: u8 = 0x40;
}
pub type RemoteSensing = u8;
pub mod remotesensing {
pub const LOCAL_TEMPERATURE: u8 = 0x01;
pub const OUTDOOR_TEMPERATURE: u8 = 0x02;
pub const OCCUPANCY: u8 = 0x04;
}
pub type ScheduleDayOfWeek = u8;
pub mod scheduledayofweek {
pub const SUNDAY: u8 = 0x01;
pub const MONDAY: u8 = 0x02;
pub const TUESDAY: u8 = 0x04;
pub const WEDNESDAY: u8 = 0x08;
pub const THURSDAY: u8 = 0x10;
pub const FRIDAY: u8 = 0x20;
pub const SATURDAY: u8 = 0x40;
pub const AWAY: u8 = 0x80;
}
pub type ScheduleMode = u8;
pub mod schedulemode {
pub const HEAT_SETPOINT_PRESENT: u8 = 0x01;
pub const COOL_SETPOINT_PRESENT: u8 = 0x02;
}
pub type ScheduleTypeFeatures = u8;
pub mod scheduletypefeatures {
pub const SUPPORTS_PRESETS: u8 = 0x01;
pub const SUPPORTS_SETPOINTS: u8 = 0x02;
pub const SUPPORTS_NAMES: u8 = 0x04;
pub const SUPPORTS_OFF: u8 = 0x08;
}
#[derive(Debug, serde::Serialize)]
pub struct Preset {
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub preset_handle: Option<Vec<u8>>,
pub preset_scenario: Option<PresetScenario>,
pub name: Option<String>,
pub cooling_setpoint: Option<i16>,
pub heating_setpoint: Option<i16>,
pub built_in: Option<bool>,
}
#[derive(Debug, serde::Serialize)]
pub struct PresetType {
pub preset_scenario: Option<PresetScenario>,
pub number_of_presets: Option<u8>,
pub preset_type_features: Option<PresetTypeFeatures>,
}
#[derive(Debug, serde::Serialize)]
pub struct Schedule {
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub schedule_handle: Option<Vec<u8>>,
pub system_mode: Option<SystemMode>,
pub name: Option<String>,
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub preset_handle: Option<Vec<u8>>,
pub transitions: Option<Vec<ScheduleTransition>>,
pub built_in: Option<bool>,
}
#[derive(Debug, serde::Serialize)]
pub struct ScheduleTransition {
pub day_of_week: Option<ScheduleDayOfWeek>,
pub transition_time: Option<u16>,
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub preset_handle: Option<Vec<u8>>,
pub system_mode: Option<SystemMode>,
pub cooling_setpoint: Option<i16>,
pub heating_setpoint: Option<i16>,
}
#[derive(Debug, serde::Serialize)]
pub struct ScheduleType {
pub system_mode: Option<SystemMode>,
pub number_of_schedules: Option<u8>,
pub schedule_type_features: Option<ScheduleTypeFeatures>,
}
#[derive(Debug, serde::Serialize)]
pub struct WeeklyScheduleTransition {
pub transition_time: Option<u16>,
pub heat_setpoint: Option<i16>,
pub cool_setpoint: Option<i16>,
}
pub fn encode_setpoint_raise_lower(mode: SetpointRaiseLowerMode, amount: i8) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(mode.to_u8())).into(),
(1, tlv::TlvItemValueEnc::Int8(amount)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_set_active_schedule_request(schedule_handle: Vec<u8>) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::OctetString(schedule_handle)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_set_active_preset_request(preset_handle: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::OctetString(preset_handle.unwrap_or(vec![]))).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn decode_local_temperature(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(Some(*v as i16))
} else {
Ok(None)
}
}
pub fn decode_outdoor_temperature(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(Some(*v as i16))
} else {
Ok(None)
}
}
pub fn decode_occupancy(inp: &tlv::TlvItemValue) -> anyhow::Result<Occupancy> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_abs_min_heat_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as i16)
} else {
Err(anyhow::anyhow!("Expected Int16"))
}
}
pub fn decode_abs_max_heat_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as i16)
} else {
Err(anyhow::anyhow!("Expected Int16"))
}
}
pub fn decode_abs_min_cool_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as i16)
} else {
Err(anyhow::anyhow!("Expected Int16"))
}
}
pub fn decode_abs_max_cool_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as i16)
} else {
Err(anyhow::anyhow!("Expected Int16"))
}
}
pub fn decode_pi_cooling_demand(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_pi_heating_demand(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_hvac_system_type_configuration(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_local_temperature_calibration(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_occupied_cooling_setpoint(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as i16)
} else {
Err(anyhow::anyhow!("Expected Int16"))
}
}
pub fn decode_occupied_heating_setpoint(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as i16)
} else {
Err(anyhow::anyhow!("Expected Int16"))
}
}
pub fn decode_unoccupied_cooling_setpoint(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as i16)
} else {
Err(anyhow::anyhow!("Expected Int16"))
}
}
pub fn decode_unoccupied_heating_setpoint(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as i16)
} else {
Err(anyhow::anyhow!("Expected Int16"))
}
}
pub fn decode_min_heat_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as i16)
} else {
Err(anyhow::anyhow!("Expected Int16"))
}
}
pub fn decode_max_heat_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as i16)
} else {
Err(anyhow::anyhow!("Expected Int16"))
}
}
pub fn decode_min_cool_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as i16)
} else {
Err(anyhow::anyhow!("Expected Int16"))
}
}
pub fn decode_max_cool_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as i16)
} else {
Err(anyhow::anyhow!("Expected Int16"))
}
}
pub fn decode_min_setpoint_dead_band(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_remote_sensing(inp: &tlv::TlvItemValue) -> anyhow::Result<RemoteSensing> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_control_sequence_of_operation(inp: &tlv::TlvItemValue) -> anyhow::Result<ControlSequenceOfOperation> {
if let tlv::TlvItemValue::Int(v) = inp {
ControlSequenceOfOperation::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_system_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<SystemMode> {
if let tlv::TlvItemValue::Int(v) = inp {
SystemMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_thermostat_running_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<ThermostatRunningMode> {
if let tlv::TlvItemValue::Int(v) = inp {
ThermostatRunningMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_temperature_setpoint_hold(inp: &tlv::TlvItemValue) -> anyhow::Result<TemperatureSetpointHold> {
if let tlv::TlvItemValue::Int(v) = inp {
TemperatureSetpointHold::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_temperature_setpoint_hold_duration(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(Some(*v as u16))
} else {
Ok(None)
}
}
pub fn decode_thermostat_programming_operation_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<ProgrammingOperationMode> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_thermostat_running_state(inp: &tlv::TlvItemValue) -> anyhow::Result<RelayState> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_setpoint_change_source(inp: &tlv::TlvItemValue) -> anyhow::Result<SetpointChangeSource> {
if let tlv::TlvItemValue::Int(v) = inp {
SetpointChangeSource::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_setpoint_change_amount(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(Some(*v as u8))
} else {
Ok(None)
}
}
pub fn decode_setpoint_change_source_timestamp(inp: &tlv::TlvItemValue) -> anyhow::Result<u64> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v)
} else {
Err(anyhow::anyhow!("Expected UInt64"))
}
}
pub fn decode_occupied_setback(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_occupied_setback_min(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_occupied_setback_max(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_unoccupied_setback(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_unoccupied_setback_min(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_unoccupied_setback_max(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_emergency_heat_delta(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_ac_type(inp: &tlv::TlvItemValue) -> anyhow::Result<ACType> {
if let tlv::TlvItemValue::Int(v) = inp {
ACType::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_ac_capacity(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u16)
} else {
Err(anyhow::anyhow!("Expected UInt16"))
}
}
pub fn decode_ac_refrigerant_type(inp: &tlv::TlvItemValue) -> anyhow::Result<ACRefrigerantType> {
if let tlv::TlvItemValue::Int(v) = inp {
ACRefrigerantType::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_ac_compressor_type(inp: &tlv::TlvItemValue) -> anyhow::Result<ACCompressorType> {
if let tlv::TlvItemValue::Int(v) = inp {
ACCompressorType::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_ac_error_code(inp: &tlv::TlvItemValue) -> anyhow::Result<ACErrorCode> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_aclouver_position(inp: &tlv::TlvItemValue) -> anyhow::Result<ACLouverPosition> {
if let tlv::TlvItemValue::Int(v) = inp {
ACLouverPosition::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_ac_coil_temperature(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(Some(*v as i16))
} else {
Ok(None)
}
}
pub fn decode_ac_capacity_format(inp: &tlv::TlvItemValue) -> anyhow::Result<ACCapacityFormat> {
if let tlv::TlvItemValue::Int(v) = inp {
ACCapacityFormat::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_preset_types(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<PresetType>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(PresetType {
preset_scenario: item.get_int(&[0]).and_then(|v| PresetScenario::from_u8(v as u8)),
number_of_presets: item.get_int(&[1]).map(|v| v as u8),
preset_type_features: item.get_int(&[2]).map(|v| v as u8),
});
}
}
Ok(res)
}
pub fn decode_schedule_types(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<ScheduleType>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(ScheduleType {
system_mode: item.get_int(&[0]).and_then(|v| SystemMode::from_u8(v as u8)),
number_of_schedules: item.get_int(&[1]).map(|v| v as u8),
schedule_type_features: item.get_int(&[2]).map(|v| v as u8),
});
}
}
Ok(res)
}
pub fn decode_number_of_presets(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_number_of_schedules(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_number_of_schedule_transitions(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_number_of_schedule_transition_per_day(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(Some(*v as u8))
} else {
Ok(None)
}
}
pub fn decode_active_preset_handle(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
if let tlv::TlvItemValue::OctetString(v) = inp {
Ok(Some(v.clone()))
} else {
Ok(None)
}
}
pub fn decode_active_schedule_handle(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
if let tlv::TlvItemValue::OctetString(v) = inp {
Ok(Some(v.clone()))
} else {
Ok(None)
}
}
pub fn decode_presets(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Preset>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(Preset {
preset_handle: item.get_octet_string_owned(&[0]),
preset_scenario: item.get_int(&[1]).and_then(|v| PresetScenario::from_u8(v as u8)),
name: item.get_string_owned(&[2]),
cooling_setpoint: item.get_int(&[3]).map(|v| v as i16),
heating_setpoint: item.get_int(&[4]).map(|v| v as i16),
built_in: item.get_bool(&[5]),
});
}
}
Ok(res)
}
pub fn decode_schedules(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Schedule>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(Schedule {
schedule_handle: item.get_octet_string_owned(&[0]),
system_mode: item.get_int(&[1]).and_then(|v| SystemMode::from_u8(v as u8)),
name: item.get_string_owned(&[2]),
preset_handle: item.get_octet_string_owned(&[3]),
transitions: {
if let Some(tlv::TlvItemValue::List(l)) = item.get(&[4]) {
let mut items = Vec::new();
for list_item in l {
items.push(ScheduleTransition {
day_of_week: list_item.get_int(&[0]).map(|v| v as u8),
transition_time: list_item.get_int(&[1]).map(|v| v as u16),
preset_handle: list_item.get_octet_string_owned(&[2]),
system_mode: list_item.get_int(&[3]).and_then(|v| SystemMode::from_u8(v as u8)),
cooling_setpoint: list_item.get_int(&[4]).map(|v| v as i16),
heating_setpoint: list_item.get_int(&[5]).map(|v| v as i16),
});
}
Some(items)
} else {
None
}
},
built_in: item.get_bool(&[5]),
});
}
}
Ok(res)
}
pub fn decode_setpoint_hold_expiry_timestamp(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(Some(*v))
} else {
Ok(None)
}
}
pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
if cluster_id != 0x0201 {
return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0201, got {}\"}}", cluster_id);
}
match attribute_id {
0x0000 => {
match decode_local_temperature(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0001 => {
match decode_outdoor_temperature(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0002 => {
match decode_occupancy(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0003 => {
match decode_abs_min_heat_setpoint_limit(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0004 => {
match decode_abs_max_heat_setpoint_limit(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0005 => {
match decode_abs_min_cool_setpoint_limit(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0006 => {
match decode_abs_max_cool_setpoint_limit(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0007 => {
match decode_pi_cooling_demand(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0008 => {
match decode_pi_heating_demand(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0009 => {
match decode_hvac_system_type_configuration(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0010 => {
match decode_local_temperature_calibration(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0011 => {
match decode_occupied_cooling_setpoint(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0012 => {
match decode_occupied_heating_setpoint(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0013 => {
match decode_unoccupied_cooling_setpoint(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0014 => {
match decode_unoccupied_heating_setpoint(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0015 => {
match decode_min_heat_setpoint_limit(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0016 => {
match decode_max_heat_setpoint_limit(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0017 => {
match decode_min_cool_setpoint_limit(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0018 => {
match decode_max_cool_setpoint_limit(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0019 => {
match decode_min_setpoint_dead_band(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x001A => {
match decode_remote_sensing(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x001B => {
match decode_control_sequence_of_operation(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x001C => {
match decode_system_mode(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x001E => {
match decode_thermostat_running_mode(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0023 => {
match decode_temperature_setpoint_hold(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0024 => {
match decode_temperature_setpoint_hold_duration(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0025 => {
match decode_thermostat_programming_operation_mode(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0029 => {
match decode_thermostat_running_state(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0030 => {
match decode_setpoint_change_source(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0031 => {
match decode_setpoint_change_amount(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0032 => {
match decode_setpoint_change_source_timestamp(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0034 => {
match decode_occupied_setback(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0035 => {
match decode_occupied_setback_min(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0036 => {
match decode_occupied_setback_max(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0037 => {
match decode_unoccupied_setback(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0038 => {
match decode_unoccupied_setback_min(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0039 => {
match decode_unoccupied_setback_max(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x003A => {
match decode_emergency_heat_delta(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0040 => {
match decode_ac_type(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0041 => {
match decode_ac_capacity(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0042 => {
match decode_ac_refrigerant_type(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0043 => {
match decode_ac_compressor_type(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0044 => {
match decode_ac_error_code(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0045 => {
match decode_aclouver_position(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0046 => {
match decode_ac_coil_temperature(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0047 => {
match decode_ac_capacity_format(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0048 => {
match decode_preset_types(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0049 => {
match decode_schedule_types(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x004A => {
match decode_number_of_presets(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x004B => {
match decode_number_of_schedules(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x004C => {
match decode_number_of_schedule_transitions(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x004D => {
match decode_number_of_schedule_transition_per_day(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x004E => {
match decode_active_preset_handle(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x004F => {
match decode_active_schedule_handle(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0050 => {
match decode_presets(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0051 => {
match decode_schedules(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0052 => {
match decode_setpoint_hold_expiry_timestamp(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
_ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
}
}
pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
vec![
(0x0000, "LocalTemperature"),
(0x0001, "OutdoorTemperature"),
(0x0002, "Occupancy"),
(0x0003, "AbsMinHeatSetpointLimit"),
(0x0004, "AbsMaxHeatSetpointLimit"),
(0x0005, "AbsMinCoolSetpointLimit"),
(0x0006, "AbsMaxCoolSetpointLimit"),
(0x0007, "PICoolingDemand"),
(0x0008, "PIHeatingDemand"),
(0x0009, "HVACSystemTypeConfiguration"),
(0x0010, "LocalTemperatureCalibration"),
(0x0011, "OccupiedCoolingSetpoint"),
(0x0012, "OccupiedHeatingSetpoint"),
(0x0013, "UnoccupiedCoolingSetpoint"),
(0x0014, "UnoccupiedHeatingSetpoint"),
(0x0015, "MinHeatSetpointLimit"),
(0x0016, "MaxHeatSetpointLimit"),
(0x0017, "MinCoolSetpointLimit"),
(0x0018, "MaxCoolSetpointLimit"),
(0x0019, "MinSetpointDeadBand"),
(0x001A, "RemoteSensing"),
(0x001B, "ControlSequenceOfOperation"),
(0x001C, "SystemMode"),
(0x001E, "ThermostatRunningMode"),
(0x0023, "TemperatureSetpointHold"),
(0x0024, "TemperatureSetpointHoldDuration"),
(0x0025, "ThermostatProgrammingOperationMode"),
(0x0029, "ThermostatRunningState"),
(0x0030, "SetpointChangeSource"),
(0x0031, "SetpointChangeAmount"),
(0x0032, "SetpointChangeSourceTimestamp"),
(0x0034, "OccupiedSetback"),
(0x0035, "OccupiedSetbackMin"),
(0x0036, "OccupiedSetbackMax"),
(0x0037, "UnoccupiedSetback"),
(0x0038, "UnoccupiedSetbackMin"),
(0x0039, "UnoccupiedSetbackMax"),
(0x003A, "EmergencyHeatDelta"),
(0x0040, "ACType"),
(0x0041, "ACCapacity"),
(0x0042, "ACRefrigerantType"),
(0x0043, "ACCompressorType"),
(0x0044, "ACErrorCode"),
(0x0045, "ACLouverPosition"),
(0x0046, "ACCoilTemperature"),
(0x0047, "ACCapacityFormat"),
(0x0048, "PresetTypes"),
(0x0049, "ScheduleTypes"),
(0x004A, "NumberOfPresets"),
(0x004B, "NumberOfSchedules"),
(0x004C, "NumberOfScheduleTransitions"),
(0x004D, "NumberOfScheduleTransitionPerDay"),
(0x004E, "ActivePresetHandle"),
(0x004F, "ActiveScheduleHandle"),
(0x0050, "Presets"),
(0x0051, "Schedules"),
(0x0052, "SetpointHoldExpiryTimestamp"),
]
}
pub fn get_command_list() -> Vec<(u32, &'static str)> {
vec![
(0x00, "SetpointRaiseLower"),
(0x05, "SetActiveScheduleRequest"),
(0x06, "SetActivePresetRequest"),
]
}
pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
match cmd_id {
0x00 => Some("SetpointRaiseLower"),
0x05 => Some("SetActiveScheduleRequest"),
0x06 => Some("SetActivePresetRequest"),
_ => None,
}
}
pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
match cmd_id {
0x00 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "mode", kind: crate::clusters::codec::FieldKind::Enum { name: "SetpointRaiseLowerMode", variants: &[(0, "Heat"), (1, "Cool"), (2, "Both")] }, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "amount", kind: crate::clusters::codec::FieldKind::I8, optional: false, nullable: false },
]),
0x05 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "schedule_handle", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
]),
0x06 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "preset_handle", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: true },
]),
_ => None,
}
}
pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
match cmd_id {
0x00 => {
let mode = {
let n = crate::clusters::codec::json_util::get_u64(args, "mode")?;
SetpointRaiseLowerMode::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid SetpointRaiseLowerMode: {}", n))?
};
let amount = crate::clusters::codec::json_util::get_i8(args, "amount")?;
encode_setpoint_raise_lower(mode, amount)
}
0x05 => {
let schedule_handle = crate::clusters::codec::json_util::get_octstr(args, "schedule_handle")?;
encode_set_active_schedule_request(schedule_handle)
}
0x06 => {
let preset_handle = crate::clusters::codec::json_util::get_opt_octstr(args, "preset_handle")?;
encode_set_active_preset_request(preset_handle)
}
_ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
}
}
pub async fn setpoint_raise_lower(conn: &crate::controller::Connection, endpoint: u16, mode: SetpointRaiseLowerMode, amount: i8) -> anyhow::Result<()> {
conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_CMD_ID_SETPOINTRAISELOWER, &encode_setpoint_raise_lower(mode, amount)?).await?;
Ok(())
}
pub async fn set_active_schedule_request(conn: &crate::controller::Connection, endpoint: u16, schedule_handle: Vec<u8>) -> anyhow::Result<()> {
conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_CMD_ID_SETACTIVESCHEDULEREQUEST, &encode_set_active_schedule_request(schedule_handle)?).await?;
Ok(())
}
pub async fn set_active_preset_request(conn: &crate::controller::Connection, endpoint: u16, preset_handle: Option<Vec<u8>>) -> anyhow::Result<()> {
conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_CMD_ID_SETACTIVEPRESETREQUEST, &encode_set_active_preset_request(preset_handle)?).await?;
Ok(())
}
pub async fn read_local_temperature(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<i16>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_LOCALTEMPERATURE).await?;
decode_local_temperature(&tlv)
}
pub async fn read_outdoor_temperature(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<i16>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OUTDOORTEMPERATURE).await?;
decode_outdoor_temperature(&tlv)
}
pub async fn read_occupancy(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Occupancy> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OCCUPANCY).await?;
decode_occupancy(&tlv)
}
pub async fn read_abs_min_heat_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ABSMINHEATSETPOINTLIMIT).await?;
decode_abs_min_heat_setpoint_limit(&tlv)
}
pub async fn read_abs_max_heat_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ABSMAXHEATSETPOINTLIMIT).await?;
decode_abs_max_heat_setpoint_limit(&tlv)
}
pub async fn read_abs_min_cool_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ABSMINCOOLSETPOINTLIMIT).await?;
decode_abs_min_cool_setpoint_limit(&tlv)
}
pub async fn read_abs_max_cool_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ABSMAXCOOLSETPOINTLIMIT).await?;
decode_abs_max_cool_setpoint_limit(&tlv)
}
pub async fn read_pi_cooling_demand(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_PICOOLINGDEMAND).await?;
decode_pi_cooling_demand(&tlv)
}
pub async fn read_pi_heating_demand(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_PIHEATINGDEMAND).await?;
decode_pi_heating_demand(&tlv)
}
pub async fn read_hvac_system_type_configuration(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_HVACSYSTEMTYPECONFIGURATION).await?;
decode_hvac_system_type_configuration(&tlv)
}
pub async fn read_local_temperature_calibration(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_LOCALTEMPERATURECALIBRATION).await?;
decode_local_temperature_calibration(&tlv)
}
pub async fn read_occupied_cooling_setpoint(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OCCUPIEDCOOLINGSETPOINT).await?;
decode_occupied_cooling_setpoint(&tlv)
}
pub async fn read_occupied_heating_setpoint(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OCCUPIEDHEATINGSETPOINT).await?;
decode_occupied_heating_setpoint(&tlv)
}
pub async fn read_unoccupied_cooling_setpoint(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_UNOCCUPIEDCOOLINGSETPOINT).await?;
decode_unoccupied_cooling_setpoint(&tlv)
}
pub async fn read_unoccupied_heating_setpoint(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_UNOCCUPIEDHEATINGSETPOINT).await?;
decode_unoccupied_heating_setpoint(&tlv)
}
pub async fn read_min_heat_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_MINHEATSETPOINTLIMIT).await?;
decode_min_heat_setpoint_limit(&tlv)
}
pub async fn read_max_heat_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_MAXHEATSETPOINTLIMIT).await?;
decode_max_heat_setpoint_limit(&tlv)
}
pub async fn read_min_cool_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_MINCOOLSETPOINTLIMIT).await?;
decode_min_cool_setpoint_limit(&tlv)
}
pub async fn read_max_cool_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_MAXCOOLSETPOINTLIMIT).await?;
decode_max_cool_setpoint_limit(&tlv)
}
pub async fn read_min_setpoint_dead_band(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_MINSETPOINTDEADBAND).await?;
decode_min_setpoint_dead_band(&tlv)
}
pub async fn read_remote_sensing(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<RemoteSensing> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_REMOTESENSING).await?;
decode_remote_sensing(&tlv)
}
pub async fn read_control_sequence_of_operation(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ControlSequenceOfOperation> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_CONTROLSEQUENCEOFOPERATION).await?;
decode_control_sequence_of_operation(&tlv)
}
pub async fn read_system_mode(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<SystemMode> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SYSTEMMODE).await?;
decode_system_mode(&tlv)
}
pub async fn read_thermostat_running_mode(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ThermostatRunningMode> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_THERMOSTATRUNNINGMODE).await?;
decode_thermostat_running_mode(&tlv)
}
pub async fn read_temperature_setpoint_hold(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<TemperatureSetpointHold> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_TEMPERATURESETPOINTHOLD).await?;
decode_temperature_setpoint_hold(&tlv)
}
pub async fn read_temperature_setpoint_hold_duration(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u16>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_TEMPERATURESETPOINTHOLDDURATION).await?;
decode_temperature_setpoint_hold_duration(&tlv)
}
pub async fn read_thermostat_programming_operation_mode(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ProgrammingOperationMode> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_THERMOSTATPROGRAMMINGOPERATIONMODE).await?;
decode_thermostat_programming_operation_mode(&tlv)
}
pub async fn read_thermostat_running_state(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<RelayState> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_THERMOSTATRUNNINGSTATE).await?;
decode_thermostat_running_state(&tlv)
}
pub async fn read_setpoint_change_source(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<SetpointChangeSource> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SETPOINTCHANGESOURCE).await?;
decode_setpoint_change_source(&tlv)
}
pub async fn read_setpoint_change_amount(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SETPOINTCHANGEAMOUNT).await?;
decode_setpoint_change_amount(&tlv)
}
pub async fn read_setpoint_change_source_timestamp(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u64> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SETPOINTCHANGESOURCETIMESTAMP).await?;
decode_setpoint_change_source_timestamp(&tlv)
}
pub async fn read_occupied_setback(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OCCUPIEDSETBACK).await?;
decode_occupied_setback(&tlv)
}
pub async fn read_occupied_setback_min(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OCCUPIEDSETBACKMIN).await?;
decode_occupied_setback_min(&tlv)
}
pub async fn read_occupied_setback_max(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OCCUPIEDSETBACKMAX).await?;
decode_occupied_setback_max(&tlv)
}
pub async fn read_unoccupied_setback(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_UNOCCUPIEDSETBACK).await?;
decode_unoccupied_setback(&tlv)
}
pub async fn read_unoccupied_setback_min(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_UNOCCUPIEDSETBACKMIN).await?;
decode_unoccupied_setback_min(&tlv)
}
pub async fn read_unoccupied_setback_max(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_UNOCCUPIEDSETBACKMAX).await?;
decode_unoccupied_setback_max(&tlv)
}
pub async fn read_emergency_heat_delta(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_EMERGENCYHEATDELTA).await?;
decode_emergency_heat_delta(&tlv)
}
pub async fn read_ac_type(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ACType> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACTYPE).await?;
decode_ac_type(&tlv)
}
pub async fn read_ac_capacity(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACCAPACITY).await?;
decode_ac_capacity(&tlv)
}
pub async fn read_ac_refrigerant_type(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ACRefrigerantType> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACREFRIGERANTTYPE).await?;
decode_ac_refrigerant_type(&tlv)
}
pub async fn read_ac_compressor_type(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ACCompressorType> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACCOMPRESSORTYPE).await?;
decode_ac_compressor_type(&tlv)
}
pub async fn read_ac_error_code(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ACErrorCode> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACERRORCODE).await?;
decode_ac_error_code(&tlv)
}
pub async fn read_aclouver_position(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ACLouverPosition> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACLOUVERPOSITION).await?;
decode_aclouver_position(&tlv)
}
pub async fn read_ac_coil_temperature(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<i16>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACCOILTEMPERATURE).await?;
decode_ac_coil_temperature(&tlv)
}
pub async fn read_ac_capacity_format(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ACCapacityFormat> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACCAPACITYFORMAT).await?;
decode_ac_capacity_format(&tlv)
}
pub async fn read_preset_types(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<PresetType>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_PRESETTYPES).await?;
decode_preset_types(&tlv)
}
pub async fn read_schedule_types(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<ScheduleType>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SCHEDULETYPES).await?;
decode_schedule_types(&tlv)
}
pub async fn read_number_of_presets(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_NUMBEROFPRESETS).await?;
decode_number_of_presets(&tlv)
}
pub async fn read_number_of_schedules(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_NUMBEROFSCHEDULES).await?;
decode_number_of_schedules(&tlv)
}
pub async fn read_number_of_schedule_transitions(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_NUMBEROFSCHEDULETRANSITIONS).await?;
decode_number_of_schedule_transitions(&tlv)
}
pub async fn read_number_of_schedule_transition_per_day(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_NUMBEROFSCHEDULETRANSITIONPERDAY).await?;
decode_number_of_schedule_transition_per_day(&tlv)
}
pub async fn read_active_preset_handle(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<Vec<u8>>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACTIVEPRESETHANDLE).await?;
decode_active_preset_handle(&tlv)
}
pub async fn read_active_schedule_handle(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<Vec<u8>>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACTIVESCHEDULEHANDLE).await?;
decode_active_schedule_handle(&tlv)
}
pub async fn read_presets(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<Preset>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_PRESETS).await?;
decode_presets(&tlv)
}
pub async fn read_schedules(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<Schedule>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SCHEDULES).await?;
decode_schedules(&tlv)
}
pub async fn read_setpoint_hold_expiry_timestamp(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u64>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SETPOINTHOLDEXPIRYTIMESTAMP).await?;
decode_setpoint_hold_expiry_timestamp(&tlv)
}