玄関2ロックのセサミを1ボタンで解錠するIFTTTボタンを作ってみた（AWS Lambda経由）

# 背景
我が家の玄関には2ロックのセサミminiがある。公式アプリ経由で解錠はできるのだが、特にWi-fiポイント経由接続とBluetooth経由接続、どっちにつながるかが微妙な距離感では通信が安定化するまでに15~20秒くらいかかることもあり、玄関の前でしばし佇まねばならず特に冬は辛い。

「では公式アプリを使わずに解錠しよう。となるとAPI叩くことになるのか」と考え、pythonistaからお手製のコードを走らせることでiPhoneから直接セサミAPIを叩く方式を取ったが、このpythonistaというやつ、重たいのか何なのか知らないがiPhone上で固まってしまうことが多く、これまた寒いのに玄関前で20秒くらいムダに佇むことが多くなった。

# そこで考えたこと
セサミAPIを叩くpythonコードはpythonista運用時代に確立していたので、これをiPhoneでない環境から動作させようと思った…が、鯖持ってないし鯖買って運用とかやりたくなかったので、AWS Lambdaで動かそうと心に決めた。APIはAWS API Gatewayで作ってやればいいし。

アーキテクチャは下の通り。

![Lambda to Sesame.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512661/acd8966e-f36d-e3d4-5d41-e4723eade976.png)
(描画：https://www.draw.io/?splash=0&libs=aws4 にて)

# 大前提
動作させたい対象のセサミがいずれも[Wi-fiアクセスポイント](https://jp.candyhouse.co/collections/frontpage/products/wi-fi-access-point)に接続されていること。インターネットに接続してなければAPIで動作のしようがない！

# やったこと
## 1. Sesame APIから、APIキーと2台分のセサミIDの取得
以下の公式ブログ記事を参考にしてAPIキーとセサミIDを取得しておく（これは後に書くAWS Lambdaで使用する）。今回は玄関の上下に設置した2台のセサミminiを解錠したいので、セサミIDは2台分得ておくこと。APIキーは1つでOK。

- 公式ブログ記事
    - [APIキー取得方法とセサミIDの確認方法](https://jp.candyhouse.co/blogs/how-to/api%E3%82%AD%E3%83%BC%E5%8F%96%E5%BE%97%E6%96%B9%E6%B3%95%E3%81%A8%E3%82%BB%E3%82%B5%E3%83%9Fid%E3%81%AE%E7%A2%BA%E8%AA%8D%E6%96%B9%E6%B3%95)

## 2. AWS Lambda設定
### 2-1. Lambda新規作成
任意の名前をつけたAWS Lambdaを作成する。なおAPI Gateway以外のAWSリソースとは関連させる必要がないので、設置する場所はVPCの外でOK。

### 2-2. 外部モジュール`pysesame2`のアップロード
Candyhouse側にあるAPIを叩いて動かすため、後にLambdaに記述するpythonコードでは`pysesame2`という外部モジュールを使用する。しかしAWS Lambdaというのはデフォルトで動かせるモジュールの種類が少なく、またpipで外から取ってくるとかそういうことができないっぽいので予めzipファイルにしてアップロードする必要があるとのこと。

ということで、手元の環境で`pysesame2`ダウンロードしてきてzipにしてアップロードする。具体的な手順は次の記事を参考にしていただければOK。

- [【Python】AWS Lambdaで外部モジュールを使用する](https://qiita.com/SHASE03/items/16fd31d3698f207b42c9)

### 2-3. Pythonコードを記述
zipファイルアップロード後のLambdaに対して、次のようにコードを記述。Pythonバージョンは割と何でもいいんでしょうけど、3.8で動いたので3.8にしときました。

```Python 
from uuid import UUID
from pysesame2 import Sesame
import os

device_id_1 = UUID(os.environ['DEVICE_ID_1']) # 'DEVICE_ID_1'は後に環境変数として別窓に入力する、1台目セサミID。
device_id_2 = UUID(os.environ['DEVICE_ID_2']) # 'DEVICE_ID_2'は後に環境変数として別窓に入力する、2台目セサミID。

def lambda_handler(event, context):
    APIKey = event['apikey'] # 後にIFTTTから送られてくるJSONから、キー`apikey`のvalueを開封して変数`APIKey`に代入
    sesame_1 = Sesame(device_id_1, APIKey)
    sesame_2 = Sesame(device_id_2, APIKey)
    sesame_1.async_unlock() # 1台目解錠命令
    sesame_2.async_unlock() # 2台目解錠命令
```
コードが書けたらその下の「環境変数」に、次にように2台のセサミIDを1つずつ書いて保存する。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512661/1bb6dc38-b748-b86b-7bd0-c2a7f6822e2f.png)

### 2-4. テスト
以上までできたら画面右上の「テスト」から、テストイベントに以下のようなJSONを記述してコードをテスト。セサミ2台が解錠すれば成功。

```json
{"apikey": "{あらかじめ取得しておいたAPIキー}"}
```

## 3. API Gateway設定
[この記事](https://qiita.com/miko88/items/7f5ebebd2549e1b8105b)を参考にしていたのですが、これの「Amazon API GatewayでLambdaのコードを外部から実行できるようにする」に書いている通り、次の2記事を参考にしてAPI Gatewayを設置して先のLambdaに関連させました。

- [AWS API Gateway+LambdaでSlackにメッセージをPOSTする(中編) - 年中アイス](https://reiki4040.hatenablog.com/entry/2017/02/03/220214)
- [AWS API Gateway+LambdaでSlackにメッセージをPOSTする(後編) - 年中アイス](https://reiki4040.hatenablog.com/entry/2017/02/11/232357)

## 4. IFTTT設定
`Button Widget`などを立ててトリガーにし、`Webhooks`から次のように設定。

| 項目名       | 設定内容 |
|--------------|---------|
| URL          | デプロイしたAPI GatewayのエンドポイントURL |
| Method       | POST |
| Content Type | application/json |
| Body         | {"apikey": "{あらかじめ取得しておいたAPIキー}"} |

ここまで設定して`Button Widget`を叩くと、セサミが2つとも解錠しました！

# 動作の具合
押してから実際の解錠までにはやはり15秒くらいのタイムラグがあるのですが、玄関の前に立ってBluetooth接続が確立するまで待ってボタンをす必要もなくなったし、操作するボタンも1つになってとても幸せです。

実際使用する場面としては、まず自室を目指してマンションのエレベーターに乗り、乗ってる間に`Button Widget`を押したら、目的階に到着するタイミングでちょうどセサミが開く感じです。玄関前に15~20秒立って寒い思いをすることがなくなりましたし、何よりエレベーターの扉が空いたらちょうどセサミが開く感じになるので、手に多くの荷物を持っていたり、子供を連れていたりする際にとても玄関に入るのが楽で、本当にとても幸せです！！