LoginSignup
1
0

More than 1 year has passed since last update.

Slack Botを使ってドア開閉システムの構築(の途中)その1

Last updated at Posted at 2022-02-24

はじめに

今回は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.システム概要

今回作成したシステム概要図を下に示します
新規 Microsoft PowerPoint プレゼンテーション.png

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」をクリックしてください
Desktop Screenshot 2022.02.25 - 01.58.55.69_LI.jpg
クリックしたら次の画像のように2つ候補が出てくると思うので「From scratch」を選択してください
Desktop Screenshot 2022.02.25 - 02.01.13.99_LI.jpg
選択後はそのAppの名前(①)と入れるworkspace(②)を選択します
Desktop Screenshot 2022.02.25 - 02.01.45.41_LI.jpg
選択後はAppの設定画面に入ることができます
ここから
①Permissions
②Bots
③Event Subscriptions
の順に設定していきたいと思います。
Desktop Screenshot 2022.02.25 - 02.02.03.60.png
まず「Permissions」をクリックしてサイト中ほどまでいって「Add an OAuth Scope」をクリックして今回やりたいことに応じたScopeを追加してください
ここで追加するものはOAuth Permission scopesを参考にしてください
また今回は「channels:history」「chat:write」「reactions:write」「channnels:join」の4つを追加しました
Desktop Screenshot 2022.02.25 - 02.12.57.09_LI.jpg

次に最初の画面に戻ってBotsの設定に入ります。(左のBasic Information→Add features and functionalityでさっきの画面が見れます)
ここで「Add Display Name」の「Edit」から
・Display Name(Slack上で表示される名前)
・Default username(ちょっとよくわかんないです)
の2つを入力して、「Always Show My Bot as Online」をONにしておいてください
Desktop Screenshot 2022.02.25 - 02.26.07.06_LI.jpg
その後「Basic Information」に戻り「Install to Workspace」をクリックしてそのままの流れでインストールしちゃってください
Desktop Screenshot 2022.02.25 - 02.31.09.14_LI.jpg

次に、また「Basic Information」に戻り、「Display Information」というSlack上で確認できるAppの情報を編集します
ここも好きに入れちゃってください
Desktop Screenshot 2022.02.25 - 02.34.46.83_LI.jpg
次に「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」になります)
Desktop Screenshot 2022.02.25 - 02.39.22.66_LI.jpg
入力直後に確認が始まり、確認が取れると「Verified」と表示されサーバーとの紐づけは完了です。
一度紐づけしてしまえば、サーバーを止めてもまた起動すれば大丈夫です
Desktop Screenshot 2022.02.25 - 02.41.26.93_LI.jpg
その後、同じページのちょっと下にある「Subsceribe to events on behalf of users」にさせたい動作を登録してください。
この際、「Required Scope」に先ほど「Permissions」の時に追加したScope以外のものが入っていないか確認し、入っていたらScopeを追加してください。

今回は「message.channels」を追加しました。

ここまでで基本的なSlack Appの準備は終了になります。(書くの忘れてたけどこまめにSave Changesしてね)

6.実際のサーバーのコード作成

ここまでで環境つくりは終わりです。
ここからは実際にSlackから「施錠/開錠」のメッセージが来るとESP32へ送るメッセージを作るプログラムをサーバーに作っていきたいと思います。
とはいえ、いちいち説明するのもめんどくさいので完成品を一気にばんと出しときたいと思います。
(EPS32周りのコードはまだいじってないです+returnがなんちゃらでエラー出るし結構汚いし…でも動くからいいよね!!!)
コード内に出てくる「channnel」ってのは入れたいチャンネルのとこコピペで調べれます
Desktop Screenshot 2022.02.25 - 07.06.01.53_LI.jpg

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.動作確認

一応動作させたときのslackの写真だけはっときます
InkedIMG_7230_LI.jpg

9.あとがき

最後はesp32がサーバーに定期的にhttp getして状態見てってのを作って終わりです
ちょっと話それるけどubuntuにgeforceのドライバ入れた瞬間ネットが何やってもつながらんくなったのいったいなんやったんやろ?あれさえなければ…

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0