Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple slaves with RTU #127

Open
AareAa opened this issue Jan 10, 2024 · 8 comments
Open

Multiple slaves with RTU #127

AareAa opened this issue Jan 10, 2024 · 8 comments

Comments

@AareAa
Copy link

AareAa commented Jan 10, 2024

hello, how to work with multiple slaves RTU, e.g. 1,2,3? After initialising port with calling Serial(), got connection an reads (and writes) with slave_id=1 ok. Putting slave_id=2 and slave_id=3 don't work, something get messed, wrong answers. Only way is to init new Serial(), but sometimes "could not open port 'COM7': PermissionError(13, 'Access is denied.', None, 5)". Have to reset COM port/USB device. So looking way to change slave without new Serial()? There seems to be no function setID()...

@OrangeTux
Copy link
Collaborator

I'm not surprised that creating multiple instance of serial.Serial() doesn't work. Usually, access to a serial device can't be shared.

I'm surprised that you run into issues when executing requests on slave id's 2 and 3. This library doesn't do any magic when encoding the slave id in the request. It just encode the slave id to a byte.

I'm wondering if your serial network is unstable. Can you leave only 1 device with slave id 2 on the serial network and disconnect all other devices. And than, try to interact with this device. Is the communication now stable?

@AareAa
Copy link
Author

AareAa commented Jan 10, 2024

Thanks for answer, not creating multiple instances, but closing on slave change previous serial(), then reopening, delay 0.2 sec. Tried 0.1 sec also, same results. With close/open works, but have to reset COM/USB sometimes, 2-3 times a month. Client operates on 3 slaves. Seems, that something going wrong in serial() when requesting with slave_id=2 or 3, without renewing serial(). Serial network is stable, all working otherways, polling 3 slaves in each 7 sec. But have to be a way? Some other librarys have function setID(), but lot to test/programming probably.

@AareAa
Copy link
Author

AareAa commented Jan 10, 2024

Multiple slaves works, sorry, my error. But this thread is useful I think, in Internet there is no information about using multiple slaves simultaneously, example code can be reachable maybe.

@MachineSaver
Copy link

I am running into the same, or what reads like a very similar issue.

If I change the value of the serial slaveAddress in line #7 to anything other than 1 the ModbusRTU server stops seeing the function call requests to read and write data that originate with the ModbusRTU client.

from serial import Serial
from collections import defaultdict
from umodbus.server.serial import get_server
from umodbus.server.serial.rtu import RTUServer

s = Serial('COM13')
s.timeout = 1
s.slaveAddress = 1
s.baudrate = 115200
s.bytesize = 8
s.parity = 'N'
s.stopbits = 1

data_store = defaultdict(int)
app = get_server(RTUServer, s)

@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."""
    print(f'Register address {address} is being read.')
    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. """
    print(f'Register address {address} is being written to.')
    data_store[address] = value

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

You can see that the device works if the slave address is 1.
image

Here you can see that the device doesn't work with slave address 207 (note that I have tried to change this value to 0, 99, 137, 202 but I get no communication unless the value is set to 1)
image

Any help would be much appreciated.

@AareAa
Copy link
Author

AareAa commented May 3, 2024

With my example was problem, that in specific RTU library (not umodbus) slave_id did'nt change, so I forced it. Not going to details, might worth to try smaller slave address, e.g. if 1 is working, use 2 instead 99 etc.

@MachineSaver
Copy link

With my example was problem, that in specific RTU library (not umodbus) slave_id did'nt change, so I forced it. Not going to details, might worth to try smaller slave address, e.g. if 1 is working, use 2 instead 99 etc.

I appreciate the suggestion. I have tried many many different slave addresses and other tricks to try to get it going. If implemented appropriately it should accept values for the RTU from 1 up to 255 (1 byte).

I mean at this point my project is urgent enough where I may comment out/edit the section of the code where the slave address is parsed or allow the system to respond to any slaveID. Ideally I could just set the slaveID the same as if it was set to 1 but instead using a different value. If I can figure that out my plan is to simply give the same data Store response no matter which slaveID is in the request.

Thanks for any help or suggestions!

@MachineSaver
Copy link

MachineSaver commented May 3, 2024

Found the issue for future users/readers

from serial import Serial
from collections import defaultdict
from umodbus.server.serial import get_server
from umodbus.server.serial.rtu import RTUServer

s = Serial('COM13')
s.timeout = 1
s.slaveAddress = 1 #THIS IS NOT WHERE THE MODBUS RTU SERVER ADDRESS IS SET, SEE BOLDED SECTIONS BELOW
s.baudrate = 115200
s.bytesize = 8
s.parity = 'N'
s.stopbits = 1

data_store = defaultdict(int)
app = get_server(RTUServer, s)

@app.route(slave_ids=[99], function_codes=[3, 4], addresses=list(range(0, 32)))

def read_data_store(slave_id, function_code, address):
    """Return value of address."""
    print(f'Register address {address} is being read.')
    return data_store[address]

@app.route(slave_ids=[99], function_codes=[6, 16], addresses=list(range(0, 32)))

def write_data_store(slave_id, function_code, address, value):
    """ Set value for address. """
    print(f'Register address {address} is being written to.')
    data_store[address] = value

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

@MachineSaver
Copy link

You can set a single integer to use a single slaveID in a list or multiple integers in the list to respond to slave addresses.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants