matc/clusters/codec/
color_control.rs

1//! Generated Matter TLV encoders and decoders for Color Control Cluster
2//! Cluster ID: 0x0300
3//! 
4//! This file is automatically generated from ColorControl.xml
5
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Command encoders
12
13/// Encode MoveToHue command (0x00)
14pub fn encode_move_to_hue(hue: u8, direction: u8, transition_time: 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(hue)).into(),
19        (1, tlv::TlvItemValueEnc::UInt8(direction)).into(),
20        (2, tlv::TlvItemValueEnc::UInt16(transition_time)).into(),
21        (3, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
22        (4, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
23        ]),
24    };
25    Ok(tlv.encode()?)
26}
27
28/// Encode MoveHue command (0x01)
29pub fn encode_move_hue(move_mode: u8, rate: u8, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
30    let tlv = tlv::TlvItemEnc {
31        tag: 0,
32        value: tlv::TlvItemValueEnc::StructInvisible(vec![
33        (0, tlv::TlvItemValueEnc::UInt8(move_mode)).into(),
34        (1, tlv::TlvItemValueEnc::UInt8(rate)).into(),
35        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
36        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
37        ]),
38    };
39    Ok(tlv.encode()?)
40}
41
42/// Encode StepHue command (0x02)
43pub fn encode_step_hue(step_mode: u8, step_size: u8, transition_time: u8, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
44    let tlv = tlv::TlvItemEnc {
45        tag: 0,
46        value: tlv::TlvItemValueEnc::StructInvisible(vec![
47        (0, tlv::TlvItemValueEnc::UInt8(step_mode)).into(),
48        (1, tlv::TlvItemValueEnc::UInt8(step_size)).into(),
49        (2, tlv::TlvItemValueEnc::UInt8(transition_time)).into(),
50        (3, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
51        (4, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
52        ]),
53    };
54    Ok(tlv.encode()?)
55}
56
57/// Encode MoveToSaturation command (0x03)
58pub fn encode_move_to_saturation(saturation: u8, transition_time: u16, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
59    let tlv = tlv::TlvItemEnc {
60        tag: 0,
61        value: tlv::TlvItemValueEnc::StructInvisible(vec![
62        (0, tlv::TlvItemValueEnc::UInt8(saturation)).into(),
63        (1, tlv::TlvItemValueEnc::UInt16(transition_time)).into(),
64        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
65        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
66        ]),
67    };
68    Ok(tlv.encode()?)
69}
70
71/// Encode MoveSaturation command (0x04)
72pub fn encode_move_saturation(move_mode: u8, rate: u8, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
73    let tlv = tlv::TlvItemEnc {
74        tag: 0,
75        value: tlv::TlvItemValueEnc::StructInvisible(vec![
76        (0, tlv::TlvItemValueEnc::UInt8(move_mode)).into(),
77        (1, tlv::TlvItemValueEnc::UInt8(rate)).into(),
78        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
79        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
80        ]),
81    };
82    Ok(tlv.encode()?)
83}
84
85/// Encode StepSaturation command (0x05)
86pub fn encode_step_saturation(step_mode: u8, step_size: u8, transition_time: u8, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
87    let tlv = tlv::TlvItemEnc {
88        tag: 0,
89        value: tlv::TlvItemValueEnc::StructInvisible(vec![
90        (0, tlv::TlvItemValueEnc::UInt8(step_mode)).into(),
91        (1, tlv::TlvItemValueEnc::UInt8(step_size)).into(),
92        (2, tlv::TlvItemValueEnc::UInt8(transition_time)).into(),
93        (3, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
94        (4, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
95        ]),
96    };
97    Ok(tlv.encode()?)
98}
99
100/// Encode MoveToHueAndSaturation command (0x06)
101pub fn encode_move_to_hue_and_saturation(hue: u8, saturation: u8, transition_time: u16, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
102    let tlv = tlv::TlvItemEnc {
103        tag: 0,
104        value: tlv::TlvItemValueEnc::StructInvisible(vec![
105        (0, tlv::TlvItemValueEnc::UInt8(hue)).into(),
106        (1, tlv::TlvItemValueEnc::UInt8(saturation)).into(),
107        (2, tlv::TlvItemValueEnc::UInt16(transition_time)).into(),
108        (3, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
109        (4, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
110        ]),
111    };
112    Ok(tlv.encode()?)
113}
114
115/// Encode MoveToColor command (0x07)
116pub fn encode_move_to_color(color_x: u16, color_y: u16, transition_time: u16, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
117    let tlv = tlv::TlvItemEnc {
118        tag: 0,
119        value: tlv::TlvItemValueEnc::StructInvisible(vec![
120        (0, tlv::TlvItemValueEnc::UInt16(color_x)).into(),
121        (1, tlv::TlvItemValueEnc::UInt16(color_y)).into(),
122        (2, tlv::TlvItemValueEnc::UInt16(transition_time)).into(),
123        (3, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
124        (4, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
125        ]),
126    };
127    Ok(tlv.encode()?)
128}
129
130/// Encode MoveColor command (0x08)
131pub fn encode_move_color(rate_x: i16, rate_y: i16, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
132    let tlv = tlv::TlvItemEnc {
133        tag: 0,
134        value: tlv::TlvItemValueEnc::StructInvisible(vec![
135        (0, tlv::TlvItemValueEnc::Int16(rate_x)).into(),
136        (1, tlv::TlvItemValueEnc::Int16(rate_y)).into(),
137        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
138        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
139        ]),
140    };
141    Ok(tlv.encode()?)
142}
143
144/// Encode StepColor command (0x09)
145pub fn encode_step_color(step_x: i16, step_y: i16, transition_time: u16, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
146    let tlv = tlv::TlvItemEnc {
147        tag: 0,
148        value: tlv::TlvItemValueEnc::StructInvisible(vec![
149        (0, tlv::TlvItemValueEnc::Int16(step_x)).into(),
150        (1, tlv::TlvItemValueEnc::Int16(step_y)).into(),
151        (2, tlv::TlvItemValueEnc::UInt16(transition_time)).into(),
152        (3, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
153        (4, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
154        ]),
155    };
156    Ok(tlv.encode()?)
157}
158
159/// Encode MoveToColorTemperature command (0x0A)
160pub fn encode_move_to_color_temperature(color_temperature_mireds: u16, transition_time: u16, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
161    let tlv = tlv::TlvItemEnc {
162        tag: 0,
163        value: tlv::TlvItemValueEnc::StructInvisible(vec![
164        (0, tlv::TlvItemValueEnc::UInt16(color_temperature_mireds)).into(),
165        (1, tlv::TlvItemValueEnc::UInt16(transition_time)).into(),
166        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
167        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
168        ]),
169    };
170    Ok(tlv.encode()?)
171}
172
173/// Encode EnhancedMoveToHue command (0x40)
174pub fn encode_enhanced_move_to_hue(enhanced_hue: u16, direction: u8, transition_time: u16, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
175    let tlv = tlv::TlvItemEnc {
176        tag: 0,
177        value: tlv::TlvItemValueEnc::StructInvisible(vec![
178        (0, tlv::TlvItemValueEnc::UInt16(enhanced_hue)).into(),
179        (1, tlv::TlvItemValueEnc::UInt8(direction)).into(),
180        (2, tlv::TlvItemValueEnc::UInt16(transition_time)).into(),
181        (3, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
182        (4, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
183        ]),
184    };
185    Ok(tlv.encode()?)
186}
187
188/// Encode EnhancedMoveHue command (0x41)
189pub fn encode_enhanced_move_hue(move_mode: u8, rate: u16, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
190    let tlv = tlv::TlvItemEnc {
191        tag: 0,
192        value: tlv::TlvItemValueEnc::StructInvisible(vec![
193        (0, tlv::TlvItemValueEnc::UInt8(move_mode)).into(),
194        (1, tlv::TlvItemValueEnc::UInt16(rate)).into(),
195        (2, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
196        (3, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
197        ]),
198    };
199    Ok(tlv.encode()?)
200}
201
202/// Encode EnhancedStepHue command (0x42)
203pub fn encode_enhanced_step_hue(step_mode: u8, step_size: u16, transition_time: u16, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
204    let tlv = tlv::TlvItemEnc {
205        tag: 0,
206        value: tlv::TlvItemValueEnc::StructInvisible(vec![
207        (0, tlv::TlvItemValueEnc::UInt8(step_mode)).into(),
208        (1, tlv::TlvItemValueEnc::UInt16(step_size)).into(),
209        (2, tlv::TlvItemValueEnc::UInt16(transition_time)).into(),
210        (3, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
211        (4, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
212        ]),
213    };
214    Ok(tlv.encode()?)
215}
216
217/// Encode EnhancedMoveToHueAndSaturation command (0x43)
218pub fn encode_enhanced_move_to_hue_and_saturation(enhanced_hue: u16, saturation: u8, transition_time: u16, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
219    let tlv = tlv::TlvItemEnc {
220        tag: 0,
221        value: tlv::TlvItemValueEnc::StructInvisible(vec![
222        (0, tlv::TlvItemValueEnc::UInt16(enhanced_hue)).into(),
223        (1, tlv::TlvItemValueEnc::UInt8(saturation)).into(),
224        (2, tlv::TlvItemValueEnc::UInt16(transition_time)).into(),
225        (3, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
226        (4, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
227        ]),
228    };
229    Ok(tlv.encode()?)
230}
231
232/// Encode ColorLoopSet command (0x44)
233pub fn encode_color_loop_set(update_flags: u8, action: u8, direction: u8, time: u16, start_hue: u16, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
234    let tlv = tlv::TlvItemEnc {
235        tag: 0,
236        value: tlv::TlvItemValueEnc::StructInvisible(vec![
237        (0, tlv::TlvItemValueEnc::UInt8(update_flags)).into(),
238        (1, tlv::TlvItemValueEnc::UInt8(action)).into(),
239        (2, tlv::TlvItemValueEnc::UInt8(direction)).into(),
240        (3, tlv::TlvItemValueEnc::UInt16(time)).into(),
241        (4, tlv::TlvItemValueEnc::UInt16(start_hue)).into(),
242        (5, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
243        (6, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
244        ]),
245    };
246    Ok(tlv.encode()?)
247}
248
249/// Encode StopMoveStep command (0x47)
250pub fn encode_stop_move_step(options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
251    let tlv = tlv::TlvItemEnc {
252        tag: 0,
253        value: tlv::TlvItemValueEnc::StructInvisible(vec![
254        (0, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
255        (1, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
256        ]),
257    };
258    Ok(tlv.encode()?)
259}
260
261/// Encode MoveColorTemperature command (0x4B)
262pub fn encode_move_color_temperature(move_mode: u8, rate: u16, color_temperature_minimum_mireds: u16, color_temperature_maximum_mireds: u16, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
263    let tlv = tlv::TlvItemEnc {
264        tag: 0,
265        value: tlv::TlvItemValueEnc::StructInvisible(vec![
266        (0, tlv::TlvItemValueEnc::UInt8(move_mode)).into(),
267        (1, tlv::TlvItemValueEnc::UInt16(rate)).into(),
268        (2, tlv::TlvItemValueEnc::UInt16(color_temperature_minimum_mireds)).into(),
269        (3, tlv::TlvItemValueEnc::UInt16(color_temperature_maximum_mireds)).into(),
270        (4, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
271        (5, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
272        ]),
273    };
274    Ok(tlv.encode()?)
275}
276
277/// Encode StepColorTemperature command (0x4C)
278pub fn encode_step_color_temperature(step_mode: u8, step_size: u16, transition_time: u16, color_temperature_minimum_mireds: u16, color_temperature_maximum_mireds: u16, options_mask: u8, options_override: u8) -> anyhow::Result<Vec<u8>> {
279    let tlv = tlv::TlvItemEnc {
280        tag: 0,
281        value: tlv::TlvItemValueEnc::StructInvisible(vec![
282        (0, tlv::TlvItemValueEnc::UInt8(step_mode)).into(),
283        (1, tlv::TlvItemValueEnc::UInt16(step_size)).into(),
284        (2, tlv::TlvItemValueEnc::UInt16(transition_time)).into(),
285        (3, tlv::TlvItemValueEnc::UInt16(color_temperature_minimum_mireds)).into(),
286        (4, tlv::TlvItemValueEnc::UInt16(color_temperature_maximum_mireds)).into(),
287        (5, tlv::TlvItemValueEnc::UInt8(options_mask)).into(),
288        (6, tlv::TlvItemValueEnc::UInt8(options_override)).into(),
289        ]),
290    };
291    Ok(tlv.encode()?)
292}
293
294// Attribute decoders
295
296/// Decode CurrentHue attribute (0x0000)
297pub fn decode_current_hue(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
298    if let tlv::TlvItemValue::Int(v) = inp {
299        Ok(*v as u8)
300    } else {
301        Err(anyhow::anyhow!("Expected Integer"))
302    }
303}
304
305/// Decode CurrentSaturation attribute (0x0001)
306pub fn decode_current_saturation(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
307    if let tlv::TlvItemValue::Int(v) = inp {
308        Ok(*v as u8)
309    } else {
310        Err(anyhow::anyhow!("Expected Integer"))
311    }
312}
313
314/// Decode RemainingTime attribute (0x0002)
315pub fn decode_remaining_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
316    if let tlv::TlvItemValue::Int(v) = inp {
317        Ok(*v as u16)
318    } else {
319        Err(anyhow::anyhow!("Expected Integer"))
320    }
321}
322
323/// Decode CurrentX attribute (0x0003)
324pub fn decode_current_x(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
325    if let tlv::TlvItemValue::Int(v) = inp {
326        Ok(*v as u16)
327    } else {
328        Err(anyhow::anyhow!("Expected Integer"))
329    }
330}
331
332/// Decode CurrentY attribute (0x0004)
333pub fn decode_current_y(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
334    if let tlv::TlvItemValue::Int(v) = inp {
335        Ok(*v as u16)
336    } else {
337        Err(anyhow::anyhow!("Expected Integer"))
338    }
339}
340
341/// Decode DriftCompensation attribute (0x0005)
342pub fn decode_drift_compensation(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
343    if let tlv::TlvItemValue::Int(v) = inp {
344        Ok(*v as u8)
345    } else {
346        Err(anyhow::anyhow!("Expected Integer"))
347    }
348}
349
350/// Decode CompensationText attribute (0x0006)
351pub fn decode_compensation_text(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
352    if let tlv::TlvItemValue::String(v) = inp {
353        Ok(v.clone())
354    } else {
355        Err(anyhow::anyhow!("Expected String"))
356    }
357}
358
359/// Decode ColorTemperatureMireds attribute (0x0007)
360pub fn decode_color_temperature_mireds(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
361    if let tlv::TlvItemValue::Int(v) = inp {
362        Ok(*v as u16)
363    } else {
364        Err(anyhow::anyhow!("Expected Integer"))
365    }
366}
367
368/// Decode ColorMode attribute (0x0008)
369pub fn decode_color_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
370    if let tlv::TlvItemValue::Int(v) = inp {
371        Ok(*v as u8)
372    } else {
373        Err(anyhow::anyhow!("Expected Integer"))
374    }
375}
376
377/// Decode Options attribute (0x000F)
378pub fn decode_options(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
379    if let tlv::TlvItemValue::Int(v) = inp {
380        Ok(*v as u8)
381    } else {
382        Err(anyhow::anyhow!("Expected Integer"))
383    }
384}
385
386/// Decode NumberOfPrimaries attribute (0x0010)
387pub fn decode_number_of_primaries(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
388    if let tlv::TlvItemValue::Int(v) = inp {
389        Ok(Some(*v as u8))
390    } else {
391        Ok(None)
392    }
393}
394
395/// Decode Primary1X attribute (0x0011)
396pub fn decode_primary1_x(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
397    if let tlv::TlvItemValue::Int(v) = inp {
398        Ok(*v as u16)
399    } else {
400        Err(anyhow::anyhow!("Expected Integer"))
401    }
402}
403
404/// Decode Primary1Y attribute (0x0012)
405pub fn decode_primary1_y(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
406    if let tlv::TlvItemValue::Int(v) = inp {
407        Ok(*v as u16)
408    } else {
409        Err(anyhow::anyhow!("Expected Integer"))
410    }
411}
412
413/// Decode Primary1Intensity attribute (0x0013)
414pub fn decode_primary1_intensity(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
415    if let tlv::TlvItemValue::Int(v) = inp {
416        Ok(Some(*v as u8))
417    } else {
418        Ok(None)
419    }
420}
421
422/// Decode Primary2X attribute (0x0015)
423pub fn decode_primary2_x(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
424    if let tlv::TlvItemValue::Int(v) = inp {
425        Ok(*v as u16)
426    } else {
427        Err(anyhow::anyhow!("Expected Integer"))
428    }
429}
430
431/// Decode Primary2Y attribute (0x0016)
432pub fn decode_primary2_y(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
433    if let tlv::TlvItemValue::Int(v) = inp {
434        Ok(*v as u16)
435    } else {
436        Err(anyhow::anyhow!("Expected Integer"))
437    }
438}
439
440/// Decode Primary2Intensity attribute (0x0017)
441pub fn decode_primary2_intensity(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
442    if let tlv::TlvItemValue::Int(v) = inp {
443        Ok(Some(*v as u8))
444    } else {
445        Ok(None)
446    }
447}
448
449/// Decode Primary3X attribute (0x0019)
450pub fn decode_primary3_x(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
451    if let tlv::TlvItemValue::Int(v) = inp {
452        Ok(*v as u16)
453    } else {
454        Err(anyhow::anyhow!("Expected Integer"))
455    }
456}
457
458/// Decode Primary3Y attribute (0x001A)
459pub fn decode_primary3_y(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
460    if let tlv::TlvItemValue::Int(v) = inp {
461        Ok(*v as u16)
462    } else {
463        Err(anyhow::anyhow!("Expected Integer"))
464    }
465}
466
467/// Decode Primary3Intensity attribute (0x001B)
468pub fn decode_primary3_intensity(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
469    if let tlv::TlvItemValue::Int(v) = inp {
470        Ok(Some(*v as u8))
471    } else {
472        Ok(None)
473    }
474}
475
476/// Decode Primary4X attribute (0x0020)
477pub fn decode_primary4_x(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
478    if let tlv::TlvItemValue::Int(v) = inp {
479        Ok(*v as u16)
480    } else {
481        Err(anyhow::anyhow!("Expected Integer"))
482    }
483}
484
485/// Decode Primary4Y attribute (0x0021)
486pub fn decode_primary4_y(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
487    if let tlv::TlvItemValue::Int(v) = inp {
488        Ok(*v as u16)
489    } else {
490        Err(anyhow::anyhow!("Expected Integer"))
491    }
492}
493
494/// Decode Primary4Intensity attribute (0x0022)
495pub fn decode_primary4_intensity(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
496    if let tlv::TlvItemValue::Int(v) = inp {
497        Ok(Some(*v as u8))
498    } else {
499        Ok(None)
500    }
501}
502
503/// Decode Primary5X attribute (0x0024)
504pub fn decode_primary5_x(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
505    if let tlv::TlvItemValue::Int(v) = inp {
506        Ok(*v as u16)
507    } else {
508        Err(anyhow::anyhow!("Expected Integer"))
509    }
510}
511
512/// Decode Primary5Y attribute (0x0025)
513pub fn decode_primary5_y(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
514    if let tlv::TlvItemValue::Int(v) = inp {
515        Ok(*v as u16)
516    } else {
517        Err(anyhow::anyhow!("Expected Integer"))
518    }
519}
520
521/// Decode Primary5Intensity attribute (0x0026)
522pub fn decode_primary5_intensity(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
523    if let tlv::TlvItemValue::Int(v) = inp {
524        Ok(Some(*v as u8))
525    } else {
526        Ok(None)
527    }
528}
529
530/// Decode Primary6X attribute (0x0028)
531pub fn decode_primary6_x(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
532    if let tlv::TlvItemValue::Int(v) = inp {
533        Ok(*v as u16)
534    } else {
535        Err(anyhow::anyhow!("Expected Integer"))
536    }
537}
538
539/// Decode Primary6Y attribute (0x0029)
540pub fn decode_primary6_y(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
541    if let tlv::TlvItemValue::Int(v) = inp {
542        Ok(*v as u16)
543    } else {
544        Err(anyhow::anyhow!("Expected Integer"))
545    }
546}
547
548/// Decode Primary6Intensity attribute (0x002A)
549pub fn decode_primary6_intensity(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
550    if let tlv::TlvItemValue::Int(v) = inp {
551        Ok(Some(*v as u8))
552    } else {
553        Ok(None)
554    }
555}
556
557/// Decode WhitePointX attribute (0x0030)
558pub fn decode_white_point_x(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
559    if let tlv::TlvItemValue::Int(v) = inp {
560        Ok(*v as u16)
561    } else {
562        Err(anyhow::anyhow!("Expected Integer"))
563    }
564}
565
566/// Decode WhitePointY attribute (0x0031)
567pub fn decode_white_point_y(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
568    if let tlv::TlvItemValue::Int(v) = inp {
569        Ok(*v as u16)
570    } else {
571        Err(anyhow::anyhow!("Expected Integer"))
572    }
573}
574
575/// Decode ColorPointRX attribute (0x0032)
576pub fn decode_color_point_rx(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
577    if let tlv::TlvItemValue::Int(v) = inp {
578        Ok(*v as u16)
579    } else {
580        Err(anyhow::anyhow!("Expected Integer"))
581    }
582}
583
584/// Decode ColorPointRY attribute (0x0033)
585pub fn decode_color_point_ry(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
586    if let tlv::TlvItemValue::Int(v) = inp {
587        Ok(*v as u16)
588    } else {
589        Err(anyhow::anyhow!("Expected Integer"))
590    }
591}
592
593/// Decode ColorPointRIntensity attribute (0x0034)
594pub fn decode_color_point_r_intensity(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
595    if let tlv::TlvItemValue::Int(v) = inp {
596        Ok(Some(*v as u8))
597    } else {
598        Ok(None)
599    }
600}
601
602/// Decode ColorPointGX attribute (0x0036)
603pub fn decode_color_point_gx(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
604    if let tlv::TlvItemValue::Int(v) = inp {
605        Ok(*v as u16)
606    } else {
607        Err(anyhow::anyhow!("Expected Integer"))
608    }
609}
610
611/// Decode ColorPointGY attribute (0x0037)
612pub fn decode_color_point_gy(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
613    if let tlv::TlvItemValue::Int(v) = inp {
614        Ok(*v as u16)
615    } else {
616        Err(anyhow::anyhow!("Expected Integer"))
617    }
618}
619
620/// Decode ColorPointGIntensity attribute (0x0038)
621pub fn decode_color_point_g_intensity(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
622    if let tlv::TlvItemValue::Int(v) = inp {
623        Ok(Some(*v as u8))
624    } else {
625        Ok(None)
626    }
627}
628
629/// Decode ColorPointBX attribute (0x003A)
630pub fn decode_color_point_bx(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
631    if let tlv::TlvItemValue::Int(v) = inp {
632        Ok(*v as u16)
633    } else {
634        Err(anyhow::anyhow!("Expected Integer"))
635    }
636}
637
638/// Decode ColorPointBY attribute (0x003B)
639pub fn decode_color_point_by(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
640    if let tlv::TlvItemValue::Int(v) = inp {
641        Ok(*v as u16)
642    } else {
643        Err(anyhow::anyhow!("Expected Integer"))
644    }
645}
646
647/// Decode ColorPointBIntensity attribute (0x003C)
648pub fn decode_color_point_b_intensity(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
649    if let tlv::TlvItemValue::Int(v) = inp {
650        Ok(Some(*v as u8))
651    } else {
652        Ok(None)
653    }
654}
655
656/// Decode EnhancedCurrentHue attribute (0x4000)
657pub fn decode_enhanced_current_hue(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
658    if let tlv::TlvItemValue::Int(v) = inp {
659        Ok(*v as u16)
660    } else {
661        Err(anyhow::anyhow!("Expected Integer"))
662    }
663}
664
665/// Decode EnhancedColorMode attribute (0x4001)
666pub fn decode_enhanced_color_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
667    if let tlv::TlvItemValue::Int(v) = inp {
668        Ok(*v as u8)
669    } else {
670        Err(anyhow::anyhow!("Expected Integer"))
671    }
672}
673
674/// Decode ColorLoopActive attribute (0x4002)
675pub fn decode_color_loop_active(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
676    if let tlv::TlvItemValue::Int(v) = inp {
677        Ok(*v as u8)
678    } else {
679        Err(anyhow::anyhow!("Expected Integer"))
680    }
681}
682
683/// Decode ColorLoopDirection attribute (0x4003)
684pub fn decode_color_loop_direction(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
685    if let tlv::TlvItemValue::Int(v) = inp {
686        Ok(*v as u8)
687    } else {
688        Err(anyhow::anyhow!("Expected Integer"))
689    }
690}
691
692/// Decode ColorLoopTime attribute (0x4004)
693pub fn decode_color_loop_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
694    if let tlv::TlvItemValue::Int(v) = inp {
695        Ok(*v as u16)
696    } else {
697        Err(anyhow::anyhow!("Expected Integer"))
698    }
699}
700
701/// Decode ColorLoopStartEnhancedHue attribute (0x4005)
702pub fn decode_color_loop_start_enhanced_hue(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
703    if let tlv::TlvItemValue::Int(v) = inp {
704        Ok(*v as u16)
705    } else {
706        Err(anyhow::anyhow!("Expected Integer"))
707    }
708}
709
710/// Decode ColorLoopStoredEnhancedHue attribute (0x4006)
711pub fn decode_color_loop_stored_enhanced_hue(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
712    if let tlv::TlvItemValue::Int(v) = inp {
713        Ok(*v as u16)
714    } else {
715        Err(anyhow::anyhow!("Expected Integer"))
716    }
717}
718
719/// Decode ColorCapabilities attribute (0x400A)
720pub fn decode_color_capabilities(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
721    if let tlv::TlvItemValue::Int(v) = inp {
722        Ok(*v as u8)
723    } else {
724        Err(anyhow::anyhow!("Expected Integer"))
725    }
726}
727
728/// Decode ColorTempPhysicalMinMireds attribute (0x400B)
729pub fn decode_color_temp_physical_min_mireds(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
730    if let tlv::TlvItemValue::Int(v) = inp {
731        Ok(*v as u16)
732    } else {
733        Err(anyhow::anyhow!("Expected Integer"))
734    }
735}
736
737/// Decode ColorTempPhysicalMaxMireds attribute (0x400C)
738pub fn decode_color_temp_physical_max_mireds(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
739    if let tlv::TlvItemValue::Int(v) = inp {
740        Ok(*v as u16)
741    } else {
742        Err(anyhow::anyhow!("Expected Integer"))
743    }
744}
745
746/// Decode CoupleColorTempToLevelMinMireds attribute (0x400D)
747pub fn decode_couple_color_temp_to_level_min_mireds(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
748    if let tlv::TlvItemValue::Int(v) = inp {
749        Ok(*v as u16)
750    } else {
751        Err(anyhow::anyhow!("Expected Integer"))
752    }
753}
754
755/// Decode StartUpColorTemperatureMireds attribute (0x4010)
756pub fn decode_start_up_color_temperature_mireds(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
757    if let tlv::TlvItemValue::Int(v) = inp {
758        Ok(Some(*v as u16))
759    } else {
760        Ok(None)
761    }
762}
763
764
765// JSON dispatcher function
766
767/// Decode attribute value and return as JSON string
768/// 
769/// # Parameters
770/// * `cluster_id` - The cluster identifier
771/// * `attribute_id` - The attribute identifier
772/// * `tlv_value` - The TLV value to decode
773/// 
774/// # Returns
775/// JSON string representation of the decoded value or error
776pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
777    // Verify this is the correct cluster
778    if cluster_id != 0x0300 {
779        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0300, got {}\"}}", cluster_id);
780    }
781    
782    match attribute_id {
783        0x0000 => {
784            match decode_current_hue(tlv_value) {
785                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
786                Err(e) => format!("{{\"error\": \"{}\"}}", e),
787            }
788        }
789        0x0001 => {
790            match decode_current_saturation(tlv_value) {
791                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
792                Err(e) => format!("{{\"error\": \"{}\"}}", e),
793            }
794        }
795        0x0002 => {
796            match decode_remaining_time(tlv_value) {
797                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
798                Err(e) => format!("{{\"error\": \"{}\"}}", e),
799            }
800        }
801        0x0003 => {
802            match decode_current_x(tlv_value) {
803                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
804                Err(e) => format!("{{\"error\": \"{}\"}}", e),
805            }
806        }
807        0x0004 => {
808            match decode_current_y(tlv_value) {
809                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
810                Err(e) => format!("{{\"error\": \"{}\"}}", e),
811            }
812        }
813        0x0005 => {
814            match decode_drift_compensation(tlv_value) {
815                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
816                Err(e) => format!("{{\"error\": \"{}\"}}", e),
817            }
818        }
819        0x0006 => {
820            match decode_compensation_text(tlv_value) {
821                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
822                Err(e) => format!("{{\"error\": \"{}\"}}", e),
823            }
824        }
825        0x0007 => {
826            match decode_color_temperature_mireds(tlv_value) {
827                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
828                Err(e) => format!("{{\"error\": \"{}\"}}", e),
829            }
830        }
831        0x0008 => {
832            match decode_color_mode(tlv_value) {
833                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
834                Err(e) => format!("{{\"error\": \"{}\"}}", e),
835            }
836        }
837        0x000F => {
838            match decode_options(tlv_value) {
839                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
840                Err(e) => format!("{{\"error\": \"{}\"}}", e),
841            }
842        }
843        0x0010 => {
844            match decode_number_of_primaries(tlv_value) {
845                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
846                Err(e) => format!("{{\"error\": \"{}\"}}", e),
847            }
848        }
849        0x0011 => {
850            match decode_primary1_x(tlv_value) {
851                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
852                Err(e) => format!("{{\"error\": \"{}\"}}", e),
853            }
854        }
855        0x0012 => {
856            match decode_primary1_y(tlv_value) {
857                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
858                Err(e) => format!("{{\"error\": \"{}\"}}", e),
859            }
860        }
861        0x0013 => {
862            match decode_primary1_intensity(tlv_value) {
863                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
864                Err(e) => format!("{{\"error\": \"{}\"}}", e),
865            }
866        }
867        0x0015 => {
868            match decode_primary2_x(tlv_value) {
869                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
870                Err(e) => format!("{{\"error\": \"{}\"}}", e),
871            }
872        }
873        0x0016 => {
874            match decode_primary2_y(tlv_value) {
875                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
876                Err(e) => format!("{{\"error\": \"{}\"}}", e),
877            }
878        }
879        0x0017 => {
880            match decode_primary2_intensity(tlv_value) {
881                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
882                Err(e) => format!("{{\"error\": \"{}\"}}", e),
883            }
884        }
885        0x0019 => {
886            match decode_primary3_x(tlv_value) {
887                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
888                Err(e) => format!("{{\"error\": \"{}\"}}", e),
889            }
890        }
891        0x001A => {
892            match decode_primary3_y(tlv_value) {
893                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
894                Err(e) => format!("{{\"error\": \"{}\"}}", e),
895            }
896        }
897        0x001B => {
898            match decode_primary3_intensity(tlv_value) {
899                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
900                Err(e) => format!("{{\"error\": \"{}\"}}", e),
901            }
902        }
903        0x0020 => {
904            match decode_primary4_x(tlv_value) {
905                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
906                Err(e) => format!("{{\"error\": \"{}\"}}", e),
907            }
908        }
909        0x0021 => {
910            match decode_primary4_y(tlv_value) {
911                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
912                Err(e) => format!("{{\"error\": \"{}\"}}", e),
913            }
914        }
915        0x0022 => {
916            match decode_primary4_intensity(tlv_value) {
917                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
918                Err(e) => format!("{{\"error\": \"{}\"}}", e),
919            }
920        }
921        0x0024 => {
922            match decode_primary5_x(tlv_value) {
923                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
924                Err(e) => format!("{{\"error\": \"{}\"}}", e),
925            }
926        }
927        0x0025 => {
928            match decode_primary5_y(tlv_value) {
929                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
930                Err(e) => format!("{{\"error\": \"{}\"}}", e),
931            }
932        }
933        0x0026 => {
934            match decode_primary5_intensity(tlv_value) {
935                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
936                Err(e) => format!("{{\"error\": \"{}\"}}", e),
937            }
938        }
939        0x0028 => {
940            match decode_primary6_x(tlv_value) {
941                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
942                Err(e) => format!("{{\"error\": \"{}\"}}", e),
943            }
944        }
945        0x0029 => {
946            match decode_primary6_y(tlv_value) {
947                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
948                Err(e) => format!("{{\"error\": \"{}\"}}", e),
949            }
950        }
951        0x002A => {
952            match decode_primary6_intensity(tlv_value) {
953                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
954                Err(e) => format!("{{\"error\": \"{}\"}}", e),
955            }
956        }
957        0x0030 => {
958            match decode_white_point_x(tlv_value) {
959                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
960                Err(e) => format!("{{\"error\": \"{}\"}}", e),
961            }
962        }
963        0x0031 => {
964            match decode_white_point_y(tlv_value) {
965                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
966                Err(e) => format!("{{\"error\": \"{}\"}}", e),
967            }
968        }
969        0x0032 => {
970            match decode_color_point_rx(tlv_value) {
971                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
972                Err(e) => format!("{{\"error\": \"{}\"}}", e),
973            }
974        }
975        0x0033 => {
976            match decode_color_point_ry(tlv_value) {
977                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
978                Err(e) => format!("{{\"error\": \"{}\"}}", e),
979            }
980        }
981        0x0034 => {
982            match decode_color_point_r_intensity(tlv_value) {
983                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
984                Err(e) => format!("{{\"error\": \"{}\"}}", e),
985            }
986        }
987        0x0036 => {
988            match decode_color_point_gx(tlv_value) {
989                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
990                Err(e) => format!("{{\"error\": \"{}\"}}", e),
991            }
992        }
993        0x0037 => {
994            match decode_color_point_gy(tlv_value) {
995                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
996                Err(e) => format!("{{\"error\": \"{}\"}}", e),
997            }
998        }
999        0x0038 => {
1000            match decode_color_point_g_intensity(tlv_value) {
1001                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1002                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1003            }
1004        }
1005        0x003A => {
1006            match decode_color_point_bx(tlv_value) {
1007                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1008                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1009            }
1010        }
1011        0x003B => {
1012            match decode_color_point_by(tlv_value) {
1013                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1014                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1015            }
1016        }
1017        0x003C => {
1018            match decode_color_point_b_intensity(tlv_value) {
1019                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1020                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1021            }
1022        }
1023        0x4000 => {
1024            match decode_enhanced_current_hue(tlv_value) {
1025                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1026                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1027            }
1028        }
1029        0x4001 => {
1030            match decode_enhanced_color_mode(tlv_value) {
1031                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1032                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1033            }
1034        }
1035        0x4002 => {
1036            match decode_color_loop_active(tlv_value) {
1037                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1038                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1039            }
1040        }
1041        0x4003 => {
1042            match decode_color_loop_direction(tlv_value) {
1043                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1044                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1045            }
1046        }
1047        0x4004 => {
1048            match decode_color_loop_time(tlv_value) {
1049                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1050                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1051            }
1052        }
1053        0x4005 => {
1054            match decode_color_loop_start_enhanced_hue(tlv_value) {
1055                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1056                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1057            }
1058        }
1059        0x4006 => {
1060            match decode_color_loop_stored_enhanced_hue(tlv_value) {
1061                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1062                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1063            }
1064        }
1065        0x400A => {
1066            match decode_color_capabilities(tlv_value) {
1067                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1068                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1069            }
1070        }
1071        0x400B => {
1072            match decode_color_temp_physical_min_mireds(tlv_value) {
1073                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1074                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1075            }
1076        }
1077        0x400C => {
1078            match decode_color_temp_physical_max_mireds(tlv_value) {
1079                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1080                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1081            }
1082        }
1083        0x400D => {
1084            match decode_couple_color_temp_to_level_min_mireds(tlv_value) {
1085                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1086                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1087            }
1088        }
1089        0x4010 => {
1090            match decode_start_up_color_temperature_mireds(tlv_value) {
1091                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1092                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1093            }
1094        }
1095        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
1096    }
1097}
1098
1099/// Get list of all attributes supported by this cluster
1100/// 
1101/// # Returns
1102/// Vector of tuples containing (attribute_id, attribute_name)
1103pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
1104    vec![
1105        (0x0000, "CurrentHue"),
1106        (0x0001, "CurrentSaturation"),
1107        (0x0002, "RemainingTime"),
1108        (0x0003, "CurrentX"),
1109        (0x0004, "CurrentY"),
1110        (0x0005, "DriftCompensation"),
1111        (0x0006, "CompensationText"),
1112        (0x0007, "ColorTemperatureMireds"),
1113        (0x0008, "ColorMode"),
1114        (0x000F, "Options"),
1115        (0x0010, "NumberOfPrimaries"),
1116        (0x0011, "Primary1X"),
1117        (0x0012, "Primary1Y"),
1118        (0x0013, "Primary1Intensity"),
1119        (0x0015, "Primary2X"),
1120        (0x0016, "Primary2Y"),
1121        (0x0017, "Primary2Intensity"),
1122        (0x0019, "Primary3X"),
1123        (0x001A, "Primary3Y"),
1124        (0x001B, "Primary3Intensity"),
1125        (0x0020, "Primary4X"),
1126        (0x0021, "Primary4Y"),
1127        (0x0022, "Primary4Intensity"),
1128        (0x0024, "Primary5X"),
1129        (0x0025, "Primary5Y"),
1130        (0x0026, "Primary5Intensity"),
1131        (0x0028, "Primary6X"),
1132        (0x0029, "Primary6Y"),
1133        (0x002A, "Primary6Intensity"),
1134        (0x0030, "WhitePointX"),
1135        (0x0031, "WhitePointY"),
1136        (0x0032, "ColorPointRX"),
1137        (0x0033, "ColorPointRY"),
1138        (0x0034, "ColorPointRIntensity"),
1139        (0x0036, "ColorPointGX"),
1140        (0x0037, "ColorPointGY"),
1141        (0x0038, "ColorPointGIntensity"),
1142        (0x003A, "ColorPointBX"),
1143        (0x003B, "ColorPointBY"),
1144        (0x003C, "ColorPointBIntensity"),
1145        (0x4000, "EnhancedCurrentHue"),
1146        (0x4001, "EnhancedColorMode"),
1147        (0x4002, "ColorLoopActive"),
1148        (0x4003, "ColorLoopDirection"),
1149        (0x4004, "ColorLoopTime"),
1150        (0x4005, "ColorLoopStartEnhancedHue"),
1151        (0x4006, "ColorLoopStoredEnhancedHue"),
1152        (0x400A, "ColorCapabilities"),
1153        (0x400B, "ColorTempPhysicalMinMireds"),
1154        (0x400C, "ColorTempPhysicalMaxMireds"),
1155        (0x400D, "CoupleColorTempToLevelMinMireds"),
1156        (0x4010, "StartUpColorTemperatureMireds"),
1157    ]
1158}
1159