Azure連携(2):デバイスからIoT HubへのMQTT送信(Python)

<< 前の記事:「Azure連携(1):クラウド-デバイス間のMQTTによるデータ交換」
>> 次の記事:「Azure連携(3):IoT Hub受信データをCosmos DBへ自動登録」 … <準備中>

この記事で紹介している内容の多くは、PLCnext Control に限らず一般的なパソコン等にも適用可能です。

前回の記事では、PLCnext Control から Azure IoT Hub へ MQTT でデータを送信する方法がいくつかあることを解説しました。

この記事では、Python と Azure 専用ライブラリ azure.iot.device モジュールを用いて PLCnext Control から Azure IoT Hub へ MQTT 通信を行うための詳細な実装手順を紹介します。

目次

Azure IoT Hub の準備

まず、Azure の IoT Hub サービスを利用するための準備が必要です。

Azure の IoT Hub サービスを利用するために必要なもの
  • Azure アカウントの作成とIoT Hub サービスの設定 (デバイス登録)
  • Azure 管理ツール (通信のモニタリング用)

Azure アカウントの作成と IoT Hub サービスの設定 (デバイス登録)

Azure のアカウントをまだ持っていなければ、30日間 USD$200 分のクレジットを無料で利用可能な無料アカウントの作成をお勧めします。

Azure のアカウントが出来たら、IoT Hub にデバイスを登録する必要があります。
デバイス名は任意で構いません。

Azure アカウント作成からデバイス登録までの手順は、以下の記事をご参照ください。

[リンク] PLCnext コントローラ-クラウド間データ転送実験の準備:Azure IoT Hubの設定

Azure 管理ツール (通信のモニタリング用)

MQTT による送受信などが実際に成功しているかは、Azure 管理ツールである「Azure CLI」を使うと簡単に確認できるので、利用できるようにあらかじめ環境を準備しておきましょう。

Linux、macOS、または Windows コンピューターへローカルインストールするか、ブラウザから Azure Cloud Shell 経由で利用、もしくは Docker コンテナ版を利用することが出来ます。

以下の記事では Azure CLI を Windows コンピューターへローカルインストールする方法について紹介していますので、ご参照ください。

[リンク] クラウド受信データのモニタツール:Azure CLI

デバイス側の Python 環境の準備

クラウドに接続するので、PLCnext Control をインターネットへ接続できるようにします。

また、Azure 専用ライブラリである azure.iot.device モジュールを使用するので、pip コマンドでインストールします。

PLCnext Control をインターネットへ接続

以下の記事を参考に、PLCnext Control がインターネットへ接続できるようにしてください。

[リンク] AXC F 1152/2152/3152をインターネットへ接続する

root パスワードの準備

PLCnext Control では、後述の pip コマンドのインストール等に root ユーザ用のパスワードが必要になります。
(デフォルトでは root ユーザ用パスワードは設定されておらず、su コマンドが使用できません)

まだ root ユーザ用パスワードを設定していない場合は、以下の記事を参考に設定を行ってください。

[リンク] Linux root ユーザー作成

pip コマンドの準備

PLCnext Control には Python3 がインストールされていますが、pip コマンドは入っていないので、以下のサイトの手順を参考に pip コマンドをインストールしてください。その際も、PLCnext Control がインターネットに接続されている必要があります。

[リンク] PLCnext で Python を始める

azure.iot.device モジュールのインストール

Teraterm, Putty 等のターミナルソフトを用いて PLCnext Control に接続し、以下の様に pip コマンドで azure.iot.device モジュールをインストールしてください。

su
<root パスワードを入力>
pip install azure.iot.device

PLCnext Control のデフォルト IP アドレスは、192.168.1.10 です。adminユーザのデフォルトパスワードは、PLCnext Control 筐体表面に印字されています。

MQTT 送信プログラム

デバイスの接続文字列を Azure サイト上で取得

