Ver Fonte

Add support for Bluetooth HU06 smart lock

- lock: add support for unlock_voice for opening via voice assistant.
        implement request/approve_intercom support (previously added
        for another lock, but not properly implemented).
- update lock documentation (was trailing by more than the above)

Issue #973

=#	modified:   custom_components/tuya_local/lock.py
Jason Rumney há 2 anos atrás
pai
commit
55a755825d

+ 1 - 0
ACKNOWLEDGEMENTS.md

@@ -335,3 +335,4 @@ Further device support has been made with the assistance of users.  Please consi
 - [Brazen00](https://github.com/Brazen00) for contributing support for Holman WX1 tap timers.
 - [nima-002](https://github.com/nima-002) for contributing improvements to Moebot S lawnmowers.
 - [maxupunk](https://github.com/maxupunk) for assistance with support for Kabum Smart 700 vacuum cleaners.
+- [thugseus](https://github.com/thugseus) for assistance with support for HU06 Bluetooth smart locks.

+ 1 - 0
DEVICES.md

@@ -459,6 +459,7 @@ of device.
 - Adaprox Fingerbot plus
 - Diivoo WT05 dual water timer
 - HCT-611 water timer
+- HU06 smart lock
 - Orion DL021HA lock
 - PT216/PT19DB-2 temperature and humidity sensor
 - Smart Ape solar garden light

+ 10 - 0
custom_components/tuya_local/devices/README.md

@@ -588,15 +588,25 @@ Humidifer can also cover dehumidifiers (use class to specify which).
    Note: If the light mixes in color modes in the same dp, `color_mode` should be used instead.  If the light contains both a separate dp for effects/scenes/presets and a mix of color_modes and effects (commonly scene and music) in the `color_mode` dp, then a separate select entity should be used for the dedicated dp to ensure the effects from `color_mode` are selectable.
 
 ### `lock`
+
+The unlock... dps below are normally integers, but can also be boolean, in which case
+no information will be available about which specific credential was used to unlock the lock.
+
 - **lock** (optional, boolean): a dp to control the lock state: true = locked, false = unlocked
 - **unlock_fingerprint** (optional, integer): a dp to identify the fingerprint used to unlock the lock.
 - **unlock_password** (optional, integer): a dp to identify the password used to unlock the lock.
 - **unlock_temp_pwd** (optional, integer): a dp to identify the temporary password used to unlock the lock.
 - **unlock_dynamic_pwd** (optional, integer): a dp to identify the dynamic password used to unlock the lock.
+- **unlock_offline_pwd** (optional, integer): a dp to identify the offline password used to unlock the lock.
 - **unlock_card** (optional, integer): a dp to identify the card used to unlock the lock.
 - **unlock_app** (optional, integer): a dp to identify the app used to unlock the lock.
+- **unlock_key** (optional, integer): a dp to identify the key used to unlock the lock.
+- **unlock_ble** (optional, integer): a dp to identify the BLE device used to unlock the lock.
+- **unlock_voice** (optional, integer): a dp to identify the voice assistant user used to unlock the lock.
 - **request_unlock** (optional, integer): a dp to signal that a request has been made to unlock, the value should indicate the time remaining for approval.
 - **approve_unlock** (optional, boolean): a dp to unlock the lock in response to a request.
+- **request_intercom** (optional, integer): a dp to signal that a request has been made via intercom to unlock, the value should indicate the time remaining for approval.
+- **approve_intercom** (optional, boolean): a dp to unlock the lock in response to an intercom request.
 - **jammed** (optional, boolean): a dp to signal that the lock is jammed.
 
 ### `number`

+ 225 - 0
custom_components/tuya_local/devices/ble_hu06_lock.yaml

@@ -0,0 +1,225 @@
+name: Smart lock
+products:
+  - id: stugc8dl
+    name: HU06
+primary_entity:
+  entity: lock
+  dps:
+    - id: 13
+      name: unlock_password
+      type: integer
+      optional: true
+      persist: false
+    - id: 16
+      name: unlock_key
+      type: integer
+      optional: true
+      persist: false
+    - id: 19
+      name: unlock_ble
+      type: integer
+      optional: true
+      persist: false
+    - id: 21
+      name: jammed
+      type: string
+      optional: true
+      persist: false
+      mapping:
+        - dps_val: tongue_bad
+          value: true
+        - value: false
+    - id: 40
+      name: closed_opened
+      type: string
+      mapping:
+        - dps_val: unknown
+        - dps_val: open
+        - dps_val: closed
+    - id: 43
+      name: unlock_fingerprint
+      type: integer
+      optional: true
+      persist: false
+    - id: 47
+      name: lock
+      type: boolean
+      readonly: true
+    - id: 62
+      name: unlock_app
+      type: integer
+      optional: true
+      persist: false
+    - id: 63
+      name: unlock_voice
+      type: integer
+      optional: true
+      persist: false
+    - id: 105
+      name: lock_record
+      type: string
+      optional: true
+secondary_entities:
+  - entity: sensor
+    class: battery
+    category: diagnostic
+    dps:
+      - id: 8
+        type: integer
+        name: sensor
+        unit: "%"
+        class: measurement
+  - entity: binary_sensor
+    name: Wrong password
+    class: problem
+    category: diagnostic
+    dps:
+      - id: 21
+        type: string
+        name: sensor
+        optional: true
+        persist: false
+        mapping:
+          - dps_val: wrong_password
+            value: true
+          - dps_val: "1"
+            value: true
+          - value: false
+  - entity: binary_sensor
+    class: tamper
+    category: diagnostic
+    dps:
+      - id: 21
+        type: string
+        name: sensor
+        optional: true
+        persist: false
+        mapping:
+          - dps_val: pry
+            value: true
+          - dps_val: "8"
+            value: true
+          - value: false
+  - entity: binary_sensor
+    class: battery
+    category: diagnostic
+    dps:
+      - id: 21
+        type: string
+        name: sensor
+        optional: true
+        persist: false
+        mapping:
+          - dps_val: low_battery
+            value: true
+          - dps_val: "10"
+            value: true
+          - dps_val: low_battery_keypad
+          - value: false
+  - entity: binary_sensor
+    class: problem
+    category: diagnostic
+    dps:
+      - id: 21
+        type: string
+        name: sensor
+        optional: true
+        persist: false
+        mapping:
+          - dps_val: defense
+            value: true
+          - dps_val: "13"
+            value: true
+          - value: false
+  - entity: binary_sensor
+    name: Duress
+    class: safety
+    category: diagnostic
+    dps:
+      - id: 22 
+        type: boolean
+        name: sensor
+        optional: true
+        persist: false
+        mapping:
+          - dps_val: null
+            value: false
+  - entity: binary_sensor
+    name: Doorbell
+    class: sound
+    category: diagnostic
+    dps:
+      - id: 24
+        type: boolean
+        name: sensor
+        optional: true
+        persist: false
+        mapping:
+          - dps_val: null
+            value: false
+  - entity: number
+    name: Doorbell volume
+    category: config
+    dps:
+      - id: 27
+        type: string
+        name: value
+        unit: "%"
+        range:
+          min: 0
+          max: 100
+        mapping:
+          - dps_val: mute
+            value: 0
+            icon: "mdi:volume-mute"
+          - dps_val: voice
+            value: 100
+            icon: "mdi:volume-high"
+  - entity: switch
+    name: Auto lock
+    category: config
+    icon: "mdi:lock-reset"
+    dps:
+      - id: 33
+        type: boolean
+        name: switch
+  - entity: number
+    name: Auto lock delay
+    category: config
+    icon: "mdi:lock-clock"
+    dps:
+      - id: 36
+        name: value
+        type: integer
+        range:
+          min: 10
+          max: 180
+          mapping:
+            - step: 10
+          unit: s
+  - entity: binary_sensor
+    name: Keypad reset
+    class: running
+    category: diagnostic
+    dps:
+      - id: 102
+        type: boolean
+        name: sensor
+  - entity: sensor
+    name: Keypad battery
+    class: battery
+    category: diagnostic
+    dps:
+      - id: 103
+        type: integer
+        name: sensor
+        unit: "%"
+        class: measurement
+  - entity: binary_sensor
+    class: connectivity
+    category: diagnostic
+    dps:
+      - id: 107
+        type: boolean
+        name: sensor
+

+ 7 - 0
custom_components/tuya_local/lock.py

@@ -42,6 +42,7 @@ class TuyaLocalLock(TuyaLocalEntity, LockEntity):
         self._unlock_app_dp = dps_map.pop("unlock_app", None)
         self._unlock_key_dp = dps_map.pop("unlock_key", None)
         self._unlock_ble_dp = dps_map.pop("unlock_ble", None)
+        self._unlock_voice_dp = dps_map.pop("unlock_voice", None)
         self._req_unlock_dp = dps_map.pop("request_unlock", None)
         self._approve_unlock_dp = dps_map.pop("approve_unlock", None)
         self._req_intercom_dp = dps_map.pop("request_intercom", None)
@@ -66,6 +67,7 @@ class TuyaLocalLock(TuyaLocalEntity, LockEntity):
                 self._unlock_app_dp,
                 self._unlock_key_dp,
                 self._unlock_ble_dp,
+                self._unlock_voice_dp,
             ):
                 if d:
                     if d.get_value(self._device):
@@ -100,6 +102,7 @@ class TuyaLocalLock(TuyaLocalEntity, LockEntity):
             self._unlock_offlinepw_dp: "Offline Password",
             self._unlock_pw_dp: "Password",
             self._unlock_tmppw_dp: "Temporary Password",
+            self._unlock_voice_dp: "Voice",
         }.items():
             by = self.unlocker_id(dp, desc)
             if by:
@@ -120,5 +123,9 @@ class TuyaLocalLock(TuyaLocalEntity, LockEntity):
             if self._req_unlock_dp and not self._req_unlock_dp.get_value(self._device):
                 raise TimeoutError()
             await self._approve_unlock_dp.async_set_value(self._device, True)
+        elif self._approve_intercom_dp:
+            if self._req_intercom_dp and not self._req_intercom_dp.get_value(self._device):
+                raise TimeoutError()
+            await self._approve_intercom_dp.async_set_value(self._device, True)
         else:
             raise NotImplementedError()