def run_simulation_server(): # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # store = ModbusSlaveContext( co=ModbusSparseDataBlock({100: 0, 110: 0, 120: 0, 130: 0,}),#initiate Coils di=ModbusSparseDataBlock({100: 0, 110: 0}), #initiate discrete inputs ir=ModbusSparseDataBlock({100: 0, 110: 0, 120:0, 130:0, 140:0}), #initiate input registers hr=ModbusSparseDataBlock({100: 60000, 110: 10000, 120:655}), zero_mode=True) #initiate holding registers context = ModbusServerContext(slaves=store, single=True) # ----------------------------------------------------------------------- # # initialize the server information # ----------------------------------------------------------------------- # identity = ModbusDeviceIdentification() identity.VendorName = 'akiUP' identity.ProductCode = 'IOP' identity.VendorUrl = 'https://github.com/akiUp/ICSonPySim' identity.ProductName = 'ICSonPy' identity.ModelName = 'ICS Simulation' identity.MajorMinorRevision = '0.0.1' # ----------------------------------------------------------------------- # # run the Modbus Server with looping call of simulation # ----------------------------------------------------------------------- # time = 0.1 # process frequency delay in seconds, increase if you want to slow down the process loop = LoopingCall(f=Process, mbcontext=(context,)) # Main caleer function continiously calls the Process() function loop.start(time, now=False) # initially delay by time StartTcpServer(context, identity=identity, address=("0.0.0.0", 502))
def __init__(self, address, port): self.holding_register_block = HoldingRegisterDataBlock.create() self.coil_block = ModbusSparseDataBlock.create() self.input_register_block = ModbusSparseDataBlock.create() self.store = ModbusSlaveContext(co=self.coil_block, hr=self.holding_register_block) self.context = ModbusServerContext(slaves=self.store, single=True) self.server = ModbusTcpServer(self.context, address=(address, port)) self.thread = threading.Thread(target=self.__run_thread__, args=())
def __init__(self, system_settings): """ Modified StartTcpServer from pymodbus.server.sync .. warning:: DO NOT CHANGE START TCP SERVER SECTION! VERY SENSITIVE! """ identity = ModbusDeviceIdentification() identity.VendorName = system_settings['company'] identity.ProductCode = system_settings['product'] identity.VendorUrl = system_settings['url'] identity.ProductName = system_settings['product'] identity.ModelName = system_settings['version'] identity.MajorMinorRevision = system_settings['version'] framer = ModbusSocketFramer if MODBUS_FILL_EMPTY_DATA: slave = ModbusSlaveContext() else: # TODO: Complete this feature! Does not work properly at the moment! empty_block = ModbusSparseDataBlock({0x00: 0x00}) slave = ModbusSlaveContext(di=empty_block, co=empty_block, hr=empty_block, ir=empty_block) # LOGGER.debug("slave.store = " + str(slave.store)) context = ModbusServerContext(slaves=slave, single=True) self.server = ModbusTcpServer(context, framer) self.server.RequestHandlerClass = CustomModbusHandler super(ModbusProcess, self).__init__(target=self.server.serve_forever)
def __configure_and_run_slave(config): identity = None if config.get('identity'): identity = ModbusDeviceIdentification() identity.VendorName = config['identity'].get('vendorName', '') identity.ProductCode = config['identity'].get('productCode', '') identity.VendorUrl = config['identity'].get('vendorUrl', '') identity.ProductName = config['identity'].get('productName', '') identity.ModelName = config['identity'].get('ModelName', '') identity.MajorMinorRevision = version.short() blocks = {} for (key, value) in config.get('values').items(): values = {} converter = BytesModbusDownlinkConverter({}) for item in value: for section in ('attributes', 'timeseries', 'attributeUpdates', 'rpc'): for val in item.get(section, []): function_code = FUNCTION_CODE_WRITE[key][0] if val['objectsCount'] <= 1 else \ FUNCTION_CODE_WRITE[key][1] converted_value = converter.convert( {**val, 'device': config.get('deviceName', 'Gateway'), 'functionCode': function_code, 'byteOrder': config['byteOrder']}, {'data': {'params': val['value']}}) values[val['address'] + 1] = converted_value blocks[FUNCTION_TYPE[key]] = ModbusSparseDataBlock(values) context = ModbusServerContext(slaves=ModbusSlaveContext(**blocks), single=True) SLAVE_TYPE[config['type']](context, identity=identity, address=(config.get('host'), config.get('port')) if ( config['type'] == 'tcp' or 'udp') else None, port=config.get('port') if config['type'] == 'serial' else None, framer=FRAMER_TYPE[config['method']])
def __init__(self, serial_port='/dev/pts/4', json_device_desc_path=DEVICE_JSON_DESC_PATH): threading.Thread.__init__(self, name='MockTracerBN2') self._serial_port = serial_port # Build data backing store from json file. mappings = json_mapping_parser(json_device_desc_path) store = ModbusSlaveContext(di=ModbusSparseDataBlock(mappings['di']), co=ModbusSparseDataBlock(mappings['co']), ir=ModbusSparseDataBlock(mappings['ir']), hr=ModbusSparseDataBlock(mappings['hr'])) identity = initialise_device_identity(mappings) context = ModbusServerContext(slaves=store, single=True) # RTU: self.server = ModbusSerialServer(context, framer=ModbusRtuFramer, identity=identity, port=self._serial_port, timeout=0.001, baudrate=115200)
def run_updating_server(): # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # store1 = ModbusSlaveContext(di=ModbusSparseDataBlock({0x10: 12}), cp=ModbusSparseDataBlock({0x10: 13}), hr=ModbusSparseDataBlock({0x10: 14}), ir=ModbusSparseDataBlock({0x100: 7000})) store2 = ModbusSlaveContext(di=ModbusSparseDataBlock({0x10: 12}), cp=ModbusSparseDataBlock({0x10: 13}), hr=ModbusSparseDataBlock({0x10: 14}), ir=ModbusSparseDataBlock({0x100: 7000})) slaves = { 28: ModbusSlaveContext(slaves=store1), 48: ModbusSlaveContext(slaves=store2) } context = ModbusServerContext(slaves=slaves, 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 = 0.1 loop = LoopingCall(f=updating_writer, a=(context, )) loop.start(time, now=False) # initially delay by time StartTcpServer(context, identity=identity, address=("0.0.0.0", 5020))
def main(args): # for test get the server parameters and test data from the test database db = dbfn.db("../db.sqlite3") test_params = db.getParams(site=args.site) db.close() db = dbfn.db("../test.sqlite3") #q_test_params = "SELECT {cols} from test_params where id = ?" #cols = ["id","modbus_servers", "field_name"] #test_params = db.getColDict( q_test_params, cols, (args.test, ) ) #print(test_params) q_data = "select key, value from test_data where site = ? and test = ? order by seq" test_val = db.getRowDict(q_data, (args.site, args.test)) #print(test_val) #q_limit = "select key, match_type from test_data where test = ?" #test_limit = db.getRowDict(q_limit, (args.test, ) ) #print(test_limit) db.close() # based on test server parameter load the serer details from the main database #load server details db = dbfn.db("../db.sqlite3") #print(params) #db.close() store = dict() #registers = dict() unit_map = dict() print(test_params["modbus_servers"]) for s in test_params["modbus_servers"].split(","): server = int(s) params = db.getConnectionParams(server) if params["unit"] not in unit_map: unit_map[params["unit"]] = dict() section = db.getDataFormat(server, 0) registers = make_block(section, test_val, test_params, params['start_address']) unit_map[params["unit"]][params['start_address']] = registers print(unit_map) data = dict() for u in unit_map: for start_address in unit_map[u]: print("Address:", u, start_address) for x in range(len(unit_map[u][start_address])): print(x, unit_map[u][start_address][x]) data[start_address + x + 1] = unit_map[u][start_address][x] print(data) block = ModbusSparseDataBlock(data) store1 = ModbusSlaveContext( di=ModbusSequentialDataBlock(0, [15] * 10), co=ModbusSequentialDataBlock(0, [115] * 10), hr=block, ir=ModbusSequentialDataBlock(0, [215] * 10)) store[params["unit"]] = store1 db.close() context = ModbusServerContext(slaves=store, single=False) #for k in store: # print(k) # print(context[k]) #print("CTX", context) for s in context: print("********************Slave", s) 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' print("Starting Server at:", params["port"]) StartTcpServer(context, identity=identity, address=("localhost", params["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))
__author__ = 'Anton Glukhov' import random from regs import * from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSparseDataBlock block_disc_a = ModbusSequentialDataBlock(regs_ksk["REG_DISC_A"], [0]*25) block_coils_a = ModbusSequentialDataBlock(regs_ksk["REG_COILS_A"], [1]*18) block_input_a = ModbusSequentialDataBlock(regs_ksk["REG_INPUT_A"], [random.randint(0,100) for x in range(92)]) block_holding_a = ModbusSequentialDataBlock(regs_ksk["REG_HOLDING_A"], [random.randint(0,100) for x in range(8)]) block_disc_b1 = ModbusSequentialDataBlock(regs_umn["REG_DISC_B"], [0]*8) block_coils_b1 = ModbusSparseDataBlock({0x0083: 1, 0x0100: 1, 0x0101: 0, 0x0102: 1, 0x0103: 1}) block_input_b1 = ModbusSequentialDataBlock(regs_umn["REG_INPUT_B"], [random.randint(0,100) for x in range(len(10))]) block_holding_b1 = ModbusSequentialDataBlock(regs_umn["REG_HOLDING_B"], [random.randint(0,100) for x in range(len(10))]) block_disc_b2 = ModbusSequentialDataBlock(regs_umn["REG_DISC_B"], [1]*8) block_coils_b2 = ModbusSparseDataBlock({0x0083: 1, 0x0100: 1, 0x0101: 0, 0x0102: 1, 0x0103: 1}) block_input_b2 = ModbusSequentialDataBlock(regs_umn["REG_INPUT_B"], [random.randint(0,100) for x in range(17)]) block_holding_b2 = ModbusSequentialDataBlock(regs_umn["REG_HOLDING_B"], [random.randint(0,100) for x in range(3)]) block_disc_b3 = ModbusSequentialDataBlock(regs_umn["REG_DISC_B"], [1]*8) block_coils_b3 = ModbusSparseDataBlock({0x0083: 1, 0x0100: 1, 0x0101: 0, 0x0102: 1, 0x0103: 1}) block_input_b3 = ModbusSequentialDataBlock(regs_umn["REG_INPUT_B"], [random.randint(0,100) for x in range(5)]) block_holding_b3 = ModbusSequentialDataBlock(regs_umn["REG_HOLDING_B"], [random.randint(0,100) for x in range(2)])
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)
def parse_template(self): if self.template == 'DEFAULT': file = DEFAULT_TEMPLATE else: # TODO: validate and open file as string file = DEFAULT_TEMPLATE lines = file.splitlines() for line in lines: if line[0:len(TEMPLATE_PARSER_DESC)] == TEMPLATE_PARSER_DESC: id = line.split(TEMPLATE_PARSER_SEPARATOR) for i in id: if i[0:len('VendorName')] == 'VendorName': self.identity.VendorName = i[len('VendorName') + 1:] elif i[0:len('ProductCode')] == 'ProductCode': self.identity.ProductCode = i[len('ProductCode') + 1:] elif i[0:len('VendorUrl')] == 'VendorUrl': self.identity.VendorUrl = i[len('VendorUrl') + 1:] elif i[0:len('ProductName')] == 'ProductName': self.identity.ProductName = i[len('ProductName') + 1:] elif i[0:len('ModelName')] == 'ModelName': self.identity.ModelName = i[len('ModelName') + 1:] elif i[0:len('MajorMinorRevision' )] == 'MajorMinorRevision': self.identity.MajorMinorRevision = i[ len('MajorMinorRevision') + 1:] elif i[0:len('sparse')].lower() == 'sparse': self.sparse = bool(int(i[len('sparse') + 1:])) if self.template == 'DEFAULT': self.identity.MajorMinorRevision = pymodbus_version elif line[0:len(TEMPLATE_PARSER_NETWORK )] == TEMPLATE_PARSER_NETWORK: net_info = line.split(TEMPLATE_PARSER_SEPARATOR) for i in net_info: if i[0:len('networkId')] == 'networkId': net_id = int(i[len('networkId') + 1:]) if net_id in range(1, 254): self.slave_id = int(i[len('networkId') + 1:]) else: log.error("Invalid Modbus Slave ID {id}".format( id=net_id)) elif i[0:len('plcBaseAddress')] == 'plcBaseAddress': plc = int(i[len('plcBaseAddress') + 1:]) self.zero_mode = False if plc == 1 else True elif line[0:len(TEMPLATE_PARSER_PORT)] == TEMPLATE_PARSER_PORT: port_info = line.split(TEMPLATE_PARSER_SEPARATOR) for i in port_info: if i[0:len('port')] == 'port': log.info("port={port}".format(port=i[len('port') + 1:])) port = i[len('port') + 1:].lower() if port in ['tcp', 'udp']: self.port = port elif port in list_serial_ports(): self.ser_config = SerialPort() else: raise EnvironmentError( "Undefined port read from {template}".format( template=self.template)) elif i[0:len('mode')] == 'mode': log.info("mode={mode}".format(mode=i[len('mode') + 1:])) self.mode = i[len('mode') + 1:] if self.mode not in ['rtu', 'ascii', 'tcp']: log.error( "Undefined mode parsed from {template}".format( template=self.template)) raise EnvironmentError( "Undefined Modbus mode read from {template}". format(template=self.template)) elif i[0:len('baudRate')] == 'baudRate': log.info("baudRate={baudRate}".format( baudRate=i[len('baudRate') + 1:])) baudrate = int(i[len('baudRate') + 1:]) if baudrate in self.ser_config.baudrates: self.ser_config.baudrate = baudrate else: log.error("Unsupported baud rate {baud}".format( baud=str(baudrate))) elif i[0:len('parity')] == 'parity': log.info("parity={parity}".format( parity=i[len('parity') + 1:])) parity = i[len('parity') + 1:] if parity not in ['none', 'even', 'odd']: self.ser_config.parity = parity else: log.error("Undefined parity {parity}".format( parity=parity)) elif line[0:len(TEMPLATE_PARSER_REG_DESC )] == TEMPLATE_PARSER_REG_DESC: reg = self.RegisterBlock(parent=self) reg_desc = line.split(TEMPLATE_PARSER_SEPARATOR) for i in reg_desc: if i[0:len('paramId')] == 'paramId': reg.paramId = int(i[len('paramId') + 1:]) elif i[0:len('address')].lower() == 'address': addr = int(i[len('address') + 1:]) if addr in range(0, 99999): reg.address = addr else: log.error("Invalid Modbus address {num}".format( num=addr)) elif i[0:len('name')].lower() == 'name': reg.name = i[len('name') + 1:] elif i[0:len('default')].lower() == 'default': reg.default = i[len('default') + 1:] self.registers.append(reg) elif line[0:len(TEMPLATE_PARSER_REG)] == TEMPLATE_PARSER_REG: # TODO: assign to proper objects, sort/group addresses by type and min/max reg_config = line.split(TEMPLATE_PARSER_SEPARATOR) reg_exists = False this_reg = None for c in reg_config: if c[0:len('paramId')] == 'paramId': paramId = int(c[len('paramId') + 1:]) for reg in self.registers: if paramId == reg.paramId: reg_exists = True if not reg_exists: reg = self.RegisterBlock(parent=self, paramId=paramId) self.registers.append(reg) reg_exists = True this_reg = paramId elif c[0:len('address')] == 'address': addr = int(c[len('address') + 1:]) if addr in range(0, 99999): for reg in self.registers: if reg.paramId == this_reg: reg.address = addr if not reg_exists: reg = self.RegisterBlock(parent=self, address=addr) self.registers.append(reg) reg_exists = True else: log.error("Invalid Modbus address {num}".format( num=addr)) elif c[0:len('registerType')] == 'registerType': reg_type = c[len('registerType') + 1:] if reg_type in ['analog']: for reg in self.registers: if reg.paramId == this_reg: reg.type = 'ir' elif reg_type in ['holding']: for reg in self.registers: if reg.paramId == this_reg: reg.type = 'hr' elif reg_type in ['input']: for reg in self.registers: if reg.paramId == this_reg: reg.type = 'di' elif reg_type in ['coil']: for reg in self.registers: if reg.paramId == this_reg: reg.type = 'co' else: log.error("Unsupported registerType {type}".format( type=reg_type)) elif c[0:len('encoding')] == 'encoding': enc = c[len('encoding') + 1:] if enc in ['int16', 'int8', 'boolean']: for reg in self.registers: if reg.paramId == this_reg: reg.encoding = enc reg.default = int(reg.default) elif enc in ['float32', 'int32']: for reg in self.registers: if reg.paramId == this_reg: reg.encoding = enc reg.length = 2 reg.default = float( reg.default ) if enc == 'float32' else int(reg.default) else: log.error( "Unsupported encoding {type}".format(type=enc)) hr_sequential = [] hr_sparse_block = {} ir_sequential = [] ir_sparse_block = {} di_sequential = [] di_sparse_block = {} co_sequential = [] co_sparse_block = {} for reg in self.registers: if reg.min is None: reg.min = reg._get_range()[0] if reg.max is None: reg.max = reg._get_range()[1] if reg.type == 'hr' and reg.address is not None: if self.sparse: hr_sparse_block[reg.address] = 0 else: hr_sequential.append(reg.address) elif reg.type == 'ir' and reg.address is not None: if self.sparse: ir_sparse_block[reg.address] = 0 else: ir_sequential.append(reg.address) elif reg.type == 'di' and reg.address is not None: if self.sparse: di_sparse_block[reg.address] = 0 else: di_sequential.append(reg.address) elif reg.type == 'co' and reg.address is not None: if self.sparse: co_sparse_block[reg.address] = 0 else: co_sequential.append(reg.address) else: log.error("Unhandled exception register {reg} addr=".format( reg=reg.name, addr=str(reg.address))) if self.sparse: hr_block = ModbusSparseDataBlock(hr_sparse_block) ir_block = ModbusSparseDataBlock(ir_sparse_block) di_block = ModbusSparseDataBlock(di_sparse_block) co_block = ModbusSparseDataBlock(co_sparse_block) else: hr_sequential.sort() hr_block = ModbusSequentialDataBlock(0, [ 0 for x in range(hr_sequential[0], hr_sequential[ len(hr_sequential) - 1]) ]) ir_sequential.sort() ir_block = ModbusSequentialDataBlock(0, [ 0 for x in range(ir_sequential[0], ir_sequential[ len(ir_sequential) - 1]) ]) di_sequential.sort() di_block = ModbusSequentialDataBlock(0, [ 0 for x in range(di_sequential[0], di_sequential[ len(di_sequential) - 1]) ]) co_sequential.sort() co_block = ModbusSequentialDataBlock(0, [ 0 for x in range(co_sequential[0], co_sequential[ len(co_sequential) - 1]) ]) self.context = ModbusSlaveContext(hr=hr_block, ir=ir_block, di=di_block, co=co_block, zero_mode=self.zero_mode) for reg in self.registers: reg.set_value(reg.default)
def _init_sparse_data(self): """ 非连续地址发布,发布地址从配置文件读取, """ for j, i in self._modbus_release_table.iterrows(): self.equipment_name[i['equipment_name']] = "null" if i['publish_regisrer'] == 1: self.coil_status_data[i['publish_address']] = i['init_value'] elif i['publish_regisrer'] == 2: self.input_status_data[i['publish_address']] = i['init_value'] elif i['publish_regisrer'] == 3: if i["data_publish_type"] == "INT": self.holding_register_data.update({ self.input_status_data['publish_address']: (i['init_value']) }) elif i["data_publish_type"] == "FLOAT": self.holding_register_data.update( dict( enumerate( self.float32_to_bytecode(i['init_value']), i['publish_address']))) elif i["data_publish_type"] == "DOUBLE": print("请完善解析double 数据代码") elif i['publish_regisrer'] == 4: if i["data_publish_type"] == "INT": self.input_register_data.update({ self.input_status_data['publish_address']: (i['init_value']) }) elif i["data_publish_type"] == "FLOAT": self.input_register_data.update( dict( enumerate( self.float32_to_bytecode(i['init_value']), i['publish_address']))) elif i["data_publish_type"] == "DOUBLE": print("请完善解析double 数据代码") else: print("publish_regisrer 输入错误") continue if (self.coil_status_data == {}) or (self.input_status_data is None): self.coil_status_data = {0: 0} if (self.input_status_data is None) or (self.input_status_data == {}): self.input_status_data = {0: 0} if (self.holding_register_data is None) or (self.holding_register_data == {}): self.holding_register_data = {0: 0} if (self.input_register_data is None) or (self.input_register_data == {}): self.input_register_data = {0: 0} print 11111, self.coil_status_data # print 22222, self.input_status_data # print 33333, self.holding_register_data # print 44444, self.input_register_data self._store = ModbusSlaveContext( di=ModbusSparseDataBlock(self.input_status_data), co=ModbusSparseDataBlock(self.coil_status_data), hr=ModbusSparseDataBlock(self.holding_register_data), ir=ModbusSparseDataBlock(self.input_register_data))
def registers_context( registers ): """ -------------------------------------------------------------------------- initialize your data store, returning an initialized ModbusServerConext -------------------------------------------------------------------------- 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) Continuting, 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) -------------------------------------------------------------------------- eg.: store = ModbusSlaveContext( di = ModbusSequentialDataBlock(0, [0]*1000), co = ModbusSequentialDataBlock(0, [0]*1000), hr = ModbusSequentialDataBlock(0, [0]*10000), ir = ModbusSequentialDataBlock(0, [0]*1000)) context = ModbusServerContext(slaves=store, single=True) Parse the register ranges, as: registers[, registers ...], and produce a keywords dictionary suitable for passing to ModbusSlaveContext, containing ModbusSparseDataBlock instances, for 'hr' (Holding Registers), 'co' (Coils), etc.: 40001=999 produces: hr = ModbusSparseDataBlock({ 0: 999 }), 1-10000 Coils 10001-30000 Input Coils 30001-40000 Input Registers 40001- Holding Registers Allow: <begin>[-<end>][=<val>[,<val>]] ... """ def registers_parse( txt ): """ Tokenizer yields integers; any other character, one at a time. """ b, i, e = 0, 0, len( txt ) while i <= e: if i == e or not( '0' <= txt[i] <= '9' ): if i > b: yield int( txt[b:i] ) # "123..." Parsed 1+ digits b, i = i, i-1 elif i < e: yield txt[b] # "?..." Something else b, i = i+1, i i += 1 # Parse register ranges # 0 10001 30001 40001 cod, did, ird, hrd = {}, {}, {}, {} for txt in registers: prs = registers_parse( txt ) beg = end = None val = [] try: beg = prs.next() end = beg end = prs.next() if end == '-': end = prs.next() # <beg>-<end>= equ = prs.next() elif end == '=': equ = end # <beg>= end = beg else: assert end == '-' # Unknown range operator assert equ == '=' while True: val += [prs.next()] assert type( val[-1] ) == int assert prs.next() == ',' except StopIteration: assert type( beg ) is int if end is None: end = beg assert type( end ) is int # Extend <beg>-<end> out to the number of values, or extend val to the # range length; duplicate entries and/or truncates to range length if not val: val = [0] if end == beg: end = beg + len( val ) - 1 if len( val ) < end - beg + 1: val *= (( end - beg + 1 ) / len( val ) + 1 ) val = val[:end - beg + 1] log.info( "%05d-%05d = %s" % ( beg, end, repr.repr( val ))) for reg in xrange( beg, end + 1 ): dct, off = ( ( hrd, 40001 ) if reg >= 40001 else ( ird, 30001 ) if reg >= 30001 else ( did, 10001 ) if reg >= 10001 else ( cod, 1 )) dct[reg - off] = val[reg - beg] except Exception as exc: log.error( "Unrecognized registers '%s': %s" % ( txt, str( exc ))) raise log.info( "Holding Registers: %s" % ( repr.repr( hrd ))) log.info( "Input Registers: %s" % ( repr.repr( ird ))) log.info( "Output Coils: %s" % ( repr.repr( cod ))) log.info( "Discrete Inputs: %s" % ( repr.repr( did ))) store = ModbusSlaveContext( di = ModbusSparseDataBlock( did ) if did else None, co = ModbusSparseDataBlock( cod ) if cod else None, hr = ModbusSparseDataBlock( hrd ) if hrd else None, ir = ModbusSparseDataBlock( ird ) if ird else None ) return ModbusServerContext( slaves=store, single=True )