示例#1
0
    def __init__(self, output):
        """ Initialize a new instance of the logger

        :param output: The output file to save to
        """
        self.output  = output
        self.context = ModbusSlaveContext(
            di = ModbusSequentialDataBlock.create(),
            co = ModbusSequentialDataBlock.create(),
            hr = ModbusSequentialDataBlock.create(),
            ir = ModbusSequentialDataBlock.create())
示例#2
0
    def __init__(self, output):
        """ Initialize a new instance of the logger

        :param output: The output file to save to
        """
        self.output = output
        self.context = ModbusSlaveContext(
            di=ModbusSequentialDataBlock.create(),
            co=ModbusSequentialDataBlock.create(),
            hr=ModbusSequentialDataBlock.create(),
            ir=ModbusSequentialDataBlock.create())
示例#3
0
def run_updating_server():
    store = ModbusSlaveContext(hr=ModbusSequentialDataBlock.create())
    context = ModbusServerContext(slaves=store, single=True)

    loop = LoopingCall(f=updating_writer, a=(context, ))
    loop.start(1, now=True)  # initially delay by time
    StartSerialServer(context,
                      framer=ModbusRtuFramer,
                      port='/dev/ttyACM0',
                      timeout=0.3,
                      baudrate=9600)
 def test_combo(self):
     test_store = ModbusSlaveContext(t=ModbusSequentialDataBlock.create())
     test_env = {'fields':
                     {'scale_8_int':
                          {'reg_type': CO, 'address': 1,
                           'encode': {'e_type': SCALE, 's_factor': 100, 'd_type': INT8}
                           },
                      'scale_8_uint':
                          {'reg_type': CO, 'address': 2,
                           'encode': {'e_type': SCALE, 's_factor': 10, 'd_type': UINT8}
                           },
                      'scale_16_int':
                          {'reg_type': CO, 'address': 3,
                           'encode': {'e_type': SCALE, 's_factor': 100, 'd_type': INT16}
                           },
                      'scale_16_uint':
                          {'reg_type': CO, 'address': 4,
                           'encode': {'e_type': SCALE, 's_factor': 100, 'd_type': UINT16}
                           },
                      'scale_32_int':
                          {'reg_type': CO, 'address': 5, 'encode': {'e_type': SCALE, 'd_type': INT32}
                           },
                      'scale_32_uint':
                          {'reg_type': CO, 'address': 6, 'encode': {'e_type': SCALE, 'd_type': UINT32}
                           },
                      'scale_32_float':
                          {'reg_type': CO, 'address': 7,
                           'encode': {'e_type': SCALE, 's_factor': 10, 'd_type': FLOAT32}
                           },
                      'comb_32_float':
                          {'reg_type': CO, 'address': 8, 'encode': {'e_type': COMB, 'd_type': FLOAT32}
                           }},
                 'byte_order': '<',
                 'word_order': '<',
                 'default_scaling_factor': 1000}
     test_fields = test_env['fields']
     test_handler = PayloadHandler(test_env, test_store)
     test_store.setValues(1, 1, test_handler.encode(1, test_fields['scale_8_int']['encode']))
     self.assertEqual(1, test_handler.decode(1, 1, test_fields['scale_8_int']['encode']))
     test_store.setValues(1, 2, test_handler.encode(10, test_fields['scale_8_uint']['encode']))
     self.assertEqual(10, test_handler.decode(1, 2, test_fields['scale_8_uint']['encode']))
     test_store.setValues(1, 3, test_handler.encode(12.5, test_fields['scale_16_int']['encode']))
     self.assertEqual(12.5, test_handler.decode(1, 3, test_fields['scale_16_int']['encode']))
     test_store.setValues(1, 4, test_handler.encode(32.991, test_fields['scale_16_uint']['encode']))
     self.assertEqual(32.99, test_handler.decode(1, 4, test_fields['scale_16_uint']['encode']))
     test_store.setValues(1, 5, test_handler.encode(1000, test_fields['scale_32_int']['encode']))
     self.assertEqual(1000, test_handler.decode(1, 5, test_fields['scale_32_int']['encode']))
     test_store.setValues(1, 6, test_handler.encode(63.2, test_fields['scale_32_uint']['encode']))
     self.assertEqual(63.2, test_handler.decode(1, 6, test_fields['scale_32_uint']['encode']))
     test_store.setValues(1, 7, test_handler.encode(1.333, test_fields['scale_32_float']['encode']))
     self.assertEqual(1.3, test_handler.decode(1, 7, test_fields['scale_32_float']['encode']))
     test_store.setValues(1, 8, test_handler.encode(789.4375, test_fields['comb_32_float']['encode']))
     self.assertEqual(789.4375, test_handler.decode(1, 8, test_fields['comb_32_float']['encode']))
