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