From f78e22dbb297ec8bb8145c73dc717cf49037c8e7 Mon Sep 17 00:00:00 2001 From: Joe Dowling <10679867+brozef@users.noreply.github.com> Date: Tue, 2 Apr 2024 12:57:27 +1000 Subject: [PATCH] Lock Adv Data Fixes, Readme Update (#236) --- README.md | 47 +++++++++++++++++++++++++++++++++++++++ src/advertising.ts | 2 +- src/device/wosmartlock.ts | 33 +++++++++++++++------------ 3 files changed, 67 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index a46d80c2..4c5b8f71 100644 --- a/README.md +++ b/README.md @@ -1149,6 +1149,53 @@ Structure of the `serviceData`: --- +### SmartLock (WoSmartLock) + +Example of the advertisement data: + +```json +{ + "id: 'd30864110b8c', + "address": 'd3:08:64:11:0b:8c', + "rssi": -52, + "serviceData": { + "model": "o", + "modelName": "WoSmartLock", + "battery": 100, + "calibration": true, + "status": "LOCKED", + "update_from_secondary_lock": false, + "door_open": false, + "double_lock_mode": false, + "unclosed_alarm": false, + "unlocked_alarm": false, + "auto_lock_paused": false + } +} + +``` + +Structure of the `serviceData`: + +| Property | Type | Description | +| :---------------------------- | :------ | :---------------------------------------------------------------------------------- | +| `model` | String | This value is `"o"`, which means "Lock (WoSmartLock)". | +| `modelName` | String | This value is always `"WoSmartLock"`, which means "Lock". | +| `battery` | Integer | This value indicates the battery level (`1-100`, `%`). | +| `calibration` | Boolean | This value indicates the calibration status (`true` or `false`). | +| `status` | String | This value indicates the current locked state. Possible values: | +| | | `"LOCKED"`, `"UNLOCKED"`, `"LOCKING"`, `"UNLOCKING"` | +| | | `"LOCKING_STOP"`, `"UNLOCKING_STOP"` (stuck when locking or unlocking respectively) | +| | | `"NOT_FULLY_LOCKED"` (eu model only), `"UNKNOWN"` (fallback: must be some error) | +| `update_from_secondary_lock` | Boolean | ?? | +| `door_open` | Boolean | door open status - whether the door is not detecting the sensor magnet | +| `double_lock_mode` | Boolean | dual lock mode enabled status - two locks working simultaneously | +| `unclosed_alarm` | Boolean | enabled status for door ajar alarm function | +| `unlocked_alarm` | Boolean | whether the alarm function is enabled for door left unlocked | +| `auto_lock_paused` | Boolean | auto lock mode paused | +| `night_latch` | Boolean | night latch mode enabled (eu firmware only) | + + ## References - [Switchbot official global site](https://www.switch-bot.com/) diff --git a/src/advertising.ts b/src/advertising.ts index cfdf6248..e08a5b70 100644 --- a/src/advertising.ts +++ b/src/advertising.ts @@ -135,7 +135,7 @@ export class Advertising { } else if (model === 'j') { sd = WoPlugMini.parseServiceData_JP(manufacturerData, onlog);// WoPlugMini (JP) } else if (model === 'o') { - sd = WoSmartLock.parseServiceData(manufacturerData, onlog);// WoSmartLock + sd = WoSmartLock.parseServiceData(buf, manufacturerData, onlog);// WoSmartLock } else if (model === 'i') { sd = WoSensorTH.parseServiceData_Plus(buf, onlog);// WoMeterPlus } else if (model === 'r') { diff --git a/src/device/wosmartlock.ts b/src/device/wosmartlock.ts index 1212438a..6d1cbad6 100644 --- a/src/device/wosmartlock.ts +++ b/src/device/wosmartlock.ts @@ -56,28 +56,32 @@ export class WoSmartLock extends SwitchbotDevice { } } - static parseServiceData(manufacturerData: Buffer, onlog: ((message: string) => void) | undefined) { - if (manufacturerData.length !== 12) { + static parseServiceData(serviceData: Buffer, manufacturerData: Buffer, onlog: ((message: string) => void) | undefined) { + if (manufacturerData.length < 11) { if (onlog && typeof onlog === 'function') { onlog( - `[parseServiceDataForWoSmartLock] Buffer length ${manufacturerData.length} !== 12!`, + `[parseServiceDataForWoSmartLock] Buffer length ${manufacturerData.length} is too short!`, ); } return null; } - const byte2 = manufacturerData.readUInt8(2); - const byte7 = manufacturerData.readUInt8(7); - const byte8 = manufacturerData.readUInt8(8); + + // adv data needs both service data and manufacturer data + // byte var names based on documentation + const byte2 = serviceData.readUInt8(2); + const byte15 = manufacturerData.readUInt8(9); + const byte16 = manufacturerData.readUInt8(10); const battery = byte2 & 0b01111111; // % - const calibration = byte7 & 0b10000000 ? true : false; - const status = WoSmartLock.getLockStatus(byte7 & 0b01110000); - const update_from_secondary_lock = byte7 & 0b00001000 ? true : false; - const door_open = byte7 & 0b00000100 ? true : false; - const double_lock_mode = byte8 & 0b10000000 ? true : false; - const unclosed_alarm = byte8 & 0b00100000 ? true : false; - const unlocked_alarm = byte8 & 0b00010000 ? true : false; - const auto_lock_paused = byte8 & 0b00000010 ? true : false; + const calibration = byte15 & 0b10000000 ? true : false; + const status = WoSmartLock.getLockStatus(byte15 & 0b01110000); + const update_from_secondary_lock = byte15 & 0b00001000 ? true : false; + const door_open = byte15 & 0b00000100 ? true : false; + const double_lock_mode = byte16 & 0b10000000 ? true : false; + const unclosed_alarm = byte16 & 0b00100000 ? true : false; + const unlocked_alarm = byte16 & 0b00010000 ? true : false; + const auto_lock_paused = byte16 & 0b00000010 ? true : false; + const night_latch = manufacturerData.length > 11 && manufacturerData.readUInt8(11) & 0b00000001 ? true : false; const data = { model: 'o', @@ -91,6 +95,7 @@ export class WoSmartLock extends SwitchbotDevice { unclosed_alarm: unclosed_alarm, unlocked_alarm: unlocked_alarm, auto_lock_paused: auto_lock_paused, + night_latch: night_latch, }; return data;