ラズパイとAWS IoT連携 (Pythonで温度情報をクラウド送信)

# はじめに

例えばラズパイを使用して、センサーの情報を取得し、クラウドにデータをアップロードし活用したいですよね！

今回はその手始めとして、**ラズパイとAWS IoT**を連携してみたいと思います。
今後、DBへの保存や、グラフの表示などもまとめていきたいと思います！


# 使用機材

安価に以下を用意して試してみました。

- Raspberry Pi Zero WH
- ブレッドボード(165408010E)
- デジタル温度センサADT7310 DIP化モジュール[MDK001]
- ジャンパーワイヤ

# ラズパイで温度情報を取得

Myブログで恐縮ですが、**ラズパイで温度センサーから温度を取得する**記事をまとめましたので参考にしてください。

[ラズパイで温度を取得(デジタル温度センサADT7310)](https://chigusa-web.com/blog/%E3%83%A9%E3%82%BA%E3%83%91%E3%82%A4%E3%81%A7%E6%B8%A9%E5%BA%A6%E3%82%92%E5%8F%96%E5%BE%97%E3%83%87%E3%82%B8%E3%82%BF%E3%83%AB%E6%B8%A9%E5%BA%A6%E3%82%BB%E3%83%B3%E3%82%B5adt7310/)

# AWS IoTの設定

AWSアカウントを取得後、**AWS IoT**の設定を行います。
結構AWS IoTの設定が多く、私は最初戸惑いました:sweat:
一度設定をしてみると、流れを把握できると思います。


## AWS IoT

AWS IoTについては、**AWS ドキュメント**に記載があります。

[AWS IoT とは](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/what-is-aws-iot.html)

> AWS IoT では、インターネットに接続されたデバイス (センサー、アクチュエーター、組み込みマイクロコントローラー、スマート家電など) と AWS クラウドとのセキュアな双方向通信が可能になります。これにより、複数のデバイスからテレメトリデータを収集し、保存して、分析できます。また、これらのデバイスをユーザーが各自の電話やタブレットから制御できるようにするアプリケーションを作成することもできます。

まずはAWS IoT コンソールを開きます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/2bcbb6c5-5f01-bce6-a5db-e7d2796ce209.png" width="50%" />

リージョンは東京にしました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/d85acf3c-5b9b-eac8-991b-0d251e281bb8.png" width="50%" />

## デバイスの登録

最初の画面で「モノの登録」をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/1c91395e-f328-789e-614f-e0f3a7c29142.png" width="50%" />

「単一のモノを作成する」をクリックします。
![2019-05-06_11h37_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/963d6949-1958-b592-1b0f-ed41afd8a42b.png)

任意で名前を入力し、次へ進みます。
![screencapture-ap-northeast-1-console-aws-amazon-iot-home-2019-05-06-11_42_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/a4892b14-c5f3-cb5a-6926-af0e07e446cb.png)

「証明書の作成」をクリックします。
![2019-05-06_11h46_24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/6b4f2ca8-96d4-99ac-3283-dbd5247c68c8.png)

パブリックキーとプライベートキー、証明書をダウンロードします。
また、「有効化」をクリックします。
このページを閉じると、**パブリックキーとプライベートキーが取得できなくなる**ので注意が必要です。
その後、「ポリシーをアタッチ」をクリックします。
![2019-05-06_11h48_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/726891d7-4643-9326-3b16-ac47839770c8.png)


ルート認証機関 (CA) は以下のURLからダウンロードします。
RSA 2048 ビットキー: Amazon ルート CA 1を選択しました。
**AmazonRootCA1.pem**という名前で保存します。

[AWS IoTのルートCAダウンロード](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/managing-device-certs.html)

「モノの登録」をクリックします。
![2019-05-06_12h24_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/a173f69c-387d-6f3b-b100-fdc0d43343b9.png)

「安全性→ポリシー」をクリックし、「ポリシーの作成」をクリックします。
![2019-05-06_12h26_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/3c8d252c-4f8b-764e-3377-d7e089818f08.png)

ポリシーの「名前」を任意で入力します。
アクションに「iot:\*」と入力し、リソース ARNに「\*」と入力します。
「許可」にチェックを入れ、「作成」をクリックします。
(許可範囲が広いので、本番稼働時は適宜設定をしてください)
![2019-05-06-12_43_19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/896863fa-260f-d808-eab7-868d7a594d52.png)

管理をクリックし、先ほど作成したモノをクリックします。
「セキュリティ」をクリックし証明書をクリックします。
![2019-05-06_12h47_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/4c703385-faa0-468f-4662-f485f8fd35d7.png)

「アクション→ポリシーのアタッチ」をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/5c527e00-77b8-c042-a326-96f8733f6006.png" width="40%" />

作成したポリシーをチェックし、「アタッチ」をクリックします。
![2019-05-06_12h49_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/68f29996-04c3-ae14-f9be-854eeeb3f085.png)

以上で、AWS IoTの設定が完了しました。

# ラズパイ側のコーディング

続いてラズパイ側の実装を行います。
以降、ラズパイ上での作業になります。

## ラズパイで温度情報を取得

Pythonで温度を取得する処理を作成しました。
(詳しくはブログ記事を参照)

```python:get_temp.py
import time
import spidev
import sys

spi_ch = 0

try:
    spi = spidev.SpiDev()
    spi.open(0,spi_ch)
    spi.mode = 0x03
    spi.max_speed_hz = 1000000
    time.sleep(0.01)
    spi.xfer2([0xff, 0xff, 0xff, 0xff])

    while True:

        spi.xfer2([0x54])
        time.sleep(0.5)
        adc = spi.xfer2([0xff,0xff]) 
        temp = (adc[0] << 8) | adc[1] 
        temp = temp >> 3  
        if(temp >= 4096):  
                temp = temp - 8192

        print(temp / 16.0)
        time.sleep(1)

except KeyboardInterrupt:
    spi.close()
    sys.exit(0)
```

## AWS IoTに送信

この処理をもとに、温度をAWS IoTに送信したいと思います。
デバイスからは443ポートで、TLSクライアント認証によるMQTT通信をします。

PythonでMQTTの通信処理を書いてもよいのですが、今回は**aws-iot-device-sdk-python**を使用しました。
https://github.com/aws/aws-iot-device-sdk-python

ラズパイにインストールします。
自分のラズパイにpipもgitも入ってなかったので、今回はzipからインストールしました。

```shell
mkdir AWSIoTPythonSDK
cd AWSIoTPythonSDK
wget https://s3.amazonaws.com/aws-iot-device-sdk-python/aws-iot-device-sdk-python-latest.zip
unzip AWSIoTPythonSDK
sudo python3 setup.py install
```

ファイルの構成は以下です。
AWS IoTの設定時にダウンロードしたキーなども配置します。
(xxxは各自のファイル名で読み替えてください)

/
├ aws-test.py
└ cert/
　　　├ AmazonRootCA1.pem
　　　├ xxx-private.pem.key
　　　└ xxx-certificate.pem.crt

実装は以下になりました。
まずは単純にデータの送信を試します。

エンドポイントURLは、**「AWS IoT→管理→モノ→操作」**から確認できます。
configureCredentialsの引数は、設定時にダウンロードしたファイルのパスを指定します。

```python:aws-test.py
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
import json

# 初期化
myMQTTClient = AWSIoTMQTTClient("raspi-zero")

# MQTTクライアントの設定
myMQTTClient.configureEndpoint("エンドポイントURL", 443)
myMQTTClient.configureCredentials("/xxx/xxx/cert/AmazonRootCA1.pem", "/xxx/xxx/cert/xxx-private.pem.key", "/xxx/xxx/cert/xxx-certificate.pem.crt")
myMQTTClient.configureOfflinePublishQueueing(-1)
myMQTTClient.configureDrainingFrequency(2)
myMQTTClient.configureConnectDisconnectTimeout(10)
myMQTTClient.configureMQTTOperationTimeout(5)

# Connect to AWS IoT endpoint and publish a message
myMQTTClient.connect()
print ("Connected to AWS IoT")
myMQTTClient.publish("awsiot/test", json.dumps({"test": "test message!"}), 0)
myMQTTClient.disconnect()
```

## 動作確認

AWS IoTのコンソールから「テスト」をクリックし、トピックのサブスクリプションに「awsiot/test」と入力しサブスクライブします。
![2019-05-06_14h05_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/0beb9fb9-25e7-5e91-044e-c553774c7d05.png)

作成したPythonを実行します。

```shell
python3 aws-test.py
```

JSON形式でデータが受信できることを確認します。
![2019-05-06_14h08_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/4a892218-20f0-efcd-c483-ea6844a00198.png)

## 温度情報を定期的に送信

温度取得処理とAWS IoT送信処理とくっつけて、1分毎にデータを送信する処理を作成しました。
(ちょっとやっつけ感ありますが:sweat_smile:)

```python:aws-send-temp.py
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
import json
import time
import spidev
import sys

# 初期化
myMQTTClient = AWSIoTMQTTClient("raspi-zero")

# MQTTクライアントの設定
myMQTTClient.configureEndpoint("エンドポイントURL", 443)
myMQTTClient.configureCredentials("/xxx/xxx/cert/AmazonRootCA1.pem", "/xxx/xxx/cert/xxx-private.pem.key", "/xxx/xxx/cert/xxx-certificate.pem.crt")
myMQTTClient.configureOfflinePublishQueueing(-1)
myMQTTClient.configureDrainingFrequency(2)
myMQTTClient.configureConnectDisconnectTimeout(10)
myMQTTClient.configureMQTTOperationTimeout(5)

# Connect to AWS IoT endpoint and publish a message
myMQTTClient.connect()
print ("Connected to AWS IoT")

# 温度情報取得・送信
spi_ch = 0

try:
    spi = spidev.SpiDev()
    spi.open(0,spi_ch)
    spi.mode = 0x03
    spi.max_speed_hz = 1000000
    time.sleep(0.01)
    spi.xfer2([0xff, 0xff, 0xff, 0xff])

    while True:

        spi.xfer2([0x54])
        time.sleep(0.5)
        adc = spi.xfer2([0xff,0xff]) 
        temp = (adc[0] << 8) | adc[1] 
        temp = temp >> 3  
        if(temp >= 4096):  
                temp = temp - 8192

        # 温度情報送信
        print(temp / 16.0)
        myMQTTClient.publish("awsiot/test", json.dumps({"temperature": (temp / 16.0)}), 0)
        # 一分待機
        time.sleep(60)

except KeyboardInterrupt:
    spi.close()
    myMQTTClient.disconnect()
    sys.exit(0)
```

実行してみると、1分毎くらいにデータが送信できました！
![2019-05-06_14h15_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408237/f4adcfcd-3951-ed92-a0c6-2f9cba4ee603.png)

# 今後について

まずはAWS IoTと連携できました。
次は例えばDBにデータを保存したり、グラフ化したりできますね！
またの機会にまとめたいです:grinning: