|  | 
|  | 1 | +#!/usr/bin/env python | 
|  | 2 | +""" | 
|  | 3 | +Pymodbus Synchronous Server Example to showcase Device Information | 
|  | 4 | +-------------------------------------------------------------------------- | 
|  | 5 | +
 | 
|  | 6 | +This server demonstrates the use of Device Information to provide information | 
|  | 7 | +to clients about the device. This is part of the MODBUS specification, and | 
|  | 8 | +uses the MEI 0x2B 0x0E request / response. This example creates an otherwise | 
|  | 9 | +empty server. | 
|  | 10 | +""" | 
|  | 11 | +# --------------------------------------------------------------------------- #  | 
|  | 12 | +# import the various server implementations | 
|  | 13 | +# --------------------------------------------------------------------------- #  | 
|  | 14 | +from pymodbus.server.sync import StartTcpServer | 
|  | 15 | +from pymodbus.server.sync import StartUdpServer | 
|  | 16 | +from pymodbus.server.sync import StartSerialServer | 
|  | 17 | + | 
|  | 18 | +from pymodbus.device import ModbusDeviceIdentification | 
|  | 19 | +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext | 
|  | 20 | + | 
|  | 21 | +from pymodbus.transaction import ModbusRtuFramer, ModbusBinaryFramer | 
|  | 22 | + | 
|  | 23 | +# --------------------------------------------------------------------------- # | 
|  | 24 | +# import versions of libraries which we will use later on for the example | 
|  | 25 | +# --------------------------------------------------------------------------- # | 
|  | 26 | +from pymodbus import __version__ as pymodbus_version | 
|  | 27 | +from serial import __version__ as pyserial_version | 
|  | 28 | + | 
|  | 29 | +# --------------------------------------------------------------------------- #  | 
|  | 30 | +# configure the service logging | 
|  | 31 | +# --------------------------------------------------------------------------- #  | 
|  | 32 | +import logging | 
|  | 33 | +FORMAT = ('%(asctime)-15s %(threadName)-15s' | 
|  | 34 | +          ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') | 
|  | 35 | +logging.basicConfig(format=FORMAT) | 
|  | 36 | +log = logging.getLogger() | 
|  | 37 | +log.setLevel(logging.DEBUG) | 
|  | 38 | + | 
|  | 39 | + | 
|  | 40 | +def run_server(): | 
|  | 41 | +    # ----------------------------------------------------------------------- # | 
|  | 42 | +    # initialize your data store | 
|  | 43 | +    # ----------------------------------------------------------------------- # | 
|  | 44 | +    store = ModbusSlaveContext() | 
|  | 45 | +    context = ModbusServerContext(slaves=store, single=True) | 
|  | 46 | +     | 
|  | 47 | +    # ----------------------------------------------------------------------- #  | 
|  | 48 | +    # initialize the server information | 
|  | 49 | +    # ----------------------------------------------------------------------- #  | 
|  | 50 | +    # If you don't set this or any fields, they are defaulted to empty strings. | 
|  | 51 | +    # ----------------------------------------------------------------------- #  | 
|  | 52 | +    identity = ModbusDeviceIdentification() | 
|  | 53 | +    identity.VendorName = 'Pymodbus' | 
|  | 54 | +    identity.ProductCode = 'PM' | 
|  | 55 | +    identity.VendorUrl = 'http://github.com/riptideio/pymodbus/' | 
|  | 56 | +    identity.ProductName = 'Pymodbus Server' | 
|  | 57 | +    identity.ModelName = 'Pymodbus Server' | 
|  | 58 | +    identity.MajorMinorRevision = '1.5' | 
|  | 59 | + | 
|  | 60 | +    # ----------------------------------------------------------------------- # | 
|  | 61 | +    # Add an example which is long enough to force the ReadDeviceInformation | 
|  | 62 | +    # request / response to require multiple responses to send back all of the | 
|  | 63 | +    # information. | 
|  | 64 | +    # ----------------------------------------------------------------------- # | 
|  | 65 | + | 
|  | 66 | +    identity[0x80] = "Lorem ipsum dolor sit amet, consectetur adipiscing " \ | 
|  | 67 | +                     "elit. Vivamus rhoncus massa turpis, sit amet " \ | 
|  | 68 | +                     "ultrices orci semper ut. Aliquam tristique sapien in " \ | 
|  | 69 | +                     "lacus pharetra, in convallis nunc consectetur. Nunc " \ | 
|  | 70 | +                     "velit elit, vehicula tempus tempus sed. " | 
|  | 71 | + | 
|  | 72 | +    # ----------------------------------------------------------------------- # | 
|  | 73 | +    # Add an example with repeated object IDs. The MODBUS specification is | 
|  | 74 | +    # entirely silent on whether or not this is allowed. In practice, this | 
|  | 75 | +    # should be assumed to be contrary to the MODBUS specification and other | 
|  | 76 | +    # clients (other than pymodbus) might behave differently when presented | 
|  | 77 | +    # with an object ID occurring twice in the returned information. | 
|  | 78 | +    # | 
|  | 79 | +    # Use this at your discretion, and at the very least ensure that all | 
|  | 80 | +    # objects which share a single object ID can fit together within a single | 
|  | 81 | +    # ADU unit. In the case of Modbus RTU, this is about 240 bytes or so. In | 
|  | 82 | +    # other words, when the spec says "An object is indivisible, therefore | 
|  | 83 | +    # any object must have a size consistent with the size of transaction | 
|  | 84 | +    # response", if you use repeated OIDs, apply that rule to the entire | 
|  | 85 | +    # grouping of objects with the repeated OID. | 
|  | 86 | +    # ----------------------------------------------------------------------- # | 
|  | 87 | +    identity[0x81] = ['pymodbus {0}'.format(pymodbus_version), | 
|  | 88 | +                      'pyserial {0}'.format(pyserial_version)] | 
|  | 89 | + | 
|  | 90 | +    # ----------------------------------------------------------------------- # | 
|  | 91 | +    # run the server you want | 
|  | 92 | +    # ----------------------------------------------------------------------- #  | 
|  | 93 | +    # Tcp: | 
|  | 94 | +    StartTcpServer(context, identity=identity, address=("localhost", 5020)) | 
|  | 95 | + | 
|  | 96 | +    # TCP with different framer | 
|  | 97 | +    # StartTcpServer(context, identity=identity, | 
|  | 98 | +    #                framer=ModbusRtuFramer, address=("0.0.0.0", 5020)) | 
|  | 99 | + | 
|  | 100 | +    # Udp: | 
|  | 101 | +    # StartUdpServer(context, identity=identity, address=("0.0.0.0", 5020)) | 
|  | 102 | +     | 
|  | 103 | +    # Ascii: | 
|  | 104 | +    # StartSerialServer(context, identity=identity, | 
|  | 105 | +    #                    port='/dev/ttyp0', timeout=1) | 
|  | 106 | +     | 
|  | 107 | +    # RTU: | 
|  | 108 | +    # StartSerialServer(context, framer=ModbusRtuFramer, identity=identity, | 
|  | 109 | +    #                   port='/dev/ttyp0', timeout=.005, baudrate=9600) | 
|  | 110 | + | 
|  | 111 | +    # Binary | 
|  | 112 | +    # StartSerialServer(context, | 
|  | 113 | +    #                   identity=identity, | 
|  | 114 | +    #                   framer=ModbusBinaryFramer, | 
|  | 115 | +    #                   port='/dev/ttyp0', | 
|  | 116 | +    #                   timeout=1) | 
|  | 117 | + | 
|  | 118 | + | 
|  | 119 | +if __name__ == "__main__": | 
|  | 120 | +    run_server() | 
0 commit comments