# Modbus RTU/TCP > Symcon documentation · English · generated on 2026-09-26 > Index: https://www.symcon.de/en/llms.txt Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/ ModBus is a protocol based on RTU (serial binary) and TCP/IP packets. A connection with IP-Symcon is possible via LAN or serial gateway. > **Note:** The following devices are supported by IP-Symcon: > > [Supported devices](modbus-rtu-tcp.md) ### Integration in IP-Symcon First a "ModBus" instance has to be added within IP-Symcon. There are several variants that can be created: | Instance | Description | | -------------- | ---------------------------------------------------------------------------------------------------- | | ModBus Device | Instance, which can map multiple addresses (coils/registers) and supports templates (7.0 and higher) | | ModBus Coil. | Instance which represents a single address (coil) | | ModBus Address | Instance which represents a single address (register) | > **Note:** Many templates can be found in our community: [Show templates](https://community.symcon.de/c/ip-symcon/vorlagen-modbus/86) The configuration of the parent gateway and I/O instance must then be adapted to the connected device. It must be selected via which protocol and device ID the device is addressed. The device ID is particularly important for RTU connected devices. For devices connected to TCP, this is often device ID 1. ![Modbus Gateway Configuration](https://www.symcon.de/media/pages/service/dokumentation/modulreferenz/geraete/modbus-rtu-tcp/eef944680d-1790424938/modbus-gatewayconfig.png) In order to be able to establish a connection to the device, IP address and port (default:502) must be entered in the gateway's parent I/O instance. Further configuration (screenshot below) is as follows. | Option | Description | | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Unit | Data type of the variable of the device | | Function (Read) | Function according to which the values are to be read | | Address (Read) | Device address of the register to be read from | | Function (Write) | Function according to which the values are to be written | | Address (Write) | Device address of the register to be written to | | Factor (Numeric values) | The factor multiplies or divides the received value and writes it to the device variable | | Length
(Strings) | If the length is greater than 0, it defines the precise number of characters (Bytes) queried. Note: 1 register = 2 characters (Bytes) | | Byte order | Depending on the device, the byte order must be adapted. Often this is not documented, but must be tried out. Big Endian and Little Endian (byte swap) are the common values. | | Emulate status | "Emulate status" means that the value of the variable is set to the new value if the write command is successful and does not depend on a read command | | Interval | If the interval is greater than 0, the address (read) is queried cyclically on the ModBus device and the variable of the device is updated | ![Modbus Device Configuration](https://www.symcon.de/media/pages/service/dokumentation/modulreferenz/geraete/modbus-rtu-tcp/018f4af88c-1790424938/modbus-deviceconfig.png) > **Note:** Due to the fact that we still support 32 bit systems Int64 values are mapped as Float64. ### Modbus device If multiple addresses are to be queried for a device, the Modbus device should be used. Here several addresses can be entered as a table and virtual addresses can be defined. Configuration: | Name | Description | | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Addresses | Tabular listing of the defined addresses | | Configure virtual addresses | Button with which a list of virtual addresses can be defined | | Byte order | The byte order must be adjusted depending on the device. This is often not documented but has to be tried out. Big Endian and Little Endian (bytes swapped) are the common values. | | Interval | If the interval is set to greater than 0, the address (read) of the ModBus device is queried cyclically and the device variable is updated. | | Import template | Using this button, a template of the tables can be quickly inserted. | | Export template | Through this button, | > **Note:** The structure of template files is described in detail under [Templates (file format)](modbus-rtu-tcp.md). | A template can be created from the settings made | | Contents of the address list: | Name | Description | | -------------------- | ---------------------------------------------------------- | | Active | Specifies whether the variable should be created | | Name | Name, used as variable name | | Unit | Data type of the register | | Function
(Read) | Function according to which the values ​​should be read | | Address
(Read) | Register to be read from | | Function (Writing) | Function according to which the values ​​should be written | | Address (writing) | Register to be written to | | Profile | Profile, which should get the variable | Under the expert options, the ident can be customized and a translation for the variable name can also be provided. Contents of the virtual address list: | Name | Description | | ------------- | -------------------------------------------------------- | | Active | The variable is created | | Name | Name, used as variable name | | Variable type | Type of variable | | Profile | Profile of the variable | | Read | Script that provides the values ​​of the virtual address | | Write | Script that passes the values ​​to the variables. | In the read script, all values ​​with their respective idents are available in $VALUES. The new value, which should load in the variable of the virtual address is simply returned with return. If no value is to be written (e.g. because invalid), null can be returned. (from 7.1) ```php return ($VALUES["A_3_3_23296"] + $VALUES["A_3_3_23298"] + $VALUES["A_3_3_23300"])/3; ``` The write script expects an associative array as return, which contains all the idents to be written to. $VALUE contains the new value, which was requested via RequestAction. ```php return ["A_3_3_23296" => $VALUE]; ``` ### FunctionCodes Depending on the FunctionCode, a suitable address must also be entered. This can be taken from the table. The table below also provides an overview of which FunctionCode is sent with which parameterization within IP-Symcon: | FunctionCode | Device address | Read/Write address | Surname | | ------------ | -------------- | ---------------------- | ------------------------ | | 0x01 (1) | 1 - 10000 | Device address - 1 | Read Coils | | 0x05 (5) | 1 - 10000 | Device address - 1 | Write Single Coil | | 0x02 (2) | 10001 - 20000 | Device address - 10001 | Read Discrete Inputs | | 0x03 (3) | 40001 - 50000 | Device address - 40001 | Read Holding Registers | | 0x10 (16) | 40001 - 50000 | Device address - 40001 | Write Multiple registers | | 0x04 (4) | 30001 - 40000 | Device address - 30001 | Read Input Registers | > **Note:** If, for example, address 40123 is to be written to (FunctionCode = 0x10), the appropriate data type (unit) must be selected and write address 122 (40123 - 40001) entered. > **Warning:** Some manufacturers do not adhere to this convention. It must be checked in the respective instructions or data sheets whether the device address must be subtracted depending on the function code or whether absolute addresses apply ### Data types | Data type | Sign | Bits | | --------- | -------- | ---- | | BOOL | unsigned | 1 | | UINT8MSB | unsigned | 8 | | UINT8LSB | unsigned | 8 | | UINT16 | unsigned | 16 | | UINT32 | unsigned | 32 | | UINT64 | unsigned | 64 | | INT8MSB | signed | 8 | | INT8LSB | signed | 8 | | INT16 | signed | 16 | | INT32 | signed | 32 | | INT64 | signed | 64 | | FLOAT32 | signed | 32 | | FLOAT64 | signed | 64 | | STRING | | | ## Device list Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/device-list/ ### Supported Gateways/Components IP-Symcon supports all devices that use the ModBus RTU or ModBus TCP protocol. In particular, devices and PLCs from [Wago/Beckhoff/ABB](sps-wago-beckhoff-abb.md). ### Supported Components IP-Symcon supports all components. | Manufacturer | Description | | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------ | | SymBox with RS485 (ModBus RTU) extension [Order now](https://www.symcon.de/en/shop/symbox/bundle-symbox) | Serial integrated module | | Exsys EX-6051 (nonbinding recommendation) | Serial to LAN converter for mode "ModBus RTU over TCP" | | Waveshare RS485 to Ethernet Converter (nonbinding recommendation) | Serial to LAN converter for mode "ModBus RTU over TCP" | ## ModBus_RequestRead Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/modbus-requestread/ `bool ModBus_RequestRead(int $InstanceID)` **Parameters** - `$InstanceID` (int): ID of the device to be switched **Returns** (bool): If the command succeeds, it returns __TRUE__, otherwise __FALSE__. ID of the device to be switched **Example** ```php //Read out device with the ID 12345 ModBus_RequestRead(12345); ``` ## ModBus_WriteCoil Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/modbus-writecoil/ `bool ModBus_WriteCoil(int $InstanceID, bool $Status)` **Parameters** - `$InstanceID` (int): ID of the device to be switched - `$Status` (bool): __TRUE__ for On, __FALSE__ for Off **Returns** (bool): If the command succeeds, it returns __TRUE__, otherwise __FALSE__. __TRUE__ for On, __FALSE__ for Off **Example** ```php //Turns instance with the ID "12345" on ModBus_WriteCoil(12345, true); ``` ## ModBus_WriteRegister Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/modbus-writeregister/ `bool ModBus_WriteRegister(int $InstanceID, float $Value)` writes a value to the write address **Parameters** - `$InstanceID` (int): ID of the device to be switched - `$Value` (float): 32-bit floating point value according to IEEE754 or integer **Returns** (bool): If the command succeeds, it returns __TRUE__, otherwise __FALSE__. 32-bit floating point value according to IEEE754 or integer **Example** ```php ////Writes the value 23.5 to the register of the instance with ID 12345 ModBus_WriteRegister(12345, 23.5); ////Writes the value 12 to the register of the instance with ID 23456 ModBus_WriteRegister(23456, 12); ``` ## ModBus_WriteRegisterByte Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/modbus-writeregisterbyte/ `bool ModBus_WriteRegisterByte(int $InstanceID, int $Value)` **Parameters** - `$InstanceID` (int): ID of the device to be switched - `$Value` (int): 0-255 **Returns** (bool): If the command succeeds, it returns __TRUE__, otherwise __FALSE__. 0-255 **Example** ```php //Writes 123 into the register of the instance with the ID 12345 ModBus_WriteRegisterByte(12345, 123); ``` ## ModBus_WriteRegisterChar Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/modbus-writeregisterchar/ `bool ModBus_WriteRegisterChar(int $InstanceID, int $Value)` _Requires Symcon >= 4.4_ Sets address with ID __InstanceID__ to __Value__ **Parameters** - `$InstanceID` (int): ID of the device to be switched - `$Value` (int): -128 to 127 **Returns** (bool): If the command succeeds, it returns __TRUE__, otherwise __FALSE__. -128 to 127 **Example** ```php //Writes -123 into the register of the instance with the ID 12345 ModBus_WriteRegisterChar(12345, -123); ``` ## ModBus_WriteRegisterDWord Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/modbus-writeregisterdword/ `bool ModBus_WriteRegisterDWord(int $InstanceID, int $Wert)` **Parameters** - `$InstanceID` (int): ID of the device to be switched - `$Wert` (int): 0-4294967295 **Returns** (bool): If the command succeeds, it returns __TRUE__, otherwise __FALSE__. 0-4294967295 **Example** ```php //Writes 123 into the register of the instance with the ID 12345 ModBus_WriteRegisterDWord(12345, 123); ``` ## ModBus_WriteRegisterInt64 Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/modbus-writeregisterint64/ `bool ModBus_WriteRegisterInt64(int $InstanceID, int $Value)` **Parameters** - `$InstanceID` (int): ID of the device to be switched - `$Value` (int): -9223372036854775808 bis 9223372036854775807 **Returns** (bool): If the command succeeds, it returns __TRUE__, otherwise __FALSE__. -9223372036854775808 bis 9223372036854775807 **Example** ```php //Writes -123 into the register of the instance with the ID 12345 ModBus_WriteRegisterInt64(12345, -123); ``` ## ModBus_WriteRegisterInteger Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/modbus-writeregisterinteger/ `bool ModBus_WriteRegisterInteger(int $InstanceID, int $Value)` **Parameters** - `$InstanceID` (int): ID of the device to be switched - `$Value` (int): -2147483648 bis 2147483647 **Returns** (bool): If the command succeeds, it returns __TRUE__, otherwise __FALSE__. -2147483648 bis 2147483647 **Example** ```php //Writes -123 into the register of the instance with the ID 12345 ModBus_WriteRegisterInteger(12345, -123); ``` ## ModBus_WriteRegisterReal Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/modbus-writeregisterreal/ `bool ModBus_WriteRegisterReal(int $InstanceID, float $Value)` **Parameters** - `$InstanceID` (int): ID of the device to be switched - `$Value` (float): 32bit floating point value according to IEEE754 **Returns** (bool): If the command succeeds, it returns __TRUE__, otherwise __FALSE__. 32bit floating point value according to IEEE754 **Example** ```php //Writes 23.5 into the register of the instance with the ID 12345 ModBus_WriteRegisterReal(12345, 23.5); ``` ## ModBus_WriteRegisterReal64 Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/modbus-writeregisterreal64/ `bool ModBus_WriteRegisterReal64(int $InstanceID, float $Value)` **Parameters** - `$InstanceID` (int): ID of the device to be switched - `$Value` (float): 64bit floating point value according to IEEE754 **Returns** (bool): If the command succeeds, it returns __TRUE__, otherwise __FALSE__. 64bit floating point value according to IEEE754 **Example** ```php //Writes 23.5 into the register of the instance with the ID 12345 ModBus_WriteRegisterReal64(12345, 23.5); ``` ## ModBus_WriteRegisterShort Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/modbus-writeregistershort/ `bool ModBus_WriteRegisterShort(int $InstanceID, int $Value)` _Requires Symcon >= 4.4_ Sets address with ID __InstanceID__ to __Value__ **Parameters** - `$InstanceID` (int): ID of the device to be switched - `$Value` (int): -32768 to 32767 **Returns** (bool): If the command succeeds, it returns __TRUE__, otherwise __FALSE__. -32768 to 32767 **Example** ```php //Writes -123 into the register of the instance with the ID 12345 ModBus_WriteRegisterShort(12345, -123); ``` ## ModBus_WriteRegisterString Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/modbus-writeregisterstring/ `bool ModBus_WriteRegisterString(int $InstanceID, string $Value)` **Parameters** - `$InstanceID` (int): ID of the device to be switched - `$Value` (string): String which should be written into register **Returns** (bool): If the command succeeds, it returns __TRUE__, otherwise __FALSE__. String which should be written into register **Example** ```php //Writes "Hello world" into the register of the instance with the ID 12345 ModBus_WriteRegisterString(12345, "Hello world"); ``` ## ModBus_WriteRegisterWord Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/modbus-writeregisterword/ `bool ModBus_WriteRegisterWord(int $InstanceID, int $Value)` **Parameters** - `$InstanceID` (int): ID of the device to be switched - `$Value` (int): 0-65535 **Returns** (bool): If the command succeeds, it returns __TRUE__, otherwise __FALSE__. 0-65535 **Example** ```php //Writes 123 into the register of the instance with the ID 12345 ModBus_WriteRegisterWord(12345, 123); ``` ## Templates (file format) Source: https://www.symcon.de/en/service/documentation/module-reference/devices/modbus-rtu-tcp/templates/ _Requires Symcon >= 7.0_ The "ModBus Device" instance can export its complete configuration as a template and import it again. A template is a JSON file containing all addresses, virtual addresses, required variable profiles, the byte order and the polling settings. A device that has been set up once can thus be set up on other systems with a few clicks or shared with other users. > **Note:** Many ready-made templates can be found in our community: [Show templates](https://community.symcon.de/c/symcon/vorlagen-modbus/86) This page describes the file format completely, so that templates can also be created directly from a manufacturer's data sheet or generated by a script. ### Import and export | Action | Description | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Export template | Creates a JSON file from the current configuration. All used profiles that do not start with "~" are exported as well. | | Import template | Replaces addresses, virtual addresses, byte order and polling settings in the configuration form. The changes are only saved with "Apply". Missing profiles are created in the process, existing profiles are not modified. | The file is checked before the import. If it does not contain the three keys "Addresses", "VirtualAddresses" and "Profiles", the import is aborted with the message "This is not a valid ModBus template!". If a profile already exists with different settings, a hint is shown (e.g. "2 profiles do not match!"). In this case the existing profile is used. > **Warning:** The import overwrites the existing configuration of the instance. Variables whose ident no longer occurs in the new configuration are deleted when applying - including their archive data. ### Structure A template is a JSON object with the following keys: | Key | Type | Required | Description | | ---------------- | ------ | -------- | -------------------------------------------------------------------------------------------- | | Addresses | Array | Yes | List of Modbus addresses, see Addresses | | VirtualAddresses | Array | Yes | List of virtual addresses, see Virtual addresses, may be empty | | Profiles | Object | Yes | Variable profiles created on import, see Profiles, may be empty | | ByteOrder | Number | No | Byte order of the instance, see Byte order | | Requests | Object | No | Polling settings, see Polling | The order of the keys is arbitrary. Unknown keys are ignored. A minimal, valid template with a single address looks like this: ```php { "Addresses": [ { "Active": true, "Name": "Battery state of charge", "Ident": "battery_soc", "Translation": [ { "Language": "de", "Name": "Batterieladezustand" } ], "DataType": 2, "ReadFunctionCode": 4, "ReadAddress": 33139, "WriteFunctionCode": 0, "WriteAddress": 0, "Factor": 0, "Length": 0, "ByteOrder": -1, "Profile": "~Battery.100" } ], "VirtualAddresses": [], "Profiles": {}, "ByteOrder": 0, "Requests": { "Type": 0, "Interval": 5000, "DataBlocks": [] } } ``` ### Addresses Each entry in "Addresses" describes one value of the device. A variable is created below the instance for each active entry. | Field | Type | Description | | ----------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Active | Bool | Defines whether the variable is created and the value is read. Inactive entries remain in the template and can be activated by the user later. | | Name | String | Name of the variable. An English name translated via "Translation" is recommended. | | Ident | String | Ident of the variable. If the field is empty, the ident is generated automatically, see Ident. | | Translation | Array | Translations of the name as a list of objects with "Language" (e.g. "de") and "Name". | | DataType | Number | Data type of the register, see Data types. | | ReadFunctionCode | Number | Function code for reading: 0 (do not read), 1, 2, 3 or 4, see Function codes. | | ReadAddress | Number | Read address (start register or coil), see Addressing. | | WriteFunctionCode | Number | Function code for writing: 0 (do not write), 5, 6, 15 or 16. If a function code is set, the variable gets a standard action. | | WriteAddress | Number | Write address. Usually identical to the read address. | | Factor | Number | Factor the read value is multiplied with. 0 means "no factor", see Factor. | | Length | Number | Strings only: length in bytes (2 bytes per register). 0 for all other data types. | | ByteOrder | Number | Byte order of this address. -1 uses the setting of the instance, see Byte order. | | Profile | String | Name of the variable profile or empty. The profile type must match the variable type, see Data types. | > **Warning:** All fields should always be specified completely and with the correct JSON type. Numbers must not be given as a string ("3") or as null, otherwise applying the configuration fails. The exception is "Active": if it is missing, the address is considered active. Older exports sometimes contain additional fields like "SwapBytes" or "CustomFactor". These are ignored and can be omitted. The value of a custom factor is always stored in the field "Factor". ### Data types in templates In the template the data type is stored as a number. For compatibility reasons the numbers are not sorted by size. | DataType | Shown in the console | Registers | Variable type (without factor) | | -------- | -------------------- | --------- | ------------------------------ | | 0 | BOOL | 1 bit | Boolean | | 1 | UINT8 (MSB) | 1 | Integer | | 12 | UINT8 (LSB) | 1 | Integer | | 2 | UINT16 | 1 | Integer | | 3 | UINT32 | 2 | Integer | | 11 | UINT64 | 4 | Float | | 4 | INT8 (MSB) | 1 | Integer | | 13 | INT8 (LSB) | 1 | Integer | | 5 | INT16 | 1 | Integer | | 6 | INT32 | 2 | Integer | | 8 | INT64 | 4 | Float | | 7 | FLOAT32 | 2 | Float | | 9 | FLOAT64 | 4 | Float | | 10 | STRING (PLAIN) | Length/2 | String | | 14 | STRING (HEX) | Length/2 | String | - __MSB/LSB:__ UINT8/INT8 read a whole register and use the high-order (MSB) or the low-order byte (LSB). This way two 8 bit values can be read from one register with two entries on the same address. - __64 bit:__ INT64 and UINT64 are mapped to a float variable because Symcon also supports 32 bit systems. - __STRING (PLAIN):__ The bytes are interpreted as text. Spaces and null bytes at the beginning and end are removed. - __STRING (HEX):__ The bytes are shown as a hex string (upper case), e.g. "0A1B". This is useful for bit fields, version numbers or MAC addresses. - __Factor:__ As soon as a factor other than 0 is set, the variable is always created as float - also for integer data types and also for the factor 1. > **Warning:** The type of a profile must match the variable type. A UINT16 register without factor results in an integer variable and can therefore not get the float profile "~Watt", for example. If an integer value should get a float profile, the factor 1 can be set. ### Function codes and addresses | Function code | Direction | Name | Allowed data types | | ------------- | --------- | ------------------------ | ------------------- | | 1 | Read | Read Coils | BOOL | | 2 | Read | Read Discrete Inputs | BOOL | | 3 | Read | Read Holding Registers | all except BOOL | | 4 | Read | Read Input Registers | all except BOOL | | 5 | Write | Write Single Coil | BOOL | | 15 | Write | Write Multiple Coils | BOOL | | 6 | Write | Write Single Register | 8/16 bit types only | | 16 | Write | Write Multiple Registers | all except BOOL | Invalid combinations are rejected with an error message when applying, e.g. "Non-Bit values must use function Read Holding Registers/Read Input Registers" or "Writing in only one register is not possible for multi register values like Int32/UInt32, Int64/UInt64, Float32/Float64, String". __Addressing:__ "ReadAddress" and "WriteAddress" are the addresses that are actually transmitted in the Modbus telegram, starting at 0. Many data sheets use the classic notation with a prefix instead (e.g. 40001 for the first holding register). In this case the prefix has to be subtracted, see [Function codes](modbus-rtu-tcp.md). Other manufacturers already specify the addresses directly (e.g. Solis with 33000 for an input register). If in doubt, a test with a known value like the serial number or the grid frequency helps. ### Byte order The byte order is defined for the whole instance in the top-level key "ByteOrder". Single addresses can override it with their own "ByteOrder" field. The value -1 uses the setting of the instance. The examples show how the 32 bit value 0x11223344 is transmitted by the device: | ByteOrder | Name | Transmitted bytes | Typical description in the data sheet | | --------- | -------------------------- | ----------------- | ------------------------------------------------ | | -1 | Inherited from device | - | address level only | | 0 | Big-Endian (Standard) | 11 22 33 44 | "High word first", "ABCD", Modbus standard | | 1 | Little-Endian | 44 33 22 11 | "DCBA" | | 2 | Big-Endian (Byte Swap) | 22 11 44 33 | "BADC" | | 3 | Little-Endian (Byte Swap) | 33 44 11 22 | "Low word first", "Word swap", "CDAB" | For 16 bit values only 1 and 2 have an effect (bytes swapped within the register). The byte order has no meaning for BOOL values. ### Factor The raw value is multiplied by "Factor" before it is written into the variable. When writing, the value is divided by the factor first. The factor is always a multiplier: a division by 10 is specified as 0.1. | Data sheet | Factor | | --------------------- | ------- | | Unit 0.1 V | 0.1 | | Unit 0.01 Hz | 0.01 | | Unit 10 W | 10 | | Wh, wanted in kWh | 0.001 | | no factor | 0 | The factor must be 0 for BOOL and string addresses. If the device provides its own scale factor in a register (e.g. SunSpec "Scale Factor"), it can be applied using a virtual address. ### Ident The ident identifies the variable permanently. If "Ident" is empty, it is generated from data type, function code and read address: A_[DataType]_[ReadFunctionCode]_[ReadAddress], e.g. "A_7_3_100". For virtual addresses the name is used, with all characters except letters, digits and underscore replaced by "_". > **Warning:** Without a fixed ident, the ident changes as soon as data type, function code or address (or the name for virtual addresses) are modified. The old variable is then deleted including its archive data and a new one is created. Templates should therefore always set a fixed, meaningful ident like "battery_soc". Each ident must only occur once - also not between addresses and virtual addresses. The ident is also used in the scripts of the virtual addresses to access the values. ### Virtual addresses Virtual addresses calculate a variable with PHP from the values of the other addresses or distribute a written value to one or more addresses. | Field | Type | Description | | ------------ | ------ | -------------------------------------------------------------------------------------------- | | Active | Bool | Defines whether the variable is created and the scripts are executed. | | Name | String | Name of the variable | | Ident | String | Ident of the variable. If the field is empty, the ident is generated from the name. | | Translation | Array | Translations of the name, like for addresses | | VariableType | Number | 0 = Boolean, 1 = Integer, 2 = Float, 3 = String | | Profile | String | Name of the variable profile or empty. The profile type must match the VariableType. | | ReadAction | String | PHP code to calculate the value, empty for no calculation | | WriteAction | String | PHP code for writing. If it is set, the variable gets a standard action. | The scripts only contain the body of a function, i.e. without ` ($current & ~0x0F) | ($VALUE & 0x0F)]; ``` > **Note:** The operator ?? 0 prevents errors as long as an address has not been read yet or is inactive. If a script outputs errors, they can be found in the debug of the instance under the ident of the virtual address. Values are only written if they change or the variable is older than 60 seconds. This applies to read addresses as well as virtual addresses. ### Profiles "Profiles" is an object with the profile name as key. Profiles whose name starts with "~" are system profiles. They are not exported and do not have to be contained in the template. Custom profiles should get a unique prefix (e.g. "Vendor.Name") so that they do not collide with profiles of other templates. | Field | Type | Description | | ------------ | ------ | ------------------------------------------------------------------------------- | | Type | Number | 0 = Boolean, 1 = Integer, 2 = Float, 3 = String | | Prefix | String | Prefix | | Suffix | String | Suffix, including a leading space, e.g. " W" | | MinValue | Number | Minimum value | | MaxValue | Number | Maximum value | | StepSize | Number | Step size. For switchable variables it defines the display as slider. | | Digits | Number | Number of decimal places | | Icon | String | Name of the icon or empty | | Associations | Array | Associations, each with "Value", "Name", "Icon" and "Color" (-1 = no color) | All fields must be specified. The JSON type of "Value" in the associations should match the profile type (true/false for Boolean, whole number for Integer). ```php "Profiles": { "Vendor.OperatingMode": { "Type": 1, "Prefix": "", "Suffix": "", "MinValue": 0.0, "MaxValue": 0.0, "StepSize": 0.0, "Digits": 0, "Icon": "Information", "Associations": [ { "Value": 0, "Name": "Standby", "Icon": "", "Color": -1 }, { "Value": 1, "Name": "Running", "Icon": "", "Color": 65280 } ] } } ``` > **Note:** Only missing profiles are created on import. An existing profile with the same name is not modified, even if it differs. ### Polling The key "Requests" contains the polling settings: | Field | Type | Description | | ---------- | ------ | ------------------------------------------------------------------------------------------------- | | Type | Number | 0 = Single addresses, 1 = Data blocks | | Interval | Number | Polling interval in milliseconds for the type "Single addresses". 0 disables polling. | | DataBlocks | Array | Data blocks for the type "Data blocks" | __Single addresses:__ In each interval every active address with a read function code is polled individually. This is simple, but creates a lot of requests for many addresses. Especially with Modbus RTU or slow data loggers the time is often not sufficient. __Data blocks:__ Each data block reads a contiguous range with a single request and has its own interval. Afterwards all addresses that are completely within the block and use the same function code are updated. This way measured values can be read every 5 seconds and meter readings only every minute, for example. | Field | Type | Description | | -------- | ------ | ---------------------------------------------------- | | Function | Number | Function code 1, 2, 3 or 4 | | Address | Number | Start address | | Quantity | Number | Number of registers or coils (at most 125 registers) | | Poller | Number | Interval in milliseconds | ```php "Requests": { "Type": 1, "Interval": 5000, "DataBlocks": [ { "Function": 4, "Address": 33049, "Quantity": 10, "Poller": 5000 }, { "Function": 4, "Address": 33161, "Quantity": 20, "Poller": 60000 }, { "Function": 3, "Address": 43110, "Quantity": 1, "Poller": 10000 } ] } ``` > **Warning:** With the type "Data blocks", addresses that are not within any data block are not updated. A data block should only cover registers that the device actually supports - many devices answer a request with a gap in the register range with an error (ILLEGAL_DATA_ADDRESS) for the whole block. ### Checklist - All three required keys "Addresses", "VirtualAddresses" and "Profiles" are present, even if they are empty. - Each address contains all fields with the correct JSON type (no strings or null instead of numbers). - Each address and virtual address has a fixed, unique ident. - Names are English and have a German translation in "Translation". - Addresses are specified as they are transmitted in the telegram (without 30001/40001 prefix). - Function code and data type match (BOOL only with 1, 2, 5, 15; multi register values not with 6). - The profile type matches the variable type (a factor other than 0 always results in float). - Custom profiles have a unique prefix and are completely contained in "Profiles". - Rarely needed values are included with "Active": false instead of being omitted. - Data blocks are used for many addresses and every active address is within a block. - The template has been imported, applied and exported again once. The export must contain the same addresses.