matc/clusters/codec/
level_control.rs

1//! Generated Matter TLV encoders and decoders for Level Control Cluster
2//! Cluster ID: 0x0008
3//! 
4//! This file is automatically generated from LevelControl.xml
5
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Command encoders
12
13/// Encode MoveToLevel command (0x00)
14pub fn encode_move_to_level(level: u8, transition_time: Option<u16>, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
15    let tlv = tlv::TlvItemEnc {
16        tag: 0,
17        value: tlv::TlvItemValueEnc::StructInvisible(vec![
18        (0, tlv::TlvItemValueEnc::UInt8(level)).into(),
19        (1, tlv::TlvItemValueEnc::UInt16(transition_time.unwrap_or(0))).into(),
20        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
21        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
22        ]),
23    };
24    Ok(tlv.encode()?)
25}
26
27/// Encode Move command (0x01)
28pub fn encode_move_(move_mode: u8, rate: Option<u8>, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
29    let tlv = tlv::TlvItemEnc {
30        tag: 0,
31        value: tlv::TlvItemValueEnc::StructInvisible(vec![
32        (0, tlv::TlvItemValueEnc::UInt8(move_mode)).into(),
33        (1, tlv::TlvItemValueEnc::UInt8(rate.unwrap_or(0))).into(),
34        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
35        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
36        ]),
37    };
38    Ok(tlv.encode()?)
39}
40
41/// Encode Step command (0x02)
42pub fn encode_step(step_mode: u8, step_size: u8, transition_time: Option<u16>, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
43    let tlv = tlv::TlvItemEnc {
44        tag: 0,
45        value: tlv::TlvItemValueEnc::StructInvisible(vec![
46        (0, tlv::TlvItemValueEnc::UInt8(step_mode)).into(),
47        (1, tlv::TlvItemValueEnc::UInt8(step_size)).into(),
48        (2, tlv::TlvItemValueEnc::UInt16(transition_time.unwrap_or(0))).into(),
49        (3, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
50        (4, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
51        ]),
52    };
53    Ok(tlv.encode()?)
54}
55
56/// Encode Stop command (0x03)
57pub fn encode_stop(options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
58    let tlv = tlv::TlvItemEnc {
59        tag: 0,
60        value: tlv::TlvItemValueEnc::StructInvisible(vec![
61        (0, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
62        (1, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
63        ]),
64    };
65    Ok(tlv.encode()?)
66}
67
68/// Encode MoveToLevelWithOnOff command (0x04)
69pub fn encode_move_to_level_with_on_off(level: u8, transition_time: Option<u16>, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
70    let tlv = tlv::TlvItemEnc {
71        tag: 0,
72        value: tlv::TlvItemValueEnc::StructInvisible(vec![
73        (0, tlv::TlvItemValueEnc::UInt8(level)).into(),
74        (1, tlv::TlvItemValueEnc::UInt16(transition_time.unwrap_or(0))).into(),
75        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
76        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
77        ]),
78    };
79    Ok(tlv.encode()?)
80}
81
82/// Encode MoveWithOnOff command (0x05)
83pub fn encode_move_with_on_off(move_mode: u8, rate: Option<u8>, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
84    let tlv = tlv::TlvItemEnc {
85        tag: 0,
86        value: tlv::TlvItemValueEnc::StructInvisible(vec![
87        (0, tlv::TlvItemValueEnc::UInt8(move_mode)).into(),
88        (1, tlv::TlvItemValueEnc::UInt8(rate.unwrap_or(0))).into(),
89        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
90        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
91        ]),
92    };
93    Ok(tlv.encode()?)
94}
95
96/// Encode StepWithOnOff command (0x06)
97pub fn encode_step_with_on_off(step_mode: u8, step_size: u8, transition_time: Option<u16>, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
98    let tlv = tlv::TlvItemEnc {
99        tag: 0,
100        value: tlv::TlvItemValueEnc::StructInvisible(vec![
101        (0, tlv::TlvItemValueEnc::UInt8(step_mode)).into(),
102        (1, tlv::TlvItemValueEnc::UInt8(step_size)).into(),
103        (2, tlv::TlvItemValueEnc::UInt16(transition_time.unwrap_or(0))).into(),
104        (3, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
105        (4, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
106        ]),
107    };
108    Ok(tlv.encode()?)
109}
110
111/// Encode StopWithOnOff command (0x07)
112pub fn encode_stop_with_on_off(options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
113    let tlv = tlv::TlvItemEnc {
114        tag: 0,
115        value: tlv::TlvItemValueEnc::StructInvisible(vec![
116        (0, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
117        (1, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
118        ]),
119    };
120    Ok(tlv.encode()?)
121}
122
123/// Encode MoveToClosestFrequency command (0x08)
124pub fn encode_move_to_closest_frequency(frequency: u16) -> anyhow::Result<Vec<u8>> {
125    let tlv = tlv::TlvItemEnc {
126        tag: 0,
127        value: tlv::TlvItemValueEnc::StructInvisible(vec![
128        (0, tlv::TlvItemValueEnc::UInt16(frequency)).into(),
129        ]),
130    };
131    Ok(tlv.encode()?)
132}
133
134// Attribute decoders
135
136/// Decode CurrentLevel attribute (0x0000)
137pub fn decode_current_level(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
138    if let tlv::TlvItemValue::Int(v) = inp {
139        Ok(Some(*v as u8))
140    } else {
141        Ok(None)
142    }
143}
144
145/// Decode RemainingTime attribute (0x0001)
146pub fn decode_remaining_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
147    if let tlv::TlvItemValue::Int(v) = inp {
148        Ok(*v as u16)
149    } else {
150        Err(anyhow::anyhow!("Expected Integer"))
151    }
152}
153
154/// Decode MinLevel attribute (0x0002)
155pub fn decode_min_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
156    if let tlv::TlvItemValue::Int(v) = inp {
157        Ok(*v as u8)
158    } else {
159        Err(anyhow::anyhow!("Expected Integer"))
160    }
161}
162
163/// Decode MaxLevel attribute (0x0003)
164pub fn decode_max_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
165    if let tlv::TlvItemValue::Int(v) = inp {
166        Ok(*v as u8)
167    } else {
168        Err(anyhow::anyhow!("Expected Integer"))
169    }
170}
171
172/// Decode CurrentFrequency attribute (0x0004)
173pub fn decode_current_frequency(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
174    if let tlv::TlvItemValue::Int(v) = inp {
175        Ok(*v as u16)
176    } else {
177        Err(anyhow::anyhow!("Expected Integer"))
178    }
179}
180
181/// Decode MinFrequency attribute (0x0005)
182pub fn decode_min_frequency(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
183    if let tlv::TlvItemValue::Int(v) = inp {
184        Ok(*v as u16)
185    } else {
186        Err(anyhow::anyhow!("Expected Integer"))
187    }
188}
189
190/// Decode MaxFrequency attribute (0x0006)
191pub fn decode_max_frequency(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
192    if let tlv::TlvItemValue::Int(v) = inp {
193        Ok(*v as u16)
194    } else {
195        Err(anyhow::anyhow!("Expected Integer"))
196    }
197}
198
199/// Decode Options attribute (0x000F)
200pub fn decode_options(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
201    if let tlv::TlvItemValue::Int(v) = inp {
202        Ok(*v as u8)
203    } else {
204        Err(anyhow::anyhow!("Expected Integer"))
205    }
206}
207
208/// Decode OnOffTransitionTime attribute (0x0010)
209pub fn decode_on_off_transition_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
210    if let tlv::TlvItemValue::Int(v) = inp {
211        Ok(*v as u16)
212    } else {
213        Err(anyhow::anyhow!("Expected Integer"))
214    }
215}
216
217/// Decode OnLevel attribute (0x0011)
218pub fn decode_on_level(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
219    if let tlv::TlvItemValue::Int(v) = inp {
220        Ok(Some(*v as u8))
221    } else {
222        Ok(None)
223    }
224}
225
226/// Decode OnTransitionTime attribute (0x0012)
227pub fn decode_on_transition_time(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
228    if let tlv::TlvItemValue::Int(v) = inp {
229        Ok(Some(*v as u16))
230    } else {
231        Ok(None)
232    }
233}
234
235/// Decode OffTransitionTime attribute (0x0013)
236pub fn decode_off_transition_time(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
237    if let tlv::TlvItemValue::Int(v) = inp {
238        Ok(Some(*v as u16))
239    } else {
240        Ok(None)
241    }
242}
243
244/// Decode DefaultMoveRate attribute (0x0014)
245pub fn decode_default_move_rate(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
246    if let tlv::TlvItemValue::Int(v) = inp {
247        Ok(Some(*v as u8))
248    } else {
249        Ok(None)
250    }
251}
252
253/// Decode StartUpCurrentLevel attribute (0x4000)
254pub fn decode_start_up_current_level(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
255    if let tlv::TlvItemValue::Int(v) = inp {
256        Ok(Some(*v as u8))
257    } else {
258        Ok(None)
259    }
260}
261
262
263// JSON dispatcher function
264
265/// Decode attribute value and return as JSON string
266/// 
267/// # Parameters
268/// * `cluster_id` - The cluster identifier
269/// * `attribute_id` - The attribute identifier
270/// * `tlv_value` - The TLV value to decode
271/// 
272/// # Returns
273/// JSON string representation of the decoded value or error
274pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
275    // Verify this is the correct cluster
276    if cluster_id != 0x0008 {
277        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0008, got {}\"}}", cluster_id);
278    }
279    
280    match attribute_id {
281        0x0000 => {
282            match decode_current_level(tlv_value) {
283                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
284                Err(e) => format!("{{\"error\": \"{}\"}}", e),
285            }
286        }
287        0x0001 => {
288            match decode_remaining_time(tlv_value) {
289                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
290                Err(e) => format!("{{\"error\": \"{}\"}}", e),
291            }
292        }
293        0x0002 => {
294            match decode_min_level(tlv_value) {
295                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
296                Err(e) => format!("{{\"error\": \"{}\"}}", e),
297            }
298        }
299        0x0003 => {
300            match decode_max_level(tlv_value) {
301                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
302                Err(e) => format!("{{\"error\": \"{}\"}}", e),
303            }
304        }
305        0x0004 => {
306            match decode_current_frequency(tlv_value) {
307                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
308                Err(e) => format!("{{\"error\": \"{}\"}}", e),
309            }
310        }
311        0x0005 => {
312            match decode_min_frequency(tlv_value) {
313                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
314                Err(e) => format!("{{\"error\": \"{}\"}}", e),
315            }
316        }
317        0x0006 => {
318            match decode_max_frequency(tlv_value) {
319                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
320                Err(e) => format!("{{\"error\": \"{}\"}}", e),
321            }
322        }
323        0x000F => {
324            match decode_options(tlv_value) {
325                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
326                Err(e) => format!("{{\"error\": \"{}\"}}", e),
327            }
328        }
329        0x0010 => {
330            match decode_on_off_transition_time(tlv_value) {
331                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
332                Err(e) => format!("{{\"error\": \"{}\"}}", e),
333            }
334        }
335        0x0011 => {
336            match decode_on_level(tlv_value) {
337                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
338                Err(e) => format!("{{\"error\": \"{}\"}}", e),
339            }
340        }
341        0x0012 => {
342            match decode_on_transition_time(tlv_value) {
343                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
344                Err(e) => format!("{{\"error\": \"{}\"}}", e),
345            }
346        }
347        0x0013 => {
348            match decode_off_transition_time(tlv_value) {
349                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
350                Err(e) => format!("{{\"error\": \"{}\"}}", e),
351            }
352        }
353        0x0014 => {
354            match decode_default_move_rate(tlv_value) {
355                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
356                Err(e) => format!("{{\"error\": \"{}\"}}", e),
357            }
358        }
359        0x4000 => {
360            match decode_start_up_current_level(tlv_value) {
361                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
362                Err(e) => format!("{{\"error\": \"{}\"}}", e),
363            }
364        }
365        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
366    }
367}
368
369/// Get list of all attributes supported by this cluster
370/// 
371/// # Returns
372/// Vector of tuples containing (attribute_id, attribute_name)
373pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
374    vec![
375        (0x0000, "CurrentLevel"),
376        (0x0001, "RemainingTime"),
377        (0x0002, "MinLevel"),
378        (0x0003, "MaxLevel"),
379        (0x0004, "CurrentFrequency"),
380        (0x0005, "MinFrequency"),
381        (0x0006, "MaxFrequency"),
382        (0x000F, "Options"),
383        (0x0010, "OnOffTransitionTime"),
384        (0x0011, "OnLevel"),
385        (0x0012, "OnTransitionTime"),
386        (0x0013, "OffTransitionTime"),
387        (0x0014, "DefaultMoveRate"),
388        (0x4000, "StartUpCurrentLevel"),
389    ]
390}
391