AdvancedClimateSystems / uModbus

Python implementation of the Modbus protocol.
Mozilla Public License 2.0
211 stars 82 forks source link

Creating Modbus Server Communication with Client #53

Closed kcsekhar14 closed 6 years ago

kcsekhar14 commented 6 years ago

I want to create a modbus server (with local host : ip address : 152.168.96.11 - same as the system) and the modbus client has (ip address : 152.168.96.32). My client application is running and i am creating the modbus server application with the umodbus server application. Data exchange of 32 bits (either read or write for testing purpose). Slave Id : 1 and Port : 255

How do i configure python umodbus server with server able to read and write data into the client ip address

Here is the umodbus server application -

#!/usr/bin/env python
# scripts/examples/simple_tcp_server.py
import random
import logging
from socketserver import TCPServer
from collections import defaultdict

from umodbus import conf
from umodbus.server.tcp import RequestHandler, get_server
from umodbus.utils import log_to_stream

# Create Random Values
rndata = []
for i in range(32):
    rndata.append(random.randint(1,32))

# Add stream handler to logger 'uModbus'.
log_to_stream(level=logging.DEBUG)

# A very simple data store which maps addresss against their values.
data_store = defaultdict(int)

# Enable values to be signed (default is False).
conf.SIGNED_VALUES = True

TCPServer.allow_reuse_address = True
app = get_server(TCPServer, ('152.168.96.11', 255), RequestHandler)

@app.route(slave_ids=[1], function_codes=[3, 4], addresses=list(range(0, 32)))
def read_data_store(slave_id, function_code, address):
    """" Return value of address. """
    return data_store[address]

@app.route(slave_ids=[1], function_codes=[6, 16], addresses=list(range(0, 32)))
def write_data_store(slave_id, function_code, address, value):
    """" Set value for address. """
    data_store[address] = value

# Configuring the Data
write_data_store(1,16,3,784)
write_data_store(1,16,24,678)
rdata1 = read_data_store(1,4,3)
print(rdata1)
rdata2 = read_data_store(1,4,24)
print(rdata2)

if __name__ == '__main__':
    try:
        app.serve_forever()
        print(rdata1)
    finally:
        app.shutdown()
        app.server_close()
OrangeTux commented 6 years ago

I'm not sure what is wrong. The code seems fine. What do you expect and isn't working? Could you posts logs of both server and client?

kcsekhar14 commented 6 years ago

I have having the two systems, one is acting as server (152.168.96.11) and other is acting as client(152.168.96.32) with the old implementation. I have replaced the client application with umodbus client application & it is working perfect (communicating with old server application). Now, i am trying to replace server application, but it is not communicating with client module (tested both with umodbus client and old client application).

My doubt is where do i need to specify the client ip address, port and slave id and how does the server application know which are read registers and write registers ( i am using all holding registers).

