LoginSignup
59

More than 5 years have passed since last update.

Raspi(デバイス)とAWSIoT(クラウド)間でMQTTを使ってメッセージを送受信する

Last updated at Posted at 2017-09-26

はじめに

AWSのIoTのサービスといえばAWSIoTですよね!
つい先日大阪で行われてた「AWS Cloud Roadshow 2017」の中で、AWS Greengrassが東京リージョンに上陸したことが発表されました!
ということでですね、デバイスとクラウド間のやり取りの基本的な部分をAWSIoTを利用して実装していこうと思います

※前半部分にはsakura.io ✕ AWS IoTハンズオン [AWS編]の内容を投稿者の方の許可をいただいた上で、使わせていただいております

[0] 主な流れ

AWSIoTとラズパイ間の通信をMQTTでつなぎ、送受信する手順を紹介します
おおまかな流れはこんな感じです

  1. AWSIoTで証明書を発行する
  2. 発行した証明書を用いてデバイス(Raspi)とAWSIoTを接続する
  3. メッセージを送受信する
  4. (おまけ)Lambda経由でDynamoDBにデータをPUTする

[1] AWS IoTの設定(Thing)

AWS IoTは概念が少々複雑ですが、ある程度把握しておかないとこれ以降の設定内容が理解できないと思います。AWS Black Belt Online Seminar 2016 AWS IoTで学習すると良いでしょう。

  1. 証明書Thingポリシーを紐付ける
  2. 証明書をデバイスにインストールする
  3. 流れてきたトピックに対するアクション(連携先等)をルールで定義する

ポリシーの作成

AWS IoTコンソールを開く

スクリーンショット 2017-09-18 00.46.54.png

リージョンが「Asia Pacific (Tokyo)」でない場合は変更する

4bd6b0f2-3593-3b10-1839-62f3c2f13173.png

[Get started]をクリックする(下図は表示されない場合もある)

スクリーンショット 2017-09-11 17.23.40.png

ポリシーを作成する

スクリーンショット 2017-09-18 01.26.53.png

下表の通り入力して[Create]をクリックする

項目 入力内容
Name AllPubSub
Action iot:*
Resource ARN *
Effect Allow

スクリーンショット 2017-09-18 01.12.18.png

Thingと証明書の作成

Thingを作成する

スクリーンショット 2017-09-18 00.49.51.png

device01を入力して[Create thing]をクリックする

awsiot_test_6.PNG

作成したThingをクリックする

awsiot_test_7.PNG

証明書を作成する

スクリーンショット 2017-09-18 00.55.14.png

クライアント証明書/クライアント秘密鍵/ルート証明書の3種類をダウンロードする(ルート証明書のみ、右クリック -> リンク先を別名で保存)

[Activate](押し忘れ注意!) -> [Attach a policy]の順にクリックする

スクリーンショット 2017-09-18 00.57.16.png

[AllPubSub]を選択して[Done]をクリックする

スクリーンショット 2017-09-18 01.18.49.png

戻る

スクリーンショット 2017-09-18 01.24.11.png

エンドポイントを確認する

歯車マークをクリックするとエンドポイントが表示されるので控えておく

スクリーンショット 2017-09-18 01.38.48.png

[2] RaspiとAWSIoTを接続する

前章で発行した証明書を使って、RaspiとAWSIoTを接続します

使用したRaspiの情報は以下のとおり

  • Raspbian GNU/Linux 8.0 (jessie)
  • Linux raspberrypi 4.4.34

MQTTの実装

MQTTの実装には「mosquitto」を利用します。下記コマンドを実行することでAWSIoTとの通信を行います

  • Pub mosquitto_pubコマンドで光量データを送信
  • Sub mosquitto_subコマンドで光量データを受信

mosquittoのインストール

Raspberry Piのデフォルトリポジトリのmosquitto-clientsはバージョンが古く、TLSのエラーが発生するため最新のmosquitto-clientsをインストールします

