Closed mbilalshaikh closed 9 months ago
Without the code it's hard to help, however it seems you have call with a port that do not exist (for serial it's typically something like
port="/dev/tty01"
Did you solve your problem ?
Here is the source code. ` import asyncio import logging import pymodbus
import helper
from pymodbus import version as pymodbus_version from pymodbus.datastore import ( ModbusSequentialDataBlock, ModbusServerContext, ModbusSlaveContext, ModbusSparseDataBlock, ) from pymodbus.device import ModbusDeviceIdentification from pymodbus.server import ( StartAsyncSerialServer, StartAsyncTcpServer, StartAsyncTlsServer, StartAsyncUdpServer, )
_logger = logging.getLogger(file) _logger.setLevel(logging.INFO)
def setup_server(description=None, context=None, cmdline=None): """Run server setup.""" args = helper.get_commandline(server=True, description=description, cmdline=cmdline) if context: args.context = context if not args.context: _logger.info("### Create datastore")
# If you initialize a DataBlock to addresses of 0x00 to 0xFF, a request to
# 0x100 will respond with an invalid address exception.
# This is because many devices exhibit this kind of behavior (but not all)
if args.store == "sequential":
# Continuing, use a sequential block without gaps.
datablock = ModbusSequentialDataBlock(0x00, [17] * 100)
elif args.store == "sparse":
# Continuing, or use a sparse DataBlock which can have gaps
datablock = ModbusSparseDataBlock({0x00: 0, 0x05: 1})
elif args.store == "factory":
# Alternately, use the factory methods to initialize the DataBlocks
# or simply do not pass them to have them initialized to 0x00 on the
# full address range::
datablock = ModbusSequentialDataBlock.create()
if args.slaves:
# The server then makes use of a server context that allows the server
# to respond with different slave contexts for different slave ids.
# By default it will return the same context for every slave id supplied
# (broadcast mode).
# However, this can be overloaded by setting the single flag to False and
# then supplying a dictionary of slave id to context mapping::
#
# The slave context can also be initialized in zero_mode which means
# that a request to address(0-7) will map to the address (0-7).
# The default is False which is based on section 4.4 of the
# specification, so address(0-7) will map to (1-8)::
context = {
0x01: ModbusSlaveContext(
di=datablock,
co=datablock,
hr=datablock,
ir=datablock,
),
0x02: ModbusSlaveContext(
di=datablock,
co=datablock,
hr=datablock,
ir=datablock,
),
0x03: ModbusSlaveContext(
di=datablock,
co=datablock,
hr=datablock,
ir=datablock,
zero_mode=True,
),
}
single = False
else:
context = ModbusSlaveContext(
di=datablock, co=datablock, hr=datablock, ir=datablock
)
single = True
# Build data storage
args.context = ModbusServerContext(slaves=context, single=single)
# ----------------------------------------------------------------------- #
# initialize the server information
# ----------------------------------------------------------------------- #
# If you don't set this or any fields, they are defaulted to empty strings.
# ----------------------------------------------------------------------- #
args.identity = ModbusDeviceIdentification(
info_name={
"VendorName": "Pymodbus",
"ProductCode": "PM",
"VendorUrl": "https://github.com/pymodbus-dev/pymodbus/",
"ProductName": "Pymodbus Server",
"ModelName": "Pymodbus Server",
"MajorMinorRevision": pymodbus_version,
}
)
return args
async def run_async_server(args): """Run server.""" txt = f"### start ASYNC server, listening on {args.port} - {args.comm}" _logger.info(txt) if args.comm == "tcp": address = (args.host if args.host else "", args.port if args.port else None) server = await StartAsyncTcpServer( context=args.context, # Data storage identity=args.identity, # server identify
# TBD port=
address=address, # listen address
# custom_functions=[], # allow custom handling
framer=args.framer, # The framer strategy to use
# ignore_missing_slaves=True, # ignore request to a missing slave
# broadcast_enable=False, # treat slave_id 0 as broadcast address,
# timeout=1, # waiting time for request to complete
# TBD strict=True, # use strict timing, t1.5 for Modbus RTU
)
elif args.comm == "udp":
address = (
args.host if args.host else "127.0.0.1",
args.port if args.port else None,
)
server = await StartAsyncUdpServer(
context=args.context, # Data storage
identity=args.identity, # server identify
address=address, # listen address
# custom_functions=[], # allow custom handling
framer=args.framer, # The framer strategy to use
# ignore_missing_slaves=True, # ignore request to a missing slave
# broadcast_enable=False, # treat slave_id 0 as broadcast address,
# timeout=1, # waiting time for request to complete
# TBD strict=True, # use strict timing, t1.5 for Modbus RTU
)
elif args.comm == "serial":
# socat -d -d PTY,link=/tmp/ptyp0,raw,echo=0,ispeed=9600
# PTY,link=/tmp/ttyp0,raw,echo=0,ospeed=9600
server = await StartAsyncSerialServer(
context=args.context, # Data storage
identity=args.identity, # server identify
# timeout=1, # waiting time for request to complete
port=args.port, # serial port
# custom_functions=[], # allow custom handling
framer=args.framer, # The framer strategy to use
# stopbits=1, # The number of stop bits to use
# bytesize=8, # The bytesize of the serial messages
# parity="N", # Which kind of parity to use
baudrate=args.baudrate, # The baud rate to use for the serial device
# handle_local_echo=False, # Handle local echo of the USB-to-RS485 adaptor
# ignore_missing_slaves=True, # ignore request to a missing slave
# broadcast_enable=False, # treat slave_id 0 as broadcast address,
# strict=True, # use strict timing, t1.5 for Modbus RTU
)
elif args.comm == "tls":
address = (args.host if args.host else "", args.port if args.port else None)
server = await StartAsyncTlsServer(
context=args.context, # Data storage
host="localhost", # define tcp address where to connect to.
# port=port, # on which port
identity=args.identity, # server identify
# custom_functions=[], # allow custom handling
address=address, # listen address
framer=args.framer, # The framer strategy to use
certfile=helper.get_certificate(
"crt"
), # The cert file path for TLS (used if sslctx is None)
# sslctx=sslctx, # The SSLContext to use for TLS (default None and auto create)
keyfile=helper.get_certificate(
"key"
), # The key file path for TLS (used if sslctx is None)
# password="none", # The password for for decrypting the private key file
# ignore_missing_slaves=True, # ignore request to a missing slave
# broadcast_enable=False, # treat slave_id 0 as broadcast address,
# timeout=1, # waiting time for request to complete
# TBD strict=True, # use strict timing, t1.5 for Modbus RTU
)
return server
async def async_helper(): """Combine setup and run.""" _logger.info("Starting...") run_args = setup_server(description="Run asynchronous server.") await run_async_server(run_args)
def main():
asyncio.run(async_helper(), debug=True) # pragma: no cover
if name == "main": main() `
Not solved yet. Even after using
python main.py -c serial -f rtu -p /dev/tty01
well it means your serial port is not /dev/tty01. You need to use the port where the rs-485 adapter is connected.
I have figured out the serial ports and running with
python main.py -c serial -f rtu -p /dev/ttyS0
Having below warning.
2023-12-01 08:31:23,837 WARNING logging:108 Failed to start server Could not configure port: (5, 'Input/output error') 2023-12-01 08:31:23,837 INFO logging:96 Server listening.
On windows machine, I am running
python main.py -c serial -f rtu -p COM3
Output:
2023-12-01 03:58:23,873 INFO logging:96 Server listening. 2023-12-01 03:58:23,873 ERROR logging:114 Server callback_connected exception: 'str' object is not callable; Traceback (most recent call last): File "C:\Users\MillSlicer\AppData\Local\Programs\Python\Python38\lib\site-packages\pymodbus\server\async_io.py", line 73, in callback_connected self.framer = self.server.framer( TypeError: 'str' object is not callable`
Need to understand and fix this Error
The first one is because your user is not allowed to use the port.
The second one is because your code do not match the version of the library you use, the framer argument is wrong.
btw if you use a usb rs485 converter it is surely not the correct port you use.
The error message cn be security but it can also mean that nothing is connected to the port.
**Changed the machine and there are three RTU devices on port COM1, COM2 and COM3.
Using pymodbus==3.5.4
running with new parameters got the new response. If the server is listening here then which port the client be connected?**
python main.py -c serial -f rtu -p COM3
2023-12-01 08:34:11,917 INFO logging:96 Server listening. 2023-12-01 08:34:11,917 ERROR logging:114 Server callback_connected exception: 'str' object is not callable; Traceback (most recent call last): File "C:\Users\MillSlicer\AppData\Local\Programs\Python\Python38\lib\site-packages\pymodbus\server\async_io.py", line 73, in callback_connected self.framer = self.server.framer( TypeError: 'str' object is not callable
Executing <Handle ModbusProtocol.connection_made(
Do you have 3 seríal-rs485 converters ? each connected to a different com port.
That is really not how you cable modbus devices.
The error with the frame parameter is because you use code which are made for a different version of pymodbus.
Updated code to
client = Mo1dbusSerialClient(method="rtu", port=f"COM{i}", baudrate=115200, timeout=1, stopbits=2, parity='N', bytesize=8)
client.connect()
while client.connect() != False:
assert client.connected
print('connected')
rr = client.read_holding_registers(address= 0x0010, count=2, unit=1)
print(rr.registers)
time.sleep(2)
Error
connected
Traceback (most recent call last):
File "search_slicer.py", line 55, in
using pymodbus version 3.5.4
You do not test the return value as suggested.....an exception do not have .registers, that is only in valid messages
updated to
while client.connect() != False: assert client.connected print('connected') try: rr = client.read_holding_registers(address= 900, count=60, unit=1) print(rr) except: print('an exception occured') finally: print('test finished')
Error: Modbus Error: [Input/Output] No Response received from the remote slave/Unable to decode response
Just running the server_async example.
Versions
Pymodbus Specific
Description
Just trying to start a async server (Serial[RTU])
python main.py -c serial -f rtu -p 502 WARNING logging:108 Failed to start server [Errno 2] could not open port 502: [Errno 2] No such file or directory: '502' 2023-11-28 INFO logging:96 Server listening.