pymodbusにはsimulatorというモジュールがあり、そのモジュールを活用することで、1台の端末でマスタ・スレーブの試験が行えます。ただ、pymodbus.simulatorのsetup.jsonには独自の癖があり使用するにはある程度の知識が必要です。
1. setup.json とは?
setup.json は、pymodbus のシミュレータにおける初期状態(レジスタやコイルの値など)を定義する設定ファイルです。これにより、複雑なコードを書かずに、簡単に Modbus デバイスの動作を模倣できます。
この記事では、setup.json の基本的な書き方と、設定例をご紹介します。
シミュレータのコーディング・疎通確認については、別途以下で記載しています。
pymodbusでシミュレータを使いModbus通信する | エクヌツITブログ
2.基本構成
以下は、setup.json の設定例です。
setup.jsonは、サーバに関わる設定を[server_list]、デバイスに関わる設定を[device_list]に設定します。
{
"server_list": {
"server": {
"device_id":14,
"comm": "tcp",
"host": "0.0.0.0",
"port": 5020,
"framer": "socket"
}
},
"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": [
]
}
}
}
3.サーバー部分(server_list)の設定
server_listにはサーバーとしての設定を追加します。
設定時には以下のような形式で設定します。
"server_list": {
"サーバ名": {
"device_id":[デバイスID],
"comm": [通信プロトコル],
"host": [ホスト名],
"port": [ポート番号],
"framer": [通信形式]
}
},
3.1.サーバ名部分
サーバ名を設定します。サーバ名はシミュレータ起動時に指定します。
例えばサーバ名として[test_server]を指定する場合は、以下のようにmodbus_serverの部分に[“test_server”]を指定します。
from pymodbus.server import ModbusSimulatorServer
import asyncio
import os
async def run():
simulator = ModbusSimulatorServer(
modbus_server="test_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())
3.2.デバイスID
デバイスIDを設定することでそのデバイスID(ユニットID)を用いて通信を行います。
pymodbus3.11.4は複数のデバイスを使用して通信することが出来ないため、14と指定した場合はデバイスIDが14のもののみ起動します。
なお、複数台設定する方法は別途以下で記載しています。(OSSを直しています。)
pymodbus 3.11.4 で複数のデバイスを 1 つのシミュレータで扱う方法 | エクヌツITブログ
3.3.通信プロトコル部分
通信プロトコルが何か指定します。
指定できる内容は以下になっています。
| 値 | 説明 |
| tcp | Modbus TCP サーバとして起動 |
| udp | Modbus UDP サーバとして起動 |
| serial | Modbus RTU(シリアル通信)として起動 |
| tls | Modbus TLSとして起動 |
3.4.ホスト名部分
ホストのIPアドレスを指定します。
3.5.ポート番号部分
ホストのポート番号を指定します。
3.6.通信形式部分
通信形式を設定します。
tcp・udpは[socket]、serialは[rtu]・[ascii]、tlsは[tls]を設定することが想定されています。
4.デバイス部分(device_list)の設定
server_listにはデバイスとしての設定を追加します。
設定時には以下のような形式で設定します。
"device_list": {
"デバイス名": {
"setup": {
[サイズ情報]
"defaults": {
"value": {
[デフォルト値情報]
},
"action": {
[デフォルトアクション情報]
}
}
},
"invalid": [エラーレジスタ設定],
"repeat": [repeatレジスタ設定]
"write": [書き込み可能レジスタ],
"bits": [bitレジスタ設定],
"uint16": [unit16レジスタ設定],
"uint32": [unit32レジスタ設定],
"float32": [float32レジスタ設定],
"string": [stringレジスタ設定],
}
}
4.1.デバイス名部分
デバイス名を設定します。デバイス名はシミュレータ起動時に指定します。
例えばデバイス名として[test_device]を指定する場合は、以下のようにmodbus_deviceの部分に[“test_device”]を指定します。
from pymodbus.server import ModbusSimulatorServer
import asyncio
import os
async def run():
simulator = ModbusSimulatorServer(
modbus_server="server",
modbus_device="test_device",
http_host="localhost",
http_port=8080)
await simulator.run_forever()
folder_path = os.path.dirname(__file__)
os.chdir(folder_path)
asyncio.run(run())
4.2.サイズ情報部分
Coils・Discrete Inputs・Holding Registers・Input Registersのサイズを設定します。
下記の設定の場合はコイルサイズが5、それ以外が0となります。
"co size": 5,
"di size": 0,
"hr size": 0,
"ir size": 0,
Modbus通信仕様については、以下で別途まとめています。
【Modbus通信仕様】開発者のための最低限知識 | エクヌツITブログ
4.3.デフォルト値情報
modbus通信を行ったときのデフォルト値を指定します。
例えば以下の場合は、bits~float32は0、stringはtestを設定します。
bits~stringの意味は別途以下で記載しています。
(現在記載中。)
"bits": 0,
"uint16": 0,
"uint32": 0,
"float32": 0.0,
"string": "test"
クライアントが通信を行ったときは以下の動作を行い、デフォルト値を設定します。
①クライアントからリクエストされたアドレスがbit~stringのどれに属しているかを[4.5.レジスタ設定情報(repeat以外)]の値を参照して確認する。
②[4.5.レジスタ設定情報(repeat以外)]で決められた値がないアドレスを取得している場合、デフォルト値の値をレスポンスする。
4.4.デフォルトアクション情報
デフォルト値のアドレスに対して通信があった時のアクションを設定します。
例えば以下のように設定した場合は通信があったときに値を1追加する動きとなります。
"action": {
"bits": "increment",
"uint16": "increment",
"uint32": "increment",
"float32": "increment",
"string": "increment"
}
以下の設定値が設定可能です。
| 値 | |
| random | ランダムな値を返します。 |
| increment | 値を1追加します。 |
| timestamp | 現在日時を返します。 |
| reset | シミュレータの再起動を行います。 |
| uptime | サーバーの起動してからの秒数を返します。 |
4.5.レジスタ設定情報(repeat以外)
どのレジスタをどの値として設定するかを記載します。
以下のような設定内容がありますが、設定方法自体はすべて同じです。
"invalid": [エラーレジスタ設定],
"write": [書き込み可能レジスタ],
"bits": [bitレジスタ設定],
"uint16": [unit16レジスタ設定],
"uint32": [unit32レジスタ設定],
"float32": [float32レジスタ設定],
"string": [stringレジスタ設定],
設定時には以下のような設定をすることが出来ます。
(ここではbitsを例に挙げていますが、他の設定値も同じように設定できます。)
"bits": [
5,
[6, 7],
{"addr": 8, "value": 7},
{"addr": 9, "value": 7, "action": "random"},
{"addr": [11, 12], "value": 7, "action": "random"}
],
上記1つ目のように [6, 7] と設定した場合は、6番目と7番目のアドレスをbitsのレジスタとして使用します。
上記2つ目のように 5 と設定した場合は、5番目のアドレスをbitsのレジスタとして使用します。
上記3つ目のように {“addr”: 8, “value”: 7} と設定した場合は、8番目のアドレスをbitsのレジスタとして使用し、初期値を7とします。
上記4つ目のように {“addr”: 9, “value”: 7, “action”: “random”}と設定した場合は、9番目のアドレスをbitsのレジスタとして使用し、初期値を7とします。動作時には「4.4.デフォルトアクション情報」で記載したrandomの動きをします。
上記5つ目のように{“addr”: [11, 12], “value”: 7, “action”: “random”}と設定した場合は、11,12番目のアドレスをbitsのレジスタとして使用し、初期値を7とします。動作時には「4.4.デフォルトアクション情報」で記載したrandomの動きをします。
invalid~stringは以下のような意味を持っております。
| キー名 | 説明 |
| invalid | invalidとして扱うレジスタの情報を設定します。 設定したアドレスを呼び出した場合、Modbus通信はエラーを返します。 |
| write | 書き込み可能なレジスタを設定します。 |
| bits | bitsとして扱うレジスタを設定します。 bits~string部分の説明は別途以下で記載しています。 (現在記載中) |
| uint16 | unit16として扱うレジスタを設定します。bits~string部分の説明は別途以下で記載しています。 (現在記載中) |
| uint32 | unit32として扱うレジスタを設定します。 bits~string部分の説明は別途以下で記載しています。 (現在記載中) |
| float32 | float32として扱うレジスタを設定します。 bits~string部分の説明は別途以下で記載しています。 (現在記載中) |
| string | stringとして扱うレジスタを設定します。 bits~string部分の説明は別途以下で記載しています。 (現在記載中) |
4.5.レジスタ設定情報(repeat)
あるレジスタと同じレジスタとして設定するための設定情報です。
例えば以下のように設定した場合は、アドレス0~2のアドレスと同様の設定をアドレス10~12にコピーします。
"repeat": [
{"addr": [0, 2], "to": [10, 11]},
{"addr": [0, 2], "to": [10, 15]},
]
5.参考
Welcome to PyModbus’s documentation! — PyModbus 3.12.1 documentation

コメント