いろいろあって会社オフィスの1FにSESAME3を導入しました。
SESAME3+スマホの組み合わせでも十分便利だけど、やっぱりWEB API使いたい!
というわけで始めました。
(1Fだけはスマホで開けてね、って言っても社内から反発ありそうだし…)
さほど難解なところもないので、公式ページを見ながら進めれば大丈夫です。
(載せたコードもほぼ公式そのままです)
導入環境
- Raspberry Pi 4
- Ubuntu Server 20.04 LTS
- Python 3.9.6
- SESAME3
- SESAME3用 Wifiモジュール
WEB APIに必要な情報(SESAME3)
- API Key(APIキー)
- Secret Key(秘密鍵)
- UUID
API Key
まずCandyHOUSEダッシュボードにアクセスして、API Keyを入手しましょう。
以下画面にメールアドレスを入力すると、4桁の認証コードがメールで届きます。
届いた認証コードを入力してログインします。
ログイン後に表示される「API Key」の中の文字列をコピーしておきましょう。
(Client IDはいまのところ使い道がわからないです…)
Secret Key
秘密鍵の確認はちょっと面倒です。(もっと良い方法あれば教えてほしい)
SESAMEの専用アプリ「セサミ、ひらけごま!」を利用します。
「セサミ」などでストア検索するとアプリが2つ出てきますが、SESAME3では「セサミ、ひらけごま!」を使います。
もうひとつの「SESAME セサミ」は旧バージョンのSESAMEで利用するようです。
※リンクはiPhoneアプリです。Android版はこちら。
アプリを起動して、SESAME3を登録したあとにメニュー画面から鍵のシェアをおこなうとQRコードが表示されます。
スマホ間で鍵を共有するときに利用するQRコードですが、これをスマホのQRコードリーダなどで読み取ると
ssm://UI?t=sk&sk=xxxxxxxxxxxxxxxxxxxxx&l=0&n=xxxxxxxxxxx
のような文字列が取得できるので、ここからsk
の部分を抜き取ります。(秘密鍵)
パースをかけたりして抜き出すかたもいるようですが、自分は目視で抜き取りました。
分解するとこんな感じ
t=sk sk=xxxxxxxxxxxxxxxxxxxxx l=0 n=xxxxxxxxxxx
のちほどこのsk
をCMACで暗号化して利用しますので、文字列をコピーしておきましょう。
(これをそのままGithubに乗せてるっぽいの見かけるけど大丈夫なんかな…?)
UUID
UUIDもSecret Keyと同じく専用アプリのメニュー内から確認できます。
メニューの一番下に表示されます。
こちらもUUID部分の文字列をコピーしておきましょう。
WEB API動作
URL : https://app.candyhouse.co/api/sesame2/
SESAME3のステータスを取得する
先程ダッシュボードで取得したAPI Keyをヘッダー(x-api-key)に入れて、GETすると現在のステータスが確認できます。
URL末尾のUUID
には、アプリで取得した自分のSESAME3のUUIDを入れます。
% curl -H "x-api-key":"[myapikey]" https://app.candyhouse.co/api/sesame2/[UUID]
{"batteryPercentage":100,"batteryVoltage":6.0316715542522,"position":-121,"CHSesame2Status":"locked","timestamp":1628937684,"wm2State":true}%
バッテリー情報、サムターンのポジション、施錠状態などが確認できます。
(施錠・解錠ログを取得するAPIもありますが、今回は割愛)
解錠・施錠
公式ページを参照するとBODY
にcmd
、history
、sign
をつけてPOSTすれば良いとのこと。
POST: "https://app.candyhouse.co/api/sesame2/${sesame_id}/cmd"
BODY: {
cmd: cmd,
history: base64_history,
sign: sign
}
※上の「${sesame_id}」はUUIDのこと
BODY | 公式説明 | 備考 |
---|---|---|
cmd | 開閉コマンドコード | toggle:88、lock:82、unlock:83 |
history | 履歴 | 操作ログを見たときに表示される名前 |
sign | 署名 | 秘密鍵をAES-CMACで暗号化した署名 |
※toggle って何に使うんですかね… |
Pythonからアクセス
以下、Python3での動作です。
pysesame3というSESAME3専用ライブラリもありますが、今回は利用していません。
ライブラリ
今回使用するライブラリをインポートします。
事前にpip
でインストールしておきましょう。
pip install pycryptodome requests
import datetime, base64, requests, json
from Crypto.Hash import CMAC
from Crypto.Cipher import AES
パラメータ(APIキー、秘密鍵、UUID)
先程取得した各種パラメータを使います。
# 各種パラメータ
uuid = 'my-uuid'
secret_key = 'my-secret_key'
api_key = 'my-api_key'
BODY
まずは開閉のコマンドcmd
に値を入れます。
今回はlock:82
で施錠します。
# cmd
cmd = 82
続いてhistory
は自分でわかりやすい名前をつければ良いだけなので、「WEB API」としました。
複数ノードからAPIを叩く場合には、判別できるように名前を区別したほうがよいかもしれません。
base64でエンコードしてからbody
に入れます
# history
history = 'WEB API'
base64_history = base64.b64encode(bytes(history, 'utf-8')).decode()
署名部分は秘密鍵をCMAC
を利用して暗号化します。
タイムスタンプを追加してから、HEXのダイジェスト値を作ります。
# sign
cmac = CMAC.new(bytes.fromhex(secret_key), ciphermod=AES)
ts = int(datetime.datetime.now().timestamp())
message = ts.to_bytes(4, byteorder='little')
message = message.hex()[2:8]
cmac = CMAC.new(bytes.fromhex(secret_key), ciphermod=AES)
cmac.update(bytes.fromhex(message))
sign = cmac.hexdigest()
あとはAPIリクエストをセットして完了です。
# API
url = f'https://app.candyhouse.co/api/sesame2/{uuid}/cmd'
body = {
'cmd': cmd,
'history': base64_history,
'sign': sign
}
res = requests.post(url, json.dumps(body), headers=headers)
コード全体
実際の運用では、クラスオブジェクトにしてレスポンスの確認やエラー処理などを追加していますが、単体の動作確認だけであればこのコードだけでも十分です。
import datetime, base64, requests, json
from Crypto.Hash import CMAC
from Crypto.Cipher import AES
# 各種パラメータ
uuid = 'my-uuid'
secret_key = 'my-secret_key'
api_key = 'my-api_key'
# ヘッダーの設定
headers = {'x-api-key': api_key}
# cmd
cmd = 82 # 施錠する場合は「82」、解錠する場合は「83」
# history
history = 'WEB API' # とりあえず「WEB API」と名付ける
base64_history = base64.b64encode(bytes(history, 'utf-8')).decode()
# sign
cmac = CMAC.new(bytes.fromhex(secret_key), ciphermod=AES)
ts = int(datetime.datetime.now().timestamp())
message = ts.to_bytes(4, byteorder='little')
message = message.hex()[2:8]
cmac = CMAC.new(bytes.fromhex(secret_key), ciphermod=AES)
cmac.update(bytes.fromhex(message))
sign = cmac.hexdigest()
# API
url = f'https://app.candyhouse.co/api/sesame2/{uuid}/cmd'
body = {
'cmd': cmd,
'history': base64_history,
'sign': sign
}
res = requests.post(url, json.dumps(body), headers=headers)
注意すること
詳細は公開されていないようですが、WEB API利用数に制限があるようです。
正確な数字はわかりませんが、1アカウントにつき900-1000回くらいのようです。1日放置したら制限は解除されていました。
CANDYHOUSE様に問い合わせたところ、WEB APIの有料化が予定されていて、その後有料ユーザは利用制限が解除されるそうです。
現時点でWEB API利用は無料です。(2021年8月時点)
利用頻度が高い場合は注意です。締め出されたり閉じ込められたりします…。