#![allow(clippy::too_many_arguments)]
use crate::tlv;
use anyhow;
use serde_json;
use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum AlarmCode {
Lockjammed = 0,
Lockfactoryreset = 1,
Lockradiopowercycled = 3,
Wrongcodeentrylimit = 4,
Frontesceutcheonremoved = 5,
Doorforcedopen = 6,
Doorajar = 7,
Forceduser = 8,
}
impl AlarmCode {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(AlarmCode::Lockjammed),
1 => Some(AlarmCode::Lockfactoryreset),
3 => Some(AlarmCode::Lockradiopowercycled),
4 => Some(AlarmCode::Wrongcodeentrylimit),
5 => Some(AlarmCode::Frontesceutcheonremoved),
6 => Some(AlarmCode::Doorforcedopen),
7 => Some(AlarmCode::Doorajar),
8 => Some(AlarmCode::Forceduser),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<AlarmCode> for u8 {
fn from(val: AlarmCode) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum CredentialRule {
Single = 0,
Dual = 1,
Tri = 2,
}
impl CredentialRule {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(CredentialRule::Single),
1 => Some(CredentialRule::Dual),
2 => Some(CredentialRule::Tri),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<CredentialRule> for u8 {
fn from(val: CredentialRule) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum CredentialType {
Programmingpin = 0,
Pin = 1,
Rfid = 2,
Fingerprint = 3,
Fingervein = 4,
Face = 5,
Alirocredentialissuerkey = 6,
Aliroevictableendpointkey = 7,
Alirononevictableendpointkey = 8,
}
impl CredentialType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(CredentialType::Programmingpin),
1 => Some(CredentialType::Pin),
2 => Some(CredentialType::Rfid),
3 => Some(CredentialType::Fingerprint),
4 => Some(CredentialType::Fingervein),
5 => Some(CredentialType::Face),
6 => Some(CredentialType::Alirocredentialissuerkey),
7 => Some(CredentialType::Aliroevictableendpointkey),
8 => Some(CredentialType::Alirononevictableendpointkey),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<CredentialType> for u8 {
fn from(val: CredentialType) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum DataOperationType {
Add = 0,
Clear = 1,
Modify = 2,
}
impl DataOperationType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(DataOperationType::Add),
1 => Some(DataOperationType::Clear),
2 => Some(DataOperationType::Modify),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<DataOperationType> for u8 {
fn from(val: DataOperationType) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum DoorState {
Dooropen = 0,
Doorclosed = 1,
Doorjammed = 2,
Doorforcedopen = 3,
Doorunspecifiederror = 4,
Doorajar = 5,
}
impl DoorState {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(DoorState::Dooropen),
1 => Some(DoorState::Doorclosed),
2 => Some(DoorState::Doorjammed),
3 => Some(DoorState::Doorforcedopen),
4 => Some(DoorState::Doorunspecifiederror),
5 => Some(DoorState::Doorajar),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<DoorState> for u8 {
fn from(val: DoorState) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum EventType {
Operation = 0,
Programming = 1,
Alarm = 2,
}
impl EventType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(EventType::Operation),
1 => Some(EventType::Programming),
2 => Some(EventType::Alarm),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<EventType> for u8 {
fn from(val: EventType) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum LEDSetting {
Noledsignal = 0,
Noledsignalaccessallowed = 1,
Ledsignalall = 2,
}
impl LEDSetting {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(LEDSetting::Noledsignal),
1 => Some(LEDSetting::Noledsignalaccessallowed),
2 => Some(LEDSetting::Ledsignalall),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<LEDSetting> for u8 {
fn from(val: LEDSetting) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum LockDataType {
Unspecified = 0,
Programmingcode = 1,
Userindex = 2,
Weekdayschedule = 3,
Yeardayschedule = 4,
Holidayschedule = 5,
Pin = 6,
Rfid = 7,
Fingerprint = 8,
Fingervein = 9,
Face = 10,
Alirocredentialissuerkey = 11,
Aliroevictableendpointkey = 12,
Alirononevictableendpointkey = 13,
}
impl LockDataType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(LockDataType::Unspecified),
1 => Some(LockDataType::Programmingcode),
2 => Some(LockDataType::Userindex),
3 => Some(LockDataType::Weekdayschedule),
4 => Some(LockDataType::Yeardayschedule),
5 => Some(LockDataType::Holidayschedule),
6 => Some(LockDataType::Pin),
7 => Some(LockDataType::Rfid),
8 => Some(LockDataType::Fingerprint),
9 => Some(LockDataType::Fingervein),
10 => Some(LockDataType::Face),
11 => Some(LockDataType::Alirocredentialissuerkey),
12 => Some(LockDataType::Aliroevictableendpointkey),
13 => Some(LockDataType::Alirononevictableendpointkey),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<LockDataType> for u8 {
fn from(val: LockDataType) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum LockOperationType {
Lock = 0,
Unlock = 1,
Nonaccessuserevent = 2,
Forceduserevent = 3,
Unlatch = 4,
}
impl LockOperationType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(LockOperationType::Lock),
1 => Some(LockOperationType::Unlock),
2 => Some(LockOperationType::Nonaccessuserevent),
3 => Some(LockOperationType::Forceduserevent),
4 => Some(LockOperationType::Unlatch),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<LockOperationType> for u8 {
fn from(val: LockOperationType) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum LockState {
Notfullylocked = 0,
Locked = 1,
Unlocked = 2,
Unlatched = 3,
}
impl LockState {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(LockState::Notfullylocked),
1 => Some(LockState::Locked),
2 => Some(LockState::Unlocked),
3 => Some(LockState::Unlatched),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<LockState> for u8 {
fn from(val: LockState) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum LockType {
Deadbolt = 0,
Magnetic = 1,
Other = 2,
Mortise = 3,
Rim = 4,
Latchbolt = 5,
Cylindricallock = 6,
Tubularlock = 7,
Interconnectedlock = 8,
Deadlatch = 9,
Doorfurniture = 10,
Eurocylinder = 11,
}
impl LockType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(LockType::Deadbolt),
1 => Some(LockType::Magnetic),
2 => Some(LockType::Other),
3 => Some(LockType::Mortise),
4 => Some(LockType::Rim),
5 => Some(LockType::Latchbolt),
6 => Some(LockType::Cylindricallock),
7 => Some(LockType::Tubularlock),
8 => Some(LockType::Interconnectedlock),
9 => Some(LockType::Deadlatch),
10 => Some(LockType::Doorfurniture),
11 => Some(LockType::Eurocylinder),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<LockType> for u8 {
fn from(val: LockType) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum OperatingMode {
Normal = 0,
Vacation = 1,
Privacy = 2,
Noremotelockunlock = 3,
Passage = 4,
}
impl OperatingMode {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(OperatingMode::Normal),
1 => Some(OperatingMode::Vacation),
2 => Some(OperatingMode::Privacy),
3 => Some(OperatingMode::Noremotelockunlock),
4 => Some(OperatingMode::Passage),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<OperatingMode> for u8 {
fn from(val: OperatingMode) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum OperationError {
Unspecified = 0,
Invalidcredential = 1,
Disableduserdenied = 2,
Restricted = 3,
Insufficientbattery = 4,
}
impl OperationError {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(OperationError::Unspecified),
1 => Some(OperationError::Invalidcredential),
2 => Some(OperationError::Disableduserdenied),
3 => Some(OperationError::Restricted),
4 => Some(OperationError::Insufficientbattery),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<OperationError> for u8 {
fn from(val: OperationError) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum OperationSource {
Unspecified = 0,
Manual = 1,
Proprietaryremote = 2,
Keypad = 3,
Auto = 4,
Button = 5,
Schedule = 6,
Remote = 7,
Rfid = 8,
Biometric = 9,
Aliro = 10,
}
impl OperationSource {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(OperationSource::Unspecified),
1 => Some(OperationSource::Manual),
2 => Some(OperationSource::Proprietaryremote),
3 => Some(OperationSource::Keypad),
4 => Some(OperationSource::Auto),
5 => Some(OperationSource::Button),
6 => Some(OperationSource::Schedule),
7 => Some(OperationSource::Remote),
8 => Some(OperationSource::Rfid),
9 => Some(OperationSource::Biometric),
10 => Some(OperationSource::Aliro),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<OperationSource> for u8 {
fn from(val: OperationSource) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum SoundVolume {
Silent = 0,
Low = 1,
High = 2,
Medium = 3,
}
impl SoundVolume {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(SoundVolume::Silent),
1 => Some(SoundVolume::Low),
2 => Some(SoundVolume::High),
3 => Some(SoundVolume::Medium),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<SoundVolume> for u8 {
fn from(val: SoundVolume) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum StatusCode {
Duplicate = 2,
Occupied = 3,
}
impl StatusCode {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
2 => Some(StatusCode::Duplicate),
3 => Some(StatusCode::Occupied),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<StatusCode> for u8 {
fn from(val: StatusCode) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum UserStatus {
Available = 0,
Occupiedenabled = 1,
Occupieddisabled = 3,
}
impl UserStatus {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(UserStatus::Available),
1 => Some(UserStatus::Occupiedenabled),
3 => Some(UserStatus::Occupieddisabled),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<UserStatus> for u8 {
fn from(val: UserStatus) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum UserType {
Unrestricteduser = 0,
Yeardayscheduleuser = 1,
Weekdayscheduleuser = 2,
Programminguser = 3,
Nonaccessuser = 4,
Forceduser = 5,
Disposableuser = 6,
Expiringuser = 7,
Schedulerestricteduser = 8,
Remoteonlyuser = 9,
}
impl UserType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(UserType::Unrestricteduser),
1 => Some(UserType::Yeardayscheduleuser),
2 => Some(UserType::Weekdayscheduleuser),
3 => Some(UserType::Programminguser),
4 => Some(UserType::Nonaccessuser),
5 => Some(UserType::Forceduser),
6 => Some(UserType::Disposableuser),
7 => Some(UserType::Expiringuser),
8 => Some(UserType::Schedulerestricteduser),
9 => Some(UserType::Remoteonlyuser),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<UserType> for u8 {
fn from(val: UserType) -> Self {
val as u8
}
}
pub type AlarmMask = u8;
pub mod alarmmask {
pub const LOCK_JAMMED: u8 = 0x01;
pub const LOCK_FACTORY_RESET: u8 = 0x02;
pub const LOCK_RADIO_POWER_CYCLED: u8 = 0x08;
pub const WRONG_CODE_ENTRY_LIMIT: u8 = 0x10;
pub const FRONT_ESCUTCHEON_REMOVED: u8 = 0x20;
pub const DOOR_FORCED_OPEN: u8 = 0x40;
}
pub type ConfigurationRegister = u8;
pub mod configurationregister {
pub const LOCAL_PROGRAMMING: u8 = 0x01;
pub const KEYPAD_INTERFACE: u8 = 0x02;
pub const REMOTE_INTERFACE: u8 = 0x04;
pub const SOUND_VOLUME: u8 = 0x20;
pub const AUTO_RELOCK_TIME: u8 = 0x40;
pub const LEDSETTINGS: u8 = 0x80;
}
pub type CredentialRules = u8;
pub mod credentialrules {
pub const SINGLE: u8 = 0x01;
pub const DUAL: u8 = 0x02;
pub const TRI: u8 = 0x04;
}
pub type DaysMask = u8;
pub mod daysmask {
pub const SUNDAY: u8 = 0x01;
pub const MONDAY: u8 = 0x02;
pub const TUESDAY: u8 = 0x04;
pub const WEDNESDAY: u8 = 0x08;
pub const THURSDAY: u8 = 0x10;
pub const FRIDAY: u8 = 0x20;
pub const SATURDAY: u8 = 0x40;
}
pub type LocalProgrammingFeatures = u8;
pub mod localprogrammingfeatures {
pub const ADD_USERS_CREDENTIALS_SCHEDULES: u8 = 0x01;
pub const MODIFY_USERS_CREDENTIALS_SCHEDULES: u8 = 0x02;
pub const CLEAR_USERS_CREDENTIALS_SCHEDULES: u8 = 0x04;
pub const ADJUST_SETTINGS: u8 = 0x08;
}
pub type OperatingModes = u8;
pub mod operatingmodes {
pub const NORMAL: u8 = 0x01;
pub const VACATION: u8 = 0x02;
pub const PRIVACY: u8 = 0x04;
pub const NO_REMOTE_LOCK_UNLOCK: u8 = 0x08;
pub const PASSAGE: u8 = 0x10;
}
#[derive(Debug, serde::Serialize)]
pub struct Credential {
pub credential_type: Option<CredentialType>,
pub credential_index: Option<u16>,
}
pub fn encode_lock_door(pin_code: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
if let Some(x) = pin_code { tlv_fields.push((0, tlv::TlvItemValueEnc::OctetString(x)).into()); }
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
};
Ok(tlv.encode()?)
}
pub fn encode_unlock_door(pin_code: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
if let Some(x) = pin_code { tlv_fields.push((0, tlv::TlvItemValueEnc::OctetString(x)).into()); }
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
};
Ok(tlv.encode()?)
}
pub fn encode_unlock_with_timeout(timeout: u16, pin_code: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
tlv_fields.push((0, tlv::TlvItemValueEnc::UInt16(timeout)).into());
if let Some(x) = pin_code { tlv_fields.push((1, tlv::TlvItemValueEnc::OctetString(x)).into()); }
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
};
Ok(tlv.encode()?)
}
pub 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>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(week_day_index)).into(),
(1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
(2, tlv::TlvItemValueEnc::UInt8(days_mask)).into(),
(3, tlv::TlvItemValueEnc::UInt8(start_hour)).into(),
(4, tlv::TlvItemValueEnc::UInt8(start_minute)).into(),
(5, tlv::TlvItemValueEnc::UInt8(end_hour)).into(),
(6, tlv::TlvItemValueEnc::UInt8(end_minute)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_get_week_day_schedule(week_day_index: u8, user_index: u16) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(week_day_index)).into(),
(1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_clear_week_day_schedule(week_day_index: u8, user_index: u16) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(week_day_index)).into(),
(1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
]),
};
Ok(tlv.encode()?)
}
pub 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>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(year_day_index)).into(),
(1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
(2, tlv::TlvItemValueEnc::UInt64(local_start_time)).into(),
(3, tlv::TlvItemValueEnc::UInt64(local_end_time)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_get_year_day_schedule(year_day_index: u8, user_index: u16) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(year_day_index)).into(),
(1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_clear_year_day_schedule(year_day_index: u8, user_index: u16) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(year_day_index)).into(),
(1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_set_holiday_schedule(holiday_index: u8, local_start_time: u64, local_end_time: u64, operating_mode: OperatingMode) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(holiday_index)).into(),
(1, tlv::TlvItemValueEnc::UInt64(local_start_time)).into(),
(2, tlv::TlvItemValueEnc::UInt64(local_end_time)).into(),
(3, tlv::TlvItemValueEnc::UInt8(operating_mode.to_u8())).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_get_holiday_schedule(holiday_index: u8) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(holiday_index)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_clear_holiday_schedule(holiday_index: u8) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(holiday_index)).into(),
]),
};
Ok(tlv.encode()?)
}
pub 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>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(operation_type.to_u8())).into(),
(1, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
(2, tlv::TlvItemValueEnc::String(user_name.unwrap_or("".to_string()))).into(),
(3, tlv::TlvItemValueEnc::UInt32(user_unique_id.unwrap_or(0))).into(),
(4, tlv::TlvItemValueEnc::UInt8(user_status.map(|e| e.to_u8()).unwrap_or(0))).into(),
(5, tlv::TlvItemValueEnc::UInt8(user_type.map(|e| e.to_u8()).unwrap_or(0))).into(),
(6, tlv::TlvItemValueEnc::UInt8(credential_rule.map(|e| e.to_u8()).unwrap_or(0))).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_get_user(user_index: u16) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_clear_user(user_index: u16) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt16(user_index)).into(),
]),
};
Ok(tlv.encode()?)
}
pub 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>> {
let mut credential_fields = Vec::new();
if let Some(x) = credential.credential_type { credential_fields.push((0, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
if let Some(x) = credential.credential_index { credential_fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(operation_type.to_u8())).into(),
(1, tlv::TlvItemValueEnc::StructInvisible(credential_fields)).into(),
(2, tlv::TlvItemValueEnc::OctetString(credential_data)).into(),
(3, tlv::TlvItemValueEnc::UInt16(user_index.unwrap_or(0))).into(),
(4, tlv::TlvItemValueEnc::UInt8(user_status.map(|e| e.to_u8()).unwrap_or(0))).into(),
(5, tlv::TlvItemValueEnc::UInt8(user_type.map(|e| e.to_u8()).unwrap_or(0))).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_get_credential_status(credential: Credential) -> anyhow::Result<Vec<u8>> {
let mut credential_fields = Vec::new();
if let Some(x) = credential.credential_type { credential_fields.push((0, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
if let Some(x) = credential.credential_index { credential_fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::StructInvisible(credential_fields)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_clear_credential(credential: Option<Credential>) -> anyhow::Result<Vec<u8>> {
let credential_enc = if let Some(s) = credential {
let mut fields = Vec::new();
if let Some(x) = s.credential_type { fields.push((0, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
if let Some(x) = s.credential_index { fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
tlv::TlvItemValueEnc::StructInvisible(fields)
} else {
tlv::TlvItemValueEnc::StructInvisible(Vec::new())
};
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, credential_enc).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_unbolt_door(pin_code: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
if let Some(x) = pin_code { tlv_fields.push((0, tlv::TlvItemValueEnc::OctetString(x)).into()); }
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
};
Ok(tlv.encode()?)
}
pub 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>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::OctetString(signing_key)).into(),
(1, tlv::TlvItemValueEnc::OctetString(verification_key)).into(),
(2, tlv::TlvItemValueEnc::OctetString(group_identifier)).into(),
(3, tlv::TlvItemValueEnc::OctetString(group_resolving_key)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn decode_lock_state(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<LockState>> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(LockState::from_u8(*v as u8))
} else {
Ok(None)
}
}
pub fn decode_lock_type(inp: &tlv::TlvItemValue) -> anyhow::Result<LockType> {
if let tlv::TlvItemValue::Int(v) = inp {
LockType::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_actuator_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
if let tlv::TlvItemValue::Bool(v) = inp {
Ok(*v)
} else {
Err(anyhow::anyhow!("Expected Bool"))
}
}
pub fn decode_door_state(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<DoorState>> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(DoorState::from_u8(*v as u8))
} else {
Ok(None)
}
}
pub fn decode_door_open_events(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u32)
} else {
Err(anyhow::anyhow!("Expected UInt32"))
}
}
pub fn decode_door_closed_events(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u32)
} else {
Err(anyhow::anyhow!("Expected UInt32"))
}
}
pub fn decode_open_period(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u16)
} else {
Err(anyhow::anyhow!("Expected UInt16"))
}
}
pub fn decode_number_of_total_users_supported(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u16)
} else {
Err(anyhow::anyhow!("Expected UInt16"))
}
}
pub fn decode_number_of_pin_users_supported(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u16)
} else {
Err(anyhow::anyhow!("Expected UInt16"))
}
}
pub fn decode_number_of_rfid_users_supported(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u16)
} else {
Err(anyhow::anyhow!("Expected UInt16"))
}
}
pub fn decode_number_of_week_day_schedules_supported_per_user(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_number_of_year_day_schedules_supported_per_user(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_number_of_holiday_schedules_supported(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_max_pin_code_length(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_min_pin_code_length(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_max_rfid_code_length(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_min_rfid_code_length(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_credential_rules_support(inp: &tlv::TlvItemValue) -> anyhow::Result<CredentialRules> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_number_of_credentials_supported_per_user(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_language(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
if let tlv::TlvItemValue::String(v) = inp {
Ok(v.clone())
} else {
Err(anyhow::anyhow!("Expected String"))
}
}
pub fn decode_led_settings(inp: &tlv::TlvItemValue) -> anyhow::Result<LEDSetting> {
if let tlv::TlvItemValue::Int(v) = inp {
LEDSetting::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_auto_relock_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u32)
} else {
Err(anyhow::anyhow!("Expected UInt32"))
}
}
pub fn decode_sound_volume(inp: &tlv::TlvItemValue) -> anyhow::Result<SoundVolume> {
if let tlv::TlvItemValue::Int(v) = inp {
SoundVolume::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_operating_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<OperatingMode> {
if let tlv::TlvItemValue::Int(v) = inp {
OperatingMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_supported_operating_modes(inp: &tlv::TlvItemValue) -> anyhow::Result<OperatingModes> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_default_configuration_register(inp: &tlv::TlvItemValue) -> anyhow::Result<ConfigurationRegister> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_enable_local_programming(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
if let tlv::TlvItemValue::Bool(v) = inp {
Ok(*v)
} else {
Err(anyhow::anyhow!("Expected Bool"))
}
}
pub fn decode_enable_one_touch_locking(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
if let tlv::TlvItemValue::Bool(v) = inp {
Ok(*v)
} else {
Err(anyhow::anyhow!("Expected Bool"))
}
}
pub fn decode_enable_inside_status_led(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
if let tlv::TlvItemValue::Bool(v) = inp {
Ok(*v)
} else {
Err(anyhow::anyhow!("Expected Bool"))
}
}
pub fn decode_enable_privacy_mode_button(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
if let tlv::TlvItemValue::Bool(v) = inp {
Ok(*v)
} else {
Err(anyhow::anyhow!("Expected Bool"))
}
}
pub fn decode_local_programming_features(inp: &tlv::TlvItemValue) -> anyhow::Result<LocalProgrammingFeatures> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected Integer"))
}
}
pub fn decode_wrong_code_entry_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_user_code_temporary_disable_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_send_pin_over_the_air(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
if let tlv::TlvItemValue::Bool(v) = inp {
Ok(*v)
} else {
Err(anyhow::anyhow!("Expected Bool"))
}
}
pub fn decode_require_pinfor_remote_operation(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
if let tlv::TlvItemValue::Bool(v) = inp {
Ok(*v)
} else {
Err(anyhow::anyhow!("Expected Bool"))
}
}
pub fn decode_security_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_expiring_user_timeout(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u16)
} else {
Err(anyhow::anyhow!("Expected UInt16"))
}
}
pub fn decode_aliro_reader_verification_key(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
if let tlv::TlvItemValue::OctetString(v) = inp {
Ok(Some(v.clone()))
} else {
Ok(None)
}
}
pub fn decode_aliro_reader_group_identifier(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
if let tlv::TlvItemValue::OctetString(v) = inp {
Ok(Some(v.clone()))
} else {
Ok(None)
}
}
pub fn decode_aliro_reader_group_sub_identifier(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<u8>> {
if let tlv::TlvItemValue::OctetString(v) = inp {
Ok(v.clone())
} else {
Err(anyhow::anyhow!("Expected OctetString"))
}
}
pub fn decode_aliro_expedited_transaction_supported_protocol_versions(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Vec<u8>>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
if let tlv::TlvItemValue::OctetString(o) = &item.value {
res.push(o.clone());
}
}
}
Ok(res)
}
pub fn decode_aliro_group_resolving_key(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
if let tlv::TlvItemValue::OctetString(v) = inp {
Ok(Some(v.clone()))
} else {
Ok(None)
}
}
pub fn decode_aliro_supported_bleuwb_protocol_versions(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Vec<u8>>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
if let tlv::TlvItemValue::OctetString(o) = &item.value {
res.push(o.clone());
}
}
}
Ok(res)
}
pub fn decode_aliro_ble_advertising_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_number_of_aliro_credential_issuer_keys_supported(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u16)
} else {
Err(anyhow::anyhow!("Expected UInt16"))
}
}
pub fn decode_number_of_aliro_endpoint_keys_supported(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u16)
} else {
Err(anyhow::anyhow!("Expected UInt16"))
}
}
pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
if cluster_id != 0x0101 {
return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0101, got {}\"}}", cluster_id);
}
match attribute_id {
0x0000 => {
match decode_lock_state(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0001 => {
match decode_lock_type(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0002 => {
match decode_actuator_enabled(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0003 => {
match decode_door_state(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0004 => {
match decode_door_open_events(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0005 => {
match decode_door_closed_events(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0006 => {
match decode_open_period(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0011 => {
match decode_number_of_total_users_supported(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0012 => {
match decode_number_of_pin_users_supported(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0013 => {
match decode_number_of_rfid_users_supported(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0014 => {
match decode_number_of_week_day_schedules_supported_per_user(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0015 => {
match decode_number_of_year_day_schedules_supported_per_user(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0016 => {
match decode_number_of_holiday_schedules_supported(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0017 => {
match decode_max_pin_code_length(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0018 => {
match decode_min_pin_code_length(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0019 => {
match decode_max_rfid_code_length(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x001A => {
match decode_min_rfid_code_length(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x001B => {
match decode_credential_rules_support(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x001C => {
match decode_number_of_credentials_supported_per_user(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0021 => {
match decode_language(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0022 => {
match decode_led_settings(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0023 => {
match decode_auto_relock_time(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0024 => {
match decode_sound_volume(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0025 => {
match decode_operating_mode(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0026 => {
match decode_supported_operating_modes(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0027 => {
match decode_default_configuration_register(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0028 => {
match decode_enable_local_programming(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0029 => {
match decode_enable_one_touch_locking(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x002A => {
match decode_enable_inside_status_led(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x002B => {
match decode_enable_privacy_mode_button(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x002C => {
match decode_local_programming_features(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0030 => {
match decode_wrong_code_entry_limit(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0031 => {
match decode_user_code_temporary_disable_time(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0032 => {
match decode_send_pin_over_the_air(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0033 => {
match decode_require_pinfor_remote_operation(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0034 => {
match decode_security_level(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0035 => {
match decode_expiring_user_timeout(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0080 => {
match decode_aliro_reader_verification_key(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0081 => {
match decode_aliro_reader_group_identifier(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0082 => {
match decode_aliro_reader_group_sub_identifier(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0083 => {
match decode_aliro_expedited_transaction_supported_protocol_versions(tlv_value) {
Ok(value) => {
let hex_array: Vec<String> = value.iter()
.map(|bytes| bytes.iter()
.map(|byte| format!("{:02x}", byte))
.collect::<String>())
.collect();
serde_json::to_string(&hex_array).unwrap_or_else(|_| "null".to_string())
},
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0084 => {
match decode_aliro_group_resolving_key(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0085 => {
match decode_aliro_supported_bleuwb_protocol_versions(tlv_value) {
Ok(value) => {
let hex_array: Vec<String> = value.iter()
.map(|bytes| bytes.iter()
.map(|byte| format!("{:02x}", byte))
.collect::<String>())
.collect();
serde_json::to_string(&hex_array).unwrap_or_else(|_| "null".to_string())
},
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0086 => {
match decode_aliro_ble_advertising_version(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0087 => {
match decode_number_of_aliro_credential_issuer_keys_supported(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0088 => {
match decode_number_of_aliro_endpoint_keys_supported(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
_ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
}
}
pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
vec![
(0x0000, "LockState"),
(0x0001, "LockType"),
(0x0002, "ActuatorEnabled"),
(0x0003, "DoorState"),
(0x0004, "DoorOpenEvents"),
(0x0005, "DoorClosedEvents"),
(0x0006, "OpenPeriod"),
(0x0011, "NumberOfTotalUsersSupported"),
(0x0012, "NumberOfPINUsersSupported"),
(0x0013, "NumberOfRFIDUsersSupported"),
(0x0014, "NumberOfWeekDaySchedulesSupportedPerUser"),
(0x0015, "NumberOfYearDaySchedulesSupportedPerUser"),
(0x0016, "NumberOfHolidaySchedulesSupported"),
(0x0017, "MaxPINCodeLength"),
(0x0018, "MinPINCodeLength"),
(0x0019, "MaxRFIDCodeLength"),
(0x001A, "MinRFIDCodeLength"),
(0x001B, "CredentialRulesSupport"),
(0x001C, "NumberOfCredentialsSupportedPerUser"),
(0x0021, "Language"),
(0x0022, "LEDSettings"),
(0x0023, "AutoRelockTime"),
(0x0024, "SoundVolume"),
(0x0025, "OperatingMode"),
(0x0026, "SupportedOperatingModes"),
(0x0027, "DefaultConfigurationRegister"),
(0x0028, "EnableLocalProgramming"),
(0x0029, "EnableOneTouchLocking"),
(0x002A, "EnableInsideStatusLED"),
(0x002B, "EnablePrivacyModeButton"),
(0x002C, "LocalProgrammingFeatures"),
(0x0030, "WrongCodeEntryLimit"),
(0x0031, "UserCodeTemporaryDisableTime"),
(0x0032, "SendPINOverTheAir"),
(0x0033, "RequirePINforRemoteOperation"),
(0x0034, "SecurityLevel"),
(0x0035, "ExpiringUserTimeout"),
(0x0080, "AliroReaderVerificationKey"),
(0x0081, "AliroReaderGroupIdentifier"),
(0x0082, "AliroReaderGroupSubIdentifier"),
(0x0083, "AliroExpeditedTransactionSupportedProtocolVersions"),
(0x0084, "AliroGroupResolvingKey"),
(0x0085, "AliroSupportedBLEUWBProtocolVersions"),
(0x0086, "AliroBLEAdvertisingVersion"),
(0x0087, "NumberOfAliroCredentialIssuerKeysSupported"),
(0x0088, "NumberOfAliroEndpointKeysSupported"),
]
}
pub fn get_command_list() -> Vec<(u32, &'static str)> {
vec![
(0x00, "LockDoor"),
(0x01, "UnlockDoor"),
(0x02, "Toggle"),
(0x03, "UnlockWithTimeout"),
(0x0B, "SetWeekDaySchedule"),
(0x0C, "GetWeekDaySchedule"),
(0x0D, "ClearWeekDaySchedule"),
(0x0E, "SetYearDaySchedule"),
(0x0F, "GetYearDaySchedule"),
(0x10, "ClearYearDaySchedule"),
(0x11, "SetHolidaySchedule"),
(0x12, "GetHolidaySchedule"),
(0x13, "ClearHolidaySchedule"),
(0x1A, "SetUser"),
(0x1B, "GetUser"),
(0x1D, "ClearUser"),
(0x22, "SetCredential"),
(0x24, "GetCredentialStatus"),
(0x26, "ClearCredential"),
(0x27, "UnboltDoor"),
(0x28, "SetAliroReaderConfig"),
(0x29, "ClearAliroReaderConfig"),
]
}
pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
match cmd_id {
0x00 => Some("LockDoor"),
0x01 => Some("UnlockDoor"),
0x02 => Some("Toggle"),
0x03 => Some("UnlockWithTimeout"),
0x0B => Some("SetWeekDaySchedule"),
0x0C => Some("GetWeekDaySchedule"),
0x0D => Some("ClearWeekDaySchedule"),
0x0E => Some("SetYearDaySchedule"),
0x0F => Some("GetYearDaySchedule"),
0x10 => Some("ClearYearDaySchedule"),
0x11 => Some("SetHolidaySchedule"),
0x12 => Some("GetHolidaySchedule"),
0x13 => Some("ClearHolidaySchedule"),
0x1A => Some("SetUser"),
0x1B => Some("GetUser"),
0x1D => Some("ClearUser"),
0x22 => Some("SetCredential"),
0x24 => Some("GetCredentialStatus"),
0x26 => Some("ClearCredential"),
0x27 => Some("UnboltDoor"),
0x28 => Some("SetAliroReaderConfig"),
0x29 => Some("ClearAliroReaderConfig"),
_ => None,
}
}
pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
match cmd_id {
0x00 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "pin_code", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
]),
0x01 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "pin_code", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
]),
0x02 => Some(vec![]),
0x03 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "timeout", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "pin_code", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
]),
0x0B => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "week_day_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
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 },
crate::clusters::codec::CommandField { tag: 3, name: "start_hour", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 4, name: "start_minute", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 5, name: "end_hour", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 6, name: "end_minute", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
]),
0x0C => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "week_day_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
]),
0x0D => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "week_day_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
]),
0x0E => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "year_day_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 2, name: "local_start_time", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 3, name: "local_end_time", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
]),
0x0F => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "year_day_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
]),
0x10 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "year_day_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
]),
0x11 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "holiday_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "local_start_time", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 2, name: "local_end_time", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
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 },
]),
0x12 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "holiday_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
]),
0x13 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "holiday_index", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
]),
0x1A => Some(vec![
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 },
crate::clusters::codec::CommandField { tag: 1, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 2, name: "user_name", kind: crate::clusters::codec::FieldKind::String, optional: false, nullable: true },
crate::clusters::codec::CommandField { tag: 3, name: "user_unique_id", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: true },
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 },
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 },
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 },
]),
0x1B => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
]),
0x1D => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
]),
0x22 => Some(vec![
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 },
crate::clusters::codec::CommandField { tag: 1, name: "credential", kind: crate::clusters::codec::FieldKind::Struct { name: "CredentialStruct" }, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 2, name: "credential_data", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 3, name: "user_index", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: true },
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 },
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 },
]),
0x24 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "credential", kind: crate::clusters::codec::FieldKind::Struct { name: "CredentialStruct" }, optional: false, nullable: false },
]),
0x26 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "credential", kind: crate::clusters::codec::FieldKind::Struct { name: "CredentialStruct" }, optional: false, nullable: true },
]),
0x27 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "pin_code", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
]),
0x28 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "signing_key", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "verification_key", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 2, name: "group_identifier", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 3, name: "group_resolving_key", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
]),
0x29 => Some(vec![]),
_ => None,
}
}
pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
match cmd_id {
0x00 => {
let pin_code = crate::clusters::codec::json_util::get_opt_octstr(args, "pin_code")?;
encode_lock_door(pin_code)
}
0x01 => {
let pin_code = crate::clusters::codec::json_util::get_opt_octstr(args, "pin_code")?;
encode_unlock_door(pin_code)
}
0x02 => Ok(vec![]),
0x03 => {
let timeout = crate::clusters::codec::json_util::get_u16(args, "timeout")?;
let pin_code = crate::clusters::codec::json_util::get_opt_octstr(args, "pin_code")?;
encode_unlock_with_timeout(timeout, pin_code)
}
0x0B => {
let week_day_index = crate::clusters::codec::json_util::get_u8(args, "week_day_index")?;
let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
let days_mask = crate::clusters::codec::json_util::get_u8(args, "days_mask")?;
let start_hour = crate::clusters::codec::json_util::get_u8(args, "start_hour")?;
let start_minute = crate::clusters::codec::json_util::get_u8(args, "start_minute")?;
let end_hour = crate::clusters::codec::json_util::get_u8(args, "end_hour")?;
let end_minute = crate::clusters::codec::json_util::get_u8(args, "end_minute")?;
encode_set_week_day_schedule(week_day_index, user_index, days_mask, start_hour, start_minute, end_hour, end_minute)
}
0x0C => {
let week_day_index = crate::clusters::codec::json_util::get_u8(args, "week_day_index")?;
let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
encode_get_week_day_schedule(week_day_index, user_index)
}
0x0D => {
let week_day_index = crate::clusters::codec::json_util::get_u8(args, "week_day_index")?;
let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
encode_clear_week_day_schedule(week_day_index, user_index)
}
0x0E => {
let year_day_index = crate::clusters::codec::json_util::get_u8(args, "year_day_index")?;
let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
let local_start_time = crate::clusters::codec::json_util::get_u64(args, "local_start_time")?;
let local_end_time = crate::clusters::codec::json_util::get_u64(args, "local_end_time")?;
encode_set_year_day_schedule(year_day_index, user_index, local_start_time, local_end_time)
}
0x0F => {
let year_day_index = crate::clusters::codec::json_util::get_u8(args, "year_day_index")?;
let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
encode_get_year_day_schedule(year_day_index, user_index)
}
0x10 => {
let year_day_index = crate::clusters::codec::json_util::get_u8(args, "year_day_index")?;
let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
encode_clear_year_day_schedule(year_day_index, user_index)
}
0x11 => {
let holiday_index = crate::clusters::codec::json_util::get_u8(args, "holiday_index")?;
let local_start_time = crate::clusters::codec::json_util::get_u64(args, "local_start_time")?;
let local_end_time = crate::clusters::codec::json_util::get_u64(args, "local_end_time")?;
let operating_mode = {
let n = crate::clusters::codec::json_util::get_u64(args, "operating_mode")?;
OperatingMode::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid OperatingMode: {}", n))?
};
encode_set_holiday_schedule(holiday_index, local_start_time, local_end_time, operating_mode)
}
0x12 => {
let holiday_index = crate::clusters::codec::json_util::get_u8(args, "holiday_index")?;
encode_get_holiday_schedule(holiday_index)
}
0x13 => {
let holiday_index = crate::clusters::codec::json_util::get_u8(args, "holiday_index")?;
encode_clear_holiday_schedule(holiday_index)
}
0x1A => {
let operation_type = {
let n = crate::clusters::codec::json_util::get_u64(args, "operation_type")?;
DataOperationType::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid DataOperationType: {}", n))?
};
let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
let user_name = crate::clusters::codec::json_util::get_opt_string(args, "user_name")?;
let user_unique_id = crate::clusters::codec::json_util::get_opt_u32(args, "user_unique_id")?;
let user_status = crate::clusters::codec::json_util::get_opt_u64(args, "user_status")?
.and_then(|n| UserStatus::from_u8(n as u8));
let user_type = crate::clusters::codec::json_util::get_opt_u64(args, "user_type")?
.and_then(|n| UserType::from_u8(n as u8));
let credential_rule = crate::clusters::codec::json_util::get_opt_u64(args, "credential_rule")?
.and_then(|n| CredentialRule::from_u8(n as u8));
encode_set_user(operation_type, user_index, user_name, user_unique_id, user_status, user_type, credential_rule)
}
0x1B => {
let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
encode_get_user(user_index)
}
0x1D => {
let user_index = crate::clusters::codec::json_util::get_u16(args, "user_index")?;
encode_clear_user(user_index)
}
0x22 => Err(anyhow::anyhow!("command \"SetCredential\" has complex args: use raw mode")),
0x24 => Err(anyhow::anyhow!("command \"GetCredentialStatus\" has complex args: use raw mode")),
0x26 => Err(anyhow::anyhow!("command \"ClearCredential\" has complex args: use raw mode")),
0x27 => {
let pin_code = crate::clusters::codec::json_util::get_opt_octstr(args, "pin_code")?;
encode_unbolt_door(pin_code)
}
0x28 => {
let signing_key = crate::clusters::codec::json_util::get_octstr(args, "signing_key")?;
let verification_key = crate::clusters::codec::json_util::get_octstr(args, "verification_key")?;
let group_identifier = crate::clusters::codec::json_util::get_octstr(args, "group_identifier")?;
let group_resolving_key = crate::clusters::codec::json_util::get_octstr(args, "group_resolving_key")?;
encode_set_aliro_reader_config(signing_key, verification_key, group_identifier, group_resolving_key)
}
0x29 => Ok(vec![]),
_ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
}
}
#[derive(Debug, serde::Serialize)]
pub struct GetWeekDayScheduleResponse {
pub week_day_index: Option<u8>,
pub user_index: Option<u16>,
pub status: Option<u8>,
pub days_mask: Option<DaysMask>,
pub start_hour: Option<u8>,
pub start_minute: Option<u8>,
pub end_hour: Option<u8>,
pub end_minute: Option<u8>,
}
#[derive(Debug, serde::Serialize)]
pub struct GetYearDayScheduleResponse {
pub year_day_index: Option<u8>,
pub user_index: Option<u16>,
pub status: Option<u8>,
pub local_start_time: Option<u64>,
pub local_end_time: Option<u64>,
}
#[derive(Debug, serde::Serialize)]
pub struct GetHolidayScheduleResponse {
pub holiday_index: Option<u8>,
pub status: Option<u8>,
pub local_start_time: Option<u64>,
pub local_end_time: Option<u64>,
pub operating_mode: Option<OperatingMode>,
}
#[derive(Debug, serde::Serialize)]
pub struct GetUserResponse {
pub user_index: Option<u16>,
pub user_name: Option<String>,
pub user_unique_id: Option<u32>,
pub user_status: Option<UserStatus>,
pub user_type: Option<UserType>,
pub credential_rule: Option<CredentialRule>,
pub credentials: Option<Vec<Credential>>,
pub creator_fabric_index: Option<u8>,
pub last_modified_fabric_index: Option<u8>,
pub next_user_index: Option<u16>,
}
#[derive(Debug, serde::Serialize)]
pub struct SetCredentialResponse {
pub status: Option<u8>,
pub user_index: Option<u16>,
pub next_credential_index: Option<u16>,
}
#[derive(Debug, serde::Serialize)]
pub struct GetCredentialStatusResponse {
pub credential_exists: Option<bool>,
pub user_index: Option<u16>,
pub creator_fabric_index: Option<u8>,
pub last_modified_fabric_index: Option<u8>,
pub next_credential_index: Option<u16>,
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub credential_data: Option<Vec<u8>>,
}
pub fn decode_get_week_day_schedule_response(inp: &tlv::TlvItemValue) -> anyhow::Result<GetWeekDayScheduleResponse> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(GetWeekDayScheduleResponse {
week_day_index: item.get_int(&[0]).map(|v| v as u8),
user_index: item.get_int(&[1]).map(|v| v as u16),
status: item.get_int(&[2]).map(|v| v as u8),
days_mask: item.get_int(&[3]).map(|v| v as u8),
start_hour: item.get_int(&[4]).map(|v| v as u8),
start_minute: item.get_int(&[5]).map(|v| v as u8),
end_hour: item.get_int(&[6]).map(|v| v as u8),
end_minute: item.get_int(&[7]).map(|v| v as u8),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_get_year_day_schedule_response(inp: &tlv::TlvItemValue) -> anyhow::Result<GetYearDayScheduleResponse> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(GetYearDayScheduleResponse {
year_day_index: item.get_int(&[0]).map(|v| v as u8),
user_index: item.get_int(&[1]).map(|v| v as u16),
status: item.get_int(&[2]).map(|v| v as u8),
local_start_time: item.get_int(&[3]),
local_end_time: item.get_int(&[4]),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_get_holiday_schedule_response(inp: &tlv::TlvItemValue) -> anyhow::Result<GetHolidayScheduleResponse> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(GetHolidayScheduleResponse {
holiday_index: item.get_int(&[0]).map(|v| v as u8),
status: item.get_int(&[1]).map(|v| v as u8),
local_start_time: item.get_int(&[2]),
local_end_time: item.get_int(&[3]),
operating_mode: item.get_int(&[4]).and_then(|v| OperatingMode::from_u8(v as u8)),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_get_user_response(inp: &tlv::TlvItemValue) -> anyhow::Result<GetUserResponse> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(GetUserResponse {
user_index: item.get_int(&[0]).map(|v| v as u16),
user_name: item.get_string_owned(&[1]),
user_unique_id: item.get_int(&[2]).map(|v| v as u32),
user_status: item.get_int(&[3]).and_then(|v| UserStatus::from_u8(v as u8)),
user_type: item.get_int(&[4]).and_then(|v| UserType::from_u8(v as u8)),
credential_rule: item.get_int(&[5]).and_then(|v| CredentialRule::from_u8(v as u8)),
credentials: {
if let Some(tlv::TlvItemValue::List(l)) = item.get(&[6]) {
let mut items = Vec::new();
for list_item in l {
items.push(Credential {
credential_type: list_item.get_int(&[0]).and_then(|v| CredentialType::from_u8(v as u8)),
credential_index: list_item.get_int(&[1]).map(|v| v as u16),
});
}
Some(items)
} else {
None
}
},
creator_fabric_index: item.get_int(&[7]).map(|v| v as u8),
last_modified_fabric_index: item.get_int(&[8]).map(|v| v as u8),
next_user_index: item.get_int(&[9]).map(|v| v as u16),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_set_credential_response(inp: &tlv::TlvItemValue) -> anyhow::Result<SetCredentialResponse> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(SetCredentialResponse {
status: item.get_int(&[0]).map(|v| v as u8),
user_index: item.get_int(&[1]).map(|v| v as u16),
next_credential_index: item.get_int(&[2]).map(|v| v as u16),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_get_credential_status_response(inp: &tlv::TlvItemValue) -> anyhow::Result<GetCredentialStatusResponse> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(GetCredentialStatusResponse {
credential_exists: item.get_bool(&[0]),
user_index: item.get_int(&[1]).map(|v| v as u16),
creator_fabric_index: item.get_int(&[2]).map(|v| v as u8),
last_modified_fabric_index: item.get_int(&[3]).map(|v| v as u8),
next_credential_index: item.get_int(&[4]).map(|v| v as u16),
credential_data: item.get_octet_string_owned(&[5]),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub async fn lock_door(conn: &crate::controller::Connection, endpoint: u16, pin_code: Option<Vec<u8>>) -> anyhow::Result<()> {
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?;
Ok(())
}
pub async fn unlock_door(conn: &crate::controller::Connection, endpoint: u16, pin_code: Option<Vec<u8>>) -> anyhow::Result<()> {
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?;
Ok(())
}
pub async fn toggle(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_TOGGLE, &[]).await?;
Ok(())
}
pub async fn unlock_with_timeout(conn: &crate::controller::Connection, endpoint: u16, timeout: u16, pin_code: Option<Vec<u8>>) -> anyhow::Result<()> {
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?;
Ok(())
}
pub 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<()> {
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?;
Ok(())
}
pub async fn get_week_day_schedule(conn: &crate::controller::Connection, endpoint: u16, week_day_index: u8, user_index: u16) -> anyhow::Result<GetWeekDayScheduleResponse> {
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?;
decode_get_week_day_schedule_response(&tlv)
}
pub async fn clear_week_day_schedule(conn: &crate::controller::Connection, endpoint: u16, week_day_index: u8, user_index: u16) -> anyhow::Result<()> {
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?;
Ok(())
}
pub 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<()> {
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?;
Ok(())
}
pub async fn get_year_day_schedule(conn: &crate::controller::Connection, endpoint: u16, year_day_index: u8, user_index: u16) -> anyhow::Result<GetYearDayScheduleResponse> {
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?;
decode_get_year_day_schedule_response(&tlv)
}
pub async fn clear_year_day_schedule(conn: &crate::controller::Connection, endpoint: u16, year_day_index: u8, user_index: u16) -> anyhow::Result<()> {
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?;
Ok(())
}
pub 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<()> {
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?;
Ok(())
}
pub async fn get_holiday_schedule(conn: &crate::controller::Connection, endpoint: u16, holiday_index: u8) -> anyhow::Result<GetHolidayScheduleResponse> {
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?;
decode_get_holiday_schedule_response(&tlv)
}
pub async fn clear_holiday_schedule(conn: &crate::controller::Connection, endpoint: u16, holiday_index: u8) -> anyhow::Result<()> {
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?;
Ok(())
}
pub 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<()> {
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?;
Ok(())
}
pub async fn get_user(conn: &crate::controller::Connection, endpoint: u16, user_index: u16) -> anyhow::Result<GetUserResponse> {
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?;
decode_get_user_response(&tlv)
}
pub async fn clear_user(conn: &crate::controller::Connection, endpoint: u16, user_index: u16) -> anyhow::Result<()> {
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?;
Ok(())
}
pub 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> {
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?;
decode_set_credential_response(&tlv)
}
pub async fn get_credential_status(conn: &crate::controller::Connection, endpoint: u16, credential: Credential) -> anyhow::Result<GetCredentialStatusResponse> {
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?;
decode_get_credential_status_response(&tlv)
}
pub async fn clear_credential(conn: &crate::controller::Connection, endpoint: u16, credential: Option<Credential>) -> anyhow::Result<()> {
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?;
Ok(())
}
pub async fn unbolt_door(conn: &crate::controller::Connection, endpoint: u16, pin_code: Option<Vec<u8>>) -> anyhow::Result<()> {
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?;
Ok(())
}
pub 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<()> {
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?;
Ok(())
}
pub async fn clear_aliro_reader_config(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_CMD_ID_CLEARALIROREADERCONFIG, &[]).await?;
Ok(())
}
pub async fn read_lock_state(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<LockState>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_LOCKSTATE).await?;
decode_lock_state(&tlv)
}
pub async fn read_lock_type(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<LockType> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_LOCKTYPE).await?;
decode_lock_type(&tlv)
}
pub async fn read_actuator_enabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ACTUATORENABLED).await?;
decode_actuator_enabled(&tlv)
}
pub async fn read_door_state(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<DoorState>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_DOORSTATE).await?;
decode_door_state(&tlv)
}
pub async fn read_door_open_events(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_DOOROPENEVENTS).await?;
decode_door_open_events(&tlv)
}
pub async fn read_door_closed_events(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_DOORCLOSEDEVENTS).await?;
decode_door_closed_events(&tlv)
}
pub async fn read_open_period(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_OPENPERIOD).await?;
decode_open_period(&tlv)
}
pub async fn read_number_of_total_users_supported(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFTOTALUSERSSUPPORTED).await?;
decode_number_of_total_users_supported(&tlv)
}
pub async fn read_number_of_pin_users_supported(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFPINUSERSSUPPORTED).await?;
decode_number_of_pin_users_supported(&tlv)
}
pub async fn read_number_of_rfid_users_supported(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFRFIDUSERSSUPPORTED).await?;
decode_number_of_rfid_users_supported(&tlv)
}
pub async fn read_number_of_week_day_schedules_supported_per_user(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFWEEKDAYSCHEDULESSUPPORTEDPERUSER).await?;
decode_number_of_week_day_schedules_supported_per_user(&tlv)
}
pub async fn read_number_of_year_day_schedules_supported_per_user(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFYEARDAYSCHEDULESSUPPORTEDPERUSER).await?;
decode_number_of_year_day_schedules_supported_per_user(&tlv)
}
pub async fn read_number_of_holiday_schedules_supported(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFHOLIDAYSCHEDULESSUPPORTED).await?;
decode_number_of_holiday_schedules_supported(&tlv)
}
pub async fn read_max_pin_code_length(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_MAXPINCODELENGTH).await?;
decode_max_pin_code_length(&tlv)
}
pub async fn read_min_pin_code_length(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_MINPINCODELENGTH).await?;
decode_min_pin_code_length(&tlv)
}
pub async fn read_max_rfid_code_length(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_MAXRFIDCODELENGTH).await?;
decode_max_rfid_code_length(&tlv)
}
pub async fn read_min_rfid_code_length(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_MINRFIDCODELENGTH).await?;
decode_min_rfid_code_length(&tlv)
}
pub async fn read_credential_rules_support(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<CredentialRules> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_CREDENTIALRULESSUPPORT).await?;
decode_credential_rules_support(&tlv)
}
pub async fn read_number_of_credentials_supported_per_user(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFCREDENTIALSSUPPORTEDPERUSER).await?;
decode_number_of_credentials_supported_per_user(&tlv)
}
pub async fn read_language(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_LANGUAGE).await?;
decode_language(&tlv)
}
pub async fn read_led_settings(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<LEDSetting> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_LEDSETTINGS).await?;
decode_led_settings(&tlv)
}
pub async fn read_auto_relock_time(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_AUTORELOCKTIME).await?;
decode_auto_relock_time(&tlv)
}
pub async fn read_sound_volume(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<SoundVolume> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_SOUNDVOLUME).await?;
decode_sound_volume(&tlv)
}
pub async fn read_operating_mode(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<OperatingMode> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_OPERATINGMODE).await?;
decode_operating_mode(&tlv)
}
pub async fn read_supported_operating_modes(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<OperatingModes> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_SUPPORTEDOPERATINGMODES).await?;
decode_supported_operating_modes(&tlv)
}
pub async fn read_default_configuration_register(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ConfigurationRegister> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_DEFAULTCONFIGURATIONREGISTER).await?;
decode_default_configuration_register(&tlv)
}
pub async fn read_enable_local_programming(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ENABLELOCALPROGRAMMING).await?;
decode_enable_local_programming(&tlv)
}
pub async fn read_enable_one_touch_locking(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ENABLEONETOUCHLOCKING).await?;
decode_enable_one_touch_locking(&tlv)
}
pub async fn read_enable_inside_status_led(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ENABLEINSIDESTATUSLED).await?;
decode_enable_inside_status_led(&tlv)
}
pub async fn read_enable_privacy_mode_button(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ENABLEPRIVACYMODEBUTTON).await?;
decode_enable_privacy_mode_button(&tlv)
}
pub async fn read_local_programming_features(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<LocalProgrammingFeatures> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_LOCALPROGRAMMINGFEATURES).await?;
decode_local_programming_features(&tlv)
}
pub async fn read_wrong_code_entry_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_WRONGCODEENTRYLIMIT).await?;
decode_wrong_code_entry_limit(&tlv)
}
pub async fn read_user_code_temporary_disable_time(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_USERCODETEMPORARYDISABLETIME).await?;
decode_user_code_temporary_disable_time(&tlv)
}
pub async fn read_send_pin_over_the_air(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_SENDPINOVERTHEAIR).await?;
decode_send_pin_over_the_air(&tlv)
}
pub async fn read_require_pinfor_remote_operation(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_REQUIREPINFORREMOTEOPERATION).await?;
decode_require_pinfor_remote_operation(&tlv)
}
pub async fn read_security_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_SECURITYLEVEL).await?;
decode_security_level(&tlv)
}
pub async fn read_expiring_user_timeout(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_EXPIRINGUSERTIMEOUT).await?;
decode_expiring_user_timeout(&tlv)
}
pub async fn read_aliro_reader_verification_key(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<Vec<u8>>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROREADERVERIFICATIONKEY).await?;
decode_aliro_reader_verification_key(&tlv)
}
pub async fn read_aliro_reader_group_identifier(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<Vec<u8>>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROREADERGROUPIDENTIFIER).await?;
decode_aliro_reader_group_identifier(&tlv)
}
pub async fn read_aliro_reader_group_sub_identifier(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<u8>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROREADERGROUPSUBIDENTIFIER).await?;
decode_aliro_reader_group_sub_identifier(&tlv)
}
pub async fn read_aliro_expedited_transaction_supported_protocol_versions(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<Vec<u8>>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROEXPEDITEDTRANSACTIONSUPPORTEDPROTOCOLVERSIONS).await?;
decode_aliro_expedited_transaction_supported_protocol_versions(&tlv)
}
pub async fn read_aliro_group_resolving_key(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<Vec<u8>>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROGROUPRESOLVINGKEY).await?;
decode_aliro_group_resolving_key(&tlv)
}
pub async fn read_aliro_supported_bleuwb_protocol_versions(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<Vec<u8>>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROSUPPORTEDBLEUWBPROTOCOLVERSIONS).await?;
decode_aliro_supported_bleuwb_protocol_versions(&tlv)
}
pub async fn read_aliro_ble_advertising_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_ALIROBLEADVERTISINGVERSION).await?;
decode_aliro_ble_advertising_version(&tlv)
}
pub async fn read_number_of_aliro_credential_issuer_keys_supported(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFALIROCREDENTIALISSUERKEYSSUPPORTED).await?;
decode_number_of_aliro_credential_issuer_keys_supported(&tlv)
}
pub async fn read_number_of_aliro_endpoint_keys_supported(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_DOOR_LOCK, crate::clusters::defs::CLUSTER_DOOR_LOCK_ATTR_ID_NUMBEROFALIROENDPOINTKEYSSUPPORTED).await?;
decode_number_of_aliro_endpoint_keys_supported(&tlv)
}
#[derive(Debug, serde::Serialize)]
pub struct DoorLockAlarmEvent {
pub alarm_code: Option<AlarmCode>,
}
#[derive(Debug, serde::Serialize)]
pub struct DoorStateChangeEvent {
pub door_state: Option<DoorState>,
}
#[derive(Debug, serde::Serialize)]
pub struct LockOperationEvent {
pub lock_operation_type: Option<LockOperationType>,
pub operation_source: Option<OperationSource>,
pub user_index: Option<u16>,
pub fabric_index: Option<u8>,
pub source_node: Option<u64>,
pub credentials: Option<Vec<Credential>>,
}
#[derive(Debug, serde::Serialize)]
pub struct LockOperationErrorEvent {
pub lock_operation_type: Option<LockOperationType>,
pub operation_source: Option<OperationSource>,
pub operation_error: Option<OperationError>,
pub user_index: Option<u16>,
pub fabric_index: Option<u8>,
pub source_node: Option<u64>,
pub credentials: Option<Vec<Credential>>,
}
#[derive(Debug, serde::Serialize)]
pub struct LockUserChangeEvent {
pub lock_data_type: Option<LockDataType>,
pub data_operation_type: Option<DataOperationType>,
pub operation_source: Option<OperationSource>,
pub user_index: Option<u16>,
pub fabric_index: Option<u8>,
pub source_node: Option<u64>,
pub data_index: Option<u16>,
}
pub fn decode_door_lock_alarm_event(inp: &tlv::TlvItemValue) -> anyhow::Result<DoorLockAlarmEvent> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(DoorLockAlarmEvent {
alarm_code: item.get_int(&[0]).and_then(|v| AlarmCode::from_u8(v as u8)),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_door_state_change_event(inp: &tlv::TlvItemValue) -> anyhow::Result<DoorStateChangeEvent> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(DoorStateChangeEvent {
door_state: item.get_int(&[0]).and_then(|v| DoorState::from_u8(v as u8)),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_lock_operation_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LockOperationEvent> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(LockOperationEvent {
lock_operation_type: item.get_int(&[0]).and_then(|v| LockOperationType::from_u8(v as u8)),
operation_source: item.get_int(&[1]).and_then(|v| OperationSource::from_u8(v as u8)),
user_index: item.get_int(&[2]).map(|v| v as u16),
fabric_index: item.get_int(&[3]).map(|v| v as u8),
source_node: item.get_int(&[4]),
credentials: {
if let Some(tlv::TlvItemValue::List(l)) = item.get(&[5]) {
let mut items = Vec::new();
for list_item in l {
items.push(Credential {
credential_type: list_item.get_int(&[0]).and_then(|v| CredentialType::from_u8(v as u8)),
credential_index: list_item.get_int(&[1]).map(|v| v as u16),
});
}
Some(items)
} else {
None
}
},
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_lock_operation_error_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LockOperationErrorEvent> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(LockOperationErrorEvent {
lock_operation_type: item.get_int(&[0]).and_then(|v| LockOperationType::from_u8(v as u8)),
operation_source: item.get_int(&[1]).and_then(|v| OperationSource::from_u8(v as u8)),
operation_error: item.get_int(&[2]).and_then(|v| OperationError::from_u8(v as u8)),
user_index: item.get_int(&[3]).map(|v| v as u16),
fabric_index: item.get_int(&[4]).map(|v| v as u8),
source_node: item.get_int(&[5]),
credentials: {
if let Some(tlv::TlvItemValue::List(l)) = item.get(&[6]) {
let mut items = Vec::new();
for list_item in l {
items.push(Credential {
credential_type: list_item.get_int(&[0]).and_then(|v| CredentialType::from_u8(v as u8)),
credential_index: list_item.get_int(&[1]).map(|v| v as u16),
});
}
Some(items)
} else {
None
}
},
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_lock_user_change_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LockUserChangeEvent> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(LockUserChangeEvent {
lock_data_type: item.get_int(&[0]).and_then(|v| LockDataType::from_u8(v as u8)),
data_operation_type: item.get_int(&[1]).and_then(|v| DataOperationType::from_u8(v as u8)),
operation_source: item.get_int(&[2]).and_then(|v| OperationSource::from_u8(v as u8)),
user_index: item.get_int(&[3]).map(|v| v as u16),
fabric_index: item.get_int(&[4]).map(|v| v as u8),
source_node: item.get_int(&[5]),
data_index: item.get_int(&[6]).map(|v| v as u16),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}