開発部の上條です。
今回は Azure IoT Hub と Excel を用いた簡単な IoTシステムに挑戦します。
システム概要
今回構築する IoTシステムについて大まかに説明すると、センサーが送信したデータを Azure Data Explorer に保持、その情報を Excel 上に出力・グラフ等で可視化させるといったものです。
この話題は若干出遅れてしまった感がありますが、多くはセンサー付きの Raspberry Pi など単独でネット接続が可能な機器から Azure IoT Hub にデータを送信するものが多いですが、弊社らしくセンサー付き Beacon と受信機(Android)を使用してチャレンジします。
また、Azure IoT Hub のデータの可視化というと Power BI が選ばれがちですが、どれだけ複雑なシステムの構築であっても結局エンドユーザ(お客様)は Excel がお好き、ということから Excel の機能で可視化することにしました。
データの流れを図で表すと以下のようになります。
では、それぞれにフォーカスしていきましょう。
センサー
全ての始まりとなるセンサーには、弊社製品のセンサー付き iBeacon、BLEAD-TSH※(ブリード・ティーエスエイチ)を利用します。BLEAD-TSH は温度センサーと加速度センサーが内蔵されており、それらのセンサーが検知した情報を BLE電波に乗せて発信することが可能です。今回は 1,000ms 間隔で送信するように設定します。
※BLEAD-TSH は現在販売を停止させていただいておりますが、ご興味のある方は個別にお問い合わせください。
Android アプリ
センサーが発信したデータは Android 端末にインストールしたアプリを使って受信し、Azure IoT Hub に送信するようにします。
今回のアプリは Android Studio 4.1.1 にて Java 8 で実装しました。画面は下記の通り BLE 電波のスキャンを開始・停止させるボタンがあるだけのシンプルなものです。
Azure IoT Hub との通信を可能にさせるためのポイントとして、IoT Hub SDK を活用します。
参考:Azure IoT Hub SDK | Microsoft Docs
(https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-devguide-sdks)
Azure IoT Hub SDK は maven でも公開されており、build.gradle ファイルの dependencies句に以下のコードを加筆します。
implementation (‘com.microsoft.azure.sdk.iot:iot-device-client:1.32.0’)
そして Azure IoT Hub SDK を使用しての接続は以下のようなソースとなります。
/** AzureIogHubへの接続文字列 */
private static final String CONNECTION_STR = "HostName=[azureIoTのパス]; DeviceId=Android01;SharedAccessKey=[azureに登録さている主キー];";
/** AzureIotHubへの接続クライアント */
private DeviceClient deviceClient = null;
~ ~ ~ 中 略 ~ ~ ~
try {
this.deviceClient = new DeviceClient(CONNECTION_STR, IotHubClientProtocol.HTTPS);
this.deviceClient.setOption("SetSASTokenExpiryTime", 2400L);
//CallBackの登録(ログの出力をしているだけなのでなくてもよい)
this.deviceClient.registerConnectionStatusChangeCallback(new IotHubConnectionStatusChangeCallback() {
@Override
public void execute(IotHubConnectionStatus status, IotHubConnectionStatusChangeReason statusChangeReason, Throwable throwable, Object callbackContext) {
Log.d(TAG, "StatusChanged : " + status.toString());
}
}, null);
//IotHubに接続
this.deviceClient.open();
}catch (Exception ex){
Log.e(MainActivity.TAG, "IoTHubClient生成、接続時のエラー", ex);
return;
}
基本的には接続文字列とプロトコルを引数に生成して、open メソッドを呼び出すだけとなりますが、ここでは確認用にコールバックの設定を行っています。
接続文字列(CONNECTION_STR)はこの後 Azure IoT Hub の設定で説明します。
接続した後は送信のコードを紹介します。
try {
//インスタンスをJson文字列にする
String json = new Gson().toJson(tsh);
//Messageの生成
Message message = new Message(json);
message.setContentTypeFinal("application/json");
message.setMessageId(java.util.UUID.randomUUID().toString());
//Message(Event)の送信
this.deviceClient.sendEventAsync(message, new IotHubEventCallback() {
@Override
public void execute(IotHubStatusCode responseStatus, Object callbackContext) {
Log.d(TAG, "IotHub ResultStatus:" + responseStatus.toString());
if(responseStatus != IotHubStatusCode.OK && responseStatus != IotHubStatusCode.OK_EMPTY){
Log.w(TAG, "IoTHubからエラーが返されました State:" + responseStatus.toString());
}
}
}, message);
}catch (Exception ex) {
Log.e(MainActivity.TAG, "IoTHubへのデータ送信時のエラー", ex);
}
JSON 文字列を引数に Message インスタンスを生成して sendEventAsync メソッドを呼び出すだけですが、接続時と同じく確認用にコールバックを登録して Azure からの応答をコンソールに出力しています。
(変数 tsh は BLEAD TSH から送信された識別子、センサー値などを格納した POJO のクラスインスタンス)(Message クラスは com.microsoft.azure.sdk.iot.device.Message をインポートしてください、コード補完で適当なものを選んでビルドが通らないとか初心者にありがち・・・)
また、BLE 電波の検知処理については説明を省略しますが、android.bluetooth.le.BluetoothLeScanner の機能を利用します。これを使うには位置情報の権限許可が必要なのですが、Android 10 以降と 9 以前で必要となる権限が異なるので注意が必要です。
Azure IoT Hub
Android から送信された情報は IoT Hub を経由して Azure Data Explorer に集約・保持させます。
まずは Azure IoT Hub から作成していきましょう。
基本的には以下のページに記載の内容を基に進めていく形で問題ありません。
参考:Azure Portal を使用して IoT Hub を作成する | Microsoft Docs
(https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-create-through-portal)
Azure Portal にログインして、Azure IoT Hub を作成します。オプション等は必要に応じて選択してください。
IoT Hub が作成出来たら、続いてデバイス登録を行います。
デバイスが作成出来たら、IoT デバイスの一覧から追加したデバイスを選択し、「プライマリ接続文字列」の値をコピーします。これを先述した Android アプリの実装に組み込むことで IoT Hub と Android 端末の間で通信が可能になります。
Azure Data Explorer
IoT Hub に送られた情報は Data Explorer でまとめて保持させることにします。
引き続き、Azure Portal から Azure Data Explorer を作成しましょう。
Azure ポータルにログインし、Azure Data Explorer クラスターを検索し「作成ボタンを」押します。
基本のページの必須項目のみ入力し、その他オプションについては、今回はデフォルトのままで「確認と作成」ボタンを押して作成しました。
続いて、Azure Data Explorer クラスター内にデータベースを作成しましょう。
作成した Azure Data Explorer のページを開き、「データベースの追加」ボタンを押します(場所は左メニューの概要か、左メニューのデータベースのページ内にあります)。
ここも名前以外はデフォルト値で作成しました。
データベースの作成が完了したら次はテーブルを作成しましょう。
ここからは GUI はなくクエリを実行していきます。
まずは、先ほど作成したデータベースを開き、左メニューのクエリを選択し、クエリの実行ができる画面に遷移しましょう。
ここでは Kusto(KQL) という大量データの取り扱いに長けたクエリ言語を使用します。
.create table BLEAD_TSH_LOG (
enqueuedtime : datetime,
deviceId : string,
bleadSerialNo: string,
temperature: real,
humidity: real,
accelerationX : int,
accelerationY : int,
accelerationZ : int
);
これを実行すると、BLEAD_TSH_LOG というテーブルが作られます。
カラムは BLEAD-TSH が送信している情報の他に受信日時(enqueuedtime)、デバイスID(deviceId、AzureIoTHub 側の IoT デバイス ID)を用意しています。
次に IoT Hub からのデータと Data Explorer の先ほど作ったデータベースとのマッピング情報を作成します。
.create table BLEAD_TSH_LOG ingestion json mapping
'BLEAD_TSH_LOG_MAPPING'
'['
'{"column":"deviceId","Properties":{"Path":"$.iothub-connection-device-id"},"datatype":"string"},'
'{"column":"enqueuedtime","Properties":{"Path":"$.iothub-enqueuedtime"},"datatype":"datetime"},'
'{"column":"bleadSerialNo","Properties":{"Path":"$.bleadSerialNo"},"datatype":"string"},'
'{"column":"humidity","Properties":{"Path":"$.humidity"},"datatype":"real"},'
'{"column":"temperature","Properties":{"Path":"$.temperature"},"datatype":"real"},'
'{"column":"accelerationX","Properties":{"Path":"$.accelerationX"},"datatype":"int"},'
'{"column":"accelerationY","Properties":{"Path":"$.accelerationY"},"datatype":"int"},'
'{"column":"accelerationZ","Properties":{"Path":"$.accelerationZ"},"datatype":"int"},'
']'
;
これを実行すると、BLEAD_TSH_LOG_MAPPING という名前のマッピング情報が作られます。
今回はテーブル側も IoT Hub 側も同じプロパティ名にしていますが、column はテーブル側、properties は IoT Hub 側のプロパティを指定していますので差異があればここを修正します。
最後にデータ接続を作成しましょう。
データベースの左メニューにあるデータインジェストを選択し、データ接続の追加をクリックします。
まずは上半分です。
- 接続の種類:IoT Hub
- データ接続名:任意
- サブスクリプション:任意
- IoT Hub:作成した IoT Hub を選択
- 共有アクセスポリシー:iothubowner(IoT Hub の方で作らなくてもデフォルトで作られているはず)
- コンシューマーグループ:$Default(IoT Hub の方で作らなくてもデフォルトで作られているはず)
- イベント システムのプロパティ:iothub-enqueuetimeとiothub-connection-device-id を選択
下側は以下のように入力して、作成ボタンを押します。
- テーブル名:BLEAD_TSH_LOG(上記で作成)
- データ形式:JSON
- マッピング名:BLEAD_TSH_LOG_MAPPING(上記で作成)
余談ですが、今回一番苦労したのはこのあたりの設定になります。
データ接続とマッピングとテーブルの 3つの設定がかみ合って初めてうまくいくものなのですが、うまくいかなかった時のエラーの確認方法がわからないから始まり、エラーを確認出来ても最低限のものでその理由がわからなかったのと、IoT にあがったデータが Data Explorer のテーブルに到達するまで 5分近くのラグがあることなど、知らないと設定が間違っているのではないかと思ってしまうことが多かったです。
以下にエラーや設定の確認方法などおまけとして付けておきます。
何かのお役にたてば幸いです。
マッピングの確認 |
.show table BLEAD_TSH_LOG ingestion mappings; |
登録に間違いがあった場合は以下で削除して登録しなおす |
.drop table BLEAD_TSH_LOG ingestion json mapping “BLEAD_TSH_LOG_MAPPING”; |
エラーの確認 |
.show ingestion failures; |
データの確認 |
BLEAD_TSH_LOG; |
または、 |
BLEAD_TSH_LOG | count; |
データの削除 |
.drop extents from BLEAD_TSH_LOG; |
Excel
ここまでで、センサーから発信された情報が Azure Data Explorer に保存されるようになりました。
あとは、この情報を Excel に出力できれば目標達成です。
Azure Data Explorer のデータを Excel で取得する方法ですが、「データ」リボン内にある「データの取得」から「Azureから」→「Azure Data Explorer から」の順に選択しましょう。
すると以下のダイアログが表示されるので、Azure Data Explorer で設定した情報を入力していきます。
具体的には、「クラスター」に先ほど作成した Azure Data Explorer クラスターの概要にある URL(URI項目に記載のもの)、「データベース」に Azure Data Explorer で作成したデータベース名、「テーブル名またはクエリ」に先ほど作成したテーブル名(私の例では、BLEAD_TSH_LOG)を入れれば OK です。
上記の内容を入力して OK を押すと認証画面へのアクセスが求められるので、自身のアカウントでログインしましょう。
接続に問題がなければ取得したデータが表示されたダイアログが表示されるので「読込」ボタンを押すとシートにデータが表示されます。
あとはシートをもとにデータの加工などを行い、グラフを作成すれば完成です。
終わりに
今回は簡単・手軽にというわけではなく IoT の一端を担う BLE Beacon を製造する弊社らしい記事とさせていただきました。
実際の案件となると、センサー+Wi-Fi モジュールで直接インターネットにデータを上げる場合と比べると、BLE の低消費電力を活かした電池駆動で設置場所を選ばず、単価も比較的安いため、モニタリング対象が多い場合など BLE Beacon +受信機の組み合わせが優れているのではないかと思います。