matc/clusters/codec/
valve_configuration_control.rs

1//! Matter TLV encoders and decoders for Valve Configuration and Control Cluster
2//! Cluster ID: 0x0081
3//!
4//! This file is automatically generated from ValveConfigurationControl.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 StatusCode {
16    /// The requested action could not be performed due to a fault on the valve.
17    Failureduetofault = 2,
18}
19
20impl StatusCode {
21    /// Convert from u8 value
22    pub fn from_u8(value: u8) -> Option<Self> {
23        match value {
24            2 => Some(StatusCode::Failureduetofault),
25            _ => None,
26        }
27    }
28
29    /// Convert to u8 value
30    pub fn to_u8(self) -> u8 {
31        self as u8
32    }
33}
34
35impl From<StatusCode> for u8 {
36    fn from(val: StatusCode) -> Self {
37        val as u8
38    }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
42#[repr(u8)]
43pub enum ValveState {
44    /// Valve is in closed position
45    Closed = 0,
46    /// Valve is in open position
47    Open = 1,
48    /// Valve is transitioning between closed and open positions or between levels
49    Transitioning = 2,
50}
51
52impl ValveState {
53    /// Convert from u8 value
54    pub fn from_u8(value: u8) -> Option<Self> {
55        match value {
56            0 => Some(ValveState::Closed),
57            1 => Some(ValveState::Open),
58            2 => Some(ValveState::Transitioning),
59            _ => None,
60        }
61    }
62
63    /// Convert to u8 value
64    pub fn to_u8(self) -> u8 {
65        self as u8
66    }
67}
68
69impl From<ValveState> for u8 {
70    fn from(val: ValveState) -> Self {
71        val as u8
72    }
73}
74
75// Bitmap definitions
76
77/// ValveFault bitmap type
78pub type ValveFault = u8;
79
80/// Constants for ValveFault
81pub mod valvefault {
82    /// Unspecified fault detected
83    pub const GENERAL_FAULT: u8 = 0x01;
84    /// Valve is blocked
85    pub const BLOCKED: u8 = 0x02;
86    /// Valve has detected a leak
87    pub const LEAKING: u8 = 0x04;
88    /// No valve is connected to controller
89    pub const NOT_CONNECTED: u8 = 0x08;
90    /// Short circuit is detected
91    pub const SHORT_CIRCUIT: u8 = 0x10;
92    /// The available current has been exceeded
93    pub const CURRENT_EXCEEDED: u8 = 0x20;
94}
95
96// Command encoders
97
98/// Encode Open command (0x00)
99pub fn encode_open(open_duration: Option<u32>, target_level: u8) -> anyhow::Result<Vec<u8>> {
100    let tlv = tlv::TlvItemEnc {
101        tag: 0,
102        value: tlv::TlvItemValueEnc::StructInvisible(vec![
103        (0, tlv::TlvItemValueEnc::UInt32(open_duration.unwrap_or(0))).into(),
104        (1, tlv::TlvItemValueEnc::UInt8(target_level)).into(),
105        ]),
106    };
107    Ok(tlv.encode()?)
108}
109
110// Attribute decoders
111
112/// Decode OpenDuration attribute (0x0000)
113pub fn decode_open_duration(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
114    if let tlv::TlvItemValue::Int(v) = inp {
115        Ok(Some(*v as u32))
116    } else {
117        Ok(None)
118    }
119}
120
121/// Decode DefaultOpenDuration attribute (0x0001)
122pub fn decode_default_open_duration(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
123    if let tlv::TlvItemValue::Int(v) = inp {
124        Ok(Some(*v as u32))
125    } else {
126        Ok(None)
127    }
128}
129
130/// Decode AutoCloseTime attribute (0x0002)
131pub fn decode_auto_close_time(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
132    if let tlv::TlvItemValue::Int(v) = inp {
133        Ok(Some(*v))
134    } else {
135        Ok(None)
136    }
137}
138
139/// Decode RemainingDuration attribute (0x0003)
140pub fn decode_remaining_duration(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
141    if let tlv::TlvItemValue::Int(v) = inp {
142        Ok(Some(*v as u32))
143    } else {
144        Ok(None)
145    }
146}
147
148/// Decode CurrentState attribute (0x0004)
149pub fn decode_current_state(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<ValveState>> {
150    if let tlv::TlvItemValue::Int(v) = inp {
151        Ok(ValveState::from_u8(*v as u8))
152    } else {
153        Ok(None)
154    }
155}
156
157/// Decode TargetState attribute (0x0005)
158pub fn decode_target_state(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<ValveState>> {
159    if let tlv::TlvItemValue::Int(v) = inp {
160        Ok(ValveState::from_u8(*v as u8))
161    } else {
162        Ok(None)
163    }
164}
165
166/// Decode CurrentLevel attribute (0x0006)
167pub fn decode_current_level(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
168    if let tlv::TlvItemValue::Int(v) = inp {
169        Ok(Some(*v as u8))
170    } else {
171        Ok(None)
172    }
173}
174
175/// Decode TargetLevel attribute (0x0007)
176pub fn decode_target_level(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
177    if let tlv::TlvItemValue::Int(v) = inp {
178        Ok(Some(*v as u8))
179    } else {
180        Ok(None)
181    }
182}
183
184/// Decode DefaultOpenLevel attribute (0x0008)
185pub fn decode_default_open_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
186    if let tlv::TlvItemValue::Int(v) = inp {
187        Ok(*v as u8)
188    } else {
189        Err(anyhow::anyhow!("Expected UInt8"))
190    }
191}
192
193/// Decode ValveFault attribute (0x0009)
194pub fn decode_valve_fault(inp: &tlv::TlvItemValue) -> anyhow::Result<ValveFault> {
195    if let tlv::TlvItemValue::Int(v) = inp {
196        Ok(*v as u8)
197    } else {
198        Err(anyhow::anyhow!("Expected Integer"))
199    }
200}
201
202/// Decode LevelStep attribute (0x000A)
203pub fn decode_level_step(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
204    if let tlv::TlvItemValue::Int(v) = inp {
205        Ok(*v as u8)
206    } else {
207        Err(anyhow::anyhow!("Expected UInt8"))
208    }
209}
210
211
212// JSON dispatcher function
213
214/// Decode attribute value and return as JSON string
215///
216/// # Parameters
217/// * `cluster_id` - The cluster identifier
218/// * `attribute_id` - The attribute identifier
219/// * `tlv_value` - The TLV value to decode
220///
221/// # Returns
222/// JSON string representation of the decoded value or error
223pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
224    // Verify this is the correct cluster
225    if cluster_id != 0x0081 {
226        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0081, got {}\"}}", cluster_id);
227    }
228
229    match attribute_id {
230        0x0000 => {
231            match decode_open_duration(tlv_value) {
232                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
233                Err(e) => format!("{{\"error\": \"{}\"}}", e),
234            }
235        }
236        0x0001 => {
237            match decode_default_open_duration(tlv_value) {
238                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
239                Err(e) => format!("{{\"error\": \"{}\"}}", e),
240            }
241        }
242        0x0002 => {
243            match decode_auto_close_time(tlv_value) {
244                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
245                Err(e) => format!("{{\"error\": \"{}\"}}", e),
246            }
247        }
248        0x0003 => {
249            match decode_remaining_duration(tlv_value) {
250                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
251                Err(e) => format!("{{\"error\": \"{}\"}}", e),
252            }
253        }
254        0x0004 => {
255            match decode_current_state(tlv_value) {
256                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
257                Err(e) => format!("{{\"error\": \"{}\"}}", e),
258            }
259        }
260        0x0005 => {
261            match decode_target_state(tlv_value) {
262                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
263                Err(e) => format!("{{\"error\": \"{}\"}}", e),
264            }
265        }
266        0x0006 => {
267            match decode_current_level(tlv_value) {
268                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
269                Err(e) => format!("{{\"error\": \"{}\"}}", e),
270            }
271        }
272        0x0007 => {
273            match decode_target_level(tlv_value) {
274                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
275                Err(e) => format!("{{\"error\": \"{}\"}}", e),
276            }
277        }
278        0x0008 => {
279            match decode_default_open_level(tlv_value) {
280                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
281                Err(e) => format!("{{\"error\": \"{}\"}}", e),
282            }
283        }
284        0x0009 => {
285            match decode_valve_fault(tlv_value) {
286                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
287                Err(e) => format!("{{\"error\": \"{}\"}}", e),
288            }
289        }
290        0x000A => {
291            match decode_level_step(tlv_value) {
292                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
293                Err(e) => format!("{{\"error\": \"{}\"}}", e),
294            }
295        }
296        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
297    }
298}
299
300/// Get list of all attributes supported by this cluster
301///
302/// # Returns
303/// Vector of tuples containing (attribute_id, attribute_name)
304pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
305    vec![
306        (0x0000, "OpenDuration"),
307        (0x0001, "DefaultOpenDuration"),
308        (0x0002, "AutoCloseTime"),
309        (0x0003, "RemainingDuration"),
310        (0x0004, "CurrentState"),
311        (0x0005, "TargetState"),
312        (0x0006, "CurrentLevel"),
313        (0x0007, "TargetLevel"),
314        (0x0008, "DefaultOpenLevel"),
315        (0x0009, "ValveFault"),
316        (0x000A, "LevelStep"),
317    ]
318}
319
320#[derive(Debug, serde::Serialize)]
321pub struct ValveStateChangedEvent {
322    pub valve_state: Option<ValveState>,
323    pub valve_level: Option<u8>,
324}
325
326#[derive(Debug, serde::Serialize)]
327pub struct ValveFaultEvent {
328    pub valve_fault: Option<ValveFault>,
329}
330
331// Event decoders
332
333/// Decode ValveStateChanged event (0x00, priority: info)
334pub fn decode_valve_state_changed_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ValveStateChangedEvent> {
335    if let tlv::TlvItemValue::List(_fields) = inp {
336        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
337        Ok(ValveStateChangedEvent {
338                                valve_state: item.get_int(&[0]).and_then(|v| ValveState::from_u8(v as u8)),
339                                valve_level: item.get_int(&[1]).map(|v| v as u8),
340        })
341    } else {
342        Err(anyhow::anyhow!("Expected struct fields"))
343    }
344}
345
346/// Decode ValveFault event (0x01, priority: info)
347pub fn decode_valve_fault_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ValveFaultEvent> {
348    if let tlv::TlvItemValue::List(_fields) = inp {
349        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
350        Ok(ValveFaultEvent {
351                                valve_fault: item.get_int(&[0]).map(|v| v as u8),
352        })
353    } else {
354        Err(anyhow::anyhow!("Expected struct fields"))
355    }
356}
357