ラズパイで写真を撮影してSlackに投稿する

# 概要
Slackにラズパイのhubotを常駐させておき、Slack上で写真撮影の指示を受けたらラズパイに接続されたカメラで写真を撮影。撮影した写真をhubotがSlackに投稿する。

# 前回までの流れ
[Slackをトリガーにしてラズパイで写真を撮影する] (https://qiita.com/s_harada/items/1d6621636036c51d9e17)

# 前提
* ラズパイにWebカメラを接続して写真を撮影できること
* ラズパイにhubotをインストールしてセットアップが済んでいること
* Slackにラズパイのhubotを連携させていること
* [前回までの流れ](https://qiita.com/s_harada/items/1d6621636036c51d9e17)で、Slackをトリガーにしてラズパイで写真を撮影するところまで実現できていること

# 使用するハードウェア
* Raspberry Pi 2 Model B
* Logicool Webcam C270

# 使用するソフトウェア
* hubot
* fswebcam

# ざっくりした処理の流れ
![WS000071.JPG](https://qiita-image-store.s3.amazonaws.com/0/329353/8308f18c-b4d9-579a-9c34-aaede23d6ad9.jpeg)

# やるべきこと
* [前回までの流れ](https://qiita.com/s_harada/items/1d6621636036c51d9e17)で、Slackをトリガーにしてラズパイで写真を撮影するところまでは実現できている
* 撮影した写真をSlackに投稿するhubotスクリプトを作成する

## coffeeスクリプトの改修
### 改修後のスクリプト

```take_photo.coffee
request = require "request";
fs = require "fs";

module.exports = (robot) ->
  robot.respond /写真撮って/i, (msg) ->
    # 写真ファイルのパスとファイル名を定義
    dt = new Date()
    year = dt.getFullYear()
    month = ("0"+( dt.getMonth() + 1 )).slice(-2)
    date = ("0"+dt.getDate()).slice(-2)
    hour = ("0"+dt.getHours()).slice(-2)
    min = ("0"+dt.getMinutes()).slice(-2)
    sec = ("0"+dt.getSeconds()).slice(-2)
    file_path = "/home/pi/Pictures/"
    file_name = "#{year}#{month}#{date}#{hour}#{min}#{sec}.jpg"

    # 写真の解像度を指定
    resolution = "1280x720"

    # fswebcamコマンドを実行
    @exec = require('child_process').exec
    command = "sudo -u pi sh ./scripts/sh/take_photo.sh -r #{resolution} #{file_path}#{file_name} "
    msg.send "写真を撮ってるよ。ちょっと待ってね。"
    @exec command, (error, stdout, stderr) ->
        if error != null
            msg.send "写真撮影に失敗しちゃったよ。。。"
        else
            # 撮った写真をSlackへアップロードする
            api_url = "https://slack.com/api/"
            channel = msg.message.room
            options = {
                token: process.env.HUBOT_SLACK_TOKEN,
                filename: file_name,
                file: fs.createReadStream("#{file_path}#{file_name}"),
                channels: channel
            }
            request.post {url:api_url + 'files.upload', formData: options}, (error, response, body) ->
                if !error && response.statusCode == 200
                    msg.send "写真投稿したよ！"
                else
                    msg.send "写真投稿に失敗しちゃったよ。。。"
```

### スクリプトの解説
#### 写真の撮影が済んでからSlackへ投稿
前半部分の写真撮影までは[前回](https://qiita.com/s_harada/items/1d6621636036c51d9e17)とほぼ同様。
写真が取れてからSlackへの投稿を行いたいので、アップロード処理はexecコマンド実行のコールバックが返ってきてから行う。 [^1]
[^1]: Promiseやasync/awaitを使った方がよりスマートな気はする

#### 写真ファイルの読み込み
[files.upload](https://api.slack.com/methods/files.upload)のfileにアップロードするファイルを指定するが、Nodeの公式モジュールfsを用いてストリームで画像ファイルの読込を行っている。

#### Slackへの写真アップロード
写真のアップロードはSlack APIの[files.upload](https://api.slack.com/methods/files.upload)を利用する。
APIからのレスポンスが200、かつコールバックのerrorに値が入っていなければ写真の投稿は成功したとみなす。

## 改修後の実行結果
Slackからhubotに対して写真撮影を指示し、ラズパイで撮影された写真がhubotによって投稿されることを確認。
fswebcamコマンドで写真を撮ってからSlackにアップロードするまでにそれなりに時間がかかるので、hubotに気の利いたコメントをさせておくといいかもしれない。

![WS000072.JPG](https://qiita-image-store.s3.amazonaws.com/0/329353/67ec6e31-f6a7-407d-5261-8c0d4b9669ec.jpeg)

# 次のステップ
Slackをトリガーにしてラズパイに写真を撮らせることはできた。
次はラズパイ側のカメラで映像の変化を監視し、変化を検知したら写真を撮影してSlackに通知するような仕組みを構築してみようと思う。