Closed ghost closed 3 years ago
No, you can overload classes in your own code. If you want to modify the source that is fine, bit it is harder for me to know how to help you when problems arise if I can't see your whole code base. If you can send me a single file with your subclassing it is much easier for me to help.
So just add those two blocks to the top of your library along with the necessary imports. On Oct 29, 2013 5:12 PM, "heming277" notifications@github.com wrote:
so if i understand correctly i should add this class into the sync.py in both master and slave sync.py?
thanks
Heming
On Tue, Oct 29, 2013 at 4:11 PM, Galen Collins notifications@github.comwrote:
Right, so in server/sync.py, there is the ModbusSerialServer. What you will have to do is something like::
class RtsModbusSerialServer(object):
def _build_handler(self): ''' A helper method to create and monkeypatch a serial handler. :returns: A patched handler '''
def rts_send(message): self.socket.setRTS(True) result = self.socket.write(message) self.socket.setRTS(False) return result
def rts_recv(count): self.socket.setRTS(False) result = self.socket.read(count) self.socket.setRTS(True) return result
request = self.socket request.send = rts_send request.recv = rts_recv handler = ModbusSingleRequestHandler(request, (self.device, self.device), self) return handler
— Reply to this email directly or view it on GitHub< https://github.com/bashwork/pymodbus/issues/33#issuecomment-27352576> .
— Reply to this email directly or view it on GitHubhttps://github.com/bashwork/pymodbus/issues/33#issuecomment-27355550 .
ok so it still doesn't work. i have my codes below. would you kindly check if i did anything wrong? thanks very much i've noticed that when using sync client it can only work with async server? but async.py in the library code doesn't have ModbusSerialClient. does Sync server work with sync client?
here's my client code:
from pymodbus.client.sync import ModbusSerialClient as ModbusClient from pymodbus.client.sync import ModbusSerialClient import serial,time
class RtsModbusSerialClient(ModbusSerialClient):
def _send(self, request):
''' Sends data on the underlying socket
:param request: The encoded request to send
:return: The number of bytes written
'''
if not self.socket:
raise ConnectionException(self.__str__())
if request:
self.socket.setRTS(True)
result = self.socket.write(request)
time.sleep(0.0022)
self.socket.setRTS(False)
return result
return 0
def _recv(self, size):
''' Reads data from the underlying descriptor
:param size: The number of bytes to read
:return: The bytes read
'''
if not self.socket:
raise ConnectionException(self.__str__())
self.socket.setRTS(False)
result = self.socket.read(size)
return result
import logging logging.basicConfig() log = logging.getLogger() log.setLevel(logging.DEBUG)
client = ModbusClient(method='rtu', retry_on_empty=True, retries=10, port='/dev\ /ttyS2', timeout=1, bytesize=8, baudrate=19200, stopbits=1, parity='E')
client.connect()
rq = client.write_register(1, 10, unit = 1) rr = client.read_holding_registers(1, count = 1, unit = 1) print rr.registers[0] assert(rq.function_code < 0x80) # test that we are not an error assert(rr.registers[0] == 10) # test the expected value
client.close()
And my Server code:
#!/usr/bin/python2.4
'''
from pymodbus.server.sync import StartSerialServer from pymodbus.server.sync import ModbusSerialServer from pymodbus.device import ModbusDeviceIdentification from pymodbus.datastore import ModbusSequentialDataBlock from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer import serial,time
class RtsModbusSerialServer(object):
def _build_handler(self):
''' A helper method to create and monkeypatch
a serial handler.
:returns: A patched handler
'''
def rts_send(message):
self.socket.setRTS(True)
result = self.socket.write(message)
time.sleep(0.0022)
self.socket.setRTS(False)
return result
def rts_recv(count):
self.socket.setRTS(False)
result = self.socket.read(count)
return result
request = self.socket
request.send = rts_send
request.recv = rts_recv
handler = ModbusSingleRequestHandler(request,
(self.device, self.device), self)
return handler
import logging logging.basicConfig() log = logging.getLogger() log.setLevel(logging.DEBUG)
slaves = { 1: ModbusSlaveContext( di = ModbusSequentialDataBlock(1, [17,18,19,20,21,22])), 2: ModbusSlaveContext( dd = ModbusSequentialDataBlock(1, [17]*100)), }
context = ModbusServerContext(slaves=slaves, single=False)
identity = ModbusDeviceIdentification() identity.VendorName = 'Pymodbus' identity.ProductCode = 'PM' identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' identity.ProductName = 'Pymodbus Server' identity.ModelName = 'Pymodbus Server' identity.MajorMinorRevision = '1.0'
timeout=1,\
StartSerialServer(context, identity=identity, port='/dev/ttyS2', timeout=1, byt\ esize=8, baudrate=19200, stopbits=1, parity='E')
framer=Modbus\ AsciiFramer)
the output after i ran the server and client is : python synclient.py DEBUG:pymodbus.transaction:Running transaction 1 DEBUG:pymodbus.transaction:getting transaction 1 DEBUG:pymodbus.transaction:Running transaction 2 DEBUG:pymodbus.transaction:getting transaction 2 Traceback (most recent call last): File "synclient.py", line 73, in ? print rr.registers[0] AttributeError: 'NoneType' object has no attribute 'registers
On Tue, Oct 29, 2013 at 5:30 PM, Galen Collins notifications@github.comwrote:
No, you can overload classes in your own code. If you want to modify the source that is fine, bit it is harder for me to know how to help you when problems arise if I can't see your whole code base. If you can send me a single file with your subclassing it is much easier for me to help.
So just add those two blocks to the top of your library along with the necessary imports. On Oct 29, 2013 5:12 PM, "heming277" notifications@github.com wrote:
so if i understand correctly i should add this class into the sync.py in both master and slave sync.py?
thanks
Heming
On Tue, Oct 29, 2013 at 4:11 PM, Galen Collins notifications@github.comwrote:
Right, so in server/sync.py, there is the ModbusSerialServer. What you will have to do is something like::
class RtsModbusSerialServer(object):
def _build_handler(self): ''' A helper method to create and monkeypatch a serial handler. :returns: A patched handler '''
def rts_send(message): self.socket.setRTS(True) result = self.socket.write(message) self.socket.setRTS(False) return result
def rts_recv(count): self.socket.setRTS(False) result = self.socket.read(count) self.socket.setRTS(True) return result
request = self.socket request.send = rts_send request.recv = rts_recv handler = ModbusSingleRequestHandler(request, (self.device, self.device), self) return handler
Reply to this email directly or view it on GitHub< https://github.com/bashwork/pymodbus/issues/33#issuecomment-27352576> .
Reply to this email directly or view it on GitHub< https://github.com/bashwork/pymodbus/issues/33#issuecomment-27355550> .
Reply to this email directly or view it on GitHubhttps://github.com/bashwork/pymodbus/issues/33#issuecomment-27356341 .
sorry i need to ask again,
if Modpoll works without any converters, how come my code using pymodbus doesn't work?
is it because it is synchronous and not asynchronous? or is there a bug in my code?
thanks ..
On Wed, Oct 30, 2013 at 1:35 PM, Heming Liu hemingliu123@gmail.com wrote:
ok so it still doesn't work. i have my codes below. would you kindly check if i did anything wrong? thanks very much i've noticed that when using sync client it can only work with async server? but async.py in the library code doesn't have ModbusSerialClient. does Sync server work with sync client?
here's my client code:
!/usr/bin/python2.4
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
from pymodbus.client.sync import ModbusUdpClient as ModbusClient
from pymodbus.client.sync import ModbusSerialClient as ModbusClient from pymodbus.client.sync import ModbusSerialClient import serial,time
class RtsModbusSerialClient(ModbusSerialClient):
def _send(self, request): ''' Sends data on the underlying socket :param request: The encoded request to send :return: The number of bytes written ''' if not self.socket: raise ConnectionException(self.__str__()) if request: self.socket.setRTS(True) result = self.socket.write(request) time.sleep(0.0022) self.socket.setRTS(False) return result return 0 def _recv(self, size): ''' Reads data from the underlying descriptor :param size: The number of bytes to read :return: The bytes read ''' if not self.socket: raise ConnectionException(self.__str__()) self.socket.setRTS(False) result = self.socket.read(size) return result
---------------------------------------------------------------------------
configure the client logging
---------------------------------------------------------------------------
import logging logging.basicConfig() log = logging.getLogger() log.setLevel(logging.DEBUG)
client = ModbusClient('localhost', port=502)
client = ModbusClient(method='ascii', port='/dev/pts/2', timeout=1)
client = ModbusClient(method='rtu', retry_on_empty=True, retries=10, port='/dev\ /ttyS2', timeout=1, bytesize=8, baudrate=19200, stopbits=1, parity='E')
client.socket = serial.Serial(port='/dev/ttyS2')
client.socket.setRTS(True)
client.connect()
dw = client.write_coil(1, True)
dr = client.read_coils(1,1)
assert(dw.function_code < 0x80)
assert(dr.bits[0] == True)
rq = client.write_register(1, 10, unit = 1) rr = client.read_holding_registers(1, count = 1, unit = 1) print rr.registers[0]
assert(rq.function_code < 0x80) # test that we are not an error assert(rr.registers[0] == 10) # test the expected value
---------------------------------------------------------------------------
close the client
---------------------------------------------------------------------------
client.close()
And my Server code:
#!/usr/bin/python2.4
'''
from pymodbus.server.async import StartTcpServer
from pymodbus.server.async import StartUdpServer
from pymodbus.server.sync import StartSerialServer from pymodbus.server.sync import ModbusSerialServer from pymodbus.device import ModbusDeviceIdentification from pymodbus.datastore import ModbusSequentialDataBlock from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer import serial,time
class RtsModbusSerialServer(object):
def _build_handler(self): ''' A helper method to create and monkeypatch a serial handler. :returns: A patched handler ''' def rts_send(message): self.socket.setRTS(True) result = self.socket.write(message) time.sleep(0.0022) self.socket.setRTS(False) return result def rts_recv(count): self.socket.setRTS(False) result = self.socket.read(count) return result request = self.socket request.send = rts_send request.recv = rts_recv handler = ModbusSingleRequestHandler(request, (self.device, self.device), self) return handler
---------------------------------------------------------------------------
configure the service logging
---------------------------------------------------------------------------
import logging logging.basicConfig() log = logging.getLogger() log.setLevel(logging.DEBUG)
slaves = {
1: ModbusSlaveContext( di = ModbusSequentialDataBlock(1, [17,18,19,20,21,22])), 2: ModbusSlaveContext( dd = ModbusSequentialDataBlock(1, [17]*100)),
}
context = ModbusServerContext(slaves=slaves, single=False)
---------------------------------------------------------------------------
initialize the server information
---------------------------------------------------------------------------
If you don't set this or any fields, they are defaulted to empty strings.
---------------------------------------------------------------------------
identity = ModbusDeviceIdentification() identity.VendorName = 'Pymodbus' identity.ProductCode = 'PM' identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' identity.ProductName = 'Pymodbus Server' identity.ModelName = 'Pymodbus Server' identity.MajorMinorRevision = '1.0'
---------------------------------------------------------------------------
run the server you want
---------------------------------------------------------------------------
server = ModbusServer(context,identity=identity, port='/dev/ttyS2',
timeout=1,\
bytesize=8, baudrate=9600, stopbits=1, parity='E')
StartTcpServer(context, identity=identity, address=("localhost", 5020))
StartUdpServer(context, identity=identity, address=("localhost", 502))
StartSerialServer(context, identity=identity, port='/dev/ttyS2', timeout=1, byt\ esize=8, baudrate=19200, stopbits=1, parity='E')
StartSerialServer(context, identity=identity, port='/dev/pts/3',
framer=Modbus\ AsciiFramer)
the output after i ran the server and client is :
python synclient.py DEBUG:pymodbus.transaction:Running transaction 1 DEBUG:pymodbus.transaction:getting transaction 1 DEBUG:pymodbus.transaction:Running transaction 2 DEBUG:pymodbus.transaction:getting transaction 2
Traceback (most recent call last): File "synclient.py", line 73, in ? print rr.registers[0] AttributeError: 'NoneType' object has no attribute 'registers
On Tue, Oct 29, 2013 at 5:30 PM, Galen Collins notifications@github.comwrote:
No, you can overload classes in your own code. If you want to modify the source that is fine, bit it is harder for me to know how to help you when problems arise if I can't see your whole code base. If you can send me a single file with your subclassing it is much easier for me to help.
So just add those two blocks to the top of your library along with the necessary imports. On Oct 29, 2013 5:12 PM, "heming277" notifications@github.com wrote:
so if i understand correctly i should add this class into the sync.py in both master and slave sync.py?
thanks
Heming
On Tue, Oct 29, 2013 at 4:11 PM, Galen Collins < notifications@github.com>wrote:
Right, so in server/sync.py, there is the ModbusSerialServer. What you will have to do is something like::
class RtsModbusSerialServer(object):
def _build_handler(self): ''' A helper method to create and monkeypatch a serial handler. :returns: A patched handler '''
def rts_send(message): self.socket.setRTS(True) result = self.socket.write(message) self.socket.setRTS(False) return result
def rts_recv(count): self.socket.setRTS(False) result = self.socket.read(count) self.socket.setRTS(True) return result
request = self.socket request.send = rts_send request.recv = rts_recv handler = ModbusSingleRequestHandler(request, (self.device, self.device), self) return handler
Reply to this email directly or view it on GitHub< https://github.com/bashwork/pymodbus/issues/33#issuecomment-27352576> .
Reply to this email directly or view it on GitHub< https://github.com/bashwork/pymodbus/issues/33#issuecomment-27355550> .
Reply to this email directly or view it on GitHubhttps://github.com/bashwork/pymodbus/issues/33#issuecomment-27356341 .
They are doing the bit banging just like you would be doing (the -4 flag). It doesn't really matter if you use sync or async. I just don't know the timing of how long the flags should be held and how much time it takes to move between the python interpreter and the OS (to bring the serial lines high and low). It really is a duct tape solution and may require a bit of hacking to get it working correctly.
As I don't have any devices, I really cannot do much to help you with debugging, sorry.
but does my code look correct?
thanks
On Thu, Nov 7, 2013 at 11:34 PM, Galen Collins notifications@github.comwrote:
They are doing the bit banging just like you would be doing (the -4 flag). It doesn't really matter if you use sync or async. I just don't know the timing of how long the flags should be held and how much time it takes to move between the python interpreter and the OS (to bring the serial lines high and low). It really is a duct tape solution and may require a bit of hacking to get it working correctly.
As I don't have any devices, I really cannot do much to help you with debugging, sorry.
— Reply to this email directly or view it on GitHubhttps://github.com/bashwork/pymodbus/issues/33#issuecomment-28042549 .
Looks okay, but I would really need to play with the code while looking at a wire trace of the serial line to see how things are actually working.
seems like it just won't work..
do anyone has other suggestions?
thanks
On Fri, Nov 8, 2013 at 3:54 PM, Galen Collins notifications@github.comwrote:
Looks okay, but I would really need to play with the code while looking at a wire trace of the serial line to see how things are actually working.
— Reply to this email directly or view it on GitHubhttps://github.com/bashwork/pymodbus/issues/33#issuecomment-28107935 .
when i'm getting transcations from the client side,
the server side doesn't have any output after i start the sync server.
does that mean my client's request never got to the server?
On Mon, Nov 11, 2013 at 3:51 PM, Heming Liu hemingliu123@gmail.com wrote:
seems like it just won't work..
do anyone has other suggestions?
thanks
On Fri, Nov 8, 2013 at 3:54 PM, Galen Collins notifications@github.comwrote:
Looks okay, but I would really need to play with the code while looking at a wire trace of the serial line to see how things are actually working.
— Reply to this email directly or view it on GitHubhttps://github.com/bashwork/pymodbus/issues/33#issuecomment-28107935 .
closing stale issue
I know this is is old thread but following works for me like a charm by .. a) overloading ModbusSerialClient and b) calculate the correct RTS delay time
class MyModbusSerialClient(ModbusSerialClient):
def __init__(self, **args):
super(MyModbusSerialClient, self).__init__(**args)
def _send(self, request):
if not self.socket:
raise ConnectionException(self.__str__())
if request:
print("in _send")
txtime = (len(request)+1) * (10.0 / self.baudrate)
self.socket.setRTS(False)
time.sleep(0.001)
rc = self.socket.write(request)
time.sleep(txtime)
self.socket.setRTS(True)
return rc
return 0
client = MyModbusSerialClient(method='rtu', port='/dev/ttyUSB0', baudrate=4800)
...
when i use serial RTU and RS-485 wires, how do i set set RTS high and low.
i know i gotta to do it in the source codes, like for read_holding_register request , i need to set it high to send the request and low to receive the response from slave.
and for the slave Linux box, i need to set RTS high to send a reponse back to master and set it low right after that.
where do i do that ?
i know i can setRTS using pyserial.