Help us understand the problem. What is going on with this article?

mockmockで簡単なIoTシステムを開発してみよう

この記事はmockmockアドベントカレンダー24日目の記事です。
クリスマスイブの今日はmockmockを使って簡単なIoTシステムを開発します。

ただし、mockmockのアドバンスドオプションの一つである「DataRecorder」を使って、
デバイスから送信されたデータの確認・クラウドへの再送を行い、スマートに開発していく点に注目です。

開発するシステム

システム名

システム名は「Suwarin」とします。
某子供向け番組のキャラクターをリスペクトして名付けました。

仕様

自分自身の着席状況をSlackへ通知するIoTシステムです。
自分が着席したら「着席しました」、離席したら「離席しました」とメッセージを送信します。

システム構成

今回、デバイスにはM5StickCを使用します。クラウドはAWSでIoT Core, DynamoDB(Stream), Lambdaを使用します。

Untitled_mockmock_-_Cacoo.png

肝心のセンサーですがたまたま手元にあった「Seed社 Grove-Ultrasonic Ranger」を使用します。

Grove_-_超音波レンジャー_-_Seeedウィキ(日本語版).png

検出した距離が近いときは「着席中」、遠いとき(未検出時の値)のときは「離席中」と判定します。

[デバイスの開発・テスト]M5StickC→mockmockにデータを送る

まずはM5StickCでプログラムを起動して、mockmockにデータを送ります。

mockmock DataRecorderの設定

エンドポイントの作成

mockmockのログインページからログイン後、「データレコーダー」→「データセット作成」の順でクリックしてください。

IoT開発を加速する仮想デバイス作成サービス___mockmock.png

「データセット新規作成」フォームが表示されるので、任意の名称と説明を入力後、「登録」をクリックしてください。

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f36303939362f31343437653835642d323661372d343030342d376566622d3439346236613464373630392e706e67.png

「データセット一覧」に作成したデータセットが表示されたら「詳細」をクリックしてください。
IoT開発を加速する仮想デバイス作成サービス___mockmock.png

「エンドポイント」の「MQTTS」の内容をメモしておいてください。後ほど使用します。

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f36303939362f38383863316432312d353135662d343233362d323434642d6563306338373630636263352e706e67.png

証明書の作成

「データレコーダー」→「証明書:新規作成」の順でクリックしてください。
IoT開発を加速する仮想デバイス作成サービス___mockmock_と_Slack___random___fusic___1_個の新しいアイテム.png

証明書ファイルのダウンロードがはじまりますので任意の場所に保存してください。後ほど使用します。
作成した証明書が表示されたら「有効化」をクリックしてください。

IoT開発を加速する仮想デバイス作成サービス___mockmock.png

デバイス側の実装

以下ソースコードをビルドして、M5StickCへ書き込んでください。
{{ }}で囲まれた文字列はmockmockの設定やご使用のWi-Fiアクセスポイントに合わせて書き換える必要があります。
Root CAはこちらを参照。

suwarin
#include <M5StickC.h>
#include "Ultrasonic.h"
#include "cloud.h"

#define FILTER_RATE 0.95
Ultrasonic ultrasonic(33);
float filtered_value = 0;

void setup_lcd() {
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextSize(1);
  M5.Lcd.setRotation(1);
  M5.Lcd.setCursor(0, 0);  
}

void setup_serial() {
  Serial.begin(9600);  
}

void setup() {
  M5.begin();

  setup_lcd();
  setup_serial();
  setup_mqtt();
}

float rc_filter(float raw_value) {
  filtered_value = (1 - FILTER_RATE) * raw_value + FILTER_RATE * filtered_value;
  return filtered_value;
}

void loop() {
  mqtt_connect();
  for(int i = 0 ; i < 10 ; i++) {
    M5.Lcd.setCursor(0, 30);
    M5.Lcd.printf("%d cm     ", ultrasonic.MeasureInCentimeters());
    M5.Lcd.println("");
    delay(100);
  }
  mqtt_publish_measure(rc_filter(ultrasonic.MeasureInCentimeters()));
}
cloud.h
#define WIFI_SSID "{{Wi-FiのSSID}}"
#define WIFI_PASSWORD "{{Wi-Fiのパスワード}}"

#define CLOUD_ENDPOINT "<実際のエンドポイントに置き換えてください>.iot.ap-northeast-1.amazonaws.com"
#define CLOUD_PORT 8883
#define CLOUD_TOPIC "{{DataRecorderが表示するtopic名に置き換えてください}}"

// {{実際の証明書に置き換えてください}}
#define ROOT_CA "-----BEGIN CERTIFICATE-----\n"\
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"\
"xxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"\
"-----END CERTIFICATE-----\n"
#define CERTIFICATE "-----BEGIN CERTIFICATE-----\n"\
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"\
"xxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"\
"-----END CERTIFICATE-----\n"
#define PRIVATE_KEY "-----BEGIN RSA PRIVATE KEY-----\n"\
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"\
"xxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"\
"-----END RSA PRIVATE KEY-----\n"\

void setup_wifi();
void setup_mqtt();
void mqtt_connect();
void mqtt_publish_measure(int centimeters);
cloud
#include <M5StickC.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include "cloud.h"

WiFiClientSecure https_client;
PubSubClient mqtt_client(https_client);

char pub_message[256];

void mqtt_callback (char* topic, byte* payload, unsigned int length) {
}

void setup_mqtt() {
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    M5.Lcd.printf(".");
  }
  M5.Lcd.println("");
  M5.Lcd.println("WiFi connected");
  M5.Lcd.printf("IP address: ");
  M5.Lcd.println(WiFi.localIP());

  https_client.setCACert(ROOT_CA);
  https_client.setCertificate(CERTIFICATE);
  https_client.setPrivateKey(PRIVATE_KEY);
  mqtt_client.setServer(CLOUD_ENDPOINT, CLOUD_PORT);
  mqtt_client.setCallback(mqtt_callback);
}