Azure へ MQTT でデータを送信するには、デバイスの接続文字列が必要になります。
接続文字列には接続先のURLやデバイスの情報などが含まれているので、Azure IoT Hub への MQTT 送信時に必要な接続情報はこの1行だけで済みます。

Azure のサイト上で以下の様に接続文字列を取得してください。

デバイスを選択
デバイスのプライマリ接続文字列をコピー

送信するデータの種類

以下のデータを JSON 形式で Azure へ送信することとします。

JSON キー名説明
DEVICE_NAMEデータ送信元のデバイスが何なのかわかりやすいように定義した任意の文字列。
このサンプルでは「PHOENIX CONTACT PLCnext Control」としています。
COUNTデバッグ用情報。データ送信が行われる毎に 1 を加算します。
TEMPERATURE気温:本来は温度センサで取得する値ですが、このサンプルでは単純化のため、10秒ごとに 1 ℃ずつ加算されていく値としています。
TEMP_WARN_H高温警報閾値※
TEMP_WARN_L低温警報閾値※
HUMIDITY湿度:本来は湿度センサで取得する値ですが、このサンプルでは単純化のため、10秒ごとに 5% ずつ加算されていく値としています。
HUM_WARN_H多湿警報閾値※
HUM_WARN_L乾燥警報閾値※
POWER消費電力:本来は電力計で取得する値ですが、このサンプルでは単純化のため、10秒ごとに 5W ずつ加算されていく値としています。
PWR_WARN_H高電力警報閾値※
PWR_WARN_L低電力警報閾値※
VOLTAGE電圧:本来は電力計で取得する値ですが、このサンプルでは単純化のため、常に 100.0 V の定数値としています。
CURRENT電流:本来は電力計で取得する値ですが、このサンプルでは単純化のため、POWER ÷ VOLTAGE の値としています。
送信するデータの種類

※本来は GUI 等からユーザが設定すべき値ですが、このサンプルでは単純化のため、プログラム内で決め打ちにした定数値としています。

このサンプルでは単純化のためにセンサ計測値として適当に生成したダミー値を用いていますが、PLCnext Engineer で作成したプロジェクトから PLCnext Runtime 変数の値を取得する作りにすると現実のセンサ計測値を使用することが出来ます。
詳細は「PythonとREST APIによるPLCnext Runtime変数の操作」を参照してください。

実際に送信される JSON 文字列は以下の様になります。

{ "DEVICE_NAME": "PHOENIX CONTACT PLCnext Control", "COUNT": 1, "TEMPERATURE": 1.00, "TEMP_WARN_H": 30.00, "TEMP_WARN_L": 15.00, "HUMIDITY": 5.00, "HUM_WARN_H": 60.00, "HUM_WARN_L": 20.00, "POWER": 80.00, "PWR_WARN_H": 50.00, "PWR_WARN_L": 15.00, "VOLTAGE": 100.00, "CURRENT": 0.80, "TIMESTAMP": "2024-07-31 18:32:52" }

Python のプログラムファイルを作成

以下のプログラムを「sample_to_send.py」というファイル名で作成してください。

IOT_HUB_CON_STR 変数の部分は、先ほど取得した実際のデバイスの接続文字列を入力してください。

ファイルをパソコン上で作成した場合は、WinSCP 等のファイル転送ソフトを用いて PLCnext Control の任意のディレクトリ※へ配置してください。(※推奨ディレクトリは後述します)
(※ターミナルソフトから SSH で PLCnext Control にログインして nano エディターなどで直接書いても構いません。)

from time               import sleep
from datetime           import datetime, timedelta, timezone
from azure.iot.device   import IoTHubDeviceClient, Message
import random
import uuid

