この記事の目的
独自のMicrosoft Azure IoT Edge(以下IoT Edge)のモジュールをビルドし、Armadillo-IoT G3(以下Armadillo-IoT)上で動作させます。
前提条件
-
Azureへの登録が完了し、ポータルをすぐに利用できる状態にあることをご確認ください。
-
Azure CLIを利用します。右のウェブサイトに従い、インストール及びログインを完了させてください。 Windows での Azure CLI のインストール
-
次の記事の内容を理解する必要があります。 Azure IoT Edgeとは | Microsoft Docs
-
VSCodeの拡張機能を利用してモジュールを作成/ビルド/デプロイします。VSCodeを利用できる状態にしてください。
IoT Edgeの準備
モジュールを動作させるために、IoT Edgeを利用する準備を行います。
以下の手順に従って操作してください。
-
左のペインから、全てのサービスをクリックし、その中からIoT Hubを選択してください。(画面上部のフィルターと表記されたテキストボックスより検索が行えます。)
-
左上の「追加」をクリックします。
-
IoT Hub Nameを設定します。英数字とハイフンが利用できますが、英数字で始まり英数字で終わる名前にする必要があります。
-
Size and scaleへ移動し、Pricing and scale tierからF1: Free tierを選択します。
-
入力内容を確認し、createをクリックします。
-
先ほど作成したIoT Hubをクリックし、内部左のペインからIoT Edgeを選択してください。
-
左上のAdd an IoT Edge deviceをクリックします。
-
有効なDevice IDを入力し、Saveをクリックします。
-
作成されたIoT Edge deviceを選択し、上から4番目のConnection string (primary key)をコピーします。何らかの方法でメモすることをお勧めします。
Armadillo-IoTへのIoT Edgeの導入
モジュールをArmadillo-IoT上にデプロイする前に、Armadillo-IoTへのIoT Edgeの導入が必要です。
以下のテキストをターミナルにペーストすることで、全てのインストールが完了します。
ただし、rootでのログインが前提です。
# Install moby-engine
curl -L https://aka.ms/moby-engine-armhf-latest -o moby_engine.deb && dpkg -i ./moby_engine.deb
# Install moby-cli
curl -L https://aka.ms/moby-cli-armhf-latest -o moby_cli.deb && dpkg -i ./moby_cli.deb
# Install libiothsm-std
curl -L https://aka.ms/libiothsm-std-linux-armhf-latest -o libiothsm-std.deb && dpkg -i ./libiothsm-std.deb
# Install IoT Edge Security Daemon
curl -L https://aka.ms/iotedged-linux-armhf-latest -o iotedge.deb && dpkg -i ./iotedge.deb
apt install -f
その後、/etc/iotedge/config.yaml
をエディタで開き、provisioningのセクションのコメントを解除し、先ほどコピーしたConnection string (primary key)をペーストします。
...
provisioning:
source: "manual"
device_connection_string: "ここにペースト"
...
その後、デーモンを再起動します。
# systemctl restart iotedge
VSCodeへのAzure IoT Edge拡張機能のインストール及び準備
VSCodeにAzure IoT Edge拡張機能をインストールすることで、モジュールを開発することができます。以下はその手順です。
-
VSCodeを起動し、左のバーから拡張機能を選択し、「IoT Edge」でMarketplaceを検索してください。
-
Azure IoT Edgeを選択し、インストールします。依存している拡張機能も同時にインストールされます。
-
Ctrl+Shift+Pよりコマンドパレットを開き、Azure: Sign inをクリックしてください。(テキストボックスに一部を入力することで補完されます。)
コンテナーレジストリの準備
モジュールはAzureのコンテナーレジストリにプッシュしてからデプロイされます。
ソリューションを作成する段階でコンテナーレジストリが必要になるので、先に作成します。
-
「すべてのサービス」からコンテナーレジストリを選択します。
-
左上の「追加」をクリックします。
-
レジストリ名を入力し、他の項目を適宜変更します。
レジストリ名は次の項で使用します。
モジュールの開発
先ほどインストールした拡張機能を用いて、モジュールを開発します。
以下の手順でソリューションを作成します。
-
Ctrl+Shift+Pでコマンドパレットを開き、Azure IoT Edge: New IoT Edge Solutionをクリックしてください。
-
ソリューションを作成するディレクトリを選択してください。
-
ソリューションの名前を入力します。今回はCPUTempとします。
-
今回はPythonを用いてモジュールを開発するため、Python Moduleを選択します。
-
モジュール名を入力します。ここではCPUTempとします。
-
コンテナーレジストリのURLを入力します。ここでは、localhost:5000の部分を「(レジストリ名).azurecr.io」に置き換えます。これ以外を置き換えると正しく動作しない可能性があります。
指定されたディレクトリにソリューションが作成され、自動で開かれます。
ソリューションへのファイルの追加
ソリューションは、作成された時点ではモジュールとして即座に動作することはできません。
そこで、一部のファイルを書き換えます。
以下に、書き換えるべきファイルの名前と、その内容を表示します。
Dockerfile.arm32v7
()で囲まれた部分を置き換えてください。
FROM arm32v7/debian:stretch-slim
WORKDIR /app
RUN apt-get update && \
apt-get install -y --no-install-recommends libboost-python1.62.0 python3-pip libpython3-dev libcurl3 && \
rm -rf /var/lib/apt/lists/*
COPY requirements.txt ./
RUN pip3 install -r requirements.txt
COPY . .
RUN useradd -ms /bin/bash moduleuser
USER moduleuser
ENTRYPOINT [ "python3", "-u", "./main.py" ]
ENV IOTEDGE_AUTHSCHEME=sasToken \
IOTEDGE_DEVICEID=(Azure IoT Edgeに登録したデバイスのID) \
IOTEDGE_WORKLOADURI=unix:///var/run/iotedge/workload.sock \
IOTEDGE_MODULEGENERATIONID=(下記の方法で取得したID) \
IOTEDGE_GATEWAYHOSTNAME=Armadillo \
IOTEDGE_MODULEID=CPUTemp \
IOTEDGE_IOTHUBHOSTNAME=(Azure PortalのIoT Hubの概要から閲覧できるホスト名)
VSCodeの左下の「AZURE IOT HUB DEVICES」からデバイス名を右クリックし、「Get Device Info」を選択してください。
JSONでデバイスの情報が表示され、その先頭に近いところにgenerationIdが表示されます。これを上記のファイルの指定された場所にペーストしてください。
main.py
# 次の行のコメントは、pylintによるモジュールが存在しないことの指摘を防ぎます。
# pylint: disable=E0611
from iothub_client import IoTHubModuleClient, IoTHubClientError, IoTHubTransportProvider
from iothub_client import IoTHubMessage, IoTHubMessageDispositionResult, IoTHubError
import time
import traceback
# IoT Edgeを操作するクラスです。このファイルをインポートすることで利用できます。
class MQTTHubManager:
def __init__(self):
protocol = IoTHubTransportProvider.MQTT
timeout = 10000
self.client = IoTHubModuleClient()
self.client.create_from_environment(protocol)
self.client.set_option("messageTimeout", timeout)
# メッセージ文字列を送信します。
def sendMessage(self, queueName, messageString):
message = IoTHubMessage(messageString)
self.client.send_event_async(queueName, message, self.callback, 0)
# コールバック関数です。通常、手動で呼び出すことはありません。
def callback(self, message, result, context):
print("result %s" % result)
def main():
try:
print("Starting Module...")
hubManager = MQTTHubManager()
tempFile = "/sys/class/thermal/thermal_zone1/temp" # CPUの温度情報ファイルです。現在の温度の1000倍の整数値が格納されています。
print("Ready")
while True:
fileHandler = open(tempFile)
tempStr = fileHandler.read()
if tempStr is not None:
temp = str(int(tempStr.strip()) / 1000.0)
hubManager.sendMessage("temp", temp)
fileHandler.close()
time.sleep(300)
except IoTHubError as e: # IoT Edgeからの例外に対応します。
print("Unexpected Error: %s" % e)
return
except KeyboardInterrupt: # CTRL+Cの入力に対応します。
print("OK.")
return
except Exception as e: # その他の例外についてはトレースバックを表示します。
traceback.print_exc()
# このファイルがモジュールとしてインポートされていない場合にはmain()を呼びます。
if __name__ == "__main__":
main()
../config/deployment.json
このファイルとディレクトリは最初は存在しないため、手動で作成してください。
()で囲まれた部分を置き換えてください。
{
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.0",
"runtime": {
"type": "docker",
"settings": {
"minDockerVersion": "v1.25",
"loggingOptions": "",
"registryCredentials": {
"(コンテナーレジストリ名)": {
"username": "(コンテナーレジストリ名)",
"password": "(下記の方法で取得できるパスワード)",
"address": "(コンテナーレジストリ名).azurecr.io"
}
}
}
},
"systemModules": {
"edgeAgent": {
"type": "docker",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.0",
"createOptions": "{}"
}
},
"edgeHub": {
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.0",
"createOptions": "{}"
}
}
},
"modules": {
"CPUTemp": {
"version": "0.0.1",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "(コンテナーレジストリ名).azurecr.io/cputemp:0.0.1-arm32v7",
"createOptions": "{}"
}
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.0",
"routes": {
"route": "FROM /* INTO $upstream"
},
"storeAndForwardConfiguration": {
"timeToLiveSecs": 7200
}
}
},
"tempSensor": {
"properties.desired": {}
}
}
}
パスワードはポータルより、
コンテナーレジストリ -> (コンテナーレジストリ名) -> アクセスキー
にて取得できます。
これらのファイルを置き換えることで、モジュールのビルドの準備が完了します。
モジュールのビルドとプッシュ
モジュールのビルドはコマンドパレットより行えます。
Ctrl+Shift+Pでコマンドパレットを開き、Build and Push IoT Edge Module Imageを選択します。
ソリューション内に作成したモジュールを選択し、プラットフォームとしてarm32v7を選択します。
これにより、モジュールイメージのビルドとプッシュが完了します。
モジュールのデプロイ
その後、モジュールをデプロイします。
AZURE IOT HUB DEVICESから対象のデバイスを右クリックし、「Create Deployment for Single Device」を選択します。
そして、先ほど作成したconfig/deployment.json
を選択します。
OUTPUTに「Deployment succeeded」と表示されればデプロイ完了です。
右下のデバイス横の更新マークを押し、CPUTempモジュールの状態がrunningであることをご確認ください。
モジュールの動作の観測
モジュールが動作しているか確認するために、PC側のAzure CLIからイベントの監視を行います。
まず、Azure CLIに拡張機能をインストールします。
$ az extension add --name azure-cli-iot-ext
そして、イベントの監視を開始します。
az iot hub monitor-events --login '接続文字列'
接続文字列は、「AZURE IOT HUB DEVICES」のデバイス名を右クリックし、「Copy Connection String」をクリックすることで取得できます。
5分ごとにCPUの温度が数値で送られてきていれば成功です。
(JSON形式で送られているデータもありますが、これはtempSensorという別のモジュールのものです。)
以上でモジュールの開発手順は終了です。お疲れさまでした。