お願いするとWebカメラで写真を撮って送信してくれるSlackBotを作った
はじめに
Pythonで Raspberry Pi3 B+ に Webカメラ ( logicool C270) ) を接続して、Slackのchannelで特定の発言があった時に、写真とって送ってくれるSlackBotを作りました。
最初はLINEで実装しましたが、「Slackでもやって!」といわれたので実装しました。
LINEBotと違うのは、常時SlackBotを動かしておき、特定の発言をトリガとして「写真を撮って保存 → 保存した写真をSlack channel に送信」というプログラムを実行しているところです。
開発期間は半日ぐらい(?)LINEBotよりちょっと難しかったです。
目次
- Step1. webカメラの写真を撮る
- Step2. Slackのchannelに撮った画像を送信する
- Step3.ログアウトしてもSlackBotの処理を続けるようにする
- Step4. 細かなバグ修正など
- 動作
Step1 . webカメラの写真を撮る
fswebcam を使って撮影しました。
次の手順で写真が撮れます。
デバイスが接続されているか確認します。
lsusb
fswebcamのインスト―ル
sudo apt-get install fswebcam
とりあえず一回とってみる
fswebcam -p MJPEG image.jpg
optionもあるので参考に(man-fswebcam)
Pythonでは、subprosessモジュールを使うとコマンドの実行ができます。参考
import subprocess def get_picture(): cheese=['fswebcam','-p','MJPEG','-r','1280x1024','--no-banner','-D','1',image.jpg] try: subprocess.check_call(cheese) print ("Command finished.") except: return "Command envailed."
cheese変数にコマンドを入れて(スペース区切りでリストに代入)subprocess.check_call(cheese)
で実行しています。
fswebcam -p MJPEG -r 1280x1024 --no-banner -D 1 imgage.jpg
を実行しているのと同義です。
いくつかオプションがあります。
- -p MJPEG : フォーマットをmjpegで
- -r 1280×1024 : 画像サイズの指定
- -D 1 : 撮影時、1秒遅延させる。(写真撮影の安定性が上がります)
参考
Step2 . Slackのchannelに撮った画像を送信する
slackbotの作成については、こちらの記事を参考にしてください。
上記の記事を見ると、次からの話分かると思います。
from slackbot.bot import respond_to # @botname: で反応するデコーダ from slackbot.bot import listen_to # チャネル内発言で反応するデコーダ from slackbot.bot import default_reply # 該当する応答がない場合に反応するデコーダ # channel内の誰かが「こんにちは」というとこの関数を実行する @listen_to('こんにちは') def listen_func(message): message.send('こんにちは') # ただの投稿 message.reply('わーい') # 「こんにちは」といった人に対して、メンションで「わーい」と返す # channel内で、「@hogehogebot おやすみ」というとこの関数が実行される @respond_to('おやすみ') def mention_func(message): do_something()
こんな感じでメンションに対してリプライや発言をします。
画像の送信方法
画像送信には、Slack API の files.upload method を使用します。
CHANNEL_TOKEN
で指定する特定のchannelに対して、画像 (image.jpg) を送信します。
CHANNEL_TOKEN
は、Slackをwebで開いた時に出るURLの一部にあります。
https://{workspacename}.slack.com/messages/{これ}
一括でCHANNEL_TOKEN
を取得したい場合は、Slack API の channels.list methodでTestすると良いです。
(slackbotライブラリに画像送信メソッドはありませんでした(たぶん))
import requests def post(): files = {'file':open(image.jpg,'rb')} params = { 'token':TOKEN, 'channels':CHANNEL_TOKEN, 'filename':"filename", 'initial_comment': "画像についてのコメント", 'title': "ファイルの名前" } requests.post(url="https://slack.com/api/files.upload",params=params, files=files)
Step1で撮った画像を、request.postで送信して終了です。
python3 run.py
で実行してみましょう。
参考
- PythonのslackbotライブラリでSlackボットを作る
- Pythonを使ったSlackBotの作成方法
- Slack API 推奨Tokenについて
- Slack API files.upload method
- プログラムからSlackに画像投稿する方法まとめ
- Slack API channels.list method
Step3 . ログアウトしてもSlackBotの処理を続けるようにする
Raspberry pi にssh接続をしてStep2で作ったrun.py
を実行しますが、slackbotの起動中は、常に実行状態になければいけません。
また、ssh接続を解除すると実行中のプログラムも終了します。
コマンドを実行している際に、仮想端末(Terminal)の画面を閉じたりログアウトしたりすると、実行中のコマンドも終了してしまいます(コマンドをバックグラウンド実行していても終了する)。
nohup
そこで、nohupコマンドを使って、nohup python3 run.py &
と指定すると、コマンドの実行を続けることができます。
ps
nohupコマンドで実行した処理の様子はpsコマンドで見ることができます。
ps -o pid,ppid,stat,tt,user,cmd
-o
は出力内容を指定するオプションです。左から
プロセスID(pid)と親プロセスのID(ppid)、状態(stat)、端末(tt)、ユーザー(user)、コマンド列(cmd)
を示しています。
ssh接続解除後、再び接続してpsを実行すると、ユーザーが変わって(?)見れなくなることがあります。
ps axu
を実行すると、他のプロセスも全て表示できます。
kill
プロセス終了には、killコマンドを使用します。
kill <プロセスID>
で終了できます。プロセスIDは上記のpsコマンドを実行して確認しましょう。
参考
Step4 . 細かなバグ修正など
Step3まででとりあえずプログラムは動きます。
しかし、「撮影 => 送信」のタイミングや、同じ画像名であったことから、結構不安定でした。
解決策
- 「撮影 => 送信」の間に5秒の遅延時間を入れました。
from time import sleep sleep(5) # try-expect文で例外処理を入れましょう。
画像名を写真の撮影時刻に変えました。
次のように時刻を取得します。
import datetime def get_now_time(): d = datetime.datetime.today() return d.strftime("%Y-%m-%d %H:%M:%S")
- 画像名時刻にしたので、ちゃんと送信ができたら撮影した画像を削除します。
import os ... os.remove('./'+img_name)
追加
nohupコマンドを使用中、nohup.out
に出力されます。fswebcamでは、デバッグメッセージがかなり表示されるので、定期的に消してあげるようにしました。
import os os.remove('./nohup.out')
動作
こんな感じです。botの入っているチャンネルで「なう」というとwebカメラが写真を撮影してchannelに流してくれます。Webカメラの位置は動かせるので、中だけではなく、研究室からみえる外の景色等も撮れますね。
しっかり動きました。