#はじめに
こんにちは
RHEMS技研荒木です。
無人島に漂流しすぎて寝不足です。島の名前はI/O島にしました。
備忘録がてらIoTCoreを用いたセンサデータの収集についてまとめました。
2020/03/21現在の情報です。1~2ヶ月のうちに情報が古くなると思いますのでご注意ください。
センサデータを収集するためのスタンダードな構成だと思います。
CloudFunctionはデータ到達確認のため置いています。 ここでは解説しません。
#IoTCore
これはAWSでいうIoTCoreと似たサービスになります。そりゃそうなんですけど。
大きく違う点はレジストリ単位でトピックが決まっている等点になります。AWSではエンドポイントは固定でトピックはデバイスごとに選択できるのですが、GCPではレジストリに属しているデバイスはすべて同じトピックへの送信になります。
設定をしていきます。
まずプロジェクトを作成します。
今回はqiita-akijin-test
という名前にしました。
組織や場所は環境によります。
問題なければ作成してしまいます。
次はIoTCoreを有効にします。
左のナビゲーションメニューよりIoTCoreを探します。
初回では画像のような画面になるので有効にする
を選択してAPIを有効にします。
有効になると下画像の用になりますので上のレジストリを作成
を選択。
すると、レジストリの設定が出るので設定をしていきます。
今回は画像の通りの設定をしました。
MQTTでしか通信する予定がないのでHTTPのチェックは外しておきましょう。
次にデバイスの登録をするのですが先に証明書関係をクリアしておきましょう。
$ openssl ecparam -genkey -name prime256v1 -noout -out ec_private.pem
$ openssl ec -in ec_private.pem -pubout -out ec_public.pem
$ openssl ec -in ec_private.pem -noout -text
上2つのコマンドでサーバー側とデバイス側の証明書を作成、3つ目でデバイスに書き込む用の証明書を書き出しています。
書き出すと画像のように出るのでpriv
の方を後ほど使うのでコピーしておきます。
また、先頭が00
だった場合は00
を抜かしてコピーします。
ではデバイスの登録をしていきます。
左のメニューよりデバイス
を選択してデバイスを作成
を選択します。
デバイスの設定は画像の通りです。
証明書は公開鍵の形式
をES256
にしてec_public.pem
の中身をペーストします。
各種設定が終わったら作成してしまいましょう。
これでIoTCoreの設定は終了になります。
#Pub/Sub
これはIoTCoreに届いたリクエストを他のGCPのサービスに割り振るために使用します。基本的にIoTCoreを使用する際はPub/Subは必ず使用します。
ここでの設定は特にないです。
IoTCoreのレジストリからPub/Subのページに飛びます。先程作成したトピックで作られているかを確認します。
#BigQuery
先にBigQueryのテーブルを作成します。
左メニューよりBigQuery
を選択。プロフェクト名がリソースに追加されているので選択して右側にあるデータセットを作成
を選択します。
作成したらテーブルを作成します。今回は画像のように設定しました。
作成するとリソースに画像のようなツリーができていることを確認します。
テーブルが作成されていることも確認しましょう。
これでBigQueryの設定は終わりです。
#Dataflow
これはサービスとサービスとの間に入れるものになります。テンプレートが予め用意されているので簡単に使用することができます。
使用するテンプレートはPub/Subの指定したトピックに届いたデータをBigQueryに追加してくれるものになります。
今回では、test-akijin
に届いたメッセージをBigQueryへと送ります。
##Storage
AWSで言うところのS3がこれに当たります。
Dataflowはデータを処理するのにバッファリングをします。なのでバッファを作成する必要があり、Storageにバッファを作成するようになっています。
左のメニューよりStorage-ブラウザを選択。
バケットの作成
よりバケットを作成していきます。設定は画像のとおりです。
バケット内にフォルダを一つ作成しておきます。このフォルダがDataflowで使用するバッファになります。
これでバッファは用意されました。
Dataflowの設定に戻ります。
Pub/SubのメニューよりBIBQUERYにエクスポート
を選択。
するとDataflowの設定に飛ぶので画像のように設定します。
リージョンエンドポイント
はDataflowの元であるComputeEngineが置かれるリージョンを指定します。なるべく近いリージョンを選ばないと他のサービスとの地理的距離が大きくなってしまうので料金がかさむ要因になります。
BigQuery output table
では書き込むBigQuery先を選択します。<プロジェクト名>:<データセット名>.<テーブル名>
の形式で入力するので、qiita-test-akijin:test.secret_word
となります。
一時的なロケーション
には先程作成したStorageのバッファの場所を入力します。
設定し終えたらDataflowの設定は終わりです。
GCP側での設定も終了です。
#デバイスの設定
デバイスはESP32を使い、ArduinoIDEで進めていきます。他のエディタでも同様に進めることができると思います。
IoTCoreでの設定の通り、通信にはHTTPではなくMQTTで通信をしていきます。
通信用のコード・ライブラリも用意されているものを使用します。
https://github.com/GoogleCloudPlatform/google-cloud-iot-arduino
をクローンして通常のライブラリを入れる要領で追加します。
使いしたらサンプル例より、Esp32-lwmqtt
を開きます。
開くとinoファイルとヘッダーファイルが2つが開かれます。
ciotc_config.h
がWiFiやGCP,MQTTの設定用ファイルになりますので編集していきます。
17行目以下のところを編集します。
// Wifi network details.
const char *ssid = "SSID";
const char *password = "PASSWORD";
// Cloud iot details.
const char *project_id = "qiita-test-akijin";
const char *location = "asia-east1";
const char *registry_id = "akijin-test";
const char *device_id = "test1";
WiFiの設定は飛ばします。
GCPの設定は変数名を参考にして書き換えます。
42行目以下は証明書を貼り付けていきます。
// is probably wrong with your key.
const char *private_key_str =
"22:d7:a2:63:05:b0:3d:df:53:71:e5:bc:53:cf:0a:"
"81:00:88:f3:4f:48:4e:82:3b:37:c6:e7:86:e9:02:"
"fa:e0";
esp32-mqtt.h
の中身も少し書きえます。
setupWifiが名前の通りWiFiの設定なのですが、中身を以下のように書き換えます。
書き換えることによってライブラリのインクルードが必要になるので追加・継承までします。
#include <Client.h>
#include <WiFiManager.h>
#include <WiFiClientSecure.h>
WiFiClientSecure client;
WiFiManager wifiManager;
void setupWifi() {
Serial.println("Starting wifi");
Serial.println(wifiManager.autoConnect());
IPAddress ipadr = WiFi.localIP();
Serial.println(ipadr);
Serial.println(WiFi.SSID());
configTime(0, 0, ntp_primary, ntp_secondary);
Serial.println("Waiting on time sync...");
while (time(nullptr) < 1510644967) {
delay(10);
}
}
こうすることによってWiFiの設定を書き込まずともPCやスマホで設定ができるようになりました。詳細は僕の他の記事やautoconnect
について検索してください。
最後にEsp32-lwmqtt.ino
を編集してきます。
loopを以下のように変更します。
void loop() {
mqtt->loop();
delay(10); // <- fixes some issues with WiFi stability
if (!mqttClient->connected()) {
connect();
}
publishTelemetry("{\"Hello\":\"World\"}");
delay(10000);
}
publishTelemetry();
の引数が送信するデータになります。
BigQueryは追加するデータをJsonで指定するので"{\"Hello\":\"World\"}"
を引数にします。
10秒に一回送信され、BigQueryのDataflowで設定したテーブルのHello
の列に文字列のWorld
が追加されます。
Dataflowの方でバッファリングするので10秒に一回追加されるわけではないので注意が必要です。
BigQueryに戻り、プレビューで追加されていることを確認します。
無事に追加されているはずです。
これでセンサデータの収集は終わりです。
#料金
これが一番気になるところです。AWSと比較してみます。
AWSはIoTCoreとDynamoDBを使用したとして比較します。
台数は1台で1時間に12回(5分おき)の送信で1ヶ月での運用と仮定して考えます。
また15分おきにPingを送ります。
メッセージ数122431= 8640が一ヶ月のメッセージ数になります。
一ヶ月は44640分です。
リージョンはいずれも東京です。
##AWS
まずAWSです。
###IoTCore
https://aws.amazon.com/jp/iot-core/pricing/?nc=sn&loc=4ここを参考にします。
0.096/1000000*44640 = 0.0042...が接続しているための料金
1.20/1000000*86400 = 0.10368 がメッセージ送信のための料金
0.18/1000000864002 = 0.031...がルールの料金(DynamoDBへのインサート)
合計して0.01388USDがIoTCoreの一ヶ月あたりの料金です。
###DynamoDB
https://aws.amazon.com/jp/dynamodb/pricing/on-demand/より、書き込みだけを想定します。
100 万単位あたり 1.4269USD
なので、1.4269/1000000*8640 = 0.0123...がDynamoDBの料金になります。
各サービスの合計で0.1511USDが一ヶ月あたりの料金になります。
##GCP
###IoTCore
https://cloud.google.com/iot/pricing?hl=ja#overviewの例から計算します。
42430*1024 =294.9120kB
250MBまで無料なのでIoTCoreでは料金はかからないみたいです。
###Pub/Sub
送受信するデータが10GBに満たないので無料になります。
###Dataflow
DataflowではCompute Engineという他のサービスで料金計算になります。
ここのサイトを参考にします。
今回はストリーミング処理なので1時間あたり約0.35$かかります。したがって、0.352431=260.6$となります。
これが一番やばい。
これはテンプレートを使用した際ストリーミング処理になってしまうので1台で運用する際はバッチ処理が適切だと思います。
そうした際はテンプレートを使用しないのでJavaもしくはPythonでコードを書くことになります。
###BigQuery
料金計算が複雑なため公式のサイトを御覧ください。
https://cloud.google.com/bigquery/pricing?hl=ja#on_demand_pricing
合計で260.6~USDになります。
Dataflowが主に占めています。台数が少ないならCloudFunctionとかで代用したほうがかなりコストが削減できそう。
#さいごに
プログラムもほぼ書かないでデータの収集までできました。
このぐらいなら初学者の方でも簡単にできそうなのでお試しください。
追記(2020/03/27)
コストカットができたので続編でまとめています。
https://qiita.com/Akijin/items/8ce14a6b1d4ffe468a74