# ========= 定数値 =========
# 接続文字列
IOT_HUB_CON_STR = "****************************************************************************************************************"
# ペイロード用メッセージを作成
DEVICE_NAME = "PHOENIX CONTACT PLCnext Control"
TEMP_MIN    =   0.0 # 気温最低値用定数
TEMP_MAX    =  50.0 # 気温最高値用定数
HUM_MIN     =   0.0 # 湿度最低値用定数
HUM_MAX     = 100.0 # 湿度最高値用定数
POW_MIN     =  80.0 # 電力最低値用定数
POW_MAX     =   5.0 # 電力最高値用定数

# ========= 変数初期値設定 ========= 
count       = 1
temperature = TEMP_MIN # 気温
humidity    = HUM_MIN  # 湿度
power       = POW_MIN  # 電力
voltage     = 100.0    # 電圧 (一定)
current     = 0.0      # 電流 (後で算出:power / voltage)
temp_warn_h = 30.0     # 高温警報閾値 (一定)
temp_warn_l = 15.0     # 低温警報閾値 (一定)
hum_warn_h  = 60.0     # 多湿警報閾値 (一定)
hum_warn_l  = 20.0     # 乾燥警報閾値 (一定)
pwr_warn_h  = 50.0     # 高電力警報閾値 (一定)
pwr_warn_l  = 15.0     # 低電力警報閾値 (一定)

# ========= メインループ =========
while True:
    # ========= Azure IoT Hub Client準備 =========
    client = IoTHubDeviceClient.create_from_connection_string(IOT_HUB_CON_STR)
    try:
        while(1):

            # タイムスタンプ取得
            timestamp_utc = datetime.now(timezone.utc)                      # 現在のUTCのタイムスタンプを取得
            timestamp_jst = timestamp_utc + timedelta(hours=9)              # 9時間を加算
            readable_time_jst = timestamp_jst.strftime('%Y-%m-%d %H:%M:%S') # 人間が読みやすい形式に変換

            # センサ計測値値生成 (本来はセンサからの出力値を取り込むべき部分)
            temperature = temperature + 1.0
            temperature = TEMP_MIN if temperature > TEMP_MAX else temperature
            humidity    = humidity    + 5.0
            humidity    = HUM_MIN  if humidity    > HUM_MAX  else humidity
            power       = power       + 5.0
            power       = POW_MIN  if power       > POW_MAX  else power
            current     = power / voltage

            # json 文字列作成
            # ---- 気温, 湿度, 電力, 電圧
            json_temp    = f'"TEMPERATURE": {temperature:.2f}, "TEMP_WARN_H": {temp_warn_h:.2f}, "TEMP_WARN_L": {temp_warn_l:.2f}'
            json_hum     = f'"HUMIDITY": {humidity:.2f}, "HUM_WARN_H": {hum_warn_h:.2f}, "HUM_WARN_L": {hum_warn_l:.2f}'
            json_pwr     = f'"POWER": {power:.2f}, "PWR_WARN_H": {pwr_warn_h:.2f}, "PWR_WARN_L": {pwr_warn_l:.2f}'
            json_vol_cur = f'"VOLTAGE": {voltage:.2f}, "CURRENT": {current:.2f}'
            # ---- 全て結合
            json_final   = f'{{ "DEVICE_NAME": "{DEVICE_NAME}", "COUNT": {count}, {json_temp}, {json_hum}, {json_pwr}, {json_vol_cur}, "TIMESTAMP": "{readable_time_jst}" }}'

            # Azure のメッセージオブジェクト作成
            message = Message(json_final)
            # ---- json プロパティを設定
            message.message_id = uuid.uuid4()
            message.content_encoding = "utf-8"
            message.content_type = "application/json"
        
            # メッセージを送信
            print(f"メッセージを送信中: {json_final}", flush = True)
            client.send_message(message)
            print("メッセージが送信されました", flush = True)

            # カウントアップ
            count = count + 1
            
            # 待機
            sleep(10)

    except Exception as e:
        print(f"送信中にエラーが発生しました: {e}", flush = True)
    finally:
        # クライアントの終了
        client.shutdown()
        print("client.shutdown()実行", flush = True)

プログラムファイルを PLCnext Control 上へ配置