Actually, server is neither reading or writing the data to client (i don't know how to enter the ip address of the client in the umodbus server), it is reading all zeros (except 3 & 24 registers).

Where can i find the log files of both server and client?

Thanks for your reply.

OrangeTux commented 6 years ago

My doubt is where do i need to specify the client ip address, port

When creating a server you must bind the socket to an address. In your example you bind the socket to 152.168.96.11:255. Could you change this to:

app = get_server(TCPServer, ('0.0.0.0', 255), RequestHandler)

You can read more here about the the meaning of binding addresses. But in short binding to 0.0.0.0 means that the server accept requests from every network.

how does the server application know which are read registers and write registers ( i am using all holding registers).

Well, you've used the app.route decorator to register routes for certain requests.

Where can i find the log files of both server and client?

The server and client writes logging to standard out. It depends a bit on how you start the server and client, but normally you'd see the logging in your console.

kcsekhar14 commented 6 years ago

Now, i am modbus server is able to communicate with the client.

  1. when i am writing data from the client to server, umodbus server script is throwing error (please find the console below).

    ERROR:uModbus:Could not handle request: unpack requires a bytes object of length 5.

  2. I want to print the read data continuously by reading from the server. Actually it is not updating, it fixes at initial values. [like 0, 0, 0, 0, ...etc]

0 0 0 0 0 0 0 0 0 0 0

  1. In my client block, i am having read function (code : 4) and write (code : 16) separately. I can disable the read function block or write block when client is running and at that time also error is appearing.

    ERROR:uModbus:Could not handle request: unpack requires a bytes object of length 32.

  2. Once server block throws error, again i have to reset the client block or restart to communicate with the server script properly.

Console Message

kcsekhar@kcsekharpi:~/Desktop/PythonScripts/modbus$ sudo python3 umodbusserver.py
0
0
0
0
0
0
0
0
0
0
0
ERROR:uModbus:Could not handle request: unpack requires a bytes object of length 5.
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/umodbus/server/__init__.py", line 79, in execute_route
    function = create_function_from_request_pdu(request_pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/utils.py", line 112, in inner
    cache[arg] = f(arg)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 136, in create_function_from_request_pdu
    return function_class.create_from_request_pdu(pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 832, in create_from_request_pdu
    _, starting_address, quantity = struct.unpack('>BHH', pdu)
struct.error: unpack requires a bytes object of length 5
ERROR:uModbus:Could not handle request: unpack requires a bytes object of length 32.
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/umodbus/server/__init__.py", line 79, in execute_route
    function = create_function_from_request_pdu(request_pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/utils.py", line 112, in inner
    cache[arg] = f(arg)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 136, in create_function_from_request_pdu
    return function_class.create_from_request_pdu(pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 1486, in create_from_request_pdu
    values = list(struct.unpack(fmt, pdu[6:]))
struct.error: unpack requires a bytes object of length 32
OrangeTux commented 6 years ago

It seems that lengths of the requests are not in line what the server expects.

First, could you post the code of the client. Second, are you sure the server code you posted is equal to the one used in last message? In your last message the server is printing a lot for 0 and I can't relate that to the code you posted?

kcsekhar14 commented 6 years ago

I have used the following code for testing, this is the latest code now running on server side.

Client side, i am running the third party application to receive the data. i have shared the screen shot of this below.

In the console, server code is unable to read data from the client, i am sending but instead it is printing all zeros, but it is able to write the data into the client successfully.

Client Application

image

Server Application

#!/usr/bin/env python
# scripts/examples/simple_tcp_server.py
import random
import logging
from socketserver import TCPServer
from collections import defaultdict

from umodbus import conf
from umodbus.server.tcp import RequestHandler, get_server
from umodbus.utils import log_to_stream

# Create Random Values
rndata = []
for i in range(32):
    rndata.append(random.randint(1,32))

# Add stream handler to logger 'uModbus'.
log_to_stream(level=logging.DEBUG)

# A very simple data store which maps addresss against their values.
data_store = defaultdict(int)

# Enable values to be signed (default is False).
conf.SIGNED_VALUES = True

TCPServer.allow_reuse_address = True
app = get_server(TCPServer, ('0.0.0.0', 255), RequestHandler)

@app.route(slave_ids=[1], function_codes=[3,4], addresses=list(range(0, 32)))
def read_data_store(slave_id, function_code, address):
    """" Return value of address. """
    return data_store[address]

@app.route(slave_ids=[1], function_codes=[6,16], addresses=list(range(0, 32)))
def write_data_store(slave_id, function_code, address, value):
    """" Set value for address. """
    data_store[address] = value

# Configuring the Data
write_data_store(1,16,16,323)
write_data_store(1,16,17,323)
write_data_store(1,16,18,323)
write_data_store(1,16,19,323)
write_data_store(1,16,20,323)
write_data_store(1,16,21,323)
write_data_store(1,16,22,323)
write_data_store(1,16,23,323)
write_data_store(1,16,24,323)
write_data_store(1,16,25,323)
write_data_store(1,16,26,323)
write_data_store(1,16,27,323)
write_data_store(1,16,28,323)
write_data_store(1,16,29,323)
write_data_store(1,16,30,323)
write_data_store(1,16,31,323)

print(read_data_store(1,4,0))
print(read_data_store(1,4,1))
print(read_data_store(1,4,2))
print(read_data_store(1,4,3))
print(read_data_store(1,4,4))
print(read_data_store(1,4,5))
print(read_data_store(1,4,6))
print(read_data_store(1,4,7))
print(read_data_store(1,4,8))
print(read_data_store(1,4,9))
print(read_data_store(1,4,10))
print(read_data_store(1,4,11))
print(read_data_store(1,4,12))
print(read_data_store(1,4,13))
print(read_data_store(1,4,14))
print(read_data_store(1,4,15))

if __name__ == '__main__':
    try:
        app.serve_forever()        
    finally:
        app.shutdown()
        app.server_close()
OrangeTux commented 6 years ago

Ah, I now understand that you're trying with a non-Python client.

I'm wondering what the requests look like that your client is sending. Could you print the request that the server is receiving? You can do this by adding this line to line 42 of modbus/tcp/server/_ _init__.py

print("{}".format(request_adu)) 

Depending on how you started the server you might need to reinstall this modified version of uModbus. You can do that with running python setup.py install.

Btw, what is the name of the software of the screenshot?

kcsekhar14 commented 6 years ago

I added the code in the line 42 and here is the console below. Actually now i am able to write the data from server to client. Client is able to read data from the Server. When i am printing the data in the server code, i think it is printing in binary format. How can i print the in decimal.

print(read_data_store(1,4,0)) print(read_data_store(1,4,1)) print(read_data_store(1,4,2)) print(read_data_store(1,4,3))

Console Output

b'\x01\xbd\x00\x00\x00\x06\x01\x03\x00\x10\x00\x10'
b"\x01\xbe\x00\x00\x00'\x01\x10\x00\x00\x00\x10 \x01,\x00\xff\x00\x0e\x00\x0f\x00\x10\x00\x11\x00\x0f\x00A\x00#\x00,\x00U\x00,\x004\x00#\x01,\x01\x00"
b'\x01\xbf\x00\x00\x00\x06\x01\x03\x00\x10\x00\x10'
b"\x01\xc0\x00\x00\x00'\x01\x10\x00\x00\x00\x10 \x01,\x00\xff\x00\x0e\x00\x0f\x00\x10\x00\x11\x00\x0f\x00A\x00#\x00,\x00U\x00,\x004\x00#\x01,\x01\x00"
b'\x01\xc1\x00\x00\x00\x06\x01\x03\x00\x10\x00\x10'
b"\x01\xc2\x00\x00\x00'\x01\x10\x00\x00\x00\x10 \x01,\x00\xff\x00\x0e\x00\x0f\x00\x10\x00\x11\x00\x0f\x00A\x00#\x00,\x00U\x00,\x004\x00#\x01,\x01\x00"
OrangeTux commented 6 years ago

I added the code in the line 42 and here is the console below. Actually now i am able to write the data from server to client. Client is able to read data from the Server.

Do you mean everything works as expected now?

How can i print the in decimal.

I don't know why you would do this. You'd end up with a very large number that says nothing.

Let me break down the first request for you.

>>> apdu = b'\x01\xbd\x00\x00\x00\x06\x01\x03\x00\x10\x00\x10'

This is an valid read holding registers request for reading 16 registers starting from address 16. The first 7 bytes are the MBAP, that is the header of a Modbus TCP request. It has 4 fields. Each fields with it's content is printed below. You can read more about the header in the documentation

>>> mbap = apdu[:7]
>>> mbap
b'\x01\xbd\x00\x00\x00\x06\x01'
Field value (hex) value (int)
transaction id 0x01bd 445
protocol id 0x0000 0
length 0x0006 6
slave id 0x01 1

The remaining bytes build up the PDU. Read here more about PDU and and the PDU for reading holding registers.

>>> pdu = apdu[7:]
>>> pdu
b'\x03\x00\x10\x00\x10'
Field value (hex) value (int)
function code 0x03 3
start address 0x0010 16
quantity 0x0010 16

The second request is not a valid request. It is far to long.

kcsekhar14 commented 6 years ago

@OrangeTux

Yes, i am able to read the values in my client application what ever server is sending. That means, write frame is working and read frame is not working in the server.

I have one doubt from my server code, does the read and write operations are happening continuously or only once at the starting.

# Configuring the Data
write_data_store(1,16,16,323)
write_data_store(1,16,17,323)
write_data_store(1,16,18,323)
write_data_store(1,16,19,323)
write_data_store(1,16,20,323)
write_data_store(1,16,21,323)
write_data_store(1,16,22,323)
write_data_store(1,16,23,323)
write_data_store(1,16,24,323)
write_data_store(1,16,25,323)
write_data_store(1,16,26,323)
write_data_store(1,16,27,323)
write_data_store(1,16,28,323)
write_data_store(1,16,29,323)
write_data_store(1,16,30,323)
write_data_store(1,16,31,323)

print(read_data_store(1,4,0))
print(read_data_store(1,4,1))
print(read_data_store(1,4,2))
print(read_data_store(1,4,3))
print(read_data_store(1,4,4))
print(read_data_store(1,4,5))
print(read_data_store(1,4,6))
print(read_data_store(1,4,7))
print(read_data_store(1,4,8))
print(read_data_store(1,4,9))
print(read_data_store(1,4,10))
print(read_data_store(1,4,11))
print(read_data_store(1,4,12))
print(read_data_store(1,4,13))
print(read_data_store(1,4,14))
print(read_data_store(1,4,15))

because i have change my code to -

y = range(16) at the starting of code

y = [val+1 for val in y]
print(y)
write_data_store(1,16,16,y[0])
write_data_store(1,16,17,y[1])
write_data_store(1,16,18,y[2])
write_data_store(1,16,19,y[3])
write_data_store(1,16,20,y[4])
write_data_store(1,16,21,y[5])
write_data_store(1,16,22,y[6])
write_data_store(1,16,23,y[7])
write_data_store(1,16,24,y[8])
write_data_store(1,16,25,y[9])
write_data_store(1,16,26,y[10])
write_data_store(1,16,27,y[11])
write_data_store(1,16,28,y[12])
write_data_store(1,16,29,y[13])
write_data_store(1,16,30,y[14])
write_data_store(1,16,31,y[15])

but i can see the values are not updating continuously in my client application but only fixed with the initial values in my client application.

Inorder to run the wirte_data_store and read_data_store in loop. I have used the LoopingCall function which doesnot worked.

#!/usr/bin/env python
# scripts/examples/simple_tcp_server.py
import random
import logging
from socketserver import TCPServer
from collections import defaultdict

from umodbus import conf
from umodbus.server.tcp import RequestHandler, get_server
from umodbus.utils import log_to_stream

from twisted.internet.task import LoopingCall
from twisted.internet import reactor

# Create Random Values
x = [11]*16
y = [22]*16
rndata = []
for i in range(32):
    rndata.append(random.randint(1,32))

# Add stream handler to logger 'uModbus'.
log_to_stream(level=logging.DEBUG)

# A very simple data store which maps addresss against their values.
data_store = defaultdict(int)

# Enable values to be signed (default is False).
conf.SIGNED_VALUES = True

TCPServer.allow_reuse_address = True
app = get_server(TCPServer, ('0.0.0.0', 255), RequestHandler)

@app.route(slave_ids=[1], function_codes=[3,4], addresses=list(range(0, 32)))
def read_data_store(slave_id, function_code, address):
    """" Return value of address. """
    return data_store[address]

@app.route(slave_ids=[1], function_codes=[6,16], addresses=list(range(0, 32)))
def write_data_store(slave_id, function_code, address, value):
    """" Set value for address. """
    data_store[address] = value

# Configuring the Data
loop = LoopingCall(f=updatevalues, a=app)
loop.start(1, now=True)
reactor.run()

def updatevalues(app):
    print("------------START----------")
    x[0]  = read_data_store(1,4,0)
    x[1]  = read_data_store(1,4,1)
    x[2]  = read_data_store(1,4,2)
    x[3]  = read_data_store(1,4,3)
    x[4]  = read_data_store(1,4,4)
    x[5]  = read_data_store(1,4,5)
    x[6]  = read_data_store(1,4,6)
    x[7]  = read_data_store(1,4,7)
    x[8]  = read_data_store(1,4,8)
    x[9]  = read_data_store(1,4,9)
    x[10] = read_data_store(1,4,10)
    x[11] = read_data_store(1,4,11)
    x[12] = read_data_store(1,4,12)
    x[13] = read_data_store(1,4,13)
    x[14] = read_data_store(1,4,14)
    x[15] = read_data_store(1,4,15)
    print(x)

    y = [val+1 for val in x]
    print(y)

    write_data_store(1,16,range(16,32,1),y)
    print("-------------END-------------")

if __name__ == '__main__':
    try:
        app.serve_forever()

    finally:
        app.shutdown()
        app.server_close()
kcsekhar14 commented 6 years ago

@OrangeTux In continuation to above comments, I have tried in other way, but i am unable to execute the function (because of syntax error), below is the code -

#!/usr/bin/env python
# scripts/examples/simple_tcp_server.py
import random
import logging
from socketserver import TCPServer
from collections import defaultdict

from umodbus import conf
from umodbus.server.tcp import RequestHandler, get_server
from umodbus.utils import log_to_stream

from twisted.internet.task import LoopingCall
from twisted.internet import reactor
import threading

# Create Random Values
interval = 2
x = [11]*16
y = [22]*16
rndata = []
for i in range(32):
    rndata.append(random.randint(1,32))

# Add stream handler to logger 'uModbus'.
log_to_stream(level=logging.DEBUG)

def run_server():
    # A very simple data store which maps addresss against their values.
    data_store = defaultdict(int)

    # Enable values to be signed (default is False).
    conf.SIGNED_VALUES = True

    TCPServer.allow_reuse_address = True
    app = get_server(TCPServer, ('0.0.0.0', 255), RequestHandler)

    t = threading.Thread(target=app.serve_forever, daemon=True)
    t.start()
    loop = LoopingCall(f=updatevalues, a=app)
    loop.start(interval, now=True)
    reactor.run()

def updatevalues(app):    
    @app.route(slave_ids=[1], function_codes=[3,4], addresses=list(range(0, 32))
    def read_data_store(slave_id, function_code, address):
               return data_store[address]

    @app.route(slave_ids=[1], function_codes=[6,16], addresses=list(range(0, 32))
    def write_data_store(slave_id, function_code, address, value):
               data_store[address] = value

    print("------------START----------")
    x = read_data_store(1,4,range(0,16))
    print(x)

    y = [val+1 for val in x]
    print(y)

    write_data_store(1,16,range(16,32,1),y)
    print("-------------END-------------")

if __name__ == '__main__':
    run_server()
OrangeTux commented 6 years ago

But I don't quite understand why are calling read_data_store and write_data_store from the server code. It doesn't make sense to me.

If you want to set/get data from the datastore you need call those functions, just call data_store directly. I think the following code demonstraties what you want to achieve.

#!/usr/bin/env python
# scripts/examples/simple_tcp_server.py
import random
import time
import logging
import threading
from socketserver import TCPServer
from collections import defaultdict

from umodbus import conf
from umodbus.server.tcp import RequestHandler, get_server
from umodbus.utils import log_to_stream

# Add stream handler to logger 'uModbus'.
log_to_stream(level=logging.DEBUG)

# A very simple data store which maps addresss against their values.
data_store = defaultdict(int)

# Enable values to be signed (default is False).
conf.SIGNED_VALUES = True

TCPServer.allow_reuse_address = True
app = get_server(TCPServer, ('0.0.0.0', 1818), RequestHandler)

@app.route(slave_ids=[1], function_codes=[3, 4], addresses=list(range(0, 32)))
def read_data_store(slave_id, function_code, address):
    """" Return value of address. """
    return data_store[address]

@app.route(slave_ids=[1], function_codes=[6, 16], addresses=list(range(0, 32)))
def write_data_store(slave_id, function_code, address, value):
    """" Set value for address. """
    data_store[address] = value

if __name__ == '__main__':
    try:
        t = threading.Thread(target=app.serve_forever)
        t.start()

        while True:
            print(data_store)

            # Or if you insists in using read_data_store
            #for i in range(0, 32):
            #    print("{}: {}".format(i, read_data_store(1, 3, i)))

            time.sleep(1)

    finally:
        app.shutdown()
        app.server_close()

        t.join()
kcsekhar14 commented 6 years ago

Thanks for the update. Now i am able to read and write the data in continuous. But i am getting the following error sometimes while running the server code after sometime. When this error occurs, again i have to reset the client application to again communicate with the server code.

Console Window

888
888
888
ERROR:uModbus:Could not handle request: unpack requires a bytes object of length 5.
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/umodbus/server/__init__.py", line 80, in execute_route
    function = create_function_from_request_pdu(request_pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/utils.py", line 112, in inner
    cache[arg] = f(arg)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 136, in create_function_from_request_pdu
    return function_class.create_from_request_pdu(pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 660, in create_from_request_pdu
    _, starting_address, quantity = struct.unpack('>BHH', pdu)
struct.error: unpack requires a bytes object of length 5
888
888
888
888
888
ERROR:uModbus:Could not handle request: unpack requires a bytes object of length 5.
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/umodbus/server/__init__.py", line 80, in execute_route
    function = create_function_from_request_pdu(request_pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/utils.py", line 112, in inner
    cache[arg] = f(arg)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 136, in create_function_from_request_pdu
    return function_class.create_from_request_pdu(pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 660, in create_from_request_pdu
    _, starting_address, quantity = struct.unpack('>BHH', pdu)
struct.error: unpack requires a bytes object of length 5
888
888
888 
[555, 444, 72, 44, 96, 44, 999, 55, 85, 55, 66, 44, 52, 35, 300, 1235]
[555, 444, 72, 44, 96, 44, 999, 55, 85, 55, 66, 44, 52, 35, 300, 1235]
[555, 444, 72, 44, 96, 44, 999, 55, 85, 55, 66, 44, 52, 35, 300, 1235]
ERROR:uModbus:Could not handle request: unpack requires a bytes object of length 32.
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/umodbus/server/__init__.py", line 80, in execute_route
    function = create_function_from_request_pdu(request_pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/utils.py", line 112, in inner
    cache[arg] = f(arg)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 136, in create_function_from_request_pdu
    return function_class.create_from_request_pdu(pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 1486, in create_from_request_pdu
    values = list(struct.unpack(fmt, pdu[6:]))
struct.error: unpack requires a bytes object of length 32
[555, 444, 72, 44, 96, 44, 999, 55, 85, 55, 66, 44, 52, 35, 300, 1235]
[555, 444, 72, 44, 96, 44, 999, 55, 85, 55, 66, 44, 52, 35, 300, 1235]
[555, 444, 72, 44, 96, 44, 999, 55, 85, 55, 66, 44, 52, 35, 300, 1235]
[555, 444, 72, 44, 96, 44, 999, 55, 85, 55, 66, 44, 52, 35, 300, 1235]
[555, 444, 72, 44, 96, 44, 999, 55, 85, 55, 66, 44, 52, 35, 300, 1235]
ERROR:uModbus:Could not handle request: unpack requires a bytes object of length 5.
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/umodbus/server/__init__.py", line 80, in execute_route
    function = create_function_from_request_pdu(request_pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/utils.py", line 112, in inner
    cache[arg] = f(arg)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 136, in create_function_from_request_pdu
    return function_class.create_from_request_pdu(pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 660, in create_from_request_pdu
    _, starting_address, quantity = struct.unpack('>BHH', pdu)
struct.error: unpack requires a bytes object of length 5
[555, 444, 72, 44, 96, 44, 999, 55, 85, 55, 66, 44, 52, 35, 300, 1235]
[555, 444, 72, 44, 96, 44, 999, 55, 85, 55, 66, 44, 52, 35, 300, 1235]

Print Line

b'\x0e\xe6\x00\x00\x00\x06\x01\x04\x00\x10\x00\x10'
b"\x0e\xe7\x00\x00\x00'\x01\x10\x00\x00\x00\x10 \x1d\x97\x00\xff\x00H\x00,\x00`\x00,\x00\x0f\x007\x00U\x007\x00A\x00,\x004\x00#\x01,\x04\xd3"
b'\x0e\xe8\x00\x00\x00\x06\x01\x04\x00\x10\x00\x10'
b"\x0e\xe9\x00\x00\x00'\x01\x10\x00\x00\x00\x10 \x1d\x97\x00\xff\x00H\x00,\x00`\x00,\x00\x0f\x007\x00U\x007\x00A\x00,\x004\x00#\x01,\x04\xd3"
b'\x0e\xea\x00\x00\x00\x06\x01\x04\x00\x10\x00\x10'
b"\x0e\xeb\x00\x00\x00'\x01\x10\x00\x00\x00\x10 \x1d\x97\x00\xff\x00H\x00,\x00`\x00,\x00\x0f\x007\x00U\x007\x00A\x00,\x004\x00#\x01,\x04\xd3"
b'\x0e\xec\x00\x00\x00\x06\x01\x04\x00\x10\x00\x10'
b"\x0e\xed\x00\x00\x00'\x01\x10\x00\x00\x00\x10 \x1d\x97\x00\xff\x00H\x00,\x00`\x00,\x00\x0f\x007\x00U\x007\x00A\x00,\x004\x00#\x01,\x04\xd3"
b'\x0e\xee\x00\x00\x00\x06\x01\x04\x00\x10\x00\x10'
b"\x0e\xef\x00\x00\x00'\x01\x10\x00\x00\x00\x10 \x1d\x97\x00\xff\x00H\x00,\x00`\x00,\x00\x0f\x007\x00U\x007\x00A\x00,\x004\x00#\x01,\x04\xd3"
OrangeTux commented 6 years ago

The requests in the last segment of your post are all fine. I've run them on my server and they are all correct. But this leaves the question open why your server can't handle some of the requests.

Could you edit server/__init__.py and edit the code around line 52 like this:

            log.exception('Error while handling request {0}: {1}.'
                          .format(request_adu, traceback.print_exc()))

You might have to reinstall uModbus. Not with python setup.py install like I said before. Instead use python setup.py develop.

kcsekhar14 commented 6 years ago

Yes, I have modified and reinstalled by python setup.py develop command. But one thing i have observed, when i uncommented on line 42 of server/init,py, i am not observing any errors below like this shown below in console.

print("{}".format(request_adu))

but when i commented this line and run the umodbuserver code, then at some regular intervals, i am getting the following message on the console -

Console Run1

[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
ERROR:uModbus:Could not handle request: unpack requires a bytes object of length 5.
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/umodbus/server/__init__.py", line 80, in execute_route
    function = create_function_from_request_pdu(request_pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/utils.py", line 112, in inner
    cache[arg] = f(arg)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 136, in create_function_from_request_pdu
    return function_class.create_from_request_pdu(pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 832, in create_from_request_pdu
    _, starting_address, quantity = struct.unpack('>BHH', pdu)
struct.error: unpack requires a bytes object of length 5
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
------------------------------ Shortened some of these lines ----------------------------------
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
ERROR:uModbus:Could not handle request: unpack requires a bytes object of length 5.
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/umodbus/server/__init__.py", line 80, in execute_route
    function = create_function_from_request_pdu(request_pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/utils.py", line 112, in inner
    cache[arg] = f(arg)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 136, in create_function_from_request_pdu
    return function_class.create_from_request_pdu(pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 832, in create_from_request_pdu
    _, starting_address, quantity = struct.unpack('>BHH', pdu)
struct.error: unpack requires a bytes object of length 5
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]

Console Run2

[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
ERROR:uModbus:Could not handle request: unpack requires a bytes object of length 5.
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/umodbus/server/__init__.py", line 80, in execute_route
    function = create_function_from_request_pdu(request_pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/utils.py", line 112, in inner
    cache[arg] = f(arg)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 136, in create_function_from_request_pdu
    return function_class.create_from_request_pdu(pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 832, in create_from_request_pdu
    _, starting_address, quantity = struct.unpack('>BHH', pdu)
struct.error: unpack requires a bytes object of length 5[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]

[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[123, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[732, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[834, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[938, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[43, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
ERROR:uModbus:Could not handle request: unpack requires a bytes object of length 32.
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/umodbus/server/__init__.py", line 80, in execute_route
    function = create_function_from_request_pdu(request_pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/utils.py", line 112, in inner
    cache[arg] = f(arg)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 136, in create_function_from_request_pdu
    return function_class.create_from_request_pdu(pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 1486, in create_from_request_pdu
    values = list(struct.unpack(fmt, pdu[6:]))
struct.error: unpack requires a bytes object of length 32
[121, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[121, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[121, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]

Console Run3

[219, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[321, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
ERROR:uModbus:Could not handle request: unpack requires a bytes object of length 32.
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/umodbus/server/__init__.py", line 80, in execute_route
    function = create_function_from_request_pdu(request_pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/utils.py", line 112, in inner
    cache[arg] = f(arg)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 136, in create_function_from_request_pdu
    return function_class.create_from_request_pdu(pdu)
  File "/usr/local/lib/python3.5/dist-packages/umodbus/functions.py", line 1486, in create_from_request_pdu
    values = list(struct.unpack(fmt, pdu[6:]))
struct.error: unpack requires a bytes object of length 32
[357, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[357, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[357, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
[357, 443, 776, 554, 110, 221, 998, 554, 332, 554, 665, 443, 554, 225, 564, 887]
OrangeTux commented 6 years ago

when i uncommented on line 42 of server/init,py, i am not observing any errors

That is unusual. I've no idea how this line could influence the observerd behaviour.

I've actually no idea what is going wrong. The last thing we could try is that I recreate your setup. But that requires that you send me your client application. I'm not sure if that is possible. If it is possible please send it to the e-mailadres listed on my profile.

kcsekhar14 commented 6 years ago

Its not possible to send the client application as it is licensed one, which i cannot arrange. But i try to explore more options, so that i will see whether i can able to capture some more information like Wireshark etc.

When Server is able to establish connection with Client, Server has to run continuously without throwing any error. But in my case it is not happening like that, at some point when server is throwing error and again i have to reset the client to communicate with server, that's the problem now.

Thank you for the continuous support.

OrangeTux commented 6 years ago

Its not possible to send the client application as it is licensed one, which i cannot arrange.

I understand.

i can able to capture some more information like Wireshark etc.

Please upload the pcap file if you manage to capture the traffic.

kcsekhar14 commented 6 years ago

I have attached the pcap file captured on the umodbus server side.

When the Client & Server are communication - Healthy TCP rows When Server throws error and Client see the Error - TCP errors When Client reset and Server connection Estrablished - Healthy TCP rows

Click Here to Download -> umodbus.pcapng.zip

OrangeTux commented 6 years ago

I'm sorry. I cannot identify the cause of the problem and I can't help you further. Therefore I'll close the issue.

rahimdzb commented 3 years ago

hello i juste need to use the serveur but i'dont actualy undertand this part of the code so can you please explain it to me

@app.route(slave_ids=[1], function_codes=[3, 4], addresses=list(range(0, 32)))
def read_data_store(slave_id, function_code, address):
    """" Return value of address. """
    return data_store[address]
OrangeTux commented 3 years ago

@rahimdzb Modbus requests for slave 1, using function code 3 or 4, addressing registers 0 till 32 will be executed by this callback.

rahimdzb commented 3 years ago

Sir can you tell me what's happening exactly in this function ( get_server(Tcpserver,('localhost',502),RequestHandler)