matc/clusters/codec/
scenes.rs

1//! Matter TLV encoders and decoders for Scenes Management Cluster
2//! Cluster ID: 0x0062
3//!
4//! This file is automatically generated from Scenes.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Bitmap definitions
14
15/// CopyMode bitmap type
16pub type CopyMode = u8;
17
18/// Constants for CopyMode
19pub mod copymode {
20    /// Copy all scenes in the scene table
21    pub const COPY_ALL_SCENES: u8 = 0x01;
22}
23
24// Struct definitions
25
26#[derive(Debug, serde::Serialize)]
27pub struct AttributeValuePair {
28    pub attribute_id: Option<u32>,
29    pub value_unsigned8: Option<u8>,
30    pub value_signed8: Option<i8>,
31    pub value_unsigned16: Option<u16>,
32    pub value_signed16: Option<i16>,
33    pub value_unsigned32: Option<u32>,
34    pub value_signed32: Option<i32>,
35    pub value_unsigned64: Option<u64>,
36    pub value_signed64: Option<i64>,
37}
38
39#[derive(Debug, serde::Serialize)]
40pub struct ExtensionFieldSet {
41    pub cluster_id: Option<u32>,
42    pub attribute_value_list: Option<Vec<AttributeValuePair>>,
43}
44
45#[derive(Debug, serde::Serialize)]
46pub struct SceneInfo {
47    pub scene_count: Option<u8>,
48    pub current_scene: Option<u8>,
49    pub current_group: Option<u8>,
50    pub scene_valid: Option<bool>,
51    pub remaining_capacity: Option<u8>,
52}
53
54// Command encoders
55
56/// Encode AddScene command (0x00)
57pub fn encode_add_scene(group_id: u8, scene_id: u8, transition_time: u32, scene_name: String, extension_field_set_structs: Vec<ExtensionFieldSet>) -> anyhow::Result<Vec<u8>> {
58    let tlv = tlv::TlvItemEnc {
59        tag: 0,
60        value: tlv::TlvItemValueEnc::StructInvisible(vec![
61        (0, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
62        (1, tlv::TlvItemValueEnc::UInt8(scene_id)).into(),
63        (2, tlv::TlvItemValueEnc::UInt32(transition_time)).into(),
64        (3, tlv::TlvItemValueEnc::String(scene_name)).into(),
65        (4, tlv::TlvItemValueEnc::Array(extension_field_set_structs.into_iter().map(|v| {
66                    let mut fields = Vec::new();
67                    if let Some(x) = v.cluster_id { fields.push((0, tlv::TlvItemValueEnc::UInt32(x)).into()); }
68                    if let Some(listv) = v.attribute_value_list {
69                        let inner_vec: Vec<_> = listv.into_iter().map(|inner| {
70                            let mut nested_fields = Vec::new();
71                                if let Some(x) = inner.attribute_id { nested_fields.push((0, tlv::TlvItemValueEnc::UInt32(x)).into()); }
72                                if let Some(x) = inner.value_unsigned8 { nested_fields.push((1, tlv::TlvItemValueEnc::UInt8(x)).into()); }
73                                if let Some(x) = inner.value_signed8 { nested_fields.push((2, tlv::TlvItemValueEnc::Int8(x)).into()); }
74                                if let Some(x) = inner.value_unsigned16 { nested_fields.push((3, tlv::TlvItemValueEnc::UInt16(x)).into()); }
75                                if let Some(x) = inner.value_signed16 { nested_fields.push((4, tlv::TlvItemValueEnc::Int16(x)).into()); }
76                                if let Some(x) = inner.value_unsigned32 { nested_fields.push((5, tlv::TlvItemValueEnc::UInt32(x)).into()); }
77                                if let Some(x) = inner.value_signed32 { nested_fields.push((6, tlv::TlvItemValueEnc::Int32(x)).into()); }
78                                if let Some(x) = inner.value_unsigned64 { nested_fields.push((7, tlv::TlvItemValueEnc::UInt64(x)).into()); }
79                                if let Some(x) = inner.value_signed64 { nested_fields.push((8, tlv::TlvItemValueEnc::Int64(x)).into()); }
80                            (0, tlv::TlvItemValueEnc::StructAnon(nested_fields)).into()
81                        }).collect();
82                        fields.push((1, tlv::TlvItemValueEnc::Array(inner_vec)).into());
83                    }
84                    (0, tlv::TlvItemValueEnc::StructAnon(fields)).into()
85                }).collect())).into(),
86        ]),
87    };
88    Ok(tlv.encode()?)
89}
90
91/// Encode ViewScene command (0x01)
92pub fn encode_view_scene(group_id: u8, scene_id: u8) -> anyhow::Result<Vec<u8>> {
93    let tlv = tlv::TlvItemEnc {
94        tag: 0,
95        value: tlv::TlvItemValueEnc::StructInvisible(vec![
96        (0, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
97        (1, tlv::TlvItemValueEnc::UInt8(scene_id)).into(),
98        ]),
99    };
100    Ok(tlv.encode()?)
101}
102
103/// Encode RemoveScene command (0x02)
104pub fn encode_remove_scene(group_id: u8, scene_id: u8) -> anyhow::Result<Vec<u8>> {
105    let tlv = tlv::TlvItemEnc {
106        tag: 0,
107        value: tlv::TlvItemValueEnc::StructInvisible(vec![
108        (0, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
109        (1, tlv::TlvItemValueEnc::UInt8(scene_id)).into(),
110        ]),
111    };
112    Ok(tlv.encode()?)
113}
114
115/// Encode RemoveAllScenes command (0x03)
116pub fn encode_remove_all_scenes(group_id: u8) -> anyhow::Result<Vec<u8>> {
117    let tlv = tlv::TlvItemEnc {
118        tag: 0,
119        value: tlv::TlvItemValueEnc::StructInvisible(vec![
120        (0, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
121        ]),
122    };
123    Ok(tlv.encode()?)
124}
125
126/// Encode StoreScene command (0x04)
127pub fn encode_store_scene(group_id: u8, scene_id: u8) -> anyhow::Result<Vec<u8>> {
128    let tlv = tlv::TlvItemEnc {
129        tag: 0,
130        value: tlv::TlvItemValueEnc::StructInvisible(vec![
131        (0, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
132        (1, tlv::TlvItemValueEnc::UInt8(scene_id)).into(),
133        ]),
134    };
135    Ok(tlv.encode()?)
136}
137
138/// Encode RecallScene command (0x05)
139pub fn encode_recall_scene(group_id: u8, scene_id: u8, transition_time: Option<u32>) -> anyhow::Result<Vec<u8>> {
140    let tlv = tlv::TlvItemEnc {
141        tag: 0,
142        value: tlv::TlvItemValueEnc::StructInvisible(vec![
143        (0, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
144        (1, tlv::TlvItemValueEnc::UInt8(scene_id)).into(),
145        (2, tlv::TlvItemValueEnc::UInt32(transition_time.unwrap_or(0))).into(),
146        ]),
147    };
148    Ok(tlv.encode()?)
149}
150
151/// Encode GetSceneMembership command (0x06)
152pub fn encode_get_scene_membership(group_id: u8) -> anyhow::Result<Vec<u8>> {
153    let tlv = tlv::TlvItemEnc {
154        tag: 0,
155        value: tlv::TlvItemValueEnc::StructInvisible(vec![
156        (0, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
157        ]),
158    };
159    Ok(tlv.encode()?)
160}
161
162/// Encode CopyScene command (0x40)
163pub fn encode_copy_scene(mode: CopyMode, group_identifier_from: u8, scene_identifier_from: u8, group_identifier_to: u8, scene_identifier_to: u8) -> anyhow::Result<Vec<u8>> {
164    let tlv = tlv::TlvItemEnc {
165        tag: 0,
166        value: tlv::TlvItemValueEnc::StructInvisible(vec![
167        (0, tlv::TlvItemValueEnc::UInt8(mode)).into(),
168        (1, tlv::TlvItemValueEnc::UInt8(group_identifier_from)).into(),
169        (2, tlv::TlvItemValueEnc::UInt8(scene_identifier_from)).into(),
170        (3, tlv::TlvItemValueEnc::UInt8(group_identifier_to)).into(),
171        (4, tlv::TlvItemValueEnc::UInt8(scene_identifier_to)).into(),
172        ]),
173    };
174    Ok(tlv.encode()?)
175}
176
177// Attribute decoders
178
179/// Decode DoNotUse attribute (0x0000)
180pub fn decode_do_not_use(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
181    if let tlv::TlvItemValue::Int(v) = inp {
182        Ok(*v as u8)
183    } else {
184        Err(anyhow::anyhow!("Expected UInt8"))
185    }
186}
187
188/// Decode SceneTableSize attribute (0x0001)
189pub fn decode_scene_table_size(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
190    if let tlv::TlvItemValue::Int(v) = inp {
191        Ok(*v as u16)
192    } else {
193        Err(anyhow::anyhow!("Expected UInt16"))
194    }
195}
196
197/// Decode FabricSceneInfo attribute (0x0002)
198pub fn decode_fabric_scene_info(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<SceneInfo>> {
199    let mut res = Vec::new();
200    if let tlv::TlvItemValue::List(v) = inp {
201        for item in v {
202            res.push(SceneInfo {
203                scene_count: item.get_int(&[0]).map(|v| v as u8),
204                current_scene: item.get_int(&[1]).map(|v| v as u8),
205                current_group: item.get_int(&[2]).map(|v| v as u8),
206                scene_valid: item.get_bool(&[3]),
207                remaining_capacity: item.get_int(&[4]).map(|v| v as u8),
208            });
209        }
210    }
211    Ok(res)
212}
213
214
215// JSON dispatcher function
216
217/// Decode attribute value and return as JSON string
218///
219/// # Parameters
220/// * `cluster_id` - The cluster identifier
221/// * `attribute_id` - The attribute identifier
222/// * `tlv_value` - The TLV value to decode
223///
224/// # Returns
225/// JSON string representation of the decoded value or error
226pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
227    // Verify this is the correct cluster
228    if cluster_id != 0x0062 {
229        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0062, got {}\"}}", cluster_id);
230    }
231
232    match attribute_id {
233        0x0000 => {
234            match decode_do_not_use(tlv_value) {
235                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
236                Err(e) => format!("{{\"error\": \"{}\"}}", e),
237            }
238        }
239        0x0001 => {
240            match decode_scene_table_size(tlv_value) {
241                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
242                Err(e) => format!("{{\"error\": \"{}\"}}", e),
243            }
244        }
245        0x0002 => {
246            match decode_fabric_scene_info(tlv_value) {
247                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
248                Err(e) => format!("{{\"error\": \"{}\"}}", e),
249            }
250        }
251        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
252    }
253}
254
255/// Get list of all attributes supported by this cluster
256///
257/// # Returns
258/// Vector of tuples containing (attribute_id, attribute_name)
259pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
260    vec![
261        (0x0000, "DoNotUse"),
262        (0x0001, "SceneTableSize"),
263        (0x0002, "FabricSceneInfo"),
264    ]
265}
266
267// Command listing
268
269pub fn get_command_list() -> Vec<(u32, &'static str)> {
270    vec![
271        (0x00, "AddScene"),
272        (0x01, "ViewScene"),
273        (0x02, "RemoveScene"),
274        (0x03, "RemoveAllScenes"),
275        (0x04, "StoreScene"),
276        (0x05, "RecallScene"),
277        (0x06, "GetSceneMembership"),
278        (0x40, "CopyScene"),
279    ]
280}
281
282pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
283    match cmd_id {
284        0x00 => Some("AddScene"),
285        0x01 => Some("ViewScene"),
286        0x02 => Some("RemoveScene"),
287        0x03 => Some("RemoveAllScenes"),
288        0x04 => Some("StoreScene"),
289        0x05 => Some("RecallScene"),
290        0x06 => Some("GetSceneMembership"),
291        0x40 => Some("CopyScene"),
292        _ => None,
293    }
294}
295
296pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
297    match cmd_id {
298        0x00 => Some(vec![
299            crate::clusters::codec::CommandField { tag: 0, name: "group_id", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
300            crate::clusters::codec::CommandField { tag: 1, name: "scene_id", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
301            crate::clusters::codec::CommandField { tag: 2, name: "transition_time", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
302            crate::clusters::codec::CommandField { tag: 3, name: "scene_name", kind: crate::clusters::codec::FieldKind::String, optional: false, nullable: false },
303            crate::clusters::codec::CommandField { tag: 4, name: "extension_field_set_structs", kind: crate::clusters::codec::FieldKind::List { entry_type: "ExtensionFieldSetStruct" }, optional: false, nullable: false },
304        ]),
305        0x01 => Some(vec![
306            crate::clusters::codec::CommandField { tag: 0, name: "group_id", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
307            crate::clusters::codec::CommandField { tag: 1, name: "scene_id", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
308        ]),
309        0x02 => Some(vec![
310            crate::clusters::codec::CommandField { tag: 0, name: "group_id", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
311            crate::clusters::codec::CommandField { tag: 1, name: "scene_id", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
312        ]),
313        0x03 => Some(vec![
314            crate::clusters::codec::CommandField { tag: 0, name: "group_id", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
315        ]),
316        0x04 => Some(vec![
317            crate::clusters::codec::CommandField { tag: 0, name: "group_id", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
318            crate::clusters::codec::CommandField { tag: 1, name: "scene_id", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
319        ]),
320        0x05 => Some(vec![
321            crate::clusters::codec::CommandField { tag: 0, name: "group_id", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
322            crate::clusters::codec::CommandField { tag: 1, name: "scene_id", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
323            crate::clusters::codec::CommandField { tag: 2, name: "transition_time", kind: crate::clusters::codec::FieldKind::U32, optional: true, nullable: true },
324        ]),
325        0x06 => Some(vec![
326            crate::clusters::codec::CommandField { tag: 0, name: "group_id", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
327        ]),
328        0x40 => Some(vec![
329            crate::clusters::codec::CommandField { tag: 0, name: "mode", kind: crate::clusters::codec::FieldKind::Bitmap { name: "CopyMode", bits: &[(1, "COPY_ALL_SCENES")] }, optional: false, nullable: false },
330            crate::clusters::codec::CommandField { tag: 1, name: "group_identifier_from", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
331            crate::clusters::codec::CommandField { tag: 2, name: "scene_identifier_from", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
332            crate::clusters::codec::CommandField { tag: 3, name: "group_identifier_to", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
333            crate::clusters::codec::CommandField { tag: 4, name: "scene_identifier_to", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
334        ]),
335        _ => None,
336    }
337}
338
339pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
340    match cmd_id {
341        0x00 => Err(anyhow::anyhow!("command \"AddScene\" has complex args: use raw mode")),
342        0x01 => {
343        let group_id = crate::clusters::codec::json_util::get_u8(args, "group_id")?;
344        let scene_id = crate::clusters::codec::json_util::get_u8(args, "scene_id")?;
345        encode_view_scene(group_id, scene_id)
346        }
347        0x02 => {
348        let group_id = crate::clusters::codec::json_util::get_u8(args, "group_id")?;
349        let scene_id = crate::clusters::codec::json_util::get_u8(args, "scene_id")?;
350        encode_remove_scene(group_id, scene_id)
351        }
352        0x03 => {
353        let group_id = crate::clusters::codec::json_util::get_u8(args, "group_id")?;
354        encode_remove_all_scenes(group_id)
355        }
356        0x04 => {
357        let group_id = crate::clusters::codec::json_util::get_u8(args, "group_id")?;
358        let scene_id = crate::clusters::codec::json_util::get_u8(args, "scene_id")?;
359        encode_store_scene(group_id, scene_id)
360        }
361        0x05 => {
362        let group_id = crate::clusters::codec::json_util::get_u8(args, "group_id")?;
363        let scene_id = crate::clusters::codec::json_util::get_u8(args, "scene_id")?;
364        let transition_time = crate::clusters::codec::json_util::get_opt_u32(args, "transition_time")?;
365        encode_recall_scene(group_id, scene_id, transition_time)
366        }
367        0x06 => {
368        let group_id = crate::clusters::codec::json_util::get_u8(args, "group_id")?;
369        encode_get_scene_membership(group_id)
370        }
371        0x40 => {
372        let mode = crate::clusters::codec::json_util::get_u8(args, "mode")?;
373        let group_identifier_from = crate::clusters::codec::json_util::get_u8(args, "group_identifier_from")?;
374        let scene_identifier_from = crate::clusters::codec::json_util::get_u8(args, "scene_identifier_from")?;
375        let group_identifier_to = crate::clusters::codec::json_util::get_u8(args, "group_identifier_to")?;
376        let scene_identifier_to = crate::clusters::codec::json_util::get_u8(args, "scene_identifier_to")?;
377        encode_copy_scene(mode, group_identifier_from, scene_identifier_from, group_identifier_to, scene_identifier_to)
378        }
379        _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
380    }
381}
382
383#[derive(Debug, serde::Serialize)]
384pub struct AddSceneResponse {
385    pub status: Option<u8>,
386    pub group_id: Option<u8>,
387    pub scene_id: Option<u8>,
388}
389
390#[derive(Debug, serde::Serialize)]
391pub struct ViewSceneResponse {
392    pub status: Option<u8>,
393    pub group_id: Option<u8>,
394    pub scene_id: Option<u8>,
395    pub transition_time: Option<u32>,
396    pub scene_name: Option<String>,
397    pub extension_field_set_structs: Option<Vec<ExtensionFieldSet>>,
398}
399
400#[derive(Debug, serde::Serialize)]
401pub struct RemoveSceneResponse {
402    pub status: Option<u8>,
403    pub group_id: Option<u8>,
404    pub scene_id: Option<u8>,
405}
406
407#[derive(Debug, serde::Serialize)]
408pub struct RemoveAllScenesResponse {
409    pub status: Option<u8>,
410    pub group_id: Option<u8>,
411}
412
413#[derive(Debug, serde::Serialize)]
414pub struct StoreSceneResponse {
415    pub status: Option<u8>,
416    pub group_id: Option<u8>,
417    pub scene_id: Option<u8>,
418}
419
420#[derive(Debug, serde::Serialize)]
421pub struct GetSceneMembershipResponse {
422    pub status: Option<u8>,
423    pub capacity: Option<u8>,
424    pub group_id: Option<u8>,
425    pub scene_list: Option<Vec<u8>>,
426}
427
428#[derive(Debug, serde::Serialize)]
429pub struct CopySceneResponse {
430    pub status: Option<u8>,
431    pub group_identifier_from: Option<u8>,
432    pub scene_identifier_from: Option<u8>,
433}
434
435// Command response decoders
436
437/// Decode AddSceneResponse command response (00)
438pub fn decode_add_scene_response(inp: &tlv::TlvItemValue) -> anyhow::Result<AddSceneResponse> {
439    if let tlv::TlvItemValue::List(_fields) = inp {
440        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
441        Ok(AddSceneResponse {
442                status: item.get_int(&[0]).map(|v| v as u8),
443                group_id: item.get_int(&[1]).map(|v| v as u8),
444                scene_id: item.get_int(&[2]).map(|v| v as u8),
445        })
446    } else {
447        Err(anyhow::anyhow!("Expected struct fields"))
448    }
449}
450
451/// Decode ViewSceneResponse command response (01)
452pub fn decode_view_scene_response(inp: &tlv::TlvItemValue) -> anyhow::Result<ViewSceneResponse> {
453    if let tlv::TlvItemValue::List(_fields) = inp {
454        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
455        Ok(ViewSceneResponse {
456                status: item.get_int(&[0]).map(|v| v as u8),
457                group_id: item.get_int(&[1]).map(|v| v as u8),
458                scene_id: item.get_int(&[2]).map(|v| v as u8),
459                transition_time: item.get_int(&[3]).map(|v| v as u32),
460                scene_name: item.get_string_owned(&[4]),
461                extension_field_set_structs: {
462                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[5]) {
463                        let mut items = Vec::new();
464                        for list_item in l {
465                            items.push(ExtensionFieldSet {
466                cluster_id: list_item.get_int(&[0]).map(|v| v as u32),
467                attribute_value_list: {
468                    if let Some(tlv::TlvItemValue::List(l)) = list_item.get(&[1]) {
469                        let mut items = Vec::new();
470                        for list_item in l {
471                            items.push(AttributeValuePair {
472                attribute_id: list_item.get_int(&[0]).map(|v| v as u32),
473                value_unsigned8: list_item.get_int(&[1]).map(|v| v as u8),
474                value_signed8: list_item.get_int(&[2]).map(|v| v as i8),
475                value_unsigned16: list_item.get_int(&[3]).map(|v| v as u16),
476                value_signed16: list_item.get_int(&[4]).map(|v| v as i16),
477                value_unsigned32: list_item.get_int(&[5]).map(|v| v as u32),
478                value_signed32: list_item.get_int(&[6]).map(|v| v as i32),
479                value_unsigned64: list_item.get_int(&[7]),
480                value_signed64: list_item.get_int(&[8]).map(|v| v as i64),
481                            });
482                        }
483                        Some(items)
484                    } else {
485                        None
486                    }
487                },
488                            });
489                        }
490                        Some(items)
491                    } else {
492                        None
493                    }
494                },
495        })
496    } else {
497        Err(anyhow::anyhow!("Expected struct fields"))
498    }
499}
500
501/// Decode RemoveSceneResponse command response (02)
502pub fn decode_remove_scene_response(inp: &tlv::TlvItemValue) -> anyhow::Result<RemoveSceneResponse> {
503    if let tlv::TlvItemValue::List(_fields) = inp {
504        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
505        Ok(RemoveSceneResponse {
506                status: item.get_int(&[0]).map(|v| v as u8),
507                group_id: item.get_int(&[1]).map(|v| v as u8),
508                scene_id: item.get_int(&[2]).map(|v| v as u8),
509        })
510    } else {
511        Err(anyhow::anyhow!("Expected struct fields"))
512    }
513}
514
515/// Decode RemoveAllScenesResponse command response (03)
516pub fn decode_remove_all_scenes_response(inp: &tlv::TlvItemValue) -> anyhow::Result<RemoveAllScenesResponse> {
517    if let tlv::TlvItemValue::List(_fields) = inp {
518        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
519        Ok(RemoveAllScenesResponse {
520                status: item.get_int(&[0]).map(|v| v as u8),
521                group_id: item.get_int(&[1]).map(|v| v as u8),
522        })
523    } else {
524        Err(anyhow::anyhow!("Expected struct fields"))
525    }
526}
527
528/// Decode StoreSceneResponse command response (04)
529pub fn decode_store_scene_response(inp: &tlv::TlvItemValue) -> anyhow::Result<StoreSceneResponse> {
530    if let tlv::TlvItemValue::List(_fields) = inp {
531        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
532        Ok(StoreSceneResponse {
533                status: item.get_int(&[0]).map(|v| v as u8),
534                group_id: item.get_int(&[1]).map(|v| v as u8),
535                scene_id: item.get_int(&[2]).map(|v| v as u8),
536        })
537    } else {
538        Err(anyhow::anyhow!("Expected struct fields"))
539    }
540}
541
542/// Decode GetSceneMembershipResponse command response (06)
543pub fn decode_get_scene_membership_response(inp: &tlv::TlvItemValue) -> anyhow::Result<GetSceneMembershipResponse> {
544    if let tlv::TlvItemValue::List(_fields) = inp {
545        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
546        Ok(GetSceneMembershipResponse {
547                status: item.get_int(&[0]).map(|v| v as u8),
548                capacity: item.get_int(&[1]).map(|v| v as u8),
549                group_id: item.get_int(&[2]).map(|v| v as u8),
550                scene_list: {
551                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[3]) {
552                        let items: Vec<u8> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u8) } else { None } }).collect();
553                        Some(items)
554                    } else {
555                        None
556                    }
557                },
558        })
559    } else {
560        Err(anyhow::anyhow!("Expected struct fields"))
561    }
562}
563
564/// Decode CopySceneResponse command response (40)
565pub fn decode_copy_scene_response(inp: &tlv::TlvItemValue) -> anyhow::Result<CopySceneResponse> {
566    if let tlv::TlvItemValue::List(_fields) = inp {
567        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
568        Ok(CopySceneResponse {
569                status: item.get_int(&[0]).map(|v| v as u8),
570                group_identifier_from: item.get_int(&[1]).map(|v| v as u8),
571                scene_identifier_from: item.get_int(&[2]).map(|v| v as u8),
572        })
573    } else {
574        Err(anyhow::anyhow!("Expected struct fields"))
575    }
576}
577
578// Typed facade (invokes + reads)
579
580/// Invoke `AddScene` command on cluster `Scenes Management`.
581pub async fn add_scene(conn: &crate::controller::Connection, endpoint: u16, group_id: u8, scene_id: u8, transition_time: u32, scene_name: String, extension_field_set_structs: Vec<ExtensionFieldSet>) -> anyhow::Result<AddSceneResponse> {
582    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SCENES_MANAGEMENT, crate::clusters::defs::CLUSTER_SCENES_MANAGEMENT_CMD_ID_ADDSCENE, &encode_add_scene(group_id, scene_id, transition_time, scene_name, extension_field_set_structs)?).await?;
583    decode_add_scene_response(&tlv)
584}
585
586/// Invoke `ViewScene` command on cluster `Scenes Management`.
587pub async fn view_scene(conn: &crate::controller::Connection, endpoint: u16, group_id: u8, scene_id: u8) -> anyhow::Result<ViewSceneResponse> {
588    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SCENES_MANAGEMENT, crate::clusters::defs::CLUSTER_SCENES_MANAGEMENT_CMD_ID_VIEWSCENE, &encode_view_scene(group_id, scene_id)?).await?;
589    decode_view_scene_response(&tlv)
590}
591
592/// Invoke `RemoveScene` command on cluster `Scenes Management`.
593pub async fn remove_scene(conn: &crate::controller::Connection, endpoint: u16, group_id: u8, scene_id: u8) -> anyhow::Result<RemoveSceneResponse> {
594    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SCENES_MANAGEMENT, crate::clusters::defs::CLUSTER_SCENES_MANAGEMENT_CMD_ID_REMOVESCENE, &encode_remove_scene(group_id, scene_id)?).await?;
595    decode_remove_scene_response(&tlv)
596}
597
598/// Invoke `RemoveAllScenes` command on cluster `Scenes Management`.
599pub async fn remove_all_scenes(conn: &crate::controller::Connection, endpoint: u16, group_id: u8) -> anyhow::Result<RemoveAllScenesResponse> {
600    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SCENES_MANAGEMENT, crate::clusters::defs::CLUSTER_SCENES_MANAGEMENT_CMD_ID_REMOVEALLSCENES, &encode_remove_all_scenes(group_id)?).await?;
601    decode_remove_all_scenes_response(&tlv)
602}
603
604/// Invoke `StoreScene` command on cluster `Scenes Management`.
605pub async fn store_scene(conn: &crate::controller::Connection, endpoint: u16, group_id: u8, scene_id: u8) -> anyhow::Result<StoreSceneResponse> {
606    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SCENES_MANAGEMENT, crate::clusters::defs::CLUSTER_SCENES_MANAGEMENT_CMD_ID_STORESCENE, &encode_store_scene(group_id, scene_id)?).await?;
607    decode_store_scene_response(&tlv)
608}
609
610/// Invoke `RecallScene` command on cluster `Scenes Management`.
611pub async fn recall_scene(conn: &crate::controller::Connection, endpoint: u16, group_id: u8, scene_id: u8, transition_time: Option<u32>) -> anyhow::Result<()> {
612    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_SCENES_MANAGEMENT, crate::clusters::defs::CLUSTER_SCENES_MANAGEMENT_CMD_ID_RECALLSCENE, &encode_recall_scene(group_id, scene_id, transition_time)?).await?;
613    Ok(())
614}
615
616/// Invoke `GetSceneMembership` command on cluster `Scenes Management`.
617pub async fn get_scene_membership(conn: &crate::controller::Connection, endpoint: u16, group_id: u8) -> anyhow::Result<GetSceneMembershipResponse> {
618    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SCENES_MANAGEMENT, crate::clusters::defs::CLUSTER_SCENES_MANAGEMENT_CMD_ID_GETSCENEMEMBERSHIP, &encode_get_scene_membership(group_id)?).await?;
619    decode_get_scene_membership_response(&tlv)
620}
621
622/// Invoke `CopyScene` command on cluster `Scenes Management`.
623pub async fn copy_scene(conn: &crate::controller::Connection, endpoint: u16, mode: CopyMode, group_identifier_from: u8, scene_identifier_from: u8, group_identifier_to: u8, scene_identifier_to: u8) -> anyhow::Result<CopySceneResponse> {
624    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SCENES_MANAGEMENT, crate::clusters::defs::CLUSTER_SCENES_MANAGEMENT_CMD_ID_COPYSCENE, &encode_copy_scene(mode, group_identifier_from, scene_identifier_from, group_identifier_to, scene_identifier_to)?).await?;
625    decode_copy_scene_response(&tlv)
626}
627
628/// Read `DoNotUse` attribute from cluster `Scenes Management`.
629pub async fn read_do_not_use(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
630    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SCENES_MANAGEMENT, crate::clusters::defs::CLUSTER_SCENES_MANAGEMENT_ATTR_ID_DONOTUSE).await?;
631    decode_do_not_use(&tlv)
632}
633
634/// Read `SceneTableSize` attribute from cluster `Scenes Management`.
635pub async fn read_scene_table_size(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
636    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SCENES_MANAGEMENT, crate::clusters::defs::CLUSTER_SCENES_MANAGEMENT_ATTR_ID_SCENETABLESIZE).await?;
637    decode_scene_table_size(&tlv)
638}
639
640/// Read `FabricSceneInfo` attribute from cluster `Scenes Management`.
641pub async fn read_fabric_scene_info(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<SceneInfo>> {
642    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SCENES_MANAGEMENT, crate::clusters::defs::CLUSTER_SCENES_MANAGEMENT_ATTR_ID_FABRICSCENEINFO).await?;
643    decode_fabric_scene_info(&tlv)
644}
645