AWS IoTとRaspberry Pi使って、プランターの野菜を救う！


菜園大好きエンジニアです！ 
毎日パソコンに向かってコード書いてると肩こりますよね〜。トラブル起きて徹夜になったりすると心も病みますよね〜。そんな時は大地のエネルギーもらって心を癒すのが一番です！そうです、 **みんなで野菜を育てましょう！** 

ん、「畑なんか無いよ」って、大丈夫、プランターがあれば畑が無くても、庭が無くても野菜は作れます。でも問題が一つあります。畑だと少しくらい水あげなくたって大地のエネルギーで野菜は元気です。でもプランターには大地のエネルギーが無いのでちゃんと **水やりしないと野菜が元気なくなっちゃいます。**

## プランター栽培の野菜にちゃんと水をやる方法

「野菜とITをデザインする」フューチャーアーキテクトのエンジニアとしては、やはりITで課題解決しないとですね！ こんな時は、最近はやりの「IoT」っしょ。農業とITも最近巷で盛り上がってますしね！。そんな農業で使えるIoT技術の基礎を実験しつつ、我が家のプランター野菜を助けてみたいと思います。

まずは「要件定義」ですね。 __「何が実現したいのか」__ かこれを明確にしないと、一生懸命開発してもエンジニアが不幸になるだけです。今回の場合、業務要件は

「プランターに適切なタイミングで水やりをする」

ことになりますが、実現方法としては

__「受験だと言いつつ、いつもLINEばっかしている中3の娘にプランターに水やりをさせる」__

これです。 _ホント勉強してくれ。_
本当は自動水やり機作るとかがいいんですが、IT投資は効果を見ながらやらないとですからね、一歩づつ行きましょう。まぁ時間が足りないだけですが。

そして、この業務要件を実現するための、システムに求められる要件としては、いかにLINEばっかやっている娘を動かすかです。

・自分で水やりをするタイミングを判断するなんて無理（LINEで忙しいですからね）
・親が言ってもやらない（部屋の掃除もやらせるの大変）

という制約条件がありますから、

__「野菜が自ら＂水が欲しいよ〜＂とLINEで話しかけてくる」__

これなら

中三娘：「マジか！野菜がLINEしてきたよ、やばくね。水あげようよ！」

ってことで動いてくれるはずです。

## プランターを救う為のアーキテクチャを考えよう！

次はアーキテクチャデザインってヤツですね。どんな仕組みでこのシステム要件を実現するかです。ここからは（やや）真面目です。

今回、以下のような仕組みで実現します。