$ wget  http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key
$ sudo apt-key add mosquitto-repo.gpg.key
$ wget http://repo.mosquitto.org/debian/mosquitto-stretch.list
$ sudo cp mosquitto-stretch.list /etc/apt/sources.list.d/

$ sudo apt-get update
$ sudo reboot

$ sudo apt-get install  mosquitto-clients
$ mosquitto_sub --help |grep version
 mosquitto_sub version 1.5 running on libmosquitto 1.5.0.

2018/05/28時点で最新のバージョンは1.5.0です

先ほど発行した証明書(クライアント証明書/クライアント秘密鍵/ルート証明書の3種類)をRasberry Piにコピーします
※この際コピーミスを防ぐために、SFTPなどで確実にコピーするようにしてください。scpでホームディレクトリにファイルを置く例

$ scp file-name pi@IP_ADDRESS:~

AWSIoT MQTTクライアントを開く

[Test]を選択する

awsiot_menu.PNG

[Subscription topic]に「$aws/things/device01/test」と入力する

awsiot_test_1.PNG

[Subscribe to topic]をクリックする

awsiot_test_2.PNG

下記のような画面になると思います

awsiot_test_3.PNG

ラズパイからAWSIoTへのメッセージ送信(publish)

例)トピック「$aws/things/device01/test」に対して文字列「test message」を送信します

$ mosquitto_pub --cafile [ルート証明書] --cert [クライアント証明書] --key [クライアント秘密鍵] -h [AWSIoTのエンドポイント] -p 8883 -q 1 -t '$aws/things/device01/test' -i device01 --tls-version tlsv1.2 -m '{"test": "message"}' -d

例)トピック「$aws/things/device01/test」に対してJSONファイル「data_sample.json」を送信します

data_sample.json
{
  "data": [
    {
      "d1": "0000",
      "d2": "9999",
      "d3": "0003",
      "d4": "0004",
      "d5": "0005",
      "d6": "0006",
      "d7": "0007",
      "d8": "0008",
      "d9": "0009",
      "d10": "0010",
      "serial": "00000001",
      "time": "201706010100"
    }
  ]
}
$ mosquitto_pub --cafile [ルート証明書] --cert [クライアント証明書] --key [クライアント秘密鍵] -h [AWSIoTのエンドポイント] -p 8883 -q 1 -t '$aws/things/device01/test' -i device01 --tls-version tlsv1.2 -f data_sample.json -d

問題なく送信が完了すれば、先ほど開いたテスト画面にデバイスからのメッセージが表示されます
↓こんな感じ(data_sample.jsonを送信した際の結果)

awsiot_test_5.PNG

AWSIoTからのメッセージ受信(subscribe)

例)トピック「$aws/things/device01/test」に対するメッセージを待ち受けます

$ mosquitto_sub --cafile [ルート証明書] --cert [クライアント証明書] --key [クライアント秘密鍵] -h [AWSIoTのエンドポイント] -p 8883 -q 1 -t '$aws/things/device01/test' -i device01 --tls-version tlsv1.2

上記コマンドでsubscribeしている状態で、テスト画面からメッセージをデバイスへ送信します

awsiot_test_4.PNG

問題なければデバイス側のターミナルに、こんなメッセージが表示されます

{
  "message": "Hello from AWS IoT console"
}

Device shadowを更新する

AWSIoTにはすでに予約されているトピックがあり「$aws/things/device01/shadow/update」に対してメッセージを送信するとshadowを更新することができます

shadow_sample.json
{
  "state":
    {
      "desired":
        {
          "status_data": [
            {
              "status1": "1101",
              "status2": "1202",
              "status3": "1303",
              "status4": "1404",
              "status5": "1005",
              "status6": "1006"
            }
          ]
        }
    }
}
$ mosquitto_pub --cafile [ルート証明書] --cert [クライアント証明書] --key [クライアント秘密鍵] -h [AWSIoTのエンドポイント] -p 8883 -q 1 -t '$aws/things/device01/shadow/update' -i device01 --tls-version tlsv1.2 -f shadow_sample.json -d

