diff --git a/README.md b/README.md
index cfb4dccd..a46d80c2 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
 </span>
 
 The node-switchbot is a Node.js module which allows you to move your [Switchbot (Bot)'s](https://www.switch-bot.com/bot) arm
-and [Switchbot Curtain](https://www.switch-bot.com/products/switchbot-curtain),
+and [Switchbot Curtain](https://www.switch-bot.com/products/switchbot-curtain), operate your [Switchbot Lock](https://www.switch-bot.com/products/switchbot-lock),
 also monitor the temperature/humidity from [SwitchBot Thermometer & Hygrometer (Meter)](https://www.switch-bot.com/meter)
 as well as the status from [SwitchBot Motion Sensor](https://www.switch-bot.com/products/motion-sensor)
 and [SwitchBot Contact Sensor](https://www.switch-bot.com/products/contact-sensor)
@@ -43,21 +43,26 @@ But some functionalities of this module were developed through trial and error.
     - [`disconnect()` method](#disconnect-method)
     - [`onconnect` event handler](#onconnect-event-handler)
     - [`ondisconnect` event handler](#ondisconnect-event-handler)
-  - [`WoHand` object](#switchbotdevicewohand-object)
+  - [`WoHand` object](#wohand-object)
     - [`press()` method](#press-method)
     - [`turnOn()` method](#turnon-method)
     - [`turnOff()` method](#turnoff-method)
     - [`down()` method](#down-method)
     - [`up()` method](#up-method)
-  - [`WoCurtain` object](#switchbotdevicewocurtain-object)
+  - [`WoCurtain` object](#wocurtain-object)
     - [`open()` method](#open-method)
     - [`close()` method](#close-method)
     - [`pause()` method](#pause-method)
     - [`runToPos()` method](#runtopos-method)
-  - [`WoPlugMini` object](#switchbotdevicewoplugmini-object)
+  - [`WoPlugMini` object](#woplugmini-object)
     - [`turnOn()` method](#turnon-method)
     - [`turnOff()` method](#turnoff-method)
     - [`toggle()` method](#toggle-method)
+  - [`WoSmartLock` object](#wosmartlock-object)
+    - [`lock()` method](#lock-method)
+    - [`unlock()` method](#unlock-method)
+    - [`unlock_no_unlatch()` method](#unlock_no_unlatch-method)
+    - [`info()` method](#info-method)
   - [Advertisement data](#advertisement-data)
     - [Bot (WoHand)](#bot-wohand)
     - [Meter (WoSensorTH)](#meter-wosensorth)
@@ -876,6 +881,49 @@ If no connection is established with the device, this method automatically estab
 
 ---
 
+---
+## `WoSmartLock` object
+
+The `WoSmartLock ` object represents a SmartLock, which is created through the discovery process triggered by the [`Switchbot.discover()`](#Switchbot-discover-method) method.
+
+Actually, the `WoSmartLock ` is an object inherited from the [`SwitchbotDevice`](#SwitchbotDevice-object). You can use not only the method described in this section but also the properties and methods implemented in the [`SwitchbotDevice`](#SwitchbotDevice-object) object.
+
+### `setKey()` method
+
+The `setKey()` method initialises the key information required for encrypted communication with the SmartLock
+
+This must be set before any control commands are sent to the device. To obtain the key information you will need to use an external tool - see [`pySwitchbot`](https://github.com/Danielhiversen/pySwitchbot/tree/master?tab=readme-ov-file#obtaining-locks-encryption-key) project for an example script.
+
+| Property         | Type    | Description                                                                                                                            |
+| :--------------- | :------ | :------------------------------------------------------------------------------------------------------------------------------------- |
+| `keyId`          | String  | unique2 character ID for the key. (e.g., `"ff"`) returned from the SwitchBot api for your device                                       |
+| `encryptionKey`  | String  | the unique encryption key returned from the SwitchBot api for your device                                                              |
+
+### `lock()` method
+
+The `lock()` method sends a lock command to the SmartLock. This method returns a `Promise` object. A `boolean` value indicating whether the SmartLock is locked (`true`), is passed to the `resolve()` method of the Promise.
+
+If no connection is established with the device, this method automatically establishes a connection with the device, then finally closes the connection. You don't have to call the [`connect()`](#SwitchbotDevice-connect-method) method in advance.
+
+### `unlock()` method
+
+The `unlock()` method sends an unlock command to the SmartLock. This method returns a `Promise` object. A `boolean` value indicating whether the SmartLock is locked (`false`), is passed to the `resolve()` method of the Promise.
+
+If no connection is established with the device, this method automatically establishes a connection with the device, then finally closes the connection. You don't have to call the [`connect()`](#SwitchbotDevice-connect-method) method in advance.
+
+### `unlockNoUnlatch()` method
+
+The `unlockNoUnlatch()` method sends a partial unlock command to the SmartLock, unlocking without the full unlatch.
+
+If no connection is established with the device, this method automatically establishes a connection with the device, then finally closes the connection. You don't have to call the [`connect()`](#SwitchbotDevice-connect-method) method in advance.
+
+### `info()` method
+
+The `info()` method retreieves state information from the SmartLock, This method returns a `Promise` object. An `object` value indicating with the state infor, is passed to the `resolve()` method of the Promise.
+
+If no connection is established with the device, this method automatically establishes a connection with the device, then finally closes the connection. You don't have to call the [`connect()`](#SwitchbotDevice-connect-method) method in advance.
+
+
 ## Advertisement data
 
 After the [`startScan()`](#startscan-method) method is invoked, the [`onadvertisement`](#Switchbot-onadvertisement-event-handler) event handler will be called whenever an advertising packet comes from the switchbot devices. An object containing the properties as follows will be passed to the event handler:
diff --git a/src/device.ts b/src/device.ts
index 112a7192..d760ece3 100644
--- a/src/device.ts
+++ b/src/device.ts
@@ -4,7 +4,7 @@
  */
 import { Characteristic, Peripheral, Service } from '@abandonware/noble';
 import { ParameterChecker } from './parameter-checker.js';
-import { Advertising } from './advertising.js';
+import { Advertising, Ad } from './advertising.js';
 
 type Chars = {
   write: Characteristic | null,
@@ -47,11 +47,12 @@ export class SwitchbotDevice {
     this._chars = null;
 
     // Save the device information
-    const ad = Advertising.parse(peripheral);
-    this._id = ad?.id;
-    this._address = ad?.address;
-    this._model = ad?.serviceData.model;
-    this._modelName = ad?.serviceData.modelName;
+    const ad: Ad = Advertising.parse(peripheral);
+    this._id = ad ? ad.id : null;
+    this._address = ad ? ad.address : null;
+    this._model = ad ? ad.serviceData.model : null;
+    this._modelName = ad ? ad.serviceData.modelName : null;
+
 
     this._was_connected_explicitly = false;
     this._connected = false;
@@ -286,7 +287,7 @@ export class SwitchbotDevice {
 
   _subscribe() {
     return new Promise<void>((resolve, reject) => {
-      const char = this._chars?.notify;
+      const char = this._chars ? this._chars.notify : null;
       if (!char) {
         reject(new Error('No notify characteristic was found.'));
         return;
@@ -306,7 +307,7 @@ export class SwitchbotDevice {
 
   _unsubscribe() {
     return new Promise<void>((resolve) => {
-      const char = this._chars?.notify;
+      const char = this._chars ? this._chars.notify : null;
       if (!char) {
         resolve();
         return;
@@ -380,7 +381,7 @@ export class SwitchbotDevice {
       let name = '';
       this._connect()
         .then(() => {
-          if (!this._chars?.device) {
+          if (!this._chars || !this._chars.device) {
             // Some models of Bot don't seem to support this characteristic UUID
             throw new Error(
               'The device does not support the characteristic UUID 0x' +
@@ -434,7 +435,7 @@ export class SwitchbotDevice {
       const buf = Buffer.from(name, 'utf8');
       this._connect()
         .then(() => {
-          if (!this._chars?.device) {
+          if (!this._chars || !this._chars.device) {
             // Some models of Bot don't seem to support this characteristic UUID
             throw new Error(
               'The device does not support the characteristic UUID 0x' +
@@ -470,7 +471,7 @@ export class SwitchbotDevice {
 
       this._connect()
         .then(() => {
-          if (!this._chars?.write) {
+          if (!this._chars || !this._chars.write) {
             return reject(new Error('No characteristics available.'));
           }
           return this._write(this._chars.write, req_buf);
diff --git a/src/device/wosmartlock.ts b/src/device/wosmartlock.ts
index 84ecbf96..1212438a 100644
--- a/src/device/wosmartlock.ts
+++ b/src/device/wosmartlock.ts
@@ -1,15 +1,66 @@
-/* Copyright(C) 2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
- *
+/*
  * wosmartlock.ts: Switchbot BLE API registration.
+ * adapted off the work done by [pySwitchbot](https://github.com/Danielhiversen/pySwitchbot)
  */
 import { SwitchbotDevice } from '../device.js';
+import { Peripheral } from '@abandonware/noble';
+import * as Crypto from 'crypto';
 
 export class WoSmartLock extends SwitchbotDevice {
+  _iv:any;
+  _key_id:string;
+  _encryption_key:any;
+
+  static COMMAND_GET_CK_IV = '570f2103';
+  static COMMAND_LOCK_INFO = '570f4f8101';
+  static COMMAND_UNLOCK = '570f4e01011080';
+  static COMMAND_UNLOCK_NO_UNLATCH = '570f4e010110a0';
+  static COMMAND_LOCK = '570f4e01011000';
+
+  static Result = {
+    ERROR: 0x00,
+    SUCCESS: 0x01,
+    SUCCESS_LOW_BATTERY: 0x06,
+  };
+
+  static validateResponse(res: Buffer) {
+    if (res.length >= 3) {
+      switch (res.readUInt8(0)) {
+        case WoSmartLock.Result.SUCCESS:
+          return WoSmartLock.Result.SUCCESS;
+        case WoSmartLock.Result.SUCCESS_LOW_BATTERY:
+          return WoSmartLock.Result.SUCCESS_LOW_BATTERY;
+      }
+    }
+    return WoSmartLock.Result.ERROR;
+  }
+
+  static getLockStatus(code: number) {
+    switch (code) {
+      case 0b0000000:
+        return 'LOCKED';
+      case 0b0010000:
+        return 'UNLOCKED';
+      case 0b0100000:
+        return 'LOCKING';
+      case 0b0110000:
+        return 'UNLOCKING';
+      case 0b1000000:
+        return 'LOCKING_STOP';
+      case 0b1010000:
+        return 'UNLOCKING_STOP';
+      case 0b1100000: //Only EU lock type
+        return 'NOT_FULLY_LOCKED';
+      default:
+        return 'UNKNOWN';
+    }
+  }
+
   static parseServiceData(manufacturerData: Buffer, onlog: ((message: string) => void) | undefined) {
-    if (manufacturerData.length !== 6) {
+    if (manufacturerData.length !== 12) {
       if (onlog && typeof onlog === 'function') {
         onlog(
-          `[parseServiceDataForWoSmartLock] Buffer length ${manufacturerData.length} !== 6!`,
+          `[parseServiceDataForWoSmartLock] Buffer length ${manufacturerData.length} !== 12!`,
         );
       }
       return null;
@@ -18,40 +69,9 @@ export class WoSmartLock extends SwitchbotDevice {
     const byte7 = manufacturerData.readUInt8(7);
     const byte8 = manufacturerData.readUInt8(8);
 
-    function getStatus(code: number): string {
-      switch (code) {
-        case LockStatus.LOCKED:
-          return 'LOCKED';
-        case LockStatus.UNLOCKED:
-          return 'UNLOCKED';
-        case LockStatus.LOCKING:
-          return 'LOCKING';
-        case LockStatus.UNLOCKING:
-          return 'UNLOCKING';
-        case LockStatus.LOCKING_STOP:
-          return 'LOCKING_STOP';
-        case LockStatus.UNLOCKING_STOP:
-          return 'UNLOCKING_STOP';
-        case LockStatus.NOT_FULLY_LOCKED:
-          return 'NOT_FULLY_LOCKED';
-        default:
-          return 'UNKNOWN';
-      }
-    }
-
-    const LockStatus = {
-      LOCKED: 0b0000000,
-      UNLOCKED: 0b0010000,
-      LOCKING: 0b0100000,
-      UNLOCKING: 0b0110000,
-      LOCKING_STOP: 0b1000000,
-      UNLOCKING_STOP: 0b1010000,
-      NOT_FULLY_LOCKED: 0b1100000,  //Only EU lock type
-    };
-
     const battery = byte2 & 0b01111111; // %
     const calibration = byte7 & 0b10000000 ? true : false;
-    const status = getStatus(byte7 & 0b01110000);
+    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;
@@ -76,5 +96,185 @@ export class WoSmartLock extends SwitchbotDevice {
     return data;
   }
 
+  constructor(peripheral: Peripheral, noble: any) {
+    super(peripheral, noble);
+    this._iv = null;
+    this._key_id = '';
+    this._encryption_key = null;
+  }
+
+  /* ------------------------------------------------------------------
+   * setKey()
+   * - initialise the encryption key info for valid lock communication, this currently must be retrived externally
+   *
+   * [Arguments]
+   * - keyId, encryptionKey
+   *
+   * [Return value]
+   * - void
+   * ---------------------------------------------------------------- */
+  setKey(keyId: string, encryptionKey: string) {
+    this._iv = null;
+    this._key_id = keyId;
+    this._encryption_key = Buffer.from(encryptionKey, 'hex');
+  }
+
+  /* ------------------------------------------------------------------
+   * unlock()
+   * - Unlock the Smart Lock
+   *
+   * [Arguments]
+   * - none
+   *
+   * [Return value]
+   * - Promise object
+   *   WoSmartLock.LockResult will be passed to the `resolve()`.
+   * ---------------------------------------------------------------- */
+  unlock() {
+    return new Promise<number>((resolve, reject) => {
+      this._operateLock(WoSmartLock.COMMAND_UNLOCK)
+        .then((resBuf) => {
+          resolve(WoSmartLock.validateResponse(resBuf));
+        }).catch((error) => {
+          reject(error);
+        });
+    });
+  }
+
+  /* ------------------------------------------------------------------
+   * unlockNoUnlatch()
+   * - Unlock the Smart Lock without unlatching door
+   *
+   * [Arguments]
+   * - none
+   *
+   * [Return value]
+   * - Promise object
+   *   WoSmartLock.LockResult will be passed to the `resolve()`.
+   * ---------------------------------------------------------------- */
+  unlockNoUnlatch() {
+    return new Promise<number>((resolve, reject) => {
+      this._operateLock(WoSmartLock.COMMAND_UNLOCK_NO_UNLATCH)
+        .then((resBuf) => {
+          resolve(WoSmartLock.validateResponse(resBuf));
+        }).catch((error) => {
+          reject(error);
+        });
+    });
+  }
+
+  /* ------------------------------------------------------------------
+   * lock()
+   * - Lock the Smart Lock
+   *
+   * [Arguments]
+   * - none
+   *
+   * [Return value]
+   * - Promise object
+   *   WoSmartLock.LockResult will be passed to the `resolve()`.
+   * ---------------------------------------------------------------- */
+  lock() {
+    return new Promise<number>((resolve, reject) => {
+      this._operateLock(WoSmartLock.COMMAND_LOCK)
+        .then((resBuf) => {
+          resolve(WoSmartLock.validateResponse(resBuf));
+        }).catch((error) => {
+          reject(error);
+        });
+    });
+  }
+
+  /* ------------------------------------------------------------------
+   * info()
+   * - Get general state info from the Smart Lock
+   *
+   * [Arguments]
+   * - none
+   *
+   * [Return value]
+   * - Promise object
+   *   state object will be passed to the `resolve()`
+   * ---------------------------------------------------------------- */
+  info() {
+    return new Promise((resolve, reject) => {
+      this._operateLock(WoSmartLock.COMMAND_LOCK_INFO)
+        .then(resBuf => {
+          const data ={
+            'calibration': Boolean(resBuf[1] & 0b10000000),
+            'status': WoSmartLock.getLockStatus((resBuf[1] & 0b01110000)),
+            'door_open': Boolean(resBuf[1] & 0b00000100),
+            'unclosed_alarm': Boolean(resBuf[2] & 0b00100000),
+            'unlocked_alarm': Boolean(resBuf[2] & 0b00010000),
+          };
+          resolve(data);
+        }).catch((error) => {
+          reject(error);
+        });
+    });
+  }
+
+  _encrypt(str:string) {
+    const cipher = Crypto.createCipheriv('aes-128-ctr', this._encryption_key, this._iv);
+    return Buffer.concat([cipher.update(str, 'hex'), cipher.final()]).toString('hex');
+  }
+
+  _decrypt(data:Buffer) {
+    const decipher = Crypto.createDecipheriv('aes-128-ctr', this._encryption_key, this._iv);
+    return Buffer.concat([decipher.update(data), decipher.final()]);
+  }
+
+  async _getIv() {
+    if (this._iv === null) {
+      const res:Buffer = await this._operateLock(WoSmartLock.COMMAND_GET_CK_IV + this._key_id, false);
+      this._iv = res.subarray(4);
+    }
+    return this._iv;
+  }
+
+  async _encryptedCommand(key: string) {
+    const iv = await this._getIv();
+    const req = Buffer.from(
+      key.substring(0, 2) + this._key_id + Buffer.from(iv.subarray(0, 2)).toString('hex') + this._encrypt(key.substring(2))
+      , 'hex');
+
+    const bytes: unknown = await this._command(req);
+    const buf = Buffer.from(bytes as Uint8Array);
+    const code = WoSmartLock.validateResponse(buf);
+
+    if (code !== WoSmartLock.Result.ERROR) {
+      return Buffer.concat([buf.subarray(0, 1), this._decrypt(buf.subarray(4))]);
+    } else {
+      throw (
+        new Error('The device returned an error: 0x' + buf.toString('hex'),
+        )
+      );
+    }
+  }
+
+  _operateLock(key: string, encrypt: boolean = true) {
+    //encrypted command
+    if (encrypt) {
+      return this._encryptedCommand(key);
+    }
+
+    //unencypted command
+    return new Promise<any>((resolve, reject) => {
+      const req = Buffer.from(key.substring(0, 2) + '000000' + key.substring(2), 'hex');
+
+      this._command(req).then(bytes => {
+        const buf = Buffer.from(bytes as Uint8Array);
+        const code = WoSmartLock.validateResponse(buf);
+
+        if (code === WoSmartLock.Result.ERROR) {
+          reject(new Error('The device returned an error: 0x' + buf.toString('hex')));
+        } else {
+          resolve(buf);
+        }
+      }).catch(error => {
+        reject(error);
+      });
+    });
+  }
 }
 
diff --git a/src/switchbot.ts b/src/switchbot.ts
index 5c779f58..8e8bbe51 100644
--- a/src/switchbot.ts
+++ b/src/switchbot.ts
@@ -17,6 +17,7 @@ import { WoHumi } from './device/wohumi.js';
 import { WoPlugMini } from './device/woplugmini.js';
 import { WoBulb } from './device/wobulb.js';
 import { WoStrip } from './device/wostrip.js';
+import { WoSmartLock } from './device/wosmartlock.js';
 import { Ad } from './advertising.js';
 
 import { Peripheral } from '@abandonware/noble';
@@ -164,25 +165,29 @@ export class SwitchBot {
       // Initialize the noble object
       this._init()
         .then(() => {
+          if (this.noble == null) {
+            return reject(new Error('noble failed to initialize'));
+          }
           const peripherals: Record<string, SwitchbotDevice> = {};
           let timer: NodeJS.Timeout = setTimeout(() => { }, 0);
           const finishDiscovery = () => {
             if (timer) {
               clearTimeout(timer);
             }
-            this.noble?.removeAllListeners('discover');
-            this.noble?.stopScanning();
+            
+            this.noble.removeAllListeners('discover');
+            this.noble.stopScanning();
+            
             const device_list: SwitchbotDevice[] = [];
             for (const addr in peripherals) {
               device_list.push(peripherals[addr]);
             }
-            if (device_list.length) {
-              resolve(device_list);
-            }
+
+            resolve(device_list);
           };
 
           // Set a handler for the 'discover' event
-          this.noble?.on('discover', (peripheral: Peripheral) => {
+          this.noble.on('discover', (peripheral: Peripheral) => {
             const device = this.getDeviceObject(peripheral, p.id, p.model) as SwitchbotDevice;
             if (!device) {
               return;
@@ -199,9 +204,8 @@ export class SwitchBot {
               return;
             }
           });
-
           // Start scanning
-          this.noble?.startScanning(
+          this.noble.startScanning(
             this.PRIMARY_SERVICE_UUID_LIST,
             false,
             (error: Error) => {
@@ -230,7 +234,7 @@ export class SwitchBot {
         resolve();
         return;
       }
-      this.noble?.once('stateChange', (state: any) => {
+      this.noble.once('stateChange', (state: any) => {
         switch (state) {
           case 'unsupported':
           case 'unauthorized':
@@ -298,7 +302,7 @@ export class SwitchBot {
             device = new WoPlugMini(peripheral, this.noble);
             break;
           case 'o':
-            //device = new SwitchbotDeviceWoSmartLock(peripheral, this.noble);
+            device = new WoSmartLock(peripheral, this.noble);
             break;
           case 'i':
             device = new WoSensorTH(peripheral, this.noble);
@@ -435,6 +439,9 @@ export class SwitchBot {
       // Initialize the noble object
       this._init()
         .then(() => {
+          if (this.noble == null) {
+            return reject(new Error('noble object failed to initialize'));
+          }
           // Determine the values of the parameters
           const p = {
             model: params.model || '',
@@ -442,7 +449,7 @@ export class SwitchBot {
           };
 
           // Set a handler for the 'discover' event
-          this.noble?.on('discover', (peripheral: Peripheral) => {
+          this.noble.on('discover', (peripheral: Peripheral) => {
             const ad = Advertising.parse(peripheral, this.onlog);
             if (this.filterAdvertising(ad, p.id, p.model)) {
               if (
@@ -455,7 +462,7 @@ export class SwitchBot {
           });
 
           // Start scanning
-          this.noble?.startScanning(
+          this.noble.startScanning(
             this.PRIMARY_SERVICE_UUID_LIST,
             true,
             (error: Error) => {
@@ -485,8 +492,10 @@ export class SwitchBot {
      * - none
      * ---------------------------------------------------------------- */
   stopScan() {
-    this.noble?.removeAllListeners('discover');
-    this.noble?.stopScanning();
+    if (this.noble == null) return;
+
+    this.noble.removeAllListeners('discover');
+    this.noble.stopScanning();
   }
 
   /* ------------------------------------------------------------------