Sesame OS1 を搭載した初代SESAMEと SESAME mini は、Sesame Smart Lock Integration を使えばAPIキーを設定するだけで Home Assistant から使用することができます。一方、SESAME 3 や SESAME 4、SESAME bot、SESAMEサイクルなどの Sesame OS2 を搭載したスマートロックは対応していません。そこで、この記事では Template Lock Integration を使うことで、SESAME 4 を Home Assistant に対応させます。

My Home Assistant in Jan 2022

Web API の使用

まずは Web API のAPIキーを入手します。 https://partners.candyhouse.co/ にログインして、API_KEYをクリックします。数分待つとAPIキーが表示されます。

制御したいSESAMEのUUIDを取得します。Sesameアプリから制御したいSESAME > 右上の… を選ぶとUUIDが表示されます。このUUIDはコピーできないので、手書きでメモします。

ここまでで、以下の2つの値が取得できました。

  • APIキー: 4Zb4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • UUID: E0A1yyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy

APIキーとUUIDが取得できたら、SESAMEの状態を取得してみましょう。

tats@fox:~$ curl -s -H "x-api-key: 4Zb4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" https://app.candyhouse.co/api/sesame2/E0A1yyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy | jq
{
  "batteryPercentage": 100,
  "batteryVoltage": 6.003519061583578,
  "position": 479,
  "CHSesame2Status": "locked",
  "timestamp": 1642253725,
  "wm2State": true
}

つづいて秘密鍵を入手します。UUIDの上にある「このセサミの鍵をシェア」からQRコードを表示して、信頼できるQRコードリーダーで文字列を入手します。iPhoneの場合、Shortcutsアプリから「QR/バーコードをスキャン」、「テキストとして」で「QB/バーコード」、「Quick Look で表示」で「テキスト」の3つを選ぶことで、QRコードからテキストを取得できます。QRコードのスクリーンショットを撮って、それをMacで映したり、印刷したりしたものをShortcutsアプリから読み取りましょう。

以下のような文字列が取得できるので、コピーします。

ssm://UI?t=sk&sk=BAAAzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzFCuL&l=2&n=Sesame%20Bottom

sk=&lに挟まれた132文字の文字列を使用します。上記の場合、BAAA[...]FCuLです。Pythonを起動し、以下を実行します。