示例#5
0
    def __init__(self, port):
        self.port = port

        self.block = ModbusSequentialDataBlock.create()
        self.store = ModbusSlaveContext(ir=self.block)
        self.context = ModbusServerContext(slaves=self.store, single=True)

        self.scheduler = BackgroundScheduler()
        params = {
            'hour': os.environ.get("VIRTUAL_SERVER_UPDATE_CRON_HOUR_TRIGGER"),
            'minute': os.environ.get("VIRTUAL_SERVER_UPDATE_CRON_MINUTE_TRIGGER"),
            'second': os.environ.get("VIRTUAL_SERVER_UPDATE_CRON_SECOND_TRIGGER"),
        }
        self.main_job = self.scheduler.add_job(**params, func=self.set_datastore, trigger='cron')
示例#6
0
def initiate_server(identity, inteval, host, port):
    """
    Start a Modbus server using the information on
    the configuration block above, and set a recurring 
    call to a function in order to update the values.
    """

    # initialize your data store
    store = ModbusSlaveContext(
        di=ModbusSequentialDataBlock.create(),
        co=ModbusSequentialDataBlock.create(),
        hr=ModbusSequentialDataBlock.create(),
        ir=ModbusSequentialDataBlock.create(),
    )

    context = ModbusServerContext(slaves=store, single=True)

    # Start the Looping callback
    loop = LoopingCall(f=updating_writer, context=context)
    loop.start(inteval, now=False)

    # Start the Modbus server
    print("Modbus Server started. Press Cntl + C to stop...")
    StartTcpServer(context, identity=identity, address=(host, port))
示例#7
0
def run_server():

    block = ModbusSequentialDataBlock.create()
    store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)

    context = ModbusServerContext(slaves=store, single=True)

    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'

    StartTcpServer(context, identity=identity, address=("0.0.0.0", 502))
 def test_decode(self):
     test_store = ModbusSlaveContext(t=ModbusSequentialDataBlock.create())
     test_env = {'fields':
                     {'scale_8_int':
                          {'reg_type': CO, 'address': 1,
                           'encode': {'e_type': SCALE, 's_factor': 10, 'd_type': INT8}
                           },
                      'scale_8_uint':
                          {'reg_type': CO, 'address': 4,
                           'encode': {'e_type': SCALE, 's_factor': 10, 'd_type': UINT8}
                           },
                      'scale_16_int':
                          {'reg_type': CO, 'address': 6,
                           'encode': {'e_type': SCALE, 's_factor': 100, 'd_type': INT16}
                           },
                      'scale_16_uint':
                          {'reg_type': CO, 'address': 8,
                           'encode': {'e_type': SCALE, 's_factor': 100, 'd_type': UINT16}
                           }},
                 'byte_order': '<',
                 'word_order': '<',
                 'default_scaling_factor': 1000}
     test_fields = test_env['fields']
     test_handler = PayloadHandler(test_env, test_store)
     test_builder = BinaryPayloadBuilder('<', '<')
     test_builder.reset()
     test_builder.add_8bit_int(100)
     test_store.setValues(1, 1, test_builder.to_registers())
     self.assertEqual(10,
                      test_handler.decode(1, 1, test_fields['scale_8_int']['encode']))
     test_builder.reset()
     test_builder.add_8bit_uint(100)
     test_store.setValues(1, 4, test_builder.to_registers())
     self.assertEqual(10,
                      test_handler.decode(1, 4, test_fields['scale_8_uint']['encode']))
     test_builder.reset()
     test_builder.add_16bit_int(1350)
     test_store.setValues(1, 6, test_builder.to_registers())
     self.assertEqual(13.5,
                      test_handler.decode(1, 6, test_fields['scale_16_int']['encode']))
     test_builder.reset()
     test_builder.add_16bit_uint(3287)
     test_store.setValues(1, 8, test_builder.to_registers())
     self.assertEqual(32.87,
                      test_handler.decode(1, 8, test_fields['scale_16_uint']['encode']))
     test_builder.reset()
 def test_no_e_type(self):
     test_store = ModbusSlaveContext(t=ModbusSequentialDataBlock.create())
     test_env = {'fields':
                     {'8_int':
                          {'reg_type': CO, 'address': 1,
                           'encode': {'d_type': INT8}
                           },
                      '8_uint':
                          {'reg_type': CO, 'address': 2,
                           'encode': {'d_type': UINT8}
                           },
                      '16_int':
                          {'reg_type': CO, 'address': 3,
                           'encode': {'d_type': INT16}
                           },
                      '16_uint':
                          {'reg_type': CO, 'address': 4,
                           'encode': {'d_type': UINT16}
                           },
                      '32_int':
                          {'reg_type': CO, 'address': 5,
                           'encode': {'d_type': INT32}
                           },
                      '32_uint':
                          {'reg_type': CO, 'address': 6,
                           'encode': {'d_type': UINT32}
                           }},
                 'byte_order': '<',
                 'word_order': '<',
                 'default_scaling_factor': 1000}
     test_fields = test_env['fields']
     test_handler = PayloadHandler(test_env, test_store)
     test_store.setValues(1, 1, test_handler.encode(1, test_fields['8_int']['encode']))
     self.assertEqual(1, test_handler.decode(1, 1, test_fields['8_int']['encode']))
     test_store.setValues(1, 2, test_handler.encode(10, test_fields['8_uint']['encode']))
     self.assertEqual(10, test_handler.decode(1, 2, test_fields['8_uint']['encode']))
     test_store.setValues(1, 3, test_handler.encode(12, test_fields['16_int']['encode']))
     self.assertEqual(12, test_handler.decode(1, 3, test_fields['16_int']['encode']))
     test_store.setValues(1, 4, test_handler.encode(32, test_fields['16_uint']['encode']))
     self.assertEqual(32, test_handler.decode(1, 4, test_fields['16_uint']['encode']))
     test_store.setValues(1, 5, test_handler.encode(1000, test_fields['32_int']['encode']))
     self.assertEqual(1000, test_handler.decode(1, 5, test_fields['32_int']['encode']))
     test_store.setValues(1, 6, test_handler.encode(63, test_fields['32_uint']['encode']))
     self.assertEqual(63, test_handler.decode(1, 6, test_fields['32_uint']['encode']))
