Slackでペットのお留守番を見守る

# 背景
「くるみちゃん」というシルバーのトイプードルを飼っています。
夫婦共働きなので、毎日長時間のお留守番を頑張ってくれています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/135983/f23f2539-ce8b-7b8e-fb6e-93cdf2b4edf8.png)

昨年、冬に部屋が寒すぎてお腹を壊してしまったくるみちゃん・・・
家に帰ったら惨状が・・・
慌てて病院に連れて行きましたが、その時は原因がわからず一週間惨状が続きました。

その後、留守中のくるみちゃんの様子が心配で、
見守りシステムを作ることにしました！！

# 解決したい課題
- 外出先からお留守番の様子が見えない
- 部屋の温度が夕方から急激に寒くなる

# システム要件
我が家は、夫婦Slackを導入しているので、見守りもSlackで行うことにしました。

- お留守番の様子を、Slackから任意のタイミングで写真を撮ることができる
- 定期的に温度を取得しSlackにつぶやく
- Slackでエアコンのオン/オフができる

# 準備したもの
**電子工作的なもの**
- Raspberry pi3
- カメラモジュール（純正）
- 温湿度センサー（DHT22)
- [光センサ付赤外線ＬＥＤリングライト　８５０ｎｍ　ＯＳＦＫＳ５ＣＳ](http://akizukidenshi.com/catalog/g/gM-09590/)
- 赤外線受信モジュール（KY-022)
- [５ｍｍ赤外線ＬＥＤ3個](http://akizukidenshi.com/catalog/g/gI-03261/)
- 光センサー（GY-30）

**システム的なもの**
- Slack

**開発環境**
- MacOSX
- センサーの操作：Python
- Slack Bot：Hubot＋CoffeeScript

# 配線
![kurumi-twitter2017_ブレッドボード.png](https://qiita-image-store.s3.amazonaws.com/0/135983/5af1c323-40f1-fbb8-78a9-fc0b295ae657.png)


# RaspberryPi構築
## RaspberryPiのセットアップ

Raspberrypiが未セットアップの方は、こちらがとても丁寧に解説されていますので参考になさってください！
我が家はセットアップ済みのRasperryPiが何個か転がっているので、そのうちの一つを使いました。
> [Raspberry Pi セットアップ(書き込み～SSH設定まで](https://qiita.com/Halhira/items/1da2ae543217be26988a)

## RaspberryPiからエアコン操作
### 赤外線リモコンを作る

Slackからエアコンをつけられるように、まずは赤外線リモコンを作ります。
配線〜スクリプトまで、基本的には、この本で全て作れます！！めちゃくちゃお世話になりました。

> [ラズベリー・パイで遊ぼう! 単行本（ソフトカバー） – 2016/7/22](https://www.amazon.co.jp/ラズベリー-パイで遊ぼう-林-和孝/dp/4899774486/)
> 林 和孝 (著)

### 赤外線送信コマンド
このコマンドを、後にSlackから操作します。

|目的|コマンド|
|:--------------|:---------------------------------------|
| 暖房オン        | irsend SEND_ONCE aircon warm24　        |
| 冷房オン        | irsend SEND_ONCE aircon cool27        　|
| エアコンオフ      | irsend SEND_ONCE aircon off　           |


### つまずいたところ
- エアコンの種類によって、赤外線学習がうまくいかなかった

我が家のエアコンは日立のしろくまくんを使っているのですが、
この本に載っているirrecordを使った赤外線記憶の方法ではうまくいかなかったため、
下記ホームページを参考にさせて頂きました。
> [Raspberry Pi 2 でエアコン操作（赤外線リモコン編）](http://kaiware007.hatenablog.jp/entry/2015/08/28/020356)

- 赤外線の指向性？

赤外線送信モジュール一つだと、エアコンの受光するところに近づけて（2mくらい？）ピンポイントで発射しないと、エアコンが反応してくれなかった。
そのため、赤外線LEDを3つ繋いで、強化しました。
指向性の問題については、[拡散キャップ](http://akizukidenshi.com/catalog/g/gI-00641/)を使うことで解決できるかと思いましたが、赤外線が弱くなってしまうため、使うことは見送りました。

## RaspberryPiから写真撮影
カメラで撮影するプログラムをPythonでかきます。
基本のコードはこの本を参考にさせていただきました！神！
> [ラズベリー・パイで遊ぼう! 単行本（ソフトカバー） – 2016/7/22](https://www.amazon.co.jp/ラズベリー-パイで遊ぼう-林-和孝/dp/4899774486/)
> 林 和孝 (著)

工夫したところは、お留守番中夜でも写真が撮れるように赤外線カメラを設置したところと、
部屋が暗い時（光センサーで判定）にはシャッタースピードを遅くし撮影しています。

光センサーは、I2Cを使っていますが、RaspberryPiでは初期状態では有効になっていません。
ライブラリーをインストールします。

```
$ sudo apt-get install i2c-tools libi2c-dev python-smbus python3-smbus
```
その後、RaspberryPiの本体のメニュー[Menu]-[設定]-[RaspberryPiの設定]-[インターフェース]-[I2C]を有効に設定します。

- 光センサーで判定する前
よーく見たら、真ん中に横たわって寝ていますが・・・、なんだかよくわかりませんね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/135983/b4528739-de01-753a-b05f-1b4c338c1437.png)


- 光センサーで判定した後
手前のトイレゾーンにいます！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/135983/bd7a1621-bc03-8e4d-dd06-1757cb2ec5c5.png)


```takePicture.py
# coding:utf-8

import smbus
import os

#光センサーで明るさを取得
def getLight():
    bus = smbus.SMBus(1)
    addr = 0x23
    luxRead = bus.read_i2c_block_data(addr,0x11)
    return luxRead[1]*10

def takePicture():
    lux = getLight()
    if lux < 200:
        #写真撮影
        os.system('raspistill -o /home/pi/..../...../images/photo.jpg -rot 90 -w 1000 -h 1000 -ss 1000000')
    else:
        #写真撮影
        os.system('raspistill -o /home/pi/..../...../images/photo.jpg -rot 90 -w 1000 -h 1000')

if __name__ == '__main__':
    takePicture()
```

## RaspberryPiから温度取得
温湿度センサーDHT２２から温度取得します。

1.ライブラリをインストールします。

```
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git
$ cd Adafruit_Python_DHT/
$ sudo python setup.py install
```

2.温度を取得するプログラムを作成します。

```getTemp.py
#!/usr/bin/python
# -*- coding: utf-8 -*-

import Adafruit_DHT

def getTemperature():
        humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.DHT22, 4)
        if humidity and temperature:
                return temperature
        else:
                return -100

def createTweetMessage():
    t = getTemperature()
    if t == -100:
        msg = "今のくるみのお部屋の温度はわからないです。ごめんなさい～"
    else:
        msg = "今のくるみのお部屋の温度は{0:0.1f}度です。"
    return msg

if __name__ == '__main__':
    msg = createTweetMessage()
    print msg
```

# SlackとRaspberryPiの連携
## Slackへ部屋の温度を投稿
###　Slackの設定
1.下記ページをクリックし、Incoming WebHooksを有効化します。

> https://my.slack.com/services/new/incoming-webhook/
![image.png](https://qiita-image-store.s3.amazonaws.com/0/135983/7c61e8fe-6df0-e034-53c9-7c3e71e37955.png)

2.**Webhook URL**の値をコピーしておきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/135983/6f50d342-1712-6e7c-590e-5b9b3b3e4466.png)

###　Slackへ投稿するモジュールをインストール

```
$ sudo pip install slackweb
```

###　温度取得プログラムを改修
1.「RaspberryPiから温度取得」で作成したプログラムgetTemp.pyを改修し、Slackへ温度を投げるプログラムを追加します。
また、温度によってくるみちゃんのコメントを変えます。

```postTemp.py
#!/usr/bin/python
# -*- coding: utf-8 -*-

import slackweb
import Adafruit_DHT

def getTemperature():
        humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.DHT22, 4)
        if humidity and temperature:
                return temperature
        else:
                return -100

def createTweetMessage():
    t = getTemperature()
    if t == -100:
        msg = "今のくるみのお部屋の温度はわからないです。ごめんなさい～"
    elif t >= 30:
        msg = "今のくるみのお部屋の温度は{0:0.1f}度です。".format(t) + "暑すぎですう。今すぐクーラーをいれてください！！"
    elif t >= 28:
        msg = "今のくるみのお部屋の温度は{0:0.1f}度です。".format(t) + "暑くなってきたのでそろそろクーラー入れてほしいですう。"
    elif t >= 25:
        msg = "今のくるみのお部屋の温度は{0:0.1f}度です。".format(t) + "そんなに暑くないですう。"
    elif t >= 22:
        msg = "今のくるみのお部屋の温度は{0:0.1f}度です。".format(t) + "今日は涼しいですう。クーラーはいらないかなー。"
    elif t >= 18:
        msg = "今のくるみのお部屋の温度は{0:0.1f}度です。".format(t) + "ちょっと寒くなってきました～。"
    elif t >= 14:
        msg = "今のくるみのお部屋の温度は{0:0.1f}度です。".format(t) + "暖かい場所が恋しいですう。"
    else:
        msg = "今のくるみのお部屋の温度は{0:0.1f}度です。".format(t) + "寒いよー。暖房つけてほしいですー！"
    return msg

if __name__ == '__main__':
    msg = createTweetMessage()
　　　　　　　　#SlackのWebhook URLを使用します。
    slack = slackweb.Slack(url="https://hooks.slack.com/services/xxxxxxxxx/xxxxxxxxx/xxxxxxxxxxxxxxxxx")
    slack.notify(text=msg)
```

２.cronに登録して1時間に１回Slackへ投稿する

```
$ crontab -e
0 * * * * python /home/pi/.../.../postTemp.py
```

３.結果！

![image.png](https://qiita-image-store.s3.amazonaws.com/0/135983/ba8ecb07-2096-d9d1-a50f-722005a165f8.png)


## Slackからカメラ撮影する・エアコンをつける
### RaspberryPiにHubotを導入〜SlackへHubot追加

こちらのページがわかりやすくまとまっていましたので、参考にさせていただきました！ありがとうございます！！！m(_ _)m

> [Raspberry Pi | 自作Slackボットを作ろう~その2~　HubotのインストールとSlack連携（Herokuは使わない）](http://www.tapun.net/raspi/raspberry-pi-raspberry-pi-slack-hubot-install)

### くるみちゃん(Hubot)に話しかけてカメラの撮影
bot/scriptsの下に、スクリプトを置いておくと自動で読み込んでくれるようなので、ここにCoffeeScriptで書いたコードを配置します。

```camera.coffee
hild_process = require 'child_process'

module.exports = (robot) ->
    #カメラ
    robot.respond /.*カメラ.*/i, (msg) ->
　　　　　　　　#「カメラで撮影するプログラムをPythonでかく」で記載したtakePicture.pyを実行する
        child_process.exec "python /home/pi/..../......./takePicture.py", (error, stdout, stderr) ->
            if !error
                try
                    filename = '/home/pi/..../......./images/photo.jpg'
                    channel = msg.message.room
                    msg.reply "今のくるみはこんな感じです。"
                    child_process.exec "curl -F file=@#{filename} -F channels=#{channel} -F token=#{process.env.HUBOT_SLACK_TOKEN} https://slack.com/api/files.upload", (err, stdout, stderr) ->
                catch e
                    msg.reply "#{e}"
            else
                msg.reply "#{error}"
        return
```

話しかけた結果はこんな感じでくるみちゃんが写真をアップロードしてくれます！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/135983/9fe7aa7f-933c-3b5e-bd7b-24e088b5d29b.png)

### くるみちゃん(Hubot)に話しかけてエアコンのオンオフ

```aircon.coffee
child_process = require 'child_process'

module.exports = (robot) ->
    #暖房
    robot.respond /.*暖房オン.*/i, (msg) ->
        # ここのコマンドは、本記事の「赤外線送信コマンド」のものを設定します。
　　　　　　　　　　　　　　　　# 冷房オン、オフもここのコマンドを変更することで対応可能です。
        child_process.exec "irsend SEND_ONCE aircon warm24", (error, stdout, stderr) ->
            if !error
                try
                    if msg.message.user.name is "<Slackの自分のID（msg.message.user.name）>"
                        name = "ママさん"
                    else
                        name = "パパさん"

                    msg.reply "#{name}、暖房つけました！"
                catch e
                    msg.reply "#{e}"
            else
                msg.reply "#{error}"
        return
```

話しかけた結果は、わかりにくいですが、返事をして暖房をつけてくれます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/135983/30026271-63a2-eb64-3513-265af652362b.png)

### CoffeeScriptでつまずいたところ

CoffeeScriptを初めて使いましたが、しょーもないところでつまずいたので、記録しておこうと思います。

#### デバッグ方法

変数などをデバッグする場合、このように書くそうです。
`robot.logger.debug "channel is: #{channel}"`


ログはどこに書かれているかというと、

```
$ forever list
info:    Forever processes running
data:        uid  command script                           forever pid   id logfile                    uptime        
data:    [0] JZT8 coffee  node_modules/.bin/hubot -a slack 15490   22705    /home/pi/.forever/JZT8.log 0:3:39:16.813
```
↑この例だと、「/home/pi/.forever/JZT8.log」になります。
よって、
`$ tail -f /home/pi/.forever/JZT8.log`でログを確認できます。

#### SyntaxError修正方法

> http://coffeescript.org/#try

左側にコードを貼り付けると、右側にJava Scriptに変換してくれて、SyntaxErrorが何行目でおきているかわかりやすくなりました。便利！

# 最後に
Slackを使って、ペットの見守りシステムを構築してみました。
RasperryPi1つでここまで出来て、便利に毎日使っています！
くるみちゃんも健康を維持できてます。
おしまい。