Raspberry Pi+FirebaseでSlackに電気ポットのお湯が沸いたことを通知する

事務所にお湯沸かしポットがあるが、自席からは壁一枚挟んで隔たっており、お湯が沸いたことが伝わってこない！を解消したくて作りました。
電気ポットは湯沸かし中にはオレンジのランプが点き、沸かし終えると消えるので、カメラでこの変化を捉える事で通知のトリガーになるだろうと考えました。
ラズパイ単体だとSlackとインターネットを介してのやり取りが面倒だなーと思ったんでFirebaseを使いました。スマホやWebで使うイメージでしたが、普通にサーバのモジュールとして使えるんですね。
![zu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177194/a68bd87e-f611-e305-42a0-2003ffa5867a.png)

FirebaseはラズパイがSlackから投げられたコマンドで監視開始ができるように、Firestoreで状態管理をします。ラズパイはこれをonSnapshotで見て監視の開始・停止を行います。動作が検知されるとラズパイはFirestoreを書き換え、Slackに通知を送るWebhookを叩きます。

## Firebase(Functions, Firestore)
プロジェクトを作り、Functions、Firestoreを作成します。Firestoreはとりあえずテストモードで作成します。

```javascript:index.js
const admin = require('firebase-admin')
admin.initializeApp()

const functions = require('firebase-functions');

exports.watch = functions.https.onRequest((request, response) => {
  admin.firestore().collection('state')
  .doc('raspberry-pi')
  .set({
    watch: true
  }).then(() => {
    response.status(200).send('見ときまーす');
  });
});

exports.unwatch = functions.https.onRequest((request, response) => {
  admin.firestore().collection('state')
  .doc('raspberry-pi')
  .set({
    watch: false
  }).then(() => {
    response.status(200).send('見るのやめまーす');
  });
});
```
これをデプロイすると`https://xxxxxxxx.cloudfunctions.net/watch`リクエストで監視on状態、`https://xxxxxxxx.cloudfunctions.net/unwatch`リクエストで監視off状態になります。

## Slack App
アプリを作成し、使いたいワークスペースにインストールします。
### Incomming Webhooks
有効にし、投げたいチャンネルを選んで**Webhook URL**を取得します。

### Slash Commands
`/watch`で監視開始するようなコマンドを作成します。**Request URL**にFirebaseで作成した`https://xxxxxxxx.cloudfunctions.net/watch`を入力します。`/unwatch`で監視を止めたい場合は`/unwatch`も作るといいでしょう。

これでSlackから`/watch`コマンドを叩くとFirestoreの`state > raspberry-pi > watch`がtrueとなり、監視on状態になります。

## Raspberry Pi

### motion
動作検知するアプリケーションをインストールします。Ubuntu（Debian)系の場合は、

```shell
$ sudo apt get install motion
```
ラズパイ起動時にデーモンモードで動くようにします。

```:/etc/default/motion
start_motion_daemon=yes
```
motionの各種設定変更

```:/etc/motion/motion.conf
// デーモンモードで起動
daemon on
// 動作検知の閾値
threshold 3000
// 一連の動作をイベントとする秒数
event_gap 10
// 画像出力オフ
output_pictures off
// ストリーム配信オフ
stream_localhost off
// 動作イベント検知時に走るコマンド
on_event_start /path/to/project/dir/detect.sh
```
動作イベント検知時に走るシェルスクリプトはFucntionsにunwatchリクエストを送って監視off状態に戻し、Slackに通知メッセージを送ります。

```shell:/path/to/project/dir/detect.sh
#!/bin/sh

# Funcsionsのunwatchリクエスト
wget -O - https://xxxxxxxx.cloudfunctions.net/unwatch

# 通知メッセージ
MSG="！"
# 作成したSlackのWebhook URL
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/xxxx/yyyy/zzzz"
curl -X POST -H 'Content-type: application/json' --data "{\"text\": \"$MSG\"}" $SLACK_WEBHOOK_URL
```
実行権限を与えます。

```
$ chmod +x detect.sh
```

これでラズパイにつないだカメラの前で動けば（10秒毎に）Slackに通知が飛ぶようになります。

あとはFirestoreの監視状態をmotionに反映させます。

プロジェクトにfirebaseを追加します。

```
$ npm install firebase
```
コードを書きます。


```javascript:/path/to/project/dir/motion_switch.js
const exec = require('child_process').exec;
const firebase = require("firebase");
const config = {
  databaseURL: "https://{FirebaseのプロジェクトID}.firebaseio.com",
  projectId: "{FirebaseのプロジェクトID}"
};
firebase.initializeApp(config);

// motionの監視開始コマンド
const startCmd = 'wget -O - http://localhost:8080/0/detection/start';
// motionの監視停止コマンド
const pauseCmd = 'wget -O - http://localhost:8080/0/detection/pause';

firebase.firestore()
  .collection('state')
  .doc('raspberry-pi')
  .onSnapshot(doc => {
    if (doc.data()['watch'] == true) {
      execCmd(startCmd);
      console.log('start');
    } else {
      execCmd(pauseCmd);
      console.log('pause');
    }
  });

function execCmd(cmd) {
  exec(cmd, (err, stdout, stderr) => {
    console.log(stdout)
    if (err) {
      console.log(err);
    }
  });
}
```
これをnodeコマンドで走らせます。

```
$ node motion_switch.js
```


これでSlackから`/watch`コマンドを叩くとラズパイの動作監視が開始され、Slackに通知メッセージが送られるようになりました！もう電気ポットに張り付く必要はありません！

## 権限まわり

SlackのWebhookやFirestoreの書き換えを適切に権限設定したいところです。

## motion_switch.jsをデーモン化
supervisorを使ってmotion_switch.jsをデーモン化します。

```
$ sudo apt get install supervisor
```
設定ファイルを作成します。

```:/etc/supervisor/conf.d/motion_switch.conf
[program:motion_switch]
directory=/path/to/project/dir
command=node motion_switch.js
numprocs=1
autostart=true
autorestart=true
user=motion
redirect_stderr=true
stdout_logfile=/var/log/supervisor/motion_switch.log
```
追加した設定ファイルを読み込みます

```
$ sudo supervisorctl reload
```
各種コマンド

```
状態確認
$ sudo supervisorctl status motion_switch
停止
$ sudo supervisorctl stop motion_switch
開始
$ sudo supervisorctl start motion_switch
```
supervisorはOS起動時に登録したプログラムを開始してくれるので、これでラズパイ起動時に必要なプロセスがすべて立ち上がるようになりました。

## 参考記事
- https://qiita.com/yuukiw00w/items/94e4495fc593cfbda45c
- https://qiita.com/horo/items/1b1549ff8354e9788c9e
- https://qiita.com/Swordroot_M/items/ff337cde987fab6795ea