1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13pub type CopyMode = u8;
17
18pub mod copymode {
20 pub const COPY_ALL_SCENES: u8 = 0x01;
22}
23
24#[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
54pub 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
91pub 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
103pub 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
115pub 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
126pub 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
138pub 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
151pub 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
162pub 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
177pub 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
188pub 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
197pub 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
215pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
227 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
255pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
260 vec![
261 (0x0000, "DoNotUse"),
262 (0x0001, "SceneTableSize"),
263 (0x0002, "FabricSceneInfo"),
264 ]
265}
266
267pub 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
435pub 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
451pub 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
501pub 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
515pub 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
528pub 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
542pub 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
564pub 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
578pub 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
586pub 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
592pub 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
598pub 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
604pub 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
610pub 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
616pub 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
622pub 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
628pub 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
634pub 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
640pub 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