matc/clusters/codec/
energy_evse.rs

1//! Generated Matter TLV encoders and decoders for Energy EVSE Cluster
2//! Cluster ID: 0x0099
3//! 
4//! This file is automatically generated from EnergyEVSE.xml
5
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Struct definitions
12
13#[derive(Debug, serde::Serialize)]
14pub struct ChargingTargetSchedule {
15    pub day_of_week_for_sequence: Option<u8>,
16    pub charging_targets: Option<Vec<ChargingTarget>>,
17}
18
19#[derive(Debug, serde::Serialize)]
20pub struct ChargingTarget {
21    pub target_time_minutes_past_midnight: Option<u16>,
22    pub target_so_c: Option<u8>,
23    pub added_energy: Option<u8>,
24}
25
26// Command encoders
27
28/// Encode EnableCharging command (0x02)
29pub fn encode_enable_charging(charging_enabled_until: Option<u64>, minimum_charge_current: u8, maximum_charge_current: u8) -> anyhow::Result<Vec<u8>> {
30    let tlv = tlv::TlvItemEnc {
31        tag: 0,
32        value: tlv::TlvItemValueEnc::StructInvisible(vec![
33        (0, tlv::TlvItemValueEnc::UInt64(charging_enabled_until.unwrap_or(0))).into(),
34        (1, tlv::TlvItemValueEnc::UInt8(minimum_charge_current)).into(),
35        (2, tlv::TlvItemValueEnc::UInt8(maximum_charge_current)).into(),
36        ]),
37    };
38    Ok(tlv.encode()?)
39}
40
41/// Encode EnableDischarging command (0x03)
42pub fn encode_enable_discharging(discharging_enabled_until: Option<u64>, maximum_discharge_current: u8) -> anyhow::Result<Vec<u8>> {
43    let tlv = tlv::TlvItemEnc {
44        tag: 0,
45        value: tlv::TlvItemValueEnc::StructInvisible(vec![
46        (0, tlv::TlvItemValueEnc::UInt64(discharging_enabled_until.unwrap_or(0))).into(),
47        (1, tlv::TlvItemValueEnc::UInt8(maximum_discharge_current)).into(),
48        ]),
49    };
50    Ok(tlv.encode()?)
51}
52
53/// Encode SetTargets command (0x05)
54pub fn encode_set_targets(charging_target_schedules: Vec<u8>) -> anyhow::Result<Vec<u8>> {
55    let tlv = tlv::TlvItemEnc {
56        tag: 0,
57        value: tlv::TlvItemValueEnc::StructInvisible(vec![
58        (0, tlv::TlvItemValueEnc::StructAnon(charging_target_schedules.into_iter().map(|v| (0, tlv::TlvItemValueEnc::UInt8(v)).into()).collect())).into(),
59        ]),
60    };
61    Ok(tlv.encode()?)
62}
63
64// Attribute decoders
65
66/// Decode State attribute (0x0000)
67pub fn decode_state(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
68    if let tlv::TlvItemValue::Int(v) = inp {
69        Ok(Some(*v as u8))
70    } else {
71        Ok(None)
72    }
73}
74
75/// Decode SupplyState attribute (0x0001)
76pub fn decode_supply_state(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
77    if let tlv::TlvItemValue::Int(v) = inp {
78        Ok(*v as u8)
79    } else {
80        Err(anyhow::anyhow!("Expected Integer"))
81    }
82}
83
84/// Decode FaultState attribute (0x0002)
85pub fn decode_fault_state(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
86    if let tlv::TlvItemValue::Int(v) = inp {
87        Ok(*v as u8)
88    } else {
89        Err(anyhow::anyhow!("Expected Integer"))
90    }
91}
92
93/// Decode ChargingEnabledUntil attribute (0x0003)
94pub fn decode_charging_enabled_until(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
95    if let tlv::TlvItemValue::Int(v) = inp {
96        Ok(Some(*v))
97    } else {
98        Ok(None)
99    }
100}
101
102/// Decode DischargingEnabledUntil attribute (0x0004)
103pub fn decode_discharging_enabled_until(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
104    if let tlv::TlvItemValue::Int(v) = inp {
105        Ok(Some(*v))
106    } else {
107        Ok(None)
108    }
109}
110
111/// Decode CircuitCapacity attribute (0x0005)
112pub fn decode_circuit_capacity(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
113    if let tlv::TlvItemValue::Int(v) = inp {
114        Ok(*v as u8)
115    } else {
116        Err(anyhow::anyhow!("Expected Integer"))
117    }
118}
119
120/// Decode MinimumChargeCurrent attribute (0x0006)
121pub fn decode_minimum_charge_current(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
122    if let tlv::TlvItemValue::Int(v) = inp {
123        Ok(*v as u8)
124    } else {
125        Err(anyhow::anyhow!("Expected Integer"))
126    }
127}
128
129/// Decode MaximumChargeCurrent attribute (0x0007)
130pub fn decode_maximum_charge_current(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
131    if let tlv::TlvItemValue::Int(v) = inp {
132        Ok(*v as u8)
133    } else {
134        Err(anyhow::anyhow!("Expected Integer"))
135    }
136}
137
138/// Decode MaximumDischargeCurrent attribute (0x0008)
139pub fn decode_maximum_discharge_current(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
140    if let tlv::TlvItemValue::Int(v) = inp {
141        Ok(*v as u8)
142    } else {
143        Err(anyhow::anyhow!("Expected Integer"))
144    }
145}
146
147/// Decode UserMaximumChargeCurrent attribute (0x0009)
148pub fn decode_user_maximum_charge_current(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
149    if let tlv::TlvItemValue::Int(v) = inp {
150        Ok(*v as u8)
151    } else {
152        Err(anyhow::anyhow!("Expected Integer"))
153    }
154}
155
156/// Decode RandomizationDelayWindow attribute (0x000A)
157pub fn decode_randomization_delay_window(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
158    if let tlv::TlvItemValue::Int(v) = inp {
159        Ok(*v as u8)
160    } else {
161        Err(anyhow::anyhow!("Expected Integer"))
162    }
163}
164
165/// Decode NextChargeStartTime attribute (0x0023)
166pub fn decode_next_charge_start_time(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
167    if let tlv::TlvItemValue::Int(v) = inp {
168        Ok(Some(*v))
169    } else {
170        Ok(None)
171    }
172}
173
174/// Decode NextChargeTargetTime attribute (0x0024)
175pub fn decode_next_charge_target_time(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
176    if let tlv::TlvItemValue::Int(v) = inp {
177        Ok(Some(*v))
178    } else {
179        Ok(None)
180    }
181}
182
183/// Decode NextChargeRequiredEnergy attribute (0x0025)
184pub fn decode_next_charge_required_energy(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
185    if let tlv::TlvItemValue::Int(v) = inp {
186        Ok(Some(*v as u8))
187    } else {
188        Ok(None)
189    }
190}
191
192/// Decode NextChargeTargetSoC attribute (0x0026)
193pub fn decode_next_charge_target_so_c(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
194    if let tlv::TlvItemValue::Int(v) = inp {
195        Ok(Some(*v as u8))
196    } else {
197        Ok(None)
198    }
199}
200
201/// Decode ApproximateEVEfficiency attribute (0x0027)
202pub fn decode_approximate_ev_efficiency(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
203    if let tlv::TlvItemValue::Int(v) = inp {
204        Ok(Some(*v as u16))
205    } else {
206        Ok(None)
207    }
208}
209
210/// Decode StateOfCharge attribute (0x0030)
211pub fn decode_state_of_charge(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
212    if let tlv::TlvItemValue::Int(v) = inp {
213        Ok(Some(*v as u8))
214    } else {
215        Ok(None)
216    }
217}
218
219/// Decode BatteryCapacity attribute (0x0031)
220pub fn decode_battery_capacity(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
221    if let tlv::TlvItemValue::Int(v) = inp {
222        Ok(Some(*v as u8))
223    } else {
224        Ok(None)
225    }
226}
227
228/// Decode VehicleID attribute (0x0032)
229pub fn decode_vehicle_id(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<String>> {
230    if let tlv::TlvItemValue::String(v) = inp {
231        Ok(Some(v.clone()))
232    } else {
233        Ok(None)
234    }
235}
236
237/// Decode SessionID attribute (0x0040)
238pub fn decode_session_id(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
239    if let tlv::TlvItemValue::Int(v) = inp {
240        Ok(Some(*v as u32))
241    } else {
242        Ok(None)
243    }
244}
245
246/// Decode SessionDuration attribute (0x0041)
247pub fn decode_session_duration(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
248    if let tlv::TlvItemValue::Int(v) = inp {
249        Ok(Some(*v as u8))
250    } else {
251        Ok(None)
252    }
253}
254
255/// Decode SessionEnergyCharged attribute (0x0042)
256pub fn decode_session_energy_charged(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
257    if let tlv::TlvItemValue::Int(v) = inp {
258        Ok(Some(*v as u8))
259    } else {
260        Ok(None)
261    }
262}
263
264/// Decode SessionEnergyDischarged attribute (0x0043)
265pub fn decode_session_energy_discharged(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
266    if let tlv::TlvItemValue::Int(v) = inp {
267        Ok(Some(*v as u8))
268    } else {
269        Ok(None)
270    }
271}
272
273
274// JSON dispatcher function
275
276/// Decode attribute value and return as JSON string
277/// 
278/// # Parameters
279/// * `cluster_id` - The cluster identifier
280/// * `attribute_id` - The attribute identifier
281/// * `tlv_value` - The TLV value to decode
282/// 
283/// # Returns
284/// JSON string representation of the decoded value or error
285pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
286    // Verify this is the correct cluster
287    if cluster_id != 0x0099 {
288        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0099, got {}\"}}", cluster_id);
289    }
290    
291    match attribute_id {
292        0x0000 => {
293            match decode_state(tlv_value) {
294                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
295                Err(e) => format!("{{\"error\": \"{}\"}}", e),
296            }
297        }
298        0x0001 => {
299            match decode_supply_state(tlv_value) {
300                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
301                Err(e) => format!("{{\"error\": \"{}\"}}", e),
302            }
303        }
304        0x0002 => {
305            match decode_fault_state(tlv_value) {
306                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
307                Err(e) => format!("{{\"error\": \"{}\"}}", e),
308            }
309        }
310        0x0003 => {
311            match decode_charging_enabled_until(tlv_value) {
312                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
313                Err(e) => format!("{{\"error\": \"{}\"}}", e),
314            }
315        }
316        0x0004 => {
317            match decode_discharging_enabled_until(tlv_value) {
318                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
319                Err(e) => format!("{{\"error\": \"{}\"}}", e),
320            }
321        }
322        0x0005 => {
323            match decode_circuit_capacity(tlv_value) {
324                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
325                Err(e) => format!("{{\"error\": \"{}\"}}", e),
326            }
327        }
328        0x0006 => {
329            match decode_minimum_charge_current(tlv_value) {
330                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
331                Err(e) => format!("{{\"error\": \"{}\"}}", e),
332            }
333        }
334        0x0007 => {
335            match decode_maximum_charge_current(tlv_value) {
336                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
337                Err(e) => format!("{{\"error\": \"{}\"}}", e),
338            }
339        }
340        0x0008 => {
341            match decode_maximum_discharge_current(tlv_value) {
342                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
343                Err(e) => format!("{{\"error\": \"{}\"}}", e),
344            }
345        }
346        0x0009 => {
347            match decode_user_maximum_charge_current(tlv_value) {
348                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
349                Err(e) => format!("{{\"error\": \"{}\"}}", e),
350            }
351        }
352        0x000A => {
353            match decode_randomization_delay_window(tlv_value) {
354                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
355                Err(e) => format!("{{\"error\": \"{}\"}}", e),
356            }
357        }
358        0x0023 => {
359            match decode_next_charge_start_time(tlv_value) {
360                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
361                Err(e) => format!("{{\"error\": \"{}\"}}", e),
362            }
363        }
364        0x0024 => {
365            match decode_next_charge_target_time(tlv_value) {
366                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
367                Err(e) => format!("{{\"error\": \"{}\"}}", e),
368            }
369        }
370        0x0025 => {
371            match decode_next_charge_required_energy(tlv_value) {
372                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
373                Err(e) => format!("{{\"error\": \"{}\"}}", e),
374            }
375        }
376        0x0026 => {
377            match decode_next_charge_target_so_c(tlv_value) {
378                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
379                Err(e) => format!("{{\"error\": \"{}\"}}", e),
380            }
381        }
382        0x0027 => {
383            match decode_approximate_ev_efficiency(tlv_value) {
384                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
385                Err(e) => format!("{{\"error\": \"{}\"}}", e),
386            }
387        }
388        0x0030 => {
389            match decode_state_of_charge(tlv_value) {
390                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
391                Err(e) => format!("{{\"error\": \"{}\"}}", e),
392            }
393        }
394        0x0031 => {
395            match decode_battery_capacity(tlv_value) {
396                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
397                Err(e) => format!("{{\"error\": \"{}\"}}", e),
398            }
399        }
400        0x0032 => {
401            match decode_vehicle_id(tlv_value) {
402                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
403                Err(e) => format!("{{\"error\": \"{}\"}}", e),
404            }
405        }
406        0x0040 => {
407            match decode_session_id(tlv_value) {
408                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
409                Err(e) => format!("{{\"error\": \"{}\"}}", e),
410            }
411        }
412        0x0041 => {
413            match decode_session_duration(tlv_value) {
414                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
415                Err(e) => format!("{{\"error\": \"{}\"}}", e),
416            }
417        }
418        0x0042 => {
419            match decode_session_energy_charged(tlv_value) {
420                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
421                Err(e) => format!("{{\"error\": \"{}\"}}", e),
422            }
423        }
424        0x0043 => {
425            match decode_session_energy_discharged(tlv_value) {
426                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
427                Err(e) => format!("{{\"error\": \"{}\"}}", e),
428            }
429        }
430        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
431    }
432}
433
434/// Get list of all attributes supported by this cluster
435/// 
436/// # Returns
437/// Vector of tuples containing (attribute_id, attribute_name)
438pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
439    vec![
440        (0x0000, "State"),
441        (0x0001, "SupplyState"),
442        (0x0002, "FaultState"),
443        (0x0003, "ChargingEnabledUntil"),
444        (0x0004, "DischargingEnabledUntil"),
445        (0x0005, "CircuitCapacity"),
446        (0x0006, "MinimumChargeCurrent"),
447        (0x0007, "MaximumChargeCurrent"),
448        (0x0008, "MaximumDischargeCurrent"),
449        (0x0009, "UserMaximumChargeCurrent"),
450        (0x000A, "RandomizationDelayWindow"),
451        (0x0023, "NextChargeStartTime"),
452        (0x0024, "NextChargeTargetTime"),
453        (0x0025, "NextChargeRequiredEnergy"),
454        (0x0026, "NextChargeTargetSoC"),
455        (0x0027, "ApproximateEVEfficiency"),
456        (0x0030, "StateOfCharge"),
457        (0x0031, "BatteryCapacity"),
458        (0x0032, "VehicleID"),
459        (0x0040, "SessionID"),
460        (0x0041, "SessionDuration"),
461        (0x0042, "SessionEnergyCharged"),
462        (0x0043, "SessionEnergyDischarged"),
463    ]
464}
465