IFTTTとRaspberry Piを連携させて、SESAME3の手ぶら解錠を実現する

SESAME3のアプリには位置情報を使った「手ぶら解錠」という便利な機能がついていますが、バッテリー消費が激しくて、スマホのバッテリーが一日持たないことも…。
IFTTTのアプリなら、位置情報を常にオンにしておいてもバッテリーの減りはそこまで激しくならないので、これを使えないかと思い、やってみました。
今回は手ぶら解錠だけでなく手ぶら施錠も行えるようにします。

※筆者は初めて使うサービスなどが多いため、間違った説明や、いらない工程があったりするかも。とりあえず正常に動作はしています。


使用したもの
------------------------------
* iPhone11 Pro iOS14.6
* SESAME3 API
* IFTTT
* Beebotte
* Raspberry Pi
* pysesame3
* Node-RED


全体的な動作
------------------------------
1. iPhone11が自宅周辺に入る・自宅周辺から出る
1. IFTTTアプリがwebhooksでJSONデータ送信
1. BeebotteがRaspberry PiのNode-REDにJSONデータ送信
1. Node-RED上でJSONデータを処理してexecでSESAME3を動作させるPythonプログラム`run.py`を実行
1. SESAME3が解錠・施錠される。

`IFTTT -> Beebotte -> Node-RED -> run.py`



SESAME3のAPI KEYとSecret KEY、UUIDの取得
------------------------------
### 1. API KEYの取得
https://dash.candyhouse.co/login からログインして、ダッシュボードでAPI KEYの確認が可能です。
(参考：https://doc.candyhouse.co/ja/SesameAPI)
### 2. Secret KEYの取得
セサミ３アプリの設定で確認できる２次元コードを使用して取得します。
#### 方法１：２次元コードから自前で取得
> iPhone の場合は「ショートカット」アプリで新規ショートカットを作成し、「書類」の「QR/バーコードをスキャン」と「Quick Lookで表示」を追加し、「QR/バーコード」を「テキストとして」にしておくとQRコードの中身をテキストのまま得られます。

> `sk=` の値をコピーしておいて、Base64 decode した文字列の1-17文字が secret key になります。

>(https://kuratsuki.net/2021/06/sesame3-%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%9F-web-api-%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9/ より引用)

#### 方法２：Webアプリに２次元コードを読ませる
こちらの方がお手軽です。

https://sesame-qr-reader.vercel.app/

※筆者はiPhoneからだとうまくいかなかったので、PCに２次元コードを送信して読み込ませました。


２次元コードはアプリの設定の「このセサミの鍵をシェア」で写真アプリに保存したりできます。
![IMG_1059_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/9732a6c6-0a5a-5d6a-b942-fd23d01b5f89.jpeg)


### 3. UUIDの確認
UUIDはアプリの設定で確認できます。
![IMG_1059.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/b921c86e-a600-abcf-a11c-738284550ff6.jpeg)



pysesame3を使用してPythonスクリプトを作成
------------------------------
pysesame3はSESAME3を解錠・施錠などするために必要な非公式Pythonライブラリです。
### 1. pysesame3のインストール
`pip install pysesame3`でインストール
(参考：https://pypi.org/project/pysesame3/)

### 2. 解錠と施錠を行うPythonスクリプトを作成
今回のスクリプトの実行では、IFTTTから送られたJSONデータの値を引数とし、解錠と施錠の動作を分けたり、実行する人の名前をログに残すようにします。そのため、`sys.argv[1]` `sys.argv[2]`を変数に格納する処理を書いています。

~~~ run.py
import sys

from pysesame3.auth import WebAPIAuth
from pysesame3.lock import CHSesame2

# ロックかアンロックの引数を格納
lock_param = sys.argv[1]
# ロック解除した人の名前の引数を格納
people_name = sys.argv[2]

# API KEY
auth = WebAPIAuth(apikey="<API KEY>")

# UUID
your_key_uuid = "<SESAME3のUUID>"

# Seacret KEY
your_key_secret = "<Seacret KEY>"

device = CHSesame2(
        authenticator=auth,
        device_uuid=your_key_uuid,
        secret_key=your_key_secret,
)

# 解錠処理
if lock_param == "unlock":
    status = device.unlock(history_tag="帰宅: "+people_name)
elif lock_param == "lock":
    status = device.lock(history_tag="外出: "+people_name)
else:
    status = False
# ステータス出力
if status == True:
    print("Success!")
    sys.exit(0)
else:
    print("Error!", file=sys.stderr)
    sys.exit(1)
~~~

今回は`/opt/sesame3/`に`run.py`として保存しました。

`python3 /opt/sesame3/run.py unlock nanashi`で動作確認できると思います。
動作すると解錠され、SESAME3のアプリの履歴に「帰宅：nanashi」と表示されます。




Beebotteの設定
------------------------------
https://beebotte.com/

### 1. チャンネルの作成
右上のCreate Newからチャンネルを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/dda567c3-74f6-652d-a8c2-5e275f1a5e0f.png)

好きなチャンネル名（今回は`raspi_sesame`）を入力し、リソース名は`sesame`としました。`Create channel`でチャンネル作成が完了します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/693b3a86-6f21-094e-97fe-7aa835c6f5a8.png)

### 2. チャンネルのトークンを確認
IFTTTの設定にて使用するトークンを確認しておきます。
トークンは**"token"から始まる赤文字の部分**になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/dfe50a18-a316-7783-a836-4f259743abc2.png)