示例#10
0
 def test_encode(self):
     test_store = ModbusSlaveContext(t=ModbusSequentialDataBlock.create())
     test_env = {'fields':
                     {'scale_8_int':
                          {'reg_type': CO, 'address': 1,
                           'encode': {'e_type': SCALE, 's_factor': 10, 'd_type': INT8}
                           },
                      'scale_8_uint':
                          {'reg_type': CO, 'address': 2,
                           'encode': {'e_type': SCALE, 's_factor': 10, 'd_type': UINT8}
                           },
                      'scale_16_int':
                          {'reg_type': CO, 'address': 3,
                           'encode': {'e_type': SCALE, 's_factor': 100, 'd_type': INT16}
                           },
                      'scale_16_uint':
                          {'reg_type': CO, 'address': 4,
                           'encode': {'e_type': SCALE, 's_factor': 100, 'd_type': UINT16}
                           },
                      'scale_32_int':
                          {'reg_type': CO, 'address': 5, 'encode': {'e_type': SCALE, 'd_type': INT32}
                           },
                      'scale_32_uint':
                          {'reg_type': CO, 'address': 6, 'encode': {'e_type': SCALE, 'd_type': UINT32}
                           },
                      'scale_32_float':
                          {'reg_type': CO, 'address': 7,
                           'encode': {'e_type': SCALE, 's_factor': 10, 'd_type': FLOAT32}
                           },
                      'comb_32_float':
                          {'reg_type': CO, 'address': 8, 'encode': {'e_type': COMB, 'd_type': FLOAT32}
                           }},
                 'byte_order': '<',
                 'word_order': '<',
                 'default_scaling_factor': 1000}
     test_fields = test_env['fields']
     test_handler = PayloadHandler(test_env, test_store)
     self.assertEqual(100, BinaryPayloadDecoder.fromRegisters(
         test_handler.encode(10, test_fields['scale_8_int']['encode']),
         byteorder='<', wordorder='<').decode_8bit_int())
     self.assertEqual(100, BinaryPayloadDecoder.fromRegisters(
         test_handler.encode(10, test_fields['scale_8_uint']['encode']),
         byteorder='<', wordorder='<').decode_8bit_uint())
     self.assertEqual(1250, BinaryPayloadDecoder.fromRegisters(
         test_handler.encode(12.5, test_fields['scale_16_int']['encode']),
         byteorder='<', wordorder='<').decode_16bit_int())
     self.assertEqual(3299, BinaryPayloadDecoder.fromRegisters(
         test_handler.encode(32.991, test_fields['scale_16_uint']['encode']),
         byteorder='<', wordorder='<').decode_16bit_uint())
     self.assertEqual(1000000, BinaryPayloadDecoder.fromRegisters(
         test_handler.encode(1000, test_fields['scale_32_int']['encode']),
         byteorder='<', wordorder='<').decode_32bit_int())
     self.assertEqual(63200, BinaryPayloadDecoder.fromRegisters(
         test_handler.encode(63.2, test_fields['scale_32_uint']['encode']),
         byteorder='<', wordorder='<').decode_32bit_uint())
     self.assertEqual(13, BinaryPayloadDecoder.fromRegisters(
         test_handler.encode(1.333, test_fields['scale_32_float']['encode']),
         byteorder='<', wordorder='<').decode_32bit_float())
     self.assertEqual(789.4375, BinaryPayloadDecoder.fromRegisters(
         test_handler.encode(789.4375, test_fields['comb_32_float']['encode']),
         byteorder='<', wordorder='<').decode_32bit_float())
