def modbus_master(module, properties): log.debug('Modbus master module : ' + str(module)) # Modbus Master #--------------------------------------------------------------------------# # initialize your data store #--------------------------------------------------------------------------# store = ModbusSlaveContext( co = ModbusSequentialDataBlock(0, [0]*100), hr = ModbusSequentialDataBlock(0, [0]*100)) context = ModbusServerContext(slaves=store, single=True) #--------------------------------------------------------------------------# # initialize the server information #--------------------------------------------------------------------------# identity = ModbusDeviceIdentification() identity.VendorName = 'ASO+AKO' identity.ProductCode = 'DYODE' identity.VendorUrl = 'yoloswag' identity.ProductName = 'DYODE' identity.ModelName = 'BSides LV release' identity.MajorMinorRevision = '0.9' #--------------------------------------------------------------------------# # run the server you want #--------------------------------------------------------------------------# time = 1 # 5 seconds delay loop = LoopingCall(f=modbus_master_update, a=(module, properties, context)) loop.start(time, now=False) # initially delay by time StartTcpServer(context, identity=identity, address=("0.0.0.0", \ properties['port_out']))
def main(): store = ModbusSlaveContext( di = ModbusSequentialDataBlock(0, [0]*100), co = ModbusSequentialDataBlock(0, [0]*100), hr = ModbusSequentialDataBlock(0, [0]*100), ir = ModbusSequentialDataBlock(0, [0]*100)) context = ModbusServerContext(slaves=store, single=True) identity = ModbusDeviceIdentification() identity.VendorName = 'pymodbus' identity.ProductCode = 'PM' identity.VendorUrl = 'http://github.com/simplyautomationized' identity.ProductName = 'pymodbus Server' identity.ModelName = 'pymodbus Server' identity.MajorMinorRevision = '1.0' time = 5 # 5 seconds delaytime = 5 # 5 seconds delay writer = LoopingCall(read_context,a=(context,)) loop = LoopingCall(updating_writer, a=(context,)) loop.start(.5) # initially delay by time writer.start(.1) StartTcpServer(context, identity=identity)#, address=("localhost", 502)) #cleanup async tasks temp.setEnabled(False) loop.stop() writer.stop() GPIO.cleanup()
def run_updating_server(): # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # store = ModbusSlaveContext( di=ModbusSequentialDataBlock(0, [17]*100), co=ModbusSequentialDataBlock(0, [17]*100), hr=ModbusSequentialDataBlock(0, [17]*100), ir=ModbusSequentialDataBlock(0, [17]*100)) 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 = '2.2.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 StartTcpServer(context, identity=identity, address=("localhost", 5020))
def ServerThread(e): global server # Configure the service logging #import logging #logging.basicConfig() #log = logging.getLogger() #log.setLevel(logging.DEBUG) # Initialize your data store store = ModbusSlaveContext( di = ModbusSequentialDataBlock(0, [17]*100), co = ModbusSequentialDataBlock(0, [17]*100), hr = ModbusSequentialDataBlock(0, [17]*100), ir = ModbusSequentialDataBlock(0, [17]*100)) 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 # StartTcpServer(context, identity=identity, address=(args.ip, 502)) server = ModbusTcpServer(context, identity=identity, address=(ip, 502)) print 'Server started' server.serve_forever(0.1) print 'Server stopped'
def run_dbstore_update_server(): # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # block = ModbusSequentialDataBlock(0x00, [0] * 0xff) store = SqlSlaveContext(block) context = ModbusServerContext(slaves={1: store}, single=False) # ----------------------------------------------------------------------- # # 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 = '2.2.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 loop.stop() StartTcpServer(context, identity=identity, address=("", 5020))
def run_custom_db_server(): # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # block = CustomDataBlock([0]*100) store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block) 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 = '2.2.0' # ----------------------------------------------------------------------- # # run the server you want # ----------------------------------------------------------------------- # # p = Process(target=device_writer, args=(queue,)) # p.start() StartTcpServer(context, identity=identity, address=("localhost", 5020))
def identity_factory(): identity = ModbusDeviceIdentification() identity.VendorName = 'pymodbus' identity.ProductCode = 'PM' identity.VendorUrl = 'http://github.com/andreadanzi/pymodbus/' identity.ProductName = 'pymodbus Pump Server' identity.ModelName = 'pymodbus Pump Server' identity.MajorMinorRevision = '1.0'
def run_server(): # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # store = ModbusSlaveContext() 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/riptideio/pymodbus/' identity.ProductName = 'Pymodbus Server' identity.ModelName = 'Pymodbus Server' identity.MajorMinorRevision = '1.5' # ----------------------------------------------------------------------- # # Add an example which is long enough to force the ReadDeviceInformation # request / response to require multiple responses to send back all of the # information. # ----------------------------------------------------------------------- # identity[0x80] = "Lorem ipsum dolor sit amet, consectetur adipiscing " \ "elit. Vivamus rhoncus massa turpis, sit amet " \ "ultrices orci semper ut. Aliquam tristique sapien in " \ "lacus pharetra, in convallis nunc consectetur. Nunc " \ "velit elit, vehicula tempus tempus sed. " # ----------------------------------------------------------------------- # # Add an example with repeated object IDs. The MODBUS specification is # entirely silent on whether or not this is allowed. In practice, this # should be assumed to be contrary to the MODBUS specification and other # clients (other than pymodbus) might behave differently when presented # with an object ID occurring twice in the returned information. # # Use this at your discretion, and at the very least ensure that all # objects which share a single object ID can fit together within a single # ADU unit. In the case of Modbus RTU, this is about 240 bytes or so. In # other words, when the spec says "An object is indivisible, therefore # any object must have a size consistent with the size of transaction # response", if you use repeated OIDs, apply that rule to the entire # grouping of objects with the repeated OID. # ----------------------------------------------------------------------- # identity[0x81] = ['pymodbus {0}'.format(pymodbus_version), 'pyserial {0}'.format(pyserial_version)] # ----------------------------------------------------------------------- # # run the server you want # ----------------------------------------------------------------------- # # Tcp: StartTcpServer(context, identity=identity, address=("localhost", 5020))
def run_payload_server(): # ----------------------------------------------------------------------- # # build your payload # ----------------------------------------------------------------------- # builder = BinaryPayloadBuilder(byteorder=Endian.Little, wordorder=Endian.Little) builder.add_string('abcdefgh') builder.add_bits([0, 1, 0, 1, 1, 0, 1, 0]) builder.add_8bit_int(-0x12) builder.add_8bit_uint(0x12) builder.add_16bit_int(-0x5678) builder.add_16bit_uint(0x1234) builder.add_32bit_int(-0x1234) builder.add_32bit_uint(0x12345678) builder.add_32bit_float(22.34) builder.add_32bit_float(-22.34) builder.add_64bit_int(-0xDEADBEEF) builder.add_64bit_uint(0x12345678DEADBEEF) builder.add_64bit_uint(0xDEADBEEFDEADBEED) builder.add_64bit_float(123.45) builder.add_64bit_float(-123.45) # ----------------------------------------------------------------------- # # use that payload in the data store # ----------------------------------------------------------------------- # # Here we use the same reference block for each underlying store. # ----------------------------------------------------------------------- # block = ModbusSequentialDataBlock(1, builder.to_registers()) store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block) 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.5' # ----------------------------------------------------------------------- # # run the server you want # ----------------------------------------------------------------------- # StartTcpServer(context, identity=identity, address=("localhost", 5020))
def __init__(self, address, port = MODBUS_PORT): store = ModbusSlaveContext( di = ModbusSequentialDataBlock(0, [0]*100), co = ModbusSequentialDataBlock(0, [0]*100), hr = ModbusSequentialDataBlock(0, [0]*100), ir = ModbusSequentialDataBlock(0, [0]*100)) self.context = ModbusServerContext(slaves=store, single=True) identity = ModbusDeviceIdentification() identity.VendorName = 'MockPLCs' identity.ProductCode = 'MP' identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' identity.ProductName = 'MockPLC 3000' identity.ModelName = 'MockPLC Ultimate' identity.MajorMinorRevision = '1.0' ModbusServerFactory.__init__(self, self.context, ModbusSocketFramer, identity)
def main(): # initialize the four register types store = ModbusSlaveContext( di = ModbusSequentialDataBlock(0, [0]*100), co = ModbusSequentialDataBlock(0, [0]*100), hr = ModbusSequentialDataBlock(0, [0]*100), ir = ModbusSequentialDataBlock(0, [0]*100)) context = ModbusServerContext(slaves=store, single=True) identity = ModbusDeviceIdentification() identity.VendorName = 'SPARSA' identity.ProductCode = 'SP' identity.VendorUrl = 'http://gentoocloud.com/bitchimabus' identity.ProductName = 'SPARSA Temperature Sensor' identity.ModelName = 'SP_1337' identity.MajorMinorRevision = '1.0' pi.start() time = 5 # 5 seconds delaytime = 5 # 5 seconds delay loop = LoopingCall(f=updating_writer, a=(context,)) loop.start(time, now=False) # initially delay by time StartTcpServer(context, identity=identity, address=(args.address, 502))
def main(): logging.basicConfig() #server_log = logging.getLogger("pymodbus.server") #protocol_log = logging.getLogger("pymodbus.protocol") """ Server launcher """ from optparse import OptionParser parser = OptionParser() parser.add_option("-D", "--debug", help="Turn on to enable tracing", action="store_true", dest="debug", default=False) (opt, arg) = parser.parse_args() # enable debugging information if opt.debug: try: _logger.setLevel(logging.DEBUG) except Exception: print "Logging is not supported on this system" # Create store context store = ModbusSlaveContext( di = ModbusSequentialDataBlock(0, [17]*100), co = ModbusSequentialDataBlock(0, [17]*100), hr = ModbusSequentialDataBlock(0, [17]*100), ir = ModbusSequentialDataBlock(0, [17]*100)) context = ModbusServerContext(slaves=store, single=True) identity = ModbusDeviceIdentification() identity.VendorName = 'Pymodbus' identity.ProductCode = 'PM' identity.VendorUrl = 'http://unipi.technology' identity.ProductName = 'Pymodbus Server on IOLoop' identity.ModelName = 'Pymodbus Server' identity.MajorMinorRevision = '1.0' StartTcpServer(context, identity=identity, address=("localhost", 5020))
pass except Exception, E: logger.debug(str(E)) pass def status_callback(self, device): try: device._modbus_handle.sync(device, self.bits, self.regs) except AttributeError: pass except Exception,e : #print str(e) pass ## small version of Modbus map, limited to Gpio devices class UnipiContextGpio(UnipiContext): devicemap = { # count coil-pos reg-pos alt-reg-pos 'ao' : (AoHandle (1, 0, 1),), 'input' : (InputHandle(14, 1, 2, 3),), } identity = ModbusDeviceIdentification() identity.VendorName = 'Unipi Technology' identity.ProductCode = 'Evok' identity.VendorUrl = 'http://unipi.technology' identity.ProductName = 'Evok Modbus/TCP Server on Tornado' identity.ModelName = 'Evok Modbus' identity.MajorMinorRevision = '1.1'
def run_async_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 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( hr=ModbusSequentialDataBlock(2000, [0]*2100)) store.register(CustomModbusRequest.function_code, 'cm', ModbusSequentialDataBlock(0, [17] * 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 = '2.2.0' # ----------------------------------------------------------------------- # # run the server you want # ----------------------------------------------------------------------- # # TCP Server StartTcpServer(context, identity=identity, address=("", 502), #https://stackoverflow.com/questions/47264617/pymodbus-server-port-502-not-open-starttcpserver custom_functions=[CustomModbusRequest])
store = ModbusSlaveContext( di = ModbusSequentialDataBlock(0, [17]*100), co = ModbusSequentialDataBlock(0, [17]*100), hr = ModbusSequentialDataBlock(0, [17]*100), ir = ModbusSequentialDataBlock(0, [17]*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/riptideio/pymodbus/' identity.ProductName = 'Pymodbus Server' identity.ModelName = 'Pymodbus Server' identity.MajorMinorRevision = '1.0' #---------------------------------------------------------------------------# # run the server you want #---------------------------------------------------------------------------# # Tcp: # StartTcpServer(context, identity=identity, address=("localhost", 5020)) # Udp: #StartUdpServer(context, identity=identity, address=("localhost", 502)) # Ascii: #StartSerialServer(context, identity=identity, port='/dev/pts/3', timeout=1)
from pymodbus.server.sync import StartTcpServer from pymodbus.device import ModbusDeviceIdentification from pymodbus.datastore import ModbusSequentialDataBlock from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext import logging logging.basicConfig() log = logging.getLogger() log.setLevel(logging.DEBUG) identity = ModbusDeviceIdentification() identity.VendorName = 'Joac-Automation' identity.ProductCode = 'PM' identity.VendorUrl = 'http://github.com/joac/ArakurWW/' identity.ProductName = 'Servidor Test Arakur' identity.ModelName = 'Servidor Test Arakur' identity.MajorMinorRevision = '0.1' marcas = ModbusSequentialDataBlock(0, [0] * 34) registros = ModbusSequentialDataBlock(0, [0] * 34) store = ModbusSlaveContext(di = marcas, co= marcas, hr = registros, ir =registros) context = ModbusServerContext(slaves=store, single=True) StartTcpServer(context, identity=identity, address=("localhost", 5020))
hr = hr, ir = ir) context = ModbusServerContext(slaves=store, single=True) return context #---------------------------------------------------------------------------# # initialize the server information #---------------------------------------------------------------------------# # If you don't set this or any fields, they are defaulted to empty strings. #---------------------------------------------------------------------------# identity = ModbusDeviceIdentification() identity.VendorName = 'VOLTTRON' identity.ProductCode = 'VT' identity.VendorUrl = 'http://github.com/VOLTTRON/volttron' identity.ProductName = 'VOLTTRON Modbus Test Device' identity.ModelName = 'VOLTTRON Modbus Test Device' identity.MajorMinorRevision = '1.0' abstraction = DeviceAbstraction(args.config) #Create the deamon as soon as we've loaded the device configuration. if not args.no_daemon: createDaemon() context = abstraction.get_server_context() #---------------------------------------------------------------------------# # run the server you want #---------------------------------------------------------------------------#
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(0, [17] * 100), co=ModbusSequentialDataBlock(0, [17] * 100), hr=ModbusSequentialDataBlock(0, [17] * 100), ir=ModbusSequentialDataBlock(0, [17] * 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/riptideio/pymodbus/' identity.ProductName = 'Pymodbus Server' identity.ModelName = 'Pymodbus Server' identity.MajorMinorRevision = '2.2.0' # ----------------------------------------------------------------------- # # run the server you want # ----------------------------------------------------------------------- # # Tcp: # StartTcpServer(context, identity=identity, address=("localhost", 5020)) # TCP with different framer # StartTcpServer(context, identity=identity, # framer=ModbusRtuFramer, address=("0.0.0.0", 5020)) # Udp: # StartUdpServer(context, identity=identity, address=("0.0.0.0", 5020)) # Ascii: # StartSerialServer(context, identity=identity, # port='/dev/ttyp0', timeout=1) # RTU: StartSerialServer(context, framer=ModbusRtuFramer, identity=identity, port='/dev/ttyUSB0', timeout=.005, baudrate=115200)
# 0x03: ModbusSlaveContext(...), # } # context = ModbusServerContext(slaves=slaves, single=False) #---------------------------------------------------------------------------# store = ModbusSlaveContext(di=ModbusSequentialDataBlock(0, [17] * 100), co=ModbusSequentialDataBlock(0, [17] * 100), hr=ModbusSequentialDataBlock(0, [17] * 100), ir=ModbusSequentialDataBlock(0, [17] * 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='/dev/pts/3', framer=ModbusRtuFramer) #StartSerialServer(context, identity=identity, port='/dev/pts/3', framer=ModbusAsciiFramer)
'ProductCode': "SAS TSXETY4103", 'VendorUrl': "", 'ProductName': "", 'ModelName': "Model", 'MajorMinorRevision': "1.0" }, } #print("Liste des signature : ") #-affichagesignature(dico) #i = demandeobligatoire("Quelle signature voulez vous utiliser ?","int") identity = ModbusDeviceIdentification() identity.VendorName = dico[sys.argv[1]]['VendorName'] identity.ProductCode = dico[sys.argv[1]]['ProductCode'] identity.VendorUrl = dico[sys.argv[1]]['VendorUrl'] identity.ProductName = dico[sys.argv[1]]['ProductName'] identity.ModelName = dico[sys.argv[1]]['ModelName'] identity.MajorMinorRevision = dico[sys.argv[1]]['MajorMinorRevision'] #---------------------------------------------------------------------------# # run the server you want #---------------------------------------------------------------------------# # Tcp: print("=== [START] ====") log.info("Server start") StartTcpServer(context, identity=identity, address=("0.0.0.0", 502)) # Udp: #StartUdpServer(context, identity=identity, address=("localhost", 502))
time.sleep(1) # Modbus stuff store = ModbusSlaveContext(di=ModbusSequentialDataBlock(0, [0] * 100), co=ModbusSequentialDataBlock(0, [0] * 100), hr=ModbusSequentialDataBlock(0, [0] * 100), ir=ModbusSequentialDataBlock(0, [0] * 100)) context = ModbusServerContext(slaves=store, single=True) # Modbus PLC server information identity = ModbusDeviceIdentification() identity.VendorName = 'Simmons Oil Refining Platform' identity.ProductCode = 'SORP' identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' identity.ProductName = 'SORP 3850' identity.ModelName = 'Simmons ORP 3850' identity.MajorMinorRevision = '2.09.01' # Port the world will listen on MODBUS_SERVER_PORT = 5020 # MODBUS_SERVER_ADDR = "127.0.0.1" # PLC Register values for various control functions PLC_FEED_PUMP = 0x01 PLC_TANK_LEVEL = 0x02 PLC_OUTLET_VALVE = 0x03 PLC_SEP_VALVE = 0x04 PLC_OIL_SPILL = 0x06 PLC_OIL_PROCESSED = 0x07
from pymodbus.server.sync import StartTcpServer from pymodbus.device import ModbusDeviceIdentification from pymodbus.datastore import ModbusSequentialDataBlock from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext import logging if __name__ == "__main__": logging.basicConfig() log = logging.getLogger() log.setLevel(logging.DEBUG) identify = ModbusDeviceIdentification() identify.VendorName = 'P4A' identify.ProductCode = 'P4AMBS' identify.VendorUrl = 'http://performanceforassets.com' identify.ProductName = 'P4AModbusServer' identify.MajorMinorRevision = '1.0' store = ModbusSlaveContext( di=ModbusSequentialDataBlock(0, [0] * 0xff), co=ModbusSequentialDataBlock(0, [0] * 0xff), hr=ModbusSequentialDataBlock( 0, [0] * 0xff), #holding register, seems to be 16 bits by default ir=ModbusSequentialDataBlock(0, [0] * 0xff)) context = ModbusServerContext(slaves=store, single=True) StartTcpServer( context, identity=identify, address=("localhost", 5020)) #put lan ip if you want outside computer to access it
import requests import json import os uid = None # Data Store for PLC Devices hr is used for Reg Read and Reg Write and is the only register interaction store = ModbusSlaveContext(di=ModbusSequentialDataBlock(0, [17] * 100), co=ModbusSequentialDataBlock(0, [17] * 100), hr=ModbusSequentialDataBlock(0, [17] * 100), ir=ModbusSequentialDataBlock(0, [17] * 100)) context = ModbusServerContext(slaves=store, single=True) # Data Store for PLC Devices hr is used for Reg Read and Reg Write and is the only register interaction identity = ModbusDeviceIdentification() identity.VendorName = 'Facility Sensor System' identity.ProductCode = 'FSS' identity.VendorUrl = 'http://www.wehaveyourback.com' identity.ProductName = 'PLC Sensor Server' identity.ModelName = 'Sensor Server 5000' identity.MajorMinorRevision = '3.a1' # Class: PLC Server Thread # Description: HMI Machines maintain connection between the PLC device and the Historian. The PLC Thread maintains three # threads one for the Server itself the interacts directly with the PLC devices. The second is the polling of sensor # systems and update the database. Lastly the actuator which polls and communicates with the the PLC actuators and # reflects the changes to the database and sensors. class PLCThread(threading.Thread): # Method: Initializer # Description: Initializer for PLC Thread Object to help create the connection between the PLC devices and # postgres DB # Arguments: address: Address of the System to be used to host the server
store = ModbusSlaveContext( di = ModbusSequentialDataBlock(0, [False]*100), co = ModbusSequentialDataBlock(0, [False]*100), hr = ModbusSequentialDataBlock(0, [0]*100), ir = ModbusSequentialDataBlock(0, [0]*100)) context = ModbusServerContext(slaves=store, single=True) #---------------------------------------------------------------------------# # initialize the server information #---------------------------------------------------------------------------# identity = ModbusDeviceIdentification() identity.VendorName = 'ZXL' identity.ProductCode = 'PLC' identity.VendorUrl = 'https://github.com/zxlin/Modbus-PLC-Simulator' identity.ProductName = 'PLC-Sim' identity.ModelName = 'Modbus-Server' identity.MajorMinorRevision = '1.0' #---------------------------------------------------------------------------# # Start running the server #---------------------------------------------------------------------------# time = 3 loop = LoopingCall(f=logToArcSight, a=(context,)) loop1 = LoopingCall(f=updating_writer, a=(context,)) loop.start(30, now=True) loop1.start(time, now=True) StartTcpServer(context, identity=identity, address=(server_address, server_port))
def run_updating_server(): # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # parser = argparse.ArgumentParser() parser.add_argument('-server_ip', action='store', dest='server_ip', type=str, help='Input the ip address of modbus server') parser.add_argument('-server_port', action='store', dest='server_port', type=int, help='Input the port of modbus server') arg = parser.parse_args() # 模拟佳环高频电源modbus-tcp的开关量输出 list_co_context = [] for i in range(200): #0000000-000157 一共158点 if i % 2 == 0: list_co_context.append(0) else: list_co_context.append(1) # 模拟佳环高频电源modbus-tcp的模拟量输入 list_ir_context = [] for i in range(10): list_ir_context.append(i + 0) # 模拟佳环高频电源modbus-tcp的模拟量输出 list_hr_context = [] for i in range(200): #400011-400164 一共154点 list_hr_context.append(i + 0) #store = ModbusSlaveContext( #di = ModbusSequentialDataBlock(0, [11]*100), #co = ModbusSequentialDataBlock(0, [12]*100), #hr = ModbusSequentialDataBlock(0, [13]*100), #ir = ModbusSequentialDataBlock(0, [14]*100)) store = ModbusSlaveContext( di=ModbusSequentialDataBlock(0, [0] * 100), co=ModbusSequentialDataBlock(0, list_co_context), hr=ModbusSequentialDataBlock(0, list_hr_context), ir=ModbusSequentialDataBlock(0, list_ir_context)) 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 = 2 # 5 seconds delay loop = LoopingCall(f=updating_writer, a=(context, )) loop.start(time, now=False) # initially delay by time #StartTcpServer(context, identity=identity, address=("192.168.168.100", 5021)) StartTcpServer(context, identity=identity, address=(arg.server_ip, arg.server_port))
def run_server(modbus_type, port): # ----------------------------------------------------------------------- # # 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 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) # ----------------------------------------------------------------------- # #block = ModbusSequentialDataBlock(0x00, [16]*0xff) coils_block = ModbusSparseDataBlock({1: 0, 2: 1, 3: 0, 4: 1}) registers_block = ModbusSparseDataBlock({ # this block is to test 32bits 1: 0xC28F, # PDU0 - BE 2: 0xC20D, 3: 0x8FC2, # PDU2 - MBE 4: 0x0DC2, 5: 0xC20D, # PDU4 - MLE 6: 0xC28F, 7: 0x0DC2, # PDU6 - LE 8: 0x8FC2, # 9: 0xC28F, # PDU8 - same as (PDU0 - BE) 10: 0xC20D, 11: 0xC28F, # PDU0 - same as (PDU0 - BE) 12: 0xC20D, # test int32 13: 0xFFFF, # PDU12 14: 0xFDCE, # this block is to test 64bits # BE 15: 0xBFBF, # PDU14 16: 0x9A6B, 17: 0x50B0, 18: 0xF27C, # LE 19: 0x7CF2, # PDU18 20: 0xB050, 21: 0x6B9A, 22: 0xBFBF, # MLE 23: 0xF27C, # PDU22 24: 0x50B0, 25: 0x9A6B, 26: 0xBFBF, # MBE 27: 0xBFBF, # PDU26 28: 0x6B9A, 29: 0xB050, 30: 0x7CF2 }) store = ModbusSlaveContext(di=coils_block, co=coils_block, hr=registers_block, ir=registers_block) 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/riptideio/pymodbus/' identity.ProductName = 'Pymodbus Server' identity.ModelName = 'Pymodbus Server' identity.MajorMinorRevision = '1.5' # ----------------------------------------------------------------------- # # run the server you want # ----------------------------------------------------------------------- # # Tcp: if (modbus_type == 'TCP'): StartTcpServer(context, identity=identity, address=("0.0.0.0", port)) elif (modbus_type == 'TCP_RTU'): # TCP with different framer StartTcpServer(context, identity=identity, framer=ModbusRtuFramer, address=("0.0.0.0", port))
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, [True] * 8), # discrete inputs co=ModbusSequentialDataBlock(0, [False] * 8), # coils hr=ModbusSequentialDataBlock(0, [0] * 8), # holding regs ir=ModbusSequentialDataBlock(0, list(range(8))), # input regs zero_mode=True) # request(0-7) will map to the address (0-7) 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)
'VendorUrl':"", 'ProductName':"", 'ModelName':"Model", 'MajorMinorRevision':"1.0" }, } #print("Liste des signature : ") #-affichagesignature(dico) #i = demandeobligatoire("Quelle signature voulez vous utiliser ?","int") i = 0 identity = ModbusDeviceIdentification() identity.VendorName = dico[i]['VendorName'] identity.ProductCode = dico[i]['ProductCode'] identity.VendorUrl = dico[i]['VendorUrl'] identity.ProductName = dico[i]['ProductName'] identity.ModelName = dico[i]['ModelName'] identity.MajorMinorRevision = dico[i]['MajorMinorRevision'] #---------------------------------------------------------------------------# # run the server you want #---------------------------------------------------------------------------# # Tcp: log.info("TcpServer START") StartTcpServer(context, identity=identity, address=("localhost", 502)) log.info("[ %s ] TcpServer STOP", time.asctime()) # Udp: #StartUdpServer(context, identity=identity, address=("localhost", 502))
logging.basicConfig() log = logging.getLogger("OpcToModbus") log.setLevel(logging.INFO) # You may change this for production depoy # Host address of the OPC Server opc_host = "opc.tcp://localhost:4840/freeopcua/server/" # Host adress for the Modbus Server modbus_host = "localhost" modbus_port = 5020 # Modbus server information identity = ModbusDeviceIdentification() identity.VendorName = 'Fuinha11' identity.ProductCode = 'POTM' identity.VendorUrl = 'https://github.com/Fuinha11' identity.ProductName = 'OPC to Modbus' identity.ModelName = 'O2M0.1' identity.MajorMinorRevision = '0.0.1' # Time between updates in sec update_inteval = 1.5 # ----------------------------------------------------------------------- # # End of Configuration # ----------------------------------------------------------------------- # opc_client: Client def initiate_client():
#---------------------------------------------------------------------------# # initialize data store #---------------------------------------------------------------------------# store = ModbusSlaveContext( di = ModbusSequentialDataBlock(0, [17]*100), co = ModbusSequentialDataBlock(0, [17]*100), hr = ModbusSequentialDataBlock(0, [17]*100), ir = ModbusSequentialDataBlock(0, [17]*100)) context = ModbusServerContext(slaves=store, single=True) #---------------------------------------------------------------------------# # initialize the server information #---------------------------------------------------------------------------# identity = ModbusDeviceIdentification() identity.VendorName = 'ZXL' identity.ProductCode = 'PLC' identity.VendorUrl = 'https://github.com/zxlin/Modbus-PLC-Simulator' identity.ProductName = 'PLC-Sim' identity.ModelName = 'Modbus-Server' identity.MajorMinorRevision = '1.0' #---------------------------------------------------------------------------# # Start running the server #---------------------------------------------------------------------------# # time = 5 # loop = LoopingCall(f=updating_writer, a=(context,)) # loop.start(time, now=False) StartTcpServer(context, identity=identity, address=(server_address, server_port))
def run_updating_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 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) # ''' # __fx_mapper = {2: 'd', 4: 'i'} # __fx_mapper.update([(i, 'h') for i in [3, 6, 16, 22, 23]]) # __fx_mapper.update([(i, 'c') for i in [1, 5, 15]]) # ''' # ----------------------------------------------------------------------- # store = ModbusSlaveContext( # di=ModbusSequentialDataBlock(1000, [1]*287), co=ModbusSequentialDataBlock(1000, [0] * 287), # hr=ModbusSequentialDataBlock(0, [17] * 100), # ir=ModbusSequentialDataBlock(0, [17] * 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.5' # ----------------------------------------------------------------------- # # run the server you want # ----------------------------------------------------------------------- # # TCP Serverq # StartXMLClient # StartTcpServer time = 3 # 1 seconds delay modbus_addr = "0.0.0.0", 5020 loop = LoopingCall(f=updating_writer, a=(context, )) loop.start(time, now=False) # initially delay by time StartTcpServer(context, identity=identity, address=modbus_addr)
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({ # aux soc 0x101: 0b01011111, # aux v 0x102: 141, # 0.1V # aux a 0x103: 3309, # 0.01A # controller temperature 0x104: 0b0001010100001111, # H: ctrl temp, L: battery temp sensor # altenator voltage 0x105: 146, # 0.1V # altenator amps 0x106: 4000, #0.01A # altenator watts 0x107: 496, # solar v 0x108: 304, # solar a 0x109: 20, # solar w 0x10A: 6684, 0x10B: 0, # lowest battery V in day 0x10C: 108, # 0.1 # max battery V in day 0x10D: 144, # max battery A in day 0x10E: 5000, #0.01A 0x10F: 0, 0x110: 0, 0x111: 0, 0x112: 0, 0x113: 0, 0x114: 0, 0x115: 0, # running day count 0x116: 1, 0x117: 0, # number of times battery is full in day 0x118: 3, 0x119: 0, 0x11A: 0, 0x11B: 0, 0x11C: 0, 0x11D: 0, 0x11E: 0, 0x11F: 0, 0x120: 0, # charge state (L) 0x121: 0b0000000010001010, 0x122: 0, 0x123: 0, }) # 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:: # store = ModbusSlaveContext(hr=block, ir=block) 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/riptideio/pymodbus/' identity.ProductName = 'Pymodbus Server' identity.ModelName = 'Pymodbus Server' identity.MajorMinorRevision = version.short() StartSerialServer( context, framer=ModbusRtuFramer, identity=identity, port='/dev/ttyUSB0', timeout=.05, baudrate=9600, stopbits=2, bytesize=8)
if reactor.running: reactor.callFromThread(reactor.stop) store = ModbusSlaveContext( di = ModbusSequentialDataBlock(0, [0]*100), co = ModbusSequentialDataBlock(0, [0]*100), hr = ModbusSequentialDataBlock(0, [0]*100), ir = ModbusSequentialDataBlock(0, [0]*100)) context = ModbusServerContext(slaves=store, single=True) # Modbus PLC server information identity = ModbusDeviceIdentification() identity.VendorName = 'Simmons Oil Refining Platform' identity.ProductCode = 'SORP' identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' identity.ProductName = 'SORP 3850' identity.ModelName = 'Simmons ORP 3850' identity.MajorMinorRevision = '2.09.01' def startModbusServer(): # Run a modbus server on specified address and modbus port (5020) StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) def main(): reactor.callInThread(run_world) startModbusServer() if __name__ == '__main__': sys.exit(main())
def run_updating_server(config_in, config_section=None): """ This function updates all the registers of each type contained in the config file to their specified initial value. :param config_in: YAML config file containing all settings (see example) :param config_section: section settings are under :returns: Nothing """ # read config file if (config_section==None): modbus_section = 'server' with open(config_in) as f: # use safe_load instead load modbusConfig = yaml.safe_load(f) PORT = modbusConfig[modbus_section]['port'] DEFINED_BLOCK = modbusConfig[modbus_section]['use_block_size'] slave_id = modbusConfig[modbus_section]['slave_id'] update_time = modbusConfig[modbus_section]['update_time'] random_range = modbusConfig[modbus_section]['random_range'] ramp_slope = modbusConfig[modbus_section]['ramp_slope'] holding_float_dict = modbusConfig[modbus_section]['float_holding'] holding_int32_dict = modbusConfig[modbus_section]['int32_holding'] holding_int16_dict = modbusConfig[modbus_section]['int16_holding'] input_float_dict = modbusConfig[modbus_section]['float_input'] input_int32_dict = modbusConfig[modbus_section]['int32_input'] input_int16_dict = modbusConfig[modbus_section]['int16_input'] coil_dict = modbusConfig[modbus_section]['coil_registers'] discrete_dict = modbusConfig[modbus_section]['discrete_registers'] if (DEFINED_BLOCK == True): # User has defined a custom block and offset, read the settings # from the config file. print("block size is user defined") coil_block_size = modbusConfig[modbus_section]['coil_block_size'] coil_block_offset = modbusConfig[modbus_section]['coil_block_offset'] discrete_block_size = modbusConfig[modbus_section]['discrete_block_size'] discrete_block_offset = modbusConfig[modbus_section]['discrete_block_offset'] holding_block_size = modbusConfig[modbus_section]['holding_block_size'] holding_block_offset = modbusConfig[modbus_section]['holding_block_offset'] input_block_size = modbusConfig[modbus_section]['holding_block_size'] input_block_offset = modbusConfig[modbus_section]['holding_block_offset'] else: print("use auto calulcator") # Calculate size needed for each register type holding_block_size = len(holding_float_dict)*2 holding_block_size += len(holding_int32_dict)*2 holding_block_size += len(holding_int16_dict)*1 input_block_size = len(input_float_dict)*2 input_block_size += len(input_int32_dict)*2 input_block_size += len(input_int16_dict)*1 discrete_block_size = len(discrete_dict) coil_block_size = len(coil_dict) coil_block_offset = 0 discrete_block_offset = 0 holding_block_offset = 0 input_block_offset = 0 # ----------------------------------------------------------------------- # # initialize data store according to config file # ----------------------------------------------------------------------- # store = ModbusSlaveContext( di=ModbusSequentialDataBlock(discrete_block_offset, [0]*discrete_block_size), co=ModbusSequentialDataBlock(coil_block_offset, [0]*coil_block_size), hr=ModbusSequentialDataBlock(holding_block_offset, [0]*holding_block_size), ir=ModbusSequentialDataBlock(input_block_offset, [0]*input_block_size)) 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' #slave_id = 0x00 # Set all registers to their initial value as specified in config file initialize_registers(context,slave_id,holding_float_dict,holding_int32_dict, holding_int16_dict,input_float_dict,input_int32_dict,input_int16_dict, coil_dict, discrete_dict) # Set updating time and call updating writer inside a loop accorind to interval # time time = update_time loop = LoopingCall(f=updating_writer, context=(context),slave_id=(slave_id), holding_float_dict=(holding_float_dict), holding_int32_dict=(holding_int32_dict), holding_int16_dict=(holding_int16_dict), input_float_dict=(input_float_dict), input_int32_dict=(input_int32_dict), input_int16_dict=(input_int16_dict), coil_dict=(coil_dict), discrete_dict=(discrete_dict), random_range=(random_range), ramp_slope=(ramp_slope)) loop.start(time, now=False) # initially delay by time # Setting address to 127.0.0.1 allows only the local machine to access the # Server. Changing to 0.0.0.0 allows for other hosts to connect. StartTcpServer(context, identity=identity, address=("0.0.0.0", 5020))
############################################################################### # Modbus Datastore Configuration ############################################################################### store = ModbusSlaveContext( di = ModbusSequentialDataBlock(0, [17]*100), co = ModbusSequentialDataBlock(0, [17]*100), hr = ModbusSequentialDataBlock(0, [17]*100), ir = ModbusSequentialDataBlock(0, [17]*100)) context = ModbusServerContext(slaves=store, single=True) identity = ModbusDeviceIdentification() identity.VendorName = 'ITI' identity.ProductCode = 'PM' identity.VendorUrl = 'code.iti.illinois.edu' identity.ProductName = 'Server Instance' identity.ModelName = 'ITI Test' identity.MajorMinorRevision = '1.0' ############################################################################### # Functions ############################################################################### def validateIface(iface): if not (iface in netifaces.interfaces()): print iface + " is not a valid interface" exit()
# ------------------------------------------------------------ from pymodbus.server.async import ModbusServerFactory from pymodbus.constants import Defaults from pymodbus.device import ModbusDeviceIdentification from pymodbus.datastore import ModbusSequentialDataBlock from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext from twisted.internet import reactor # ------------------------------------------------------------ # initialize the identity # ------------------------------------------------------------ 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' # ------------------------------------------------------------ # initialize the datastore # ------------------------------------------------------------ store = ModbusSlaveContext( di = ModbusSequentialDataBlock(0, [17]*100), co = ModbusSequentialDataBlock(0, [17]*100), hr = ModbusSequentialDataBlock(0, [17]*100), ir = ModbusSequentialDataBlock(0, [17]*100)) context = ModbusServerContext(slaves=store, single=True) # ------------------------------------------------------------
#---------------------------------------------------------------------------# store = ModbusSlaveContext(di=ModbusSequentialDataBlock(0, [17] * 100), co=ModbusSequentialDataBlock(0, [17] * 100), hr=ModbusSequentialDataBlock(0, [17] * 100), ir=ModbusSequentialDataBlock(0, [17] * 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/riptideio/pymodbus/' identity.ProductName = 'Pymodbus Server' identity.ModelName = 'Pymodbus Server' identity.MajorMinorRevision = '1.0' #---------------------------------------------------------------------------# # run the server you want #---------------------------------------------------------------------------# # Tcp: StartTcpServer(context, identity=identity, address=("localhost", 502)) # Udp: #StartUdpServer(context, identity=identity, address=("localhost", 502)) # Ascii: #StartSerialServer(context, identity=identity, port='/dev/pts/3', timeout=1)
def run_async_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 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, [17]*100), #co=ModbusSequentialDataBlock(0, [17]*100), hr=ModbusSequentialDataBlock(0, [18] * 3) #ir=ModbusSequentialDataBlock(0, [17]*100)) #store.register(CustomModbusRequest.function_code, 'cm', #ModbusSequentialDataBlock(0, [17] * 100) ) context = ModbusServerContext(slaves=store, single=True) # DI: functie 1; coil status (Modbus Doctor)? # CO: Input status? COIL? # HR: Holding Register # IR: Input Register # What are we doing here: set address value 0 (1 in Modbus Docter?) # Holding Register starts at 40000. So, address 400001. # 30000 is for Input Register. # # Examples include setting 100 * 17 in a list. These are 100 # registers. On address 0, (1, 40001) there are 100 register # values. # # Register 'should' start at index 1 (40001), so example: # hr=ModbusSequentialDataBlock(0, [18]*2) writes 18 at the 40001 position (and 40000?) # # Example write by Modbus Doctor # Green little balls: bits (yes/no) # Purple little balls: value of the entire register (16 bits) # # The green ones affect the values in the entire register # # Bit 0: Ledstrip On/Off (40001.0) # Bit 1: Ledstrip fixed color (40001.1) # If bit 1 is set, read the following addresses # 40002: R; 40003: G; 40004: B; # So, reading continuously from the 40002, 3, 4; # Update the values for RGB 'in the background' # Update the ledstrip when values change # Bit 2: Activate rainbow (40001.2) # Bit 3: Activate color mix / strandtest (40001.3) # 40005: number of leds to use; # Only read at the start of ledstrip initialization # 40006: brightness to set # Only read at the start of ledstrip initialization # 40007: LED pin (digital pin) # Only read at the start of ledstrip initialization # Add handling of UNITs (devices, device addresses) # See https://github.com/riptideio/pymodbus/blob/master/examples/common/asynchronous_server.py#L77 # Idea is to run 'multiple instances' of the ledstrip for different # contexts / hardware. The logic is exactly the same, only the # 'database' of values stores is different. # 40008: Which program should be active # Value 1, 2, 3, (etc) # 1: fixed color, 2: rainbow, 3: color mix # # Look into CustomModbusRequest for handling data changes # See ModbusTcpServer.StartTCPServer logging functionality # Also see request.execute; https://github.com/riptideio/pymodbus/blob/13de8ab0a840d04b41cf53b9aaa98875d96ac5ec/pymodbus/server/async.py#L58 # Framer, decoder, custom_functions, custom messages # https://github.com/riptideio/pymodbus/blob/2ef91e9e565b10fc9abc0840c87cf4a29f3d9bbf/pymodbus/server/asynchronous.py#L233 # # Proposed solution: create LedstripRequest, extending ModbusRequest # Override the default function code (3), register the LedstripRequest, # override the execute funtion to react to specific data changes on specific # addresses, store data from the changed data from registers in local variables # update the ledstrip code to lookup values from local variables and react to # changes # # Bit values are on/off; react to on/off states. Toggle function. # No function active: ledstip should shutdown # # ----------------------------------------------------------------------- # # initialize the server information # ----------------------------------------------------------------------- # # If you don't set this or any fields, they are defaulted to empty strings. # ----------------------------------------------------------------------- # identity = ModbusDeviceIdentification() identity.VendorName = 'hslatman' identity.ProductCode = 'MLS' identity.VendorUrl = 'https://github.com/hslatman/ledstrip' identity.ProductName = 'ModLed Server' identity.ModelName = 'ModLed X' identity.MajorMinorRevision = '0.1.0' # ----------------------------------------------------------------------- # # run the server you want # ----------------------------------------------------------------------- # # TCP Server # StartTcpServer(context, identity=identity, address=("0.0.0.0", 502), # custom_functions=[CustomModbusRequest]) #StartTcpServer(context, identity=identity, address=("0.0.0.0", 502)) StartTcpServer(context, identity=identity, address=("0.0.0.0", 502), custom_functions=[LedstripControlRequest])
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(0, [17]*100), co=ModbusSequentialDataBlock(0, [17]*100), hr=ModbusSequentialDataBlock(0, [17]*100), ir=ModbusSequentialDataBlock(0, [17]*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/riptideio/pymodbus/' identity.ProductName = 'Pymodbus Server' identity.ModelName = 'Pymodbus Server' identity.MajorMinorRevision = '2.2.0' # ----------------------------------------------------------------------- # # run the server you want # ----------------------------------------------------------------------- # # Tcp: StartTcpServer(context, identity=identity, address=("localhost", 5020))
# enable debugging information if opt.debug: try: _logger.setLevel(logging.DEBUG) except Exception, e: print "Logging is not supported on this system" # Create store context store = ModbusSlaveContext( di = ModbusSequentialDataBlock(0, [17]*100), co = ModbusSequentialDataBlock(0, [17]*100), hr = ModbusSequentialDataBlock(0, [17]*100), ir = ModbusSequentialDataBlock(0, [17]*100)) context = ModbusServerContext(slaves=store, single=True) identity = ModbusDeviceIdentification() identity.VendorName = 'Pymodbus' identity.ProductCode = 'PM' identity.VendorUrl = 'http://unipi.technology' identity.ProductName = 'Pymodbus Server on IOLoop' identity.ModelName = 'Pymodbus Server' identity.MajorMinorRevision = '1.0' StartTcpServer(context, identity=identity, address=("localhost", 5020)) if __name__ == '__main__': main()
from pymodbus.device import ModbusDeviceIdentification from pymodbus.datastore import ModbusSequentialDataBlock from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext # Create a datastore and populate it with test data store = ModbusSlaveContext( di=ModbusSequentialDataBlock( 0, [17] * 100), # Initialisation des Discrete Inputs (booléens en lecture seule) co=ModbusSequentialDataBlock( 0, [17] * 100), # Initialisation des Coils (booléens en lecture/écriture) hr=ModbusSequentialDataBlock( 0, [17] * 100 ), # Initialisation des Holding Register ( nombres entiers en lecture/écriture) ir=ModbusSequentialDataBlock( 0, [17] * 100)) # Initialisation des Input Registers (entiers en lecture seule) context = ModbusServerContext(slaves=store, single=True) # Ces champs sont renvoyés par le serveur au client identity = ModbusDeviceIdentification() identity.VendorName = 'PyModbus Inc.' identity.ProductCode = 'PM' identity.VendorUrl = 'https://github.com/riptideio/pyModbus' identity.ProductName = 'Modbus Server' identity.ModelName = 'PyModbus' identity.MajorMinorRevision = '1.0' print("Démarrage du serveur Modbus:") StartTcpServer(context, identity=identity, address=("0.0.0.0", 502))
store = ModbusSlaveContext(di=di, co=co, hr=hr, ir=ir) context = ModbusServerContext(slaves=store, single=True) return context #---------------------------------------------------------------------------# # initialize the server information #---------------------------------------------------------------------------# # If you don't set this or any fields, they are defaulted to empty strings. #---------------------------------------------------------------------------# identity = ModbusDeviceIdentification() identity.VendorName = 'VOLTTRON' identity.ProductCode = 'VT' identity.VendorUrl = 'http://github.com/VOLTTRON/volttron' identity.ProductName = 'VOLTTRON Modbus Test Device' identity.ModelName = 'VOLTTRON Modbus Test Device' identity.MajorMinorRevision = '1.0' abstraction = DeviceAbstraction(args.config) #Create the deamon as soon as we've loaded the device configuration. if not args.no_daemon: createDaemon() context = abstraction.get_server_context() #---------------------------------------------------------------------------# # run the server you want #---------------------------------------------------------------------------#
''' Asynchronous Modbus Server Built in Python using the pyModbus module ''' # Import the libraries we need from pymodbus.server.asynchronous import StartTcpServer #from pymodbus.server.asynchronous import StartTcpServer from pymodbus.device import ModbusDeviceIdentification from pymodbus.datastore import ModbusSequentialDataBlock from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext # Create a datastore and populate it with test data store = ModbusSlaveContext( di=ModbusSequentialDataBlock(0, [17] * 100), # Discrete Inputs initializer co=ModbusSequentialDataBlock(0, [17] * 100), # Coils initializer hr=ModbusSequentialDataBlock(0, [17] * 100), # Holding Register initializer ir=ModbusSequentialDataBlock(0, [17] * 100)) # Input Registers initializer context = ModbusServerContext(slaves=store, single=True) # Populate the Modbus server information fields, these get returned as # response to identity queries identity = ModbusDeviceIdentification() identity.VendorName = 'ModbusTagServer' identity.ProductCode = 'ModbusTagServer' identity.VendorUrl = 'https://github.com/gilzin' identity.ProductName = 'ModbusTagServer' identity.ModelName = 'PyModbus' identity.MajorMinorRevision = '1.0' # Start the listening server print("Starting Modbus server...") StartTcpServer(context, identity=identity, address=("0.0.0.0", 502))
def run_async_server(): """ The main loop instantiates one or more PyModbus servers mapped to ClearBlade Modbus proxies based on IP address and port defined in a ClearBlade platform Collection """ log = None virtual_ifs = [] err_msg = None defer_reactor = False try: parser = get_parser() user_options = parser.parse_args() local_ip_address = user_options.ip_address local_tcp_port = user_options.tcp_port net_if = user_options.net_if if user_options.log_level == 'DEBUG': _debug = True else: _debug = False HEARTBEAT = user_options.heartbeat log = headless.get_wrapping_logger(name=ADAPTER_DEVICE_ID, debug=_debug) server_log = headless.get_wrapping_logger(name="pymodbus.server", debug=_debug) log.info("Initializing ClearBlade System connection") cb_system = System(systemKey=user_options.systemKey, systemSecret=user_options.systemSecret, url=user_options.url) cb_auth = cb_system.Device(name=user_options.deviceName, key=user_options.deviceKey) cb_slave_config = user_options.slaves_collection cb_data = user_options.data_collection ip_proxies = [] proxy_ports = [] ip_address = None collection = cb_system.Collection(cb_auth, collectionName=cb_slave_config) query = Query() query.notEqualTo(COL_PROXY_IP_ADDRESS, '') rows = collection.getItems(query) for row in rows: # TODO: allow for possibility of multiple IPs with same port or same IP with multiple ports ip_address = str(row[COL_PROXY_IP_ADDRESS]) tcp_port = int(row[COL_PROXY_IP_PORT]) if ip_address not in ip_proxies: log.info("Found slave at {} on ClearBlade adapter config".format(ip_address)) ip_proxies.append(ip_address) proxy_ports.append(tcp_port) else: log.warning("Duplicate proxy IP address {} found in configuration - ignoring".format(ip_address)) log.debug("Processing {} slaves".format(len(ip_proxies))) for i in range(0, len(ip_proxies)): log.debug("Getting server context for {}".format(ip_proxies[i])) context = ClearBladeModbusProxyServerContext(cb_system=cb_system, cb_auth=cb_auth, cb_slaves_config=cb_slave_config, cb_data=cb_data, ip_address=ip_proxies[i], log=log) # Create IP aliases local_ip_address = ip_proxies[i] ip_mask = '255.255.255.0' local_tcp_port = proxy_ports[i] if sys.platform.startswith('win'): log.info("I'm on Windows!") local_ip_address = 'localhost' elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'): virtual_if = '{nif}:{alias}'.format(nif=net_if, alias=i) virtual_ifs.append(virtual_if) linux_command = "ifconfig {vif} {ip}".format(vif=virtual_if, ip=local_ip_address) if ip_mask is not None: linux_command += " netmask {mask}".format(mask=ip_mask) log.info("Creating virtual IP address / alias via $ {}".format(linux_command)) subprocess.call(linux_command, shell=True) # Create Server Identification identity = ModbusDeviceIdentification() identity.VendorName = 'PyModbus' identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' identity.ProductName = 'Inmarsat/ClearBlade Modbus Server Adapter' identity.ModelName = ip_proxies[i] identity.MajorMinorRevision = '1.0' # Setup Modbus TCP Server log.info("Starting Modbus TCP server on {}:{}".format(local_ip_address, local_tcp_port)) modbus_server_args = { 'context': context, 'identity': identity, 'address': (local_ip_address, local_tcp_port), # 'console': _debug, 'defer_reactor_run': True, } if modbus_server_args['defer_reactor_run']: defer_reactor = True reactor.callInThread(StartTcpServer, **modbus_server_args) if local_ip_address == 'localhost': log.info("Windows retricted environment prevents IP alias - running localhost for {}" .format(ip_proxies[i])) break reactor.callInThread(_heartbeat, log, time.time(), HEARTBEAT) if defer_reactor: reactor.suggestThreadPoolSize(len(ip_proxies)) reactor.run() except KeyboardInterrupt: err_msg = "modbus_server_adapter.py halted by Keyboard Interrupt" if log is not None: log.info(err_msg) else: print(err_msg) sys.exit("modbus_server_adapter.py halted by Keyboard Interrupt") except Exception as e: err_msg = "EXCEPTION: {}".format(e) if log is not None: log.info(err_msg) else: print(err_msg) sys.exit("modbus_server_adapter.py halted by exception {}".format(e)) finally: if defer_reactor and reactor.running: reactor.stop() for vif in virtual_ifs: debug_msg = "Taking down virtual interface {}".format(vif) if log is not None: log.debug(debug_msg) else: print(debug_msg) linux_command = "ifconfig {} down".format(vif) subprocess.call(linux_command, shell=True) print("Exiting...")