|
| 1 | +#!/usr/bin/env python3 |
| 2 | +"""Pymodbus server datamodel examples. |
| 3 | +
|
| 4 | +This file shows examples of how to configure the datamodel for the server/simulator. |
| 5 | +
|
| 6 | +There are different examples showing the flexibility of the datamodel. |
| 7 | +""" |
| 8 | + |
| 9 | +from pymodbus.simulator import SimData, SimDataType, SimDevice |
| 10 | + |
| 11 | + |
| 12 | +def define_datamodel(): |
| 13 | + """Define register groups. |
| 14 | +
|
| 15 | + Coils and direct inputs are modeled as bits representing a relay in the device. |
| 16 | + There are no real difference between coils and direct inputs, but historically |
| 17 | + they have been divided. Please be aware the coils and direct inputs are addressed differently |
| 18 | + in shared vs non-shared models. |
| 19 | + - In a non-shared model the address is the bit directly. |
| 20 | + It can be thought of as if 1 register == 1 bit. |
| 21 | + - In a shared model the address is the register containing the bits. |
| 22 | + 1 register == 16bit, so a single bit CANNOT be addressed directly. |
| 23 | +
|
| 24 | + Holding registers and input registers are modeled as int/float/string representing a sensor in the device. |
| 25 | + There are no real difference between holding registers and input registers, but historically they have |
| 26 | + been divided. |
| 27 | + Please be aware that 1 sensor might be modeled as several register because it needs more than |
| 28 | + 16 bit for accuracy (e.g. a INT32). |
| 29 | + """ |
| 30 | + # SimData can be instantiated with positional or optional parameters: |
| 31 | + assert SimData( |
| 32 | + 5, 17, 10, SimDataType.REGISTERS |
| 33 | + ) == SimData( |
| 34 | + address=5, value=17, count=10, datatype=SimDataType.REGISTERS |
| 35 | + ) |
| 36 | + |
| 37 | + # Define a group of coils/direct inputs non-shared (address=15..31 each 1 bit) |
| 38 | + block1 = SimData(address=15, value=True, count=16, datatype=SimDataType.BITS) |
| 39 | + # Define a group of coils/direct inputs shared (address=15..31 each 16 bit) |
| 40 | + block2 = SimData(address=15, value=0xFFFF, count=16, datatype=SimDataType.BITS) |
| 41 | + |
| 42 | + # Define a group of holding/input registers (remark NO difference between shared and non-shared) |
| 43 | + block3 = SimData(10, 123.4, datatype=SimDataType.FLOAT32) |
| 44 | + block4 = SimData(17, value=123, count=5, datatype=SimDataType.INT64) |
| 45 | + block5 = SimData(27, "Hello ", datatype=SimDataType.STRING) |
| 46 | + |
| 47 | + # Please use SimDataType.DEFAULT to define register limits. |
| 48 | + # this datatype only uses 1 object, whereas SimDataType.REGISTERS uses <count> objects, |
| 49 | + # mean SimDataType.DEFAULT is factors more efficient and much less memory consuming |
| 50 | + block_def = SimData(0, count=1000, datatype=SimDataType.DEFAULT) |
| 51 | + |
| 52 | + # SimDevice can be instantiated with positional or optional parameters: |
| 53 | + assert SimDevice( |
| 54 | + 5,False, [block_def, block5] |
| 55 | + ) == SimDevice( |
| 56 | + id=5, type_check=False, block_shared=[block_def, block5] |
| 57 | + ) |
| 58 | + |
| 59 | + # SimDevice can define either a shared or a non-shared register model |
| 60 | + SimDevice(1, False, block_shared=[block_def, block5]) |
| 61 | + SimDevice(2, False, |
| 62 | + block_coil=[block1], |
| 63 | + block_direct=[block1], |
| 64 | + block_holding=[block2], |
| 65 | + block_input=[block3, block4]) |
| 66 | + # Remark: it is legal to reuse SimData, the object is only used for configuration, |
| 67 | + # not for runtime. |
| 68 | + |
| 69 | + # id=0 in a SimDevice act as a "catch all". Requests to an unknown id is executed in this SimDevice. |
| 70 | + SimDevice(0, block_shared=[block2]) |
| 71 | + |
| 72 | + |
| 73 | +def main(): |
| 74 | + """Combine setup and run.""" |
| 75 | + define_datamodel() |
| 76 | + |
| 77 | +if __name__ == "__main__": |
| 78 | + main() |
0 commit comments