Overview
On this page you will find explanation of how and what can be configured using the json configuration. This json configuration can be used to initialize the Modbus Slave Device Simulator, but in addition this configuration can be used to create a Modbus Device. Here is how a json configuration file would look like. Actually the following example shows basically everything that might be configured. From now on, by Discrete Object we will mean a coil, or discrete input, by Register we will mean input or holding register and by Modbus Object we will mean any Discrete Object or Register.
Simulator Configuration
{
"deviceConfiguration": {
"id": "1234567890",
"oidPrefix": "1.3.6.1.4.1.46863.218",
"type": "Modbus",
"connections": [{
"type": "TCP_IP",
"port": "502"
}]
},
"sensors": [{
"id": "101",
"address": 10,
"objectType": "inputRegister",
"dataDefinition": {
"dataType": "int16",
"valueType": "Measurement Value",
"initialValue": 1000,
"min": 10,
"max": 100
},
"automation": {
"values": [10, 20, 30, 40, 50, 60]
}
}, {
"id": "102",
"address": 50,
"objectType": "holdingRegister",
"dataDefinition": {
"dataType": "int16",
"valueType": "Measurement Value",
"min": 100,
"max": 1000,
"factor": 10,
"offset": 100000
},
"automation": {
"values": [100, 200, 300, 400, 500]
}
}, {
"id": "103",
"address": 51,
"objectType": "holdingRegister",
"dataDefinition": {
"dataType": "int32",
"valueType": "Notification Value"
},
"dataAccessChannels": [{
"type": "Modbus_TCP",
"refreshRate": 2,
"minimalMeaningfulValueDifference": 0.5,
}],
"automation": {
"values": [100000, 200000, 3000000, 40000000]
}
}, {
"id": "104",
"address": 10,
"objectType": "coil",
"dataDefinition": {
"dataType": "bool",
"valueType": "Alarm",
"referenceObjectId": "103",
"valueChangeNotificationCondition": "valueIncremented"
},
"automation": {
"values": [1, 1, 0, 0, 1, 0]
}
}, {
"id": "105",
"address": 11,
"objectType": "coil",
"dataDefinition": {
"dataType": "bool",
"valueType": "Warning"
},
"automation": {
"values": [3, 2, 1, 0]
}
}, {
"id": "106",
"address": 13,
"objectType": "discreteInput",
"dataDefinition": {
"dataType": "bool",
"valueType": "Measurement Value"
},
"automation": {
"values": [1, 0, 1, 0, 1, 0]
}
}, {
"id": "107",
"address": 14,
"objectType": "discreteInput",
"dataDefinition": {
"dataType": "bool",
"valueType": "Notification Value"
}
}, {
"id": "108",
"address": 510,
"objectType": "inputRegister",
"initialValue": "hi",
"dataDefinition": {
"dataType": "char[10]",
"valueType": "Notification Value"
},
"automation": {
"values": ["hello", "world"]
}
}, {
"id": "109",
"address": 516,
"objectType": "holdingRegister",
"dataDefinition": {
"dataType": "int16",
},
"automation": {
"values": [15, 20, 25, 30, 35, 40, 45, 50],
"interval": 10
}
}, {
"id": "110",
"address": 12,
"objectType": "coil",
"dataDefinition": {
"dataType": "char[5]",
"valueType": "Warning"
},
"automation": {
"values": ["11100", "101010"]
}
}, {
"id": "111",
"address": 17,
"objectType": "coil",
"dataDefinition": {
"dataType": "int8",
"valueType": "Warning"
},
"automation": {
"values": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
}
}, {
"id": "112",
"address": 25,
"objectType": "coil",
"dataDefinition": {
"dataType": "char[1]",
"valueType": "Warning"
},
"automation": {
"values": ["1", "0", "0"]
}
}]
}
Configuration Description
Some of the items in the json configuration are used only when creating a Modbus Master Device with this configuration. In here we will describe only the ones used by the simulator.
We can split the configuration on two parts – the first one describes how the simulator can connect with the other devices and the second one describes the data model of the simulator.
Data Types
The Simulator does not actually make any difference between the data types. These data types are used when configuring a device to communicate with this simulator. The various data types are used exclusively to get the count of registers the sensor is going to occupy.
Here we will add detailed explanation of the supported data types.
Value to Modbus Objects Mapping
The simulator understands two types of Java objects – String and Long. The configuration parser converts the Double and Float values to Long value, and then provides these to the simulator. Here is how the Long and String values are converted to Registers and Discrete Objects.
Long Value
As Registers
The Least significant 16 bits are taken as an integer value and are written in the base address of the sensor, if the sensor occupies more than one Register, then the next 16-bit are taken and written in the nest register and so on, until all of the registers are filled.
As Discrete Object
The least significant bit is taken and written in the first Discrete Object, then the next bit is written in the next Discrete Object and so on, until all of the Discrete Objects assigned to this sensor are written.
String Value
As Registers
The first character is put as the most significant byte and the next one as the least significant byte of the first register. If the sensor spans on more than one register the next two characters are written in the next register and so on, until all of the registers are filled.
As Discrete Object
If the first character is '1' then the first Discrete Object is raised, i.e. 1 is written in it. otherwise it is a zero. If there is another discrete object, and another character they are processed in the same manner. If the length of the String value is less than the Discrete Objects count then these discrete objects are filled with zeroes. There is some small trick here. If the string itself equals "true" then all of the Discrete Objects will be filled with ones.