概要
Azure IoT実践編としてRaspberry Piに温湿度センサーを付け、Azure IoT Hubへ温度と湿度を送信、PowerBIで可視化する構成で作ってみます。
デバイスからAzure IoT Hubへ直接情報を送ってもいいのですが、実際のところではAzure IoT Edgeを経由することが多い?と思うので、自宅のWindows PCをAzure IoT Edgeとして利用しAzure IoT Hubへ情報を流しています(データの加工などは行っていません)。
※Azure IoT Edgeでは、デバイスからの情報の不要部分の削除や集約などを行うことができ、必要なデータだけを送ることで帯域幅コスト削減などが期待できる。
※Raspberry Piに温湿度センサーを付ける、情報を読み取る方法は解説しませんのでそこは他のサイトを参照ください。
構成図と説明
①Raspberry Piから温度・湿度の値をWindows PC(Azure IoT Edge for Linux on WIndows)へ流す
②Windows PCからAzure IoT Hubへそのまま情報を受け渡す(3秒間隔)
③Azure IoT Hubで情報を受信
④Stream AnalyticsでAzure IoT Hubからデータを読み込み、ADLS(Azure Data Lake Storage Gen2)へファイルを出力
⑤DatabricksでADLSのファイルを読み込んで分単位の温度・湿度平均を算出
⑥PowerBIレポートで分毎の温度・湿度変化をグラフ化
環境
- デバイス:Raspberry Pi 4 Model B Rev 1.2(Raspbian 10)
- IoT Edge(Windows PC):Windows10 Pro(21H1)
- IoT Hub:Edgeエージェント Ver1.4、Edgeハブ Ver1.4
構築手順
1.Azureサービスの作成
1.1 Azure IoT Hub
①Azure PortalからIoT Hubを検索
②以下の設定で作成(記載以外はデフォルト)
- リソースグループ:任意
- IoT Hub名:任意
- リージョン:Japan East
- 価格とスケールティア:F1:Free レベル
1.2 Azure Stream Analytics
①Azure PortalからStream Analytics ジョブを検索
②以下の設定で作成(記載以外はデフォルト)
- リソースグループ:Azure IoT Hubを作成したリソースグループ
- 名前:任意
- リージョン:Japan East
- ストリーミングユニット:1
1.3 Azure Data Lake Storage Gen2(ADLS)
①Azure Portalからストレージ アカウントを検索
②以下の設定で作成(記載以外はデフォルト)
- リソースグループ:Azure IoT Hubを作成したリソースグループ
- ストレージ アカウント名:任意
- リージョン:Japan East
- 冗長性:ローカル冗長ストレージ(LRS)
- 階層型名前空間を有効にする:チェック
1.4 Azure Databricks
①Azure PortalからAzure Databricksを検索
②以下の設定で作成(記載以外はデフォルト)
- リソースグループ:Azure IoT Hubを作成したリソースグループ
- ワークスペース名:任意
- リージョン:Japan East
- 価格レベル:試用版
③クラスタ作成(お金があまりかからないように低スペックで作成)
2.Azure IoT Hub設定
①IoT Edge デバイスの追加
デバイス IDは任意のものを指定し、その他はデフォルト設定
プライマリ接続文字列は後で使うので保管しておいてください。
IoT Edgeに届いたメッセージをIoT Hubに転送するよう設定する
↓
↓ 名前:allMessagesToHub、値:FROM /messages/* INTO $upstream を設定
②デバイスの追加
デバイス IDは任意、親デバイスに①で作成したIoT Edgeを指定し、その他はデフォルト設定
こちらも同様にプライマリ接続文字列は後で使うので保管しておく。
3.Raspberry Pi設定①
①以下のコマンドでRaspberry PiにAzure IoT SDKをインストール
pip3 install azure-iot-device
pip3 install azure-iot-hub
②Gitリポジトリもクローン
git clone https://github.com/Azure/azure-iot-sdk-python.git
4.Windows PC設定
4.1 Azure IoT Edge for Linux on Windowsをインストール
参考サイト:対称キーを使用して IoT Edge for Linux on Windows デバイスを作成してプロビジョニングする
①PowerShellスクリプト実行ポリシー設定
Set-ExecutionPolicy -ExecutionPolicy AllSigned -Force
②IoT Edge for Linux on Windows をダウンロード
$msiPath = $([io.Path]::Combine($env:TEMP, 'AzureIoTEdge.msi'))
$ProgressPreference = 'SilentlyContinue'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest "https://aka.ms/AzEFLOWMSI-CR-X64" -OutFile $msiPath
③IoT Edge for Linux on Windows をインストール
Start-Process -Wait msiexec -ArgumentList "/i","$([io.Path]::Combine($env:TEMP, 'AzureIoTEdge.msi'))","/qn"
④IoT Edge for Linux on Windows のデプロイ
ライセンス条項はYで同意。Optional diagnostic dataはRを入力。
「Deployment successful」が表示されれば成功。
Deploy-Eflow
⑤デバイスをプロビジョニング
PASTE_DEVICE_CONNECTION_STRING_HERE
には2-①で保管していたプライマリ接続文字列を設定
Provision-EflowVm -provisioningType ManualConnectionString -devConnString "PASTE_DEVICE_CONNECTION_STRING_HERE"
⑥IoT Edge仮想マシンにログインしモジュールの状態を確認
Connect-EflowVm
sudo iotedge list
edgeAgent、edgeHubともにrunningになっていればOK(edgeHubが出てこなければしばらく待って再度確認)。
IoT HubのIoT Edgeデバイスもrunningになる。
4.2 証明書の作成
4.1でとりあえずIoT HubとIoT Edgeが繋がりましたが、デバイスからIoT Edgeに繋げるのに証明書が必要になるためデモ用証明書(30日間のみ使用可能)を作成します。
参考サイト:IoT Edge デバイスの機能をテストするためのデモ用の証明書を作成する
①OpenSSL のインストール
参考サイト参照
②証明書作成スクリプト実行のための準備
git clone https://github.com/Azure/iotedge.git
mkdir wrkdir
cd .\wrkdir\
cp ..\iotedge\tools\CACertificates\*.cnf .
cp ..\iotedge\tools\CACertificates\ca-certs.ps1 .
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser
. .\ca-certs.ps1
③ルート CA 証明書の作成
New-CACertsCertChain rsa
④エッジ CA 証明書の作成
※ CA cert name
は任意ではあるが、IoT HubのデバイスIDと同じにしない方がよいらしい。
今回は「iotEdgeMyPCCACert」にした。
New-CACertsEdgeDevice "<CA cert name>"
4.3 証明書をIoT Edge仮想マシンに配置
参考サイト:透過的なゲートウェイとして機能するように IoT Edge デバイスを構成する
①IoT Edge仮想マシンに証明書配置用ディレクトリを作成
Connect-EflowVm
cd ~
mkdir certs
cd certs
mkdir certs
mkdir private
exit
②証明書をIoT Edge仮想マシンにコピー
path
は4.2-②で作成したwrkdirのパス。CA cert name
は4.2-④で決めた名前。
# Copy the IoT Edge device CA certificates
Copy-EflowVMFile -fromFile <path>\certs\iot-edge-device-ca-<CA cert name>-full-chain.cert.pem -toFile /home/iotedge-user/certs/certs/iot-edge-device-ca-<CA cert name>-full-chain.cert.pem -pushFile
Copy-EflowVMFile -fromFile <path>\private\iot-edge-device-ca-<CA cert name>.key.pem -toFile /home/iotedge-user/certs/private/iot-edge-device-ca-<CA cert name>.key.pem -pushFile
# Copy the root CA certificate
Copy-EflowVMFile -fromFile <path>\certs\azure-iot-test-only.root.ca.cert.pem -toFile /home/iotedge-user/certs/certs/azure-iot-test-only.root.ca.cert.pem -pushFile
③証明書へのアクセス権付与
参考サイトの設定だとうまくいかなかったので、以下のようにした。
Invoke-EflowVmCommand "sudo chmod 755 -R /home/iotedge-user/"
④IoT Edgeの構成ファイルに証明書を設定する
既存の構成ファイルの内容はEdge用になっていない場合があるためリネームして使われないようにし、Edge用テンプレートを構成ファイルにする。
Connect-EflowVm
#構成ファイルの場所に移動
cd /etc/aziot
#既存の構成ファイルをリネーム
sudo mv config.toml config.toml.bk
#Edge用テンプレートを構成ファイルにする
sudo cp config.toml.edge.template config.toml
構成ファイルを開いて、以下のように編集する。
sudo vim config.toml
・provisioning
部分のコメントを外し、connection_string
を2-①で保管していたプライマリ接続文字列を設定
・trust_bundle_cert
部分のコメントを外し、ルートCA証明書のパスを設定
・edge_ca
部分のコメントを外し、デバイスCA証明書とデバイスCA秘密キーのパスを設定
構成ファイルの変更を適用。
sudo iotedge config apply
モジュールの状態がrunningになっていることをsudo iotedge list
コマンドで確認。
runningになっていない場合はsudo iotedge check
コマンドを実行しエラー内容を確認。
4.4 IoT Edge仮想マシンのポート開放
今回はMQTTプロトコルで通信するため8883ポートだけ開放。
# Open MQTT port
Invoke-EflowVmCommand "sudo iptables -A INPUT -p tcp --dport 8883 -j ACCEPT"
# Save the iptables rules
Invoke-EflowVmCommand "sudo iptables-save | sudo tee /etc/systemd/scripts/ip4save"
4.5 Windows PCのポート開放とポート転送設定
デバイスからIoT Edge仮想マシンに通信するにはWindows PCを経由する必要があるため、デバイス⇒Windows PC⇒IoT Edge仮想マシンという流れになる。
Windows PCはデバイスからのアクセスをIoT Edge仮想マシンに流す必要があるためその設定を入れる。
netsh interface portproxy add v4tov4 listenport=8883 listenaddr=<Windows PCのIPアドレス> connectport=8883 connectaddress=<IoT Edge仮想マシンのIPアドレス>
IoT Edge仮想マシンのIPアドレス
は以下のコマンドで確認できる。
Get-EflowVmAddr
5.Raspberry Pi設定②
①IoT Edge仮想マシンに配置したルート CA 証明書をデバイス側にも配置
②IoT Edgeとの通信プログラム作成
3-②でクローン下azure-iot-sdk-python内のサンプルプログラムを少し書き換えて作ります。
#! /bin/bash
echo "Run simple_send_message.py"
#引数:接続文字列
export IOTHUB_DEVICE_CONNECTION_STRING="<2-②で保管したプライマリ接続文字列>;GatewayHostName=<IoT Edge仮想マシン名>"
#引数:ルートCA証明書パス
export IOTHUB_CA_CERTIFICATE_PATH="/home/pi/Desktop/Azure IoT/azure-iot-test-only.root.ca.cert.pem.iotEdgeMyPC"
python3 simple_send_message.py
read -p "Press [Enter] key to resume."
import osimport time
import asyncio
import Adafruit_DHT as DHT
from azure.iot.device.aio import IoTHubDeviceClient
async def main():
# IoT Edge -> Hub Connection Ver
conn_str = os.getenv("IOTHUB_DEVICE_CONNECTION_STRING")
ca_path_str = os.getenv("IOTHUB_CA_CERTIFICATE_PATH")
certfile = open(ca_path_str)
root_ca_cert = certfile.read()
#MQTT(port:8883)
device_client = IoTHubDeviceClient.create_from_connection_string(connection_string=conn_str, server_verification_cert=root_ca_cert)
# Connect the device client.
await device_client.connect()
while True:
# Send a single message
print("Sending message...")
SENSOR_TYPE = DHT.DHT22
DHT_GPIO = 4
h,t = DHT.read_retry(SENSOR_TYPE, DHT_GPIO)
send_message = "{\"temprature\":" + "{0:0.1f}".format(t) + ", \"humidity\":" + "{0:0.1f}".format(h) + "}"
print(send_message)
await device_client.send_message(send_message)
print("Message successfully sent!")
time.sleep(3)
# Finally, shut down the client
await device_client.shutdown()
if __name__ == "__main__": asyncio.run(main())
simple_send_message.shの<IoT Edge仮想マシン名>
はGet-EflowVmName
コマンドで取得できます。
Get-EflowVmName
simple_send_message.pyの7~11行目では引数を取得して、証明書を読み込んでいます。
# IoT Edge -> Hub Connection Ver
conn_str = os.getenv("IOTHUB_DEVICE_CONNECTION_STRING")
ca_path_str = os.getenv("IOTHUB_CA_CERTIFICATE_PATH")
certfile = open(ca_path_str)
root_ca_cert = certfile.read()
simple_send_message.pyの13~17行目ではIoT Edge仮想マシンに接続しています。
#MQTT(port:8883)
device_client = IoTHubDeviceClient.create_from_connection_string(connection_string=conn_str, server_verification_cert=root_ca_cert)
# Connect the device client.
await device_client.connect()
simple_send_message.pyの19~30行目は、3秒おきに温湿度センサーの情報を取得し、温度と湿度をIoT Edge仮想マシンに送り続ける内容になっています。
h,t = DHT.read_retry(SENSOR_TYPE, DHT_GPIO)
:温湿度センサーから温度、湿度を取得
send_message = "{\"temprature\":" + "{0:0.1f}".format(t) + ", \"humidity\":" + "{0:0.1f}".format(h) + "}"
:JSON形式のメッセージを作成
await device_client.send_message(send_message)
:IoT Edge仮想マシンにメッセージを送信
while True:
# Send a single message
print("Sending message...")
SENSOR_TYPE = DHT.DHT22
DHT_GPIO = 4
h,t = DHT.read_retry(SENSOR_TYPE, DHT_GPIO)
send_message = "{\"temprature\":" + "{0:0.1f}".format(t) + ", \"humidity\":" + "{0:0.1f}".format(h) + "}"
print(send_message)
await device_client.send_message(send_message)
print("Message successfully sent!")
time.sleep(3)
③Host設定
②で設定したIoT Edge仮想マシン名
の名前解決ができないのでとりあえずHostsに記載
IPはWindows PCに投げるのでWindows PCのものにする。
sudo vim /etc/hosts
④simple_send_message.shの実行
simple_send_message.shを実行し正常に送信できていることを確認。
6.Azure IoT Explorer
送信はできているとしてIoT Hubまでメッセージがに届いているかをAzure IoT Explorerで確認してみる。
①インストール
参考サイト参照:Azure IoT エクスプローラーをインストールして使用する
②IoT Hubを登録
IoT Hubの共有アクセスポリシーの接続文字列を使うのでコピーしておく
IoT ExplorerのConnection_stringに接続文字列を貼り付けてSave
③メッセージ監視
②で登録したIoT Hubを選択
デバイスを選択
TelemetryでStartをクリックし、下の欄にメッセージ内容が表示されればデバイス⇒IoT Edge⇒IoT Hubへと正常にメッセージが流れてきたことを確認できる。
※simple_send_message.shを実行し、メッセージ送信中の状態であること
7.Azure Stream Analytics設定
- 入力のエイリアス:任意
- サブスクリプションからIoT Hubを選択する:チェック
- サブスクリプション:自身のサブスクリプション
- IoT Hub:1.1で作成したIoT Hub
- コンシューマーグループ:$Default
- 共有アクセスポリシー名:iothubowner
- 出力のエイリアス:任意
- サブスクリプションからBlob StorageまたはADLS Gen2を選択する:チェック
- サブスクリプション:自身のサブスクリプション
- ストレージアカウント:1.3で作成したADLS
- コンテナー:既存のものを使用にチェックし、1.3で作成したコンテナを選択
③クエリの設定
入力のエイリアス名
と出力のエイリアス名
には①②で決めた名前を設定
クエリのテストを実行すると結果が表示されればOK(simple_send_message.shは実行中であること)
8.Azure Data Lake Storage Gen2(ADLS)確認
9.Azure Databricksコード実行
DatabricksにADLSのiotコンテナーをマウントしておき以下のようなコードで、JSON読み込み⇒3秒おきのデータを分単位の平均値に変換したiot_avgテーブルを作成
マウント方法は参考サイトなどを参考
10.PowerBIレポート作成
Databricksにアクセスしてiot_avgテーブルを読み込んでグラフ化
↑サーバホスト名
とHTTPパス
にはDatabricksのクラスタのServer Hostname
とHTTP Path
を設定
サインインして接続
iot_avgテーブルを読み込んで任意のグラフを作成
最後まで読んでいただきありがとうございました。
Azure IoT Edge for Linux on Windowsを経由させるというだけで結構四苦八苦したので備忘も兼ねて残しておきます。