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. 応用(必要な場合のみ)
疎通が確認できたら、次のような応用も可能。
- サーバ側で自発的に値を変える。
(現在記載中) - シミュレータサーバをWeb UI(管理画面)で操作する。
(現在記載中) - デバイスIDを設定して通信を行う。
pymodbus で device_idを指定して通信する | エクヌツITブログ
pymodbus 3.11.4 で複数のデバイスを 1 つのシミュレータで扱う方法 | エクヌツITブログ - シミュレータサーバのログ出力を行う。
(現在記載中)

コメント