Azure IoT Centralがどういうプロトコルで、どういう認証をやっているのか全く分からない。ちょっと調べると、IoT Hubを使ってデバイスと接続しているようだ。認証は、X.509とSASトークンがあるらしい。推奨はSASトークンのようだ。X.509が推奨されないのはなぜだろうか??
MicroPython用のSDKがGitHubに出ている。最後はSDKを使うとしても、SDKに頼ってしまうとデバイスとIotHub間でどのような認証、通信をやってるのか全く分からないので、最初は素のMQTT Clientで接続したい。
GitHub - Azure/iot-central-micropython-client: A micropython SDK for connecting devices to Microsoft Azure IoT Central
SASトークンがまだ理解できておらずX.509で認証させたいので、自己署名でCAを作って、デバイス用証明書を作る必要がある。AWSのIoT CoreではAWS側がClient証明書を発行してくれるのだが、それは設計ポリシーの違いということか。
チュートリアル - OpenSSL を使用して Azure IoT Hub 向けの X.509 テスト証明書を作成する | Microsoft Learn
azure-iot-sdk-c/CACertificateOverview.md at main · Azure/azure-iot-sdk-c · GitHub
■追記
上記手順書に従って、ルート CA と下位 CA を作成した。これを一旦IoTHubに登録する必要がある。
■追記
下位CAを作成して、IoT Hubに登録した後、IoT Hubが提示するコード(数字の羅列)をSubjectとする証明書を発行して再度登録することで、所有証明が完了する*1。下位CAを使ってデバイスのClient証明書に署名して、このClient証明書を使ってMQTTでIoT Hubに接続する。
IoT Hubとの接続テストはMicrosoftからサンプルソースが提供されているのだがC#で提示されている。C#だとビルド環境の準備が大変で、さらにソースが結構複雑でよくわからない。というわけで、PythonのサンプルコードがないかChatに聞いてみた。回答は以下。このソースはシンプルで分かりやすい。まだ試していないのでエラーなく動くかどうかは不明。
import paho.mqtt.client as mqtt import ssl import os # Azure IoT Hub connection settings hub_address = "<your-hub-name>.azure-devices.net" device_id = "<your-device-id>" cert_file = "<path-to-cert-file>" key_file = "<path-to-key-file>" topic = "devices/" + device_id + "/messages/events/" # SSL/TLS context ssl_context = ssl.create_default_context() ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE ssl_context.load_cert_chain(certfile=cert_file, keyfile=key_file) # MQTT client client = mqtt.Client(client_id=device_id, protocol=mqtt.MQTTv311) client.tls_set_context(context=ssl_context) # Connect to Azure IoT Hub client.tls_insecure_set(True) client.username_pw_set(username=hub_address + "/" + device_id, password=None) client.connect(host=hub_address, port=8883) # Send a message message = "Hello from Python" client.publish(topic=topic, payload=message, qos=1) # Disconnect from Azure IoT Hub client.disconnect()
実行時Exception等はならなかったがPublishはされなかった。Connectで多分認証エラーになっていると思われる
Azure IoT Hub の MQTT サポートについて | Microsoft Learn
Azureの説明ページにMQTT CLientから呼び出す例があった。X.509の場合の例も示されている。どうもusernameの所が変わっている様だ。
■追記
動かなかった要素はいろいろありそうだが、動作確認できたコードは以下。動いたといっても、コンソール側でメッセージ送信のカウントが増えたことを根拠としており、Subscribeによる確認はまだ
#!/usr/bin/python3 # $ python3 -m pip install paho-mqtt import paho.mqtt.client as mqtt import ssl import os import time HUB_NAME = "xxxxx" DEVICE_ID = "xxxxxxx" # Azure IoT Hub connection settings ROOT_CA = "./root.ca" CERT_FILE = "device.crt" KEY_FILE = "device.key" def on_connect(client,userdata,flag,rc): print("on connected:",str(rc)) def on_publish(client,userdata,mid): print("on published") def on_disconnect(client,userdata,rc): print("on disconnected:",str(rc)) # MQTT client client = mqtt.Client(client_id=DEVICE_ID, protocol=mqtt.MQTTv311) client.on_connect = on_connect client.on_disconnect = on_disconnect client.on_publish = on_publish hub_address = f"{HUB_NAME}.azure-devices.net" user_name = f"{hub_address}/{DEVICE_ID}/?api-version=2021-04-12" client.username_pw_set(username=user_name, password=None) # SSL/TLS context ssl_context = ssl.create_default_context() ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE client.tls_set(ca_certs=ROOT_CA, certfile=CERT_FILE, keyfile = KEY_FILE, cert_reqs=ssl.CERT_REQUIRED, tls_version = ssl.PROTOCOL_TLSv1_2, ciphers=None) client.tls_insecure_set(False) # Connect to Azure IoT Hub print(f"connect: {hub_address}") client.connect(host=hub_address, port=8883) time.sleep(1) # start the MQTT processing loop client.loop_start() # Send a message topic = f"devices/{DEVICE_ID}/messages/events/" message = "Hello from Python?" print(f"publish: {topic}") client.publish(topic=topic, payload=message, qos=1) time.sleep(3) # Disconnect from Azure IoT Hub client.disconnect() time.sleep(3)
sleepは適当に入れていて本当はフラグがセットされるまで待つような同期化で実装すべき
■Subscriptの例
Subscribeは以下で動作を確認した。Topicが異なるので折返し試験はできない
#!/usr/bin/python3 # $ python3 -m pip install paho-mqtt import paho.mqtt.client as mqtt import ssl import os import time # upkhub02.azure-devices.net HUB_NAME = "xxxxxx" DEVICE_ID = "xxxxxx" # Azure IoT Hub connection settings ROOT_CA = "./root.ca" CERT_FILE = "device.crt" KEY_FILE = "device.key" def on_connect(client,userdata,flag,rc): print("Connected:",str(rc)) # def on_publish(client,userdata,mid): # print("Ppublished") def on_subscribe(client, userdata, mid, granted_qos): print("Subscribed:",str(mid)) def on_message(client, userdata, message): print("Received message '" + str(message.payload) + "' on topic '" + message.topic + "' with QoS " + str(message.qos)) def on_disconnect(client,userdata,rc): print("Disconnected:",str(rc)) # MQTT client client = mqtt.Client(client_id=DEVICE_ID, protocol=mqtt.MQTTv311) client.on_connect = on_connect client.on_disconnect = on_disconnect # client.on_publish = on_publish client.on_subscribe = on_subscribe client.on_message = on_message hub_address = f"{HUB_NAME}.azure-devices.net" user_name = f"{hub_address}/{DEVICE_ID}/?api-version=2021-04-12" client.username_pw_set(username=user_name, password=None) # SSL/TLS context ssl_context = ssl.create_default_context() ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE client.tls_set(ca_certs=ROOT_CA, certfile=CERT_FILE, keyfile = KEY_FILE, cert_reqs=ssl.CERT_REQUIRED, tls_version = ssl.PROTOCOL_TLSv1_2, ciphers=None) client.tls_insecure_set(False) # Connect to Azure IoT Hub print(f"connect: {hub_address}") client.connect(host=hub_address, port=8883) time.sleep(1) # subscribe message topic = f"devices/{DEVICE_ID}/messages/devicebound/#" client.subscribe(topic=topic) # start the MQTT processing loop client.loop_forever() # Disconnect from Azure IoT Hub client.disconnect() time.sleep(3)
■追記
Pubishしたつもりの値が正しく受理されているか?はMSが提供しているAzureIoTExplorerを用いて確認する。これはAzureのコンソールからたどるのではなく、別アプリなのであった。インストールして確認すると、以下の通りPublishされているのを確認(東京エレクトロン様TNX!)
Tue Mar 07 2023 20:27:58 GMT+0900 (日本標準時): { "body": "Hello from Python?", "enqueuedTime": "Tue Mar 07 2023 20:27:58 GMT+0900 (日本標準時)", "properties": {} }
■今後の作業
PCのPythonでは動作確認できたので、これをMicroPythoのMQTTで書き直して、IoTデバイスからAzureIoTにPub/Subできるかを確認する。AWSもClinet証明書による認証でPub/Subできるのを確認しているので、動くだろうとは思うが、、やってみないとわからない。
■参考URL
Azure IoT Hub のドキュメント | Microsoft Learn
IoT Hub に MQTT でメッセージを Publish する際のトピック名について | Japan IoT Support Blog
IoT Hubへ接続するときの認証やキーなど - matsujirushi’s blog
Azure IoT Hub に Mosquitto™ から MQTT なげてみる - Qiita
Azure IoT Hub に mosquitto で接続 - Qiita
Azure IoT Hubを生MQTTS(mosquitto)やHTTP RESTで使う方法 - Qiita
図解 X.509 証明書 - Qiita
Getting Started: Azure IoT Hub と X.509 CA 証明書で認証した接続をする | SORACOM Beam | ソラコムユーザーサイト - SORACOM Users
IoT Hubの設定 | ぷらっとホームどきゅめんと
X.509 証明書を持つデバイスをアプリケーションに接続する - Azure IoT Central | Microsoft Learn
SAS トークンを使用して IoT Hub へのアクセスを制御する | Microsoft Learn
azure-docs.ja-jp/iot-hub-x509ca-overview.md at master · MicrosoftDocs/azure-docs.ja-jp · GitHub
IoTMQTTSample/IoTHubRootCA.crt.pem at master · Azure-Samples/IoTMQTTSample · GitHub
Understand Azure IoT Hub MQTT support | Microsoft Learn
https://cptechweb.teldevice.co.jp/hc/ja/articles/900007074643--%E5%88%9D%E5%BF%83%E8%80%85%E5%90%91-Azure-IoT-%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E6%A7%8B%E7%AF%89-4-IoT-Hub%E3%81%AE%E5%8F%97%E4%BF%A1%E7%A2%BA%E8%AA%8D