Example #1
0
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))
Example #2
0
 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=())
Example #3
0
    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)
Example #4
0
    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']])
Example #5
0
    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"]))
Example #8
0
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))
Example #9
0
__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)])
Example #10
0
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)
Example #11
0
 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)
Example #12
0
    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))
Example #13
0
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 )