# Callback Server Example

    #!/usr/bin/env python
    """
    Pymodbus Server With Callbacks
    --------------------------------------------------------------------------

    This is an example of adding callbacks to a running modbus server
    when a value is written to it. In order for this to work, it needs
    a device-mapping file.
    """
    # --------------------------------------------------------------------------- #
    # import the modbus libraries we need
    # --------------------------------------------------------------------------- #
    from pymodbus.server.asynchronous import StartTcpServer
    from pymodbus.device import ModbusDeviceIdentification
    from pymodbus.datastore import ModbusSparseDataBlock
    from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
    from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer

    # --------------------------------------------------------------------------- #
    # import the python libraries we need
    # --------------------------------------------------------------------------- #
    from multiprocessing import Queue, Process

    # --------------------------------------------------------------------------- #
    # configure the service logging
    # --------------------------------------------------------------------------- #
    import logging
    logging.basicConfig()
    log = logging.getLogger()
    log.setLevel(logging.DEBUG)

    # --------------------------------------------------------------------------- #
    # create your custom data block with callbacks
    # --------------------------------------------------------------------------- #

    class CallbackDataBlock(ModbusSparseDataBlock):
        """ A datablock that stores the new value in memory
        and passes the operation to a message queue for further
        processing.
        """

        def __init__(self, devices, queue):
            """
            """
            self.devices = devices
            self.queue = queue

            values = {k: 0 for k in devices.keys()}
            values[0xbeef] = len(values)  # the number of devices
            super(CallbackDataBlock, self).__init__(values)

        def setValues(self, address, value):
            """ Sets the requested values of the datastore

            :param address: The starting address
            :param values: The new values to be set
            """
            super(CallbackDataBlock, self).setValues(address, value)
            self.queue.put((self.devices.get(address, None), value))

    # --------------------------------------------------------------------------- #
    # define your callback process
    # --------------------------------------------------------------------------- #

    def rescale_value(value):
        """ Rescale the input value from the range
        of 0..100 to -3200..3200.

        :param value: The input value to scale
        :returns: The rescaled value
        """
        s = 1 if value >= 50 else -1
        c = value if value < 50 else (value - 50)
        return s * (c * 64)

    def device_writer(queue):
        """ A worker process that processes new messages
        from a queue to write to device outputs

        :param queue: The queue to get new messages from
        """
        while True:
            device, value = queue.get()
            scaled = rescale_value(value[0])
            log.debug("Write(%s) = %s" % (device, value))
            if not device: continue
            # do any logic here to update your devices

    # --------------------------------------------------------------------------- #
    # initialize your device map
    # --------------------------------------------------------------------------- #

    def read_device_map(path):
        """ A helper method to read the device
        path to address mapping from file::

           0x0001,/dev/device1
           0x0002,/dev/device2

        :param path: The path to the input file
        :returns: The input mapping file
        """
        devices = {}
        with open(path, 'r') as stream:
            for line in stream:
                piece = line.strip().split(',')
                devices[int(piece[0], 16)] = piece[1]
        return devices

    def run_callback_server():
        # ----------------------------------------------------------------------- #
        # initialize your data store
        # ----------------------------------------------------------------------- #
        queue = Queue()
        devices = read_device_map("device-mapping")
        block = CallbackDataBlock(devices, queue)
        store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)
        context = ModbusServerContext(slaves=store, single=True)

        # ----------------------------------------------------------------------- #
        # initialize the server information
        # ----------------------------------------------------------------------- #
        identity = ModbusDeviceIdentification()
        identity.VendorName = 'pymodbus'
        identity.ProductCode = 'PM'
        identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
        identity.ProductName = 'pymodbus Server'
        identity.ModelName = 'pymodbus Server'
        identity.MajorMinorRevision = '1.0'

        # ----------------------------------------------------------------------- #
        # run the server you want
        # ----------------------------------------------------------------------- #
        p = Process(target=device_writer, args=(queue,))
        p.start()
        StartTcpServer(context, identity=identity, address=("localhost", 5020))

    if __name__ == "__main__":
        run_callback_server()