IFTTTの設定
-----------------------------
https://ifttt.com/home

iPhoneの位置情報によるアクションを実行するためにIFTTTを設定していきます。
右上の`Create`をクリックしてアプレットを作成しましょう。

### 1. If Thisの設定
`IF This Add`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/7125e4d4-c059-3c2b-67c5-ea11ffd3b176.png)

「Choose a service」で`Location`を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/dc71fb3d-b174-427c-5566-1f1dae931dfd.png)

「Choose a trigger」で`You enter an area`をクリックして、どの位置に自分が入ったら解錠するかを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/bdfd21ee-a5b3-4ea6-493c-40b2c230359c.png)
自宅が円の中心に来るようにすると良いでしょう。
`+`と`-`をクリックすることで、ある程度円の範囲を広げたり狭めたりできます。誤作動が多い場合は広めにするといいかも。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/f7e65e33-dfd9-ee93-5699-a41230df3f1d.png)
`Create trigger`をクリックすると以下のようにIf Thenの設定が完了します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/73af0d4f-66a3-fba8-6c48-fa15b4ecbd4b.png)

### 2. Then Thatの設定
同じ要領で、今度は`Then That`を選択。指定したエリアに入ったらどのような動作をするかを選択します。Beebotteと連携させるために、`Webhooks`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/d2491f81-6c7e-f0d5-a230-8a2c130bad11.png)

#### WebhooksのURL
URLは
`https://api.beebotte.com/v1/data/publish/<チャンネル名>/<リソース名>?token=<トークン>`
となります。
チャンネル名、リソース名、トークンは[Beebotteで設定・確認したもの](#beebotteの設定)を使用します。
今回の例だと
`https://api.beebotte.com/v1/data/publish/raspi_sesame/sesame?token=token_xxxxxxxxxxxxxxxxx`
となります。

#### WebhooksのMethod
`POST`を選択

#### WebhooksのContent-Type
`application/json`を選択

#### webhooksのbody
bodyにはJSON形式でデータを記述します。

~~~ JSON
{"data":{"key":"unlock", "name":"解錠する人の名前"}}
~~~

※iPhoneのIFTTTアプリから設定を行う場合、キーボードからそのまま`"`を入力すると、左斜のダブルクォーテーションになってしまい、正常に動作しません。iPhoneから入力するときは、**`"`を長押しして入力します。**
![イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/8135e3de-9269-941b-6a5e-2d1f6fc6766e.png)


### 3. 手ぶら施錠の場合
手ぶら施錠を設定したい場合は、[If This Addの設定](#1-if-thisの設定)で`You exit an area`を選択し、bodyのJSONデータは

~~~ JSON
{"data":{"key":"lock", "name":"施錠する人の名前"}}
~~~
とします。



Node-REDのインストールと起動
-------------------------------
[Raspberry Piで実行する : Node-RED日本ユーザ会](https://nodered.jp/docs/getting-started/raspberrypi)を参考に設定していきます。


### 1. Node-REDのインストール
以下のコマンドを実行してNode.js、npm、Node-REDをインストールします。
>~~~ bash
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
~~~
(https://nodered.jp/docs/getting-started/raspberrypi から引用)


### 2. Node-REDがRaspberry Pi起動時に自動的に起動するようにする
> ~~~
sudo systemctl enable nodered.service
~~~
(https://nodered.jp/docs/getting-started/raspberrypi から引用)

### エディタを開く
`http://<Raspberry PiのIPアドレス>:1880` でブラウザからエディタを開くことができます。




Node-REDのエディタで手ぶら解錠のフローを作成する
------------------------------
### 1. mqtt inノードを配置
ノード一覧の**ネットワーク**から`mqtt in`というノードを探します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/481a6c14-e036-0c73-668e-1d3b47001534.png)

ノードをドラッグアンドドロップで置きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/a37a2fa1-ad10-0913-a42d-e17b6a2aa2e4.png)

#### mqtt in ノードを編集
mqtt in ノードをダブルクリックして設定を開き、**トピック**に`<Beebotteのチャンネル名>/<Beebotteのリソース名>`を入力します。
今回の例では`raspi_sesame/sesame`
入力したら、`鉛筆マーク`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/7a50eb6e-ce41-b603-1231-ee1ceecdbb38.png)

「新規にmqtt-broker ノードの設定を追加」の接続タブにて、以下の通りに設定します。

|項目|設定値|
|:-|:-|
|サーバ|mqtt.beebotte.com|
|ポート|8883|
|SSL/TLS接続を使用|○|
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/e73ec0b6-b556-00e3-28bf-41764697a002.png)



セキュリティタブのユーザ名にBeebotteの[チャンネルのトークン](#2-チャンネルのトークンを確認)を設定します。

| 項目 | 設定値 |
|:-|:-|
| ユーザ名 | token:token_xxxxxxxxxxxxxxxx |
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/1be41eb4-9c88-08fd-c52f-8f763f1e6b64.png)

右上の`更新`ボタンをクリックして戻り、下の画像の通りに設定できたら**完了**をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/dc470400-33ae-7889-5c02-e622d049d0ff.png)

