matc/clusters/codec/
level_control.rs

1//! Matter TLV encoders and decoders for Level Control Cluster
2//! Cluster ID: 0x0008
3//!
4//! This file is automatically generated from LevelControl.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Enum definitions
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
16#[repr(u8)]
17pub enum MoveMode {
18    /// Increase the level
19    Up = 0,
20    /// Decrease the level
21    Down = 1,
22}
23
24impl MoveMode {
25    /// Convert from u8 value
26    pub fn from_u8(value: u8) -> Option<Self> {
27        match value {
28            0 => Some(MoveMode::Up),
29            1 => Some(MoveMode::Down),
30            _ => None,
31        }
32    }
33
34    /// Convert to u8 value
35    pub fn to_u8(self) -> u8 {
36        self as u8
37    }
38}
39
40impl From<MoveMode> for u8 {
41    fn from(val: MoveMode) -> Self {
42        val as u8
43    }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
47#[repr(u8)]
48pub enum StepMode {
49    /// Step upwards
50    Up = 0,
51    /// Step downwards
52    Down = 1,
53}
54
55impl StepMode {
56    /// Convert from u8 value
57    pub fn from_u8(value: u8) -> Option<Self> {
58        match value {
59            0 => Some(StepMode::Up),
60            1 => Some(StepMode::Down),
61            _ => None,
62        }
63    }
64
65    /// Convert to u8 value
66    pub fn to_u8(self) -> u8 {
67        self as u8
68    }
69}
70
71impl From<StepMode> for u8 {
72    fn from(val: StepMode) -> Self {
73        val as u8
74    }
75}
76
77// Bitmap definitions
78
79/// Options bitmap type
80pub type Options = u8;
81
82/// Constants for Options
83pub mod options {
84    /// Dependency on On/Off cluster
85    pub const EXECUTE_IF_OFF: u8 = 0x01;
86    /// Dependency on Color Control cluster
87    pub const COUPLE_COLOR_TEMP_TO_LEVEL: u8 = 0x02;
88}
89
90// Command encoders
91
92/// Encode MoveToLevel command (0x00)
93pub fn encode_move_to_level(level: u8, transition_time: Option<u16>, options_mask: Options, options_override: Options) -> anyhow::Result<Vec<u8>> {
94    let tlv = tlv::TlvItemEnc {
95        tag: 0,
96        value: tlv::TlvItemValueEnc::StructInvisible(vec![
97        (0, tlv::TlvItemValueEnc::UInt8(level)).into(),
98        (1, tlv::TlvItemValueEnc::UInt16(transition_time.unwrap_or(0))).into(),
99        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
100        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
101        ]),
102    };
103    Ok(tlv.encode()?)
104}
105
106/// Encode Move command (0x01)
107pub fn encode_move_(move_mode: MoveMode, rate: Option<u8>, options_mask: Options, options_override: Options) -> anyhow::Result<Vec<u8>> {
108    let tlv = tlv::TlvItemEnc {
109        tag: 0,
110        value: tlv::TlvItemValueEnc::StructInvisible(vec![
111        (0, tlv::TlvItemValueEnc::UInt8(move_mode.to_u8())).into(),
112        (1, tlv::TlvItemValueEnc::UInt8(rate.unwrap_or(0))).into(),
113        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
114        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
115        ]),
116    };
117    Ok(tlv.encode()?)
118}
119
120/// Encode Step command (0x02)
121pub fn encode_step(step_mode: StepMode, step_size: u8, transition_time: Option<u16>, options_mask: Options, options_override: Options) -> anyhow::Result<Vec<u8>> {
122    let tlv = tlv::TlvItemEnc {
123        tag: 0,
124        value: tlv::TlvItemValueEnc::StructInvisible(vec![
125        (0, tlv::TlvItemValueEnc::UInt8(step_mode.to_u8())).into(),
126        (1, tlv::TlvItemValueEnc::UInt8(step_size)).into(),
127        (2, tlv::TlvItemValueEnc::UInt16(transition_time.unwrap_or(0))).into(),
128        (3, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
129        (4, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
130        ]),
131    };
132    Ok(tlv.encode()?)
133}
134
135/// Encode Stop command (0x03)
136pub fn encode_stop(options_mask: Options, options_override: Options) -> anyhow::Result<Vec<u8>> {
137    let tlv = tlv::TlvItemEnc {
138        tag: 0,
139        value: tlv::TlvItemValueEnc::StructInvisible(vec![
140        (0, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
141        (1, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
142        ]),
143    };
144    Ok(tlv.encode()?)
145}
146
147/// Encode MoveToLevelWithOnOff command (0x04)
148pub fn encode_move_to_level_with_on_off(level: u8, transition_time: Option<u16>, options_mask: Options, options_override: Options) -> anyhow::Result<Vec<u8>> {
149    let tlv = tlv::TlvItemEnc {
150        tag: 0,
151        value: tlv::TlvItemValueEnc::StructInvisible(vec![
152        (0, tlv::TlvItemValueEnc::UInt8(level)).into(),
153        (1, tlv::TlvItemValueEnc::UInt16(transition_time.unwrap_or(0))).into(),
154        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
155        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
156        ]),
157    };
158    Ok(tlv.encode()?)
159}
160
161/// Encode MoveWithOnOff command (0x05)
162pub fn encode_move_with_on_off(move_mode: MoveMode, rate: Option<u8>, options_mask: Options, options_override: Options) -> anyhow::Result<Vec<u8>> {
163    let tlv = tlv::TlvItemEnc {
164        tag: 0,
165        value: tlv::TlvItemValueEnc::StructInvisible(vec![
166        (0, tlv::TlvItemValueEnc::UInt8(move_mode.to_u8())).into(),
167        (1, tlv::TlvItemValueEnc::UInt8(rate.unwrap_or(0))).into(),
168        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
169        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
170        ]),
171    };
172    Ok(tlv.encode()?)
173}
174
175/// Encode StepWithOnOff command (0x06)
176pub fn encode_step_with_on_off(step_mode: StepMode, step_size: u8, transition_time: Option<u16>, options_mask: Options, options_override: Options) -> anyhow::Result<Vec<u8>> {
177    let tlv = tlv::TlvItemEnc {
178        tag: 0,
179        value: tlv::TlvItemValueEnc::StructInvisible(vec![
180        (0, tlv::TlvItemValueEnc::UInt8(step_mode.to_u8())).into(),
181        (1, tlv::TlvItemValueEnc::UInt8(step_size)).into(),
182        (2, tlv::TlvItemValueEnc::UInt16(transition_time.unwrap_or(0))).into(),
183        (3, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
184        (4, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
185        ]),
186    };
187    Ok(tlv.encode()?)
188}
189
190/// Encode StopWithOnOff command (0x07)
191pub fn encode_stop_with_on_off(options_mask: Options, options_override: Options) -> anyhow::Result<Vec<u8>> {
192    let tlv = tlv::TlvItemEnc {
193        tag: 0,
194        value: tlv::TlvItemValueEnc::StructInvisible(vec![
195        (0, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
196        (1, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
197        ]),
198    };
199    Ok(tlv.encode()?)
200}
201
202/// Encode MoveToClosestFrequency command (0x08)
203pub fn encode_move_to_closest_frequency(frequency: u16) -> anyhow::Result<Vec<u8>> {
204    let tlv = tlv::TlvItemEnc {
205        tag: 0,
206        value: tlv::TlvItemValueEnc::StructInvisible(vec![
207        (0, tlv::TlvItemValueEnc::UInt16(frequency)).into(),
208        ]),
209    };
210    Ok(tlv.encode()?)
211}
212
213// Attribute decoders
214
215/// Decode CurrentLevel attribute (0x0000)
216pub fn decode_current_level(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
217    if let tlv::TlvItemValue::Int(v) = inp {
218        Ok(Some(*v as u8))
219    } else {
220        Ok(None)
221    }
222}
223
224/// Decode RemainingTime attribute (0x0001)
225pub fn decode_remaining_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
226    if let tlv::TlvItemValue::Int(v) = inp {
227        Ok(*v as u16)
228    } else {
229        Err(anyhow::anyhow!("Expected UInt16"))
230    }
231}
232
233/// Decode MinLevel attribute (0x0002)
234pub fn decode_min_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
235    if let tlv::TlvItemValue::Int(v) = inp {
236        Ok(*v as u8)
237    } else {
238        Err(anyhow::anyhow!("Expected UInt8"))
239    }
240}
241
242/// Decode MaxLevel attribute (0x0003)
243pub fn decode_max_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
244    if let tlv::TlvItemValue::Int(v) = inp {
245        Ok(*v as u8)
246    } else {
247        Err(anyhow::anyhow!("Expected UInt8"))
248    }
249}
250
251/// Decode CurrentFrequency attribute (0x0004)
252pub fn decode_current_frequency(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
253    if let tlv::TlvItemValue::Int(v) = inp {
254        Ok(*v as u16)
255    } else {
256        Err(anyhow::anyhow!("Expected UInt16"))
257    }
258}
259
260/// Decode MinFrequency attribute (0x0005)
261pub fn decode_min_frequency(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
262    if let tlv::TlvItemValue::Int(v) = inp {
263        Ok(*v as u16)
264    } else {
265        Err(anyhow::anyhow!("Expected UInt16"))
266    }
267}
268
269/// Decode MaxFrequency attribute (0x0006)
270pub fn decode_max_frequency(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
271    if let tlv::TlvItemValue::Int(v) = inp {
272        Ok(*v as u16)
273    } else {
274        Err(anyhow::anyhow!("Expected UInt16"))
275    }
276}
277
278/// Decode Options attribute (0x000F)
279pub fn decode_options(inp: &tlv::TlvItemValue) -> anyhow::Result<Options> {
280    if let tlv::TlvItemValue::Int(v) = inp {
281        Ok(*v as u8)
282    } else {
283        Err(anyhow::anyhow!("Expected Integer"))
284    }
285}
286
287/// Decode OnOffTransitionTime attribute (0x0010)
288pub fn decode_on_off_transition_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
289    if let tlv::TlvItemValue::Int(v) = inp {
290        Ok(*v as u16)
291    } else {
292        Err(anyhow::anyhow!("Expected UInt16"))
293    }
294}
295
296/// Decode OnLevel attribute (0x0011)
297pub fn decode_on_level(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
298    if let tlv::TlvItemValue::Int(v) = inp {
299        Ok(Some(*v as u8))
300    } else {
301        Ok(None)
302    }
303}
304
305/// Decode OnTransitionTime attribute (0x0012)
306pub fn decode_on_transition_time(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
307    if let tlv::TlvItemValue::Int(v) = inp {
308        Ok(Some(*v as u16))
309    } else {
310        Ok(None)
311    }
312}
313
314/// Decode OffTransitionTime attribute (0x0013)
315pub fn decode_off_transition_time(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
316    if let tlv::TlvItemValue::Int(v) = inp {
317        Ok(Some(*v as u16))
318    } else {
319        Ok(None)
320    }
321}
322
323/// Decode DefaultMoveRate attribute (0x0014)
324pub fn decode_default_move_rate(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
325    if let tlv::TlvItemValue::Int(v) = inp {
326        Ok(Some(*v as u8))
327    } else {
328        Ok(None)
329    }
330}
331
332/// Decode StartUpCurrentLevel attribute (0x4000)
333pub fn decode_start_up_current_level(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
334    if let tlv::TlvItemValue::Int(v) = inp {
335        Ok(Some(*v as u8))
336    } else {
337        Ok(None)
338    }
339}
340
341
342// JSON dispatcher function
343
344/// Decode attribute value and return as JSON string
345///
346/// # Parameters
347/// * `cluster_id` - The cluster identifier
348/// * `attribute_id` - The attribute identifier
349/// * `tlv_value` - The TLV value to decode
350///
351/// # Returns
352/// JSON string representation of the decoded value or error
353pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
354    // Verify this is the correct cluster
355    if cluster_id != 0x0008 {
356        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0008, got {}\"}}", cluster_id);
357    }
358
359    match attribute_id {
360        0x0000 => {
361            match decode_current_level(tlv_value) {
362                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
363                Err(e) => format!("{{\"error\": \"{}\"}}", e),
364            }
365        }
366        0x0001 => {
367            match decode_remaining_time(tlv_value) {
368                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
369                Err(e) => format!("{{\"error\": \"{}\"}}", e),
370            }
371        }
372        0x0002 => {
373            match decode_min_level(tlv_value) {
374                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
375                Err(e) => format!("{{\"error\": \"{}\"}}", e),
376            }
377        }
378        0x0003 => {
379            match decode_max_level(tlv_value) {
380                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
381                Err(e) => format!("{{\"error\": \"{}\"}}", e),
382            }
383        }
384        0x0004 => {
385            match decode_current_frequency(tlv_value) {
386                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
387                Err(e) => format!("{{\"error\": \"{}\"}}", e),
388            }
389        }
390        0x0005 => {
391            match decode_min_frequency(tlv_value) {
392                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
393                Err(e) => format!("{{\"error\": \"{}\"}}", e),
394            }
395        }
396        0x0006 => {
397            match decode_max_frequency(tlv_value) {
398                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
399                Err(e) => format!("{{\"error\": \"{}\"}}", e),
400            }
401        }
402        0x000F => {
403            match decode_options(tlv_value) {
404                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
405                Err(e) => format!("{{\"error\": \"{}\"}}", e),
406            }
407        }
408        0x0010 => {
409            match decode_on_off_transition_time(tlv_value) {
410                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
411                Err(e) => format!("{{\"error\": \"{}\"}}", e),
412            }
413        }
414        0x0011 => {
415            match decode_on_level(tlv_value) {
416                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
417                Err(e) => format!("{{\"error\": \"{}\"}}", e),
418            }
419        }
420        0x0012 => {
421            match decode_on_transition_time(tlv_value) {
422                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
423                Err(e) => format!("{{\"error\": \"{}\"}}", e),
424            }
425        }
426        0x0013 => {
427            match decode_off_transition_time(tlv_value) {
428                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
429                Err(e) => format!("{{\"error\": \"{}\"}}", e),
430            }
431        }
432        0x0014 => {
433            match decode_default_move_rate(tlv_value) {
434                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
435                Err(e) => format!("{{\"error\": \"{}\"}}", e),
436            }
437        }
438        0x4000 => {
439            match decode_start_up_current_level(tlv_value) {
440                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
441                Err(e) => format!("{{\"error\": \"{}\"}}", e),
442            }
443        }
444        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
445    }
446}
447
448/// Get list of all attributes supported by this cluster
449///
450/// # Returns
451/// Vector of tuples containing (attribute_id, attribute_name)
452pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
453    vec![
454        (0x0000, "CurrentLevel"),
455        (0x0001, "RemainingTime"),
456        (0x0002, "MinLevel"),
457        (0x0003, "MaxLevel"),
458        (0x0004, "CurrentFrequency"),
459        (0x0005, "MinFrequency"),
460        (0x0006, "MaxFrequency"),
461        (0x000F, "Options"),
462        (0x0010, "OnOffTransitionTime"),
463        (0x0011, "OnLevel"),
464        (0x0012, "OnTransitionTime"),
465        (0x0013, "OffTransitionTime"),
466        (0x0014, "DefaultMoveRate"),
467        (0x4000, "StartUpCurrentLevel"),
468    ]
469}
470
471// Command listing
472
473pub fn get_command_list() -> Vec<(u32, &'static str)> {
474    vec![
475        (0x00, "MoveToLevel"),
476        (0x01, "Move"),
477        (0x02, "Step"),
478        (0x03, "Stop"),
479        (0x04, "MoveToLevelWithOnOff"),
480        (0x05, "MoveWithOnOff"),
481        (0x06, "StepWithOnOff"),
482        (0x07, "StopWithOnOff"),
483        (0x08, "MoveToClosestFrequency"),
484    ]
485}
486
487pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
488    match cmd_id {
489        0x00 => Some("MoveToLevel"),
490        0x01 => Some("Move"),
491        0x02 => Some("Step"),
492        0x03 => Some("Stop"),
493        0x04 => Some("MoveToLevelWithOnOff"),
494        0x05 => Some("MoveWithOnOff"),
495        0x06 => Some("StepWithOnOff"),
496        0x07 => Some("StopWithOnOff"),
497        0x08 => Some("MoveToClosestFrequency"),
498        _ => None,
499    }
500}
501
502pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
503    match cmd_id {
504        0x00 => Some(vec![
505            crate::clusters::codec::CommandField { tag: 0, name: "level", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
506            crate::clusters::codec::CommandField { tag: 1, name: "transition_time", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: true },
507            crate::clusters::codec::CommandField { tag: 2, name: "options_mask", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
508            crate::clusters::codec::CommandField { tag: 3, name: "options_override", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
509        ]),
510        0x01 => Some(vec![
511            crate::clusters::codec::CommandField { tag: 0, name: "move_mode", kind: crate::clusters::codec::FieldKind::Enum { name: "MoveMode", variants: &[(0, "Up"), (1, "Down")] }, optional: false, nullable: false },
512            crate::clusters::codec::CommandField { tag: 1, name: "rate", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: true },
513            crate::clusters::codec::CommandField { tag: 2, name: "options_mask", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
514            crate::clusters::codec::CommandField { tag: 3, name: "options_override", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
515        ]),
516        0x02 => Some(vec![
517            crate::clusters::codec::CommandField { tag: 0, name: "step_mode", kind: crate::clusters::codec::FieldKind::Enum { name: "StepMode", variants: &[(0, "Up"), (1, "Down")] }, optional: false, nullable: false },
518            crate::clusters::codec::CommandField { tag: 1, name: "step_size", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
519            crate::clusters::codec::CommandField { tag: 2, name: "transition_time", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: true },
520            crate::clusters::codec::CommandField { tag: 3, name: "options_mask", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
521            crate::clusters::codec::CommandField { tag: 4, name: "options_override", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
522        ]),
523        0x03 => Some(vec![
524            crate::clusters::codec::CommandField { tag: 0, name: "options_mask", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
525            crate::clusters::codec::CommandField { tag: 1, name: "options_override", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
526        ]),
527        0x04 => Some(vec![
528            crate::clusters::codec::CommandField { tag: 0, name: "level", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
529            crate::clusters::codec::CommandField { tag: 1, name: "transition_time", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: true },
530            crate::clusters::codec::CommandField { tag: 2, name: "options_mask", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
531            crate::clusters::codec::CommandField { tag: 3, name: "options_override", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
532        ]),
533        0x05 => Some(vec![
534            crate::clusters::codec::CommandField { tag: 0, name: "move_mode", kind: crate::clusters::codec::FieldKind::Enum { name: "MoveMode", variants: &[(0, "Up"), (1, "Down")] }, optional: false, nullable: false },
535            crate::clusters::codec::CommandField { tag: 1, name: "rate", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: true },
536            crate::clusters::codec::CommandField { tag: 2, name: "options_mask", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
537            crate::clusters::codec::CommandField { tag: 3, name: "options_override", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
538        ]),
539        0x06 => Some(vec![
540            crate::clusters::codec::CommandField { tag: 0, name: "step_mode", kind: crate::clusters::codec::FieldKind::Enum { name: "StepMode", variants: &[(0, "Up"), (1, "Down")] }, optional: false, nullable: false },
541            crate::clusters::codec::CommandField { tag: 1, name: "step_size", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
542            crate::clusters::codec::CommandField { tag: 2, name: "transition_time", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: true },
543            crate::clusters::codec::CommandField { tag: 3, name: "options_mask", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
544            crate::clusters::codec::CommandField { tag: 4, name: "options_override", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
545        ]),
546        0x07 => Some(vec![
547            crate::clusters::codec::CommandField { tag: 0, name: "options_mask", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
548            crate::clusters::codec::CommandField { tag: 1, name: "options_override", kind: crate::clusters::codec::FieldKind::Bitmap { name: "Options", bits: &[(1, "EXECUTE_IF_OFF"), (2, "COUPLE_COLOR_TEMP_TO_LEVEL")] }, optional: false, nullable: false },
549        ]),
550        0x08 => Some(vec![
551            crate::clusters::codec::CommandField { tag: 0, name: "frequency", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
552        ]),
553        _ => None,
554    }
555}
556
557pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
558    match cmd_id {
559        0x00 => {
560        let level = crate::clusters::codec::json_util::get_u8(args, "level")?;
561        let transition_time = crate::clusters::codec::json_util::get_opt_u16(args, "transition_time")?;
562        let options_mask = crate::clusters::codec::json_util::get_u8(args, "options_mask")?;
563        let options_override = crate::clusters::codec::json_util::get_u8(args, "options_override")?;
564        encode_move_to_level(level, transition_time, options_mask, options_override)
565        }
566        0x01 => {
567        let move_mode = {
568            let n = crate::clusters::codec::json_util::get_u64(args, "move_mode")?;
569            MoveMode::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid MoveMode: {}", n))?
570        };
571        let rate = crate::clusters::codec::json_util::get_opt_u8(args, "rate")?;
572        let options_mask = crate::clusters::codec::json_util::get_u8(args, "options_mask")?;
573        let options_override = crate::clusters::codec::json_util::get_u8(args, "options_override")?;
574        encode_move_(move_mode, rate, options_mask, options_override)
575        }
576        0x02 => {
577        let step_mode = {
578            let n = crate::clusters::codec::json_util::get_u64(args, "step_mode")?;
579            StepMode::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid StepMode: {}", n))?
580        };
581        let step_size = crate::clusters::codec::json_util::get_u8(args, "step_size")?;
582        let transition_time = crate::clusters::codec::json_util::get_opt_u16(args, "transition_time")?;
583        let options_mask = crate::clusters::codec::json_util::get_u8(args, "options_mask")?;
584        let options_override = crate::clusters::codec::json_util::get_u8(args, "options_override")?;
585        encode_step(step_mode, step_size, transition_time, options_mask, options_override)
586        }
587        0x03 => {
588        let options_mask = crate::clusters::codec::json_util::get_u8(args, "options_mask")?;
589        let options_override = crate::clusters::codec::json_util::get_u8(args, "options_override")?;
590        encode_stop(options_mask, options_override)
591        }
592        0x04 => {
593        let level = crate::clusters::codec::json_util::get_u8(args, "level")?;
594        let transition_time = crate::clusters::codec::json_util::get_opt_u16(args, "transition_time")?;
595        let options_mask = crate::clusters::codec::json_util::get_u8(args, "options_mask")?;
596        let options_override = crate::clusters::codec::json_util::get_u8(args, "options_override")?;
597        encode_move_to_level_with_on_off(level, transition_time, options_mask, options_override)
598        }
599        0x05 => {
600        let move_mode = {
601            let n = crate::clusters::codec::json_util::get_u64(args, "move_mode")?;
602            MoveMode::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid MoveMode: {}", n))?
603        };
604        let rate = crate::clusters::codec::json_util::get_opt_u8(args, "rate")?;
605        let options_mask = crate::clusters::codec::json_util::get_u8(args, "options_mask")?;
606        let options_override = crate::clusters::codec::json_util::get_u8(args, "options_override")?;
607        encode_move_with_on_off(move_mode, rate, options_mask, options_override)
608        }
609        0x06 => {
610        let step_mode = {
611            let n = crate::clusters::codec::json_util::get_u64(args, "step_mode")?;
612            StepMode::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid StepMode: {}", n))?
613        };
614        let step_size = crate::clusters::codec::json_util::get_u8(args, "step_size")?;
615        let transition_time = crate::clusters::codec::json_util::get_opt_u16(args, "transition_time")?;
616        let options_mask = crate::clusters::codec::json_util::get_u8(args, "options_mask")?;
617        let options_override = crate::clusters::codec::json_util::get_u8(args, "options_override")?;
618        encode_step_with_on_off(step_mode, step_size, transition_time, options_mask, options_override)
619        }
620        0x07 => {
621        let options_mask = crate::clusters::codec::json_util::get_u8(args, "options_mask")?;
622        let options_override = crate::clusters::codec::json_util::get_u8(args, "options_override")?;
623        encode_stop_with_on_off(options_mask, options_override)
624        }
625        0x08 => {
626        let frequency = crate::clusters::codec::json_util::get_u16(args, "frequency")?;
627        encode_move_to_closest_frequency(frequency)
628        }
629        _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
630    }
631}
632
633// Typed facade (invokes + reads)
634
635/// Invoke `MoveToLevel` command on cluster `Level Control`.
636pub async fn move_to_level(conn: &crate::controller::Connection, endpoint: u16, level: u8, transition_time: Option<u16>, options_mask: Options, options_override: Options) -> anyhow::Result<()> {
637    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_CMD_ID_MOVETOLEVEL, &encode_move_to_level(level, transition_time, options_mask, options_override)?).await?;
638    Ok(())
639}
640
641/// Invoke `Move` command on cluster `Level Control`.
642pub async fn move_(conn: &crate::controller::Connection, endpoint: u16, move_mode: MoveMode, rate: Option<u8>, options_mask: Options, options_override: Options) -> anyhow::Result<()> {
643    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_CMD_ID_MOVE, &encode_move_(move_mode, rate, options_mask, options_override)?).await?;
644    Ok(())
645}
646
647/// Invoke `Step` command on cluster `Level Control`.
648pub async fn step(conn: &crate::controller::Connection, endpoint: u16, step_mode: StepMode, step_size: u8, transition_time: Option<u16>, options_mask: Options, options_override: Options) -> anyhow::Result<()> {
649    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_CMD_ID_STEP, &encode_step(step_mode, step_size, transition_time, options_mask, options_override)?).await?;
650    Ok(())
651}
652
653/// Invoke `Stop` command on cluster `Level Control`.
654pub async fn stop(conn: &crate::controller::Connection, endpoint: u16, options_mask: Options, options_override: Options) -> anyhow::Result<()> {
655    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_CMD_ID_STOP, &encode_stop(options_mask, options_override)?).await?;
656    Ok(())
657}
658
659/// Invoke `MoveToLevelWithOnOff` command on cluster `Level Control`.
660pub async fn move_to_level_with_on_off(conn: &crate::controller::Connection, endpoint: u16, level: u8, transition_time: Option<u16>, options_mask: Options, options_override: Options) -> anyhow::Result<()> {
661    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_CMD_ID_MOVETOLEVELWITHONOFF, &encode_move_to_level_with_on_off(level, transition_time, options_mask, options_override)?).await?;
662    Ok(())
663}
664
665/// Invoke `MoveWithOnOff` command on cluster `Level Control`.
666pub async fn move_with_on_off(conn: &crate::controller::Connection, endpoint: u16, move_mode: MoveMode, rate: Option<u8>, options_mask: Options, options_override: Options) -> anyhow::Result<()> {
667    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_CMD_ID_MOVEWITHONOFF, &encode_move_with_on_off(move_mode, rate, options_mask, options_override)?).await?;
668    Ok(())
669}
670
671/// Invoke `StepWithOnOff` command on cluster `Level Control`.
672pub async fn step_with_on_off(conn: &crate::controller::Connection, endpoint: u16, step_mode: StepMode, step_size: u8, transition_time: Option<u16>, options_mask: Options, options_override: Options) -> anyhow::Result<()> {
673    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_CMD_ID_STEPWITHONOFF, &encode_step_with_on_off(step_mode, step_size, transition_time, options_mask, options_override)?).await?;
674    Ok(())
675}
676
677/// Invoke `StopWithOnOff` command on cluster `Level Control`.
678pub async fn stop_with_on_off(conn: &crate::controller::Connection, endpoint: u16, options_mask: Options, options_override: Options) -> anyhow::Result<()> {
679    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_CMD_ID_STOPWITHONOFF, &encode_stop_with_on_off(options_mask, options_override)?).await?;
680    Ok(())
681}
682
683/// Invoke `MoveToClosestFrequency` command on cluster `Level Control`.
684pub async fn move_to_closest_frequency(conn: &crate::controller::Connection, endpoint: u16, frequency: u16) -> anyhow::Result<()> {
685    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_CMD_ID_MOVETOCLOSESTFREQUENCY, &encode_move_to_closest_frequency(frequency)?).await?;
686    Ok(())
687}
688
689/// Read `CurrentLevel` attribute from cluster `Level Control`.
690pub async fn read_current_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
691    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_CURRENTLEVEL).await?;
692    decode_current_level(&tlv)
693}
694
695/// Read `RemainingTime` attribute from cluster `Level Control`.
696pub async fn read_remaining_time(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
697    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_REMAININGTIME).await?;
698    decode_remaining_time(&tlv)
699}
700
701/// Read `MinLevel` attribute from cluster `Level Control`.
702pub async fn read_min_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
703    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_MINLEVEL).await?;
704    decode_min_level(&tlv)
705}
706
707/// Read `MaxLevel` attribute from cluster `Level Control`.
708pub async fn read_max_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
709    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_MAXLEVEL).await?;
710    decode_max_level(&tlv)
711}
712
713/// Read `CurrentFrequency` attribute from cluster `Level Control`.
714pub async fn read_current_frequency(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
715    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_CURRENTFREQUENCY).await?;
716    decode_current_frequency(&tlv)
717}
718
719/// Read `MinFrequency` attribute from cluster `Level Control`.
720pub async fn read_min_frequency(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
721    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_MINFREQUENCY).await?;
722    decode_min_frequency(&tlv)
723}
724
725/// Read `MaxFrequency` attribute from cluster `Level Control`.
726pub async fn read_max_frequency(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
727    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_MAXFREQUENCY).await?;
728    decode_max_frequency(&tlv)
729}
730
731/// Read `Options` attribute from cluster `Level Control`.
732pub async fn read_options(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Options> {
733    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_OPTIONS).await?;
734    decode_options(&tlv)
735}
736
737/// Read `OnOffTransitionTime` attribute from cluster `Level Control`.
738pub async fn read_on_off_transition_time(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
739    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_ONOFFTRANSITIONTIME).await?;
740    decode_on_off_transition_time(&tlv)
741}
742
743/// Read `OnLevel` attribute from cluster `Level Control`.
744pub async fn read_on_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
745    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_ONLEVEL).await?;
746    decode_on_level(&tlv)
747}
748
749/// Read `OnTransitionTime` attribute from cluster `Level Control`.
750pub async fn read_on_transition_time(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u16>> {
751    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_ONTRANSITIONTIME).await?;
752    decode_on_transition_time(&tlv)
753}
754
755/// Read `OffTransitionTime` attribute from cluster `Level Control`.
756pub async fn read_off_transition_time(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u16>> {
757    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_OFFTRANSITIONTIME).await?;
758    decode_off_transition_time(&tlv)
759}
760
761/// Read `DefaultMoveRate` attribute from cluster `Level Control`.
762pub async fn read_default_move_rate(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
763    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_DEFAULTMOVERATE).await?;
764    decode_default_move_rate(&tlv)
765}
766
767/// Read `StartUpCurrentLevel` attribute from cluster `Level Control`.
768pub async fn read_start_up_current_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
769    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_LEVEL_CONTROL, crate::clusters::defs::CLUSTER_LEVEL_CONTROL_ATTR_ID_STARTUPCURRENTLEVEL).await?;
770    decode_start_up_current_level(&tlv)
771}
772