tats@fox:~$ python3
Python 3.9.9 (main, Nov 21 2021, 03:23:44)
[Clang 13.0.0 (clang-1300.0.29.3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import base64
>>> sk = "BAAAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFCuL"
>>> base64.b64decode(sk)[1:17].hex()
'0000cf3cf3cf3cf3cf3cf3cf3cf3cf3c'

ここまでで以下の3つの値が取得できました。SESAMEの制御にはこのような3つの値が必要です。

  • APIキー: 4Zb4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • UUID: E0A1yyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
  • 秘密鍵: 0000cf3cf3cf3cf3cf3cf3cf3cf3cf3c

pysesame3というPythonライブラリがありますが、SESAME 4 で使うだけならライブラリを使わなくてもそれほど難しくないため、私は以下のようなスクリプトを用意しました。

/etc/homeassistant/bin/sesame

#!/usr/bin/env python3

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

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)

    if command == "lock":
        cmd = 82
    elif command == "unlock":
        cmd = 83
    else:
        cmd = 88

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

    cmac = CMAC.new(bytes.fromhex(secret), ciphermod=AES)
    cmac.update(
        int(datetime.datetime.now().timestamp()).to_bytes(4, "little", signed=False)[1:4]
    )
    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(res.status_code, res.text)

if __name__ == "__main__":
    main()

Home Assistant OS を使用している場合は/usr/local/bin/sesameに、Home Assistant Container を使用している場合は/etc/homeassistant/binに保存し、実行権限を与えます。

tats@fox:~$ sudo chmod 755 /etc/homeassistant/bin/sesame
tats@fox:~$ /etc/homeassistant/bin/sesame --help
Usage: sesame <lock|unlock|toggle> <api_key> <uuid> <secret>

解錠してみましょう。

tats@fox:~$ /etc/homeassistant/bin/sesame unlock 4Zb4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx E0A1yyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy 0000cf3cf3cf3cf3cf3cf3cf3cf3cf3c

Home Assistant の設定

状態の取得には RESTful Sensor Integration を使用します。scan_intervalが小さすぎると、しばらく後に 429 Too Many Requests で {"message":"Limit Exceeded"} が返ってきてしまうので、ここでは3600秒(1時間)にしています。この頻度の低さは、あとで対策します。

/etc/homeassisntant/configuration.yaml

sensor:
  - platform: rest
    name: Entrance Lock Bottom Sensor
    resource: https://app.candyhouse.co/api/sesame2/E0A1yyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
    headers:
      x-api-key: 4Zb4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    value_template: '{{ value_json.CHSesame2Status }}'
    json_attributes:
      - batteryPercentage
      - batteryVoltage
      - position
      - CHSesame2Status
      - timestamp
    scan_interval: 3600

Home Assistant の Developer Tools > States から値が取得できているか確認しましょう。

制御には Shell Command Integration を使用します。sesameコマンドのパスは、Home Assistant OS ならば/usr/local/bin、Home Assistant Container ならば/config/binになります。

/etc/homeassisntant/configuration.yaml

shell_command:
  lock_entrance_lock_bottom: /config/bin/sesame lock 4Zb4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx E0A1yyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy 0000cf3cf3cf3cf3cf3cf3cf3cf3cf3c
  unlock_entrance_lock_bottom: /config/bin/sesame unlock 4Zb4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx E0A1yyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy 0000cf3cf3cf3cf3cf3cf3cf3cf3cf3c

Home Assistant の Developer Tools > Services から動作するか確認してみましょう。

これらのsensorとshell_commandを Template Lock Integration で一つにまとめます。

/etc/homeassisntant/configuration.yaml

lock:
  - platform: template
    unique_id: lock.entrance_lock_bottom
    name: Entrance Lock Bottom
    value_template: "{{ is_state('sensor.entrance_lock_bottom_sensor', 'locked') }}"
    lock:
      service: shell_command.lock_entrance_lock_bottom
    unlock:
      service: shell_command.unlock_entrance_lock_bottom

私の家の玄関はダブルロックのため、SESAME 4 を2個使用しています。そのため、この2個をまとめて制御できるように、lock.entrance_locksも作成しています。

/etc/homeassisntant/configuration.yaml

lock:
  - platform: template
    unique_id: lock.entrance_lock_bottom
    name: Entrance Lock Bottom
    value_template: "{{ is_state('sensor.entrance_lock_bottom_sensor', 'locked') }}"
    lock:
      service: shell_command.control_lock_entrance_lock_bottom
    unlock:
      service: shell_command.control_unlock_entrance_lock_bottom
  - platform: template
    unique_id: lock.entrance_lock_top
    name: Entrance Lock Top
    value_template: "{{ is_state('sensor.entrance_lock_top_sensor', 'locked') }}"
    lock:
      service: shell_command.control_lock_entrance_lock_top
    unlock:
      service: shell_command.control_unlock_entrance_lock_top
  - platform: template
    unique_id: lock.entrance_locks
    name: Entrance Locks
    value_template: "{{ is_state('sensor.entrance_lock_top_sensor', 'locked') or is_state('sensor.entrance_lock_top_sensor', 'locked') }}"
    lock:
      - service: shell_command.control_lock_entrance_lock_top
      - service: shell_command.control_lock_entrance_lock_bottom
    unlock:
      - service: shell_command.control_unlock_entrance_lock_top
      - service: shell_command.control_unlock_entrance_lock_bottom

Developer Tools > States と Developer Tools > Services から Template Lock の動作確認をしましょう。

sensor.entrance_lock_bottom_sensorのscan_intervalが大きいため、施解錠しても状態がなかなか反映されません。そのため、玄関ドアにZigbeeセンサーをつけ、玄関ドアが閉じた30秒後に SESAME 4 の状態を更新するオートメーションを作成します。ドアを閉めた後に手動で鍵を掛けるまでの時間を待つため、30秒遅らせています。また、その間に何度もドアを開閉する可能性があるため、mode: restart にしています。鍵を手動で施解錠したけどドアは開閉しないという状況はあまりないため、ドアの開閉をトリガーに SESAME 4 の状態を取得すれば十分でしょう。

/etc/homeassistant/automations.yaml

- id: automation.update_entrace_lock_states
  alias: Update Entrance Lock States
  mode: restart
  trigger:
    - platform: state
      entity_id: binary_sensor.entrance_door
      from: "on"
      to: "off"
  action:
    - delay:
        seconds: 30
    - service: homeassistant.update_entity
      target:
        entity_id:
          - lock.entrance_lock_bottom
          - lock.entrance_lock_top

以上で Home Assistant から SESAME 4 などの Sesame OS2 を搭載したスマートロックを使用できるようになりました。

Automationのサンプル

Home Assistant から SESAME 4 が使えるようになったため、私は以下のようなAutomationを作成します。

Sesameアプリでもオートロックの設定は可能ですが、以下では、日中は30分後にオートロック、夜間は10分後にオートロックというように、日中と夜間でオートロックまでの時間を変更しています。また、Manual Alarm Control Panel Integration を使ってalarm_control_panel.entrance_auto_lockを作成し、これをarmed_homeにするとオートロックが有効、disarmedにするとオートロックが無効になるようにしました。これによって、簡単に一時的なオートロック無効を行うことができます。最後に、オートロックが作動した30秒後に SESAME 4 の状態を取得しています。SESAME 4 の最新の状態がクラウドから取得できるようになるまで30秒程度必要です。

lock.entrance_lock_bottomだけでなく、binary_sensor.entrance_door(玄関のドア)が30分閉まり続けていることも条件にしています。この条件がないと、SESAME 4 が解錠された29分後に何も持たずにちょっとした用で外出したときに、その1分後に施錠されてしまって閉め出される可能性があります。オートロックが動くようになると手動で施錠する機会が減るため、1回目の外出で解錠してそのまま、2回目の外出が1回目の29分後という事態は十分にあり得ます。そのため、「SESAME 4 が解錠されて30分経っている AND ドアが30分閉まり続けている」という条件にしています。2回目の外出時のドア開放によってドアが閉まり続けていた時間がリセットされるため、必ず2回目の外出から30分間後にオートロックされるようになります。この2回目に閉め出されかねない問題はSesameアプリを含めたすべてのスマートロック製品のオートロックで発生しますが、Home Assistant でオートロックを実装することで回避できました。

/etc/homeassisntant/configuration.yaml

alarm_control_panel:
- platform: manual
name: Entrance Auto-Lock
code_arm_required: false
delay_time: 0
arming_time: 0
trigger_time: 0

/etc/homeassistant/automations.yaml

- id: automation.auto_lock_entrance_lock_bottom_in_daytime
  alias: Auto-Lock Entrnace Lock bottom in Daytime
  mode: single
  trigger:
    - platform: time_pattern
      minutes: "/5"
      seconds: 5
  condition:
    - condition: state
      entity_id: lock.entrance_lock_bottom
      state: unlocked
      for:
        minutes: 30
    - condition: state
      entity_id: binary_sensor.entrance_door
      state: "off"
      for:
        minutes: 30
    - condition: time
      after: "9:00"
      before: "21:00"
    - condition: state
      entity_id: alarm_control_panel.entrance_auto_lock
      state: armed_home
  action:
    - service: lock.lock
      target:
        entity_id: lock.entrance_lock_bottom
    - delay:
        seconds: 30
    - service: homeassistant.update_entity
      target:
        entity_id: lock.entrance_lock_bottom
- id: automation.auto_lock_entrance_lock_bottom_in_nighttime
  alias: Auto-Lock Entrance Lock Bottom in Nighttime
  mode: single
  trigger:
    - platform: time_pattern
      minutes: "/5"
      seconds: 21
  condition:
    - condition: state
      entity_id: lock.entrance_lock_bottom
      state: unlocked
      for:
        minutes: 10
    - condition: state
      entity_id: binary_sensor.entrance_door
      state: "off"
      for:
        minutes: 10
    - condition: time
      after: "21:00"
      before: "9:00"
    - condition: state
      entity_id: alarm_control_panel.entrance_auto_lock
      state: armed_home
  action:
    - service: lock.lock
      target:
        entity_id: lock.entrance_lock_bottom
    - delay:
        seconds: 30
    - service: homeassistant.update_entity
      target:
        entity_id: lock.entrance_lock_bottom

Zigbeeスイッチを玄関モニターに設置し、玄関モニターの前でスイッチを押すと、玄関に到着したときにはダブルロックが解錠されているようにしています。

/etc/homeassistant/automations.yaml

- id: automation.unlock_entrance_locks
  alias: Unlock Entrance Locks
  mode: restart
  trigger:
    - platform: state
      entity_id: sensor.living_room_1_button_switch_action
      to: single
  action:
    - service: lock.unlock
      target:
        entity_id: lock.entrance_locks
    - delay:
        seconds: 30
    - service: homeassistant.update_entity
      target:
        entity_id:
          - lock.entrance_lock_bottom
          - lock.entrance_lock_top

娘の通う学校では、登下校時に非接触カードをリーダーにかざすと家族にメールが来るシステムが導入されいます。そのため、このメールが下校時に来たら鍵を開けるようにしています。ただし、誰も在宅していない場合は不用心のため、自動解錠は行いません。また、オートロックが作動する30分以内に帰ってこないことがたまにあるため、このオートメーションがトリガーされたときにはオートロックを一時的に解除しています。

/etc/homeassistant/automations.yaml

- id: automation.info_denshobato
  alias: "INFO: Denshobato"
  mode: single
  trigger:
    - platform: state
      entity_id: sensor.denshobato
  condition:
    - condition: template
      value_template: >-
        {{ (as_timestamp(now()) -
          as_timestamp(states('sensor.denshobato_received_date_time'))) < 180 }}
  action:
    - service: notify.all_devices
      data:
        message: "️{{ states('sensor.denshobato_time') }}に{{ states('sensor.denshobato_action') }}しました"
        data:
          push:
            interruption-level: time-sensitive
    - condition: state
      entity_id: sensor.denshobato_action
      state: 下校
    - condition: or
      conditions:
        - condition: state
          entity_id: person.shibata_tats
          state: home
        - condition: state
          entity_id: person.shibata_wife
          state: home
    - delay:
        minutes: 5
    - service: lock.unlock
      target:
        entity_id: lock.entrance_locks
    - service: alarm_control_panel.alarm_disarm
      target:
        entity_id: alarm_control_panel.entrance_auto_lock
    - delay:
        seconds: 30
    - service: homeassistant.update_entity
      target:
        entity_id:
          - lock.entrance_lock_bottom
          - lock.entrance_lock_top

ドアが開くとオートロックは再び有効になります。

/etc/homeassistant/automations.yaml

- id: automation.trun_on_entrance_auto_lock
  alias: Turn on Entrance Auto-Lock
  trigger:
    - platform: state
      entity_id: binary_sensor.entrance_door
      from: "off"
      to: "on"
  action:
    - service: alarm_control_panel.alarm_arm_home
      target:
        entity_id: alarm_control_panel.entrance_auto_lock

念のため、オートロックが2時間以上無効な場合は通知するようにしています。

/etc/homeassistant/automations.yaml

- id: automation.info_entrance_auto_lock_is_off
  alias: "INFO: Entrance Auto-Lock is Off"
  trigger:
    - platform: time_pattern
      hours: "/2"
      minutes: 48
      seconds: 13
  condition:
    - condition: state
      entity_id: alarm_control_panel.entrance_auto_lock
      state: disarmed
      for:
        hours: 2
  action:
    - service: notify.tats_devices
      data:
        message: "Entrance Auto-Lock is Off"
        data:
          url: /lovelace/home
          push:
            interruption-level: time-sensitive

まとめ

Template Lock Integration を使うことで、Sesame OS2 を搭載した SESAME 3 や SESAME 4 スマートロックを Home Assistant に対応させることができます。SESAMEが Home Assistant から使えるようになると、SESAMEの標準機能以上に複雑なオートロックの仕組みを作ったり、より高度なスマートホームを実現できます。

参考

SESAME3 に対応した Web API の使い方 – くらつきねっと

TwitterFacebook