The binding can also _write_ data to Modbus slaves using FC05 (Write single coil), FC06 (Write single holding register), FC15 (Write multiple coils) or FC16 (Write multiple holding registers).
- The binding does _not_ act as Modbus slave (e.g. as Modbus TCP server).
- The binding _does_ support Modbus RTU over Modbus TCP, (also known as "Modbus over TCP/IP" or "Modbus over TCP" or "Modbus RTU/IP"), as well as normal "Modbus TCP".
- [binaryconvert.com](https://www.binaryconvert.com/): tool to convert numbers between different binary presentations
- [rapidscada.net Modbus parser](https://modbus.rapidscada.net/): tool to parse Modbus requests and responses. Useful for debugging purposes when you want to understand the message sent / received.
- [JSFiddle tool](https://jsfiddle.net/rgypuuxq/) to test JavaScript (JS) transformations interactively
| `poller` | Bridge | Thing taking care of polling the data from modbus slaves. One poller corresponds to single Modbus read request (FC01, FC02, FC03, or FC04). Is child of `tcp` or `serial`. |
| `data` | Thing | thing for converting polled data to meaningful numbers. Analogously, is responsible of converting openHAB commands to Modbus write requests. Is child of `poller` (read-only or read-write things) or `tcp`/`serial` (write-only things). |
Typically one defines either `tcp` or `serial` bridge, depending on the variant of Modbus slave.
For each Modbus read request, a `poller` is defined.
Finally, one ore more `data` things are introduced to extract relevant numbers from the raw Modbus data.
For write-only communication, `data` things can be introduced directly as children of `tcp` or `serial` bridges.
## Binding Configuration
Other than the things themselves, there is no binding configuration.
## Serial Port Configuration
With serial Modbus slaves, configuration of the serial port in openHAB is important.
Otherwise you might encounter errors preventing all communication.
See [general documentation about serial port configuration](/docs/administration/serial.html) to configure the serial port correctly.
## Thing Configuration
In the tables below the thing configuration parameters are grouped by thing type.
| `timeBetweenTransactionsMillis` | | integer | `60` | How long to delay we must have at minimum between two consecutive MODBUS transactions. In milliseconds. |
| `timeBetweenReconnectMillis` | | integer | `0` | How long to wait to before trying to establish a new connection after the previous one has been disconnected. In milliseconds. |
| `connectMaxTries` | | integer | `1` | How many times we try to establish the connection. Should be at least 1. |
| `afterConnectionDelayMillis` | | integer | `0` | Connection warm-up time. Additional time which is spent on preparing connection which should be spent waiting while end device is getting ready to answer first modbus call. In milliseconds. |
| `reconnectAfterMillis` | | integer | `0` | The connection is kept open at least the time specified here. Value of zero means that connection is disconnected after every MODBUS transaction. In milliseconds. |
| `connectTimeoutMillis` | | integer | `10000` | The maximum time that is waited when establishing the connection. Value of zero means that system/OS default is respected. In milliseconds. |
| `enableDiscovery` | | boolean | false | Enable auto-discovery feature. Effective only if a supporting extension has been installed. |
**Note:** Advanced parameters must be equal for all `tcp` things sharing the same `host` and `port`.
The advanced parameters have conservative defaults, meaning that they should work for most users.
In some cases when extreme performance is required (e.g. poll period below 10 ms), one might want to decrease the delay parameters, especially `timeBetweenTransactionsMillis`.
Similarly, with some slower devices on might need to increase the values.
### `serial` Thing
`serial` is representing a particular Modbus serial slave.
| port | text | ✓ | | Serial port to use, for example `"/dev/ttyS0"` or `"COM1"` | |
| id | integer | | `1` | Slave id. Also known as station address or unit identifier. See [Wikipedia](https://en.wikipedia.org/wiki/Modbus) and [simplymodbus](https://www.simplymodbus.ca/index.html) articles for more information | |
| echo | boolean | | `false` | Flag for setting the RS485 echo mode. This controls whether we should try to read back whatever we send on the line, before reading the response. Valid values are: `true`, `false`. | |
| `receiveTimeoutMillis` | | integer | `1500` | Timeout for read operations. In milliseconds. |
| `flowControlIn` | | text | `"none"` | Type of flow control for receiving. Valid values are: `"none"`, `"xon/xoff in"`, `"rts/cts in"`. |
| `flowControlOut` | | text | `"none"` | Type of flow control for sending. Valid values are: `"none"`, `"xon/xoff out"`, `"rts/cts out"`. |
| `timeBetweenTransactionsMillis` | | integer | `35` | How long to delay we must have at minimum between two consecutive MODBUS transactions. In milliseconds. |
| `connectMaxTries` | | integer | `1` | How many times we try to establish the connection. Should be at least 1. |
| `afterConnectionDelayMillis` | | integer | `0` | Connection warm-up time. Additional time which is spent on preparing connection which should be spent waiting while end device is getting ready to answer first modbus call. In milliseconds. |
| `connectTimeoutMillis` | | integer | `10000` | The maximum time that is waited when establishing the connection. Value of zero means thatsystem/OS default is respected. In milliseconds. |
| `enableDiscovery` | | boolean | false | Enable auto-discovery feature. Effective only if a supporting extension has been installed. |
With the exception of `id` parameters should be equal for all `serial` things sharing the same `port`.
These parameters have conservative defaults, meaning that they should work for most users.
In some cases when extreme performance is required (e.g. poll period below 10ms), one might want to decrease the delay parameters, especially `timeBetweenTransactionsMillis`.
With some slower devices on might need to increase the values.
With low baud rates and/or long read requests (that is, many items polled), there might be need to increase the read timeout `receiveTimeoutMillis` to e.g. `5000` (=5 seconds).
### `poller` Thing
`poller` thing takes care of polling the Modbus serial slave or Modbus TCP server data regularly.
You must give each of your bridge Things a reference (thing ID) that is unique for this binding.
| Parameter | Type | Required | Default if omitted | Description |
| `type` | text | ✓ | (-) | Type of modbus items to poll. This matches directly to Modbus request type or function code (FC). Valid values are: `"coil"` (FC01), `"discrete"` (FC02), `"holding"`(FC03), `"input"` (FC04). |
| `refresh` | integer | | `500` | Poll interval in milliseconds. Use zero to disable automatic polling. |
| `maxTries` | integer | | `3` | Maximum tries when reading. <br/><br/>Number of tries when reading data, if some of the reading fail. For single try, enter 1. |
| `cacheMillis` | integer | | `50` | Duration for data cache to be valid, in milliseconds. This cache is used only to serve `REFRESH` commands. Use zero to disable the caching. |
Polling can be manually triggered by sending `REFRESH` command to item bound to channel of `data` thing.
When manually triggering polling, a new poll is executed as soon as possible, and sibling `data` things (i.e. things that share the same `poller` bridge) are updated.
In case the `poller` had just received a data response or an error occurred, a cached response is used instead.
See [Refresh command](#refresh-command) section for more details.
Some devices do not allow to query too many registers in a single readout action or a range that spans reserved registers.
Split your poller into multiple smaller ones to work around this problem.
### `data` Thing
`data` is responsible of extracting relevant piece of data (e.g. a number `3.14`) from binary received from the slave.
Similarly, `data` thing is responsible of converting openHAB commands to write requests to the Modbus slave.
n.b. note that some numerics like 'readStart' need to be entered as 'text'.
You must give each of your data Things a reference (thing ID) that is unique for this binding.
| Parameter | Type | Required | Default if omitted | Description |
| `readValueType` | text | | (empty) | How data is read from modbus. Use empty for write-only things.<br/><br/>Bit value type must be used with coils and discrete inputs. With registers all value types are applicable. Valid values are: `"int64"`, `"int64_swap"`, `"uint64"`, `"uint64_swap"`, `"float32"`, `"float32_swap"`, `"int32"`, `"int32_swap"`, `"uint32"`, `"uint32_swap"`, `"int16"`, `"uint16"`, `"int8"`, `"uint8"`, or `"bit"`. See also [Value types on read and write](#value-types-on-read-and-write). |
| `readStart` | text | | (empty) | Start address to start reading the value. Use empty for write-only things. <br/><br/>Input as zero-based index number, e.g. in place of `400001` (first holding register), use the address `"0"`. Must be between (poller start) and (poller start + poller length - 1) (inclusive).<br/><br/>With registers and value type less than 16 bits, you must use `"X.Y"` format where `Y` specifies the sub-element to read from the 16 bit register:<ul><li>For example, `"3.1"` would mean pick second bit from register index `3` with bit value type. </li><li>With int8 valuetype, it would pick the high byte of register index `3`.</li></ul> |
| `readTransform` | text | | `"default"` | Transformation to apply to polled data, after it has been converted to number using `readValueType`. <br/><br/>Use "default" to communicate that no transformation is done and value should be passed as is.<br/>Use `"SERVICENAME(ARG)"` or `"SERVICENAME:ARG"` to use transformation service `SERVICENAME` with argument `ARG`. <br/>Any other value than the above types will be interpreted as static text, in which case the actual content of the polled value is ignored. You can chain many transformations with ∩, for example `"SERVICE1(ARG1)∩SERVICE2(ARG2)"`. |
| `writeValueType` | text | | (empty) | How data is written to modbus. Only applicable to registers. Valid values are: `"int64"`, `"int64_swap"`, `"float32"`, `"float32_swap"`, `"int32"`, `"int32_swap"`, `"int16"`. See also [Value types on read and write](#value-types-on-read-and-write). Value of `"bit"` can be used with registers as well when `writeStart` is of format `"X.Y"` (see below). See also [Value types on read and write](#value-types-on-read-and-write). |
| `writeStart` | text | | (empty) | Start address of the first holding register or coil in the write. Use empty for read-only things. <br/>Use zero based address, e.g. in place of `400001` (first holding register), use the address `"0"`. This address is passed to data frame as is. One can use `"X.Y"` to write individual bit `Y` of an holding `X` (analogous to `readStart`). |
| `writeType` | text | | (empty) | Type of data to write. Use empty for read-only things. Valid values: `"coil"` or `"holding"`.<br/><br/> Coil uses function code (FC) FC05 or FC15. Holding register uses FC06 or FC16. See `writeMultipleEvenWithSingleRegisterOrCoil` parameter. |
| `writeTransform` | text | | `"default"` | Transformation to apply to received commands.<br/><br/>Use `"default"` to communicate that no transformation is done and value should be passed as is. <br/>Use `"SERVICENAME(ARG)"` or `"SERVICENAME:ARG"` to use transformation service `SERVICENAME` with argument `ARG`. <br/>Any other value than the above types will be interpreted as static text, in which case the actual content of the command value is ignored. You can chain many transformations with ∩, for example `"SERVICE1(ARG1)∩SERVICE2(ARG2)"`. |
| `writeMultipleEvenWithSingleRegisterOrCoil` | boolean | | `false` | Controls how single register / coil of data is written.<br/> By default, or when 'false, FC06 ("Write single holding register") / FC05 ("Write single coil"). Or when 'true', using FC16 ("Write Multiple Holding Registers") / FC15 ("Write Multiple Coils"). |
| `writeMaxTries` | integer | | `3` | Maximum tries when writing <br/><br/>Number of tries when writing data, if some of the writes fail. For single try, enter `1`. |
| `updateUnchangedValuesEveryMillis` | integer | | `1000` | Interval to update unchanged values. <br/><br/>Modbus binding by default is not updating the item and channel state every time new data is polled from a slave, for performance reasons. Instead, the state is updated whenever it differs from previously updated state, or when enough time has passed since the last update. The time interval can be adjusted using this parameter. Use value of `0` if you like to update state with every poll, even though the value has not changed. In milliseconds. |
## Channels
Only the `data` thing has channels.
It has several "data channels", serving the polled data in different formats, and for accepting openHAB commands from different item types.
Please note that transformations might be _necessary_ in order to update some data channels, or to convert some openHAB commands to suitable Modbus data.
| `lastReadSuccess` | `DateTime` | Last successful read |
| `lastReadError` | `DateTime` | Last erroring read |
| `lastWriteSuccess` | `DateTime` | Last successful write |
| `lastWriteError` | `DateTime` | Last erroring write |
## Item configuration
Items are configured the typical way, using `channel` to bind the item to a particular channel.
For example, in the following example, item `Temperature_Modbus_Livingroom` is bound to channel `number` of thing `modbus:data:siemensplc:holding:livingroom_temperature`.
Number Temperature_Modbus_Livingroom "Temperature Living room [%.1f °C]" <temperature> { channel="modbus:data:siemensplc:holding:livingroom_temperature:number" }
```
Make sure you bind item to a channel that is compatible, or use transformations to make it compatible.
See [Transformations](#transformations) section for more information on transformation.
### `autoupdate` parameter with items
By default, openHAB has `autoupdate` enabled.
This means that item _state_ is updated according to received commands.
In some situations this might have unexpected side effects with polling bindings such as Modbus - see example below.
Typically, you see something like this
```java
1 [ome.event.ItemCommandEvent] - Item 'Kitchen_Bar_Table_Light' received command ON
2 [vent.ItemStateChangedEvent] - Kitchen_Bar_Table_Light changed from OFF to ON
3 [vent.ItemStateChangedEvent] - Kitchen_Bar_Table_Light changed from ON to OFF
4 [vent.ItemStateChangedEvent] - Kitchen_Bar_Table_Light changed from OFF to ON
```
Let's go through it step by step
```java
// openHAB UI switch changed command is sent
1 [ome.event.ItemCommandEvent] - Item 'Kitchen_Bar_Table_Light' received command ON
// openHAB immediately updates the item state to match the command
2 [vent.ItemStateChangedEvent] - Kitchen_Bar_Table_Light changed from OFF to ON
// modbus binding poll completes (old value)
3 [vent.ItemStateChangedEvent] - Kitchen_Bar_Table_Light changed from ON to OFF
// (the binding writes the command over Modbus to the slave)
// modbus binding poll completes (updated value)
4 [vent.ItemStateChangedEvent] - Kitchen_Bar_Table_Light changed from OFF to ON
```
To prevent this "state fluctuation" (`OFF` -> `ON` -> `OFF` -> `ON`), some people prefer to disable `autoupdate` on Items used with polling bindings.
With `autoupdate` disabled, one would get
```java
// openHAB UI switch changed command is sent
1 [ome.event.ItemCommandEvent] - Item 'Kitchen_Bar_Table_Light' received command ON
// modbus binding poll completes (STILL the old value) -- UI not updated, still showing OFF
// (the binding writes the command over Modbus to the slave)
// modbus binding poll completes (updated value)
4 [vent.ItemStateChangedEvent] - Kitchen_Bar_Table_Light changed from OFF to ON
```
Item state has no "fluctuation", it updates from `OFF` to `ON`.
To summarize (credits to [rossko57's community post](https://community.openhab.org/t/rule-to-postupdate-an-item-works-but-item-falls-back-after-some-seconds/19986/2?u=ssalonen)):
Number Temperature_Modbus_Livingroom "Temperature Living room [%.1f °C]" <temperature> { channel="modbus:data:siemensplc:holding:livingroom_temperature:number", autoupdate="false" }
```
Main documentation on `autoupdate` in [Items section of openHAB docs](https://www.openhab.org/docs/configuration/items.html#item-definition-and-syntax).
Device specific modbus bindings can take part in the discovery of things, and detect devices automatically. The discovery is initiated by the `tcp` and `serial` bridges when they have `enableDiscovery` setting enabled.
Note that the main binding does not recognize any devices, so it is pointless to turn this on unless you have a suitable add-on binding installed.
## Details
### Comment On Addressing
[Modbus Wikipedia article](https://en.wikipedia.org/wiki/Modbus#Coil.2C_discrete_input.2C_input_register.2C_holding_register_numbers_and_addresses) summarizes this excellently:
> In the traditional standard, [entity] numbers for those entities start with a digit, followed by a number of four digits in range 1–9,999:
- same as `int64` except value is interpreted as unsigned integer
The MODBUS specification defines each 16bit word to be encoded as Big Endian,
but there is no specification on the order of those words within 32bit or larger data types.
The net result is that when you have a master and slave that operate with the same Endian mode things work fine,
but add a device with a different Endian mode and it is very hard to correct.
To resolve this the binding supports a second set of valuetypes that have the words swapped.
If you get strange values using the `int32`, `uint32`, `float32`, `int64`, or `uint64` valuetypes then just try the `int32_swap`, `uint32_swap`, `float32_swap`, `int64_swap`, or `uint64_swap` valuetype, depending upon what your data type is.
- same as `uint64` except value is interpreted as unsigned integer
### REFRESH Command
`REFRESH` command to item bound to any [data channel](#channels) makes `poller` thing to poll new from the Modbus slave.
All data channels of children `data` things are refreshed per the normal logic.
`REFRESH` can be useful tool if you like to refresh only on demand (`poller` has refresh disabled, i.e. `refresh=0`), or have custom logic of refreshing only in some special cases.
Note that poller has `cacheMillis` parameter to re-use previously received data, and thus avoid polling the Modbus slave too much.
This parameter is specifically limiting the flood of requests that come when openHAB itself is calling `REFRESH` for new things.
### Read Steps
Every time data is read by the binding, these steps are taken to convert the raw binary data to actual item `State` in openHAB:
1. Poll the data from Modbus slave.
Data received is stored in list of bits (discrete inputs and coils), or in list of registers (input registers and holding registers)
1. Extract a single number from the polled data, using specified location `readStart` and number "value type" `readValueType`.
As an example, we can tell the binding to extract 32-bit float (`readValueType="float32"`) from register index `readStart="105"`.
1. Number is converted to string (e.g. `"3.14"`) and passed as input to the transformation.
Note that in case `readTransform="default"`, a default transformation provided by the binding is used.
See [Transformations](#transformations) section for more details.
1. For each [data channel](#channels), we try to convert the transformation output of previous step to a State type (e.g. `ON`/`OFF`, or `DecimalType`) accepted by the channel.
If all the conversions fail (e.g. trying to convert `ON` to a number), the data channel is not updated.
In case of read errors, all data channels are left unchanged, and `lastReadError` channel is updated with current time.
Examples of errors include connection errors, IO errors on read, and explicit exception responses from the slave.
Note: there is a performance optimization that channel state is only updated when enough time has passed since last update, or when the state differs from previous update.
See `updateUnchangedValuesEveryMillis` parameter in `data` thing.
### Write Steps
#### Basic Case
Commands passed to openHAB items that are bound to a [data channel](#channels) are most often processed according to following steps:
1. Command is sent to openHAB item, that is bound to a [data channel](#channels).
Command must be such that it is accepted by the item in the first place
1. Command is converted to string (e.g. `"3.14"`) and passed to the transformation.
Note that in case `readTransform="default"`, a default transformation provided by the binding is used.
See [Transformations](#transformations) section for more details.
-`writeType="holding"`: First, the command from the transformation is converted `1`/`0` number in case of `OPEN`/`ON` or `CLOSED`/`OFF`. The number is converted to one or more registers using `writeValueType`.
1. Boolean (`writeType="coil"`) or registers (`writeType="holding"`) are written to the Modbus slave using `FC05`, `FC06`, `FC15`, or `FC16`, depending on the value of `writeMultipleEvenWithSingleRegisterOrCoil`.
Write is tried maximum of 10 times in case some of the writes fail.
The JSON transformation output can be useful when you need full control how the write goes, for example in case where the write address depends on the incoming command.
Actually, you can omit specifying `writeStart`, `writeValueType` and `writeType` with JSON transformation output altogether.
Empty JSON array (`[]`) can be used to suppress all writes.
Explanation for the different properties of the JSON object in the array.
| Key name | Value type | Required | Default if omitted | Description |
| `functionCode` | number | ✓ | (-) | Modbus function code to use with write. Use one of `5`, `6`, `15` or `16`. |
| `address` | number | ✓ | (-) | Start address of the first holding register or coil in the write. Use empty for read-only things. <br/>Use zero based address, e.g. in place of 400001 (first holding register), use the address 0. This address is passed to data frame as is. |
| `value` | JSON array of numbers | ✓ | (-) | Array of coil or register values. Encode coil values as `0` or `1`. |
| `maxTries` | number | | 3 | Number of tries when writing data, in case some of the writes fail. Should be at least 1. |
Note that transformation is only one part of the overall process how polled data is converted to openHAB state, or how commands are converted to Modbus writes.
Consult [Read steps](#read-steps) and [Write steps](#write-steps) for more details.
Specifically, note that you might not need transformations at all in some uses cases.
Transformations can be chained in the UI by listing each transformation on a separate line, or by separating them with the mathematical intersection character "∩".
In the .things file, multiple transformations can be specified by enclosing each transformation with double quotes, and separating them with commas, for example,
this will chain `JSONPATH` and `MAP` transformations:
```java
Thing data DimmerReg [ ..., readTransform="JSONPATH($data)", "MAP(modbus_dimmer_read.map)", writeStart="4700", ... ]
**`readTransform`** can be used to transform the polled data, after a number is extracted from the polled data using `readValueType` and `readStart` (consult [Read steps](#read-steps)).
There are three different format to specify the configuration:
1. String `"default"`, in which case the default transformation is used. The default is to convert non-zero numbers to `ON`/`OPEN`, and zero numbers to `OFF`/`CLOSED`, respectively. If the item linked to the data channel does not accept these states, the number is converted to best-effort-basis to the states accepted by the item. For example, the extracted number is passed as-is for `Number` items, while `ON`/`OFF` would be used with `DimmerItem`.
1.`"SERVICENAME(ARG)"` for calling a transformation service. The transformation receives the extracted number as input. This is useful for applying complex arithmetic of the polled data before it is used in openHAB. See examples for more details.
1. Any other value is interpreted as static text, in which case the actual content of the polled value is ignored. Transformation result is always the same. The transformation output is converted to best-effort-basis to the states accepted by the item.
Consult [background documentation on items](https://www.openhab.org/docs/concepts/items.html) to understand accepted data types (state) by each item.
#### Transform On Write
**`writeTransform`** can be used to transform the openHAB command before it is converted to actual binary data (see [Write steps](#write-steps)).
There are three different format to specify the configuration:
1. String `"default"`, in which case the default transformation is used. The default is to do no conversion to the command.
1.`"SERVICENAME(ARG)"` for calling a transformation service. The transformation receives the command as input. This is useful for applying complex arithmetic for commands before the data is written to Modbus. See examples for more details.
Switch SecondLeastSignificantBit "2nd least significant bit write switch [%d]" { channel="modbus:data:localhostTCP3:holdingPoller:register5:switch" }
Number SecondLeastSignificantBitAltRead "2nd least significant bit is now [%d]" { channel="modbus:data:localhostTCP3:holdingPoller:register5Bit1:number" }
Dimmer type Items are not a straightforward match to Modbus registers, as they feature a numeric value which is limited to 0-100 Percent, as well as handling ON/OFF commands.
Transforms can be used to match and scale both reading and writing.
Example for a dimmer device where 255 register value = 100% for fully ON:
In many cases fast enough poll interval is pretty long, e.g. 1 second.
This is problematic in cases when faster updates are wanted based on events in openHAB.
For example, in some cases it is useful to update faster when a command is sent to some specific items.
Simple solution is just increase the poll period with the associated performance penalties and possible burden to the slave device.
It is also possible to use `REFRESH` command to ask the binding to update more frequently for a short while.
`rules/fast_refresh.rules`:
```javascript
import org.eclipse.xtext.xbase.lib.Procedures
import org.openhab.core.types.RefreshType
val Procedures$Procedure0 refreshData = [ |
// Refresh SetTemperature. In fact, all data things in the same poller are refreshed
SetTemperature.sendCommand(RefreshType.REFRESH)
return null
]
rule "Refresh modbus data quickly after changing settings"
when
Item VacationMode received command or
Item HeatingEnabled received command
then
if (receivedCommand != RefreshType.REFRESH) {
// Update more frequently for a short while, to get
// refereshed data after the newly received command
refreshData()
createTimer(now.plus(100), refreshData)
createTimer(now.plus(200), refreshData)
createTimer(now.plus(300), refreshData)
createTimer(now.plus(500), refreshData)
}
end
```
Please be aware that `REFRESH` commands are "throttled" (to be exact, responses are cached) with `poller` parameter `cacheMillis`.
## Troubleshooting
Modbus, while simple at its heart, potentially is a complicated standard to use because there's a lot of freedom (and bugs) when it comes to implementations.
There are many device or vendor specific quirks and wrinkles you might stumble across. Here's some:
- With Modbus TCP devices, there may be multiple network interfaces available, e.g. Wifi and wired Ethernet. However, with some devices the Modbus data is accessible via only one of the interfaces. You need to check the device manufacturer manual, or simply try out which of the IPs are returning valid modbus data.
Attention: a device may have an interface with a port open (502 or other) that it responds to Modbus requests on, but that may have no connection to the real bus hardware, resulting in generic Modbus error responses to _every_ request.
So check ALL interfaces. Usually either the IP on Ethernet will do.
If you fail to read a register or you only ever get invalid values (such as 00 or FF bytes), try with various poller lengths such as the exact length of a register in question or twice the amount.
In extreme cases you might even need more than a poller for a single register so you have two or more poller with two or more data things and need to combine these into another item using a rule.
This means that the addresses start from zero (first entity), and can go up to 65 535. See [Wikipedia explanation](https://en.wikipedia.org/wiki/Modbus#Coil.2C_discrete_input.2C_input_register.2C_holding_register_numbers_and_addresses) for more information.
Previous binding sometimes used absolute addresses (`modbus.cfg`), sometimes relative to polled data (items configuration).
### Register And Bit Addressing
Now 32 bit value types refer start register address. For example `valueType="int32"` with `start="3"` refers to 32 bit integer in registers `3` and `4`.
The old binding could not handle this case at all since it was assumed that the values were addressed differently.
Read index of `3` would refer to 32 bit integer in registers `3*2=6` and `3*2+1=7`.
It was not possible to refer to 32 bit type starting at odd index.
It is still not possible to read 32 bit value type starting "middle" of register.
However, if such need arises the addressing syntax is extensible to covert these cases.
Bits, and other <16bitvaluetypes,insideregistersareaddressedusing`start="X.Y"`convention.
This is more explicit notation hopefully reduces the risk of misinterpretation.
### Polling Details
The new binding polls data in parallel which means that errors with one slave do not necessarily slow down polling with some other slave.
Furthermore, once can disable polling altogether and trigger polling on-demand using `REFRESH`.
### Transformation Changes
With the new binding the transformations get slightly different input. In polling, the transformation always receives number as input (see [Read steps](#read-steps)).
Old binding had converted the input based on item type.
### Trigger Removed
The old binding had `trigger` parameter in item configuration to react only to some openHAB commands, or to some polled states.
There is no trigger anymore but one can use transformations to accomplish the same thing. See [Transformations](#transformations) for examples.
### Support For 32, 64 Bit Value Types In Writing
The new binding supports 32 and 64 bit values types when writing.
Address, length and type can be directly taken over from the 1.x config.
The third (and most complex) part is the definition of data `Thing` objects for every `Item` bound to modbus.
This definitions go into the corresponding 2nd level `Bridge` definitions.
Here it is especially important that the modbus binding now uses absolute addresses all over the place, while the addresses in the item definition for the 1.x binding were relative to the start address of the slave definition before.
For less work in the following final step, the update of the `Item` configuration, the naming of the `data` things in this example uses the offset of the modbus value within the `poller` as suffix, starting with 0(!).
If you have many Items to change and used the naming scheme recommended above, you can now use the following search-and-replace expressions in your editor:
If you have a Modbus enabled device that you want to support in openHAB please read the [developer section](https://github.com/openhab/openhab-addons/blob/main/bundles/org.openhab.binding.modbus/DEVELOPERS.md).