この記事について
この記事は Akatsuki Games Advent Calendar 2023 の8日目の記事です。
Advent Calendar の7日目はなかひこくんの
Terraform で CloudRun + Identity-Aware Proxy をやっていく 2023 でした。
記事内にある基盤は本当にお世話になっていて、自分もクライアントの立場から貢献をしていきたいところです…!
作るきっかけ
自分は 自宅のドア と アパートのエントランスドア(この規模では珍しい気がする)を開ける解錠ボタン にスマートロックのsesameを使用しています。
また、wifiモジュールを使用してbluetooth圏外からも操作できるようにしています。
ただ操作はsesame公式のアプリを使用していたのですが、wifi経由だと反応しない場合が何回かあり家に入りたいのに入れない!という状況があったためより使いやすい手段を探す事にしました。
使用するもの
- line bot
- aws lambda
- python3.10.11
line botを選んだ理由は
- lineの公式アカウントとかでメニューからメッセージを送る機能が個人的にはわかりやすかった
- line botにちょっと興味があった
aws lambdaを選んだ理由は
- こちらも単純に興味から
フロー
line botの構築
構築ページ
上記リンクにアクセスして、ログインをします
新規プロバイダーの作成
Line Developerトップ から Providersの赤枠Createを選択します
Messaging API channelの作成
今回はメッセージのやり取りを行うので Messaging API channel
を選択します
アクセストークンの作成
作成したchannelを開いて、Messaging APIを選択します
一番下にアクセストークンを発行する項目があるので、Issue
を押して発行します
なお、出てきた文字列はメモをしてください
account managerへ移動する
作成したchannelのページから、 赤枠の Line Official Account Manager
へアクセスします
line account managerでメニューを構築する
リッチメニューの作成
作成
account manager の タブから ホーム
を選択して、左のメニューから リッチメニュー
を選択します
すると、リッチメニューを作成 と出ているので選択します
タイトルと表示期間を設定
とりあえず 2037年まで有効にしておきます
テンプレートと画像を変更する
テンプレートは3つのボタンに
画像
を選択すると、全体かエリア毎が出てくるのでエリア毎にします
とりあえず単色塗りつぶしをしておきます。
押した時のアクション
タイプを テキスト
にして、開ける、閉める、エントランス用で設定します
ここのテキストは後ほど実行するコードで合わせる必要があります。
webhookの有効化
上のタブの右側にある設定
を選択して 左のメニューから 応答設定
を選択して 応答機能
にある Webhook
のみ有効にしておきます
sesame apiにアクセスするための設定
api利用のために登録
https://partners.candyhouse.co/login/
上記リンクにアクセスしてログインをします
Keyを取得する
-
ご利用中のapi key
をメモしておく - 既にデバイスを登録している場合は、赤枠の
user devices
を選択してデバイスを取得します - 右側の赤枠のデバイスを選択すると、UUIDとSecret Keyが表示されるのでメモをしておきます
AWS Lambdaで実装する
使用するpythonのライブラリをまとめる
仮想環境にインストール
必要なライブラリのみzip化していくので仮想環境内にインストールしていきます
mkdir aws-line-bot
cd aws-line-bot
python -m venv venv
./venv/scripts/activate
python -m pip install line-bot-sdk
zip化
仮想環境にline-bot-sdkをインストールしたら、これをzip化していきます
- pythonフォルダを作成し、
./venv/Lib/site-packages
下のフォルダをpythonフォルダへコピーします - pythonフォルダをzip化
レイヤーにライブラリを登録する
aws Lambdaにアクセスしたら、左のメニューから その他のリソース
-> レイヤー
-> レイヤーの作成
を選択します
先程zip化したpythonライブラリを登録します。
また、今回はpython3.10 + windows11を用いて作成したのでpython 3.10とx86_64を指定します
関数を作成する
では、本題の関数を作成します
AWS Lambda から 左のメニューより 関数 -> 関数の作成 を選択します
一から作成を選択した後は、ライブラリの時と同じバージョンをとアーキテクチャを指定しておきます
環境変数に必要な情報を登録しておく
関数を作成したら、まずは必要になる環境変数を登録していきます
- sesameのAPI Key
- sesameのデバイス毎のUUIDとSecret Key
- Line botのAccess Token
以上を登録します
自分はこんな感じになりました
sesame botはエントランスを開ける用のsesame botで
upperとlowerに分かれているのは玄関ドアには2つ鍵があるためです
使用するレイヤーを登録する
ページ一番下に レイヤー
があるので レイヤーの追加
を選択します
先程zip化してアップロードしたレイヤーを追加
そして、もう一つ pycryptodome
を使用するために下記ページからARNを持ってきます
https://github.com/keithrozario/Klayers/tree/master/deployments/python3.10
サンプルの実行コード
https://doc.candyhouse.co/ja/SesameAPI#web-api-%E3%81%AB%E3%82%88%E3%82%8B%E6%96%BD%E8%A7%A3%E9%8C%A0
sesame apiのドキュメントはこちら
ここで注意してほしいのが、sesame botを操作する場合のコマンドコードは 89
となります
ドキュメントには以下のコマンドがありますが、このコマンドでsesame botを動かすと回転量がおかしくなってしまいます。
コマンドコードリスト
toggle:88
lock:82
unlock:83
※ 1つ謝罪として89で動く事を発見したブログ記事があったのですが、今探しても全然見つからず参考に載せられませんでした。もしありましたらコメントに書き込んでいただけると助かります。
以下がサンプルの実行コードとなります
import os
import json
from linebot import LineBotApi
from linebot.models import TextSendMessage
# sesame apiと通信する時に使用する
import Crypto.Cipher.AES as AES
from Crypto.Hash import CMAC
import json
import base64
import datetime
import requests
LINE_CHANNEL_ACCESS_TOKEN = os.getenv('LINE_CHANNEL_ACCESS_TOKEN')
SESAME_KEY = os.getenv('SESAME_KEY')
# エントランスドアを開けるsesame bot
SESAME_BOT_ID = os.getenv('SESAME_BOT_ID')
SESAME_BOT_SECRET_KEY = os.getenv('SESAME_BOT_SECRET_KEY')
# 玄関のドアにあるsesame
SESAME_UPPER_ID = os.getenv('SESAME_UPPER_ID')
SESAME_UPPER_SECRET_KEY = os.getenv('SESAME_UPPER_SECRET_KEY')
bot_api = LineBotApi(LINE_CHANNEL_ACCESS_TOKEN)
def sesame_post(id, key, command):
url = f'https://app.candyhouse.co/api/sesame2/{id}/cmd'
headers = {"x-api-key" : SESAME_KEY}
message = int(datetime.datetime.now().timestamp()).to_bytes(4, byteorder='little').hex()[2:8]
cmac = CMAC.new(bytes.fromhex(key), bytes.fromhex(message), ciphermod=AES)
sign = cmac.hexdigest()
body = {"cmd":command, "sign":sign,"history":base64.b64encode("Linebotから".encode()).decode()}
# sesame web apiへリクエスト
requests.post(url, headers=headers, data=json.dumps(body))
def lambda_handler(event, context):
try:
events = json.loads(event['body'])['events']
# メッセージではない場合は終了する
if events[0]['type'] != 'message':
return {'statusCode': 200, 'body': json.dumps('成功')}
# メッセージの種類がテキスト以外だった場合は終了する
if events[0]['message']['type'] != 'text':
return {'statusCode': 200, 'body': json.dumps('成功')}
# line botから送られてきたメッセージを判定する
messageText = events[0]['message']['text']
if messageText == "鍵を開ける":
sesame_post(SESAME_UPPER_ID, SESAME_UPPER_SECRET_KEY, 83)
elif messageText == "鍵を閉める":
sesame_post(SESAME_UPPER_ID, SESAME_UPPER_SECRET_KEY, 82)
elif messageText == "エントランス開ける":
sesame_post(SESAME_BOT_ID, SESAME_BOT_SECRET_KEY, 89)
replyToken = events[0]['replyToken']
bot_api.reply_message(replyToken, TextSendMessage(text="完了"))
except Exception as e:
print(e)
return {'statusCode': 500, 'body': json.dumps('失敗')}
return {'statusCode': 200, 'body': json.dumps('成功')}
デプロイ
コードソースより Deploy
を選択してデプロイを行い実装は完了となります
AWS API Gatewayに登録
作成
関数が出来たらAPIのトリガーに登録をします。
関数の概要より、 トリガーを追加を選択します
ひとまず動作を行いたいので、Create a new API
と REST API
を選び追加をします
URLのコピー
白塗りつぶしの部分にURLがありますので、コピーをします
LinebotのWebhookにAPI URLを登録する
Line Developersに戻り、Webhook settings
より先程コピーしたURLを登録します
実行する端末からLinebotを友だち登録する
Line Developers のチャンネルから Messaging APIを開いて、QRコードを読み取ります
これで全ての作業が完了しました。
実際の動作の様子
色々と変えていますが、以下のように終わったら返答が返ってきます。
結果
目的にあった反応しないを解消するについては今のところ達成できています。
ただし、サンプルのままでは複数のデバイスを動かすと都度待ってしまいますので、async等を使用して非同期でそれぞれを実行するのが良いかと思います。
参考
- https://www.ryucom.co.jp/blog/aws/4713
- https://www.actie.smagai.com/%E3%82%BB%E3%82%B5%E3%83%9F%E3%81%AEapi%E3%82%AD%E3%83%BC%E5%8F%96%E5%BE%97%E6%96%B9%E6%B3%95/
明日の記事は Yusuke Nakajimaさんより UnityのProjectWindowに表示履歴機能を付けるエディタ拡張 とのことです。
エディタ拡張いいですよね!既存のProjectWindowにつけるということでどう付けるか気になるところです。