Raspberry Pi 3 とTypetalk HubotアダプターでシンプルIoT

# Raspberry Pi 3 とTypetalk HubotアダプターでシンプルIoT
## はじめに
"[Raspberry Pi 3 で赤外線リモコン&温度センサーを試す](http://qiita.com/revsystem/items/4ad6977917e36af63848)" で接続した赤外線リモコン irMagician を使って、外出先から Typetalk でコマンドを送信するとエアコンや照明を操作するシンプルなIoTに挑戦します。

## 準備するもの
- [Typetalk](https://www.typetalk.in/ja/) で使用するヌーラボアカウント2つ。1つは自分用、もうひとつはコマンドに返事をする bot アカウント。

## 前提条件
- "[RaspberryPi 3 model B に CentOS7をインストール](http://qiita.com/revsystem/items/9989a18116e554c133b6)" が完了していること。
- "[Raspberry Pi 3 で赤外線リモコン&温度センサーを試す](http://qiita.com/revsystem/items/4ad6977917e36af63848)" でRaspberryPi 3 と irMagician のセットアップを終えていること。
- rootユーザのほかに一般ユーザが存在し sudo コマンドが実行可能であること。
- "まず、動くこと"を優先しているので、パラメータ調整は含まれていません。
- Raspberry Pi 3 は、無線/有線LANに接続されていてインターネットに接続可能であること。(インターネットからRaspberry Pi 3に直接/間接的に接続する必要はありません。)

## 参考情報
- https://github.com/nulab/hubot-typetalk
- https://gist.github.com/pbolduc/e7a7e5559d01c4f500cc2ea4e9baf817
- https://gist.github.com/nghuuphuoc/7801123
- https://github.com/hubotio/hubot/blob/master/docs/scripting.md
- http://tech.quartetcom.co.jp/2014/06/07/typetalk-hubot/
- http://jun8man.hatenablog.com/entry/2016/09/19/004524
- http://qiita.com/bouzuya/items/11c0c6da2b3ad54b827f

## Typetalk に bot アカウントを準備
### Typetalk アカウントの作成
Typetalk のアカウントを持っていない場合は、[ヌーラボアカウントの作成](https://apps.nulab-inc.com/signup) からアカウントを作成できます。アカウント作成後、 [Typetalk にログイン](https://typetalk.in/)します。

### bot用アカウントの作成
いちどログアウトし、bot 用のアカウントを作成します。
このとき、bot用のアカウントのユニークIDは、 `raspbot`と登録したものとして進めます。
bot 用のアカウント作成後、自分用のアカウントで Typetalk にログインし、bot アカウントをトピックに招待します。
<img width="506" alt="typetalk001_png.png" src="https://qiita-image-store.s3.amazonaws.com/0/61809/0d465aa0-b312-efde-d3f1-e9e207b8314e.png">

### Typetalk bot の設定
bot 用アカウントをトピックに招待できたら、再び bot 用アカウントにログインしhubot 連携用の設定を行います。
設定画面で、連携用アプリケーションを登録します。

1. 画面左下のアイコン(設定画面へのリンクボタン)をクリックし、設定画面に入ります。
2. `デベロッパー`をクリックし、デベロッパー画面を開きます。
3. 画面右上の`新規アプリケーション`をクリックしアプリケーション設定画面に入ります。
<img width="507" alt="Typetalk002_png.png" src="https://qiita-image-store.s3.amazonaws.com/0/61809/e90a58f5-1caf-2653-7194-9a0f74a560cc.png">
4. アプリケーション名に任意の名称を入力します。ここでは、`tbot`と入力したものとして進めます。
5. Grant Typeは`Client Credentials`を選択します。
<img width="512" alt="Typetalk003_png.png" src="https://qiita-image-store.s3.amazonaws.com/0/61809/03764fb7-703a-a09e-26d8-3f6d8fe99f4e.png">

アプリケーションを登録すると、　`Client ID`と`Client Secret`が表示されます。この2つはこの画面でいつでも確認可能です。後述の Raspberry Pi 3 で hubot を起動する際に使用します。
<img width="513" alt="Typetalk004_png.png" src="https://qiita-image-store.s3.amazonaws.com/0/61809/51eab396-eeb7-b33c-cd8b-f79e62411d56.png">

## hubotのセットアップ
Raspberry Pi 3上で hubot をセットアップします。

### node.jsをインストール
Raspberry Pi 3 のCPUモデル名を確認します。

```
# cat /proc/cpuinfo | grep 'model name'
model name  : ARMv7 Processor rev 4 (v7l)
model name  : ARMv7 Processor rev 4 (v7l)
model name  : ARMv7 Processor rev 4 (v7l)
model name  : ARMv7 Processor rev 4 (v7l)
```
https://nodejs.org/ja/download/ からARMv7用のバイナリをダウンロードし、/usr/local以下に配置します。

```
$ sudo curl --location https://nodejs.org/dist/v6.11.2/node-v6.11.2-linux-armv7l.tar.xz > ./node-v6.11.2-linux-armv7l.tar.xz
$ tar Jxfv node-v6.11.2-linux-armv7l.tar.xz
$ sudo mv node-v6.11.2-linux-armv7l /usr/local/node-v6.11.2-linux-armv7l
$ sudo ln -s /usr/local/node-v6.11.2-linux-armv7l /usr/local/nodejs
```
node.jsにパスを通します。

```
$ vi ~/.bash_profile
```
変更前

```
# User specific environment and startup programs
PATH=$PATH:$HOME/.local/bin:$HOME/bin:
```
変更後

```
# User specific environment and startup programs
NODEJS_HOME="/usr/local/nodejs"
PATH=$PATH:$HOME/.local/bin:$HOME/bin:$NODEJS_HOME/bin:
```

バージョンを確認します。

```
$ node -v
v6.11.2
$ npm -v
3.10.10
```

npmをアップデートします。

```
$ npm update -g
$ npm -v
5.3.0
```

### cofee scriptのインストール  
Typetalk で入力したコマンドを受け取りRaspberry Pi 3 上で処理を行うための cofee script モジュールをインストールします。

```
$ npm install -g coffee-script
/usr/local/node-v6.11.2-linux-armv7l/bin/coffee -> /usr/local/node-v6.11.2-linux-armv7l/lib/node_modules/coffee-script/bin/coffee
/usr/local/node-v6.11.2-linux-armv7l/bin/cake -> /usr/local/node-v6.11.2-linux-armv7l/lib/node_modules/coffee-script/bin/cake
+ coffee-script@1.12.7
```

### hubotのインストール

yoとgenerator-hubotをインストールします。

```
$ npm install -g yo generator-hubot
```
次に、hubot をインストールします。

```
$ mkdir -p hubot
$ cd hubot
$ yo hubot
                     _____________________________
                    /                             \
   //\              |      Extracting input for    |
  ////\    _____    |   self-replication process   |
 //////\  /_____\   \                             /
 ======= |[^_/\_]|   /----------------------------
  |   | _|___@@__|__
  +===+/  ///     \_\
   | |_\ /// HUBOT/\\
   |___/\//      /  \\
         \      /   +---+
          \____/    |   |
           | //|    +===+
            \//      |xx|

? Owner User <user@example.com> (Enter)
? Bot name tbot  (任意の名称。Typetalk上で作成したアプリケーション名 tbot とします。)
? Description A simple helpful robot for your Company (何も入力せずにEnter)
? Bot adapter typetalk  (Typetalk アダプターを指定します。)
   create bin/hubot
   create bin/hubot.cmd
   create Procfile
   create README.md
   create external-scripts.json
   create hubot-scripts.json
   create .gitignore
   create package.json
   create scripts/example.coffee
   create .editorconfig
                     _____________________________
 _____              /                             \
 \    \             |   Self-replication process   |
 |    |    _____    |          complete...         |
 |__\\|   /_____\   \     Good luck with that.    /
   |//+  |[^_/\_]|   /----------------------------
  |   | _|___@@__|__
  +===+/  ///     \_\
   | |_\ /// HUBOT/\\
   |___/\//      /  \\
         \      /   +---+
          \____/    |   |
           | //|    +===+
            \//      |xx|

npm WARN deprecated connect@2.30.2: connect 2.x series is deprecated
npm WARN deprecated node-uuid@1.4.8: Use uuid module instead

> ws@0.4.32 install /home/tsuyoshi/hubot/node_modules/ws
> (node-gyp rebuild 2> builderror.log) || (exit 0)

make: Entering directory `/home/tsuyoshi/hubot/node_modules/ws/build'
  CXX(target) Release/obj.target/bufferutil/src/bufferutil.o
make: Leaving directory `/home/tsuyoshi/hubot/node_modules/ws/build'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN hubot-help@0.2.2 requires a peer of coffee-script@^1.12.6 but none was installed.

+ hubot-google-images@0.2.7
+ hubot-heroku-keepalive@1.0.3
+ hubot-diagnostics@0.0.2
+ hubot-scripts@2.17.2
+ hubot@2.19.0
+ hubot-maps@0.0.3
+ hubot-google-translate@0.2.1
+ hubot-pugme@0.1.1
+ hubot-redis-brain@0.0.4
+ hubot-help@0.2.2
+ hubot-rules@0.1.2
+ hubot-shipit@0.2.1
+ hubot-typetalk@0.2.3
```
様々なモジュールがインストールされました。

```
$ ls
Procfile   bin                    hubot-scripts.json  package-lock.json  scripts
README.md  external-scripts.json  node_modules        package.json
```

### coffee scriptを用意する。
Typetalk 上で、botに送ったコマンドに反応する処理を　coffee script　で実装します。
`hello` と送信すると、`Hi!`もしくはスマイルの絵文字:smile:で返事をするサンプルです。

```
$ vi ./script/example.coffee

```

```
module.exports = (robot) ->
 hello = ['Hi!',':smile:']

 robot.hear /hello/i, (res) ->
   res.send res.random hello
```


### hubotを起動してみる
hubotを起動して、さきほどの coffee script を試してみます。

```
$ ./bin/hubot
tbot> [Sun Aug 13 2017 03:24:14 GMT+0900 (JST)] WARNING Loading scripts from hubot-scripts.json is deprecated and will be removed in 3.0 (https://github.com/github/hubot-scripts/issues/1113) in favor of packages for each script.

Your hubot-scripts.json is empty, so you just need to remove it.
[Sun Aug 13 2017 03:24:15 GMT+0900 (JST)] ERROR hubot-heroku-keepalive included, but missing HUBOT_HEROKU_KEEPALIVE_URL. `heroku config:set HUBOT_HEROKU_KEEPALIVE_URL=$(heroku apps:info -s | grep web.url | cut -d= -f2)`
[Sun Aug 13 2017 03:24:17 GMT+0900 (JST)] INFO hubot-redis-brain: Using default redis on localhost:6379
(ここでEnterを押さないとプロンプトが表示されないので注意)
tbot>
```

tbotに `hello` と話しかけてみると、`Hi!` もしくは `:smile:`と返事をしてくれます。
2種類の返事はランダムに返されるので、何度か　`hello`を繰り返すと両方出力されるはずです。
この画面では、絵文字は表示できないので文字で`:smile:`と返されます。
終了するときは `exit` と入力する。

```
tbot> hello
tbot> Hi!

tbot> hello
tbot> :smile:

tbot> exit
```


### redis-serverのインストール
redis-serverをインストールします。

```
$ sudo yum -y install gcc make tcl
$ wget http://download.redis.io/releases/redis-3.2.9.tar.gz
$ tar xzvf redis-3.2.9.tar.gz
$ cd redis-3.2.9
$ make
$ make install
```

redis-serverを起動します。

```
$ redis-server & 
```


### Typetalk と連携する
いよいよ　 Typetalk　 との連携設定を行います。
Typetalkアプリケーションの環境変数を設定し hubot を起動します。

|変数名|値| 
|:-----------------|:------------------|
|HUBOT_TYPETALK_CLIENT_ID|Typetalk アプリケーションの Client ID |
|HUBOT_TYPETALK_CLIENT_SECRET|Typetalk アプリケーションの Client Secret |
|HUBOT_TYPETALK_ROOMS| hubotを使用するTypetalk上のトピックID |

Client ID と Client Secretは、 https://typetalk.in/my/develop/applications にアクセスし、作成したTypetalkアプリケーション名をクリックすることで表示されます。

HUBOT_TYPETALK_ROOMS　は、
https://typetalk.in/topics/xxxxx の xxxxx部分です。 bot 用のTypetalkアカウントを招待したトピックを開いた際のURLに該当します。

これらの環境変数を　export し、Typetalk アダプターを使用して hubot を起動します。
実際に運用する場合は、hubot を起動するユーザの　.bash_profile などに環境変数を定義しておきます。

```
$ export HUBOT_TYPETALK_CLIENT_ID='xxxxxxxxxxxxxxxxxxxxx'
$ export HUBOT_TYPETALK_CLIENT_SECRET='xxxxxxxxxxxxxxxxxxxxx'
$ export HUBOT_TYPETALK_ROOMS='xxxxxx'
$ ./bin/hubot -a typetalk

[Sun Aug 13 2017 05:24:11 GMT+0900 (JST)] INFO Typetalk WebSocket connected
```

### Typetalk bot から hubot を呼び出す

```
@raspbot hello
```
`Hi!` もしくは スマイルの絵文字で返事が返ってきました。
<img width="511" alt="Typetalk005_png.png" src="https://qiita-image-store.s3.amazonaws.com/0/61809/3fddcb7a-fd48-d049-a82f-b835a65545dc.png">



### irMagician と連携してリモコンを操作する。

ターミナルで以下のようになっているので、Ctlr + C で終了させます。

```
[Sun Aug 13 2017 05:24:11 GMT+0900 (JST)] INFO Typetalk WebSocket connected
```

学習させたリモコン操作の呼び出しや温度計測を実行するように、example.coffeeを以下のように変更し、保存します。詳細は、 "[Raspberry Pi 3 で赤外線リモコン&温度センサーを試す](http://qiita.com/revsystem/items/4ad6977917e36af63848)" を参照。
 
`air_on.json`、`air_off.json` はそれぞれエアコンをON/OFFにする操作を学習した結果を出力したJSONファイルです。
`/PATH/TO/irmcli/irmcli.py` は irmcli.py がある場所を絶対パスで指定します。

```
$ vi ./script/example.coffee
```
example.coffeeの内容

```
module.exports = (robot) ->

 robot.hear /temperature/i, (msg) ->
   @exec = require('child_process').exec
   command = "sudo python /PATH/TO/irmcli/irmcli.py -t"

   @exec command, (error,stdout, stderr) ->
     msg.send stdout

 robot.hear /aircon on/i,(msg) ->
   @exec = require('child_process').exec
   command = "sudo python /PATH/TO/irmcli/irmcli.py -p -f /PATH/TO/irmcli/air_on.json"

   @exec command, (error,stdout, stderr) ->
     msg.send stdout

 robot.hear /aircon off/i,(msg) ->
   @exec = require('child_process').exec
   command = "sudo python /PATH/TO/irmcli/irmcli.py -p -f /PATH/TO/irmcli/air_off.json"

   @exec command, (error,stdout, stderr) ->
     msg.send stdout
``` 

hubot を起動します。

```
$ ./bin/hubot -a typetalk
```


以下のコマンドを hubot　に送ります。

```
@raspbot temperature
```

```
@raspbot aircon on
```

```
@raspbot aircon off
```
<img width="511" alt="Typetalk006_png.png" src="https://qiita-image-store.s3.amazonaws.com/0/61809/f476d161-0d2d-b3a0-f7e4-a5cfb0d284fb.png">

実行結果を得ることができました。

## テレビを操作するサンプル
上記はエアコンの例ですが、テレビも操作することができました。
[![テレビを操作するサンプル](http://img.youtube.com/vi/Jz_Jfh6Y1Bw/0.jpg)](http://www.youtube.com/watch?v=Jz_Jfh6Y1Bw)

## 実行結果
ここで得られるirMagicianからの結果は、あくまでもコマンド自体の実行結果であり、その先のエアコン等が意図したとおりに動作したかはわかりません。
赤外線が届いたかどうかもわかりません。
エアコンは結果を返してくれないし、返ってきたところで受け取る仕組みがありません。
そういう意味では、シンプルIoTということになります。

Typetalkはインターネット上のサービスなので、hubot 連携することで外出先からでもRaspberry Pi 3 上で上記のようなコマンドを実行することが可能です。
相手の状態を得られるような実装を行えば、より現実的なIoTが楽しめそうです。