matc/clusters/codec/
time_sync.rs

1//! Generated Matter TLV encoders and decoders for Time Synchronization Cluster
2//! Cluster ID: 0x0038
3//! 
4//! This file is automatically generated from TimeSync.xml
5
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Struct definitions
12
13#[derive(Debug, serde::Serialize)]
14pub struct DSTOffset {
15    pub offset: Option<i32>,
16    pub valid_starting: Option<u8>,
17    pub valid_until: Option<u8>,
18}
19
20#[derive(Debug, serde::Serialize)]
21pub struct FabricScopedTrustedTimeSource {
22    pub node_id: Option<u64>,
23    pub endpoint: Option<u16>,
24}
25
26#[derive(Debug, serde::Serialize)]
27pub struct TimeZone {
28    pub offset: Option<i32>,
29    pub valid_at: Option<u8>,
30    pub name: Option<String>,
31}
32
33#[derive(Debug, serde::Serialize)]
34pub struct TrustedTimeSource {
35    pub fabric_index: Option<u8>,
36    pub node_id: Option<u64>,
37    pub endpoint: Option<u16>,
38}
39
40// Command encoders
41
42/// Encode SetUTCTime command (0x00)
43pub fn encode_set_utc_time(utc_time: u8, granularity: u8, time_source: u8) -> anyhow::Result<Vec<u8>> {
44    let tlv = tlv::TlvItemEnc {
45        tag: 0,
46        value: tlv::TlvItemValueEnc::StructInvisible(vec![
47        (0, tlv::TlvItemValueEnc::UInt8(utc_time)).into(),
48        (1, tlv::TlvItemValueEnc::UInt8(granularity)).into(),
49        (2, tlv::TlvItemValueEnc::UInt8(time_source)).into(),
50        ]),
51    };
52    Ok(tlv.encode()?)
53}
54
55/// Encode SetTrustedTimeSource command (0x01)
56pub fn encode_set_trusted_time_source(trusted_time_source: Option<u8>) -> anyhow::Result<Vec<u8>> {
57    let tlv = tlv::TlvItemEnc {
58        tag: 0,
59        value: tlv::TlvItemValueEnc::StructInvisible(vec![
60        (0, tlv::TlvItemValueEnc::UInt8(trusted_time_source.unwrap_or(0))).into(),
61        ]),
62    };
63    Ok(tlv.encode()?)
64}
65
66/// Encode SetTimeZone command (0x02)
67pub fn encode_set_time_zone(time_zone: Vec<u8>) -> anyhow::Result<Vec<u8>> {
68    let tlv = tlv::TlvItemEnc {
69        tag: 0,
70        value: tlv::TlvItemValueEnc::StructInvisible(vec![
71        (0, tlv::TlvItemValueEnc::StructAnon(time_zone.into_iter().map(|v| (0, tlv::TlvItemValueEnc::UInt8(v)).into()).collect())).into(),
72        ]),
73    };
74    Ok(tlv.encode()?)
75}
76
77/// Encode SetDSTOffset command (0x04)
78pub fn encode_set_dst_offset(dst_offset: Vec<u8>) -> anyhow::Result<Vec<u8>> {
79    let tlv = tlv::TlvItemEnc {
80        tag: 0,
81        value: tlv::TlvItemValueEnc::StructInvisible(vec![
82        (0, tlv::TlvItemValueEnc::StructAnon(dst_offset.into_iter().map(|v| (0, tlv::TlvItemValueEnc::UInt8(v)).into()).collect())).into(),
83        ]),
84    };
85    Ok(tlv.encode()?)
86}
87
88/// Encode SetDefaultNTP command (0x05)
89pub fn encode_set_default_ntp(default_ntp: Option<String>) -> anyhow::Result<Vec<u8>> {
90    let tlv = tlv::TlvItemEnc {
91        tag: 0,
92        value: tlv::TlvItemValueEnc::StructInvisible(vec![
93        (0, tlv::TlvItemValueEnc::String(default_ntp.unwrap_or("".to_string()))).into(),
94        ]),
95    };
96    Ok(tlv.encode()?)
97}
98
99// Attribute decoders
100
101/// Decode UTCTime attribute (0x0000)
102pub fn decode_utc_time(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
103    if let tlv::TlvItemValue::Int(v) = inp {
104        Ok(Some(*v as u8))
105    } else {
106        Ok(None)
107    }
108}
109
110/// Decode Granularity attribute (0x0001)
111pub fn decode_granularity(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
112    if let tlv::TlvItemValue::Int(v) = inp {
113        Ok(*v as u8)
114    } else {
115        Err(anyhow::anyhow!("Expected Integer"))
116    }
117}
118
119/// Decode TimeSource attribute (0x0002)
120pub fn decode_time_source(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
121    if let tlv::TlvItemValue::Int(v) = inp {
122        Ok(*v as u8)
123    } else {
124        Err(anyhow::anyhow!("Expected Integer"))
125    }
126}
127
128/// Decode TrustedTimeSource attribute (0x0003)
129pub fn decode_trusted_time_source(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<TrustedTimeSource>> {
130    if let tlv::TlvItemValue::List(_fields) = inp {
131        // Struct with fields
132        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
133        Ok(Some(TrustedTimeSource {
134                fabric_index: item.get_int(&[0]).map(|v| v as u8),
135                node_id: item.get_int(&[1]),
136                endpoint: item.get_int(&[2]).map(|v| v as u16),
137        }))
138    //} else if let tlv::TlvItemValue::Null = inp {
139    //    // Null value for nullable struct
140    //    Ok(None)
141    } else {
142    Ok(None)
143    //    Err(anyhow::anyhow!("Expected struct fields or null"))
144    }
145}
146
147/// Decode DefaultNTP attribute (0x0004)
148pub fn decode_default_ntp(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<String>> {
149    if let tlv::TlvItemValue::String(v) = inp {
150        Ok(Some(v.clone()))
151    } else {
152        Ok(None)
153    }
154}
155
156/// Decode TimeZone attribute (0x0005)
157pub fn decode_time_zone(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<TimeZone>> {
158    let mut res = Vec::new();
159    if let tlv::TlvItemValue::List(v) = inp {
160        for item in v {
161            res.push(TimeZone {
162                offset: item.get_int(&[0]).map(|v| v as i32),
163                valid_at: item.get_int(&[1]).map(|v| v as u8),
164                name: item.get_string_owned(&[2]),
165            });
166        }
167    }
168    Ok(res)
169}
170
171/// Decode DSTOffset attribute (0x0006)
172pub fn decode_dst_offset(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DSTOffset>> {
173    let mut res = Vec::new();
174    if let tlv::TlvItemValue::List(v) = inp {
175        for item in v {
176            res.push(DSTOffset {
177                offset: item.get_int(&[0]).map(|v| v as i32),
178                valid_starting: item.get_int(&[1]).map(|v| v as u8),
179                valid_until: item.get_int(&[2]).map(|v| v as u8),
180            });
181        }
182    }
183    Ok(res)
184}
185
186/// Decode LocalTime attribute (0x0007)
187pub fn decode_local_time(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
188    if let tlv::TlvItemValue::Int(v) = inp {
189        Ok(Some(*v as u8))
190    } else {
191        Ok(None)
192    }
193}
194
195/// Decode TimeZoneDatabase attribute (0x0008)
196pub fn decode_time_zone_database(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
197    if let tlv::TlvItemValue::Int(v) = inp {
198        Ok(*v as u8)
199    } else {
200        Err(anyhow::anyhow!("Expected Integer"))
201    }
202}
203
204/// Decode NTPServerAvailable attribute (0x0009)
205pub fn decode_ntp_server_available(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
206    if let tlv::TlvItemValue::Bool(v) = inp {
207        Ok(*v)
208    } else {
209        Err(anyhow::anyhow!("Expected Bool"))
210    }
211}
212
213/// Decode TimeZoneListMaxSize attribute (0x000A)
214pub fn decode_time_zone_list_max_size(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
215    if let tlv::TlvItemValue::Int(v) = inp {
216        Ok(*v as u8)
217    } else {
218        Err(anyhow::anyhow!("Expected Integer"))
219    }
220}
221
222/// Decode DSTOffsetListMaxSize attribute (0x000B)
223pub fn decode_dst_offset_list_max_size(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
224    if let tlv::TlvItemValue::Int(v) = inp {
225        Ok(*v as u8)
226    } else {
227        Err(anyhow::anyhow!("Expected Integer"))
228    }
229}
230
231/// Decode SupportsDNSResolve attribute (0x000C)
232pub fn decode_supports_dns_resolve(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
233    if let tlv::TlvItemValue::Bool(v) = inp {
234        Ok(*v)
235    } else {
236        Err(anyhow::anyhow!("Expected Bool"))
237    }
238}
239
240
241// JSON dispatcher function
242
243/// Decode attribute value and return as JSON string
244/// 
245/// # Parameters
246/// * `cluster_id` - The cluster identifier
247/// * `attribute_id` - The attribute identifier
248/// * `tlv_value` - The TLV value to decode
249/// 
250/// # Returns
251/// JSON string representation of the decoded value or error
252pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
253    // Verify this is the correct cluster
254    if cluster_id != 0x0038 {
255        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0038, got {}\"}}", cluster_id);
256    }
257    
258    match attribute_id {
259        0x0000 => {
260            match decode_utc_time(tlv_value) {
261                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
262                Err(e) => format!("{{\"error\": \"{}\"}}", e),
263            }
264        }
265        0x0001 => {
266            match decode_granularity(tlv_value) {
267                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
268                Err(e) => format!("{{\"error\": \"{}\"}}", e),
269            }
270        }
271        0x0002 => {
272            match decode_time_source(tlv_value) {
273                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
274                Err(e) => format!("{{\"error\": \"{}\"}}", e),
275            }
276        }
277        0x0003 => {
278            match decode_trusted_time_source(tlv_value) {
279                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
280                Err(e) => format!("{{\"error\": \"{}\"}}", e),
281            }
282        }
283        0x0004 => {
284            match decode_default_ntp(tlv_value) {
285                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
286                Err(e) => format!("{{\"error\": \"{}\"}}", e),
287            }
288        }
289        0x0005 => {
290            match decode_time_zone(tlv_value) {
291                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
292                Err(e) => format!("{{\"error\": \"{}\"}}", e),
293            }
294        }
295        0x0006 => {
296            match decode_dst_offset(tlv_value) {
297                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
298                Err(e) => format!("{{\"error\": \"{}\"}}", e),
299            }
300        }
301        0x0007 => {
302            match decode_local_time(tlv_value) {
303                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
304                Err(e) => format!("{{\"error\": \"{}\"}}", e),
305            }
306        }
307        0x0008 => {
308            match decode_time_zone_database(tlv_value) {
309                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
310                Err(e) => format!("{{\"error\": \"{}\"}}", e),
311            }
312        }
313        0x0009 => {
314            match decode_ntp_server_available(tlv_value) {
315                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
316                Err(e) => format!("{{\"error\": \"{}\"}}", e),
317            }
318        }
319        0x000A => {
320            match decode_time_zone_list_max_size(tlv_value) {
321                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
322                Err(e) => format!("{{\"error\": \"{}\"}}", e),
323            }
324        }
325        0x000B => {
326            match decode_dst_offset_list_max_size(tlv_value) {
327                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
328                Err(e) => format!("{{\"error\": \"{}\"}}", e),
329            }
330        }
331        0x000C => {
332            match decode_supports_dns_resolve(tlv_value) {
333                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
334                Err(e) => format!("{{\"error\": \"{}\"}}", e),
335            }
336        }
337        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
338    }
339}
340
341/// Get list of all attributes supported by this cluster
342/// 
343/// # Returns
344/// Vector of tuples containing (attribute_id, attribute_name)
345pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
346    vec![
347        (0x0000, "UTCTime"),
348        (0x0001, "Granularity"),
349        (0x0002, "TimeSource"),
350        (0x0003, "TrustedTimeSource"),
351        (0x0004, "DefaultNTP"),
352        (0x0005, "TimeZone"),
353        (0x0006, "DSTOffset"),
354        (0x0007, "LocalTime"),
355        (0x0008, "TimeZoneDatabase"),
356        (0x0009, "NTPServerAvailable"),
357        (0x000A, "TimeZoneListMaxSize"),
358        (0x000B, "DSTOffsetListMaxSize"),
359        (0x000C, "SupportsDNSResolve"),
360    ]
361}
362