パソコン上で作成したプログラムファイルを、WinsSCP 等の SCP/SFTP ソフトを使用して PLCnext Control 上のディレクトリに配置してください。

ファイル名PLCnext Control 上の配置パス (推奨)
sample_to_send.py/opt/plcnext/
Python コードの配置パス (推奨)
WinSCP の操作例

プログラムの実行

PLCnext Control へターミナルソフトから SSH ログインし、以下のコマンドを入力して Python のプログラムを実行してください。

python3 sample_to_send.py

成功すると、以下の様なメッセージが表示されます。

admin@axcf2152:~$ python3 sample_to_send.py
メッセージを送信中: { "DEVICE_NAME": "PHOENIX CONTACT PLCnext Control", "COUNT": 1, "TEMPERATURE": 1.00, "TEMP_WARN_H": 30.00, "TEMP_WARN_L": 15.00, "HUMIDITY": 5.00, "HUM_WARN_H": 60.00, "HUM_WARN_L": 20.00, "POWER": 80.00, "PWR_WARN_H": 50.00, "PWR_WARN_L": 15.00, "VOLTAGE": 100.00, "CURRENT": 0.80, "TIMESTAMP": "2024-07-31 18:32:52" }
メッセージが送信されました
メッセージを送信中: { "DEVICE_NAME": "PHOENIX CONTACT PLCnext Control", "COUNT": 2, "TEMPERATURE": 2.00, "TEMP_WARN_H": 30.00, "TEMP_WARN_L": 15.00, "HUMIDITY": 10.00, "HUM_WARN_H": 60.00, "HUM_WARN_L": 20.00, "POWER": 80.00, "PWR_WARN_H": 50.00, "PWR_WARN_L": 15.00, "VOLTAGE": 100.00, "CURRENT": 0.80, "TIMESTAMP": "2024-07-31 18:33:02" }
メッセージが送信されました

Azure CLI による通信確認

Windows パソコンにローカルインストールした Azure CLI で Azure IoT Hub に対する通信の内容を確認する手順を解説します。
Azure CLI をブラウザから Azure Cloud Shell 経由で利用したり Docker コンテナ版を利用する方法については、インターネット上の Azure の解説サイト等をご参照ください。

Azure へログイン

パソコンでコマンドプロンプトを開き、以下のコマンドで Azure にログインします。

az login

そうするとブラウザが立ち上がりアカウントの選択を求められるので、Azure へのログインに使用するアカウントを選択してください。

アカウントを選択
ログイン完了

上記の画面になったらログインは完了です。ブラウザは閉じて構いません。

az login コマンド実行時の様子

IoT Hub 上のイベントをモニタ

パソコンでコマンドプロンプトで以下のコマンドを実行すると、指定した IoT Hub 上の指定したデバイスで発生しているイベントをモニタすることが出来ます。

az iot hub monitor-events --hub-name <IoT Hub 名> --device-id <デバイス名>
az iot hub monitor-events コマンド実行時の様子

上記の通り、Azure IoT Hub がデバイスから送信されたメッセージを受信していることがわかります。
デバイスから送信された JSON データは、”payload” の値に反映されています。

デバイスから Azure IoT Hub へデータ送信を送信する手順は以上で完了です。

Azure IoT Hub で受信したデータをクラウド上で利用するには、クラウド上のストレージやデータベース等にいったん格納する必要があります。
「データベース」というと一見ハードルが高そうに響きますが、当記事の例のような文字/数値データをクラウド上で扱う際には普通のストレージよりも操作が容易になります。

次回は、Azure IoT Hub で受信したデータをデータベース Cosmos DB へ自動的に登録する方法の詳細を紹介します。

<< 前の記事:「Azure連携(1):クラウド-デバイス間のMQTTによるデータ交換」
>> 次の記事:「Azure連携(3):IoT Hub受信データをCosmos DBへ自動登録」 … <準備中>

  • URLをコピーしました!
目次