Cannot get simulator client to perform any reads #1562
-
I apologize in my advance for being a novice at MODBUS. I am attempting to create a basic MODBUS simulator that takes sensor readings from a game/simulation environment to emulate MODBUS-based devices. Right now I am just trying to get the MODBUS server/client working correctly before I attempt to update registers with my simulated sensor readings. However, no matter what my register arrangement (shared true/false; avoiding coils in register addresses in 0-15), I cannot get my client cannot make any successful read calls to either coils/discrete or input/holding registers. I always receive IllegalAddress errors:
If someone would be willing to help me debug my register setup and basic server/client scripts, I would be most grateful. My device configuration .json file: {
"server_list": {
"server": {
"comm": "tcp",
"host": "0.0.0.0",
"port": 5020,
"allow_reuse_address": true,
"ignore_missing_slaves": false,
"framer": "socket",
"identity": {
"VendorName": "pymodbus",
"ProductCode": "PM",
"VendorUrl": "https://github.com/riptideio/pymodbus/",
"ProductName": "pymodbus Server",
"ModelName": "pymodbus Server",
"MajorMinorRevision": "3.1.0"
}
}
},
"device_list": {
"device": {
"setup": {
"co size": 32,
"di size": 32,
"hr size": 4,
"ir size": 15,
"shared blocks": false,
"type exception": true,
"defaults": {
"value": {
"bits": true,
"uint16": 0,
"uint32": 0,
"float32": 0.0,
"string": " "
},
"action": {
"bits": null,
"uint16": null,
"uint32": null,
"float32": null,
"string": null
}
}
},
"invalid": [[0,29], [32, 61]],
"write": [],
"bits": [
{"addr": [30, 31], "value": true},
{"addr": [62, 63], "value": true}
],
"uint16": [{"addr": 68, "value": 0}],
"uint32": [],
"float32": [
{"addr": [64, 67], "value": 100.0}, {"addr": [69, 82], "value": 100.0} ],
"string": [],
"repeat": []
}
}
} My server code: import argparse
import asyncio
import logging
import pathlib
import json
from pymodbus import pymodbus_apply_logging_config
from pymodbus.datastore import ModbusServerContext, ModbusSimulatorContext
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.server import StartAsyncTcpServer
from pymodbus.transaction import ModbusSocketFramer
_logger = logging.getLogger(__name__)
def get_commandline(cmdline=None):
"""Read and validate command line arguments"""
parser = argparse.ArgumentParser(description="Run server simulator.")
parser.add_argument(
"--log",
choices=["critical", "error", "warning", "info", "debug"],
help="set log level, default is info",
default="info",
type=str,
)
parser.add_argument("--host", help="set host", type=str, default="localhost")
parser.add_argument("--port", help="set port", type=str, default="5020")
args = parser.parse_args(cmdline)
return args
def setup_simulator(setup=None, actions=None, cmdline=None):
"""Run server setup."""
args = get_commandline(cmdline=cmdline)
pymodbus_apply_logging_config(args.log)
_logger.setLevel(args.log.upper())
args.framer = ModbusSocketFramer
args.port = int(args.port)
_logger.info("### Create datastore")
if not setup:
path = str(pathlib.Path(__file__).resolve().parent) + "/config.json"
with open(path, 'r') as f:
setup = json.load(f)['device_list']["device"]
context = ModbusSimulatorContext(setup, actions)
args.context = ModbusServerContext(slaves=context, single=True)
args.identity = ModbusDeviceIdentification(
info_name={
"VendorName": "Pymodbus",
"ProductCode": "PM",
"VendorUrl": "https://github.com/pymodbus-dev/pymodbus/",
"ProductName": "Pymodbus Server",
"ModelName": "Pymodbus Server",
"MajorMinorRevision": "test",
}
)
return args
async def run_server_simulator(args):
"""Run server."""
_logger.info("### start server simulator")
pymodbus_apply_logging_config(args.log.upper())
await StartAsyncTcpServer(
context=args.context,
address=(args.host, args.port),
framer=args.framer,
allow_reuse_address=True,
)
if __name__ == "__main__":
run_args = setup_simulator()
asyncio.run(run_server_simulator(run_args), debug=True) and my client code: #!/usr/bin/env python3
"""Pymodbus Aynchronous Client Example.
An example of a single threaded synchronous client.
usage: client_async.py [-h] [--comm {tcp,udp,serial,tls}]
[--framer {ascii,binary,rtu,socket,tls}]
[--log {critical,error,warning,info,debug}]
[--port PORT]
options:
-h, --help show this help message and exit
--comm {tcp,udp,serial,tls}
"serial", "tcp", "udp" or "tls"
--framer {ascii,binary,rtu,socket,tls}
"ascii", "binary", "rtu", "socket" or "tls"
--log {critical,error,warning,info,debug}
"critical", "error", "warning", "info" or "debug"
--port PORT the port to use
--baudrate BAUDRATE the baud rate to use for the serial device
The corresponding server must be started before e.g. as:
python3 server_sync.py
"""
import asyncio
import logging
import os
from pymodbus.transaction import ModbusSocketFramer
# --------------------------------------------------------------------------- #
# import the various client implementations
# --------------------------------------------------------------------------- #
from rtu.utils import get_command_line
from pymodbus.client import (
AsyncModbusSerialClient,
AsyncModbusTcpClient,
AsyncModbusTlsClient,
AsyncModbusUdpClient,
)
_logger = logging.getLogger()
def setup_async_client(description=None, cmdline=None):
"""Run client setup."""
args = get_command_line(server=False, description=description, cmdline=cmdline)
_logger.info("### Create client object")
if args.comm == "tcp":
client = AsyncModbusTcpClient(
"localhost",
port=args.port, # on which port
# Common optional paramers:
framer=ModbusSocketFramer,
# timeout=10,
# retries=3,
# retry_on_empty=False,
# close_comm_on_error=False,
# strict=True,
# TCP setup parameters
# source_address=("localhost", 0),
)
return client
async def run_async_client(client, modbus_calls=None):
"""Run sync client."""
_logger.info("### Client starting")
await client.connect()
assert client.connected
if modbus_calls:
await modbus_calls(client)
result = await client.read_coils(32)
result1 = await client.read_device_information()
client.close()
_logger.info("### End of Program")
if __name__ == "__main__":
testclient = setup_async_client(description="Run asynchronous client.")
asyncio.run(run_async_client(testclient), debug=True) |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 10 replies
-
First off, why do you use the datastore simulator and not the simulator which have web etc. (just read the documentation). It seems to me like you want to make a new simulator, based on then datastore simulator, please explain why you see this need ? |
Beta Was this translation helpful? Give feedback.
-
Your client code is missing slave= in the read call, that can be the reason why you do not get an answer. |
Beta Was this translation helpful? Give feedback.
-
And finally, the illegal address is because you use an invalid address. You actually defined address 32 as being illegal, so why do expect a different response. May I politely suggest you read the simulator documentation we provide. |
Beta Was this translation helpful? Give feedback.
-
How does one explicitly make a register valid? I thought my defining it as a bit register would make it valid (per my original configuration file). |
Beta Was this translation helpful? Give feedback.
First off, why do you use the datastore simulator and not the simulator which have web etc. (just read the documentation).
It seems to me like you want to make a new simulator, based on then datastore simulator, please explain why you see this need ?