matc/clusters/codec/
temperature_control.rs

1//! Matter TLV encoders and decoders for Temperature Control Cluster
2//! Cluster ID: 0x0056
3//!
4//! This file is automatically generated from TemperatureControl.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Command encoders
14
15/// Encode SetTemperature command (0x00)
16pub fn encode_set_temperature(target_temperature: i16, target_temperature_level: u8) -> anyhow::Result<Vec<u8>> {
17    let tlv = tlv::TlvItemEnc {
18        tag: 0,
19        value: tlv::TlvItemValueEnc::StructInvisible(vec![
20        (0, tlv::TlvItemValueEnc::Int16(target_temperature)).into(),
21        (1, tlv::TlvItemValueEnc::UInt8(target_temperature_level)).into(),
22        ]),
23    };
24    Ok(tlv.encode()?)
25}
26
27// Attribute decoders
28
29/// Decode TemperatureSetpoint attribute (0x0000)
30pub fn decode_temperature_setpoint(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
31    if let tlv::TlvItemValue::Int(v) = inp {
32        Ok(*v as i16)
33    } else {
34        Err(anyhow::anyhow!("Expected Int16"))
35    }
36}
37
38/// Decode MinTemperature attribute (0x0001)
39pub fn decode_min_temperature(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
40    if let tlv::TlvItemValue::Int(v) = inp {
41        Ok(*v as i16)
42    } else {
43        Err(anyhow::anyhow!("Expected Int16"))
44    }
45}
46
47/// Decode MaxTemperature attribute (0x0002)
48pub fn decode_max_temperature(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
49    if let tlv::TlvItemValue::Int(v) = inp {
50        Ok(*v as i16)
51    } else {
52        Err(anyhow::anyhow!("Expected Int16"))
53    }
54}
55
56/// Decode Step attribute (0x0003)
57pub fn decode_step(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
58    if let tlv::TlvItemValue::Int(v) = inp {
59        Ok(*v as i16)
60    } else {
61        Err(anyhow::anyhow!("Expected Int16"))
62    }
63}
64
65/// Decode SelectedTemperatureLevel attribute (0x0004)
66pub fn decode_selected_temperature_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
67    if let tlv::TlvItemValue::Int(v) = inp {
68        Ok(*v as u8)
69    } else {
70        Err(anyhow::anyhow!("Expected UInt8"))
71    }
72}
73
74/// Decode SupportedTemperatureLevels attribute (0x0005)
75pub fn decode_supported_temperature_levels(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<String>> {
76    let mut res = Vec::new();
77    if let tlv::TlvItemValue::List(v) = inp {
78        for item in v {
79            if let tlv::TlvItemValue::String(s) = &item.value {
80                res.push(s.clone());
81            }
82        }
83    }
84    Ok(res)
85}
86
87
88// JSON dispatcher function
89
90/// Decode attribute value and return as JSON string
91///
92/// # Parameters
93/// * `cluster_id` - The cluster identifier
94/// * `attribute_id` - The attribute identifier
95/// * `tlv_value` - The TLV value to decode
96///
97/// # Returns
98/// JSON string representation of the decoded value or error
99pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
100    // Verify this is the correct cluster
101    if cluster_id != 0x0056 {
102        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0056, got {}\"}}", cluster_id);
103    }
104
105    match attribute_id {
106        0x0000 => {
107            match decode_temperature_setpoint(tlv_value) {
108                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
109                Err(e) => format!("{{\"error\": \"{}\"}}", e),
110            }
111        }
112        0x0001 => {
113            match decode_min_temperature(tlv_value) {
114                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
115                Err(e) => format!("{{\"error\": \"{}\"}}", e),
116            }
117        }
118        0x0002 => {
119            match decode_max_temperature(tlv_value) {
120                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
121                Err(e) => format!("{{\"error\": \"{}\"}}", e),
122            }
123        }
124        0x0003 => {
125            match decode_step(tlv_value) {
126                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
127                Err(e) => format!("{{\"error\": \"{}\"}}", e),
128            }
129        }
130        0x0004 => {
131            match decode_selected_temperature_level(tlv_value) {
132                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
133                Err(e) => format!("{{\"error\": \"{}\"}}", e),
134            }
135        }
136        0x0005 => {
137            match decode_supported_temperature_levels(tlv_value) {
138                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
139                Err(e) => format!("{{\"error\": \"{}\"}}", e),
140            }
141        }
142        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
143    }
144}
145
146/// Get list of all attributes supported by this cluster
147///
148/// # Returns
149/// Vector of tuples containing (attribute_id, attribute_name)
150pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
151    vec![
152        (0x0000, "TemperatureSetpoint"),
153        (0x0001, "MinTemperature"),
154        (0x0002, "MaxTemperature"),
155        (0x0003, "Step"),
156        (0x0004, "SelectedTemperatureLevel"),
157        (0x0005, "SupportedTemperatureLevels"),
158    ]
159}
160
161// Command listing
162
163pub fn get_command_list() -> Vec<(u32, &'static str)> {
164    vec![
165        (0x00, "SetTemperature"),
166    ]
167}
168
169pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
170    match cmd_id {
171        0x00 => Some("SetTemperature"),
172        _ => None,
173    }
174}
175
176pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
177    match cmd_id {
178        0x00 => Some(vec![
179            crate::clusters::codec::CommandField { tag: 0, name: "target_temperature", kind: crate::clusters::codec::FieldKind::I16, optional: false, nullable: false },
180            crate::clusters::codec::CommandField { tag: 1, name: "target_temperature_level", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
181        ]),
182        _ => None,
183    }
184}
185
186pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
187    match cmd_id {
188        0x00 => {
189        let target_temperature = crate::clusters::codec::json_util::get_i16(args, "target_temperature")?;
190        let target_temperature_level = crate::clusters::codec::json_util::get_u8(args, "target_temperature_level")?;
191        encode_set_temperature(target_temperature, target_temperature_level)
192        }
193        _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
194    }
195}
196
197// Typed facade (invokes + reads)
198
199/// Invoke `SetTemperature` command on cluster `Temperature Control`.
200pub async fn set_temperature(conn: &crate::controller::Connection, endpoint: u16, target_temperature: i16, target_temperature_level: u8) -> anyhow::Result<()> {
201    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_CONTROL, crate::clusters::defs::CLUSTER_TEMPERATURE_CONTROL_CMD_ID_SETTEMPERATURE, &encode_set_temperature(target_temperature, target_temperature_level)?).await?;
202    Ok(())
203}
204
205/// Read `TemperatureSetpoint` attribute from cluster `Temperature Control`.
206pub async fn read_temperature_setpoint(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
207    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_CONTROL, crate::clusters::defs::CLUSTER_TEMPERATURE_CONTROL_ATTR_ID_TEMPERATURESETPOINT).await?;
208    decode_temperature_setpoint(&tlv)
209}
210
211/// Read `MinTemperature` attribute from cluster `Temperature Control`.
212pub async fn read_min_temperature(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
213    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_CONTROL, crate::clusters::defs::CLUSTER_TEMPERATURE_CONTROL_ATTR_ID_MINTEMPERATURE).await?;
214    decode_min_temperature(&tlv)
215}
216
217/// Read `MaxTemperature` attribute from cluster `Temperature Control`.
218pub async fn read_max_temperature(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
219    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_CONTROL, crate::clusters::defs::CLUSTER_TEMPERATURE_CONTROL_ATTR_ID_MAXTEMPERATURE).await?;
220    decode_max_temperature(&tlv)
221}
222
223/// Read `Step` attribute from cluster `Temperature Control`.
224pub async fn read_step(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
225    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_CONTROL, crate::clusters::defs::CLUSTER_TEMPERATURE_CONTROL_ATTR_ID_STEP).await?;
226    decode_step(&tlv)
227}
228
229/// Read `SelectedTemperatureLevel` attribute from cluster `Temperature Control`.
230pub async fn read_selected_temperature_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
231    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_CONTROL, crate::clusters::defs::CLUSTER_TEMPERATURE_CONTROL_ATTR_ID_SELECTEDTEMPERATURELEVEL).await?;
232    decode_selected_temperature_level(&tlv)
233}
234
235/// Read `SupportedTemperatureLevels` attribute from cluster `Temperature Control`.
236pub async fn read_supported_temperature_levels(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<String>> {
237    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_CONTROL, crate::clusters::defs::CLUSTER_TEMPERATURE_CONTROL_ATTR_ID_SUPPORTEDTEMPERATURELEVELS).await?;
238    decode_supported_temperature_levels(&tlv)
239}
240