Slackで現実世界も記録する

## はじめに
2014年12月頃、[SlackのHubot Integrationの仕様が変わりまして、](http://qiita.com/KeitaMoromizato/items/0ee11d795d18a49538d8)Slack上でhubotが動いているURLを設定する必要がなくなりました。このおかげで、RaspberryPi上のhubotも簡単にSlackと連携させることができます。

というわけで、世の中のIoTブームに乗っかってSlackを現実世界とつなげてみましょう。

## 作ったもの
今回実装したのは、Slackのあるコマンドに反応してRasPiが写真を撮影、自動アップロードするという機能です。

なぜこれを実装したかと言うと、[これ](http://irorio.jp/sophokles/20141218/188730/)が欲しかったんです。画像データを自動で飛ばしてくれるホワイトボード。でもお高いですよね。普通はこんなお高いやつを何台も買えないので、ミーティングのときにはiPhoneで写真を撮って、Slackにアップロードして共有しています。

これ、自動化できればお高いホワイトボード買わなくていいんじゃね？ということで作ってみました。

![IMG_20150105_120156.jpg](https://qiita-image-store.s3.amazonaws.com/0/52054/f2b48636-ed65-dcf0-38e5-f86e767575ea.jpeg)

## 実演
こんな感じでセッティングして...

![IMG_20150105_120139.jpg](https://qiita-image-store.s3.amazonaws.com/0/52054/fe1d53ed-d972-0d69-2eea-ac6f9c1f7922.jpeg)

slack上でcameraと入力すると...

![5.png](https://qiita-image-store.s3.amazonaws.com/0/52054/f6a3272a-1745-e530-ad1d-be9377bfc05a.png)

10数秒後の画像がポストされます！Slack APIのtokenが自分のものなので自分が投稿しているように見えますが、完全に自動で画像がアップロードされています。

## RasPi設定
若干覚えていないところがあるのですが覚えている範囲で...Raspbianのインストールまでは完了している前提で。

### nvmインストール

```
curl https://raw.githubusercontent.com/creationix/nvm/v0.11.1/install.sh | bash
source ~/.profile
nvm install 0.10
```

### npmインストール
__追記:nvmインストールしたらnpm付いてきますね...不要です__

```
git clone git://github.com/isaacs/npm.git
cd npm/scripts
chmod +x install.sh
sudo ./install.sh
```

### Webカメラ設定

```
sudo apt-get install fswebcam
```

## hubotスクリプト
コードは[Github](https://github.com/KeitaMoromizato/slack-camera/)に置いていますので、cloneしたら使えるはず。スクリプトはこんな感じ。今回は市販のWebカメラを使用しているので`fswebcam`コマンドで撮影しています。RasPi用カメラモジュールを使う場合はここを`raspistill`に置き換えたら動くはず。

node.jsからmultipartのリクエストを投げるのがどうしても出来なかったので、しょうがなく`curl`コマンドを叩いて画像をアップロードしています。どなたかいい感じの書き方をご存知の方、コメントなりPullRequestなりお願いします。

``` /scripts/camera.coffee
module.exports = (robot) ->
  exec = require('child_process').exec
  Slack = require 'slack-node'
  slack = new Slack process.env.SLACK_API_TOKEN
  DIR = '/tmp/'

  robot.hear /camera/i, (msg) ->
    channel = msg.message.room
    fileName = "#{getNow()}.jpg"

    console.log "rcv"
    exec "fswebcam -S 50 -r 1920x1080 --no-banner #{DIR}#{fileName}", (err, stdout, stderr) ->
      if err
        return msg.send "Failed " + err

      postSlack channel, fileName, (err, res) ->
        if err
          return msg.send "Failed " + err
        msg.send "OK"

  postSlack = (channel, fileName, callback) ->
    getChannelFromName channel, (err, id) ->
      if err
        return callback err
      exec "curl -F file=@#{DIR}#{fileName} -F channels=#{id} -F token=#{process.env.SLACK_API_TOKEN} https://slack.com/api/files.upload", (err, stdout, stderr) ->
        exec "rm -f #{DIR}#{fileName}", (err, stdout, stderr) ->
          if err
            console.log "failed to delete file"
        if err
          return callback err
        callback null, 'OK'
 
  getChannelFromName = (channelName, callback) ->
    slack.api "channels.list", exclude_archived: 1, (err, response) ->
      if err
        return callback err

      if !response.ok
        return callback response.error
      for val, i in response.channels
        if val.name == channelName
          return callback null, val.id
   
      return callback err 

  getNow = () ->
    date = new Date
    y = date.getFullYear()
    m = date.getMonth() + 1
    d = date.getDate()
    h = date.getHours()
    M = date.getMinutes()
    s = date.getSeconds()

    return "#{y}#{m}#{d}#{h}#{M}#{s}" 
```

## おわりに
IoT連携まで来るといよいよSlackはただのチャットツールじゃないなと。チャットであり、コマンドラインであり、すべてのインタフェースに成り得る。自分の想像力でプロジェクトをもっと面白いものにしていきましょう！