matc/clusters/codec/
identify.rs

1//! Matter TLV encoders and decoders for Identify Cluster
2//! Cluster ID: 0x0003
3//!
4//! This file is automatically generated from Identify.xml
5
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Enum definitions
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
14#[repr(u8)]
15pub enum EffectIdentifier {
16    /// e.g., Light is turned on/off once.
17    Blink = 0,
18    /// e.g., Light is turned on/off over 1 second and repeated 15 times.
19    Breathe = 1,
20    /// e.g., Colored light turns green for 1 second; non-colored light flashes twice.
21    Okay = 2,
22    /// e.g., Colored light turns orange for 8 seconds; non-colored light switches to the maximum brightness for 0.5s and then minimum brightness for 7.5s.
23    Channelchange = 11,
24    /// Complete the current effect sequence before terminating. e.g., if in the middle of a breathe effect (as above), first complete the current 1s breathe effect and then terminate the effect.
25    Finisheffect = 254,
26    /// Terminate the effect as soon as possible.
27    Stopeffect = 255,
28}
29
30impl EffectIdentifier {
31    /// Convert from u8 value
32    pub fn from_u8(value: u8) -> Option<Self> {
33        match value {
34            0 => Some(EffectIdentifier::Blink),
35            1 => Some(EffectIdentifier::Breathe),
36            2 => Some(EffectIdentifier::Okay),
37            11 => Some(EffectIdentifier::Channelchange),
38            254 => Some(EffectIdentifier::Finisheffect),
39            255 => Some(EffectIdentifier::Stopeffect),
40            _ => None,
41        }
42    }
43
44    /// Convert to u8 value
45    pub fn to_u8(self) -> u8 {
46        self as u8
47    }
48}
49
50impl From<EffectIdentifier> for u8 {
51    fn from(val: EffectIdentifier) -> Self {
52        val as u8
53    }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
57#[repr(u8)]
58pub enum EffectVariant {
59    /// Indicates the default effect is used
60    Default = 0,
61}
62
63impl EffectVariant {
64    /// Convert from u8 value
65    pub fn from_u8(value: u8) -> Option<Self> {
66        match value {
67            0 => Some(EffectVariant::Default),
68            _ => None,
69        }
70    }
71
72    /// Convert to u8 value
73    pub fn to_u8(self) -> u8 {
74        self as u8
75    }
76}
77
78impl From<EffectVariant> for u8 {
79    fn from(val: EffectVariant) -> Self {
80        val as u8
81    }
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
85#[repr(u8)]
86pub enum IdentifyType {
87    /// No presentation.
88    None = 0,
89    /// Light output of a lighting product.
90    Lightoutput = 1,
91    /// Typically a small LED.
92    Visibleindicator = 2,
93    Audiblebeep = 3,
94    /// Presentation will be visible on display screen.
95    Display = 4,
96    /// Presentation will be conveyed by actuator functionality such as through a window blind operation or in-wall relay.
97    Actuator = 5,
98}
99
100impl IdentifyType {
101    /// Convert from u8 value
102    pub fn from_u8(value: u8) -> Option<Self> {
103        match value {
104            0 => Some(IdentifyType::None),
105            1 => Some(IdentifyType::Lightoutput),
106            2 => Some(IdentifyType::Visibleindicator),
107            3 => Some(IdentifyType::Audiblebeep),
108            4 => Some(IdentifyType::Display),
109            5 => Some(IdentifyType::Actuator),
110            _ => None,
111        }
112    }
113
114    /// Convert to u8 value
115    pub fn to_u8(self) -> u8 {
116        self as u8
117    }
118}
119
120impl From<IdentifyType> for u8 {
121    fn from(val: IdentifyType) -> Self {
122        val as u8
123    }
124}
125
126// Command encoders
127
128/// Encode Identify command (0x00)
129pub fn encode_identify(identify_time: u16) -> anyhow::Result<Vec<u8>> {
130    let tlv = tlv::TlvItemEnc {
131        tag: 0,
132        value: tlv::TlvItemValueEnc::StructInvisible(vec![
133        (0, tlv::TlvItemValueEnc::UInt16(identify_time)).into(),
134        ]),
135    };
136    Ok(tlv.encode()?)
137}
138
139/// Encode TriggerEffect command (0x40)
140pub fn encode_trigger_effect(effect_identifier: EffectIdentifier, effect_variant: EffectVariant) -> anyhow::Result<Vec<u8>> {
141    let tlv = tlv::TlvItemEnc {
142        tag: 0,
143        value: tlv::TlvItemValueEnc::StructInvisible(vec![
144        (0, tlv::TlvItemValueEnc::UInt8(effect_identifier.to_u8())).into(),
145        (1, tlv::TlvItemValueEnc::UInt8(effect_variant.to_u8())).into(),
146        ]),
147    };
148    Ok(tlv.encode()?)
149}
150
151// Attribute decoders
152
153/// Decode IdentifyTime attribute (0x0000)
154pub fn decode_identify_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
155    if let tlv::TlvItemValue::Int(v) = inp {
156        Ok(*v as u16)
157    } else {
158        Err(anyhow::anyhow!("Expected UInt16"))
159    }
160}
161
162/// Decode IdentifyType attribute (0x0001)
163pub fn decode_identify_type(inp: &tlv::TlvItemValue) -> anyhow::Result<IdentifyType> {
164    if let tlv::TlvItemValue::Int(v) = inp {
165        IdentifyType::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
166    } else {
167        Err(anyhow::anyhow!("Expected Integer"))
168    }
169}
170
171
172// JSON dispatcher function
173
174/// Decode attribute value and return as JSON string
175///
176/// # Parameters
177/// * `cluster_id` - The cluster identifier
178/// * `attribute_id` - The attribute identifier
179/// * `tlv_value` - The TLV value to decode
180///
181/// # Returns
182/// JSON string representation of the decoded value or error
183pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
184    // Verify this is the correct cluster
185    if cluster_id != 0x0003 {
186        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0003, got {}\"}}", cluster_id);
187    }
188
189    match attribute_id {
190        0x0000 => {
191            match decode_identify_time(tlv_value) {
192                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
193                Err(e) => format!("{{\"error\": \"{}\"}}", e),
194            }
195        }
196        0x0001 => {
197            match decode_identify_type(tlv_value) {
198                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
199                Err(e) => format!("{{\"error\": \"{}\"}}", e),
200            }
201        }
202        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
203    }
204}
205
206/// Get list of all attributes supported by this cluster
207///
208/// # Returns
209/// Vector of tuples containing (attribute_id, attribute_name)
210pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
211    vec![
212        (0x0000, "IdentifyTime"),
213        (0x0001, "IdentifyType"),
214    ]
215}
216