matc/clusters/codec/
pump_configuration_control.rs

1//! Matter TLV encoders and decoders for Pump Configuration and Control Cluster
2//! Cluster ID: 0x0200
3//!
4//! This file is automatically generated from PumpConfigurationControl.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 ControlMode {
16    /// The pump is running at a constant speed.
17    Constantspeed = 0,
18    /// The pump will regulate its speed to maintain a constant differential pressure over its flanges.
19    Constantpressure = 1,
20    /// The pump will regulate its speed to maintain a constant differential pressure over its flanges.
21    Proportionalpressure = 2,
22    /// The pump will regulate its speed to maintain a constant flow through the pump.
23    Constantflow = 3,
24    /// The pump will regulate its speed to maintain a constant temperature.
25    Constanttemperature = 5,
26    /// The operation of the pump is automatically optimized to provide the most suitable performance with respect to comfort and energy savings.
27    Automatic = 7,
28}
29
30impl ControlMode {
31    /// Convert from u8 value
32    pub fn from_u8(value: u8) -> Option<Self> {
33        match value {
34            0 => Some(ControlMode::Constantspeed),
35            1 => Some(ControlMode::Constantpressure),
36            2 => Some(ControlMode::Proportionalpressure),
37            3 => Some(ControlMode::Constantflow),
38            5 => Some(ControlMode::Constanttemperature),
39            7 => Some(ControlMode::Automatic),
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<ControlMode> for u8 {
51    fn from(val: ControlMode) -> Self {
52        val as u8
53    }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
57#[repr(u8)]
58pub enum OperationMode {
59    /// The pump is controlled by a setpoint, as defined by a connected remote sensor or by the ControlMode attribute.
60    Normal = 0,
61    /// This value sets the pump to run at the minimum possible speed it can without being stopped.
62    Minimum = 1,
63    /// This value sets the pump to run at its maximum possible speed.
64    Maximum = 2,
65    /// This value sets the pump to run with the local settings of the pump, regardless of what these are.
66    Local = 3,
67}
68
69impl OperationMode {
70    /// Convert from u8 value
71    pub fn from_u8(value: u8) -> Option<Self> {
72        match value {
73            0 => Some(OperationMode::Normal),
74            1 => Some(OperationMode::Minimum),
75            2 => Some(OperationMode::Maximum),
76            3 => Some(OperationMode::Local),
77            _ => None,
78        }
79    }
80
81    /// Convert to u8 value
82    pub fn to_u8(self) -> u8 {
83        self as u8
84    }
85}
86
87impl From<OperationMode> for u8 {
88    fn from(val: OperationMode) -> Self {
89        val as u8
90    }
91}
92
93// Bitmap definitions
94
95/// PumpStatus bitmap type
96pub type PumpStatus = u16;
97
98/// Constants for PumpStatus
99pub mod pumpstatus {
100    /// A fault related to the system or pump device is detected.
101    pub const DEVICE_FAULT: u16 = 0x01;
102    /// A fault related to the supply to the pump is detected.
103    pub const SUPPLY_FAULT: u16 = 0x02;
104    /// Setpoint is too low to achieve.
105    pub const SPEED_LOW: u16 = 0x04;
106    /// Setpoint is too high to achieve.
107    pub const SPEED_HIGH: u16 = 0x08;
108    /// Device control is overridden by hardware, such as an external STOP button or via a local HMI.
109    pub const LOCAL_OVERRIDE: u16 = 0x10;
110    /// Pump is currently running
111    pub const RUNNING: u16 = 0x20;
112    /// A remote pressure sensor is used as the sensor for the regulation of the pump.
113    pub const REMOTE_PRESSURE: u16 = 0x40;
114    /// A remote flow sensor is used as the sensor for the regulation of the pump.
115    pub const REMOTE_FLOW: u16 = 0x80;
116    /// A remote temperature sensor is used as the sensor for the regulation of the pump.
117    pub const REMOTE_TEMPERATURE: u16 = 0x100;
118}
119
120// Attribute decoders
121
122/// Decode MaxPressure attribute (0x0000)
123pub fn decode_max_pressure(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
124    if let tlv::TlvItemValue::Int(v) = inp {
125        Ok(Some(*v as i16))
126    } else {
127        Ok(None)
128    }
129}
130
131/// Decode MaxSpeed attribute (0x0001)
132pub fn decode_max_speed(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
133    if let tlv::TlvItemValue::Int(v) = inp {
134        Ok(Some(*v as u16))
135    } else {
136        Ok(None)
137    }
138}
139
140/// Decode MaxFlow attribute (0x0002)
141pub fn decode_max_flow(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
142    if let tlv::TlvItemValue::Int(v) = inp {
143        Ok(Some(*v as u16))
144    } else {
145        Ok(None)
146    }
147}
148
149/// Decode MinConstPressure attribute (0x0003)
150pub fn decode_min_const_pressure(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
151    if let tlv::TlvItemValue::Int(v) = inp {
152        Ok(Some(*v as i16))
153    } else {
154        Ok(None)
155    }
156}
157
158/// Decode MaxConstPressure attribute (0x0004)
159pub fn decode_max_const_pressure(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
160    if let tlv::TlvItemValue::Int(v) = inp {
161        Ok(Some(*v as i16))
162    } else {
163        Ok(None)
164    }
165}
166
167/// Decode MinCompPressure attribute (0x0005)
168pub fn decode_min_comp_pressure(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
169    if let tlv::TlvItemValue::Int(v) = inp {
170        Ok(Some(*v as i16))
171    } else {
172        Ok(None)
173    }
174}
175
176/// Decode MaxCompPressure attribute (0x0006)
177pub fn decode_max_comp_pressure(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
178    if let tlv::TlvItemValue::Int(v) = inp {
179        Ok(Some(*v as i16))
180    } else {
181        Ok(None)
182    }
183}
184
185/// Decode MinConstSpeed attribute (0x0007)
186pub fn decode_min_const_speed(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
187    if let tlv::TlvItemValue::Int(v) = inp {
188        Ok(Some(*v as u16))
189    } else {
190        Ok(None)
191    }
192}
193
194/// Decode MaxConstSpeed attribute (0x0008)
195pub fn decode_max_const_speed(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
196    if let tlv::TlvItemValue::Int(v) = inp {
197        Ok(Some(*v as u16))
198    } else {
199        Ok(None)
200    }
201}
202
203/// Decode MinConstFlow attribute (0x0009)
204pub fn decode_min_const_flow(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
205    if let tlv::TlvItemValue::Int(v) = inp {
206        Ok(Some(*v as u16))
207    } else {
208        Ok(None)
209    }
210}
211
212/// Decode MaxConstFlow attribute (0x000A)
213pub fn decode_max_const_flow(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
214    if let tlv::TlvItemValue::Int(v) = inp {
215        Ok(Some(*v as u16))
216    } else {
217        Ok(None)
218    }
219}
220
221/// Decode MinConstTemp attribute (0x000B)
222pub fn decode_min_const_temp(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
223    if let tlv::TlvItemValue::Int(v) = inp {
224        Ok(Some(*v as i16))
225    } else {
226        Ok(None)
227    }
228}
229
230/// Decode MaxConstTemp attribute (0x000C)
231pub fn decode_max_const_temp(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
232    if let tlv::TlvItemValue::Int(v) = inp {
233        Ok(Some(*v as i16))
234    } else {
235        Ok(None)
236    }
237}
238
239/// Decode PumpStatus attribute (0x0010)
240pub fn decode_pump_status(inp: &tlv::TlvItemValue) -> anyhow::Result<PumpStatus> {
241    if let tlv::TlvItemValue::Int(v) = inp {
242        Ok(*v as u16)
243    } else {
244        Err(anyhow::anyhow!("Expected Integer"))
245    }
246}
247
248/// Decode EffectiveOperationMode attribute (0x0011)
249pub fn decode_effective_operation_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<OperationMode> {
250    if let tlv::TlvItemValue::Int(v) = inp {
251        OperationMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
252    } else {
253        Err(anyhow::anyhow!("Expected Integer"))
254    }
255}
256
257/// Decode EffectiveControlMode attribute (0x0012)
258pub fn decode_effective_control_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<ControlMode> {
259    if let tlv::TlvItemValue::Int(v) = inp {
260        ControlMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
261    } else {
262        Err(anyhow::anyhow!("Expected Integer"))
263    }
264}
265
266/// Decode Capacity attribute (0x0013)
267pub fn decode_capacity(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
268    if let tlv::TlvItemValue::Int(v) = inp {
269        Ok(Some(*v as i16))
270    } else {
271        Ok(None)
272    }
273}
274
275/// Decode Speed attribute (0x0014)
276pub fn decode_speed(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
277    if let tlv::TlvItemValue::Int(v) = inp {
278        Ok(Some(*v as u16))
279    } else {
280        Ok(None)
281    }
282}
283
284/// Decode LifetimeRunningHours attribute (0x0015)
285pub fn decode_lifetime_running_hours(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
286    if let tlv::TlvItemValue::Int(v) = inp {
287        Ok(Some(*v as u8))
288    } else {
289        Ok(None)
290    }
291}
292
293/// Decode Power attribute (0x0016)
294pub fn decode_power(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
295    if let tlv::TlvItemValue::Int(v) = inp {
296        Ok(Some(*v as u8))
297    } else {
298        Ok(None)
299    }
300}
301
302/// Decode LifetimeEnergyConsumed attribute (0x0017)
303pub fn decode_lifetime_energy_consumed(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
304    if let tlv::TlvItemValue::Int(v) = inp {
305        Ok(Some(*v as u32))
306    } else {
307        Ok(None)
308    }
309}
310
311/// Decode OperationMode attribute (0x0020)
312pub fn decode_operation_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<OperationMode> {
313    if let tlv::TlvItemValue::Int(v) = inp {
314        OperationMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
315    } else {
316        Err(anyhow::anyhow!("Expected Integer"))
317    }
318}
319
320/// Decode ControlMode attribute (0x0021)
321pub fn decode_control_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<ControlMode> {
322    if let tlv::TlvItemValue::Int(v) = inp {
323        ControlMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
324    } else {
325        Err(anyhow::anyhow!("Expected Integer"))
326    }
327}
328
329/// Decode AlarmMask attribute (0x0022)
330pub fn decode_alarm_mask(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
331    if let tlv::TlvItemValue::Int(v) = inp {
332        Ok(*v as u8)
333    } else {
334        Err(anyhow::anyhow!("Expected UInt8"))
335    }
336}
337
338
339// JSON dispatcher function
340
341/// Decode attribute value and return as JSON string
342///
343/// # Parameters
344/// * `cluster_id` - The cluster identifier
345/// * `attribute_id` - The attribute identifier
346/// * `tlv_value` - The TLV value to decode
347///
348/// # Returns
349/// JSON string representation of the decoded value or error
350pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
351    // Verify this is the correct cluster
352    if cluster_id != 0x0200 {
353        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0200, got {}\"}}", cluster_id);
354    }
355
356    match attribute_id {
357        0x0000 => {
358            match decode_max_pressure(tlv_value) {
359                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
360                Err(e) => format!("{{\"error\": \"{}\"}}", e),
361            }
362        }
363        0x0001 => {
364            match decode_max_speed(tlv_value) {
365                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
366                Err(e) => format!("{{\"error\": \"{}\"}}", e),
367            }
368        }
369        0x0002 => {
370            match decode_max_flow(tlv_value) {
371                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
372                Err(e) => format!("{{\"error\": \"{}\"}}", e),
373            }
374        }
375        0x0003 => {
376            match decode_min_const_pressure(tlv_value) {
377                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
378                Err(e) => format!("{{\"error\": \"{}\"}}", e),
379            }
380        }
381        0x0004 => {
382            match decode_max_const_pressure(tlv_value) {
383                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
384                Err(e) => format!("{{\"error\": \"{}\"}}", e),
385            }
386        }
387        0x0005 => {
388            match decode_min_comp_pressure(tlv_value) {
389                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
390                Err(e) => format!("{{\"error\": \"{}\"}}", e),
391            }
392        }
393        0x0006 => {
394            match decode_max_comp_pressure(tlv_value) {
395                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
396                Err(e) => format!("{{\"error\": \"{}\"}}", e),
397            }
398        }
399        0x0007 => {
400            match decode_min_const_speed(tlv_value) {
401                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
402                Err(e) => format!("{{\"error\": \"{}\"}}", e),
403            }
404        }
405        0x0008 => {
406            match decode_max_const_speed(tlv_value) {
407                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
408                Err(e) => format!("{{\"error\": \"{}\"}}", e),
409            }
410        }
411        0x0009 => {
412            match decode_min_const_flow(tlv_value) {
413                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
414                Err(e) => format!("{{\"error\": \"{}\"}}", e),
415            }
416        }
417        0x000A => {
418            match decode_max_const_flow(tlv_value) {
419                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
420                Err(e) => format!("{{\"error\": \"{}\"}}", e),
421            }
422        }
423        0x000B => {
424            match decode_min_const_temp(tlv_value) {
425                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
426                Err(e) => format!("{{\"error\": \"{}\"}}", e),
427            }
428        }
429        0x000C => {
430            match decode_max_const_temp(tlv_value) {
431                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
432                Err(e) => format!("{{\"error\": \"{}\"}}", e),
433            }
434        }
435        0x0010 => {
436            match decode_pump_status(tlv_value) {
437                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
438                Err(e) => format!("{{\"error\": \"{}\"}}", e),
439            }
440        }
441        0x0011 => {
442            match decode_effective_operation_mode(tlv_value) {
443                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
444                Err(e) => format!("{{\"error\": \"{}\"}}", e),
445            }
446        }
447        0x0012 => {
448            match decode_effective_control_mode(tlv_value) {
449                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
450                Err(e) => format!("{{\"error\": \"{}\"}}", e),
451            }
452        }
453        0x0013 => {
454            match decode_capacity(tlv_value) {
455                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
456                Err(e) => format!("{{\"error\": \"{}\"}}", e),
457            }
458        }
459        0x0014 => {
460            match decode_speed(tlv_value) {
461                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
462                Err(e) => format!("{{\"error\": \"{}\"}}", e),
463            }
464        }
465        0x0015 => {
466            match decode_lifetime_running_hours(tlv_value) {
467                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
468                Err(e) => format!("{{\"error\": \"{}\"}}", e),
469            }
470        }
471        0x0016 => {
472            match decode_power(tlv_value) {
473                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
474                Err(e) => format!("{{\"error\": \"{}\"}}", e),
475            }
476        }
477        0x0017 => {
478            match decode_lifetime_energy_consumed(tlv_value) {
479                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
480                Err(e) => format!("{{\"error\": \"{}\"}}", e),
481            }
482        }
483        0x0020 => {
484            match decode_operation_mode(tlv_value) {
485                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
486                Err(e) => format!("{{\"error\": \"{}\"}}", e),
487            }
488        }
489        0x0021 => {
490            match decode_control_mode(tlv_value) {
491                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
492                Err(e) => format!("{{\"error\": \"{}\"}}", e),
493            }
494        }
495        0x0022 => {
496            match decode_alarm_mask(tlv_value) {
497                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
498                Err(e) => format!("{{\"error\": \"{}\"}}", e),
499            }
500        }
501        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
502    }
503}
504
505/// Get list of all attributes supported by this cluster
506///
507/// # Returns
508/// Vector of tuples containing (attribute_id, attribute_name)
509pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
510    vec![
511        (0x0000, "MaxPressure"),
512        (0x0001, "MaxSpeed"),
513        (0x0002, "MaxFlow"),
514        (0x0003, "MinConstPressure"),
515        (0x0004, "MaxConstPressure"),
516        (0x0005, "MinCompPressure"),
517        (0x0006, "MaxCompPressure"),
518        (0x0007, "MinConstSpeed"),
519        (0x0008, "MaxConstSpeed"),
520        (0x0009, "MinConstFlow"),
521        (0x000A, "MaxConstFlow"),
522        (0x000B, "MinConstTemp"),
523        (0x000C, "MaxConstTemp"),
524        (0x0010, "PumpStatus"),
525        (0x0011, "EffectiveOperationMode"),
526        (0x0012, "EffectiveControlMode"),
527        (0x0013, "Capacity"),
528        (0x0014, "Speed"),
529        (0x0015, "LifetimeRunningHours"),
530        (0x0016, "Power"),
531        (0x0017, "LifetimeEnergyConsumed"),
532        (0x0020, "OperationMode"),
533        (0x0021, "ControlMode"),
534        (0x0022, "AlarmMask"),
535    ]
536}
537