iA Blog

Integrating the New Sesame Lock with Home Assistant

10 Oct 2022 | home-assistant, sesame-lock, python
[Update 2024/02/04]: Instead of using Sesame's Web APIs, I reintegrated my Sesame Lock without depending on the cloud using an ESP32 module.

I’ve been using Sesame Lock for the past 1.5 years. At around ¥10,000 which also includes the Wifi Module and Sesame Bot (IoT button), it is a great option for those interested in a smart lock without breaking the bank. In addition, one could control it with a web API, opening up possibilities to integrate with any setup.

While I relied on iOS shortcuts to unlock my doors, I came across a great post by Tats Shibata on how to integrate the new Sesame Locks with Home Assistant. As the official Home Assistant integration only support models before Sesame 3, it took some effort to make the new Sesame locks work with Home Assistant.

Obtaining API key, Device UUID and Secret Key

The easiest way to integrate Sesame into Home Assistant is via their web API. Do note the web API is only free up to 30,000 calls a month, which I think is sufficient for day-to-day use. There are libraries such as pysesameos2 that controls Sesame via Bluetooth communication, but I won’t be exploring these method for now.

To obtain an API key, go to Sesame API portal and login with the email that you used to login into the mobile app.

Sesame API Portal
Sesame API portal

In the API portal, click on the user icon circled in red. You’ll see your devices appear on the right. You might need to click on the icon a couple of times for all of the devices that you own to appear. Then, click on the device that you want to control. The device UUID and secret key fields will be populated. Add these values to your secrets.yaml file.

sesame_api_key: [api_key]
sesame_device_uuid: [device_uuid]
sesame_device_secret: [secret_key]
secrets.yaml

Getting Device Status

Getting the device status is as easy as issuing a HTTP GET request:

$ curl -s -H "x-api-key: $API_KEY" https://app.candyhouse.co/api/sesame2/$DEVICE_UUID | jq
{
  "batteryPercentage": 100,
  "batteryVoltage": 6.003519061583578,
  "position": 479,
  "CHSesame2Status": "locked",
  "timestamp": 1642253725,
  "wm2State": true
}

You can integrate the status into a Home Assistant sensor using the RESTful Sensor integration:

# you can't use secrets directly in a template string hence this workaround
input_text:
  sesame_device_uuid:
    initial: !secret sesame_device_uuid

sensor:
  - platform: rest
    name: Sesame Lock Sensor
    # Adjust the scan interval so you don't get rate limited
    scan_interval: 600
    method: GET
    headers:
      x-api-key: !secret sesame_api_key
    resource_template: "https://app.candyhouse.co/api/sesame2/{{ states('input_text.sesame_device_uuid') }}"
    value_template: '{{ value_json.CHSesame2Status }}'
    json_attributes:
      - batteryPercentage
      - batteryVoltage
      - position
      - CHSesame2Status
      - timestamp
Sesame Lock sensor config

Sending Commands to the Device

Unfortunately sending commands to the device is not as easy as getting the status. The secret key needs to be encrypted before sending, which is not achievable via the YAML config. Home Assistant’s Python Script integration isn’t good enough as you’ll need to import modules to encrypt the secret key. But it is simple enough to make a standalone script like so:

#!/usr/bin/env python3

import base64, datetime, json, requests, sys
from Crypto.Cipher import AES
from Crypto.Hash import CMAC

COMMANDS = {
    "lock": 82,
    "unlock": 83,
    "toggle": 88,
}

def main():
    try:
        command = sys.argv[1]
        api_key = sys.argv[2]
        uuid = sys.argv[3]
        secret = sys.argv[4]
    except IndexError:
        print("Usage: sesame <lock|unlock|toggle> <api_key> <uuid> <secret>")
        sys.exit(1)

    cmd = COMMANDS[command]

    history = base64.b64encode("HomeAssistant".encode()).decode()

    ts = int(datetime.datetime.now().timestamp())
    msg = ts.to_bytes(4, byteorder="little").hex()[2:8]

    cmac = CMAC.new(bytes.fromhex(secret), ciphermod=AES)
    cmac.update(bytes.fromhex(msg))
    sign = cmac.hexdigest()

    url = f'https://app.candyhouse.co/api/sesame2/{uuid}/cmd'
    headers = { "x-api-key": api_key }
    body = { "cmd": cmd, "history": history, "sign": sign }

    res = requests.post(url, json.dumps(body), headers=headers)
    print(url, headers, body)
    print(res.status_code, res.text)

if __name__ == "__main__":
    main()
sesame.py

Save this file somewhere in your Home Assistant config and make it executable:

$ chmod +x sesame.py

You can then call the script like so via the command line:

$ /config/python_scripts/sesame.py [lock|unlock|toggle] $API_KEY $DEVICE_UUID $DEVICE_SECRET

And here’s how to integrate the commands into Home Assistant using the Shell Command integration:

shell_command:
  sesame: "/config/python_scripts/sesame.py {{ command }} {{ api_key }} {{ uuid }} {{ secret }}"

scripts:
  lock_sesame:
    sequence:
      - service: shell_command.sesame
        data_template:
          command: lock
          api_key: !secret sesame_api_key
          uuid: !secret sesame_device_uuid
          secret: !secret sesame_device_secret

  unlock_sesame:
    sequence:
      - service: shell_command.sesame
        data_template:
          command: unlock
          api_key: !secret sesame_api_key
          uuid: !secret sesame_device_uuid
          secret: !secret sesame_device_secret
Sesame Lock commands config

If all goes well, you should be able to invoke commands by using scripts:lock_sesame and scripts:unlock_sesame service.

Bringing them all together in a single device

We can finally combine the sensor and controls into a single entity using the Template Lock integration:

lock:
  - platform: template
    name: Sesame Lock
    value_template: "{{ is_state('sensor.sesame_lock_sensor', 'locked') }}"
    lock:
      service: script.lock_sesame
    unlock:
      service: script.unlock_sesame
Sesame Lock entity config

All done! You can now integrate the Sesame lock into your Home Assistant using lock.sesame_lock. My Sesame Lock config can be found in my Home Assistant config Github repository.


Adwin Ying's avatar
Adwin Ying

Self-taught full-stack web dev based in Tokyo. Occasionally wrecks servers through  self-hosting  and  homelab-ing.

← Back to all posts