示例#11
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({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))
    store = ModbusSlaveContext(di=ModbusSequentialDataBlock.create())
    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 = '2.3.0'

    # ----------------------------------------------------------------------- #
    # run the server you want
    # ----------------------------------------------------------------------- #
    # Tcp:
    StartTcpServer(context, identity=identity, address=("", 502))
示例#12
0
class Battery:
    """
    Battery represents the Server/Slave. Basically is a modbus server wrapper.
    """
    """
    Initialize the store and the context
    """
    store = ModbusSlaveContext(di=ModbusSequentialDataBlock.create(),
                               co=ModbusSequentialDataBlock.create(),
                               hr=ModbusSequentialDataBlock.create(),
                               ir=ModbusSequentialDataBlock.create())

    context = ModbusServerContext(slaves=store, single=True)

    def __init__(self, env):
        self.fields = env['fields']
        self.id = env['id']
        self.max_capacity = env['battery_capacity']
        self.payload_handler = PayloadHandler(env['float_store'], self.store)
        self.set_initial_values()
        self.run_server(self.context, env['server_address'])

    def set_initial_values(self):
        """
        setting initial values to fields which have 'init' keyword in their dictionary
        """
        for field_name in self.fields:
            if 'init' in self.fields[field_name]:
                self.set_value(self.fields[field_name],
                               self.fields[field_name]['init'])

    def set_value(self, field, value):
        """
        sets the value to the given field; ALL data which is assigned to  16-bit registers (meaning fx > 2) will
        be encoded by payload_handler
        :param field: a field from the the dictionary (fields[field_name])
        :param value: value to set
        """
        fx = field['reg_type']
        addr = field['address']
        if fx > 2:
            mode = field['encode']
            value = self.payload_handler.encode(value, mode)
            self.store.setValues(fx, addr, value)
        else:
            self.store.setValues(fx, addr, [value])

    def get_value(self, field):
        """
        gets the value of a given field; ALL data from  16-bit registers (meaning fx > 2) will be decoded  by
        payload_handler
        :param field: a field from the the dictionary (fields[field_name])
        :return: value of the given field
        """
        fx = field['reg_type']
        addr = field['address']
        if fx <= 2:
            value = int(self.store.getValues(fx, addr, 1)[0])
        elif fx > 2:
            mode = field['encode']
            value = self.payload_handler.decode(fx, addr, mode)
        return value

    def is_input_connected(self):
        return self.get_value(self.fields['input_connected'])

    def is_converter_started(self):
        return self.get_value(self.fields['converter_started'])

    def run_server(self, context, env):
        """
        starts the servers with filled in context
        runs in separate thread
        """
        t = threading.Thread(target=StartTcpServer,
                             kwargs={
                                 'context': context,
                                 'address': tuple(env)
                             },
                             daemon=True)
        t.start()
        print("SERVER: is running")