pymodbusでシミュレータを使って Modbus 通信の疎通を確認する

pymodbus には、実機がなくても Modbus サーバーを立てられる Simulator が用意されている。この記事では、この Simulator を使って 最小構成で Modbus 通信の疎通を確認する方法をまとめる。

Modbus の詳細な仕組みや実運用向けの設計は扱わず、あくまで「通信できることを確認する」ことに焦点を当てている。

このページでできること
  • pymodbus.simulator を使って Modbus TCP サーバーを起動する
  • Python のクライアントコードからレジスタを読み取る
  • 実機なしで Modbus 通信の動作確認ができる
注意事項(この記事で扱わないこと)

当ページでは、疎通確認に絞って記載を行っている。

  • Modbus プロトコルの詳細な説明
  • エラーハンドリングや例外処理
  • 実運用を想定したセキュリティ設定
  • RTU(シリアル通信)の扱い
前提環境
  • Python 3.11.7
  • pymodbus 3.11.4 *
  • OS:Windows
    *vertion 3.11.4以外の動作確認を行っていないが、仕様書を見たところ、
    3.x以降であれば同様の動作環境構築で行える見込み。

pymodbusのインストールがまだの場合は以下ページを参考にインストールを行ってください。
WindowsでpythonのOSSをインストールする | エクヌツITブログ

1. Simulator(Modbus サーバー)を起動する

pymodbus には簡易サーバーを起動できる Simulator が含まれている。
本項では、最小構成で起動する際の設定内容を記載する。
pymodbusのシミュレータを作成するには以下の手順が必要である。

  • aiohttp(PythonのOSS)のインポート
  • シミュレータの作成
  • setup.jsonの作成

(1)aiohttpのインポート

本ページではpymodbusが持っている複数の通信方式のうち、tcp通信を使用して疎通を行う。
当機能はaiohttpをインポートしなければ、動作しない。
にもかかわらず、pymodbusをインポートした時は同時にインポートされない。
そのため、pymodbusとは別にaiohttpをインポートする必要がある。

pip install aiohttp==3.13.3

インストール時のバージョンは当ページ記載時の最新である[3.13.3]を使用している。
ossのインポート方法が分からない場合は、以下を参照。
WindowsでpythonのOSSをインストールする | エクヌツITブログ

なお、aiohttpのインポートが必要な理由は別途以下で記載している。
pymodbus SimulatorServerでNameError発生 | エクヌツITブログ

(2)シミュレータの作成

以下のコードを作成し、任意のフォルダに格納する。
simulator_server.py

from pymodbus.server import ModbusSimulatorServer
import asyncio
import os


async def run():
    simulator = ModbusSimulatorServer(
        modbus_server="server",
        modbus_device="device",
        http_host="localhost",
        http_port=8080)
    await simulator.run_forever()

folder_path = os.path.dirname(__file__)
os.chdir(folder_path)
asyncio.run(run())

詳しい説明は当ページでは行わないが、大まかには以下のようなコーディングを行っている。
1~3行目:OSSのインポート
6~12行目:シミュレータサーバーの各種設定を行っている。
14,15行目:フォルダ移動を行っている。
      シミュレータサーバーは実行フォルダに[set_up.json]が存在する必要がある。
      どこのフォルダで実行しても正しく動作するために設定している。
16行目:[6~12行目]の関数を呼び出している。

なお、当箇所の詳しい説明は以下で記載している。
ModbusSimulatorServerの引数仕様:
(現在記載中)
シミュレータサーバをWeb UI(管理画面)で操作する。:
(現在記載中)
set_up.jsonの不存在エラーの説明:
(現在記載中)

(3)set_up.jsonの作成

以下の設定ファイルを作成し、シミュレータサーバと同じフォルダに作成する。
setup.json

{
    "server_list": {
        "server": {
            "comm": "tcp",
            "host": "0.0.0.0",
            "port": 5020,
            "ignore_missing_devices": false,
            "framer": "socket",
            "identity": {
                "VendorName": "pymodbus",
                "ProductCode": "PM",
                "VendorUrl": "https://github.com/pymodbus-dev/pymodbus/",
                "ProductName": "pymodbus Server",
                "ModelName": "pymodbus Server",
                "MajorMinorRevision": "3.1.0"
            }
        }
    },
    "device_list": {
        "device": {
            "setup": {
                "co size": 5,
                "di size": 0,
                "hr size": 0,
                "ir size": 0,
                "shared blocks": true,
                "type exception": true,
                "defaults": {
                    "value": {
                        "bits": 0,
                        "uint16": 0,
                        "uint32": 0,
                        "float32": 0.0,
                        "string": "test"
                    },
                    "action": {
                        "bits": "increment",
                        "uint16": "increment",
                        "uint32": "increment",
                        "float32": "increment",
                        "string": "increment"
                    }
                }
            },
            "invalid": [
            ],
            "write": [
            ],
            "bits": [
                {"addr": 0, "value": 100}
            ],
            "uint16": [
            ],
            "uint32": [
            ],
            "float32": [
            ],
            "string": [
            ],
            "repeat": [
            ]
        }
    }
}

set_up.jsonの詳しい仕様については、以下で説明している。
pymodbusのシミュレータ setup.json の書き方(ver 3.11.4) | エクヌツITブログ

2. クライアントからレジスタを読み取る

クライアント側のファイルを以下のように作成する。
client.py

from pymodbus.client import ModbusTcpClient


client = ModbusTcpClient(
            host="127.0.0.1",
            port=5020)       # Create client object0
client.connect()                               # connect to device

result = client.read_coils(0, count=16, device_id=1)  # get information from device
print(result.bits)  

詳しい説明は当ページでは行わないが、大まかには以下のようなコーディングを行っている。
1行目:OSSのインポート
3~7行目:クライアントの設定を行っている。
     ホストは自サーバー、ポート番号は5020を設定している。
9行目:client.read_coilsを実行して、コイルのデータを取得する。
10行目:取得したデータを表示する。

ModbusTcpClientはTcp向けの設定を行っている。
Tcp向け以外の設定も含め、クライアントの設定はまとめて以下に記載している。
(現在記載中)
client.read_coilsはコイルの読み取りを行っている。
Modbusはコイル以外のデータの読み込みや書き込みの設定もあるため、まとめて以下に記載してる。
(現在記載中)
当箇所では詳しい説明を行っていないが、Modbusを使用するには最低限のModbusの通信仕様を知っている必要がある。
通信仕様はの説明は以下に記載している。
【Modbus通信仕様】開発者のための最低限知識 | エクヌツITブログ

3.動作確認方法

以下の作業を行い、サーバのデータをクライアントが取得出来るかを確認する。
(1)[simulator_server.py]を実行する。
(2)[client.py]を実行する。
(3)実行結果として以下の実行となることを確認する。
実行結果:

[True, False, True, False, False, True, True, False, False, False, False, False, False, False, False, False]

4. 動作確認のポイント

疎通がうまくいかない場合は次を確認する。

  • Simulator が起動したうえで、クライアントを実行しているか?
  • ポート 5020、8080 が他のプロセスで使用されていないか
  • クライアント側のホスト名・ポート番号とサーバー側のホスト名・ポート名が一致しているか
  • ファイアウォールでブロックされていないか

特にポート競合はよくある原因。

5. 応用(必要な場合のみ)

疎通が確認できたら、次のような応用も可能。

6.参考

コメント

タイトルとURLをコピーしました