![IMG_0791.JPG](https://qiita-image-store.s3.amazonaws.com/0/101135/496257b5-ae1f-fb8d-740d-ea27334885c5.jpeg "IMG_0791.JPG")


水いつやるかを判断するにはやっぱりセンサーですね、センサー。流行ってます。今回は水やりですので水分量を測れるセンサー __「GROVE - 水分センサ【SEN92355P】」__ を使います。高いのかなと思ったら、安いのは安いんですね。こちらを使います。GROVEはAmazonでも購入できます。

![IMG_0774.JPG](https://qiita-image-store.s3.amazonaws.com/0/101135/ae6f78f6-46b8-f3d5-0035-d33794da89ae.jpeg "IMG_0774.JPG")

センサーからデータを取る部分は __Raspberry Pi（ラズパイ）__ を使います。本当はArduinoとか使いたいですがこちらも時間の関係で、A/D変換かましてラズパイのみでいきます。アプリ開発はnode.jsベースでいきます。ただセンサーからデータ抜くところは諸事情（GPIOをnode.jsから操作する余力がありませんでした...）によりPythonです。ここ作りが歪ですが、後で直しましょう。ラズパイもAmazonで買えますね。

![IMG_0657.JPG](https://qiita-image-store.s3.amazonaws.com/0/101135/3d1f2a65-c95f-6052-6247-9c87198a4200.jpeg "IMG_0657.JPG")

ラズパイで受け取ったデータはサーバ経由して送ります。自前のサーバとか面倒なのでやっぱAWSでしょ。ちょうど良いサービスがあります。その名も __「AWS IoT」__ 今回にぴったりのサービスですね。偶然ラズパイでも使えるSDKも用意されてますので、node.js版のSDKを使いましょう。
このSDK使うと内部的にはMQTTと言う通信プロトコルが使われて、ラズパイ上のnode.jsとAWS IoTが会話をします。このMQTTに関してもう少し知りたい方は[この記事](http://qiita.com/mamatumo/items/e99428775c20064f41ee)が役に立ちますよ。

AWS IoT
	[http://aws.amazon.com/jp/iot/](http://aws.amazon.com/jp/iot/)

さてAWS IoTて受け取ったデータは、各種AWSのサービスに引き渡すことができます。以下対応しているサービスです。

- Insert message into a database table (DynamoDB)
- Send message as a push notification (SNS)
- Send message to a real-time data stream (Kinesis)
- Republish this message to another topic (AWS IoT)
- Insert this message into a code function and execute it (Lambda)
- Store the message in a file and store in the cloud (S3)
- Send the message to a queue in the cloud (SQS)

本当は、Lambdaで処理したり、Kinesisに送ったり、DynamoDBに保存したりしたいところですが、今回は「中三の娘に伝える」ことが至上命題ですから、 __Amazon SNS__ を使うことにします。ちょっとLINEに送ったり、スマホアプリ作ってプッシュ通知と行きたいところですが、時間が足らないのでまずはメール通知にしておきます。

## さて構築の始まりです。まずはAWSの準備、最初はSNSから

続いてサーバ側の環境ですが、こちらは全てAWSですのでアカウントさえあれば大丈夫です。AWSは１年間の無料お試し期間もありますので、まだ使ってない人はこれを機会に使ってみてください。まずは「Amazon SNS」にて、中三の娘にメール通知する定義をしましょう。まずはAWSコンソールでAmazon SNSを選択しましょう。

![Window_と_AWS_マネジメントコンソール 2.png](https://qiita-image-store.s3.amazonaws.com/0/5170/bb823429-40e8-ef04-171c-c4db6a80e633.png "Window_と_AWS_マネジメントコンソール 2.png")

続いて、新しいtopicを作成します。後でAWS IoTのルールと言うものでこのtopicを呼び出します。

![Window_と_AWS_SNS 2.png](https://qiita-image-store.s3.amazonaws.com/0/5170/0bb6efcf-ec83-9ae6-daab-8f1fd0e54984.png "Window_と_AWS_SNS 2.png")

![Window_と_AWS_SNS 3.png](https://qiita-image-store.s3.amazonaws.com/0/5170/ddfe5bf9-405c-d2ce-f767-b9cf8e07bd7c.png "Window_と_AWS_SNS 3.png")

topicができたら今度はSubscriptionsを選択して、通知先の設定をします。今回は一番手軽なメール通知を選びます。本格的にやるときはスマホアプリを作って、そのアプリにプッシュ通知とかですかね。

![AWS_SNS.png](https://qiita-image-store.s3.amazonaws.com/0/5170/182c4e77-7528-0931-69b7-7ef4d526591b.png "AWS_SNS.png")

ここでは対象となるtopicのARNと、通知先のメールアドレスを設定します。

![Window_と_AWS_SNS 4.png](https://qiita-image-store.s3.amazonaws.com/0/5170/018b3287-a1d4-4c99-326a-e826401d4464.png "Window_と_AWS_SNS 4.png")

登録すると指定したメールアドレスに確認メールがきますので、そのメールにある「Confirm subscription」のリンクをクリックして承認してください。これでSNSの設定は完了です。

## 続いて、AWS IoTの設定をしていきます

続いてAWS IoTの設定をしていきましょう。AWSコンソールにアクセスしてAWS IoTを選びます。

![Window_と_AWS_マネジメントコンソール.png](https://qiita-image-store.s3.amazonaws.com/0/5170/196e470e-e73e-4c2d-0235-a58a1a1ce1b7.png "Window_と_AWS_マネジメントコンソール.png")

AWS IoTの管理画面に来たら「Create Resource」ボタンを押して、必要な定義を作っていきます。

![AWS_IoT 3.png](https://qiita-image-store.s3.amazonaws.com/0/5170/fc3336f7-fa77-61dc-2afd-873b21d5d3a3.png "AWS_IoT 3.png")

まずは、デバイスを登録しましょう。今回はラズパイを使いますので、ラズパイを登録することになります。ここはデバイス名を任意で付けるだけで大丈夫です。

![Window_と_AWS_IoT 2.png](https://qiita-image-store.s3.amazonaws.com/0/5170/5368fa43-8f5d-1fd4-5a05-780989c47fb4.png "Window_と_AWS_IoT 2.png")

デバイスを登録すると、新しいthingが作られます。今作ったthing選択を選択すると、画面右側に詳細情報が表示され、その下に「Create Rule」というボタンが出てきますので、このデバイスから受け取ったデータを処理するルールを作ります。

![Window_と_AWS_IoT 7.png](https://qiita-image-store.s3.amazonaws.com/0/101135/8be44381-5e99-d74f-c4a9-abebacaee93a.png "Window_と_AWS_IoT 7.png")

ルールではデバイスから受け取ったメッセージをどう処理するかを書きます。メッセージをフィルターする部分はSQLライクな記載なので突付き易いですね。ここではConditionとして

```
moisture > 500
```
としてますが、これは水分センサーの出力値から設定しています。センサーの仕様は以下のURLで確認できます。

[水分センサーの仕様](http://seeedstudio.com/wiki/Grove_-_Moisture_Sensor)

![Window_と_AWS_IoT 4.png](https://qiita-image-store.s3.amazonaws.com/0/5170/634bf52d-ac6f-3142-be8e-79afbaece04b.png "Window_と_AWS_IoT 4.png")

次に、取得したデータをどう処理するかのルールを書きます。

![Window_と_AWS_IoT 5.png](https://qiita-image-store.s3.amazonaws.com/0/5170/db76f79a-a380-d54d-2285-13f4bbeb0f27.png "Window_と_AWS_IoT 5.png")

ルールができたら、次にデバイス（ラズパイ）からつなぐために、node.js用のSDKのダウンロードと、接続時に使う証明書や鍵を準備します。先程作成したデバイスを再度選択し、詳細画面を表示したら今度は右側の「 Connect a device」のボタンを押しましょう。

![Window_と_AWS_IoT 6.png](https://qiita-image-store.s3.amazonaws.com/0/5170/0980314e-8efe-2a47-7fb9-07792e8b3f09.png "Window_と_AWS_IoT 6.png")

するとSDKを選択する画面が表示されます。今回はラズパイ上でnode.jsを動かしますので、「NodeJS」を選択します。すると右側に鍵（公開鍵、秘密鍵）や証明書のダウンロードするリンクがでますので、秘密鍵と証明書をダウンロードしておいてください。後でラズパイに配置して使います。最後に「Confirm & start connecting」のボタンを押すとSDKのダウンロードURLが表示され、合わせてSDKでの設定例が表示されます。SDKはあとでラズパイから直接ダウンロードするのでここではダウンロード不要です。ここでは設定例だけメモしておいてください。

![AWS_IoT 4.png](https://qiita-image-store.s3.amazonaws.com/0/5170/6cb8a530-ee81-e94c-36bd-00e93d1ea691.png "AWS_IoT 4.png")

サーバ側のセットアップはこれで終了です。やはりAWSは楽ですよね、Webの画面でポチポチやるだけで環境できちゃうんですからね。便利な世の中になったものんですね！

## Raspberry Pi側のセットアップ

さて今度はラズパイ側のセットアップですが、まずはお買い物が必要ですね。今回買い物が必要なものは水分センサーと、ラズパイ、そしてラズパイにセンサーをつなぐ為の配線、A/Dコンバータなどですね。後は、ラズパイにインストールするソフトウェア、こちらはネットからダウンロードできます。実際に使ったハードウェアとソフトウェアの一覧を以下に挙げておきます。

### ハードウェア・ソフトウェアの一覧

| ハード/ソフト | 入手元 | 
|:-----------|:------------|
| Raspberry Pi model B+ | Amazonにて購入<br><a href="http://www.amazon.co.jp/s/ref=nb_sb_ss_i_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&url=search-alias%3Dcomputers&field-keywords=raspberry+pi&sprefix=raspberry+pi%2Ccomputers%2C263&rh=n%3A2127209051%2Ck%3Araspberry+pi" target="_blank">Amazonで"Raspberry Pi"で検索</a> |
| 　RASPBIAN WHEEZY | [https://www.raspberrypi.org/downloads/raspbian/](https://www.raspberrypi.org/downloads/raspbian/)|
| 　node.js v4.2.1 | nodebrewでインストール |
| 　AWS Iot SDK | gitでインストール<br>[https://github.com/aws/aws-iot-device-sdk-js.git](https://github.com/aws/aws-iot-device-sdk-js.git) |
| 　Python v2.7 | apt-getでインストール |
| GROVE  | Amazonにて購入<br><a href="http://www.amazon.co.jp/s/ref=nb_sb_noss?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&url=search-alias%3Dcomputers&field-keywords=Grove+%E6%B0%B4%E5%88%86%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC&rh=n%3A2127209051%2Ck%3AGrove+%E6%B0%B4%E5%88%86%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC&ajr=0" target="_blank">Amazonで"GROVE 水分センサ"で検索</a> |
|Raspberry Pi 工作キット | Amazonにて購入<br>[Amazonで工作キットを検索](http://www.amazon.co.jp/s/ref=nb_sb_noss?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&url=search-alias%3Daps&field-keywords=Raspberry+Pi%E9%9B%BB%E5%AD%90%E5%B7%A5%E4%BD%9C%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%83%BC%E3%82%AD%E3%83%83%E3%83%88&rh=i%3Aaps%2Ck%3ARaspberry+Pi%E9%9B%BB%E5%AD%90%E5%B7%A5%E4%BD%9C%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%83%BC%E3%82%AD%E3%83%83%E3%83%88)|

工作キットには最低限以下のパーツが入っている必要があります。

- ブレッドボード（簡易的に配線するボード）
- ジャンパーワイヤ（オス-メスはラズパイとボード間で利用、オス-オスはボード内で利用）
- A/Dコンバータ（MCP3208とかでセンサーからくるアナログ値をデジタル値に変換します）

## Raspberry Piへの各種ソフトウェアインストール

さて買い物が届いたらやっとラズパイ側のセットアップになります。ここからは今までのようにWeb画面でポチポチってわけにはいきません。ラズパイ自体のセットアップ方法の情報はネット上にたくさんありますので、ここでは省きます。

まずはnode.jsをインストールします。nodebrew経由でインストールしましょう。まずはnodebrewをインストールして、パス通して

```
> curl -L git.io/nodebrew | perl - setup
> export PATH=$HOME/.nodebrew/current/bin:$PATH
```
その後、node.jsをインストールしましょう。今回はなんとなくv4系を入れてみました。

```
> nodebrew install-binary 4.2.1
> nodebrew use v4.2.1
```

続いてPython環境もセットアップします。今回はセンサーからGPIO経由でデータ取得する部分だけPythonで逃げました。全部node.jsでやればPythonは必須ではありません。以下のようにPythonとRPi.GPIO moduleをインストールします。

```
> sudo apt-get install python-dev
> sudo apt-get install python-setuptools
> sudo easy_install rpi.gpio
```

最後、AWT IoTのSDKをインストールしましょう。まずはgitコマンドでダウンロードし、そのままnpmで関連モジュール含めてインストールしましょう。

```
> git clone https://github.com/aws/aws-iot-device-sdk-js.git
> cd aws-iot-device-sdk-js
> npm install
```

## 土壌水分センサーをラズパイにつないでみよう！

ラズパイの環境が準備できたら水分センサーをつないでみましょう。今回の接続は以下のPDFを参考にしてつないでみました。この資料はボリュームの制御になっていますがアナログ→デジタル変換の仕組みは同じなので同じ配線でイケます。デバイスだけセンサーに切り替わるイメージです。

[Analog Inputs for Raspberry Pi Using the MCP3008](https://learn.adafruit.com/downloads/pdf/reading-a-analog-in-and-controlling-audio-volume-with-the-raspberry-pi.pdf)

こんな感じでつなぎました。

![IMG_0778.JPG](https://qiita-image-store.s3.amazonaws.com/0/5170/6c4462ca-6ac9-2d7b-3a6d-e5c887166d5f.jpeg "IMG_0778.JPG")

これでセンサーからのアナログ値をA/Dコンバーターでデジタル値に変換されてラズパイで読み出せる状態になっています。デジタル変換された値はラズパイのGPIOにつながっていますので、プログラムでこのGPIOの値を読めばいいわけです。この部分はPythonで読みました。Pythonのコードは配線で参考にさせてもらった

[Analog Inputs for Raspberry Pi Using the MCP3008](https://learn.adafruit.com/downloads/pdf/reading-a-analog-in-and-controlling-audio-volume-with-the-raspberry-pi.pdf)

にあるコードが参考になります。

## node.jsでAWS Iot SDKを使った処理

センサーからの値をPythonで取得しているが、AWS IoTへのメッセージはnode.jsで書こうとしています。ここがちょっと面倒でした。少しやっつけ的な実装ですが、node.jsからPythonのプログラムを呼び出して、標準出力で戻り値をJSON文字列として取得するという原始的な方法でまずは逃げました。コードの抜粋は以下です。

```get_grove.py
# 別関数でセンサーからのデータをGPIOから取得する
trim_pot = readadc(potentiometer_adc, SPICLK, SPIMOSI, SPIMISO, SPICS)
set_value = trim_pot
set_value = round(set_value)      
set_value = int(set_value)        
# 値をオブジェクトの形へ
ret_value = {
  "value": set_value
}
# JSON文字列へ変換して標準出力へ
jsonstring = json.dumps(ret_value)
print jsonstring

```

今度は呼び出すJavascript側のコードです。

```get_grove.js
exec('python ./get_grove.py', function(err, stdout, stderr) {
  // 標準出力のJSON文字列からオブジェクトへ
  var data = JSON.parse(stdout);
  // 呼び出し元へ
  callback(err, data, stderr);
});
```

そして、呼び出し元のJavascriptでは、AWS IoT SDKを使ってセンサーから受け取ったデータをサーバへ送信します。

```send_iot.js
// AWS IoT SDKから提供されるdeviceオブジェクト
const deviceModule   = require('..').device;
const device = deviceModule({
  keyPath: args.privateKey,
  certPath: args.clientCert,
  caPath: args.caCert,
  clientId: args.clientId,
  region: args.region,
  reconnectPeriod: args.reconnectPeriod
});

// Pythonのラッパー
var getGrove = require('./get_grove.js');
// Python呼び出し
getGrove(function(err, data, stderr) {
  if (err) {
    return console.log(stderr);
  }else{
    // IoTのdeviceModuleのpublishメソッドでメッセージを送る
    // 送り先 -> topic:planter_moisture
    device.publish('planter_moisture', JSON.stringify({
      moisture: data.value}));
  }
});
```

これでAWS IoTにメッセージが送られます。送られたメッセージはAWS IoTに定義されたルールに従って処理をされます。ルールとして設定したのが、以下のものでした。

##### Query stringの定義

topicが「planter_moisture」に送られてきたメッセージの「moisture」の値が500未満だったら、水が足りないと判定する。

```
SELECT * FROM 'planter_moisture' WHERE moisture < 500
```

##### アクション定義

アクションとしては「SNS経由でメール通知」としました。ですのでこの場合、ラズパイから送られて来たメッセージがそのままメール通知されることになります。メールで受信すると以下のようになっています。

```

From: AWS Notifications(no-reply@sns.amazonaws.com)
件名：AWS Notification Message
本文：

{"moisture":608}

```

あっ、なるほど直接AWS IoTからSNS経由でメールしちゃうと意味不明になっちゃいますね。ここはやはりLambdaなど経由してメッセージを人（この場合、我が家の中三の娘）が理解出来る形にしないとですね。そうしないと

中三娘： __「なんか意味不明なメールが来たから、消した」__

ってなっちゃいます（笑
まだまだプランターの野菜を救うには時間がかかりそうです。

## まとめ

結果としてまだうちの娘がプランターに水やりしてくれるまでは至りませんでしたが、センサーで水分量を計測して、それをラズパイからAWS IoT経由してAmazon SNS経由でメールで通知するという一連の流れは通りました。疎通テストができたって状態ですね。
今回、AWS IoTもラズパイ＋センサーもほぼ初めて使いましたが、あまりはまらずにできましたね。今回はプランターの水分量で試しましたが、もっと色々応用はできますね。また、AWS IoT側で受けたメッセージの処理に関しても色々工夫ができそうです。楽しくなってきたので、これをベースに本気でやってみよう。春が来てプランターで野菜をたくさん栽培するときには使えるように！