[3]Lambda経由でDynamoDBにデータをPUTする(おまけ)

前章でデバイスからAWSIoTにメッセージを送信することができるようになりましたので、デバイスからJSONのデータを送信し、それをDynamoDBに格納してみます

簡単な流れとしては
1. AWSIoTのルールを設定し、特定のトピックにメッセージが送信されたらLambdaをキックする
2. Lambdaが受け取ったデータを加工しDynamoDBにPUTする

送信するデータは前章で作成した「data_sample.json」を利用します

Lambdaの作成

関数名「IoT-Lambda-DynamoDB」というLambda関数を作成していきます
今回はRuntimeをNode.js6.10でLambdaを作成しています

Policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": "dynamodb:PutItem",
            "Resource": "arn:aws:dynamodb:ap-northeast-1:xxxxxxxxxx:table/iot-data-lambda"
        }
    ]
}

※DynamoDBにPUTする部分のARNはご利用されているAWSのアカウントIDに書き換えてください

Code(Node.js)

const AWS = require("aws-sdk");
const dynamoDB = new AWS.DynamoDB.DocumentClient({
    region: "ap-northeast-1"
});

exports.handler = (event, context, callback) => {
    const item = event["data"][0];
    item["deviceID"] = event["deviceID"];
    const nowTime = Date.now();
    item["time"] = String(nowTime);

    const params = {
        TableName: "iot-data-lambda",
        Item: item
    };

    dynamoDB.put(params).promise();
};

DynamoDBの作成

LambdaがPUTするDynamoDBを作成します

DynamoDBの情報

項目 入力内容
TableName iot-data-lambda
Primary partition key deviceID (String)
Primary sort key time (String)

AWSIoTルールの作成

  1. AWSIoTコンソール画面左メニューからルール画面に移動し、画面右上の「create」をクリックしてルール作成画面に移動する
  2. 「Name」に任意の文字列を入力する
  3. 「Attribute」「Topic filter」に下記の内容を入力する
項目 入力内容
Attribute *,topic(3) AS deviceID
Topic filter $aws/things/+/data

「topic(3) AS deviceID」と書いておくことで、トピックの3番目をdeviceIDとしてデータの中に含ませて次のActionに渡します
今回の場合はトピックの「+」に入る文字列が、Lambdaに渡されるeventの中にdeviceIDが含まれるようになります

awsiot_test_8.PNG

4. [Set one or more actions]の「Add action」をクリックし、Lambdaを選択、画面下部の[Configure action]をクリック

awsiot_test_9.PNG

awsiot_test_10.PNG

5. 先ほど作成したLambda関数を選択し[Add action]をクリック

awsiot_test_11.PNG

6. 最後に[Create rule]をクリック

これで「IoT_Lambda_DynamoDB」というルールが作成されました
デバイスからトピック「$aws/things/+/data」(+にはdeviceIDとなる文字列を入れる)にメッセージが送信されたときに、Lambdaにデータが渡され、加工してDynamoDBに格納します

実際に実行してみる

デバイスからデータを送信する

$ mosquitto_pub --cafile [ルート証明書] --cert [クライアント証明書] --key [クライアント秘密鍵] -h [AWSIoTのエンドポイント] -p 8883 -q 1 -t '$aws/things/device01/data' -i device01 --tls-version tlsv1.2 -f data_sample.json -d

問題なく処理が実行されればDynamoDBにデータがPUTされる

awsiot_test_12.PNG

さいごに

AWSIoTで発行した証明書ベースでメッセージの送受信ができるようになりました
今回は証明書の発行、デバイスへの証明書のコピーなどすべて手作業で行いましたが、デバイスが複数台になってくるとこんなことしれいられないので、このあたりを自動化するのが必要になってくるなと実感しましたね
そこらへんの自動化を実現してくれたすばらしいお方から資料をいただいたので、試していこうと思います
もし許可をいただいたら記事にまとめようと思いますー

ではまた!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
59