mqtt inが設定できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/974bfb82-77e7-e9bb-9cd4-f0e36681abf7.png)


### 2. json ノードを配置
Beebotteから渡されたJSON文字列をオブジェクトに変換するために、左のノード一覧の**パーサ**から`json ノード`を持ってきて接続します。
変換するだけなので、特に編集するところはありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/15ae7d6f-6c53-b4ef-f65a-ef61cedca50b.png)

### 3. template ノードを配置
ノード一覧の**機能**から、`template ノード`を持ってきて接続します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/78a7bb50-e720-07d6-e60e-bb94f99e1f55.png)

#### template ノードの編集
[IFTTTで設定した](#webhooksのbody)JSONの`key`と`name`の値を`run.py`実行時の引数とするために、値を取り出して並べます。
template ノードをダブルクリックし、**テンプレート**の部分を以下の通りに書き換えます。

~~~ mustache
{{payload.data.key}} {{payload.data.name}}
~~~
今回の場合、`unlock 解錠する人の名前`が出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/e413a87f-5bcf-dfa5-5fde-56f953b37856.png)

`完了`ボタンをクリックして編集完了です。

### 4. exec ノードを配置
Pythonスクリプトを実行するために、ノード一覧の**機能**から`exec ノード`を持ってきて接続します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/e15865e8-cefc-9110-9cde-2f816822dc61.png)

#### exec ノードの編集
exec ノードをダブルクリックし、**コマンド**を`python3 -u /opt/sesame3/run.py`と設定します。
**引数**のmsg.payloadにチェックが付いているため、先程`template ノード`で設定した文字列が引数として設定されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/fb82a2d7-68ff-a3fe-3e30-fd834e23df35.png)

`完了`ボタンをクリックして編集完了です。

### 5. debug ノードを配置
debugノードを配置することで、エラーが出たり、うまく動かない場合に原因を特定しやすくなります。
ノード一覧の**共通**から`debug ノード`を持ってきて接続します。
ダブルクリックして名前を付けるとわかりやすくなります。
`exec ノード`の出力は、上から`標準出力`、`エラー出力`、`返却コード`となっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/07fac902-3040-0c4f-d15c-572f9239c9a4.png)

### 6. デプロイ
デプロイすることで、配置したノードが反映され、使える状態となります。
`デプロイ`をクリックすればいよいよ完成です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/529cb539-a9be-c9e2-775d-1256ab4e0626.png)


動作確認
-------------------------------
IFTTTの**If This**を`Location`から`Button widget`に変えて、手動で実行することで、IFTTTからの動作がうまく行えているか確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/c0250670-128c-fbe4-ad88-c5ef5b18561e.png)

Node-REDの右側の虫マークのタブをクリックすることで、デバッグ情報が見られます。うまく動作しているのがわかりますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/2ee7991b-04b3-3f67-46da-f12d952b14c0.png)

アプリの履歴にも反映されています。
![イメージ (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138183/c6ebc822-eeae-1033-bc95-ce953ad36fce.png)