matc/clusters/codec/
switch.rs

1//! Matter TLV encoders and decoders for Switch Cluster
2//! Cluster ID: 0x003B
3//!
4//! This file is automatically generated from Switch.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Attribute decoders
14
15/// Decode NumberOfPositions attribute (0x0000)
16pub fn decode_number_of_positions(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
17    if let tlv::TlvItemValue::Int(v) = inp {
18        Ok(*v as u8)
19    } else {
20        Err(anyhow::anyhow!("Expected UInt8"))
21    }
22}
23
24/// Decode CurrentPosition attribute (0x0001)
25pub fn decode_current_position(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
26    if let tlv::TlvItemValue::Int(v) = inp {
27        Ok(*v as u8)
28    } else {
29        Err(anyhow::anyhow!("Expected UInt8"))
30    }
31}
32
33/// Decode MultiPressMax attribute (0x0002)
34pub fn decode_multi_press_max(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
35    if let tlv::TlvItemValue::Int(v) = inp {
36        Ok(*v as u8)
37    } else {
38        Err(anyhow::anyhow!("Expected UInt8"))
39    }
40}
41
42
43// JSON dispatcher function
44
45/// Decode attribute value and return as JSON string
46///
47/// # Parameters
48/// * `cluster_id` - The cluster identifier
49/// * `attribute_id` - The attribute identifier
50/// * `tlv_value` - The TLV value to decode
51///
52/// # Returns
53/// JSON string representation of the decoded value or error
54pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
55    // Verify this is the correct cluster
56    if cluster_id != 0x003B {
57        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x003B, got {}\"}}", cluster_id);
58    }
59
60    match attribute_id {
61        0x0000 => {
62            match decode_number_of_positions(tlv_value) {
63                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
64                Err(e) => format!("{{\"error\": \"{}\"}}", e),
65            }
66        }
67        0x0001 => {
68            match decode_current_position(tlv_value) {
69                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
70                Err(e) => format!("{{\"error\": \"{}\"}}", e),
71            }
72        }
73        0x0002 => {
74            match decode_multi_press_max(tlv_value) {
75                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
76                Err(e) => format!("{{\"error\": \"{}\"}}", e),
77            }
78        }
79        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
80    }
81}
82
83/// Get list of all attributes supported by this cluster
84///
85/// # Returns
86/// Vector of tuples containing (attribute_id, attribute_name)
87pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
88    vec![
89        (0x0000, "NumberOfPositions"),
90        (0x0001, "CurrentPosition"),
91        (0x0002, "MultiPressMax"),
92    ]
93}
94
95// Typed facade (invokes + reads)
96
97/// Read `NumberOfPositions` attribute from cluster `Switch`.
98pub async fn read_number_of_positions(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
99    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SWITCH, crate::clusters::defs::CLUSTER_SWITCH_ATTR_ID_NUMBEROFPOSITIONS).await?;
100    decode_number_of_positions(&tlv)
101}
102
103/// Read `CurrentPosition` attribute from cluster `Switch`.
104pub async fn read_current_position(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
105    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SWITCH, crate::clusters::defs::CLUSTER_SWITCH_ATTR_ID_CURRENTPOSITION).await?;
106    decode_current_position(&tlv)
107}
108
109/// Read `MultiPressMax` attribute from cluster `Switch`.
110pub async fn read_multi_press_max(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
111    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SWITCH, crate::clusters::defs::CLUSTER_SWITCH_ATTR_ID_MULTIPRESSMAX).await?;
112    decode_multi_press_max(&tlv)
113}
114
115#[derive(Debug, serde::Serialize)]
116pub struct SwitchLatchedEvent {
117    pub new_position: Option<u8>,
118}
119
120#[derive(Debug, serde::Serialize)]
121pub struct InitialPressEvent {
122    pub new_position: Option<u8>,
123}
124
125#[derive(Debug, serde::Serialize)]
126pub struct LongPressEvent {
127    pub new_position: Option<u8>,
128}
129
130#[derive(Debug, serde::Serialize)]
131pub struct ShortReleaseEvent {
132    pub previous_position: Option<u8>,
133}
134
135#[derive(Debug, serde::Serialize)]
136pub struct LongReleaseEvent {
137    pub previous_position: Option<u8>,
138}
139
140#[derive(Debug, serde::Serialize)]
141pub struct MultiPressOngoingEvent {
142    pub new_position: Option<u8>,
143    pub current_number_of_presses_counted: Option<u8>,
144}
145
146#[derive(Debug, serde::Serialize)]
147pub struct MultiPressCompleteEvent {
148    pub previous_position: Option<u8>,
149    pub total_number_of_presses_counted: Option<u8>,
150}
151
152// Event decoders
153
154/// Decode SwitchLatched event (0x00, priority: info)
155pub fn decode_switch_latched_event(inp: &tlv::TlvItemValue) -> anyhow::Result<SwitchLatchedEvent> {
156    if let tlv::TlvItemValue::List(_fields) = inp {
157        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
158        Ok(SwitchLatchedEvent {
159                                new_position: item.get_int(&[0]).map(|v| v as u8),
160        })
161    } else {
162        Err(anyhow::anyhow!("Expected struct fields"))
163    }
164}
165
166/// Decode InitialPress event (0x01, priority: info)
167pub fn decode_initial_press_event(inp: &tlv::TlvItemValue) -> anyhow::Result<InitialPressEvent> {
168    if let tlv::TlvItemValue::List(_fields) = inp {
169        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
170        Ok(InitialPressEvent {
171                                new_position: item.get_int(&[0]).map(|v| v as u8),
172        })
173    } else {
174        Err(anyhow::anyhow!("Expected struct fields"))
175    }
176}
177
178/// Decode LongPress event (0x02, priority: info)
179pub fn decode_long_press_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LongPressEvent> {
180    if let tlv::TlvItemValue::List(_fields) = inp {
181        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
182        Ok(LongPressEvent {
183                                new_position: item.get_int(&[0]).map(|v| v as u8),
184        })
185    } else {
186        Err(anyhow::anyhow!("Expected struct fields"))
187    }
188}
189
190/// Decode ShortRelease event (0x03, priority: info)
191pub fn decode_short_release_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ShortReleaseEvent> {
192    if let tlv::TlvItemValue::List(_fields) = inp {
193        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
194        Ok(ShortReleaseEvent {
195                                previous_position: item.get_int(&[0]).map(|v| v as u8),
196        })
197    } else {
198        Err(anyhow::anyhow!("Expected struct fields"))
199    }
200}
201
202/// Decode LongRelease event (0x04, priority: info)
203pub fn decode_long_release_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LongReleaseEvent> {
204    if let tlv::TlvItemValue::List(_fields) = inp {
205        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
206        Ok(LongReleaseEvent {
207                                previous_position: item.get_int(&[0]).map(|v| v as u8),
208        })
209    } else {
210        Err(anyhow::anyhow!("Expected struct fields"))
211    }
212}
213
214/// Decode MultiPressOngoing event (0x05, priority: info)
215pub fn decode_multi_press_ongoing_event(inp: &tlv::TlvItemValue) -> anyhow::Result<MultiPressOngoingEvent> {
216    if let tlv::TlvItemValue::List(_fields) = inp {
217        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
218        Ok(MultiPressOngoingEvent {
219                                new_position: item.get_int(&[0]).map(|v| v as u8),
220                                current_number_of_presses_counted: item.get_int(&[1]).map(|v| v as u8),
221        })
222    } else {
223        Err(anyhow::anyhow!("Expected struct fields"))
224    }
225}
226
227/// Decode MultiPressComplete event (0x06, priority: info)
228pub fn decode_multi_press_complete_event(inp: &tlv::TlvItemValue) -> anyhow::Result<MultiPressCompleteEvent> {
229    if let tlv::TlvItemValue::List(_fields) = inp {
230        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
231        Ok(MultiPressCompleteEvent {
232                                previous_position: item.get_int(&[0]).map(|v| v as u8),
233                                total_number_of_presses_counted: item.get_int(&[1]).map(|v| v as u8),
234        })
235    } else {
236        Err(anyhow::anyhow!("Expected struct fields"))
237    }
238}
239