はじめに
今回はSlack Botを用いて部屋の鍵の施錠や開錠を行うシステムを構築しようとしたのでその記録を残しときます
Slack botを作成して送信したメッセージに応じて返信するところまで書きます(時間足りなかった…)
注意
筆者はごりごりのプログラミング初心者で間違っているところや適当なところ、必要のないことをしているかもしれませんが温かい目で見ていただけただ幸いです
また、本記事を真似するのは自己責任でお願いします(一応)
もくじ
1.開発環境
2.システム概要
3.Webhookされるサーバーの作成
4.サーバー上の確認コード作成
5.Slack Botの作成
6.実際のサーバーのコード作成
7.ESP32上のコード作成
8.動作確認
9.あとがき
1.開発環境
Ubuntu 20.0.4
python3.8.10
ngrok 2.3.40
2.システム概要
3.Webhookされるサーバーの作成
Ubuntuのインストールや基本的なセットアップは終了してるものとして話していきます
3.1 ngrokのインストール
まずコマンドを使ってngrokをインストールします
sudo snap install ngrok
次のコマンドでインストールがしっかりできてngrokが仕事してくれることを確認します(80は使用するポート番号)
ngrok http 80
このコマンドを打つと次のように表示されていたらインストールは成功しています。
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Session Expires 1 hour, 59 minutes
Version 2.3.40
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://2467-2400-4150-52e2-6200-264b-feff-fe90-8af
Forwarding https://2467-2400-4150-52e2-6200-264b-feff-fe90-8a
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
ちなみにこの状態で「http://127.0.0.1:4040 」にアクセスできることも確認しておきましょう
ただ、この状態では少し問題があってどうやらログインしないと2時間で自動的に終了してしまうようなのでここでアカウント登録します(無料版で大丈夫です)
アカウント登録後に表示されるこのサイトの「Connect your account」という欄に書いている
ngrok authtoken {authToken}
の欄をコピペしてコマンドに打ち込んでください
その状態で先程の
ngrok http 80
を入力するとその実行結果が少し変わって時間制限がなくなります
とはいえ無料版にはIPが固定できない欠点があり、ngrokを起動するたびにURLが変わってしまいます
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Account {ここが時間からアカウントに変化する}(Plan: Free)
Version 2.3.40
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://0d77-2400-4150-52e2-6200-264b-feff-fe90-8af
Forwarding https://0d77-2400-4150-52e2-6200-264b-feff-fe90-8a
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
これでngrok自体のインストールと初期設定は終了です。
4.サーバー上の確認コード作成
次にこのwebhookされるサーバー(今作ったやつ)にアクセスされたときに実行されるコードを作っていきたいと思います。
まず最初にSlackのEvent APIにWebhookとして登録するときにサーバーの存在確認用のリクエストが来るため、それに対応するコードを書く必要があります。(詳しくは公式ドキュメントを見てね)
公式ドキュメントによると以下のようなPOSTリクエストが来ます。(公式ドキュメントからの引用なので実際に来る際は少し違うかもしれません)
{
"token": "Jhj5dZrVaK7ZwHHjRyZWjbDl",
"challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P",
"type": "url_verification"
}
ここでtokenがSlack AppのBasic Informationで確認できるtokenと一致しているか、challengeの内容がそのまま帰ってきているか、typeがurl_verificationと一致しているかの3つの条件を満たすコードを用意する必要があります。
まずそのコードに使用するライブラリをインポートしていきたいと思います。
sudo apt install python3-pip
pip install flask
その用意するコードのサンプルがこちら(わかりやすいように好きなところにフォルダを作ってそこに作成してください)
import flask
from flask import request, Response
import os
import json
app = flask.Flask(__name__)
#動作確認用
@app.route('/')
def main():
return "Hello world!"
#実際にSlackからの認証用に使うところ
@app.route('/slackCheck', methods=["POST"])
def index():
data = request.data.decode('utf-8')
data = json.loads(data)
# for challenge of slack api
if 'challenge' in data:
token = str(data['challenge'])
return Response(token, mimetype='text/plane')
# for events which you added
if 'event' in data:
print("get event")
event = data['event']
if 'user' in event:
print("user = ", event["user"])
if "text" in event:
print("text = ", event["text"])
return Response("nothing", mimetype='text/plane')
#ここのポート番号は好きにしてね。基本は80とか8080とか使うのかな?知らんけど
port = os.getenv('VCAP_APP_PORT', '30240')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=int(port), debug=True)
また好きなポート番号を使っている人は
sudo ufw allow 30240/tcp
sudo ufw reload
でポートを開放しておいてください
それができたら
ngrok http 30240
で実際にpythonのプログラムを動かした状態でngrokによって作られたForwarding後のURLでアクセスして「Hello World!」が表示されることを確認してください
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Account ??????(Plan: Free)
Version 2.3.40
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://4068-2400-4150-52e2-6200-264b-feff-fe90-8afa.ngrok.io -> http://localhost:30240
Forwarding https://4068-2400-4150-52e2-6200-264b-feff-fe90-8afa.ngrok.io -> http://localhost:30240
#ここの上にあるやつです→→→→→→→→→→→→→→→→→→↑
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
ここまでで一旦サーバー側の操作は終了です。(今作ったURLは後々使うので起動したままでほっといてね)
ここからはSlack botの作成に移ります
5.Slack botの作成
slackにブラウザでログインした状態でここにアクセスしてください
アクセスしたら画面中央の「Create an App」をクリックしてください
クリックしたら次の画像のように2つ候補が出てくると思うので「From scratch」を選択してください
選択後はそのAppの名前(①)と入れるworkspace(②)を選択します
選択後はAppの設定画面に入ることができます
ここから
①Permissions
②Bots
③Event Subscriptions
の順に設定していきたいと思います。
まず「Permissions」をクリックしてサイト中ほどまでいって「Add an OAuth Scope」をクリックして今回やりたいことに応じたScopeを追加してください
ここで追加するものはOAuth Permission scopesを参考にしてください
また今回は「channels:history」「chat:write」「reactions:write」「channnels:join」の4つを追加しました
次に最初の画面に戻ってBotsの設定に入ります。(左のBasic Information→Add features and functionalityでさっきの画面が見れます)
ここで「Add Display Name」の「Edit」から
・Display Name(Slack上で表示される名前)
・Default username(ちょっとよくわかんないです)
の2つを入力して、「Always Show My Bot as Online」をONにしておいてください
その後「Basic Information」に戻り「Install to Workspace」をクリックしてそのままの流れでインストールしちゃってください
次に、また「Basic Information」に戻り、「Display Information」というSlack上で確認できるAppの情報を編集します
ここも好きに入れちゃってください
次に「Event Subscriprions」というこのslack botのサーバーを設定していきたいと思います(さっき作ったURLはここで使います)
「Basic Information」に戻り、「Event Subscriprions」をクリックしてください
ここで「Enable Events」をONにした後、「Request URL」に先ほど作ったURLを入れてください
(今回の私の場合は「http://4068-2400-4150-52e2-6200-264b-feff-fe90-8afa.ngrok.io/slackCheck」になります)
入力直後に確認が始まり、確認が取れると「Verified」と表示されサーバーとの紐づけは完了です。
一度紐づけしてしまえば、サーバーを止めてもまた起動すれば大丈夫です
その後、同じページのちょっと下にある「Subsceribe to events on behalf of users」にさせたい動作を登録してください。
この際、「Required Scope」に先ほど「Permissions」の時に追加したScope以外のものが入っていないか確認し、入っていたらScopeを追加してください。
今回は「message.channels」を追加しました。
ここまでで基本的なSlack Appの準備は終了になります。(書くの忘れてたけどこまめにSave Changesしてね)
6.実際のサーバーのコード作成
ここまでで環境つくりは終わりです。
ここからは実際にSlackから「施錠/開錠」のメッセージが来るとESP32へ送るメッセージを作るプログラムをサーバーに作っていきたいと思います。
とはいえ、いちいち説明するのもめんどくさいので完成品を一気にばんと出しときたいと思います。
(EPS32周りのコードはまだいじってないです+returnがなんちゃらでエラー出るし結構汚いし…でも動くからいいよね!!!)
コード内に出てくる「channnel」ってのは入れたいチャンネルのとこコピペで調べれます
from cgi import print_environ_usage
import flask
from flask import request, Response
import os
import json
import requests
app = flask.Flask(__name__)
previous = "施錠"
global lockState = 0 #0がしまってて、1が空いてる
#動作確認用
@app.route('/')
def main():
return "Hello world!"
#実際にSlackからの認証用に使うところ
@app.route('/slackCheck', methods=["POST"])
def index():
TOKEN = '????'
CHANNEL = '???'
url = "https://slack.com/api/conversations.history"
headers = {"Authorization": "Bearer "+TOKEN}
params = {
"channel": CHANNEL,
"limit": 1
}
r = requests.get(url, headers=headers, params=params)
json_data = r.json()
messages = json_data["messages"]
global previous #ここらへんめんどくさかったのだ
global fuser
for i in messages:
print(i["text"])
word = i["text"]
if word == previous:
url1 = "https://slack.com/api/chat.postMessage"
data = {
"token": "????",
"channel": "???",
"text": "変化なしだぞ"
}
requests.post(url1, data=data)
elif word != previous:
if word == '開錠':
lockState = 1
url2 = "https://slack.com/api/chat.postMessage"
data = {
"token": "????",
"channel": "???",
"text": "開けたよ"
}
requests.post(url2, data=data)
previous = word
elif word == '施錠':
lockState = 0
url3 = "https://slack.com/api/chat.postMessage"
data = {
"token": "????",
"channel": "????",
"text": "閉めたよ"
}
requests.post(url3, data=data)
previous = word
else:
fuser = i["user"]
if fuser == '?????': #これはBOTの無限ループを防ぐためのやつ(botのuserを入れてね)
break
else:
url4 = "https://slack.com/api/chat.postMessage"
data = {
"token": "????",
"channel": "???????",
"text": "ちゃんとしてよ"
}
requests.post(url4, data=data)
return word ,lockState
#ここのポート番号は好きにしてね。基本は80とか8080とか使うのかな?知らんけど
port = os.getenv('VCAP_APP_PORT', '30240')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=int(port), debug=True)
#ESP32が情報求むするとこ
@app.route('/esp32')
def esp():
return "Hello world!"
7.ESP32上のコード作成
ここでは一定間隔ごとにサーバーに対してリクエストを送り、現在の鍵の状態をレスポンスしてもらってその状態によって鍵の開閉をするプログラムを作りました。
今回はパス(ちょっと待ってね)
8.動作確認
9.あとがき
最後はesp32がサーバーに定期的にhttp getして状態見てってのを作って終わりです
ちょっと話それるけどubuntuにgeforceのドライバ入れた瞬間ネットが何やってもつながらんくなったのいったいなんやったんやろ?あれさえなければ…