From 6fd7d1d584f39c42f5b2ad846e853ab74e183c14 Mon Sep 17 00:00:00 2001 From: jhongturney Date: Wed, 7 Aug 2024 08:20:26 -0500 Subject: [PATCH 1/4] adding T85L0, patterned after T8506 --- docs/_media/smartlock_t85l0_small.jpg | Bin 0 -> 30060 bytes docs/supported_devices.md | 1 + src/eufysecurity.ts | 6 ++-- src/http/device.ts | 15 ++++++-- src/http/station.ts | 50 +++++++++++++------------- src/http/types.ts | 36 +++++++++++++++++++ src/p2p/session.ts | 2 +- 7 files changed, 79 insertions(+), 31 deletions(-) create mode 100644 docs/_media/smartlock_t85l0_small.jpg diff --git a/docs/_media/smartlock_t85l0_small.jpg b/docs/_media/smartlock_t85l0_small.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9719e47f11436c5e6ca98af1eb1f462628e04a88 GIT binary patch literal 30060 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 { } } this.getStationDevice(station.getSerial(), result.channel).then((device: Device) => { - if ((result.customData !== undefined && result.customData.property !== undefined && !device.isLockWifiR10() && !device.isLockWifiR20() && !device.isSmartSafe() && !device.isLockWifiT8506() && !device.isLockWifiT8502() && !device.isLockWifiT8510P() && !device.isLockWifiT8520P()) || + if ((result.customData !== undefined && result.customData.property !== undefined && !device.isLockWifiR10() && !device.isLockWifiR20() && !device.isSmartSafe() && !device.isLockWifiT8506() && !device.isLockWifiT8502() && !device.isLockWifiT8510P() && !device.isLockWifiT8520P() && !device.isLockWifiT85L0()) || (result.customData !== undefined && result.customData.property !== undefined && device.isSmartSafe() && result.command_type !== CommandType.CMD_SMARTSAFE_SETTINGS) || - (result.customData !== undefined && result.customData.property !== undefined && (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) && result.command_type !== CommandType.CMD_DOORLOCK_SET_PUSH_MODE)) { + (result.customData !== undefined && result.customData.property !== undefined && (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) && result.command_type !== CommandType.CMD_DOORLOCK_SET_PUSH_MODE)) { if (device.hasProperty(result.customData.property.name)) { const metadata = device.getPropertyMetadata(result.customData.property.name); if (typeof result.customData.property.value !== "object" || metadata.type === "object") { @@ -2473,7 +2473,7 @@ export class EufySecurity extends TypedEmitter { let found = false; for (const user of users) { if (user.user_name === username) { - if ((device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) && user.password_list.length > 0) { + if ((device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) && user.password_list.length > 0) { for (const entry of user.password_list) { if (entry.password_type === UserPasswordType.PIN) { let schedule = entry.schedule; diff --git a/src/http/device.ts b/src/http/device.ts index 5425421..a38c0b9 100644 --- a/src/http/device.ts +++ b/src/http/device.ts @@ -1033,6 +1033,7 @@ export class Device extends TypedEmitter { type == DeviceType.LOCK_85A3 || type == DeviceType.LOCK_8506 || type == DeviceType.LOCK_8502 || + type == DeviceType.LOCK_85L0 || type == DeviceType.SMART_SAFE_7400 || type == DeviceType.SMART_SAFE_7401 || type == DeviceType.SMART_SAFE_7402 || @@ -1176,7 +1177,8 @@ export class Device extends TypedEmitter { Device.isLockWifiR20(type) || Device.isLockWifiVideo(type) || Device.isLockWifiT8506(type) || - Device.isLockWifiT8502(type); + Device.isLockWifiT8502(type) || + Device.isLockWifiT85L0(type); } static isLockKeypad(type: number): boolean { @@ -1239,6 +1241,10 @@ export class Device extends TypedEmitter { return false; } + static isLockWifiT85L0(type: number): boolean { + return DeviceType.LOCK_85L0 == type; + } + static isBatteryDoorbell1(type: number): boolean { return DeviceType.BATTERY_DOORBELL == type; } @@ -1443,7 +1449,8 @@ export class Device extends TypedEmitter { sn.startsWith("T8502") || sn.startsWith("T8504") || sn.startsWith("T8506") || - sn.startsWith("T8530"); + sn.startsWith("T8530") || + sn.startsWith("T85L0"); } static isGarageCameraBySn(sn: string): boolean { @@ -1598,6 +1605,10 @@ export class Device extends TypedEmitter { return Device.isLockWifiT8520P(this.rawDevice.device_type, this.rawDevice.device_sn); } + public isLockWifiT85L0(): boolean { + return Device.isLockWifiT85L0(this.rawDevice.device_type); + } + public isBatteryDoorbell1(): boolean { return Device.isBatteryDoorbell1(this.rawDevice.device_type); } diff --git a/src/http/station.ts b/src/http/station.ts index 00a606c..b852d49 100644 --- a/src/http/station.ts +++ b/src/http/station.ts @@ -109,7 +109,7 @@ export class Station extends TypedEmitter { static async getInstance(api: HTTPApi, stationData: StationListResponse, ipAddress?: string): Promise { let publicKey: string | undefined; - if (Device.isLock(stationData.device_type) && !Device.isLockWifiT8506(stationData.device_type) && !Device.isLockWifiT8502(stationData.device_type) && !Device.isLockWifiT8510P(stationData.device_type, stationData.station_sn) && !Device.isLockWifiT8520P(stationData.device_type, stationData.station_sn)) { + if (Device.isLock(stationData.device_type) && !Device.isLockWifiT8506(stationData.device_type) && !Device.isLockWifiT8502(stationData.device_type) && !Device.isLockWifiT8510P(stationData.device_type, stationData.station_sn) && !Device.isLockWifiT8520P(stationData.device_type, stationData.station_sn) && !Device.isLockWifiT85L0(stationData.device_type)) { publicKey = await api.getPublicKey(stationData.station_sn, PublicKeyType.LOCK); } return new Station(api, stationData, ipAddress, publicKey); @@ -5233,7 +5233,7 @@ export class Station extends TypedEmitter { this._sendLockV12P2PCommand(command, { property: propertyData }); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { const command = getSmartLockP2PCommand( this.rawStation.station_sn, this.rawStation.member.admin_user_id, @@ -6268,7 +6268,7 @@ export class Station extends TypedEmitter { command: commandData }); rootHTTPLogger.debug("Station calibrate lock - Calibrate lock...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id }); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { const command = getSmartLockP2PCommand( this.rawStation.station_sn, this.rawStation.member.admin_user_id, @@ -7886,7 +7886,7 @@ export class Station extends TypedEmitter { this.setAdvancedLockParams(device, PropertyName.DeviceScramblePasscode, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { this.setLockV12Params(device, PropertyName.DeviceScramblePasscode, value); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { this.setSmartLockParams(device, PropertyName.DeviceScramblePasscode, value); } else if (device.isSmartSafe()) { this.setSmartSafeParams(device, PropertyName.DeviceScramblePasscode, value); @@ -7911,7 +7911,7 @@ export class Station extends TypedEmitter { this.setAdvancedLockParams(device, PropertyName.DeviceWrongTryProtection, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { this.setLockV12Params(device, PropertyName.DeviceWrongTryProtection, value); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { this.setSmartLockParams(device, PropertyName.DeviceWrongTryProtection, value); } else if (device.isSmartSafe()) { this.setSmartSafeParams(device, PropertyName.DeviceWrongTryProtection, value); @@ -7936,7 +7936,7 @@ export class Station extends TypedEmitter { this.setAdvancedLockParams(device, PropertyName.DeviceWrongTryAttempts, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { this.setLockV12Params(device, PropertyName.DeviceWrongTryAttempts, value); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { this.setSmartLockParams(device, PropertyName.DeviceWrongTryAttempts, value); } else if (device.isSmartSafe()) { this.setSmartSafeParams(device, PropertyName.DeviceWrongTryAttempts, value); @@ -7961,7 +7961,7 @@ export class Station extends TypedEmitter { this.setAdvancedLockParams(device, PropertyName.DeviceWrongTryLockdownTime, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { this.setLockV12Params(device, PropertyName.DeviceWrongTryLockdownTime, value); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { this.setSmartLockParams(device, PropertyName.DeviceWrongTryLockdownTime, value); } else if (device.isSmartSafe()) { this.setSmartSafeParams(device, PropertyName.DeviceWrongTryLockdownTime, value); @@ -8401,7 +8401,7 @@ export class Station extends TypedEmitter { }, { command: commandData }); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { const command = getSmartLockP2PCommand( this.rawStation.station_sn, this.rawStation.member.admin_user_id, @@ -8493,7 +8493,7 @@ export class Station extends TypedEmitter { }, { command: commandData }); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { const command = getSmartLockP2PCommand( this.rawStation.station_sn, this.rawStation.member.admin_user_id, @@ -8593,7 +8593,7 @@ export class Station extends TypedEmitter { }, { command: commandData }); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { const command = getSmartLockP2PCommand( this.rawStation.station_sn, this.rawStation.member.admin_user_id, @@ -8690,7 +8690,7 @@ export class Station extends TypedEmitter { }, { command: commandData }); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { const command = getSmartLockP2PCommand( this.rawStation.station_sn, this.rawStation.member.admin_user_id, @@ -8838,7 +8838,7 @@ export class Station extends TypedEmitter { validValue(propertyMetadata, value); rootHTTPLogger.debug(`Station set smart lock settings - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), property: property, value: value }); - if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { let payload: Buffer; switch (property) { case PropertyName.DeviceWrongTryProtection: @@ -8972,7 +8972,7 @@ export class Station extends TypedEmitter { this.setAdvancedLockParams(device, PropertyName.DeviceAutoLock, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { this.setLockV12Params(device, PropertyName.DeviceAutoLock, value); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { this.setSmartLockParams(device, PropertyName.DeviceAutoLock, value); } else { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); @@ -8995,7 +8995,7 @@ export class Station extends TypedEmitter { this.setAdvancedLockParams(device, PropertyName.DeviceAutoLockSchedule, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { this.setLockV12Params(device, PropertyName.DeviceAutoLockSchedule, value); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { this.setSmartLockParams(device, PropertyName.DeviceAutoLockSchedule, value); } else { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); @@ -9018,7 +9018,7 @@ export class Station extends TypedEmitter { this.setAdvancedLockParams(device, PropertyName.DeviceAutoLockScheduleStartTime, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { this.setLockV12Params(device, PropertyName.DeviceAutoLockScheduleStartTime, value); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { this.setSmartLockParams(device, PropertyName.DeviceAutoLockScheduleStartTime, value); } else { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); @@ -9041,7 +9041,7 @@ export class Station extends TypedEmitter { this.setAdvancedLockParams(device, PropertyName.DeviceAutoLockScheduleEndTime, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { this.setLockV12Params(device, PropertyName.DeviceAutoLockScheduleEndTime, value); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { this.setSmartLockParams(device, PropertyName.DeviceAutoLockScheduleEndTime, value); } else { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); @@ -9064,7 +9064,7 @@ export class Station extends TypedEmitter { this.setAdvancedLockParams(device, PropertyName.DeviceAutoLockTimer, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { this.setLockV12Params(device, PropertyName.DeviceAutoLockTimer, value); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { this.setSmartLockParams(device, PropertyName.DeviceAutoLockTimer, value); } else { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); @@ -9087,7 +9087,7 @@ export class Station extends TypedEmitter { this.setAdvancedLockParams(device, PropertyName.DeviceOneTouchLocking, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { this.setLockV12Params(device, PropertyName.DeviceOneTouchLocking, value); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { this.setSmartLockParams(device, PropertyName.DeviceOneTouchLocking, value); } else { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); @@ -9110,7 +9110,7 @@ export class Station extends TypedEmitter { this.setAdvancedLockParams(device, PropertyName.DeviceSound, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { this.setLockV12Params(device, PropertyName.DeviceSound, value); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { this.setSmartLockParams(device, PropertyName.DeviceSound, value); } else { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); @@ -9142,7 +9142,7 @@ export class Station extends TypedEmitter { }, { property: propertyData }); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiR10() || device.isLockWifiR20()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0() || device.isLockWifiR10() || device.isLockWifiR20()) { let oldvalue = 0; const rawproperty = device.getRawProperty(CommandType.CMD_DOORLOCK_SET_PUSH_MODE); if (rawproperty !== undefined) { @@ -9189,7 +9189,7 @@ export class Station extends TypedEmitter { rootHTTPLogger.debug(`Station set notification locked - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger() || device.isLockWifiVideo()) { this.setAdvancedLockParams(device, PropertyName.DeviceNotificationLocked, value); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiR10() || device.isLockWifiR20()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0() || device.isLockWifiR10() || device.isLockWifiR20()) { let oldvalue = 0; const rawproperty = device.getRawProperty(CommandType.CMD_DOORLOCK_SET_PUSH_MODE); if (rawproperty !== undefined) { @@ -9236,7 +9236,7 @@ export class Station extends TypedEmitter { rootHTTPLogger.debug(`Station set notification unlocked - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger() || device.isLockWifiVideo()) { this.setAdvancedLockParams(device, PropertyName.DeviceNotificationUnlocked, value); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiR10() || device.isLockWifiR20()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0() || device.isLockWifiR10() || device.isLockWifiR20()) { let oldvalue = 0; const rawproperty = device.getRawProperty(CommandType.CMD_DOORLOCK_SET_PUSH_MODE); if (rawproperty !== undefined) { @@ -9365,7 +9365,7 @@ export class Station extends TypedEmitter { }, { command: commandData }); - } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P()) { + } else if (device.isLockWifiT8506() || device.isLockWifiT8502() || device.isLockWifiT8510P() || device.isLockWifiT8520P() || device.isLockWifiT85L0()) { const command = getSmartLockP2PCommand( this.rawStation.station_sn, this.rawStation.member.admin_user_id, @@ -10917,7 +10917,7 @@ export class Station extends TypedEmitter { public getLockParameters(): void { //TODO: Implement support for other Locks - if (Device.isLockWifiT8506(this.getDeviceType()) || Device.isLockWifiT8502(this.getDeviceType()) || Device.isLockWifiT8510P(this.getDeviceType(), this.getSerial()) || Device.isLockWifiT8520P(this.getDeviceType(), this.getSerial())) { + if (Device.isLockWifiT8506(this.getDeviceType()) || Device.isLockWifiT8502(this.getDeviceType()) || Device.isLockWifiT8510P(this.getDeviceType(), this.getSerial()) || Device.isLockWifiT8520P(this.getDeviceType(), this.getSerial()) || Device.isLockWifiT85L0(this.getDeviceType())) { rootHTTPLogger.debug(`Station smart lock send get lock parameters command`, { stationSN: this.getSerial() }); const command = getSmartLockP2PCommand( this.rawStation.station_sn, @@ -10945,7 +10945,7 @@ export class Station extends TypedEmitter { public getLockStatus(): void { //TODO: Implement support for other Locks - if (Device.isLockWifiT8506(this.getDeviceType()) || Device.isLockWifiT8502(this.getDeviceType()) || Device.isLockWifiT8510P(this.getDeviceType(), this.getSerial()) || Device.isLockWifiT8520P(this.getDeviceType(), this.getSerial())) { + if (Device.isLockWifiT8506(this.getDeviceType()) || Device.isLockWifiT8502(this.getDeviceType()) || Device.isLockWifiT8510P(this.getDeviceType(), this.getSerial()) || Device.isLockWifiT8520P(this.getDeviceType(), this.getSerial()) || Device.isLockWifiT85L0(this.getDeviceType())) { rootHTTPLogger.debug(`Station smart lock send get lock status command`, { stationSN: this.getSerial() }); const command = getSmartLockP2PCommand( this.rawStation.station_sn, diff --git a/src/http/types.ts b/src/http/types.ts index 9956655..8406408 100644 --- a/src/http/types.ts +++ b/src/http/types.ts @@ -74,6 +74,7 @@ export enum DeviceType { SMART_TRACK_CARD = 159, //T87B2 LOCK_8502 = 180, LOCK_8506 = 184, + LOCK_85L0 = 185, WALL_LIGHT_CAM_81A0 = 10005, } @@ -1000,6 +1001,7 @@ export const GenericTypeProperty: PropertyMetadataNumeric = { 159: "SmartTrack Card (T87B2)", 180: "Smart Lock C210 (T8502)", 184: "Smart Lock C220 (T8506)", + 185: "Smart Lock C33 (T85L0)", 10005: "Solar Wall Light Cam S120 (T81A0)", }, } @@ -7084,6 +7086,29 @@ export const DeviceProperties: Properties = { [PropertyName.DeviceLockEventOrigin]: DeviceLockEventOriginProperty, [PropertyName.DevicePersonName]: DevicePersonNameProperty, }, + [DeviceType.LOCK_85L0]: { + ...GenericDeviceProperties, + [PropertyName.DeviceBattery]: DeviceBatteryLockProperty, + [PropertyName.DeviceLocked]: DeviceLockedProperty, + [PropertyName.DeviceLockStatus]: DeviceAdvancedLockStatusProperty, + [PropertyName.DeviceAutoLock]: DeviceAutoLockProperty, + [PropertyName.DeviceAutoLockTimer]: DeviceAutoLockTimerProperty, + [PropertyName.DeviceAutoLockSchedule]: DeviceAutoLockScheduleProperty, + [PropertyName.DeviceAutoLockScheduleStartTime]: DeviceAutoLockScheduleStartTimeProperty, + [PropertyName.DeviceAutoLockScheduleEndTime]: DeviceAutoLockScheduleEndTimeProperty, + [PropertyName.DeviceOneTouchLocking]: DeviceOneTouchLockingProperty, + [PropertyName.DeviceWrongTryProtection]: DeviceWrongTryProtectionProperty, + [PropertyName.DeviceWrongTryAttempts]: DeviceWrongTryAttemptsProperty, + [PropertyName.DeviceWrongTryLockdownTime]: DeviceWrongTryLockdownTimeProperty, + [PropertyName.DeviceScramblePasscode]: DeviceScramblePasscodeProperty, + [PropertyName.DeviceSound]: DeviceSoundProperty, + [PropertyName.DeviceNotification]: DeviceNotificationSmartLockProperty, + [PropertyName.DeviceNotificationUnlocked]: DeviceNotificationUnlockedSmartLockProperty, + [PropertyName.DeviceNotificationLocked]: DeviceNotificationLockedSmartLockProperty, + [PropertyName.DeviceLowBatteryAlert]: DeviceLowBatteryAlertProperty, + [PropertyName.DeviceLockEventOrigin]: DeviceLockEventOriginProperty, + [PropertyName.DevicePersonName]: DevicePersonNameProperty, + }, [DeviceType.LOCK_8502]: { ...GenericDeviceProperties, [PropertyName.DeviceBattery]: DeviceBatteryLockProperty, @@ -8540,6 +8565,9 @@ export const StationProperties: Properties = { [DeviceType.LOCK_8506]: { ...BaseStationProperties, }, + [DeviceType.LOCK_85L0]: { + ...BaseStationProperties, + }, [DeviceType.LOCK_8502]: { ...BaseStationProperties, }, @@ -9080,6 +9108,14 @@ export const DeviceCommands: Commands = { CommandName.DeviceUpdateUserSchedule, CommandName.DeviceUpdateUsername, ], + [DeviceType.LOCK_85L0]: [ + CommandName.DeviceLockCalibration, + CommandName.DeviceAddUser, + CommandName.DeviceDeleteUser, + CommandName.DeviceUpdateUserPasscode, + CommandName.DeviceUpdateUserSchedule, + CommandName.DeviceUpdateUsername, + ], [DeviceType.LOCK_8502]: [ CommandName.DeviceLockCalibration, CommandName.DeviceAddUser, diff --git a/src/p2p/session.ts b/src/p2p/session.ts index 33389a9..719445f 100644 --- a/src/p2p/session.ts +++ b/src/p2p/session.ts @@ -1737,7 +1737,7 @@ export class P2PClientProtocol extends TypedEmitter { if (payload.lock_cmd > 0) { if (Device.isLockWifiR10(this.rawStation.devices[0].device_type) || Device.isLockWifiR20(this.rawStation.devices[0].device_type)) { this.emit("sequence error", message.channel, ESLCommand[ESLBleCommand[payload.lock_cmd] as unknown as number] as unknown as number, payload.seq_num, payload.dev_sn); - } else if (Device.isLockWifiT8506(this.rawStation.devices[0].device_type) || Device.isLockWifiT8502(this.rawStation.devices[0].device_type) || Device.isLockWifiT8510P(this.rawStation.devices[0].device_type, this.rawStation.devices[0].device_sn) || Device.isLockWifiT8520P(this.rawStation.devices[0].device_type, this.rawStation.devices[0].device_sn)) { + } else if (Device.isLockWifiT8506(this.rawStation.devices[0].device_type) || Device.isLockWifiT8502(this.rawStation.devices[0].device_type) || Device.isLockWifiT8510P(this.rawStation.devices[0].device_type, this.rawStation.devices[0].device_sn) || Device.isLockWifiT8520P(this.rawStation.devices[0].device_type, this.rawStation.devices[0].device_sn) || Device.isLockWifiT85L0(this.rawStation.devices[0].device_type)) { this.emit("sequence error", message.channel, SmartLockCommand[payload.bus_type! == SmartLockFunctionType.TYPE_2 ? SmartLockBleCommandFunctionType2[payload.lock_cmd] as unknown as number : SmartLockBleCommandFunctionType1[payload.lock_cmd] as unknown as number] as unknown as number, payload.seq_num, payload.dev_sn); } else { rootP2PLogger.debug(`Handle DATA ${P2PDataType[message.dataType]} - CMD_NOTIFY_PAYLOAD - Lock sequence number - Unknwon device`, { stationSN: this.rawStation.station_sn, oldSequenceNumber: this.lockSeqNumber, newSequenceNumber: this.lockSeqNumber + 1, payload: payload }); From 1e75273c76cd2a1175a216523d3a506ecae2680d Mon Sep 17 00:00:00 2001 From: Jason Hong-Turney <32313951+jhongturney@users.noreply.github.com> Date: Sun, 15 Sep 2024 17:04:30 -0700 Subject: [PATCH 2/4] Correcting id number --- src/http/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/http/types.ts b/src/http/types.ts index c03d30e..794e085 100644 --- a/src/http/types.ts +++ b/src/http/types.ts @@ -74,7 +74,7 @@ export enum DeviceType { SMART_TRACK_CARD = 159, //T87B2 LOCK_8502 = 180, LOCK_8506 = 184, - LOCK_85L0 = 185, + LOCK_85L0 = 201, WALL_LIGHT_CAM_81A0 = 10005, } @@ -1001,7 +1001,7 @@ export const GenericTypeProperty: PropertyMetadataNumeric = { 159: "SmartTrack Card (T87B2)", 180: "Smart Lock C210 (T8502)", 184: "Smart Lock C220 (T8506)", - 185: "Smart Lock C33 (T85L0)", + 201: "Smart Lock C33 (T85L0)", 10005: "Solar Wall Light Cam S120 (T81A0)", }, } From b5dc543f99eb1e4d4fc427fc311cf306e0849720 Mon Sep 17 00:00:00 2001 From: jhongturney Date: Thu, 26 Dec 2024 11:58:24 -0600 Subject: [PATCH 3/4] typo fixes --- src/http/device.ts | 6 +++--- src/http/utils.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/http/device.ts b/src/http/device.ts index 562f739..47220a3 100644 --- a/src/http/device.ts +++ b/src/http/device.ts @@ -643,7 +643,7 @@ export class Device extends TypedEmitter { ) && this.isIndoorPanAndTiltCameraS350()) { const booleanProperty = property as PropertyMetadataBoolean; try { - return isIndoorNotitficationEnabled(Number.parseInt(value), property.name === PropertyName.DeviceNotificationAllOtherMotion ? IndoorS350NotificationTypes.ALL_OTHER_MOTION : property.name === PropertyName.DeviceNotificationPerson ? IndoorS350NotificationTypes.HUMAN : property.name === PropertyName.DeviceNotificationPet ? IndoorS350NotificationTypes.PET : property.name === PropertyName.DeviceNotificationCrying ? IndoorS350NotificationTypes.CRYING : IndoorS350NotificationTypes.ALL_SOUND); + return isIndoorNotificationEnabled(Number.parseInt(value), property.name === PropertyName.DeviceNotificationAllOtherMotion ? IndoorS350NotificationTypes.ALL_OTHER_MOTION : property.name === PropertyName.DeviceNotificationPerson ? IndoorS350NotificationTypes.HUMAN : property.name === PropertyName.DeviceNotificationPet ? IndoorS350NotificationTypes.PET : property.name === PropertyName.DeviceNotificationCrying ? IndoorS350NotificationTypes.CRYING : IndoorS350NotificationTypes.ALL_SOUND); } catch (err) { const error = ensureError(err); rootHTTPLogger.error("Device convert raw property - IndoorPanAndTiltCameraS350 notification Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); @@ -657,7 +657,7 @@ export class Device extends TypedEmitter { ) && this.isFloodLightT8425()) { const booleanProperty = property as PropertyMetadataBoolean; try { - return isFloodlightT8425NotitficationEnabled(Number.parseInt(value), property.name === PropertyName.DeviceNotificationAllOtherMotion ? FloodlightT8425NotificationTypes.ALL_OTHER_MOTION : property.name === PropertyName.DeviceNotificationPerson ? FloodlightT8425NotificationTypes.HUMAN : property.name === PropertyName.DeviceNotificationPet ? FloodlightT8425NotificationTypes.PET : FloodlightT8425NotificationTypes.VEHICLE); + return isFloodlightT8425NotificationEnabled(Number.parseInt(value), property.name === PropertyName.DeviceNotificationAllOtherMotion ? FloodlightT8425NotificationTypes.ALL_OTHER_MOTION : property.name === PropertyName.DeviceNotificationPerson ? FloodlightT8425NotificationTypes.HUMAN : property.name === PropertyName.DeviceNotificationPet ? FloodlightT8425NotificationTypes.PET : FloodlightT8425NotificationTypes.VEHICLE); } catch (err) { const error = ensureError(err); rootHTTPLogger.error("Device convert raw property - FloodLightT8425 notification Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); @@ -2206,7 +2206,7 @@ export class Camera extends Device { this.updateProperty(PropertyName.DeviceStrangerPersonDetected, false); this.eventTimeouts.delete(DeviceEvent.StrangerPersonDetected); }, eventDurationSeconds * 1000)); - + if (this.config.simultaneousDetections) { this.updateProperty(PropertyName.DevicePersonDetected, true); this.clearEventTimeout(DeviceEvent.PersonDetected); diff --git a/src/http/utils.ts b/src/http/utils.ts index e8f29b5..6cff811 100644 --- a/src/http/utils.ts +++ b/src/http/utils.ts @@ -683,7 +683,7 @@ export const getIndoorS350DetectionMode = function(value: number, type: IndoorS3 return result; } -export const isIndoorNotitficationEnabled = function(value: number, type: IndoorS350NotificationTypes): boolean { +export const isIndoorNotificationEnabled = function(value: number, type: IndoorS350NotificationTypes): boolean { return (type & value) == type; } @@ -697,7 +697,7 @@ export const getIndoorNotification = function(value: number, type: IndoorS350Not return result; } -export const isFloodlightT8425NotitficationEnabled = function(value: number, type: FloodlightT8425NotificationTypes): boolean { +export const isFloodlightT8425NotificationEnabled = function(value: number, type: FloodlightT8425NotificationTypes): boolean { return (type & value) == type; } From 533ffcfbc89ebbe02390ab65ea48fad209f0ac4f Mon Sep 17 00:00:00 2001 From: jhongturney Date: Thu, 26 Dec 2024 12:01:21 -0600 Subject: [PATCH 4/4] typo fixes --- src/http/device.ts | 2 +- src/p2p/session.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/http/device.ts b/src/http/device.ts index 47220a3..ee28a95 100644 --- a/src/http/device.ts +++ b/src/http/device.ts @@ -6,7 +6,7 @@ import { DeviceListResponse, Voice, GarageDoorSensorsProperty, FloodlightDetecti import { ParameterHelper } from "./parameter"; import { DeviceEvents, PropertyValue, PropertyValues, PropertyMetadataAny, IndexedProperty, RawValues, PropertyMetadataNumeric, PropertyMetadataBoolean, PropertyMetadataString, Schedule, Voices, PropertyMetadataObject, DeviceConfig } from "./interfaces"; import { CommandType, ESLAnkerBleConstant, TrackerCommandType } from "../p2p/types"; -import { calculateCellularSignalLevel, calculateWifiSignalLevel, getAbsoluteFilePath, getDistances, getImagePath, getLockEventType, hexDate, hexTime, hexWeek, isFloodlightT8425NotitficationEnabled, isHB3DetectionModeEnabled, isIndoorNotitficationEnabled, isIndoorS350DetectionModeEnabled, isPrioritySourceType, isSmartLockNotification, isT8170DetectionModeEnabled, loadEventImage, WritePayload } from "./utils"; +import { calculateCellularSignalLevel, calculateWifiSignalLevel, getAbsoluteFilePath, getDistances, getImagePath, getLockEventType, hexDate, hexTime, hexWeek, isFloodlightT8425NotificationEnabled, isHB3DetectionModeEnabled, isIndoorNotificationEnabled, isIndoorS350DetectionModeEnabled, isPrioritySourceType, isSmartLockNotification, isT8170DetectionModeEnabled, loadEventImage, WritePayload } from "./utils"; import { DecimalToRGBColor, eslTimestamp, getCurrentTimeInSeconds, isCharging } from "../p2p/utils"; import { CusPushEvent, DoorbellPushEvent, LockPushEvent, IndoorPushEvent, SmartSafeEvent, HB3PairedDevicePushEvent, GarageDoorPushEvent, SmartDropOpen, SmartDropOpenedBy, SmartDropPushEvent } from "../push/types"; import { PushMessage, SmartSafeEventValueDetail } from "../push/models"; diff --git a/src/p2p/session.ts b/src/p2p/session.ts index 4a81441..eaf7afe 100644 --- a/src/p2p/session.ts +++ b/src/p2p/session.ts @@ -1771,7 +1771,7 @@ export class P2PClientProtocol extends TypedEmitter { } else if (Device.isLockWifiT8506(this.rawStation.devices[0]?.device_type) || Device.isLockWifiT8502(this.rawStation.devices[0]?.device_type) || Device.isLockWifiT8510P(this.rawStation.devices[0]?.device_type, this.rawStation.devices[0]?.device_sn) || Device.isLockWifiT8520P(this.rawStation.devices[0]?.device_type, this.rawStation.devices[0]?.device_sn) || Device.isLockWifiT85L0(this.rawStation.devices[0]?.device_type)) { this.emit("sequence error", message.channel, SmartLockCommand[payload.bus_type! == SmartLockFunctionType.TYPE_2 ? SmartLockBleCommandFunctionType2[payload.lock_cmd] as unknown as number : SmartLockBleCommandFunctionType1[payload.lock_cmd] as unknown as number] as unknown as number, payload.seq_num, payload.dev_sn); } else { - rootP2PLogger.debug(`Handle DATA ${P2PDataType[message.dataType]} - CMD_NOTIFY_PAYLOAD - Lock sequence number - Unknwon device`, { stationSN: this.rawStation.station_sn, oldSequenceNumber: this.lockSeqNumber, newSequenceNumber: this.lockSeqNumber + 1, payload: payload }); + rootP2PLogger.debug(`Handle DATA ${P2PDataType[message.dataType]} - CMD_NOTIFY_PAYLOAD - Lock sequence number - Unknown device`, { stationSN: this.rawStation.station_sn, oldSequenceNumber: this.lockSeqNumber, newSequenceNumber: this.lockSeqNumber + 1, payload: payload }); } } }