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: Vec<u8>) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::OctetString(pin_code)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_unlock_door(pin_code: Vec<u8>) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::OctetString(pin_code)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_unlock_with_timeout(timeout: u16, pin_code: Vec<u8>) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt16(timeout)).into(),
(1, tlv::TlvItemValueEnc::OctetString(pin_code)).into(),
]),
};
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: Vec<u8>) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::OctetString(pin_code)).into(),
]),
};
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"),
]
}
#[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"))
}
}
#[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"))
}
}