matc/clusters/codec/
door_lock.rs

1//! Matter TLV encoders and decoders for Door Lock Cluster
2//! Cluster ID: 0x0101
3//!
4//! This file is automatically generated from DoorLock.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Import serialization helpers for octet strings
14use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
15
16// Enum definitions
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[repr(u8)]
20pub enum AlarmCode {
21    /// Locking Mechanism Jammed
22    Lockjammed = 0,
23    /// Lock Reset to Factory Defaults
24    Lockfactoryreset = 1,
25    /// Lock Radio Power Cycled
26    Lockradiopowercycled = 3,
27    /// Tamper Alarm - wrong code entry limit
28    Wrongcodeentrylimit = 4,
29    /// Tamper Alarm - front escutcheon removed from main
30    Frontesceutcheonremoved = 5,
31    /// Forced Door Open under Door Locked Condition
32    Doorforcedopen = 6,
33    /// Door ajar
34    Doorajar = 7,
35    /// Force User SOS alarm
36    Forceduser = 8,
37}
38
39impl AlarmCode {
40    /// Convert from u8 value
41    pub fn from_u8(value: u8) -> Option<Self> {
42        match value {
43            0 => Some(AlarmCode::Lockjammed),
44            1 => Some(AlarmCode::Lockfactoryreset),
45            3 => Some(AlarmCode::Lockradiopowercycled),
46            4 => Some(AlarmCode::Wrongcodeentrylimit),
47            5 => Some(AlarmCode::Frontesceutcheonremoved),
48            6 => Some(AlarmCode::Doorforcedopen),
49            7 => Some(AlarmCode::Doorajar),
50            8 => Some(AlarmCode::Forceduser),
51            _ => None,
52        }
53    }
54
55    /// Convert to u8 value
56    pub fn to_u8(self) -> u8 {
57        self as u8
58    }
59}
60
61impl From<AlarmCode> for u8 {
62    fn from(val: AlarmCode) -> Self {
63        val as u8
64    }
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
68#[repr(u8)]
69pub enum CredentialRule {
70    /// Only one credential is required for lock operation
71    Single = 0,
72    /// Any two credentials are required for lock operation
73    Dual = 1,
74    /// Any three credentials are required for lock operation
75    Tri = 2,
76}
77
78impl CredentialRule {
79    /// Convert from u8 value
80    pub fn from_u8(value: u8) -> Option<Self> {
81        match value {
82            0 => Some(CredentialRule::Single),
83            1 => Some(CredentialRule::Dual),
84            2 => Some(CredentialRule::Tri),
85            _ => None,
86        }
87    }
88
89    /// Convert to u8 value
90    pub fn to_u8(self) -> u8 {
91        self as u8
92    }
93}
94
95impl From<CredentialRule> for u8 {
96    fn from(val: CredentialRule) -> Self {
97        val as u8
98    }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
102#[repr(u8)]
103pub enum CredentialType {
104    /// Programming PIN code credential type
105    Programmingpin = 0,
106    /// PIN code credential type
107    Pin = 1,
108    /// RFID identifier credential type
109    Rfid = 2,
110    /// Fingerprint identifier credential type
111    Fingerprint = 3,
112    /// Finger vein identifier credential type
113    Fingervein = 4,
114    /// Face identifier credential type
115    Face = 5,
116    /// A Credential Issuer public key as defined in Aliro
117    Alirocredentialissuerkey = 6,
118    /// An Endpoint public key as defined in Aliro which can be evicted if space is needed for another endpoint key
119    Aliroevictableendpointkey = 7,
120    /// An Endpoint public key as defined in Aliro which cannot be evicted if space is needed for another endpoint key
121    Alirononevictableendpointkey = 8,
122}
123
124impl CredentialType {
125    /// Convert from u8 value
126    pub fn from_u8(value: u8) -> Option<Self> {
127        match value {
128            0 => Some(CredentialType::Programmingpin),
129            1 => Some(CredentialType::Pin),
130            2 => Some(CredentialType::Rfid),
131            3 => Some(CredentialType::Fingerprint),
132            4 => Some(CredentialType::Fingervein),
133            5 => Some(CredentialType::Face),
134            6 => Some(CredentialType::Alirocredentialissuerkey),
135            7 => Some(CredentialType::Aliroevictableendpointkey),
136            8 => Some(CredentialType::Alirononevictableendpointkey),
137            _ => None,
138        }
139    }
140
141    /// Convert to u8 value
142    pub fn to_u8(self) -> u8 {
143        self as u8
144    }
145}
146
147impl From<CredentialType> for u8 {
148    fn from(val: CredentialType) -> Self {
149        val as u8
150    }
151}
152
153#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
154#[repr(u8)]
155pub enum DataOperationType {
156    /// Data is being added or was added
157    Add = 0,
158    /// Data is being cleared or was cleared
159    Clear = 1,
160    /// Data is being modified or was modified
161    Modify = 2,
162}
163
164impl DataOperationType {
165    /// Convert from u8 value
166    pub fn from_u8(value: u8) -> Option<Self> {
167        match value {
168            0 => Some(DataOperationType::Add),
169            1 => Some(DataOperationType::Clear),
170            2 => Some(DataOperationType::Modify),
171            _ => None,
172        }
173    }
174
175    /// Convert to u8 value
176    pub fn to_u8(self) -> u8 {
177        self as u8
178    }
179}
180
181impl From<DataOperationType> for u8 {
182    fn from(val: DataOperationType) -> Self {
183        val as u8
184    }
185}
186
187#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
188#[repr(u8)]
189pub enum DoorState {
190    /// Door state is open
191    Dooropen = 0,
192    /// Door state is closed
193    Doorclosed = 1,
194    /// Door state is jammed
195    Doorjammed = 2,
196    /// Door state is currently forced open
197    Doorforcedopen = 3,
198    /// Door state is invalid for unspecified reason
199    Doorunspecifiederror = 4,
200    /// Door state is ajar
201    Doorajar = 5,
202}
203
204impl DoorState {
205    /// Convert from u8 value
206    pub fn from_u8(value: u8) -> Option<Self> {
207        match value {
208            0 => Some(DoorState::Dooropen),
209            1 => Some(DoorState::Doorclosed),
210            2 => Some(DoorState::Doorjammed),
211            3 => Some(DoorState::Doorforcedopen),
212            4 => Some(DoorState::Doorunspecifiederror),
213            5 => Some(DoorState::Doorajar),
214            _ => None,
215        }
216    }
217
218    /// Convert to u8 value
219    pub fn to_u8(self) -> u8 {
220        self as u8
221    }
222}
223
224impl From<DoorState> for u8 {
225    fn from(val: DoorState) -> Self {
226        val as u8
227    }
228}
229
230#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
231#[repr(u8)]
232pub enum EventType {
233    /// Event type is operation
234    Operation = 0,
235    /// Event type is programming
236    Programming = 1,
237    /// Event type is alarm
238    Alarm = 2,
239}
240
241impl EventType {
242    /// Convert from u8 value
243    pub fn from_u8(value: u8) -> Option<Self> {
244        match value {
245            0 => Some(EventType::Operation),
246            1 => Some(EventType::Programming),
247            2 => Some(EventType::Alarm),
248            _ => None,
249        }
250    }
251
252    /// Convert to u8 value
253    pub fn to_u8(self) -> u8 {
254        self as u8
255    }
256}
257
258impl From<EventType> for u8 {
259    fn from(val: EventType) -> Self {
260        val as u8
261    }
262}
263
264#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
265#[repr(u8)]
266pub enum LEDSetting {
267    /// Never use LED for signalization
268    Noledsignal = 0,
269    /// Use LED signalization except for access allowed events
270    Noledsignalaccessallowed = 1,
271    /// Use LED signalization for all events
272    Ledsignalall = 2,
273}
274
275impl LEDSetting {
276    /// Convert from u8 value
277    pub fn from_u8(value: u8) -> Option<Self> {
278        match value {
279            0 => Some(LEDSetting::Noledsignal),
280            1 => Some(LEDSetting::Noledsignalaccessallowed),
281            2 => Some(LEDSetting::Ledsignalall),
282            _ => None,
283        }
284    }
285
286    /// Convert to u8 value
287    pub fn to_u8(self) -> u8 {
288        self as u8
289    }
290}
291
292impl From<LEDSetting> for u8 {
293    fn from(val: LEDSetting) -> Self {
294        val as u8
295    }
296}
297
298#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
299#[repr(u8)]
300pub enum LockDataType {
301    /// Unspecified or manufacturer specific lock user data added, cleared, or modified.
302    Unspecified = 0,
303    /// Lock programming PIN code was added, cleared, or modified.
304    Programmingcode = 1,
305    /// Lock user index was added, cleared, or modified.
306    Userindex = 2,
307    /// Lock user week day schedule was added, cleared, or modified.
308    Weekdayschedule = 3,
309    /// Lock user year day schedule was added, cleared, or modified.
310    Yeardayschedule = 4,
311    /// Lock holiday schedule was added, cleared, or modified.
312    Holidayschedule = 5,
313    /// Lock user PIN code was added, cleared, or modified.
314    Pin = 6,
315    /// Lock user RFID code was added, cleared, or modified.
316    Rfid = 7,
317    /// Lock user fingerprint was added, cleared, or modified.
318    Fingerprint = 8,
319    /// Lock user finger-vein information was added, cleared, or modified.
320    Fingervein = 9,
321    /// Lock user face information was added, cleared, or modified.
322    Face = 10,
323    /// An Aliro credential issuer key credential was added, cleared, or modified.
324    Alirocredentialissuerkey = 11,
325    /// An Aliro endpoint key credential which can be evicted credential was added, cleared, or modified.
326    Aliroevictableendpointkey = 12,
327    /// An Aliro endpoint key credential which cannot be evicted was added, cleared, or modified.
328    Alirononevictableendpointkey = 13,
329}
330
331impl LockDataType {
332    /// Convert from u8 value
333    pub fn from_u8(value: u8) -> Option<Self> {
334        match value {
335            0 => Some(LockDataType::Unspecified),
336            1 => Some(LockDataType::Programmingcode),
337            2 => Some(LockDataType::Userindex),
338            3 => Some(LockDataType::Weekdayschedule),
339            4 => Some(LockDataType::Yeardayschedule),
340            5 => Some(LockDataType::Holidayschedule),
341            6 => Some(LockDataType::Pin),
342            7 => Some(LockDataType::Rfid),
343            8 => Some(LockDataType::Fingerprint),
344            9 => Some(LockDataType::Fingervein),
345            10 => Some(LockDataType::Face),
346            11 => Some(LockDataType::Alirocredentialissuerkey),
347            12 => Some(LockDataType::Aliroevictableendpointkey),
348            13 => Some(LockDataType::Alirononevictableendpointkey),
349            _ => None,
350        }
351    }
352
353    /// Convert to u8 value
354    pub fn to_u8(self) -> u8 {
355        self as u8
356    }
357}
358
359impl From<LockDataType> for u8 {
360    fn from(val: LockDataType) -> Self {
361        val as u8
362    }
363}
364
365#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
366#[repr(u8)]
367pub enum LockOperationType {
368    /// Lock operation
369    Lock = 0,
370    /// Unlock operation
371    Unlock = 1,
372    /// Triggered by keypad entry for user with User Type set to Non Access User
373    Nonaccessuserevent = 2,
374    /// Triggered by using a user with UserType set to Forced User
375    Forceduserevent = 3,
376    /// Unlatch operation
377    Unlatch = 4,
378}
379
380impl LockOperationType {
381    /// Convert from u8 value
382    pub fn from_u8(value: u8) -> Option<Self> {
383        match value {
384            0 => Some(LockOperationType::Lock),
385            1 => Some(LockOperationType::Unlock),
386            2 => Some(LockOperationType::Nonaccessuserevent),
387            3 => Some(LockOperationType::Forceduserevent),
388            4 => Some(LockOperationType::Unlatch),
389            _ => None,
390        }
391    }
392
393    /// Convert to u8 value
394    pub fn to_u8(self) -> u8 {
395        self as u8
396    }
397}
398
399impl From<LockOperationType> for u8 {
400    fn from(val: LockOperationType) -> Self {
401        val as u8
402    }
403}
404
405#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
406#[repr(u8)]
407pub enum LockState {
408    /// Lock state is not fully locked
409    Notfullylocked = 0,
410    /// Lock state is fully locked
411    Locked = 1,
412    /// Lock state is fully unlocked
413    Unlocked = 2,
414    /// Lock state is fully unlocked and the latch is pulled
415    Unlatched = 3,
416}
417
418impl LockState {
419    /// Convert from u8 value
420    pub fn from_u8(value: u8) -> Option<Self> {
421        match value {
422            0 => Some(LockState::Notfullylocked),
423            1 => Some(LockState::Locked),
424            2 => Some(LockState::Unlocked),
425            3 => Some(LockState::Unlatched),
426            _ => None,
427        }
428    }
429
430    /// Convert to u8 value
431    pub fn to_u8(self) -> u8 {
432        self as u8
433    }
434}
435
436impl From<LockState> for u8 {
437    fn from(val: LockState) -> Self {
438        val as u8
439    }
440}
441
442#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
443#[repr(u8)]
444pub enum LockType {
445    /// Physical lock type is dead bolt
446    Deadbolt = 0,
447    /// Physical lock type is magnetic
448    Magnetic = 1,
449    /// Physical lock type is other
450    Other = 2,
451    /// Physical lock type is mortise
452    Mortise = 3,
453    /// Physical lock type is rim
454    Rim = 4,
455    /// Physical lock type is latch bolt
456    Latchbolt = 5,
457    /// Physical lock type is cylindrical lock
458    Cylindricallock = 6,
459    /// Physical lock type is tubular lock
460    Tubularlock = 7,
461    /// Physical lock type is interconnected lock
462    Interconnectedlock = 8,
463    /// Physical lock type is dead latch
464    Deadlatch = 9,
465    /// Physical lock type is door furniture
466    Doorfurniture = 10,
467    /// Physical lock type is euro cylinder
468    Eurocylinder = 11,
469}
470
471impl LockType {
472    /// Convert from u8 value
473    pub fn from_u8(value: u8) -> Option<Self> {
474        match value {
475            0 => Some(LockType::Deadbolt),
476            1 => Some(LockType::Magnetic),
477            2 => Some(LockType::Other),
478            3 => Some(LockType::Mortise),
479            4 => Some(LockType::Rim),
480            5 => Some(LockType::Latchbolt),
481            6 => Some(LockType::Cylindricallock),
482            7 => Some(LockType::Tubularlock),
483            8 => Some(LockType::Interconnectedlock),
484            9 => Some(LockType::Deadlatch),
485            10 => Some(LockType::Doorfurniture),
486            11 => Some(LockType::Eurocylinder),
487            _ => None,
488        }
489    }
490
491    /// Convert to u8 value
492    pub fn to_u8(self) -> u8 {
493        self as u8
494    }
495}
496
497impl From<LockType> for u8 {
498    fn from(val: LockType) -> Self {
499        val as u8
500    }
501}
502
503#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
504#[repr(u8)]
505pub enum OperatingMode {
506    Normal = 0,
507    Vacation = 1,
508    Privacy = 2,
509    Noremotelockunlock = 3,
510    Passage = 4,
511}
512
513impl OperatingMode {
514    /// Convert from u8 value
515    pub fn from_u8(value: u8) -> Option<Self> {
516        match value {
517            0 => Some(OperatingMode::Normal),
518            1 => Some(OperatingMode::Vacation),
519            2 => Some(OperatingMode::Privacy),
520            3 => Some(OperatingMode::Noremotelockunlock),
521            4 => Some(OperatingMode::Passage),
522            _ => None,
523        }
524    }
525
526    /// Convert to u8 value
527    pub fn to_u8(self) -> u8 {
528        self as u8
529    }
530}
531
532impl From<OperatingMode> for u8 {
533    fn from(val: OperatingMode) -> Self {
534        val as u8
535    }
536}
537
538#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
539#[repr(u8)]
540pub enum OperationError {
541    /// Lock/unlock error caused by unknown or unspecified source
542    Unspecified = 0,
543    /// Lock/unlock error caused by invalid PIN, RFID, fingerprint or other credential
544    Invalidcredential = 1,
545    /// Lock/unlock error caused by disabled USER or credential
546    Disableduserdenied = 2,
547    /// Lock/unlock error caused by schedule restriction
548    Restricted = 3,
549    /// Lock/unlock error caused by insufficient battery power left to safely actuate the lock
550    Insufficientbattery = 4,
551}
552
553impl OperationError {
554    /// Convert from u8 value
555    pub fn from_u8(value: u8) -> Option<Self> {
556        match value {
557            0 => Some(OperationError::Unspecified),
558            1 => Some(OperationError::Invalidcredential),
559            2 => Some(OperationError::Disableduserdenied),
560            3 => Some(OperationError::Restricted),
561            4 => Some(OperationError::Insufficientbattery),
562            _ => None,
563        }
564    }
565
566    /// Convert to u8 value
567    pub fn to_u8(self) -> u8 {
568        self as u8
569    }
570}
571
572impl From<OperationError> for u8 {
573    fn from(val: OperationError) -> Self {
574        val as u8
575    }
576}
577
578#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
579#[repr(u8)]
580pub enum OperationSource {
581    /// Lock/unlock operation came from unspecified source
582    Unspecified = 0,
583    /// Lock/unlock operation came from manual operation (key, thumbturn, handle, etc).
584    Manual = 1,
585    /// Lock/unlock operation came from proprietary remote source (e.g. vendor app/cloud)
586    Proprietaryremote = 2,
587    /// Lock/unlock operation came from keypad
588    Keypad = 3,
589    /// Lock/unlock operation came from lock automatically (e.g. relock timer)
590    Auto = 4,
591    /// Lock/unlock operation came from lock button (e.g. one touch or button)
592    Button = 5,
593    /// Lock/unlock operation came from lock due to a schedule
594    Schedule = 6,
595    /// Lock/unlock operation came from remote node
596    Remote = 7,
597    /// Lock/unlock operation came from RFID card
598    Rfid = 8,
599    /// Lock/unlock operation came from biometric source (e.g. face, fingerprint/fingervein)
600    Biometric = 9,
601    /// Lock/unlock operation came from an interaction defined in Aliro, or user change operation was a step-up credential provisioning as defined in Aliro
602    Aliro = 10,
603}
604
605impl OperationSource {
606    /// Convert from u8 value
607    pub fn from_u8(value: u8) -> Option<Self> {
608        match value {
609            0 => Some(OperationSource::Unspecified),
610            1 => Some(OperationSource::Manual),
611            2 => Some(OperationSource::Proprietaryremote),
612            3 => Some(OperationSource::Keypad),
613            4 => Some(OperationSource::Auto),
614            5 => Some(OperationSource::Button),
615            6 => Some(OperationSource::Schedule),
616            7 => Some(OperationSource::Remote),
617            8 => Some(OperationSource::Rfid),
618            9 => Some(OperationSource::Biometric),
619            10 => Some(OperationSource::Aliro),
620            _ => None,
621        }
622    }
623
624    /// Convert to u8 value
625    pub fn to_u8(self) -> u8 {
626        self as u8
627    }
628}
629
630impl From<OperationSource> for u8 {
631    fn from(val: OperationSource) -> Self {
632        val as u8
633    }
634}
635
636#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
637#[repr(u8)]
638pub enum SoundVolume {
639    /// Silent Mode
640    Silent = 0,
641    /// Low Volume
642    Low = 1,
643    /// High Volume
644    High = 2,
645    /// Medium Volume
646    Medium = 3,
647}
648
649impl SoundVolume {
650    /// Convert from u8 value
651    pub fn from_u8(value: u8) -> Option<Self> {
652        match value {
653            0 => Some(SoundVolume::Silent),
654            1 => Some(SoundVolume::Low),
655            2 => Some(SoundVolume::High),
656            3 => Some(SoundVolume::Medium),
657            _ => None,
658        }
659    }
660
661    /// Convert to u8 value
662    pub fn to_u8(self) -> u8 {
663        self as u8
664    }
665}
666
667impl From<SoundVolume> for u8 {
668    fn from(val: SoundVolume) -> Self {
669        val as u8
670    }
671}
672
673#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
674#[repr(u8)]
675pub enum StatusCode {
676    /// Entry would cause a duplicate credential/ID.
677    Duplicate = 2,
678    /// Entry would replace an occupied slot.
679    Occupied = 3,
680}
681
682impl StatusCode {
683    /// Convert from u8 value
684    pub fn from_u8(value: u8) -> Option<Self> {
685        match value {
686            2 => Some(StatusCode::Duplicate),
687            3 => Some(StatusCode::Occupied),
688            _ => None,
689        }
690    }
691
692    /// Convert to u8 value
693    pub fn to_u8(self) -> u8 {
694        self as u8
695    }
696}
697
698impl From<StatusCode> for u8 {
699    fn from(val: StatusCode) -> Self {
700        val as u8
701    }
702}
703
704#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
705#[repr(u8)]
706pub enum UserStatus {
707    /// The user ID is available
708    Available = 0,
709    /// The user ID is occupied and enabled
710    Occupiedenabled = 1,
711    /// The user ID is occupied and disabled
712    Occupieddisabled = 3,
713}
714
715impl UserStatus {
716    /// Convert from u8 value
717    pub fn from_u8(value: u8) -> Option<Self> {
718        match value {
719            0 => Some(UserStatus::Available),
720            1 => Some(UserStatus::Occupiedenabled),
721            3 => Some(UserStatus::Occupieddisabled),
722            _ => None,
723        }
724    }
725
726    /// Convert to u8 value
727    pub fn to_u8(self) -> u8 {
728        self as u8
729    }
730}
731
732impl From<UserStatus> for u8 {
733    fn from(val: UserStatus) -> Self {
734        val as u8
735    }
736}
737
738#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
739#[repr(u8)]
740pub enum UserType {
741    /// The user ID type is unrestricted
742    Unrestricteduser = 0,
743    /// The user ID type is schedule
744    Yeardayscheduleuser = 1,
745    /// The user ID type is schedule
746    Weekdayscheduleuser = 2,
747    /// The user ID type is programming
748    Programminguser = 3,
749    /// The user ID type is non access
750    Nonaccessuser = 4,
751    /// The user ID type is forced
752    Forceduser = 5,
753    /// The user ID type is disposable
754    Disposableuser = 6,
755    /// The user ID type is expiring
756    Expiringuser = 7,
757    /// The user ID type is schedule restricted
758    Schedulerestricteduser = 8,
759    /// The user ID type is remote only
760    Remoteonlyuser = 9,
761}
762
763impl UserType {
764    /// Convert from u8 value
765    pub fn from_u8(value: u8) -> Option<Self> {
766        match value {
767            0 => Some(UserType::Unrestricteduser),
768            1 => Some(UserType::Yeardayscheduleuser),
769            2 => Some(UserType::Weekdayscheduleuser),
770            3 => Some(UserType::Programminguser),
771            4 => Some(UserType::Nonaccessuser),
772            5 => Some(UserType::Forceduser),
773            6 => Some(UserType::Disposableuser),
774            7 => Some(UserType::Expiringuser),
775            8 => Some(UserType::Schedulerestricteduser),
776            9 => Some(UserType::Remoteonlyuser),
777            _ => None,
778        }
779    }
780
781    /// Convert to u8 value
782    pub fn to_u8(self) -> u8 {
783        self as u8
784    }
785}
786
787impl From<UserType> for u8 {
788    fn from(val: UserType) -> Self {
789        val as u8
790    }
791}
792
793// Bitmap definitions
794
795/// AlarmMask bitmap type
796pub type AlarmMask = u8;
797
798/// Constants for AlarmMask
799pub mod alarmmask {
800    /// Locking Mechanism Jammed
801    pub const LOCK_JAMMED: u8 = 0x01;
802    /// Lock Reset to Factory Defaults
803    pub const LOCK_FACTORY_RESET: u8 = 0x02;
804    /// RF Module Power Cycled
805    pub const LOCK_RADIO_POWER_CYCLED: u8 = 0x08;
806    /// Tamper Alarm - wrong code entry limit
807    pub const WRONG_CODE_ENTRY_LIMIT: u8 = 0x10;
808    /// Tamper Alarm - front escutcheon removed from main
809    pub const FRONT_ESCUTCHEON_REMOVED: u8 = 0x20;
810    /// Forced Door Open under Door Locked Condition
811    pub const DOOR_FORCED_OPEN: u8 = 0x40;
812}
813
814/// ConfigurationRegister bitmap type
815pub type ConfigurationRegister = u8;
816
817/// Constants for ConfigurationRegister
818pub mod configurationregister {
819    /// The state of local programming functionality
820    pub const LOCAL_PROGRAMMING: u8 = 0x01;
821    /// The state of the keypad interface
822    pub const KEYPAD_INTERFACE: u8 = 0x02;
823    /// The state of the remote interface
824    pub const REMOTE_INTERFACE: u8 = 0x04;
825    /// Sound volume is set to Silent value
826    pub const SOUND_VOLUME: u8 = 0x20;
827    /// Auto relock time it set to 0
828    pub const AUTO_RELOCK_TIME: u8 = 0x40;
829    /// LEDs is disabled
830    pub const LEDSETTINGS: u8 = 0x80;
831}
832
833/// CredentialRules bitmap type
834pub type CredentialRules = u8;
835
836/// Constants for CredentialRules
837pub mod credentialrules {
838    /// Only one credential is required for lock operation
839    pub const SINGLE: u8 = 0x01;
840    /// Any two credentials are required for lock operation
841    pub const DUAL: u8 = 0x02;
842    /// Any three credentials are required for lock operation
843    pub const TRI: u8 = 0x04;
844}
845
846/// DaysMask bitmap type
847pub type DaysMask = u8;
848
849/// Constants for DaysMask
850pub mod daysmask {
851    /// Schedule is applied on Sunday
852    pub const SUNDAY: u8 = 0x01;
853    /// Schedule is applied on Monday
854    pub const MONDAY: u8 = 0x02;
855    /// Schedule is applied on Tuesday
856    pub const TUESDAY: u8 = 0x04;
857    /// Schedule is applied on Wednesday
858    pub const WEDNESDAY: u8 = 0x08;
859    /// Schedule is applied on Thursday
860    pub const THURSDAY: u8 = 0x10;
861    /// Schedule is applied on Friday
862    pub const FRIDAY: u8 = 0x20;
863    /// Schedule is applied on Saturday
864    pub const SATURDAY: u8 = 0x40;
865}
866
867/// LocalProgrammingFeatures bitmap type
868pub type LocalProgrammingFeatures = u8;
869
870/// Constants for LocalProgrammingFeatures
871pub mod localprogrammingfeatures {
872    /// The state of the ability to add users, credentials or schedules on the device
873    pub const ADD_USERS_CREDENTIALS_SCHEDULES: u8 = 0x01;
874    /// The state of the ability to modify users, credentials or schedules on the device
875    pub const MODIFY_USERS_CREDENTIALS_SCHEDULES: u8 = 0x02;
876    /// The state of the ability to clear users, credentials or schedules on the device
877    pub const CLEAR_USERS_CREDENTIALS_SCHEDULES: u8 = 0x04;
878    /// The state of the ability to adjust settings on the device
879    pub const ADJUST_SETTINGS: u8 = 0x08;
880}
881
882/// OperatingModes bitmap type
883pub type OperatingModes = u8;
884
885/// Constants for OperatingModes
886pub mod operatingmodes {
887    /// Normal operation mode
888    pub const NORMAL: u8 = 0x01;
889    /// Vacation operation mode
890    pub const VACATION: u8 = 0x02;
891    /// Privacy operation mode
892    pub const PRIVACY: u8 = 0x04;
893    /// No remote lock and unlock operation mode
894    pub const NO_REMOTE_LOCK_UNLOCK: u8 = 0x08;
895    /// Passage operation mode
896    pub const PASSAGE: u8 = 0x10;
897}
898
899// Struct definitions
900
901#[derive(Debug, serde::Serialize)]
902pub struct Credential {
903    pub credential_type: Option<CredentialType>,
904    pub credential_index: Option<u16>,
905}
906
907// Command encoders
908
909/// Encode LockDoor command (0x00)
910pub fn encode_lock_door(pin_code: Vec<u8>) -> anyhow::Result<Vec<u8>> {
911    let tlv = tlv::TlvItemEnc {
912        tag: 0,
913        value: tlv::TlvItemValueEnc::StructInvisible(vec![
914        (0, tlv::TlvItemValueEnc::OctetString(pin_code)).into(),
915        ]),
916    };
917    Ok(tlv.encode()?)
918}
919
920/// Encode UnlockDoor command (0x01)
921pub fn encode_unlock_door(pin_code: Vec<u8>) -> anyhow::Result<Vec<u8>> {
922    let tlv = tlv::TlvItemEnc {
923        tag: 0,
924        value: tlv::TlvItemValueEnc::StructInvisible(vec![
925        (0, tlv::TlvItemValueEnc::OctetString(pin_code)).into(),
926        ]),
927    };
928    Ok(tlv.encode()?)
929}
930
931/// Encode UnlockWithTimeout command (0x03)
932pub fn encode_unlock_with_timeout(timeout: u16, pin_code: Vec<u8>) -> anyhow::Result<Vec<u8>> {
933    let tlv = tlv::TlvItemEnc {
934        tag: 0,
935        value: tlv::TlvItemValueEnc::StructInvisible(vec![
936        (0, tlv::TlvItemValueEnc::UInt16(timeout)).into(),
937        (1, tlv::TlvItemValueEnc::OctetString(pin_code)).into(),
938        ]),
939    };
940    Ok(tlv.encode()?)
941}
942
943/// Encode SetWeekDaySchedule command (0x0B)
944pub fn encode_set_week_day_schedule(week_day_index: u8, user_index: u16, days_mask: DaysMask, start_hour: u8, start_minute: u8, end_hour: u8, end_minute: u8) -> anyhow::Result<Vec<u8>> {
945    let tlv = tlv::TlvItemEnc {
946        tag: 0,
947        value: tlv::TlvItemValueEnc::StructInvisible(vec![
948        (0, tlv::TlvItemValueEnc::UInt8(week_day_index)).into(),
949        (1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
950        (2, tlv::TlvItemValueEnc::UInt8(days_mask)).into(),
951        (3, tlv::TlvItemValueEnc::UInt8(start_hour)).into(),
952        (4, tlv::TlvItemValueEnc::UInt8(start_minute)).into(),
953        (5, tlv::TlvItemValueEnc::UInt8(end_hour)).into(),
954        (6, tlv::TlvItemValueEnc::UInt8(end_minute)).into(),
955        ]),
956    };
957    Ok(tlv.encode()?)
958}
959
960/// Encode GetWeekDaySchedule command (0x0C)
961pub fn encode_get_week_day_schedule(week_day_index: u8, user_index: u16) -> anyhow::Result<Vec<u8>> {
962    let tlv = tlv::TlvItemEnc {
963        tag: 0,
964        value: tlv::TlvItemValueEnc::StructInvisible(vec![
965        (0, tlv::TlvItemValueEnc::UInt8(week_day_index)).into(),
966        (1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
967        ]),
968    };
969    Ok(tlv.encode()?)
970}
971
972/// Encode ClearWeekDaySchedule command (0x0D)
973pub fn encode_clear_week_day_schedule(week_day_index: u8, user_index: u16) -> anyhow::Result<Vec<u8>> {
974    let tlv = tlv::TlvItemEnc {
975        tag: 0,
976        value: tlv::TlvItemValueEnc::StructInvisible(vec![
977        (0, tlv::TlvItemValueEnc::UInt8(week_day_index)).into(),
978        (1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
979        ]),
980    };
981    Ok(tlv.encode()?)
982}
983
984/// Encode SetYearDaySchedule command (0x0E)
985pub fn encode_set_year_day_schedule(year_day_index: u8, user_index: u16, local_start_time: u64, local_end_time: u64) -> anyhow::Result<Vec<u8>> {
986    let tlv = tlv::TlvItemEnc {
987        tag: 0,
988        value: tlv::TlvItemValueEnc::StructInvisible(vec![
989        (0, tlv::TlvItemValueEnc::UInt8(year_day_index)).into(),
990        (1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
991        (2, tlv::TlvItemValueEnc::UInt64(local_start_time)).into(),
992        (3, tlv::TlvItemValueEnc::UInt64(local_end_time)).into(),
993        ]),
994    };
995    Ok(tlv.encode()?)
996}
997
998/// Encode GetYearDaySchedule command (0x0F)
999pub fn encode_get_year_day_schedule(year_day_index: u8, user_index: u16) -> anyhow::Result<Vec<u8>> {
1000    let tlv = tlv::TlvItemEnc {
1001        tag: 0,
1002        value: tlv::TlvItemValueEnc::StructInvisible(vec![
1003        (0, tlv::TlvItemValueEnc::UInt8(year_day_index)).into(),
1004        (1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
1005        ]),
1006    };
1007    Ok(tlv.encode()?)
1008}
1009
1010/// Encode ClearYearDaySchedule command (0x10)
1011pub fn encode_clear_year_day_schedule(year_day_index: u8, user_index: u16) -> anyhow::Result<Vec<u8>> {
1012    let tlv = tlv::TlvItemEnc {
1013        tag: 0,
1014        value: tlv::TlvItemValueEnc::StructInvisible(vec![
1015        (0, tlv::TlvItemValueEnc::UInt8(year_day_index)).into(),
1016        (1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
1017        ]),
1018    };
1019    Ok(tlv.encode()?)
1020}
1021
1022/// Encode SetHolidaySchedule command (0x11)
1023pub fn encode_set_holiday_schedule(holiday_index: u8, local_start_time: u64, local_end_time: u64, operating_mode: OperatingMode) -> anyhow::Result<Vec<u8>> {
1024    let tlv = tlv::TlvItemEnc {
1025        tag: 0,
1026        value: tlv::TlvItemValueEnc::StructInvisible(vec![
1027        (0, tlv::TlvItemValueEnc::UInt8(holiday_index)).into(),
1028        (1, tlv::TlvItemValueEnc::UInt64(local_start_time)).into(),
1029        (2, tlv::TlvItemValueEnc::UInt64(local_end_time)).into(),
1030        (3, tlv::TlvItemValueEnc::UInt8(operating_mode.to_u8())).into(),
1031        ]),
1032    };
1033    Ok(tlv.encode()?)
1034}
1035
1036/// Encode GetHolidaySchedule command (0x12)
1037pub fn encode_get_holiday_schedule(holiday_index: u8) -> anyhow::Result<Vec<u8>> {
1038    let tlv = tlv::TlvItemEnc {
1039        tag: 0,
1040        value: tlv::TlvItemValueEnc::StructInvisible(vec![
1041        (0, tlv::TlvItemValueEnc::UInt8(holiday_index)).into(),
1042        ]),
1043    };
1044    Ok(tlv.encode()?)
1045}
1046
1047/// Encode ClearHolidaySchedule command (0x13)
1048pub fn encode_clear_holiday_schedule(holiday_index: u8) -> anyhow::Result<Vec<u8>> {
1049    let tlv = tlv::TlvItemEnc {
1050        tag: 0,
1051        value: tlv::TlvItemValueEnc::StructInvisible(vec![
1052        (0, tlv::TlvItemValueEnc::UInt8(holiday_index)).into(),
1053        ]),
1054    };
1055    Ok(tlv.encode()?)
1056}
1057
1058/// Encode SetUser command (0x1A)
1059pub fn encode_set_user(operation_type: DataOperationType, user_index: u16, user_name: Option<String>, user_unique_id: Option<u32>, user_status: Option<UserStatus>, user_type: Option<UserType>, credential_rule: Option<CredentialRule>) -> anyhow::Result<Vec<u8>> {
1060    let tlv = tlv::TlvItemEnc {
1061        tag: 0,
1062        value: tlv::TlvItemValueEnc::StructInvisible(vec![
1063        (0, tlv::TlvItemValueEnc::UInt8(operation_type.to_u8())).into(),
1064        (1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
1065        (2, tlv::TlvItemValueEnc::String(user_name.unwrap_or("".to_string()))).into(),
1066        (3, tlv::TlvItemValueEnc::UInt32(user_unique_id.unwrap_or(0))).into(),
1067        (4, tlv::TlvItemValueEnc::UInt8(user_status.map(|e| e.to_u8()).unwrap_or(0))).into(),
1068        (5, tlv::TlvItemValueEnc::UInt8(user_type.map(|e| e.to_u8()).unwrap_or(0))).into(),
1069        (6, tlv::TlvItemValueEnc::UInt8(credential_rule.map(|e| e.to_u8()).unwrap_or(0))).into(),
1070        ]),
1071    };
1072    Ok(tlv.encode()?)
1073}
1074
1075/// Encode GetUser command (0x1B)
1076pub fn encode_get_user(user_index: u16) -> anyhow::Result<Vec<u8>> {
1077    let tlv = tlv::TlvItemEnc {
1078        tag: 0,
1079        value: tlv::TlvItemValueEnc::StructInvisible(vec![
1080        (0, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
1081        ]),
1082    };
1083    Ok(tlv.encode()?)
1084}
1085
1086/// Encode ClearUser command (0x1D)
1087pub fn encode_clear_user(user_index: u16) -> anyhow::Result<Vec<u8>> {
1088    let tlv = tlv::TlvItemEnc {
1089        tag: 0,
1090        value: tlv::TlvItemValueEnc::StructInvisible(vec![
1091        (0, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
1092        ]),
1093    };
1094    Ok(tlv.encode()?)
1095}
1096
1097/// Encode SetCredential command (0x22)
1098pub fn encode_set_credential(operation_type: DataOperationType, credential: Credential, credential_data: Vec<u8>, user_index: Option<u16>, user_status: Option<UserStatus>, user_type: Option<UserType>) -> anyhow::Result<Vec<u8>> {
1099            // Encode struct CredentialStruct
1100            let mut credential_fields = Vec::new();
1101            if let Some(x) = credential.credential_type { credential_fields.push((0, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
1102            if let Some(x) = credential.credential_index { credential_fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
1103    let tlv = tlv::TlvItemEnc {
1104        tag: 0,
1105        value: tlv::TlvItemValueEnc::StructInvisible(vec![
1106        (0, tlv::TlvItemValueEnc::UInt8(operation_type.to_u8())).into(),
1107        (1, tlv::TlvItemValueEnc::StructInvisible(credential_fields)).into(),
1108        (2, tlv::TlvItemValueEnc::OctetString(credential_data)).into(),
1109        (3, tlv::TlvItemValueEnc::UInt16(user_index.unwrap_or(0))).into(),
1110        (4, tlv::TlvItemValueEnc::UInt8(user_status.map(|e| e.to_u8()).unwrap_or(0))).into(),
1111        (5, tlv::TlvItemValueEnc::UInt8(user_type.map(|e| e.to_u8()).unwrap_or(0))).into(),
1112        ]),
1113    };
1114    Ok(tlv.encode()?)
1115}
1116
1117/// Encode GetCredentialStatus command (0x24)
1118pub fn encode_get_credential_status(credential: Credential) -> anyhow::Result<Vec<u8>> {
1119            // Encode struct CredentialStruct
1120            let mut credential_fields = Vec::new();
1121            if let Some(x) = credential.credential_type { credential_fields.push((0, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
1122            if let Some(x) = credential.credential_index { credential_fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
1123    let tlv = tlv::TlvItemEnc {
1124        tag: 0,
1125        value: tlv::TlvItemValueEnc::StructInvisible(vec![
1126        (0, tlv::TlvItemValueEnc::StructInvisible(credential_fields)).into(),
1127        ]),
1128    };
1129    Ok(tlv.encode()?)
1130}
1131
1132/// Encode ClearCredential command (0x26)
1133pub fn encode_clear_credential(credential: Option<Credential>) -> anyhow::Result<Vec<u8>> {
1134            // Encode optional struct CredentialStruct
1135            let credential_enc = if let Some(s) = credential {
1136                let mut fields = Vec::new();
1137                if let Some(x) = s.credential_type { fields.push((0, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
1138                if let Some(x) = s.credential_index { fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
1139                tlv::TlvItemValueEnc::StructInvisible(fields)
1140            } else {
1141                tlv::TlvItemValueEnc::StructInvisible(Vec::new())
1142            };
1143    let tlv = tlv::TlvItemEnc {
1144        tag: 0,
1145        value: tlv::TlvItemValueEnc::StructInvisible(vec![
1146        (0, credential_enc).into(),
1147        ]),
1148    };
1149    Ok(tlv.encode()?)
1150}
1151
1152/// Encode UnboltDoor command (0x27)
1153pub fn encode_unbolt_door(pin_code: Vec<u8>) -> anyhow::Result<Vec<u8>> {
1154    let tlv = tlv::TlvItemEnc {
1155        tag: 0,
1156        value: tlv::TlvItemValueEnc::StructInvisible(vec![
1157        (0, tlv::TlvItemValueEnc::OctetString(pin_code)).into(),
1158        ]),
1159    };
1160    Ok(tlv.encode()?)
1161}
1162
1163/// Encode SetAliroReaderConfig command (0x28)
1164pub fn encode_set_aliro_reader_config(signing_key: Vec<u8>, verification_key: Vec<u8>, group_identifier: Vec<u8>, group_resolving_key: Vec<u8>) -> anyhow::Result<Vec<u8>> {
1165    let tlv = tlv::TlvItemEnc {
1166        tag: 0,
1167        value: tlv::TlvItemValueEnc::StructInvisible(vec![
1168        (0, tlv::TlvItemValueEnc::OctetString(signing_key)).into(),
1169        (1, tlv::TlvItemValueEnc::OctetString(verification_key)).into(),
1170        (2, tlv::TlvItemValueEnc::OctetString(group_identifier)).into(),
1171        (3, tlv::TlvItemValueEnc::OctetString(group_resolving_key)).into(),
1172        ]),
1173    };
1174    Ok(tlv.encode()?)
1175}
1176
1177// Attribute decoders
1178
1179/// Decode LockState attribute (0x0000)
1180pub fn decode_lock_state(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<LockState>> {
1181    if let tlv::TlvItemValue::Int(v) = inp {
1182        Ok(LockState::from_u8(*v as u8))
1183    } else {
1184        Ok(None)
1185    }
1186}
1187
1188/// Decode LockType attribute (0x0001)
1189pub fn decode_lock_type(inp: &tlv::TlvItemValue) -> anyhow::Result<LockType> {
1190    if let tlv::TlvItemValue::Int(v) = inp {
1191        LockType::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
1192    } else {
1193        Err(anyhow::anyhow!("Expected Integer"))
1194    }
1195}
1196
1197/// Decode ActuatorEnabled attribute (0x0002)
1198pub fn decode_actuator_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
1199    if let tlv::TlvItemValue::Bool(v) = inp {
1200        Ok(*v)
1201    } else {
1202        Err(anyhow::anyhow!("Expected Bool"))
1203    }
1204}
1205
1206/// Decode DoorState attribute (0x0003)
1207pub fn decode_door_state(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<DoorState>> {
1208    if let tlv::TlvItemValue::Int(v) = inp {
1209        Ok(DoorState::from_u8(*v as u8))
1210    } else {
1211        Ok(None)
1212    }
1213}
1214
1215/// Decode DoorOpenEvents attribute (0x0004)
1216pub fn decode_door_open_events(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
1217    if let tlv::TlvItemValue::Int(v) = inp {
1218        Ok(*v as u32)
1219    } else {
1220        Err(anyhow::anyhow!("Expected UInt32"))
1221    }
1222}
1223
1224/// Decode DoorClosedEvents attribute (0x0005)
1225pub fn decode_door_closed_events(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
1226    if let tlv::TlvItemValue::Int(v) = inp {
1227        Ok(*v as u32)
1228    } else {
1229        Err(anyhow::anyhow!("Expected UInt32"))
1230    }
1231}
1232
1233/// Decode OpenPeriod attribute (0x0006)
1234pub fn decode_open_period(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
1235    if let tlv::TlvItemValue::Int(v) = inp {
1236        Ok(*v as u16)
1237    } else {
1238        Err(anyhow::anyhow!("Expected UInt16"))
1239    }
1240}
1241
1242/// Decode NumberOfTotalUsersSupported attribute (0x0011)
1243pub fn decode_number_of_total_users_supported(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
1244    if let tlv::TlvItemValue::Int(v) = inp {
1245        Ok(*v as u16)
1246    } else {
1247        Err(anyhow::anyhow!("Expected UInt16"))
1248    }
1249}
1250
1251/// Decode NumberOfPINUsersSupported attribute (0x0012)
1252pub fn decode_number_of_pin_users_supported(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
1253    if let tlv::TlvItemValue::Int(v) = inp {
1254        Ok(*v as u16)
1255    } else {
1256        Err(anyhow::anyhow!("Expected UInt16"))
1257    }
1258}
1259
1260/// Decode NumberOfRFIDUsersSupported attribute (0x0013)
1261pub fn decode_number_of_rfid_users_supported(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
1262    if let tlv::TlvItemValue::Int(v) = inp {
1263        Ok(*v as u16)
1264    } else {
1265        Err(anyhow::anyhow!("Expected UInt16"))
1266    }
1267}
1268
1269/// Decode NumberOfWeekDaySchedulesSupportedPerUser attribute (0x0014)
1270pub fn decode_number_of_week_day_schedules_supported_per_user(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1271    if let tlv::TlvItemValue::Int(v) = inp {
1272        Ok(*v as u8)
1273    } else {
1274        Err(anyhow::anyhow!("Expected UInt8"))
1275    }
1276}
1277
1278/// Decode NumberOfYearDaySchedulesSupportedPerUser attribute (0x0015)
1279pub fn decode_number_of_year_day_schedules_supported_per_user(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1280    if let tlv::TlvItemValue::Int(v) = inp {
1281        Ok(*v as u8)
1282    } else {
1283        Err(anyhow::anyhow!("Expected UInt8"))
1284    }
1285}
1286
1287/// Decode NumberOfHolidaySchedulesSupported attribute (0x0016)
1288pub fn decode_number_of_holiday_schedules_supported(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1289    if let tlv::TlvItemValue::Int(v) = inp {
1290        Ok(*v as u8)
1291    } else {
1292        Err(anyhow::anyhow!("Expected UInt8"))
1293    }
1294}
1295
1296/// Decode MaxPINCodeLength attribute (0x0017)
1297pub fn decode_max_pin_code_length(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1298    if let tlv::TlvItemValue::Int(v) = inp {
1299        Ok(*v as u8)
1300    } else {
1301        Err(anyhow::anyhow!("Expected UInt8"))
1302    }
1303}
1304
1305/// Decode MinPINCodeLength attribute (0x0018)
1306pub fn decode_min_pin_code_length(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1307    if let tlv::TlvItemValue::Int(v) = inp {
1308        Ok(*v as u8)
1309    } else {
1310        Err(anyhow::anyhow!("Expected UInt8"))
1311    }
1312}
1313
1314/// Decode MaxRFIDCodeLength attribute (0x0019)
1315pub fn decode_max_rfid_code_length(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1316    if let tlv::TlvItemValue::Int(v) = inp {
1317        Ok(*v as u8)
1318    } else {
1319        Err(anyhow::anyhow!("Expected UInt8"))
1320    }
1321}
1322
1323/// Decode MinRFIDCodeLength attribute (0x001A)
1324pub fn decode_min_rfid_code_length(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1325    if let tlv::TlvItemValue::Int(v) = inp {
1326        Ok(*v as u8)
1327    } else {
1328        Err(anyhow::anyhow!("Expected UInt8"))
1329    }
1330}
1331
1332/// Decode CredentialRulesSupport attribute (0x001B)
1333pub fn decode_credential_rules_support(inp: &tlv::TlvItemValue) -> anyhow::Result<CredentialRules> {
1334    if let tlv::TlvItemValue::Int(v) = inp {
1335        Ok(*v as u8)
1336    } else {
1337        Err(anyhow::anyhow!("Expected Integer"))
1338    }
1339}
1340
1341/// Decode NumberOfCredentialsSupportedPerUser attribute (0x001C)
1342pub fn decode_number_of_credentials_supported_per_user(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1343    if let tlv::TlvItemValue::Int(v) = inp {
1344        Ok(*v as u8)
1345    } else {
1346        Err(anyhow::anyhow!("Expected UInt8"))
1347    }
1348}
1349
1350/// Decode Language attribute (0x0021)
1351pub fn decode_language(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
1352    if let tlv::TlvItemValue::String(v) = inp {
1353        Ok(v.clone())
1354    } else {
1355        Err(anyhow::anyhow!("Expected String"))
1356    }
1357}
1358
1359/// Decode LEDSettings attribute (0x0022)
1360pub fn decode_led_settings(inp: &tlv::TlvItemValue) -> anyhow::Result<LEDSetting> {
1361    if let tlv::TlvItemValue::Int(v) = inp {
1362        LEDSetting::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
1363    } else {
1364        Err(anyhow::anyhow!("Expected Integer"))
1365    }
1366}
1367
1368/// Decode AutoRelockTime attribute (0x0023)
1369pub fn decode_auto_relock_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
1370    if let tlv::TlvItemValue::Int(v) = inp {
1371        Ok(*v as u32)
1372    } else {
1373        Err(anyhow::anyhow!("Expected UInt32"))
1374    }
1375}
1376
1377/// Decode SoundVolume attribute (0x0024)
1378pub fn decode_sound_volume(inp: &tlv::TlvItemValue) -> anyhow::Result<SoundVolume> {
1379    if let tlv::TlvItemValue::Int(v) = inp {
1380        SoundVolume::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
1381    } else {
1382        Err(anyhow::anyhow!("Expected Integer"))
1383    }
1384}
1385
1386/// Decode OperatingMode attribute (0x0025)
1387pub fn decode_operating_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<OperatingMode> {
1388    if let tlv::TlvItemValue::Int(v) = inp {
1389        OperatingMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
1390    } else {
1391        Err(anyhow::anyhow!("Expected Integer"))
1392    }
1393}
1394
1395/// Decode SupportedOperatingModes attribute (0x0026)
1396pub fn decode_supported_operating_modes(inp: &tlv::TlvItemValue) -> anyhow::Result<OperatingModes> {
1397    if let tlv::TlvItemValue::Int(v) = inp {
1398        Ok(*v as u8)
1399    } else {
1400        Err(anyhow::anyhow!("Expected Integer"))
1401    }
1402}
1403
1404/// Decode DefaultConfigurationRegister attribute (0x0027)
1405pub fn decode_default_configuration_register(inp: &tlv::TlvItemValue) -> anyhow::Result<ConfigurationRegister> {
1406    if let tlv::TlvItemValue::Int(v) = inp {
1407        Ok(*v as u8)
1408    } else {
1409        Err(anyhow::anyhow!("Expected Integer"))
1410    }
1411}
1412
1413/// Decode EnableLocalProgramming attribute (0x0028)
1414pub fn decode_enable_local_programming(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
1415    if let tlv::TlvItemValue::Bool(v) = inp {
1416        Ok(*v)
1417    } else {
1418        Err(anyhow::anyhow!("Expected Bool"))
1419    }
1420}
1421
1422/// Decode EnableOneTouchLocking attribute (0x0029)
1423pub fn decode_enable_one_touch_locking(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
1424    if let tlv::TlvItemValue::Bool(v) = inp {
1425        Ok(*v)
1426    } else {
1427        Err(anyhow::anyhow!("Expected Bool"))
1428    }
1429}
1430
1431/// Decode EnableInsideStatusLED attribute (0x002A)
1432pub fn decode_enable_inside_status_led(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
1433    if let tlv::TlvItemValue::Bool(v) = inp {
1434        Ok(*v)
1435    } else {
1436        Err(anyhow::anyhow!("Expected Bool"))
1437    }
1438}
1439
1440/// Decode EnablePrivacyModeButton attribute (0x002B)
1441pub fn decode_enable_privacy_mode_button(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
1442    if let tlv::TlvItemValue::Bool(v) = inp {
1443        Ok(*v)
1444    } else {
1445        Err(anyhow::anyhow!("Expected Bool"))
1446    }
1447}
1448
1449/// Decode LocalProgrammingFeatures attribute (0x002C)
1450pub fn decode_local_programming_features(inp: &tlv::TlvItemValue) -> anyhow::Result<LocalProgrammingFeatures> {
1451    if let tlv::TlvItemValue::Int(v) = inp {
1452        Ok(*v as u8)
1453    } else {
1454        Err(anyhow::anyhow!("Expected Integer"))
1455    }
1456}
1457
1458/// Decode WrongCodeEntryLimit attribute (0x0030)
1459pub fn decode_wrong_code_entry_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1460    if let tlv::TlvItemValue::Int(v) = inp {
1461        Ok(*v as u8)
1462    } else {
1463        Err(anyhow::anyhow!("Expected UInt8"))
1464    }
1465}
1466
1467/// Decode UserCodeTemporaryDisableTime attribute (0x0031)
1468pub fn decode_user_code_temporary_disable_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1469    if let tlv::TlvItemValue::Int(v) = inp {
1470        Ok(*v as u8)
1471    } else {
1472        Err(anyhow::anyhow!("Expected UInt8"))
1473    }
1474}
1475
1476/// Decode SendPINOverTheAir attribute (0x0032)
1477pub fn decode_send_pin_over_the_air(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
1478    if let tlv::TlvItemValue::Bool(v) = inp {
1479        Ok(*v)
1480    } else {
1481        Err(anyhow::anyhow!("Expected Bool"))
1482    }
1483}
1484
1485/// Decode RequirePINforRemoteOperation attribute (0x0033)
1486pub fn decode_require_pinfor_remote_operation(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
1487    if let tlv::TlvItemValue::Bool(v) = inp {
1488        Ok(*v)
1489    } else {
1490        Err(anyhow::anyhow!("Expected Bool"))
1491    }
1492}
1493
1494/// Decode SecurityLevel attribute (0x0034)
1495pub fn decode_security_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1496    if let tlv::TlvItemValue::Int(v) = inp {
1497        Ok(*v as u8)
1498    } else {
1499        Err(anyhow::anyhow!("Expected UInt8"))
1500    }
1501}
1502
1503/// Decode ExpiringUserTimeout attribute (0x0035)
1504pub fn decode_expiring_user_timeout(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
1505    if let tlv::TlvItemValue::Int(v) = inp {
1506        Ok(*v as u16)
1507    } else {
1508        Err(anyhow::anyhow!("Expected UInt16"))
1509    }
1510}
1511
1512/// Decode AliroReaderVerificationKey attribute (0x0080)
1513pub fn decode_aliro_reader_verification_key(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
1514    if let tlv::TlvItemValue::OctetString(v) = inp {
1515        Ok(Some(v.clone()))
1516    } else {
1517        Ok(None)
1518    }
1519}
1520
1521/// Decode AliroReaderGroupIdentifier attribute (0x0081)
1522pub fn decode_aliro_reader_group_identifier(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
1523    if let tlv::TlvItemValue::OctetString(v) = inp {
1524        Ok(Some(v.clone()))
1525    } else {
1526        Ok(None)
1527    }
1528}
1529
1530/// Decode AliroReaderGroupSubIdentifier attribute (0x0082)
1531pub fn decode_aliro_reader_group_sub_identifier(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<u8>> {
1532    if let tlv::TlvItemValue::OctetString(v) = inp {
1533        Ok(v.clone())
1534    } else {
1535        Err(anyhow::anyhow!("Expected OctetString"))
1536    }
1537}
1538
1539/// Decode AliroExpeditedTransactionSupportedProtocolVersions attribute (0x0083)
1540pub fn decode_aliro_expedited_transaction_supported_protocol_versions(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Vec<u8>>> {
1541    let mut res = Vec::new();
1542    if let tlv::TlvItemValue::List(v) = inp {
1543        for item in v {
1544            if let tlv::TlvItemValue::OctetString(o) = &item.value {
1545                res.push(o.clone());
1546            }
1547        }
1548    }
1549    Ok(res)
1550}
1551
1552/// Decode AliroGroupResolvingKey attribute (0x0084)
1553pub fn decode_aliro_group_resolving_key(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
1554    if let tlv::TlvItemValue::OctetString(v) = inp {
1555        Ok(Some(v.clone()))
1556    } else {
1557        Ok(None)
1558    }
1559}
1560
1561/// Decode AliroSupportedBLEUWBProtocolVersions attribute (0x0085)
1562pub fn decode_aliro_supported_bleuwb_protocol_versions(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Vec<u8>>> {
1563    let mut res = Vec::new();
1564    if let tlv::TlvItemValue::List(v) = inp {
1565        for item in v {
1566            if let tlv::TlvItemValue::OctetString(o) = &item.value {
1567                res.push(o.clone());
1568            }
1569        }
1570    }
1571    Ok(res)
1572}
1573
1574/// Decode AliroBLEAdvertisingVersion attribute (0x0086)
1575pub fn decode_aliro_ble_advertising_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1576    if let tlv::TlvItemValue::Int(v) = inp {
1577        Ok(*v as u8)
1578    } else {
1579        Err(anyhow::anyhow!("Expected UInt8"))
1580    }
1581}
1582
1583/// Decode NumberOfAliroCredentialIssuerKeysSupported attribute (0x0087)
1584pub fn decode_number_of_aliro_credential_issuer_keys_supported(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
1585    if let tlv::TlvItemValue::Int(v) = inp {
1586        Ok(*v as u16)
1587    } else {
1588        Err(anyhow::anyhow!("Expected UInt16"))
1589    }
1590}
1591
1592/// Decode NumberOfAliroEndpointKeysSupported attribute (0x0088)
1593pub fn decode_number_of_aliro_endpoint_keys_supported(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
1594    if let tlv::TlvItemValue::Int(v) = inp {
1595        Ok(*v as u16)
1596    } else {
1597        Err(anyhow::anyhow!("Expected UInt16"))
1598    }
1599}
1600
1601
1602// JSON dispatcher function
1603
1604/// Decode attribute value and return as JSON string
1605///
1606/// # Parameters
1607/// * `cluster_id` - The cluster identifier
1608/// * `attribute_id` - The attribute identifier
1609/// * `tlv_value` - The TLV value to decode
1610///
1611/// # Returns
1612/// JSON string representation of the decoded value or error
1613pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
1614    // Verify this is the correct cluster
1615    if cluster_id != 0x0101 {
1616        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0101, got {}\"}}", cluster_id);
1617    }
1618
1619    match attribute_id {
1620        0x0000 => {
1621            match decode_lock_state(tlv_value) {
1622                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1623                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1624            }
1625        }
1626        0x0001 => {
1627            match decode_lock_type(tlv_value) {
1628                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1629                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1630            }
1631        }
1632        0x0002 => {
1633            match decode_actuator_enabled(tlv_value) {
1634                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1635                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1636            }
1637        }
1638        0x0003 => {
1639            match decode_door_state(tlv_value) {
1640                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1641                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1642            }
1643        }
1644        0x0004 => {
1645            match decode_door_open_events(tlv_value) {
1646                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1647                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1648            }
1649        }
1650        0x0005 => {
1651            match decode_door_closed_events(tlv_value) {
1652                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1653                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1654            }
1655        }
1656        0x0006 => {
1657            match decode_open_period(tlv_value) {
1658                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1659                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1660            }
1661        }
1662        0x0011 => {
1663            match decode_number_of_total_users_supported(tlv_value) {
1664                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1665                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1666            }
1667        }
1668        0x0012 => {
1669            match decode_number_of_pin_users_supported(tlv_value) {
1670                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1671                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1672            }
1673        }
1674        0x0013 => {
1675            match decode_number_of_rfid_users_supported(tlv_value) {
1676                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1677                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1678            }
1679        }
1680        0x0014 => {
1681            match decode_number_of_week_day_schedules_supported_per_user(tlv_value) {
1682                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1683                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1684            }
1685        }
1686        0x0015 => {
1687            match decode_number_of_year_day_schedules_supported_per_user(tlv_value) {
1688                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1689                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1690            }
1691        }
1692        0x0016 => {
1693            match decode_number_of_holiday_schedules_supported(tlv_value) {
1694                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1695                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1696            }
1697        }
1698        0x0017 => {
1699            match decode_max_pin_code_length(tlv_value) {
1700                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1701                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1702            }
1703        }
1704        0x0018 => {
1705            match decode_min_pin_code_length(tlv_value) {
1706                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1707                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1708            }
1709        }
1710        0x0019 => {
1711            match decode_max_rfid_code_length(tlv_value) {
1712                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1713                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1714            }
1715        }
1716        0x001A => {
1717            match decode_min_rfid_code_length(tlv_value) {
1718                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1719                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1720            }
1721        }
1722        0x001B => {
1723            match decode_credential_rules_support(tlv_value) {
1724                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1725                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1726            }
1727        }
1728        0x001C => {
1729            match decode_number_of_credentials_supported_per_user(tlv_value) {
1730                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1731                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1732            }
1733        }
1734        0x0021 => {
1735            match decode_language(tlv_value) {
1736                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1737                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1738            }
1739        }
1740        0x0022 => {
1741            match decode_led_settings(tlv_value) {
1742                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1743                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1744            }
1745        }
1746        0x0023 => {
1747            match decode_auto_relock_time(tlv_value) {
1748                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1749                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1750            }
1751        }
1752        0x0024 => {
1753            match decode_sound_volume(tlv_value) {
1754                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1755                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1756            }
1757        }
1758        0x0025 => {
1759            match decode_operating_mode(tlv_value) {
1760                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1761                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1762            }
1763        }
1764        0x0026 => {
1765            match decode_supported_operating_modes(tlv_value) {
1766                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1767                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1768            }
1769        }
1770        0x0027 => {
1771            match decode_default_configuration_register(tlv_value) {
1772                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1773                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1774            }
1775        }
1776        0x0028 => {
1777            match decode_enable_local_programming(tlv_value) {
1778                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1779                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1780            }
1781        }
1782        0x0029 => {
1783            match decode_enable_one_touch_locking(tlv_value) {
1784                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1785                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1786            }
1787        }
1788        0x002A => {
1789            match decode_enable_inside_status_led(tlv_value) {
1790                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1791                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1792            }
1793        }
1794        0x002B => {
1795            match decode_enable_privacy_mode_button(tlv_value) {
1796                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1797                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1798            }
1799        }
1800        0x002C => {
1801            match decode_local_programming_features(tlv_value) {
1802                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1803                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1804            }
1805        }
1806        0x0030 => {
1807            match decode_wrong_code_entry_limit(tlv_value) {
1808                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1809                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1810            }
1811        }
1812        0x0031 => {
1813            match decode_user_code_temporary_disable_time(tlv_value) {
1814                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1815                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1816            }
1817        }
1818        0x0032 => {
1819            match decode_send_pin_over_the_air(tlv_value) {
1820                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1821                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1822            }
1823        }
1824        0x0033 => {
1825            match decode_require_pinfor_remote_operation(tlv_value) {
1826                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1827                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1828            }
1829        }
1830        0x0034 => {
1831            match decode_security_level(tlv_value) {
1832                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1833                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1834            }
1835        }
1836        0x0035 => {
1837            match decode_expiring_user_timeout(tlv_value) {
1838                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1839                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1840            }
1841        }
1842        0x0080 => {
1843            match decode_aliro_reader_verification_key(tlv_value) {
1844                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1845                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1846            }
1847        }
1848        0x0081 => {
1849            match decode_aliro_reader_group_identifier(tlv_value) {
1850                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1851                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1852            }
1853        }
1854        0x0082 => {
1855            match decode_aliro_reader_group_sub_identifier(tlv_value) {
1856                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1857                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1858            }
1859        }
1860        0x0083 => {
1861            match decode_aliro_expedited_transaction_supported_protocol_versions(tlv_value) {
1862                Ok(value) => {
1863                    // Serialize Vec<Vec<u8>> as array of hex strings
1864                    let hex_array: Vec<String> = value.iter()
1865                        .map(|bytes| bytes.iter()
1866                            .map(|byte| format!("{:02x}", byte))
1867                            .collect::<String>())
1868                        .collect();
1869                    serde_json::to_string(&hex_array).unwrap_or_else(|_| "null".to_string())
1870                },
1871                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1872            }
1873        }
1874        0x0084 => {
1875            match decode_aliro_group_resolving_key(tlv_value) {
1876                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1877                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1878            }
1879        }
1880        0x0085 => {
1881            match decode_aliro_supported_bleuwb_protocol_versions(tlv_value) {
1882                Ok(value) => {
1883                    // Serialize Vec<Vec<u8>> as array of hex strings
1884                    let hex_array: Vec<String> = value.iter()
1885                        .map(|bytes| bytes.iter()
1886                            .map(|byte| format!("{:02x}", byte))
1887                            .collect::<String>())
1888                        .collect();
1889                    serde_json::to_string(&hex_array).unwrap_or_else(|_| "null".to_string())
1890                },
1891                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1892            }
1893        }
1894        0x0086 => {
1895            match decode_aliro_ble_advertising_version(tlv_value) {
1896                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1897                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1898            }
1899        }
1900        0x0087 => {
1901            match decode_number_of_aliro_credential_issuer_keys_supported(tlv_value) {
1902                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1903                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1904            }
1905        }
1906        0x0088 => {
1907            match decode_number_of_aliro_endpoint_keys_supported(tlv_value) {
1908                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1909                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1910            }
1911        }
1912        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
1913    }
1914}
1915
1916/// Get list of all attributes supported by this cluster
1917///
1918/// # Returns
1919/// Vector of tuples containing (attribute_id, attribute_name)
1920pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
1921    vec![
1922        (0x0000, "LockState"),
1923        (0x0001, "LockType"),
1924        (0x0002, "ActuatorEnabled"),
1925        (0x0003, "DoorState"),
1926        (0x0004, "DoorOpenEvents"),
1927        (0x0005, "DoorClosedEvents"),
1928        (0x0006, "OpenPeriod"),
1929        (0x0011, "NumberOfTotalUsersSupported"),
1930        (0x0012, "NumberOfPINUsersSupported"),
1931        (0x0013, "NumberOfRFIDUsersSupported"),
1932        (0x0014, "NumberOfWeekDaySchedulesSupportedPerUser"),
1933        (0x0015, "NumberOfYearDaySchedulesSupportedPerUser"),
1934        (0x0016, "NumberOfHolidaySchedulesSupported"),
1935        (0x0017, "MaxPINCodeLength"),
1936        (0x0018, "MinPINCodeLength"),
1937        (0x0019, "MaxRFIDCodeLength"),
1938        (0x001A, "MinRFIDCodeLength"),
1939        (0x001B, "CredentialRulesSupport"),
1940        (0x001C, "NumberOfCredentialsSupportedPerUser"),
1941        (0x0021, "Language"),
1942        (0x0022, "LEDSettings"),
1943        (0x0023, "AutoRelockTime"),
1944        (0x0024, "SoundVolume"),
1945        (0x0025, "OperatingMode"),
1946        (0x0026, "SupportedOperatingModes"),
1947        (0x0027, "DefaultConfigurationRegister"),
1948        (0x0028, "EnableLocalProgramming"),
1949        (0x0029, "EnableOneTouchLocking"),
1950        (0x002A, "EnableInsideStatusLED"),
1951        (0x002B, "EnablePrivacyModeButton"),
1952        (0x002C, "LocalProgrammingFeatures"),
1953        (0x0030, "WrongCodeEntryLimit"),
1954        (0x0031, "UserCodeTemporaryDisableTime"),
1955        (0x0032, "SendPINOverTheAir"),
1956        (0x0033, "RequirePINforRemoteOperation"),
1957        (0x0034, "SecurityLevel"),
1958        (0x0035, "ExpiringUserTimeout"),
1959        (0x0080, "AliroReaderVerificationKey"),
1960        (0x0081, "AliroReaderGroupIdentifier"),
1961        (0x0082, "AliroReaderGroupSubIdentifier"),
1962        (0x0083, "AliroExpeditedTransactionSupportedProtocolVersions"),
1963        (0x0084, "AliroGroupResolvingKey"),
1964        (0x0085, "AliroSupportedBLEUWBProtocolVersions"),
1965        (0x0086, "AliroBLEAdvertisingVersion"),
1966        (0x0087, "NumberOfAliroCredentialIssuerKeysSupported"),
1967        (0x0088, "NumberOfAliroEndpointKeysSupported"),
1968    ]
1969}
1970
1971// Command listing
1972
1973pub fn get_command_list() -> Vec<(u32, &'static str)> {
1974    vec![
1975        (0x00, "LockDoor"),
1976        (0x01, "UnlockDoor"),
1977        (0x02, "Toggle"),
1978        (0x03, "UnlockWithTimeout"),
1979        (0x0B, "SetWeekDaySchedule"),
1980        (0x0C, "GetWeekDaySchedule"),
1981        (0x0D, "ClearWeekDaySchedule"),
1982        (0x0E, "SetYearDaySchedule"),
1983        (0x0F, "GetYearDaySchedule"),
1984        (0x10, "ClearYearDaySchedule"),
1985        (0x11, "SetHolidaySchedule"),
1986        (0x12, "GetHolidaySchedule"),
1987        (0x13, "ClearHolidaySchedule"),
1988        (0x1A, "SetUser"),
1989        (0x1B, "GetUser"),
1990        (0x1D, "ClearUser"),
1991        (0x22, "SetCredential"),
1992        (0x24, "GetCredentialStatus"),
1993        (0x26, "ClearCredential"),
1994        (0x27, "UnboltDoor"),
1995        (0x28, "SetAliroReaderConfig"),
1996        (0x29, "ClearAliroReaderConfig"),
1997    ]
1998}
1999
2000pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
2001    match cmd_id {
2002        0x00 => Some("LockDoor"),
2003        0x01 => Some("UnlockDoor"),
2004        0x02 => Some("Toggle"),
2005        0x03 => Some("UnlockWithTimeout"),
2006        0x0B => Some("SetWeekDaySchedule"),
2007        0x0C => Some("GetWeekDaySchedule"),
2008        0x0D => Some("ClearWeekDaySchedule"),
2009        0x0E => Some("SetYearDaySchedule"),
2010        0x0F => Some("GetYearDaySchedule"),
2011        0x10 => Some("ClearYearDaySchedule"),
2012        0x11 => Some("SetHolidaySchedule"),
2013        0x12 => Some("GetHolidaySchedule"),
2014        0x13 => Some("ClearHolidaySchedule"),
2015        0x1A => Some("SetUser"),
2016        0x1B => Some("GetUser"),
2017        0x1D => Some("ClearUser"),
2018        0x22 => Some("SetCredential"),
2019        0x24 => Some("GetCredentialStatus"),
2020        0x26 => Some("ClearCredential"),
2021        0x27 => Some("UnboltDoor"),
2022        0x28 => Some("SetAliroReaderConfig"),
2023        0x29 => Some("ClearAliroReaderConfig"),
2024        _ => None,
2025    }
2026}
2027
2028pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
2029    match cmd_id {
2030        0x00 => Some(vec![
2031            crate::clusters::codec::CommandField { tag: 0, name: "pin_code", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
2032        ]),
2033        0x01 => Some(vec![
2034            crate::clusters::codec::CommandField { tag: 0, name: "pin_code", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
2035        ]),
2036        0x02 => Some(vec![]),
2037        0x03 => Some(vec![
2038            crate::clusters::codec::CommandField { tag: 0, name: "timeout", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
2039            crate::clusters::codec::CommandField { tag: 1, name: "pin_code", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
2040        ]),
2041        0x0B => Some(vec![
2042            crate::clusters::codec::CommandField { tag: 0, name: "week_day_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
2043            crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
2044            crate::clusters::codec::CommandField { tag: 2, name: "days_mask", kind: crate::clusters::codec::FieldKind::Bitmap { name: "DaysMask", bits: &[(1, "SUNDAY"), (2, "MONDAY"), (4, "TUESDAY"), (8, "WEDNESDAY"), (16, "THURSDAY"), (32, "FRIDAY"), (64, "SATURDAY")] }, optional: false, nullable: false },
2045            crate::clusters::codec::CommandField { tag: 3, name: "start_hour", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
2046            crate::clusters::codec::CommandField { tag: 4, name: "start_minute", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
2047            crate::clusters::codec::CommandField { tag: 5, name: "end_hour", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
2048            crate::clusters::codec::CommandField { tag: 6, name: "end_minute", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
2049        ]),
2050        0x0C => Some(vec![
2051            crate::clusters::codec::CommandField { tag: 0, name: "week_day_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
2052            crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
2053        ]),
2054        0x0D => Some(vec![
2055            crate::clusters::codec::CommandField { tag: 0, name: "week_day_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
2056            crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
2057        ]),
2058        0x0E => Some(vec![
2059            crate::clusters::codec::CommandField { tag: 0, name: "year_day_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
2060            crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
2061            crate::clusters::codec::CommandField { tag: 2, name: "local_start_time", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
2062            crate::clusters::codec::CommandField { tag: 3, name: "local_end_time", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
2063        ]),
2064        0x0F => Some(vec![
2065            crate::clusters::codec::CommandField { tag: 0, name: "year_day_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
2066            crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
2067        ]),
2068        0x10 => Some(vec![
2069            crate::clusters::codec::CommandField { tag: 0, name: "year_day_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
2070            crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
2071        ]),
2072        0x11 => Some(vec![
2073            crate::clusters::codec::CommandField { tag: 0, name: "holiday_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
2074            crate::clusters::codec::CommandField { tag: 1, name: "local_start_time", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
2075            crate::clusters::codec::CommandField { tag: 2, name: "local_end_time", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
2076            crate::clusters::codec::CommandField { tag: 3, name: "operating_mode", kind: crate::clusters::codec::FieldKind::Enum { name: "OperatingMode", variants: &[(0, "Normal"), (1, "Vacation"), (2, "Privacy"), (3, "Noremotelockunlock"), (4, "Passage")] }, optional: false, nullable: false },
2077        ]),
2078        0x12 => Some(vec![
2079            crate::clusters::codec::CommandField { tag: 0, name: "holiday_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
2080        ]),
2081        0x13 => Some(vec![
2082            crate::clusters::codec::CommandField { tag: 0, name: "holiday_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
2083        ]),
2084        0x1A => Some(vec![
2085            crate::clusters::codec::CommandField { tag: 0, name: "operation_type", kind: crate::clusters::codec::FieldKind::Enum { name: "DataOperationType", variants: &[(0, "Add"), (1, "Clear"), (2, "Modify")] }, optional: false, nullable: false },
2086            crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
2087            crate::clusters::codec::CommandField { tag: 2, name: "user_name", kind: crate::clusters::codec::FieldKind::String, optional: false, nullable: true },
2088            crate::clusters::codec::CommandField { tag: 3, name: "user_unique_id", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: true },
2089            crate::clusters::codec::CommandField { tag: 4, name: "user_status", kind: crate::clusters::codec::FieldKind::Enum { name: "UserStatus", variants: &[(0, "Available"), (1, "Occupiedenabled"), (3, "Occupieddisabled")] }, optional: false, nullable: true },
2090            crate::clusters::codec::CommandField { tag: 5, name: "user_type", kind: crate::clusters::codec::FieldKind::Enum { name: "UserType", variants: &[(0, "Unrestricteduser"), (1, "Yeardayscheduleuser"), (2, "Weekdayscheduleuser"), (3, "Programminguser"), (4, "Nonaccessuser"), (5, "Forceduser"), (6, "Disposableuser"), (7, "Expiringuser"), (8, "Schedulerestricteduser"), (9, "Remoteonlyuser")] }, optional: false, nullable: true },
2091            crate::clusters::codec::CommandField { tag: 6, name: "credential_rule", kind: crate::clusters::codec::FieldKind::Enum { name: "CredentialRule", variants: &[(0, "Single"), (1, "Dual"), (2, "Tri")] }, optional: false, nullable: true },
2092        ]),
2093        0x1B => Some(vec![
2094            crate::clusters::codec::CommandField { tag: 0, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
2095        ]),
2096        0x1D => Some(vec![
2097            crate::clusters::codec::CommandField { tag: 0, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
2098        ]),
2099        0x22 => Some(vec![
2100            crate::clusters::codec::CommandField { tag: 0, name: "operation_type", kind: crate::clusters::codec::FieldKind::Enum { name: "DataOperationType", variants: &[(0, "Add"), (1, "Clear"), (2, "Modify")] }, optional: false, nullable: false },
2101            crate::clusters::codec::CommandField { tag: 1, name: "credential", kind: crate::clusters::codec::FieldKind::Struct { name: "CredentialStruct" }, optional: false, nullable: false },
2102            crate::clusters::codec::CommandField { tag: 2, name: "credential_data", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
2103            crate::clusters::codec::CommandField { tag: 3, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: true },
2104            crate::clusters::codec::CommandField { tag: 4, name: "user_status", kind: crate::clusters::codec::FieldKind::Enum { name: "UserStatus", variants: &[(0, "Available"), (1, "Occupiedenabled"), (3, "Occupieddisabled")] }, optional: false, nullable: true },
2105            crate::clusters::codec::CommandField { tag: 5, name: "user_type", kind: crate::clusters::codec::FieldKind::Enum { name: "UserType", variants: &[(0, "Unrestricteduser"), (1, "Yeardayscheduleuser"), (2, "Weekdayscheduleuser"), (3, "Programminguser"), (4, "Nonaccessuser"), (5, "Forceduser"), (6, "Disposableuser"), (7, "Expiringuser"), (8, "Schedulerestricteduser"), (9, "Remoteonlyuser")] }, optional: false, nullable: true },
2106        ]),
2107        0x24 => Some(vec![
2108            crate::clusters::codec::CommandField { tag: 0, name: "credential", kind: crate::clusters::codec::FieldKind::Struct { name: "CredentialStruct" }, optional: false, nullable: false },
2109        ]),
2110        0x26 => Some(vec![
2111            crate::clusters::codec::CommandField { tag: 0, name: "credential", kind: crate::clusters::codec::FieldKind::Struct { name: "CredentialStruct" }, optional: false, nullable: true },
2112        ]),
2113        0x27 => Some(vec![
2114            crate::clusters::codec::CommandField { tag: 0, name: "pin_code", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
2115        ]),
2116        0x28 => Some(vec![
2117            crate::clusters::codec::CommandField { tag: 0, name: "signing_key", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
2118            crate::clusters::codec::CommandField { tag: 1, name: "verification_key", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
2119            crate::clusters::codec::CommandField { tag: 2, name: "group_identifier", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
2120            crate::clusters::codec::CommandField { tag: 3, name: "group_resolving_key", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
2121        ]),
2122        0x29 => Some(vec![]),
2123        _ => None,
2124    }
2125}
2126
2127pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
2128    match cmd_id {
2129        0x00 => {
2130        let pin_code = crate::clusters::codec::json_util::get_octstr(args, "pin_code")?;
2131        encode_lock_door(pin_code)
2132        }
2133        0x01 => {
2134        let pin_code = crate::clusters::codec::json_util::get_octstr(args, "pin_code")?;
2135        encode_unlock_door(pin_code)
2136        }
2137        0x02 => Ok(vec![]),
2138        0x03 => {
2139        let timeout = crate::clusters::codec::json_util::get_u16(args, "timeout")?;
2140        let pin_code = crate::clusters::codec::json_util::get_octstr(args, "pin_code")?;
2141        encode_unlock_with_timeout(timeout, pin_code)
2142        }
2143        0x0B => {
2144        let week_day_index = crate::clusters::codec::json_util::get_u8(args, "week_day_index")?;
2145        let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
2146        let days_mask = crate::clusters::codec::json_util::get_u8(args, "days_mask")?;
2147        let start_hour = crate::clusters::codec::json_util::get_u8(args, "start_hour")?;
2148        let start_minute = crate::clusters::codec::json_util::get_u8(args, "start_minute")?;
2149        let end_hour = crate::clusters::codec::json_util::get_u8(args, "end_hour")?;
2150        let end_minute = crate::clusters::codec::json_util::get_u8(args, "end_minute")?;
2151        encode_set_week_day_schedule(week_day_index, user_index, days_mask, start_hour, start_minute, end_hour, end_minute)
2152        }
2153        0x0C => {
2154        let week_day_index = crate::clusters::codec::json_util::get_u8(args, "week_day_index")?;
2155        let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
2156        encode_get_week_day_schedule(week_day_index, user_index)
2157        }
2158        0x0D => {
2159        let week_day_index = crate::clusters::codec::json_util::get_u8(args, "week_day_index")?;
2160        let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
2161        encode_clear_week_day_schedule(week_day_index, user_index)
2162        }
2163        0x0E => {
2164        let year_day_index = crate::clusters::codec::json_util::get_u8(args, "year_day_index")?;
2165        let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
2166        let local_start_time = crate::clusters::codec::json_util::get_u64(args, "local_start_time")?;
2167        let local_end_time = crate::clusters::codec::json_util::get_u64(args, "local_end_time")?;
2168        encode_set_year_day_schedule(year_day_index, user_index, local_start_time, local_end_time)
2169        }
2170        0x0F => {
2171        let year_day_index = crate::clusters::codec::json_util::get_u8(args, "year_day_index")?;
2172        let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
2173        encode_get_year_day_schedule(year_day_index, user_index)
2174        }
2175        0x10 => {
2176        let year_day_index = crate::clusters::codec::json_util::get_u8(args, "year_day_index")?;
2177        let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
2178        encode_clear_year_day_schedule(year_day_index, user_index)
2179        }
2180        0x11 => {
2181        let holiday_index = crate::clusters::codec::json_util::get_u8(args, "holiday_index")?;
2182        let local_start_time = crate::clusters::codec::json_util::get_u64(args, "local_start_time")?;
2183        let local_end_time = crate::clusters::codec::json_util::get_u64(args, "local_end_time")?;
2184        let operating_mode = {
2185            let n = crate::clusters::codec::json_util::get_u64(args, "operating_mode")?;
2186            OperatingMode::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid OperatingMode: {}", n))?
2187        };
2188        encode_set_holiday_schedule(holiday_index, local_start_time, local_end_time, operating_mode)
2189        }
2190        0x12 => {
2191        let holiday_index = crate::clusters::codec::json_util::get_u8(args, "holiday_index")?;
2192        encode_get_holiday_schedule(holiday_index)
2193        }
2194        0x13 => {
2195        let holiday_index = crate::clusters::codec::json_util::get_u8(args, "holiday_index")?;
2196        encode_clear_holiday_schedule(holiday_index)
2197        }
2198        0x1A => {
2199        let operation_type = {
2200            let n = crate::clusters::codec::json_util::get_u64(args, "operation_type")?;
2201            DataOperationType::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid DataOperationType: {}", n))?
2202        };
2203        let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
2204        let user_name = crate::clusters::codec::json_util::get_opt_string(args, "user_name")?;
2205        let user_unique_id = crate::clusters::codec::json_util::get_opt_u32(args, "user_unique_id")?;
2206        let user_status = crate::clusters::codec::json_util::get_opt_u64(args, "user_status")?
2207            .and_then(|n| UserStatus::from_u8(n as u8));
2208        let user_type = crate::clusters::codec::json_util::get_opt_u64(args, "user_type")?
2209            .and_then(|n| UserType::from_u8(n as u8));
2210        let credential_rule = crate::clusters::codec::json_util::get_opt_u64(args, "credential_rule")?
2211            .and_then(|n| CredentialRule::from_u8(n as u8));
2212        encode_set_user(operation_type, user_index, user_name, user_unique_id, user_status, user_type, credential_rule)
2213        }
2214        0x1B => {
2215        let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
2216        encode_get_user(user_index)
2217        }
2218        0x1D => {
2219        let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
2220        encode_clear_user(user_index)
2221        }
2222        0x22 => Err(anyhow::anyhow!("command \"SetCredential\" has complex args: use raw mode")),
2223        0x24 => Err(anyhow::anyhow!("command \"GetCredentialStatus\" has complex args: use raw mode")),
2224        0x26 => Err(anyhow::anyhow!("command \"ClearCredential\" has complex args: use raw mode")),
2225        0x27 => {
2226        let pin_code = crate::clusters::codec::json_util::get_octstr(args, "pin_code")?;
2227        encode_unbolt_door(pin_code)
2228        }
2229        0x28 => {
2230        let signing_key = crate::clusters::codec::json_util::get_octstr(args, "signing_key")?;
2231        let verification_key = crate::clusters::codec::json_util::get_octstr(args, "verification_key")?;
2232        let group_identifier = crate::clusters::codec::json_util::get_octstr(args, "group_identifier")?;
2233        let group_resolving_key = crate::clusters::codec::json_util::get_octstr(args, "group_resolving_key")?;
2234        encode_set_aliro_reader_config(signing_key, verification_key, group_identifier, group_resolving_key)
2235        }
2236        0x29 => Ok(vec![]),
2237        _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
2238    }
2239}
2240
2241#[derive(Debug, serde::Serialize)]
2242pub struct GetWeekDayScheduleResponse {
2243    pub week_day_index: Option<u8>,
2244    pub user_index: Option<u16>,
2245    pub status: Option<u8>,
2246    pub days_mask: Option<DaysMask>,
2247    pub start_hour: Option<u8>,
2248    pub start_minute: Option<u8>,
2249    pub end_hour: Option<u8>,
2250    pub end_minute: Option<u8>,
2251}
2252
2253#[derive(Debug, serde::Serialize)]
2254pub struct GetYearDayScheduleResponse {
2255    pub year_day_index: Option<u8>,
2256    pub user_index: Option<u16>,
2257    pub status: Option<u8>,
2258    pub local_start_time: Option<u64>,
2259    pub local_end_time: Option<u64>,
2260}
2261
2262#[derive(Debug, serde::Serialize)]
2263pub struct GetHolidayScheduleResponse {
2264    pub holiday_index: Option<u8>,
2265    pub status: Option<u8>,
2266    pub local_start_time: Option<u64>,
2267    pub local_end_time: Option<u64>,
2268    pub operating_mode: Option<OperatingMode>,
2269}
2270
2271#[derive(Debug, serde::Serialize)]
2272pub struct GetUserResponse {
2273    pub user_index: Option<u16>,
2274    pub user_name: Option<String>,
2275    pub user_unique_id: Option<u32>,
2276    pub user_status: Option<UserStatus>,
2277    pub user_type: Option<UserType>,
2278    pub credential_rule: Option<CredentialRule>,
2279    pub credentials: Option<Vec<Credential>>,
2280    pub creator_fabric_index: Option<u8>,
2281    pub last_modified_fabric_index: Option<u8>,
2282    pub next_user_index: Option<u16>,
2283}
2284
2285#[derive(Debug, serde::Serialize)]
2286pub struct SetCredentialResponse {
2287    pub status: Option<u8>,
2288    pub user_index: Option<u16>,
2289    pub next_credential_index: Option<u16>,
2290}
2291
2292#[derive(Debug, serde::Serialize)]
2293pub struct GetCredentialStatusResponse {
2294    pub credential_exists: Option<bool>,
2295    pub user_index: Option<u16>,
2296    pub creator_fabric_index: Option<u8>,
2297    pub last_modified_fabric_index: Option<u8>,
2298    pub next_credential_index: Option<u16>,
2299    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
2300    pub credential_data: Option<Vec<u8>>,
2301}
2302
2303// Command response decoders
2304
2305/// Decode GetWeekDayScheduleResponse command response (0C)
2306pub fn decode_get_week_day_schedule_response(inp: &tlv::TlvItemValue) -> anyhow::Result<GetWeekDayScheduleResponse> {
2307    if let tlv::TlvItemValue::List(_fields) = inp {
2308        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
2309        Ok(GetWeekDayScheduleResponse {
2310                week_day_index: item.get_int(&[0]).map(|v| v as u8),
2311                user_index: item.get_int(&[1]).map(|v| v as u16),
2312                status: item.get_int(&[2]).map(|v| v as u8),
2313                days_mask: item.get_int(&[3]).map(|v| v as u8),
2314                start_hour: item.get_int(&[4]).map(|v| v as u8),
2315                start_minute: item.get_int(&[5]).map(|v| v as u8),
2316                end_hour: item.get_int(&[6]).map(|v| v as u8),
2317                end_minute: item.get_int(&[7]).map(|v| v as u8),
2318        })
2319    } else {
2320        Err(anyhow::anyhow!("Expected struct fields"))
2321    }
2322}
2323
2324/// Decode GetYearDayScheduleResponse command response (0F)
2325pub fn decode_get_year_day_schedule_response(inp: &tlv::TlvItemValue) -> anyhow::Result<GetYearDayScheduleResponse> {
2326    if let tlv::TlvItemValue::List(_fields) = inp {
2327        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
2328        Ok(GetYearDayScheduleResponse {
2329                year_day_index: item.get_int(&[0]).map(|v| v as u8),
2330                user_index: item.get_int(&[1]).map(|v| v as u16),
2331                status: item.get_int(&[2]).map(|v| v as u8),
2332                local_start_time: item.get_int(&[3]),
2333                local_end_time: item.get_int(&[4]),
2334        })
2335    } else {
2336        Err(anyhow::anyhow!("Expected struct fields"))
2337    }
2338}
2339
2340/// Decode GetHolidayScheduleResponse command response (12)
2341pub fn decode_get_holiday_schedule_response(inp: &tlv::TlvItemValue) -> anyhow::Result<GetHolidayScheduleResponse> {
2342    if let tlv::TlvItemValue::List(_fields) = inp {
2343        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
2344        Ok(GetHolidayScheduleResponse {
2345                holiday_index: item.get_int(&[0]).map(|v| v as u8),
2346                status: item.get_int(&[1]).map(|v| v as u8),
2347                local_start_time: item.get_int(&[2]),
2348                local_end_time: item.get_int(&[3]),
2349                operating_mode: item.get_int(&[4]).and_then(|v| OperatingMode::from_u8(v as u8)),
2350        })
2351    } else {
2352        Err(anyhow::anyhow!("Expected struct fields"))
2353    }
2354}
2355
2356/// Decode GetUserResponse command response (1C)
2357pub fn decode_get_user_response(inp: &tlv::TlvItemValue) -> anyhow::Result<GetUserResponse> {
2358    if let tlv::TlvItemValue::List(_fields) = inp {
2359        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
2360        Ok(GetUserResponse {
2361                user_index: item.get_int(&[0]).map(|v| v as u16),
2362                user_name: item.get_string_owned(&[1]),
2363                user_unique_id: item.get_int(&[2]).map(|v| v as u32),
2364                user_status: item.get_int(&[3]).and_then(|v| UserStatus::from_u8(v as u8)),
2365                user_type: item.get_int(&[4]).and_then(|v| UserType::from_u8(v as u8)),
2366                credential_rule: item.get_int(&[5]).and_then(|v| CredentialRule::from_u8(v as u8)),
2367                credentials: {
2368                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[6]) {
2369                        let mut items = Vec::new();
2370                        for list_item in l {
2371                            items.push(Credential {
2372                credential_type: list_item.get_int(&[0]).and_then(|v| CredentialType::from_u8(v as u8)),
2373                credential_index: list_item.get_int(&[1]).map(|v| v as u16),
2374                            });
2375                        }
2376                        Some(items)
2377                    } else {
2378                        None
2379                    }
2380                },
2381                creator_fabric_index: item.get_int(&[7]).map(|v| v as u8),
2382                last_modified_fabric_index: item.get_int(&[8]).map(|v| v as u8),
2383                next_user_index: item.get_int(&[9]).map(|v| v as u16),
2384        })
2385    } else {
2386        Err(anyhow::anyhow!("Expected struct fields"))
2387    }
2388}
2389
2390/// Decode SetCredentialResponse command response (23)
2391pub fn decode_set_credential_response(inp: &tlv::TlvItemValue) -> anyhow::Result<SetCredentialResponse> {
2392    if let tlv::TlvItemValue::List(_fields) = inp {
2393        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
2394        Ok(SetCredentialResponse {
2395                status: item.get_int(&[0]).map(|v| v as u8),
2396                user_index: item.get_int(&[1]).map(|v| v as u16),
2397                next_credential_index: item.get_int(&[2]).map(|v| v as u16),
2398        })
2399    } else {
2400        Err(anyhow::anyhow!("Expected struct fields"))
2401    }
2402}
2403
2404/// Decode GetCredentialStatusResponse command response (25)
2405pub fn decode_get_credential_status_response(inp: &tlv::TlvItemValue) -> anyhow::Result<GetCredentialStatusResponse> {
2406    if let tlv::TlvItemValue::List(_fields) = inp {
2407        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
2408        Ok(GetCredentialStatusResponse {
2409                credential_exists: item.get_bool(&[0]),
2410                user_index: item.get_int(&[1]).map(|v| v as u16),
2411                creator_fabric_index: item.get_int(&[2]).map(|v| v as u8),
2412                last_modified_fabric_index: item.get_int(&[3]).map(|v| v as u8),
2413                next_credential_index: item.get_int(&[4]).map(|v| v as u16),
2414                credential_data: item.get_octet_string_owned(&[5]),
2415        })
2416    } else {
2417        Err(anyhow::anyhow!("Expected struct fields"))
2418    }
2419}
2420
2421// Typed facade (invokes + reads)
2422
2423/// Invoke `LockDoor` command on cluster `Door Lock`.
2424pub async fn lock_door(conn: &crate::controller::Connection, endpoint: u16, pin_code: Vec<u8>) -> anyhow::Result<()> {
2425    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_LOCKDOOR, &encode_lock_door(pin_code)?).await?;
2426    Ok(())
2427}
2428
2429/// Invoke `UnlockDoor` command on cluster `Door Lock`.
2430pub async fn unlock_door(conn: &crate::controller::Connection, endpoint: u16, pin_code: Vec<u8>) -> anyhow::Result<()> {
2431    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_UNLOCKDOOR, &encode_unlock_door(pin_code)?).await?;
2432    Ok(())
2433}
2434
2435/// Invoke `Toggle` command on cluster `Door Lock`.
2436pub async fn toggle(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
2437    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_TOGGLE, &[]).await?;
2438    Ok(())
2439}
2440
2441/// Invoke `UnlockWithTimeout` command on cluster `Door Lock`.
2442pub async fn unlock_with_timeout(conn: &crate::controller::Connection, endpoint: u16, timeout: u16, pin_code: Vec<u8>) -> anyhow::Result<()> {
2443    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_UNLOCKWITHTIMEOUT, &encode_unlock_with_timeout(timeout, pin_code)?).await?;
2444    Ok(())
2445}
2446
2447/// Invoke `SetWeekDaySchedule` command on cluster `Door Lock`.
2448pub async fn set_week_day_schedule(conn: &crate::controller::Connection, endpoint: u16, week_day_index: u8, user_index: u16, days_mask: DaysMask, start_hour: u8, start_minute: u8, end_hour: u8, end_minute: u8) -> anyhow::Result<()> {
2449    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_SETWEEKDAYSCHEDULE, &encode_set_week_day_schedule(week_day_index, user_index, days_mask, start_hour, start_minute, end_hour, end_minute)?).await?;
2450    Ok(())
2451}
2452
2453/// Invoke `GetWeekDaySchedule` command on cluster `Door Lock`.
2454pub async fn get_week_day_schedule(conn: &crate::controller::Connection, endpoint: u16, week_day_index: u8, user_index: u16) -> anyhow::Result<GetWeekDayScheduleResponse> {
2455    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_GETWEEKDAYSCHEDULE, &encode_get_week_day_schedule(week_day_index, user_index)?).await?;
2456    decode_get_week_day_schedule_response(&tlv)
2457}
2458
2459/// Invoke `ClearWeekDaySchedule` command on cluster `Door Lock`.
2460pub async fn clear_week_day_schedule(conn: &crate::controller::Connection, endpoint: u16, week_day_index: u8, user_index: u16) -> anyhow::Result<()> {
2461    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_CLEARWEEKDAYSCHEDULE, &encode_clear_week_day_schedule(week_day_index, user_index)?).await?;
2462    Ok(())
2463}
2464
2465/// Invoke `SetYearDaySchedule` command on cluster `Door Lock`.
2466pub async fn set_year_day_schedule(conn: &crate::controller::Connection, endpoint: u16, year_day_index: u8, user_index: u16, local_start_time: u64, local_end_time: u64) -> anyhow::Result<()> {
2467    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_SETYEARDAYSCHEDULE, &encode_set_year_day_schedule(year_day_index, user_index, local_start_time, local_end_time)?).await?;
2468    Ok(())
2469}
2470
2471/// Invoke `GetYearDaySchedule` command on cluster `Door Lock`.
2472pub async fn get_year_day_schedule(conn: &crate::controller::Connection, endpoint: u16, year_day_index: u8, user_index: u16) -> anyhow::Result<GetYearDayScheduleResponse> {
2473    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_GETYEARDAYSCHEDULE, &encode_get_year_day_schedule(year_day_index, user_index)?).await?;
2474    decode_get_year_day_schedule_response(&tlv)
2475}
2476
2477/// Invoke `ClearYearDaySchedule` command on cluster `Door Lock`.
2478pub async fn clear_year_day_schedule(conn: &crate::controller::Connection, endpoint: u16, year_day_index: u8, user_index: u16) -> anyhow::Result<()> {
2479    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_CLEARYEARDAYSCHEDULE, &encode_clear_year_day_schedule(year_day_index, user_index)?).await?;
2480    Ok(())
2481}
2482
2483/// Invoke `SetHolidaySchedule` command on cluster `Door Lock`.
2484pub async fn set_holiday_schedule(conn: &crate::controller::Connection, endpoint: u16, holiday_index: u8, local_start_time: u64, local_end_time: u64, operating_mode: OperatingMode) -> anyhow::Result<()> {
2485    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_SETHOLIDAYSCHEDULE, &encode_set_holiday_schedule(holiday_index, local_start_time, local_end_time, operating_mode)?).await?;
2486    Ok(())
2487}
2488
2489/// Invoke `GetHolidaySchedule` command on cluster `Door Lock`.
2490pub async fn get_holiday_schedule(conn: &crate::controller::Connection, endpoint: u16, holiday_index: u8) -> anyhow::Result<GetHolidayScheduleResponse> {
2491    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_GETHOLIDAYSCHEDULE, &encode_get_holiday_schedule(holiday_index)?).await?;
2492    decode_get_holiday_schedule_response(&tlv)
2493}
2494
2495/// Invoke `ClearHolidaySchedule` command on cluster `Door Lock`.
2496pub async fn clear_holiday_schedule(conn: &crate::controller::Connection, endpoint: u16, holiday_index: u8) -> anyhow::Result<()> {
2497    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_CLEARHOLIDAYSCHEDULE, &encode_clear_holiday_schedule(holiday_index)?).await?;
2498    Ok(())
2499}
2500
2501/// Invoke `SetUser` command on cluster `Door Lock`.
2502pub async fn set_user(conn: &crate::controller::Connection, endpoint: u16, operation_type: DataOperationType, user_index: u16, user_name: Option<String>, user_unique_id: Option<u32>, user_status: Option<UserStatus>, user_type: Option<UserType>, credential_rule: Option<CredentialRule>) -> anyhow::Result<()> {
2503    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_SETUSER, &encode_set_user(operation_type, user_index, user_name, user_unique_id, user_status, user_type, credential_rule)?).await?;
2504    Ok(())
2505}
2506
2507/// Invoke `GetUser` command on cluster `Door Lock`.
2508pub async fn get_user(conn: &crate::controller::Connection, endpoint: u16, user_index: u16) -> anyhow::Result<GetUserResponse> {
2509    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_GETUSER, &encode_get_user(user_index)?).await?;
2510    decode_get_user_response(&tlv)
2511}
2512
2513/// Invoke `ClearUser` command on cluster `Door Lock`.
2514pub async fn clear_user(conn: &crate::controller::Connection, endpoint: u16, user_index: u16) -> anyhow::Result<()> {
2515    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_CLEARUSER, &encode_clear_user(user_index)?).await?;
2516    Ok(())
2517}
2518
2519/// Invoke `SetCredential` command on cluster `Door Lock`.
2520pub async fn set_credential(conn: &crate::controller::Connection, endpoint: u16, operation_type: DataOperationType, credential: Credential, credential_data: Vec<u8>, user_index: Option<u16>, user_status: Option<UserStatus>, user_type: Option<UserType>) -> anyhow::Result<SetCredentialResponse> {
2521    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_SETCREDENTIAL, &encode_set_credential(operation_type, credential, credential_data, user_index, user_status, user_type)?).await?;
2522    decode_set_credential_response(&tlv)
2523}
2524
2525/// Invoke `GetCredentialStatus` command on cluster `Door Lock`.
2526pub async fn get_credential_status(conn: &crate::controller::Connection, endpoint: u16, credential: Credential) -> anyhow::Result<GetCredentialStatusResponse> {
2527    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_GETCREDENTIALSTATUS, &encode_get_credential_status(credential)?).await?;
2528    decode_get_credential_status_response(&tlv)
2529}
2530
2531/// Invoke `ClearCredential` command on cluster `Door Lock`.
2532pub async fn clear_credential(conn: &crate::controller::Connection, endpoint: u16, credential: Option<Credential>) -> anyhow::Result<()> {
2533    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_CLEARCREDENTIAL, &encode_clear_credential(credential)?).await?;
2534    Ok(())
2535}
2536
2537/// Invoke `UnboltDoor` command on cluster `Door Lock`.
2538pub async fn unbolt_door(conn: &crate::controller::Connection, endpoint: u16, pin_code: Vec<u8>) -> anyhow::Result<()> {
2539    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_UNBOLTDOOR, &encode_unbolt_door(pin_code)?).await?;
2540    Ok(())
2541}
2542
2543/// Invoke `SetAliroReaderConfig` command on cluster `Door Lock`.
2544pub async fn set_aliro_reader_config(conn: &crate::controller::Connection, endpoint: u16, signing_key: Vec<u8>, verification_key: Vec<u8>, group_identifier: Vec<u8>, group_resolving_key: Vec<u8>) -> anyhow::Result<()> {
2545    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_SETALIROREADERCONFIG, &encode_set_aliro_reader_config(signing_key, verification_key, group_identifier, group_resolving_key)?).await?;
2546    Ok(())
2547}
2548
2549/// Invoke `ClearAliroReaderConfig` command on cluster `Door Lock`.
2550pub async fn clear_aliro_reader_config(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
2551    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_CLEARALIROREADERCONFIG, &[]).await?;
2552    Ok(())
2553}
2554
2555/// Read `LockState` attribute from cluster `Door Lock`.
2556pub async fn read_lock_state(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<LockState>> {
2557    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_LOCKSTATE).await?;
2558    decode_lock_state(&tlv)
2559}
2560
2561/// Read `LockType` attribute from cluster `Door Lock`.
2562pub async fn read_lock_type(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<LockType> {
2563    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_LOCKTYPE).await?;
2564    decode_lock_type(&tlv)
2565}
2566
2567/// Read `ActuatorEnabled` attribute from cluster `Door Lock`.
2568pub async fn read_actuator_enabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
2569    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ACTUATORENABLED).await?;
2570    decode_actuator_enabled(&tlv)
2571}
2572
2573/// Read `DoorState` attribute from cluster `Door Lock`.
2574pub async fn read_door_state(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<DoorState>> {
2575    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_DOORSTATE).await?;
2576    decode_door_state(&tlv)
2577}
2578
2579/// Read `DoorOpenEvents` attribute from cluster `Door Lock`.
2580pub async fn read_door_open_events(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
2581    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_DOOROPENEVENTS).await?;
2582    decode_door_open_events(&tlv)
2583}
2584
2585/// Read `DoorClosedEvents` attribute from cluster `Door Lock`.
2586pub async fn read_door_closed_events(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
2587    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_DOORCLOSEDEVENTS).await?;
2588    decode_door_closed_events(&tlv)
2589}
2590
2591/// Read `OpenPeriod` attribute from cluster `Door Lock`.
2592pub async fn read_open_period(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
2593    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_OPENPERIOD).await?;
2594    decode_open_period(&tlv)
2595}
2596
2597/// Read `NumberOfTotalUsersSupported` attribute from cluster `Door Lock`.
2598pub async fn read_number_of_total_users_supported(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
2599    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFTOTALUSERSSUPPORTED).await?;
2600    decode_number_of_total_users_supported(&tlv)
2601}
2602
2603/// Read `NumberOfPINUsersSupported` attribute from cluster `Door Lock`.
2604pub async fn read_number_of_pin_users_supported(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
2605    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFPINUSERSSUPPORTED).await?;
2606    decode_number_of_pin_users_supported(&tlv)
2607}
2608
2609/// Read `NumberOfRFIDUsersSupported` attribute from cluster `Door Lock`.
2610pub async fn read_number_of_rfid_users_supported(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
2611    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFRFIDUSERSSUPPORTED).await?;
2612    decode_number_of_rfid_users_supported(&tlv)
2613}
2614
2615/// Read `NumberOfWeekDaySchedulesSupportedPerUser` attribute from cluster `Door Lock`.
2616pub async fn read_number_of_week_day_schedules_supported_per_user(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2617    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFWEEKDAYSCHEDULESSUPPORTEDPERUSER).await?;
2618    decode_number_of_week_day_schedules_supported_per_user(&tlv)
2619}
2620
2621/// Read `NumberOfYearDaySchedulesSupportedPerUser` attribute from cluster `Door Lock`.
2622pub async fn read_number_of_year_day_schedules_supported_per_user(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2623    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFYEARDAYSCHEDULESSUPPORTEDPERUSER).await?;
2624    decode_number_of_year_day_schedules_supported_per_user(&tlv)
2625}
2626
2627/// Read `NumberOfHolidaySchedulesSupported` attribute from cluster `Door Lock`.
2628pub async fn read_number_of_holiday_schedules_supported(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2629    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFHOLIDAYSCHEDULESSUPPORTED).await?;
2630    decode_number_of_holiday_schedules_supported(&tlv)
2631}
2632
2633/// Read `MaxPINCodeLength` attribute from cluster `Door Lock`.
2634pub async fn read_max_pin_code_length(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2635    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_MAXPINCODELENGTH).await?;
2636    decode_max_pin_code_length(&tlv)
2637}
2638
2639/// Read `MinPINCodeLength` attribute from cluster `Door Lock`.
2640pub async fn read_min_pin_code_length(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2641    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_MINPINCODELENGTH).await?;
2642    decode_min_pin_code_length(&tlv)
2643}
2644
2645/// Read `MaxRFIDCodeLength` attribute from cluster `Door Lock`.
2646pub async fn read_max_rfid_code_length(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2647    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_MAXRFIDCODELENGTH).await?;
2648    decode_max_rfid_code_length(&tlv)
2649}
2650
2651/// Read `MinRFIDCodeLength` attribute from cluster `Door Lock`.
2652pub async fn read_min_rfid_code_length(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2653    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_MINRFIDCODELENGTH).await?;
2654    decode_min_rfid_code_length(&tlv)
2655}
2656
2657/// Read `CredentialRulesSupport` attribute from cluster `Door Lock`.
2658pub async fn read_credential_rules_support(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<CredentialRules> {
2659    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_CREDENTIALRULESSUPPORT).await?;
2660    decode_credential_rules_support(&tlv)
2661}
2662
2663/// Read `NumberOfCredentialsSupportedPerUser` attribute from cluster `Door Lock`.
2664pub async fn read_number_of_credentials_supported_per_user(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2665    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFCREDENTIALSSUPPORTEDPERUSER).await?;
2666    decode_number_of_credentials_supported_per_user(&tlv)
2667}
2668
2669/// Read `Language` attribute from cluster `Door Lock`.
2670pub async fn read_language(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
2671    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_LANGUAGE).await?;
2672    decode_language(&tlv)
2673}
2674
2675/// Read `LEDSettings` attribute from cluster `Door Lock`.
2676pub async fn read_led_settings(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<LEDSetting> {
2677    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_LEDSETTINGS).await?;
2678    decode_led_settings(&tlv)
2679}
2680
2681/// Read `AutoRelockTime` attribute from cluster `Door Lock`.
2682pub async fn read_auto_relock_time(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
2683    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_AUTORELOCKTIME).await?;
2684    decode_auto_relock_time(&tlv)
2685}
2686
2687/// Read `SoundVolume` attribute from cluster `Door Lock`.
2688pub async fn read_sound_volume(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<SoundVolume> {
2689    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_SOUNDVOLUME).await?;
2690    decode_sound_volume(&tlv)
2691}
2692
2693/// Read `OperatingMode` attribute from cluster `Door Lock`.
2694pub async fn read_operating_mode(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<OperatingMode> {
2695    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_OPERATINGMODE).await?;
2696    decode_operating_mode(&tlv)
2697}
2698
2699/// Read `SupportedOperatingModes` attribute from cluster `Door Lock`.
2700pub async fn read_supported_operating_modes(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<OperatingModes> {
2701    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_SUPPORTEDOPERATINGMODES).await?;
2702    decode_supported_operating_modes(&tlv)
2703}
2704
2705/// Read `DefaultConfigurationRegister` attribute from cluster `Door Lock`.
2706pub async fn read_default_configuration_register(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ConfigurationRegister> {
2707    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_DEFAULTCONFIGURATIONREGISTER).await?;
2708    decode_default_configuration_register(&tlv)
2709}
2710
2711/// Read `EnableLocalProgramming` attribute from cluster `Door Lock`.
2712pub async fn read_enable_local_programming(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
2713    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ENABLELOCALPROGRAMMING).await?;
2714    decode_enable_local_programming(&tlv)
2715}
2716
2717/// Read `EnableOneTouchLocking` attribute from cluster `Door Lock`.
2718pub async fn read_enable_one_touch_locking(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
2719    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ENABLEONETOUCHLOCKING).await?;
2720    decode_enable_one_touch_locking(&tlv)
2721}
2722
2723/// Read `EnableInsideStatusLED` attribute from cluster `Door Lock`.
2724pub async fn read_enable_inside_status_led(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
2725    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ENABLEINSIDESTATUSLED).await?;
2726    decode_enable_inside_status_led(&tlv)
2727}
2728
2729/// Read `EnablePrivacyModeButton` attribute from cluster `Door Lock`.
2730pub async fn read_enable_privacy_mode_button(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
2731    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ENABLEPRIVACYMODEBUTTON).await?;
2732    decode_enable_privacy_mode_button(&tlv)
2733}
2734
2735/// Read `LocalProgrammingFeatures` attribute from cluster `Door Lock`.
2736pub async fn read_local_programming_features(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<LocalProgrammingFeatures> {
2737    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_LOCALPROGRAMMINGFEATURES).await?;
2738    decode_local_programming_features(&tlv)
2739}
2740
2741/// Read `WrongCodeEntryLimit` attribute from cluster `Door Lock`.
2742pub async fn read_wrong_code_entry_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2743    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_WRONGCODEENTRYLIMIT).await?;
2744    decode_wrong_code_entry_limit(&tlv)
2745}
2746
2747/// Read `UserCodeTemporaryDisableTime` attribute from cluster `Door Lock`.
2748pub async fn read_user_code_temporary_disable_time(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2749    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_USERCODETEMPORARYDISABLETIME).await?;
2750    decode_user_code_temporary_disable_time(&tlv)
2751}
2752
2753/// Read `SendPINOverTheAir` attribute from cluster `Door Lock`.
2754pub async fn read_send_pin_over_the_air(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
2755    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_SENDPINOVERTHEAIR).await?;
2756    decode_send_pin_over_the_air(&tlv)
2757}
2758
2759/// Read `RequirePINforRemoteOperation` attribute from cluster `Door Lock`.
2760pub async fn read_require_pinfor_remote_operation(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
2761    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_REQUIREPINFORREMOTEOPERATION).await?;
2762    decode_require_pinfor_remote_operation(&tlv)
2763}
2764
2765/// Read `SecurityLevel` attribute from cluster `Door Lock`.
2766pub async fn read_security_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2767    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_SECURITYLEVEL).await?;
2768    decode_security_level(&tlv)
2769}
2770
2771/// Read `ExpiringUserTimeout` attribute from cluster `Door Lock`.
2772pub async fn read_expiring_user_timeout(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
2773    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_EXPIRINGUSERTIMEOUT).await?;
2774    decode_expiring_user_timeout(&tlv)
2775}
2776
2777/// Read `AliroReaderVerificationKey` attribute from cluster `Door Lock`.
2778pub async fn read_aliro_reader_verification_key(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<Vec<u8>>> {
2779    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROREADERVERIFICATIONKEY).await?;
2780    decode_aliro_reader_verification_key(&tlv)
2781}
2782
2783/// Read `AliroReaderGroupIdentifier` attribute from cluster `Door Lock`.
2784pub async fn read_aliro_reader_group_identifier(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<Vec<u8>>> {
2785    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROREADERGROUPIDENTIFIER).await?;
2786    decode_aliro_reader_group_identifier(&tlv)
2787}
2788
2789/// Read `AliroReaderGroupSubIdentifier` attribute from cluster `Door Lock`.
2790pub async fn read_aliro_reader_group_sub_identifier(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<u8>> {
2791    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROREADERGROUPSUBIDENTIFIER).await?;
2792    decode_aliro_reader_group_sub_identifier(&tlv)
2793}
2794
2795/// Read `AliroExpeditedTransactionSupportedProtocolVersions` attribute from cluster `Door Lock`.
2796pub async fn read_aliro_expedited_transaction_supported_protocol_versions(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<Vec<u8>>> {
2797    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROEXPEDITEDTRANSACTIONSUPPORTEDPROTOCOLVERSIONS).await?;
2798    decode_aliro_expedited_transaction_supported_protocol_versions(&tlv)
2799}
2800
2801/// Read `AliroGroupResolvingKey` attribute from cluster `Door Lock`.
2802pub async fn read_aliro_group_resolving_key(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<Vec<u8>>> {
2803    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROGROUPRESOLVINGKEY).await?;
2804    decode_aliro_group_resolving_key(&tlv)
2805}
2806
2807/// Read `AliroSupportedBLEUWBProtocolVersions` attribute from cluster `Door Lock`.
2808pub async fn read_aliro_supported_bleuwb_protocol_versions(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<Vec<u8>>> {
2809    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROSUPPORTEDBLEUWBPROTOCOLVERSIONS).await?;
2810    decode_aliro_supported_bleuwb_protocol_versions(&tlv)
2811}
2812
2813/// Read `AliroBLEAdvertisingVersion` attribute from cluster `Door Lock`.
2814pub async fn read_aliro_ble_advertising_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2815    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROBLEADVERTISINGVERSION).await?;
2816    decode_aliro_ble_advertising_version(&tlv)
2817}
2818
2819/// Read `NumberOfAliroCredentialIssuerKeysSupported` attribute from cluster `Door Lock`.
2820pub async fn read_number_of_aliro_credential_issuer_keys_supported(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
2821    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFALIROCREDENTIALISSUERKEYSSUPPORTED).await?;
2822    decode_number_of_aliro_credential_issuer_keys_supported(&tlv)
2823}
2824
2825/// Read `NumberOfAliroEndpointKeysSupported` attribute from cluster `Door Lock`.
2826pub async fn read_number_of_aliro_endpoint_keys_supported(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
2827    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFALIROENDPOINTKEYSSUPPORTED).await?;
2828    decode_number_of_aliro_endpoint_keys_supported(&tlv)
2829}
2830
2831#[derive(Debug, serde::Serialize)]
2832pub struct DoorLockAlarmEvent {
2833    pub alarm_code: Option<AlarmCode>,
2834}
2835
2836#[derive(Debug, serde::Serialize)]
2837pub struct DoorStateChangeEvent {
2838    pub door_state: Option<DoorState>,
2839}
2840
2841#[derive(Debug, serde::Serialize)]
2842pub struct LockOperationEvent {
2843    pub lock_operation_type: Option<LockOperationType>,
2844    pub operation_source: Option<OperationSource>,
2845    pub user_index: Option<u16>,
2846    pub fabric_index: Option<u8>,
2847    pub source_node: Option<u64>,
2848    pub credentials: Option<Vec<Credential>>,
2849}
2850
2851#[derive(Debug, serde::Serialize)]
2852pub struct LockOperationErrorEvent {
2853    pub lock_operation_type: Option<LockOperationType>,
2854    pub operation_source: Option<OperationSource>,
2855    pub operation_error: Option<OperationError>,
2856    pub user_index: Option<u16>,
2857    pub fabric_index: Option<u8>,
2858    pub source_node: Option<u64>,
2859    pub credentials: Option<Vec<Credential>>,
2860}
2861
2862#[derive(Debug, serde::Serialize)]
2863pub struct LockUserChangeEvent {
2864    pub lock_data_type: Option<LockDataType>,
2865    pub data_operation_type: Option<DataOperationType>,
2866    pub operation_source: Option<OperationSource>,
2867    pub user_index: Option<u16>,
2868    pub fabric_index: Option<u8>,
2869    pub source_node: Option<u64>,
2870    pub data_index: Option<u16>,
2871}
2872
2873// Event decoders
2874
2875/// Decode DoorLockAlarm event (0x00, priority: critical)
2876pub fn decode_door_lock_alarm_event(inp: &tlv::TlvItemValue) -> anyhow::Result<DoorLockAlarmEvent> {
2877    if let tlv::TlvItemValue::List(_fields) = inp {
2878        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
2879        Ok(DoorLockAlarmEvent {
2880                                alarm_code: item.get_int(&[0]).and_then(|v| AlarmCode::from_u8(v as u8)),
2881        })
2882    } else {
2883        Err(anyhow::anyhow!("Expected struct fields"))
2884    }
2885}
2886
2887/// Decode DoorStateChange event (0x01, priority: desc)
2888pub fn decode_door_state_change_event(inp: &tlv::TlvItemValue) -> anyhow::Result<DoorStateChangeEvent> {
2889    if let tlv::TlvItemValue::List(_fields) = inp {
2890        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
2891        Ok(DoorStateChangeEvent {
2892                                door_state: item.get_int(&[0]).and_then(|v| DoorState::from_u8(v as u8)),
2893        })
2894    } else {
2895        Err(anyhow::anyhow!("Expected struct fields"))
2896    }
2897}
2898
2899/// Decode LockOperation event (0x02, priority: desc)
2900pub fn decode_lock_operation_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LockOperationEvent> {
2901    if let tlv::TlvItemValue::List(_fields) = inp {
2902        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
2903        Ok(LockOperationEvent {
2904                                lock_operation_type: item.get_int(&[0]).and_then(|v| LockOperationType::from_u8(v as u8)),
2905                                operation_source: item.get_int(&[1]).and_then(|v| OperationSource::from_u8(v as u8)),
2906                                user_index: item.get_int(&[2]).map(|v| v as u16),
2907                                fabric_index: item.get_int(&[3]).map(|v| v as u8),
2908                                source_node: item.get_int(&[4]),
2909                                credentials: {
2910                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[5]) {
2911                        let mut items = Vec::new();
2912                        for list_item in l {
2913                            items.push(Credential {
2914                credential_type: list_item.get_int(&[0]).and_then(|v| CredentialType::from_u8(v as u8)),
2915                credential_index: list_item.get_int(&[1]).map(|v| v as u16),
2916                            });
2917                        }
2918                        Some(items)
2919                    } else {
2920                        None
2921                    }
2922                },
2923        })
2924    } else {
2925        Err(anyhow::anyhow!("Expected struct fields"))
2926    }
2927}
2928
2929/// Decode LockOperationError event (0x03, priority: desc)
2930pub fn decode_lock_operation_error_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LockOperationErrorEvent> {
2931    if let tlv::TlvItemValue::List(_fields) = inp {
2932        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
2933        Ok(LockOperationErrorEvent {
2934                                lock_operation_type: item.get_int(&[0]).and_then(|v| LockOperationType::from_u8(v as u8)),
2935                                operation_source: item.get_int(&[1]).and_then(|v| OperationSource::from_u8(v as u8)),
2936                                operation_error: item.get_int(&[2]).and_then(|v| OperationError::from_u8(v as u8)),
2937                                user_index: item.get_int(&[3]).map(|v| v as u16),
2938                                fabric_index: item.get_int(&[4]).map(|v| v as u8),
2939                                source_node: item.get_int(&[5]),
2940                                credentials: {
2941                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[6]) {
2942                        let mut items = Vec::new();
2943                        for list_item in l {
2944                            items.push(Credential {
2945                credential_type: list_item.get_int(&[0]).and_then(|v| CredentialType::from_u8(v as u8)),
2946                credential_index: list_item.get_int(&[1]).map(|v| v as u16),
2947                            });
2948                        }
2949                        Some(items)
2950                    } else {
2951                        None
2952                    }
2953                },
2954        })
2955    } else {
2956        Err(anyhow::anyhow!("Expected struct fields"))
2957    }
2958}
2959
2960/// Decode LockUserChange event (0x04, priority: info)
2961pub fn decode_lock_user_change_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LockUserChangeEvent> {
2962    if let tlv::TlvItemValue::List(_fields) = inp {
2963        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
2964        Ok(LockUserChangeEvent {
2965                                lock_data_type: item.get_int(&[0]).and_then(|v| LockDataType::from_u8(v as u8)),
2966                                data_operation_type: item.get_int(&[1]).and_then(|v| DataOperationType::from_u8(v as u8)),
2967                                operation_source: item.get_int(&[2]).and_then(|v| OperationSource::from_u8(v as u8)),
2968                                user_index: item.get_int(&[3]).map(|v| v as u16),
2969                                fabric_index: item.get_int(&[4]).map(|v| v as u8),
2970                                source_node: item.get_int(&[5]),
2971                                data_index: item.get_int(&[6]).map(|v| v as u16),
2972        })
2973    } else {
2974        Err(anyhow::anyhow!("Expected struct fields"))
2975    }
2976}
2977