Raspberry Pi でSORACOM 接続＋MQTTをしてみよう 後編 [Step 6 ～ Step 8]

# はじめに
この記事は、[春のIoTリレーハンズオン@関西](http://www.slideshare.net/ichiroohkini/jawsugiot-iot)の一環として開催される[＜SORACOM接続 + MQTT編>](https://soracom-ug-kansai.doorkeeper.jp/events/39574)のハンズオン用資料です。
本ハンズオンでは、RaspbianをインストールしたRaspberry Pi（以降、ラズパイ）でSORACOMのサービスの基本部分をひととおり使えるようになるまでの手順をまとめています。
この記事では、8ステップあるハンズオン手順のうち、後半となるStep 6 ～ Step 8を掲載しています。
前半のStep 1 ～ Step 5は[こちら](http://qiita.com/dietposter/items/901de889b1a83f11fa60)です。
 
# [Step 6.] ラズパイにADコンバータと光センサーを接続する
ラズパイには以下の図のように様々な電子部品を接続するピン（GPIOピンと呼ぶ）があります。それぞれにピン番号（例：左上のピンの灰色の`1`)）と名前（例：左上のピンの黄色の`[3.3V PWR]`）が割り当てられていて役割も決まっています。
![image](http://ms-iot.github.io/content/images/PinMappings/RP2_Pinout.png)
*[IoTコアのサンプルページ](http://ms-iot.github.io/content/en-US/win10/samples/PushButton.htm)より引用*

ラズパイのGPIOで他のマイコンボードと違う点は、アナログ入力ピンが無いという点です。温度や光量、音量などはアナログ入力でセンサー部品が豊富にありますが、ラズパイではそれらセンサーのアナログデータを直接入力できません。ADコンバータ用ICを介して適切なビット長のデジタルデータに変換する必要があります（もしくはI2Cインターフェースをもったセンサー部品を入手する必要があります）。
当ハンズオンでは、フォトダイオードのアナログ入力を10ビット(0～1023）のデジタルデータに変換してラズパイに入力します。
## 【ToDo 6.1】ADコンバータとフォトトランジスタなど電子部品を準備する
以下の電子部品があるかどうか確認してください。

* ラズパイ（Raspberry Pi 2 Model B推奨）1個
* ブレッドボード（ハーフタイプEIC801を推奨） 1個
* ADコンバータ 8ピンIC MCP3002 1個
* フォトトランジスタ NJL7502L 1個
* 抵抗 7.5kΩ 1個
* オス・メスケーブル 6本
* オス・オスケーブルまたはジャンパーワイヤ 3本

欠品があるようでしたら補充してから以下の作業に入ってください。

## 【ToDo 6.2】ADコンバータとフォトトランジスタを配線する
ラズパイをシャットダウンし、電源ケーブルを抜いて電源オフします。
以下の図を元にラズパイとブレッドボード上に部品を配置しケーブルを配線してください。
![image](https://qiita-image-store.s3.amazonaws.com/0/4092/800ea87a-2c8f-1ba8-7ff4-38ec8bd5e8a3.png)

1. ADコンバータMCP3002をブレッドボードに差し込む。4つづつある左右のピンは、ブレッドボードの中央の溝にかかるようにし、半円状の切り欠きが図では下側に向くようにする。
2. 7.5kΩ抵抗をADコンバータMCP3002 `4`番とフォトトランジスタNJL7502Lの短い脚にあたるブレッドボードの穴に差し込む。
3. フォトトランジスタNJL7502Lをブレッドボードの穴に差し込む。短い脚（カソード：陰極側）を図では下側になるようにする。
4. オス・オスケーブルをMCP3002 `3`番とフォトトランジスタNJL7502Lの短い脚にあたるブレッドボードの穴に差し込む。
5. オス・メスケーブルをラズパイの`1`番ピン`[3.3V PWR]`とブレッドボードの＋（赤色）のラインに差し込む。
6.  オス・メスケーブルをラズパイの`9`番ピン`[GND]`とMCP3002 `4`番にあたるブレッドボードの穴に差し込む。
7.  オス・メスケーブルをラズパイの`19`番ピン`[SPI0 MOSI]`とMCP3002 `5`番にあたるブレッドボードの穴に差し込む。
8.  オス・メスケーブルをラズパイの`21`番ピン`[SPI0 MISO]`とMCP3002 `6`番にあたるブレッドボードの穴に差し込む。
9.  オス・メスケーブルをラズパイの`23`番ピン`[SPI0 SCLK]`とMCP3002 `7`番にあたるブレッドボードの穴に差し込む。
10.  オス・メスケーブルをラズパイの`24`番ピン`[SPI0 CS0]`とMCP3002 `1`番にあたるブレッドボードの穴に差し込む。
11.  オス・オスケーブルをブレッドボードの＋（赤色）のラインとMCP3002 `8`番にあたるブレッドボードの穴に差し込む。
12.  オス・オスケーブルをブレッドボードの＋（赤色）のラインとフォトトランジスタNJL7502Lの長い脚（アノード：陽極側）にあたるブレッドボードの穴に差し込む。

## 【ToDo 6.3】SPIを使用可能にする
配線が終わればラズパイの電源を入れます。A/DコンバータMCP3002はSPIインターフェースを用いています。ラズパイでは初期状態でSPIモジュールを無効にしているため`raspi-config`でSPIモジュールを動作するように設定します（Rasbian JESSIEでは以下の操作のみになりました）。

```bash
$ sudo raspi-config
```
・管理画面が出ますので「9 Advanced Options」を選択してEnter
![image](https://qiita-image-store.s3.amazonaws.com/0/4092/d7e894c2-6f44-9663-bbc7-01214ef501ab.png)
・「A6 SPI」を選択
・「Would you like the SPI interface to be enabled?」と出るので「Yes」を選択
・「The SPI interface is enabled」と出るので「Ok」を選択
・「 Would you like the SPI kernel module to be loaded by default?」と出るので「Yes」を選択。
・「SPI kernel module will now be loaded by default」と出るので「Ok」を選択
・メニュー画面に戻ってくるので「Finish」を選択し、再起動を促されればそのままリブートします。

## 【ToDo 6.4】照度センサの動作確認
ADコンバータとフォトトランジスタの配線を確認するため、以下のPythonソースを実行します。

* [sora03.py](https://gist.github.com/yoshidaken1/e04c8b9da2b974c3228f#file-sora03-py)

実行例を以下に示します。GPIOを利用するPythonコードはsudoをつけて実行する必要があります。実行時に光をあてたり遮ったりして、値が変化するか確認してください。

```bash
$ vi sora03.py
$ sudo python sora03.py
ch0 =   40, 0.13[V], ch1 =  391,  1.26[V] ←自然光
ch0 =    0, 0.00[V], ch1 =  400,  1.29[V]
ch0 =    0, 0.00[V], ch1 =  416,  1.34[V]
ch0 =    0, 0.00[V], ch1 =  413,  1.33[V]
ch0 =   77, 0.25[V], ch1 =  382,  1.23[V]
ch0 =  168, 0.54[V], ch1 =  370,  1.19[V]
ch0 =  220, 0.71[V], ch1 =  725,  2.34[V] ←スマホのライトをあてる
ch0 =  194, 0.63[V], ch1 =  936,  3.02[V]
ch0 =  122, 0.39[V], ch1 =  939,  3.03[V]
ch0 =   22, 0.07[V], ch1 =  936,  3.02[V]
ch0 =    0, 0.00[V], ch1 =  932,  3.01[V]
ch0 =   11, 0.04[V], ch1 =  729,  2.35[V]
ch0 =  116, 0.37[V], ch1 =  756,  2.44[V]
ch0 =  191, 0.62[V], ch1 =   13,  0.04[V] ←フォトトランジスタを隠す
ch0 =  224, 0.72[V], ch1 =   15,  0.05[V]
ch0 =  203, 0.65[V], ch1 =   13,  0.04[V]
^C$ ←[Ctrl]+Cキーで中断
```
※実行例にあるとおりADコンバータMCP3002は、2つのアナログ入力チャネルを持っており、今回はch1だけしか使っていません。時間があれば、ch0側にアナログ入力センサーを接続して2つのデータを取得できるようにしてみてください。

# [Step 7.] 光センサーの値をMQTTブローカーに送信する
MQTTは、HTTPに比べ軽量で単純なプロトコルでIoT用途に向いています。
単純な構成図を以下に示します。

```bash:MQTTのPubSubモデル
┏━━━━━━┓     ┏━━━━━━━━━┓     ┏━━━━━━┓
┃(A)Pub┃---->┃(B)Broker┃---->┃(C)Sub┃
┗━━━━━━┛     ┗━━━━━━━━━┛     ┗━━━━━━┛
(A)Publisher（発行者）：ラズパイなどセンサーデータの送信
(B)MQ Broker（仲介者）：データが発生したらSubscriberに通知
(C)Subscriber（購読者）：センサーデータを受信
```

システム運用上の構成では(A)(B)(C)は以下のようになります。

* __(A)Pub__にラズパイなどのセンサーデータを送信するデバイス
* __(B)Broker__にsango時雨堂などMQTTサービスを提供しているクラウド
* __(C)Sub__にAWSなどのセンサーデータを蓄積するクラウド

詳細は割愛しますが、(B)Brokerの**MQTTブローカーがセンサーデータのやり取りを仲介する**ことによって、大量に配置されるIoTデバイスからのセンサーデータを効率よくクラウドにプッシュし蓄積することができるモデルです。
こういったデータ送受信の方式をPub/Subメッセージングモデルと呼びます。

## 【ToDo 7.1】ラズパイ上で(A)(B)(C)を実装し(A)(C)をコマンドで実行
今回MQTTの実装には[mosquitto](http://mosquitto.org/)を用います。
まずは(A)(B)(C)をすべてラズパイ上で実行して動作を確認してみましょう。

* __(A)Pub__ `mosquitto_pub`コマンドで光量データを送信
* __(B)Broker__ `mosquitto`サービスをバックグラウンドで稼働
* __(C)Sub__ `mosquitto_sub`コマンドで光量データを受信

mosquittoおよびmosquitto-clientsをインストールします。インストールと同時にMQブローカーのmosquittoサービスが起動しますので、以下のようにステータスを確認してください。

```bash
$ sudo apt-get install mosquitto mosquitto-clients
$ sudo /etc/init.d/mosquitto status
● mosquitto.service - LSB: mosquitto MQTT v3.1 message broker
   Loaded: loaded (/etc/init.d/mosquitto)
   Active: active (running) since Mon 2016-03-21 12:17:48 JST; 3 days ago
  Process: 373 ExecStart=/etc/init.d/mosquitto start (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/mosquitto.service
           mq389 /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf

Mar 21 12:17:48 raspberrypi mosquitto[373]: Starting network daemon:: mosquitto.
Mar 21 12:17:48 raspberrypi systemd[1]: Started LSB: mosquitto MQTT v3.1 message broker.
$
```

次に__(C)Sub__のデータを受信する側を準備します。新たに別のターミナルを起動し`pi`ユーザーでログインします。以下の`mosquitt_sub`コマンドを実行しデータを待ち受けください。`spinning/3f/brightness000`の部分はトピックと呼ばれる「観察対象」です（ここではセンサー固有のIDとなる）。末尾の`000`の部分は任意の数値にしてください（複数のセンサーがある際、区別するために必要です）。

```bash:新たに別のターミナル画面をだしてmosquitt_subコマンドを実行し待受け
$ mosquitto_sub -t spinning/3f/brightness000 -v # 000は任意の数字に変更
```

`mosquitto`サービスのステータスを確認した元のターミナル画面に戻って、__(A)Sub__のデータを送信する側をコマンドで実行します。

```bash:元のターミナル画面からmosquittp_pubコマンドを実行しデータ送信
$ mosquitto_pub -t spinning/3f/brightness000 -m 1023 # 000は任意の数字に変更
```
すると、`mosquittp_sub`コマンドを実行していた別の画面でトピックおよびデータがSubscribe（＝表示）されます。

```bash:新たな別のターミナル画面（mosquittp_subコマンドを実行し待受け）
$ mosquitto_sub -t spinning/3f/brightness000 -v
spinning/3f/brightness000 1023    ← トピックおよびデータがSubscribeされる
```

## 【ToDo 7.2】ラズパイ上で(A)(B)(C)を実装し(A)をPythonで実行
次に(B)(C)はそのままに、(A)Pub部分をPyhtonソースを実行し、すべてラズパイ上で実行して動作を確認してみましょう。

* __(A)Pub__ `pub_light.py`を実行しで光量データを定期的に送信
* __(B)Broker__ `mosquitto`サービスをバックグラウンドで稼働
* __(C)Sub__ `mosquito sub`コマンドで光量データを受信（別ターミナル画面）

以下のPythonソースを実行します。

* [pub_light.py](https://gist.github.com/yoshidaken1/e04c8b9da2b974c3228f#file-pub_light-py)

実行例を以下に示します。10秒おきにPublishを行います。光をあてたり遮ったりして、値を変化させてください。

```bash:元のターミナル画面からPythonソースで定期的にデータ送信
$ vi pub_light.py
$ sudo python pub_light.py
mosquitto_pub -t spinning/3f/brightness000 -m {"brightness": 562, "ID": "id000", "time_sensor": "2016-03-24 14:35:20"}
mosquitto_pub -t spinning/3f/brightness000 -m {"brightness": 572, "ID": "id000", "time_sensor": "2016-03-24 14:35:30"}
…
```

既に`mosquittp_sub`コマンドを実行し待受け状態になっている別のターミナル画面を確認してください。以下のようにトピックとJSON形式のメッセージが表示されていればOKです。

```bash:新たな別のターミナル画面（mosquittp_subコマンドを実行し待受け）
$ mosquitto_sub -t spinning/3f/brightness000 -v
spinning/3f/brightness000 1023    ← コマンドで送られてきたトピックおよびデータ
spinning/3f/brightness000 {"brightness": 562, "ID": "id000", "time_sensor": "2016-03-24 14:35:20"} ← トピックおよびデータが10秒おきにSubscribeされていく
spinning/3f/brightness000 {"brightness": 572, "ID": "id000", "time_sensor": "2016-03-24 14:35:30"}
…
```
## 【Appendix】センサーデータをJSON形式でテキストファイルとして保存する

光量のアナログセンサーデータをJSONデータとしてテキストファイルに保存しておくと、以後のリレーハンズオンで行われるAWSで可視化セクションで再利用することができます。以下のようにコマンドを打って保存してみてください。

```bash
$ sudo python pub_light.py >> brightness000.json
```

カレントディレクトリにファイル名`brightness000.json`でJSONデータが追記保存されます。

## 【ToDo 7.3】ラズパイ上で(A)(C)を実行し(B)に外部MQTTブローカーを使う

上記一通りの動作が確認できました。実際の運用ではMQTTブローカーにクラウドのサービスなどを用いることになりますので、時雨堂が開発している「[sango](https://sango.shiguredo.jp)」を使って試してみます。

* __(A)Pub__ `pub_light_to_cloud.py`を実行して照度データを定期的に送信
* __(B)Broker__ 時雨堂 sangoサービスの無料プランを利用
* __(C)Sub__ `mosquito sub`コマンドで照度データを受信（別ターミナル画面）

以下のPythonソースを実行します。

* [pub_light_to_cloud.py](https://gist.github.com/yoshidaken1/e04c8b9da2b974c3228f#file-pub_light_to_cloud-py)

実行する前に時雨堂「[sango](https://sango.shiguredo.jp)」でログイン登録をして下さい。ライトプランで10コネクションまで無料で使えます。登録後表示される[ダッシュボード](https://sango.shiguredo.jp/dashboard)で、ユーザー名とパスワードを確認してください。
![image](https://qiita-image-store.s3.amazonaws.com/0/4092/6d95ef55-c489-b566-84a3-935e58608967.png)
※ハンズオンで時雨堂「[sango](https://sango.shiguredo.jp)」に登録できない方は申し出てください（5名ほどなら一時的に一緒に使いましょう）。

実行例を以下に示します。15秒おきにPublishを行います。先ほどと同様に光をあてたり遮ったりして、値を変化させてください。

```bash:元のターミナル画面からPythonソースでsangoに定期的にデータ送信
$ vi pub_light_to_cloud.py
$ sudo python pub_light_to_cloud.py
mosquitto_pub -t spinning/3f/brightness000 -m {"brightness": 562, "ID": "id000", "time_sensor": "2016-03-24 14:35:20"}
mosquitto_pub -t spinning/3f/brightness000 -m {"brightness": 572, "ID": "id000", "time_sensor": "2016-03-24 14:35:30"}
…
```

別のターミナル画面で`mosquittp_sub`コマンドの実行を中断し、新たにsangoのMQTTブローカーにspinning/3f/brightness000トピックへのSubscribeを行う。
コマンド内に{…}で囲まれた文字列は以下のように{…}ごと差し替えてください。

* {account_name}はご自身のsangoアカウント（=githubアカウント）
* {password}はご自身のsangoアカウントのパスワード

新たにデータが流れてくれば正常にSubscribeできています。

```bash:新たな別のターミナル画面（mosquittp_subコマンドを実行し待受け）
$ mosquitto_sub -h lite.mqtt.shiguredo.jp -u {account_name}@github -P {password} -t {account_name}@github/spinning/3f/brightness000 -v
{account_name}@github/spinning/3f/brightness000 {"brightness": 579, "ID": "id000", "time_sensor": "2016-03-24 16:03:52"}
{account_name}@github/spinning/3f/brightness000 {"brightness": 542, "ID": "id000", "time_sensor": "2016-03-24 16:04:08"} ← トピックおよびデータが15秒おきにSubscribeされていく
…
```

# [Step 8.] 光センサーの値をSORACOM Beamを使って外部MQTTブローカーに送信する

最後に、(A)Pubと(B)Broker間を、SORACOM Beamを中継するようにします。

* __(A)Pub__ `pub_light_to_beam.py`を実行してデータを定期的に送信
* __SORACOM Beam経由で一括して安全にデータを中継__
* __(B)Broker__ 時雨堂 sangoサービスの無料プラン
* __(C)Sub__ `mosquito_sub`コマンドでデータを受信（別ターミナル画面）

SORACOM Beamは、Beamを使いたいSORACOM Airを特定のグループに設定することで適用することができます。特定のグループとは、すでにSORACOM Beam設定が済んでいるグループのことを指します。
SORACOMコンソールから所属グループを変更してみましょう。

## 【ToDo 8.1】SORACOMコンソールでグループ設定を行う

自身のPCのブラウザで[SORACOMコンソール](https://console.soracom.io/#/)を表示させ、SORACOMアカウントでログインします。
![キャプチャ02.PNG](https://qiita-image-store.s3.amazonaws.com/0/4092/0d653422-bb64-2873-a43f-764df205a6a5.png)
メールアドレス・パスワードは、ご自身のSORACOMアカウントやハンズオン指定のSORACOMアカウントを入力して「ログイン」ボタンをクリックします。

SIM管理画面が表示されるのでSIMの名前などを入力し検索して、自分のIMSIをパソコン（のエディタなど）にコピーしておいてください。
![キャプチャ03.PNG](https://qiita-image-store.s3.amazonaws.com/0/4092/1ee848f3-e577-f6d0-a081-dbcb18d0357d.png)

自分のSIMの番号を控えておいてください。一番左のチェックボックスをクリックして、「操作」プルダウンを選び、SIM詳細画面を表示させます。
![image](https://qiita-image-store.s3.amazonaws.com/0/4092/2238c8e3-a7cb-aaae-69f5-200f8c148be4.png)

SIM詳細画面からグループの欄に「MQTT」を指定して、「閉じる」をクリック
![image](https://qiita-image-store.s3.amazonaws.com/0/4092/fd595b48-f998-3a50-7f41-ecf68937be4a.png)

## 【ToDo 8.2】SORACOM Beamを用いたPythonソースによるPublishの実行

以下のPythonソースを実行します。

* [pub_light_to_beam.py](https://gist.github.com/yoshidaken1/e04c8b9da2b974c3228f#file-pub_light_to_beam-py)

実行例を以下に示します。これもまた15秒おきにPublishを行います。先ほどと同様に光をあてたり遮ったりして、値を変化させてください。

```bash:元のターミナル画面からPythonソースでsangoに定期的にデータ送信
$ vi pub_light_to_cloud.py
$ $ sudo python  pub_light_to_beam.py
mosquitto_pub -t {account_name}@github/spinning/3f/brightness000 -m {"brightness": 560, "ID": "id000", "time_sensor": "2016-03-25 02:44:16"} -h beam.soracom.io
mosquitto_pub -t {account_name}@github/spinning/3f/brightness000 -m {"brightness": 536, "ID": "id000", "time_sensor": "2016-03-25 02:44:32"} -h beam.soracom.io
…
```
別のターミナル画面で新たにsangoのMQTTブローカーにspinning/3f/brightness000トピックへのSubscribeを行う。
コマンド内に{…}で囲まれた文字列は以下のように{…}ごと差し替えてください。

* {account_name}はご自身のsangoアカウント（=githubアカウント）
* {password}はご自身のsangoアカウントのパスワード
* {imsi}はハンズオンで使っているSIMのIMSI番号

新たにデータが流れてくれば正常にSubscribeできています。

```bash:新たな別のターミナル画面（mosquittp_subコマンドを実行し待受け）
$ mosquitto_sub -h lite.mqtt.shiguredo.jp -u {account_name}@github -P {password} -t yoshidaken1@github/spinning/3f/brightness000/{imsi} -v
yoshidaken1@github/spinning/3f/brightness000/{imsi} {"brightness": 583, "ID": "id000", "time_sensor": "2016-03-25 02:48:52"}
yoshidaken1@github/spinning/3f/brightness000/{imsi} {"brightness": 576, "ID": "id000", "time_sensor": "2016-03-25 02:49:08"}
```

今回の場合、MQTTグループに属したSIMはすべてbeam.soracom.io経由でPublishされています。MQTTコネクションが１つにまとまりコネクション数の節約にもなるのですが、Publish元のセンサーデータはどのラズパイから送信してきたか特定できません。
そのためMQTTグループのSORACOM Beamでは、トピックの末尾にIMSI番号を付与する指定が可能になっています。
![image](https://qiita-image-store.s3.amazonaws.com/0/4092/0b039885-c5f9-9559-09b5-3d94567073b6.png)

時間があれば、新たに自分でSORACOMグループを作成し（MQTT_00など。00は自分の番号）、上図に基づいたSORACOM Beam - MQTT 設定を行って、Publish/Subscribeしてみてください。