0. はじめに
僕も含め家族がよく鍵を締めたか外に出てから心配になって戻りがちなので、外出先で鍵締めたか確認できるようしてみました。1
できるだけコストをかけず、手元にある機器で作りたかったので余っていたRaspberry Piを使って、玄関において外出先から扉を撮影する設計にしました。
また、家族なども使うため、操作がわかりすいことが必要だったので、LINE Botを使ったインターフェースを設計します。
1. 設計
要件
- Line Botに「鍵見て」と呼びかけると起動する
- 玄関に置いたRaspberryPiが写真を撮る
- 鍵のところが撮影されてLineで送られてくる
構成
LINE BotとRaspberry Piを双方向に直接やり取りする方法はありません。
また、Raspberry PiからLINEにはLINE Notifyで簡単かつ安全に接続できますが、LINEからRaspberry Piは少々工夫をしてやる必要があります。
そもそも、LINEから飛んでくるリクエストを確認するためにはAPIを公開する必要があります。
一番手っ取り早いのは、Raspberry Piを直接Webサーバにしてしまう方法です。しかし、この方法は無防備のサーバーを剥き出しにするのでセキュリティリスクが高すぎます。
AWSやAzureといったクラウドサービスを挟む方法も考えられますが、ランニングコストがかかるのでこの方法は採用したくないです。
そこで、Google Apps Script(GAS)とSlack botを挟んでRaspberry Piにリクエストを投げるようにします。2
ここまでの構成をまとめると以下のようになります。
2. LINE botを作る
準備
LINE Developersにアクセスし、ログインします。LINEアカウント持ってない場合はアカウントを作ってください。
ログインができたら開発者情報をポチポチ登録して、「新規プロバイダー作成」からプロバイダーを作成します。その後、「Messaging API」を選択してからチャネルを作成します。
チャネルが作成されたら、「Messaging API設定」の中にある「チャネルアクセストークン」を発行します。(後でこのトークンが必要になります。)
悪用されるのを防ぐためにこのトークンは公開してはいけません。
GASを作成
Googleドライブにアクセスして、「新規>その他」からGoogle Apps Scriptを選択します。表示が無ければ、「アプリを追加」から検索して追加してください。
プロジェクト名を適当に入れて、以下のスクリプトを入れます。このコード中のhello()
関数を呼び出してるあたりに関数を追加して開発していきます。
とりあえず、アクセストークンのところを張り付けて、保存します。
function doPost(e) {
var replyToken= JSON.parse(e.postData.contents).events[0].replyToken;
if (typeof replyToken === 'undefined') {
return;
}
var url = 'https://api.line.me/v2/bot/message/reply';
var channelToken = 'ここにアクセストークン(ロングターム)を貼り付け';
var event = JSON.parse(e.postData.contents).events[0];
var source = event.source;
var input = event.message;
var messages = null;
//■■■■ この中に機能を追加していく ■■■■
if(input.type == 'text') {
messages = hello();
}
UrlFetchApp.fetch(url, {
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + channelToken,
},
'method': 'post',
'payload': JSON.stringify({
'replyToken': replyToken,
'messages': messages,
}),
});
return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}
function hello(){
var messages = [{
'type': 'text',
'text': 'こんにちは',
}];
return messages;
}
ひとまず公開
右上にある「デプロイ>新しいデプロイ」を押して公開します。
種類の選択から、ウェブアプリをえらんでアクセスできるユーザーを「全員」にしてデプロイします。
初回はアクセスの承認が必要になると思うので、承認しましょう。おそらく、英語や日本語で「このアプリは確認されていません」3と言われると思うので「詳細を表示」/「Advance」から自分のアプリケーションに移動して許可します。
「デプロイを更新しました。」と表示されていれば成功です。
ウェブアプリのURLをコピーしておきます。
LINEと連携
作成したGASをLINEと連携させます。「Messaging API設定」のページに戻って「Webhook設定」を更新していきましょう。
- Webhook URL
- GASのウェブアプリケーションのURLを貼り付け
- Webhookの利用
- 利用する
次にその下にある「LINE公式アカウント機能>応答メッセージ」を編集します。
- 応答メッセージ
- オフ
- Webhook
- オン
設定は以上です! 一度動くか試してみましょう!
QRコードを読み取ってテストしてみてください。なにか呼びかけると「こんにちは」と帰ってきたら成功です。
応答範囲を限定する
LINEbotが他人に友達登録されると、鍵の様子を他人が確認できるようになってしまいます。
セキュリティ的にいい方法ではありませんが、送信元のユーザーIDもしくはグループIDを調べて、それら以外のIDからのリクエストには応答しないようにします。
先ほどのコードの中に、source
という変数を用意しているので、こいつを使ってIDを判別しようと思います。
まず、//■■■■ この中に機能を追加していく ■■■■
書いてあったあたりのコードを改変して、IDをそのまま返すようにしてデプロイしましょう。
下記コードではグループIDを判別するようにしています。sourceの中身はドキュメントを参照してください。
このあとに、「LINE Notify」と同じグループに入れる必要があるので、グループを作ってBotを招待しておくのをおすすめします。
更新は右上のデプロイから「新しいデプロイ」を押して、「デプロイ」を押します。
このとき、保存してからデプロイするのを忘れないようにしましょう。
//■■■■ この中に機能を追加していく ■■■■
if (source.type == 'group' && source.groupId == 'ここにID'){
if(input.type == 'text') {
messages = hello();
}
} else {
messages = [{
'type': 'text',
'text': 'id:' + source.groupId,
}];
}
デプロイしてから呼びかけるとIDが返ってくると思うので、そのIDをif文のなかに記述してもう一度デプロイします。
これで、いま入力したID以外からのリクエストを受け付けなくなりました。(入力したID以外からにはIDを返す処理になってます)
ひとまず、LINEbotの開発はひと段落です。
3. Slack botを作る
導入
次に、Slack botを作っていきましょう。
適当なワークスペースを作成し(もちろん既存のワークスペースも可)、そのワークスペースにボットインテグレーションの作成からbotを作成します。
Raspberry PiはIP固定しておいてください。(固定方法はここを参照)4
Raspberry Piにslackbotをpipで導入します。
$ sudo pip3 install slackbot
ひとまずSlack Botを動かす
Slack botを動かすために必要なファイルを作っていきましょう。
$ mkdir bot
# 好きな名前のファイルを作ってください。ここでは'bot'にします。
$ cd bot
$ touch run.py
$ touch slackbot_setting.py
$ mkdir plugins
$ touch ./plugins/__init__.py
ファイル構造は下のようになっているはずです
bot/ # 任意の名前
├─ run.py # 起動時に使う
├─ slackbot_settings.py # botに関する設定ファイル
└─ plugins/ # botの機能はこの配下に追加していく
├─ __init__.py # モジュールを示すためのファイル。空ファイル。
└─ test.py # 任意の名前(まだない)
各ファイルを編集していきましょう。
slackbot_settings.py
には先ほど作ったSlackのトークンを入れましょう。
API_TOKEN = '<BOTのトークン>'
# デフォルトの返答
default_reply = 'わからん'
# プラグインを記述するディレクトリ名
PLUGINS = ['plugins']
test.py
をplugins/
の配下に作って行きましょう。
from slackbot.bot import respond_to, listen_to
import re
# おはようテスト
@listen_to('おはよう')
@respond_to('おはよう')
def ohayou(message, *something):
message.send('おはよう') # 投稿
#message.reply('おはよう') # メンション付き投稿
@listen_to
デコレータを付けた関数は、botが参加したチャンネルに、botにメンションされなかった投稿に、引数の文字列が含まれるときに反応します。
逆に@respond_to
デコレータを付けた関数は、botに向けた投稿に、引数の文字列が含まれるときに反応します。
どちらもつけるとチャンネル内の投稿すべてに対応できます。
最後に、起動用のrun.py
を作りましょう。
from slackbot.bot import Bot
def main():
bot = Bot()
bot.run()
if __name__ == "__main__":
print('start slackbot')
main()
これで動かす準備は整いました。実行してみましょう。
$ python3 run.py
エラーなく'start slackbot'と表示されていれば行けていそうです。
ダイレクトメッセージかBotを任意のチャンネルに招待して、Slack上で問題なく「おはよう」が帰ってくれば成功です。
GAS-Slackの連携
ここまでで下図の緑色になっているところまでが開発が終わりました。次に④のところの連携をします。
まずはSlackのIncoming WebHooksを登録し、前章で作成したSlack BOTがいるチャンネルに投稿するように設定します。
これで下準備は完了です!
GASの改変
すでに作っているGASのスクリプトにSlackに投稿する関数を追加します。
ここでは、「やあ」と呼びかけたら、「おはよう」とSlackに投げるようにします。
SlackのWebhoolURLを入れるのを忘れないようにしましょう。
// ~~~~~~~~~~~~~~~~~~~~~~
//■■■■ この中に機能を追加していく ■■■■
if (source.type == 'user' && source.userId == 'groupのID') {
if(input.type == 'text') {
if (input.text.match('おはよう')) {
messages = sendSlack();
} else {
messages = hello();
}
}
// ~~~~~~~~~~~~~~~~~~~~~~
// 中略
// ~~~~~~~~~~~~~~~~~~~~~~
function sendSlack(m) {
try{
var postUrl = 'SlackのWebhoolURL';
var username = 'LINE'; // 通知時に表示されるユーザー名
var icon = ':globe_with_meridians:'; // 通知時に表示されるアイコン
var jsonData =
{
"username" : username,
"icon_emoji": icon,
"text" : m
};
var payload = JSON.stringify(jsonData);
var options =
{
"method" : "post",
"contentType" : "application/json",
"payload" : payload
};
UrlFetchApp.fetch(postUrl, options);
var messages = [{
'type': 'text',
'text': 'Slackに送信したよ',
}];
return messages;
} catch (e) {
var em = [{
'type': 'text',
'text': e.message,
}];
return em;
}
}
改変できたら、デプロイします。
LINEで「やあ」と呼びかけるとSlackにも「おはよう」と送信されて、ラズパイからSlack上で「おはよう」と帰ってきました。
これで、ほぼ完成に近づきました!あとは本題の撮影機能を実装しましょう!
4. 撮影機能の実装
要件をおさらいします。
- Line Botに「鍵見て」と呼びかけると起動する
- 玄関に置いたRaspberryPiが写真を撮る
- 鍵のところが撮影されてLineで送られてくる
「鍵見て」に反応するようにする
GASを改変して「カメラ」や「鍵」などを含むときにSlackに送信するようにします。
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//■■■■ この中に機能を追加していく ■■■■
if (source.type == 'user' && source.userId == 'U09f976d7b3c475d54161d589f74fe9e8'){
if(input.type == 'text') {
if (input.text.match('やあ')) {
messages = sendSlack('おはよう');
} else if (input.text.match('カメラ') || input.text.match('かぎ') || input.text.match('鍵') || input.text.match('玄関') || input.text.match('げんかん') || input.text.match('ドア')){
messages = sendSlack('カメラ');
} else {
messages = hello();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Raspberry Piで撮影する
Raspberry Piのカメラで撮影するためには、raspistill
コマンドを実行すればいいので、Slack botに組み込んでしまいましょう。plugins/
配下に新しいファイルを作成します。
from slackbot.bot import respond_to, listen_to
import re
import os
import datetime
import requests
@listen_to('カメラ')
@respond_to('カメラ')
def cam(message, *something):
message.send('ハイチーズ!!')
os.system('raspistill -w 1280 -h 1024 -o image.jpg')
message.send('パシャ!!!!!!')
ここまでの実装で、LINEで「鍵みて」って呼びかけると、Slackにも投げられて、Raspberry Piのカメラがエラーなく起動すれば成功です。5
LINE Notifyで画像を返す
LINE Notifyからログインして、「トークンを発行する」を選びます。先に作ったLINE Botがいるグループを選んで、トークンを発行しましょう。
発行したトークンはページを閉じると再発行されないので、必ずコピーしてから移動しましょう。
次にRaspberry Piのプログラムを改変します。LINE Notifyのトークンを張り付けるのを忘れないでください。
from slackbot.bot import respond_to, listen_to
import re
import os
import datetime
import requests
@listen_to('カメラ')
@respond_to('カメラ')
def cam(message, *something):
message.send('ハイチーズ!!')
os.system('raspistill -w 1280 -h 1024 -o image.jpg')
dt_now = datetime.datetime.now()
message.send('パシャ!!!!!!')
fname='image.jpg'
url = "https://notify-api.line.me/api/notify"
token = "LINE Notifyのトークンを張り付ける"
headers = {"Authorization" : "Bearer "+ token}
message = dt_now.strftime('%Y年%m月%d日 %H:%M:%S')
payload = {"message" : message}
files = {"imageFile": open(fname, "rb")}
r = requests.post(url, headers = headers, params=payload, files=files)
お疲れ様でした。これで完成です!!
最後にLINEで「鍵見て」と呼びかけて写真が返ってくるか見てみましょう。
うまく画像が返ってきたら成功です!
5.オチ
ワイ「玄関の様子みて」
Bot「見てきたやで」っ[画像]
う~~~~~~~~ん、逆光!!
##参考にした記事&関連記事
- Raspberry Pi とSlackとLINE Messaging APIでLINEから家電を操作する | Zumi blog
- LINE Botの作り方と作ってみた時にマジかと思ったことと作るときに使ってほしいサンプルと・・・っていうたくさんの話 - Qiita
- Google Apps ScriptでLINE BOTつくったら30分で動かせた件 - Qiita
- LINE BOTの作り方~アカウントの作成とQ&Aの登録方法~