void mqtt_connect() {
  if (!mqtt_client.connected()) {
    while (!mqtt_client.connected()) {
      String clientId = "1";
      if (!(mqtt_client.connect(clientId.c_str()))) {
        Serial.println(mqtt_client.state());
        delay(5000);
      }
    }
    M5.Lcd.println("MQTT Connected!");
  }
  mqtt_client.loop();
}

void mqtt_publish_measure(int centimeters) {
  memset(pub_message, 0x0, sizeof(pub_message));
  sprintf(pub_message, "{\"centimeters\":%d}", centimeters);
  mqtt_client.publish(CLOUD_TOPIC, pub_message);
  M5.Lcd.println("MQTT Published!");
}

テスト

M5StickCの電源をONしてください。
次に「データレコーダー」→「証明書:新規作成」の順でクリックすると、デバイスから送信されたデータを確認できます。

IoT開発を加速する仮想デバイス作成サービス___mockmock.png

[クラウドの開発・テスト]mockmock→AWS IoTにデータを送る

AWSの設定

以下の記事の「IoT Coreの証明書を作成する」〜「AWS IoT Coreのエンドポイントの確認」までの手順を実施ください。
mockmockでAWS IoT Coreにデータを送るプロジェクトを作成する

mockmockの設定

「プロジェクト一覧」→「プロジェクト作成」の順にクリックしてください。
IoT開発を加速する仮想デバイス作成サービス___mockmock.png

フォームに以下の通り入力して、「登録」をクリックしてください。
「送信先ホスト」や「各種証明書ファイル」は先の手順で確認した内容・ファイルに変更ください。

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f36303939362f65363064386339662d396530362d363864332d376664642d3061356564663435356233322e706e67.png

「リプレイヤー」を作成します。
「リプレイヤーの右側の+ボタン」をクリック後、フォームを以下の通り入力して、「登録」をクリックしてください。
IoT開発を加速する仮想デバイス作成サービス___mockmock.png

「mockグループ」を作成します。
「mockグループの右側の+ボタン」をクリック後、フォームを以下の通り入力して、「登録」をクリックしてください。
IoT開発を加速する仮想デバイス作成サービス___mockmock.png

「送信設定」を作成します。
「mock管理」→「送信設定編集」の順にクリックしてください。
IoT開発を加速する仮想デバイス作成サービス___mockmock.png

以下の通り入力して「登録」をクリックしてください。
「Topic」はデータレコーダーで使用していたエンドポイントに合わせておくと、後々楽に作業を進められます。
IoT開発を加速する仮想デバイス作成サービス___mockmock.png

テスト

「mockグループ:suwarin」→「mock作成」の順にクリックしてください。
IoT開発を加速する仮想デバイス作成サービス___mockmock.png

以下の通り入力して「登録」をクリックしてください。
IoT開発を加速する仮想デバイス作成サービス___mockmock.png

表示されたmockの「操作」→「起動」をクリックします。
IoT開発を加速する仮想デバイス作成サービス___mockmock.png

AWS IoT Coreの「テスト」をクリックし、以下の通り入力して「トピックへのサブスクライブ」をクリックしてください。
AWS_IoT.png

mockが起動すると、データレコーダ内のデータが送信されます。

AWS_IoT.png

[クラウドの開発・テスト]DynamoDB, Lambdaの動作確認をする

この手順に関しては本記事のメインの部分から外れるので、簡単に紹介します。

まずAWS IoT Coreのルールを以下の通り作成します。
AWS_IoT.png

アクションは以下の通りDynamoDBへ値を書き込むこととします。
AWS_IoT.png

DynamoDBのコンソールにてストリームを有効にしておきます。
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f36303939362f32643032323139652d636163312d343239652d356139392d6436613563656432363461372e706e67.png

DynamoDBのストリームをトリガーとするLambdaを作成します。

lambda_function.rb
require 'json'
require 'slack-notifier'

def lambda_handler(event:, context:)
  event['Records'].each do |record|
    next unless record['eventName'] == 'MODIFY'

    old = record['dynamodb']['OldImage']['payload']['M']['centimeters']['N'].to_f
    new = record['dynamodb']['NewImage']['payload']['M']['centimeters']['N'].to_f
    next if sit_down?(old) == sit_down?(new)

    notifier = Slack::Notifier.new('<WEBHOOK_URLに置き換えてください>')
    if sit_down?(new)
      notifier.ping('着席しました')
    else
      notifier.ping('離席しました')
    end
  end
end

def sit_down?(centimeters)
  centimeters.to_f < 100.0
end

以上の設定・実装を終えた後、mockmockデータを送信してみます。
数値が100を超えたタイミング、100を下回ったタイミングでSlackに通知が飛ぶことが確認できます。

Slack___nicole-dev___fusic.png

[システム統合テスト]M5StickC→AWS IoTにデータを送る

M5StickCのソースコードを変更し、証明書およびエンドポイントをAWS IoT Coreのものに変更すれば
無事IoTシステムが完成です。

まとめ

mockmockのDataRecorderを使うことで、クラウドなしでデバイスの動作確認、デバイスなしでクラウドの動作確認を行った上で、システム全体をテストすることができました。

IoT開発においてデバイス・クラウドのテストが不十分な状態で、システム統合テストに突入すると不具合の原因調査に膨大な工数がかかるケースが多いです。

mockmockを活用し段階を踏んでテストすると、早い段階で不具合を検出し原因の特定に要する時間を短縮化できるため、開発工数を大幅に削減することが可能です。ぜひお試しください!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした