def testStopServerFromMainThread(self, mock_sp): """ Stop async server :return: """ with patch('twisted.internet.reactor') as mock_reactor: StartSerialServer(context=None, port=SERIAL_PORT) self.assertEqual(mock_reactor.run.call_count, 1) StopServer() self.assertEqual(mock_reactor.stop.call_count, 1)
def run_updating_server(): store = ModbusSlaveContext(hr=ModbusSequentialDataBlock.create()) context = ModbusServerContext(slaves=store, single=True) loop = LoopingCall(f=updating_writer, a=(context, )) loop.start(1, now=True) # initially delay by time StartSerialServer(context, framer=ModbusRtuFramer, port='/dev/ttyACM0', timeout=0.3, baudrate=9600)
def testStopServerFromThread(self, mock_sp): """ Stop async server from child thread :return: """ from threading import Thread import time with patch('twisted.internet.reactor') as mock_reactor: StartSerialServer(context=None, port=SERIAL_PORT) self.assertEqual(mock_reactor.run.call_count, 1) t = Thread(target=StopServer) t.start() time.sleep(2) self.assertEqual(mock_reactor.callFromThread.call_count, 1)
def __init__(self, config, params): ''' ''' print("ModBus init") self.update_interval = config.update_interval self.params = params block = CallbackDataBlock(params) store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block, zero_mode=True) slave = { 0x02: store, } context = ModbusServerContext(slaves=store, single=True) identity = ModbusDeviceIdentification() identity.VendorName = 'WK' identity.ProductCode = 'XX' identity.VendorUrl = 'http://xxx.xxx' identity.ProductName = 'ModBus Server' identity.ModelName = 'ModBus Server' identity.MajorMinorRevision = '1.0' # prepare and start ModBus process # self.test_thread = threading.Thread(target=self.setter_function, args=(queue, )) # self.test_thread.start() time = 2 # 5 seconds delay StartSerialServer(context, identity=identity, port='/dev/ttyUSB0', stopbits=1, bytesize=8, parity='N', baudrate=9600, framer=ModbusRtuFramer)
def run(self, mode, tcpport=5020, baud=9600, rtuport=None): # ----------------------------------------------------------------------- # # run the server you want # ----------------------------------------------------------------------- # # time = 1 # 5 seconds delay # loop = LoopingCall(f=updating_writer, a=(context,)) # loop.start(time, now=False) # initially delay by time if mode == MODBUS_MODE_RTU: print("@@@@@@@ Starting ModBus Server %s @ %d" % (rtuport, baud)) StartSerialServer(self.serverContext, framer=ModbusRtuFramer, identity=self.modbusIdentity, port=rtuport, timeout=.05, baudrate=baud) elif modbus_server_mode == MODBUS_MODE_TCP: StartTcpServer(self.serverContext, identity=self.modbusIdentity, address=("", tcpport))
def run_updating_server(): # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # store = ModbusSlaveContext( di=ModbusSequentialDataBlock(0, [17] * 1), co=ModbusSequentialDataBlock(0, [17] * 1), hr=ModbusSequentialDataBlock(1, [17] * 20), ir=ModbusSequentialDataBlock(0, [17] * 1)) context = ModbusServerContext(slaves=store, single=True) # ----------------------------------------------------------------------- # # initialize the server information # ----------------------------------------------------------------------- # 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 # ----------------------------------------------------------------------- # time = 5 # 5 seconds delay loop = LoopingCall(f=updating_writer, a=(context,)) loop.start(time, now=False) # initially delay by time StartSerialServer(context, identity=identity, port='/dev/ttyUSB0', framer=ModbusRtuFramer, stopbits=2, parity='none', baudrate=9600, UnitId=0x01, ignore_missing_slaves=True)
def testSerialServerStartup(self): ''' Test that the modbus serial async server starts correctly ''' with patch('twisted.internet.reactor') as mock_reactor: StartSerialServer(context=None, port=SERIAL_PORT) self.assertEqual(mock_reactor.run.call_count, 1)
def run_server(opt): global gp10block global gp40block store = {} if opt['gp10']['enable'] is True: gp10block = Gp10ModbusSlave(opt['gp10']['deviceid'], **opt['gp10']) store[opt['gp10']['deviceid']] = gp10block.store if opt['gp40']['enable'] is True: gp40block = Gp40ModbusSlave(opt['gp40']['deviceid'], **opt['gp40']) store[opt['gp40']['deviceid']] = gp40block.store if 0 == len(store): print("ERR: enable GP10 or GP40.") return context = ModbusServerContext(slaves=store, 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 = 'RatocSystems, Inc.' identity.ProductCode = 'RPi-Modbus' identity.VendorUrl = 'https://github.com/ratocsystems' identity.ProductName = 'RasPi Modbus Server' identity.ModelName = 'RasPi Modbus Server' identity.MajorMinorRevision = '1.0' # ----------------------------------------------------------------------- # # updater # ----------------------------------------------------------------------- # updater_500ms = LoopingCall(f=write_context_500ms, a=(context,)) updater_500ms.start(.5) updater_1000ms = LoopingCall(f=write_context_1000ms, a=(context,)) updater_1000ms.start(1) writer = LoopingCall(f=read_context, a=(context,)) writer.start(.1) # ----------------------------------------------------------------------- # # run the server you want # ----------------------------------------------------------------------- # if 'tcp' == opt['common']['protocol']: # Tcp: StartTcpServer(context, identity=identity, address=(opt['tcp']['host'], opt['tcp']['port'])) elif 'ascii' == opt['common']['protocol']: # Ascii: StartSerialServer(context, identity=identity, port=opt['serial']['device'], timeout=1, baudrate=opt['serial']['baudrate']) elif 'rtu' == opt['common']['protocol']: # RTU: StartSerialServer(context, framer=ModbusRtuFramer, identity=identity, port=opt['serial']['device'], timeout=.005, baudrate=opt['serial']['baudrate']) else: print("ERR: select protocol tcp, rtu or ascii") # ----------------------------------------------------------------------- # # end proc # ----------------------------------------------------------------------- # updater_500ms.stop() updater_1000ms.stop() writer.stop() if gp10block is not None: del gp10block if gp40block is not None: del gp40block
def _start_rtu_server(self, framer=ModbusRtuFramer): # @req an open and existing /tmp/pts0 is required #---------------------------------------------------------------------------# # initialize your data store #---------------------------------------------------------------------------# # The datastores only respond to the addresses that they are initialized to. # Therefore, if you initialize a DataBlock to addresses from 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):: # # block = ModbusSequentialDataBlock(0x00, [0]*0xff) # # Continuing, you can choose to use a sequential or a sparse DataBlock in # your data context. The difference is that the sequential has no gaps in # the data while the sparse can. Once again, there are devices that exhibit # both forms of behavior:: # # block = ModbusSparseDataBlock({0x00: 0, 0x05: 1}) # block = ModbusSequentialDataBlock(0x00, [0]*5) # # Alternately, you can 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:: # # store = ModbusSlaveContext(di = ModbusSequentialDataBlock.create()) # store = ModbusSlaveContext() # # Finally, you are allowed to use the same DataBlock reference for every # table or you you may use a seperate DataBlock for each table. This depends # if you would like functions to be able to access and modify the same data # or not:: # # block = ModbusSequentialDataBlock(0x00, [0]*0xff) # store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block) # # The server then makes use of a server context that allows the server to # respond with different slave contexts for different unit ids. By default # it will return the same context for every unit id supplied (broadcast # mode). However, this can be overloaded by setting the single flag to False # and then supplying a dictionary of unit id to context mapping:: # # slaves = { # 0x01: ModbusSlaveContext(...), # 0x02: ModbusSlaveContext(...), # 0x03: ModbusSlaveContext(...), # } # context = ModbusServerContext(slaves=slaves, single=False) # # 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):: # # store = ModbusSlaveContext(..., zero_mode=True) #---------------------------------------------------------------------------# store = ModbusSlaveContext( di=ModbusSequentialDataBlock(0, [12] * 100), # discrete input co=ModbusSequentialDataBlock(0, [13] * 100), # coils hr=ModbusSequentialDataBlock(0, [14] * 100), # holding reg ir=ModbusSequentialDataBlock(0, [15] * 100)) # context = ModbusServerContext(slaves=store, single=True) #---------------------------------------------------------------------------# # 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 #---------------------------------------------------------------------------# #StartTcpServer(context, identity=identity, address=("localhost", 5020)) #StartUdpServer(context, identity=identity, address=("localhost", 502)) StartSerialServer(context, identity=identity, port=self.serialPort, baudrate=19200, framer=framer)
def run_server(): # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # # The datastores only respond to the addresses that they are initialized to # Therefore, 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):: # # block = ModbusSequentialDataBlock(0x00, [0]*0xff) # # Continuing, you can choose to use a sequential or a sparse DataBlock in # your data context. The difference is that the sequential has no gaps in # the data while the sparse can. Once again, there are devices that exhibit # both forms of behavior:: # # block = ModbusSparseDataBlock({0x00: 0, 0x05: 1}) # block = ModbusSequentialDataBlock(0x00, [0]*5) # # Alternately, you can 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:: # # store = ModbusSlaveContext(di = ModbusSequentialDataBlock.create()) # store = ModbusSlaveContext() # # Finally, you are allowed to use the same DataBlock reference for every # table or you may use a separate DataBlock for each table. # This depends if you would like functions to be able to access and modify # the same data or not:: # # block = ModbusSequentialDataBlock(0x00, [0]*0xff) # store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block) # # The server then makes use of a server context that allows the server to # respond with different slave contexts for different unit ids. By default # it will return the same context for every unit id supplied (broadcast # mode). # However, this can be overloaded by setting the single flag to False and # then supplying a dictionary of unit id to context mapping:: # # slaves = { # 0x01: ModbusSlaveContext(...), # 0x02: ModbusSlaveContext(...), # 0x03: ModbusSlaveContext(...), # } # context = ModbusServerContext(slaves=slaves, single=False) # # 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):: # # store = ModbusSlaveContext(..., zero_mode=True) # ----------------------------------------------------------------------- # store = ModbusSlaveContext( di=ModbusSequentialDataBlock(0x4000, [0] * 0x6006), co=ModbusSequentialDataBlock(0x4000, [0] * 0x6006), hr=ModbusSequentialDataBlock(0x4000, [0] * 0x6006), ir=ModbusSequentialDataBlock(0x4000, [0] * 0x6006)) context = ModbusServerContext(slaves={1: store}, 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/riptideio/pymodbus/' identity.ProductName = 'Pymodbus Server' identity.ModelName = 'Pymodbus Server' identity.MajorMinorRevision = '1.5' # ----------------------------------------------------------------------- # # run the server you want # ----------------------------------------------------------------------- # time = 10 # 5 seconds delay loop = LoopingCall(f=updating_writer, a=(context,)) loop.start(time, now=False) # initially delay by time prefil_registers(a=(context,)) # RTU: StartSerialServer(context, framer=ModbusRtuFramer, identity=identity, port='/dev/ttyUSB0', timeout=.005, baudrate=9600)
def run_async_server(): """ Runs the Modbus asynchronous server """ parser = get_parser() user_options = parser.parse_args() TCP_PORT = 502 UDP_PORT = 5020 # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # # The datastores only respond to the addresses that they are initialized to # Therefore, if you initialize a DataBlock to addresses from 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) # # block = ModbusSequentialDataBlock(0x00, [0]*0xff) # # Continuing, you can choose to use a sequential or a sparse DataBlock in # your data context. The difference is that the sequential has no gaps in # the data while the sparse can. Once again, there are devices that exhibit # both forms of behavior:: # # block = ModbusSparseDataBlock({0x00: 0, 0x05: 1}) # block = ModbusSequentialDataBlock(0x00, [0]*5) # # Alternately, you can 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:: # # store = ModbusSlaveContext(di = ModbusSequentialDataBlock.create()) # store = ModbusSlaveContext() # # Finally, you are allowed to use the same DataBlock reference for every # table or you you may use a separate DataBlock for each table. # This depends if you would like functions to be able to access and modify # the same data or not:: # # block = ModbusSequentialDataBlock(0x00, [0]*0xff) # store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block) # # The server then makes use of a server context that allows the server to # respond with different slave contexts for different unit ids. By default # it will return the same context for every unit id supplied (broadcast # mode). # However, this can be overloaded by setting the single flag to False # and then supplying a dictionary of unit id to context mapping:: # # slaves = { # 0x01: ModbusSlaveContext(...), # 0x02: ModbusSlaveContext(...), # 0x03: ModbusSlaveContext(...), # } # context = ModbusServerContext(slaves=slaves, single=False) # # 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):: # # store = ModbusSlaveContext(..., zero_mode=True) # ----------------------------------------------------------------------- # # slaves = { # 0x01: get_slave_context(), # } slave = Slave(template=user_options.template) slaves = {slave.slave_id: slave.context} context = ModbusServerContext(slaves=slaves, single=False) # Set up looping call to update values UPDATE_INTERVAL = 5 slave_list = [slave] slave_updater = RepeatingTimer(seconds=UPDATE_INTERVAL, name='slave_updater', defer=True, callback=update_values, **{ 'server_context': context, 'slaves': slave_list }) slave_updater.start_timer() if (slave.mode == 'tcp' or user_options.mode == 'tcp' or user_options.mode is None and user_options.port.lower() == 'tcp'): framer = ModbusSocketFramer elif slave.mode == 'ascii' or user_options.mode == 'ascii': framer = ModbusAsciiFramer else: framer = ModbusRtuFramer # TODO: trap master connect/disconnect as INFO logs rather than DEBUG (default of pyModbus) if user_options.port.lower() == 'tcp': StartTcpServer(context, identity=slave.identity, address=("localhost", TCP_PORT), framer=framer) elif user_options.port.lower() == 'udp': StartUdpServer(context, identity=slave.identity, address=("127.0.0.1", UDP_PORT), framer=framer) else: ser = SerialPort() StartSerialServer( context, identity=slave.identity, framer=framer, port=ser.port, baudrate=ser.baudrate, bytesize=ser.bytesize, parity=ser.parity, stopbits=ser.stopbits, ) # need timeout=X?