# Modbus Communication Issue Between Ignition and jlibmodbus Code

**URL:** <https://forum.inductiveautomation.com/t/modbus-communication-issue-between-ignition-and-jlibmodbus-code/108846>\
**Category:** Ignition\
**Tags:** modbus, python\
**Created:** [July 23, 2025, 6:49pm UTC](https://forum.inductiveautomation.com/t/modbus-communication-issue-between-ignition-and-jlibmodbus-code/108846 "2025-07-23T18:49:30Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Spencer\_Lommel1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/spencer_lommel1/32/78679_2.png) [@Spencer\_Lommel1](https://forum.inductiveautomation.com/u/Spencer_Lommel1)\
**Post date:** [July 23, 2025, 6:49pm UTC](https://forum.inductiveautomation.com/t/modbus-communication-issue-between-ignition-and-jlibmodbus-code/108846/1 "2025-07-23T18:49:30Z")

</div>

## What I'm attempting to do

I am working on a custom Java application that implements Modbus using [this jlibmodbus library](https://github.com/kochedykov/jlibmodbus)

## My Modbus Client Code

I was able to get a simple ModbusTCP client going with this example code that I slightly modified

```java
package org.example;

import com.intelligt.modbus.jlibmodbus.Modbus;
import com.intelligt.modbus.jlibmodbus.data.DataHolder;
import com.intelligt.modbus.jlibmodbus.data.ModbusCoils;
import com.intelligt.modbus.jlibmodbus.data.ModbusHoldingRegisters;
import com.intelligt.modbus.jlibmodbus.exception.IllegalDataAddressException;
import com.intelligt.modbus.jlibmodbus.exception.IllegalDataValueException;
import com.intelligt.modbus.jlibmodbus.ModbusSlave;
import com.intelligt.modbus.jlibmodbus.ModbusSlaveFactory;
import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Handler;
import java.util.logging.LogRecord;

/*
 * Copyright (c) 2017 Vladislav Kochedykov
 * All rights reserved
 *
 * This file is part of JLibModbus.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse
 * or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Vladislav Y. Kochedykov, software engineer.
 * email: vladislav.kochedykov@gmail.com
 */
public class SimpleSlaveTCP {

    static public void main(String[] argv) {

        Modbus.log().addHandler(new Handler() {
            @Override
            public void publish(LogRecord record) {
                System.out.println(record.getLevel().getName() + ": " + record.getMessage());
            }

            @Override
            public void flush() {
                //do nothing
            }

            @Override
            public void close() throws SecurityException {
                //do nothing
            }
        });
        Modbus.setLogLevel(Modbus.LogLevel.LEVEL_DEBUG);

        try {

            final ModbusSlave slave;

            TcpParameters tcpParameters = new TcpParameters();

            tcpParameters.setHost(InetAddress.getLocalHost());
            tcpParameters.setKeepAlive(true);
            tcpParameters.setPort(Modbus.TCP_PORT);

            slave = ModbusSlaveFactory.createModbusSlaveTCP(tcpParameters);
            slave.setReadTimeout(0); // if not set default timeout is 1000ms, I think this must be set to 0 (infinitive timeout)
            Modbus.setLogLevel(Modbus.LogLevel.LEVEL_DEBUG);

            MyOwnDataHolder dh = new MyOwnDataHolder();
            dh.addEventListener(new ModbusEventListener() {
                @Override
                public void onWriteToSingleCoil(int address, boolean value) {
                    System.out.print("onWriteToSingleCoil: address " + address + ", value " + value);
                }

                @Override
                public void onWriteToMultipleCoils(int address, int quantity, boolean[] values) {
                    System.out.print("onWriteToMultipleCoils: address " + address + ", quantity " + quantity);
                }

                @Override
                public void onWriteToSingleHoldingRegister(int address, int value) {
                    System.out.print("onWriteToSingleHoldingRegister: address " + address + ", value " + value);
                }

                @Override
                public void onWriteToMultipleHoldingRegisters(int address, int quantity, int[] values) {
                    System.out.print("onWriteToMultipleHoldingRegisters: address " + address + ", quantity " + quantity);
                }
            });

            slave.setDataHolder(dh);
            ModbusHoldingRegisters hr = new ModbusHoldingRegisters(30);
            hr.set(0, 12345);
            slave.getDataHolder().setHoldingRegisters(hr);
            slave.setServerAddress(1);
            /*
             * using master-branch it should be #slave.open();
             */
            slave.listen();

            /*
             * since 1.2.8
             */
            if (slave.isListening()) {
                Runtime.getRuntime().addShutdownHook(new Thread() {
                    @Override
                    public void run() {
                        synchronized (slave) {
                            slave.notifyAll();
                        }
                    }
                });

                synchronized (slave) {
                    slave.wait();
                }

                /*
                 * using master-branch it should be #slave.close();
                 */
                slave.shutdown();
            }
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public interface ModbusEventListener {
        void onWriteToSingleCoil(int address, boolean value);

        void onWriteToMultipleCoils(int address, int quantity, boolean[] values);

        void onWriteToSingleHoldingRegister(int address, int value);

        void onWriteToMultipleHoldingRegisters(int address, int quantity, int[] values);
    }

    public static class MyOwnDataHolder extends DataHolder {

        final List<ModbusEventListener> modbusEventListenerList = new ArrayList<ModbusEventListener>();

        public MyOwnDataHolder() {

            setHoldingRegisters(new ModbusHoldingRegisters(128));
            setCoils(new ModbusCoils(128));

        }

        public void addEventListener(ModbusEventListener listener) {
            modbusEventListenerList.add(listener);
        }

        public boolean removeEventListener(ModbusEventListener listener) {
            return modbusEventListenerList.remove(listener);
        }

        @Override
        public void writeHoldingRegister(int offset, int value) throws IllegalDataAddressException, IllegalDataValueException {
            for (ModbusEventListener l : modbusEventListenerList) {
                l.onWriteToSingleHoldingRegister(offset, value);
            }
            super.writeHoldingRegister(offset, value);
        }

        @Override
        public void writeHoldingRegisterRange(int offset, int[] range) throws IllegalDataAddressException, IllegalDataValueException {
            for (ModbusEventListener l : modbusEventListenerList) {
                l.onWriteToMultipleHoldingRegisters(offset, range.length, range);
            }
            super.writeHoldingRegisterRange(offset, range);
        }

        @Override
        public void writeCoil(int offset, boolean value) throws IllegalDataAddressException, IllegalDataValueException {
            for (ModbusEventListener l : modbusEventListenerList) {
                l.onWriteToSingleCoil(offset, value);
            }
            super.writeCoil(offset, value);
        }

        @Override
        public void writeCoilRange(int offset, boolean[] range) throws IllegalDataAddressException, IllegalDataValueException {
            for (ModbusEventListener l : modbusEventListenerList) {
                l.onWriteToMultipleCoils(offset, range.length, range);
            }
            super.writeCoilRange(offset, range);
        }
    }
}

```

## Python Client Validation

I am able to read & write to this using this Python code so I have validated that this client works.

```python
from pyModbusTCP.client import ModbusClient

c = ModbusClient(auto_open=True, port=502)

print("--------------------")
print("Attempting register writes")
w_m10_reg = c.write_multiple_registers(0, [10,20,30,40,50,60,70,80,90,100])

if w_m10_reg:
    print("Wrote to registers")
else:
    print("Unable to write to registers")
    print(c.last_error_as_txt)

print("--------------------")
r_m10_reg = c.read_holding_registers(0, 10)
if r_m10_reg:
    print("Read registers")
    print(r_m10_reg)
else:
    print("Unable to read registers")
    print(c.last_error_as_txt)
print("--------------------")

```

## Ignition Issue when connecting

But when I try to connect to this device with Ignition I do get a `Connected` status  
 ![{5B956AB1-E8EF-4D5B-A7D0-B91CAF6BC5CB}](https://us1.discourse-cdn.com/inductiveautomation/original/3X/2/4/24541bade96f0c01f4a027c79693733cce568db3.png)

I then setup my addresses and created a new OPC tag in Ignition that binds to this device.

But I get `Bad` value message and when I attempt to modify this value it takes a bit then I get this error  
`Error writing to ModBusTest1.value: Bad("Bad_Timeout: The operation timed out.")`

## In my `wrapper.log` I see this error.

```python
INFO | jvm 1 | 2025/07/23 13:26:12 | W [d.M.ReadCoilsRequest] [13:26:12.148]: Request failed. FailureType==TIMEOUT device-name=Test Modbus Device
INFO | jvm 1 | 2025/07/23 13:26:12 | java.lang.Exception: Request failed by TimeoutDaemon due to timeout: ScheduledRequest[com.inductiveautomation.xopc.drivers.modbus2.requests.ReadCoilsRequest@1605772b]
INFO | jvm 1 | 2025/07/23 13:26:12 | at com.inductiveautomation.xopc.driver.api.BasicRequestCycle$TimeoutDaemon.failRequests(BasicRequestCycle.java:376)
INFO | jvm 1 | 2025/07/23 13:26:12 | at com.inductiveautomation.xopc.driver.api.BasicRequestCycle$TimeoutDaemon.run(BasicRequestCycle.java:328)
INFO | jvm 1 | 2025/07/23 13:26:12 | at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:12 | at java.base/java.util.concurrent.FutureTask.runAndReset(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:12 | at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:12 | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:12 | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:12 | at java.base/java.lang.Thread.run(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | W [d.M.B.B.TimeoutDaemon] [13:26:14.151]: ScheduledRequest[com.inductiveautomation.xopc.drivers.modbus2.requests.ReadCoilsRequest@1605772b] request with key "60" failed due to timeout. device-name=Test Modbus Device
INFO | jvm 1 | 2025/07/23 13:26:14 | W [d.M.ReadCoilsRequest] [13:26:14.151]: Request failed. FailureType==TIMEOUT device-name=Test Modbus Device
INFO | jvm 1 | 2025/07/23 13:26:14 | java.lang.Exception: Request failed by TimeoutDaemon due to timeout: ScheduledRequest[com.inductiveautomation.xopc.drivers.modbus2.requests.ReadCoilsRequest@1605772b]
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.BasicRequestCycle$TimeoutDaemon.failRequests(BasicRequestCycle.java:376)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.BasicRequestCycle$TimeoutDaemon.run(BasicRequestCycle.java:328)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.FutureTask.runAndReset(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.lang.Thread.run(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | W [d.M.ReadCoilsRequest] [13:26:14.151]: Request failed. FailureType==DISCONNECTED device-name=Test Modbus Device
INFO | jvm 1 | 2025/07/23 13:26:14 | java.lang.Exception: Driver is disconnected.
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.AbstractDriver$RequestSchedule.cancelCurrentSchedule(AbstractDriver.java:1255)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.AbstractDriver.notifyDisconnectDone(AbstractDriver.java:658)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.AbstractIODelegatingDriver.notifyDisconnectDone(AbstractIODelegatingDriver.java:70)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.AbstractIODelegatingDriver.disconnect(AbstractIODelegatingDriver.java:42)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.AbstractIODelegatingDriver.reconnect(AbstractIODelegatingDriver.java:92)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.drivers.modbus2.AbstractModbusDriver.access$000(AbstractModbusDriver.java:102)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.drivers.modbus2.AbstractModbusDriver$2.notifyCommunicationTimeout(AbstractModbusDriver.java:149)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.drivers.modbus2.requests.AbstractModbusRequest.fail(AbstractModbusRequest.java:212)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.drivers.modbus2.requests.AbstractModbusReadRequest.fail(AbstractModbusReadRequest.java:121)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.ScheduledRequest.fail(ScheduledRequest.java:126)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.BasicRequestCycle$TimeoutDaemon.failRequests(BasicRequestCycle.java:373)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.BasicRequestCycle$TimeoutDaemon.run(BasicRequestCycle.java:328)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.FutureTask.runAndReset(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.lang.Thread.run(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | W [d.M.ReadCoilsRequest] [13:26:14.152]: Request failed. FailureType==DISCONNECTED device-name=Test Modbus Device
INFO | jvm 1 | 2025/07/23 13:26:14 | java.lang.Exception: RequestCycle stopped.
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.BasicRequestCycle.shutdown(BasicRequestCycle.java:278)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.AbstractDriver.createNewRequestCycle(AbstractDriver.java:698)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.AbstractDriver.notifyDisconnectDone(AbstractDriver.java:659)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.AbstractIODelegatingDriver.notifyDisconnectDone(AbstractIODelegatingDriver.java:70)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.AbstractIODelegatingDriver.disconnect(AbstractIODelegatingDriver.java:42)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.AbstractIODelegatingDriver.reconnect(AbstractIODelegatingDriver.java:92)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.drivers.modbus2.AbstractModbusDriver.access$000(AbstractModbusDriver.java:102)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.drivers.modbus2.AbstractModbusDriver$2.notifyCommunicationTimeout(AbstractModbusDriver.java:149)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.drivers.modbus2.requests.AbstractModbusRequest.fail(AbstractModbusRequest.java:212)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.drivers.modbus2.requests.AbstractModbusReadRequest.fail(AbstractModbusReadRequest.java:121)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.ScheduledRequest.fail(ScheduledRequest.java:126)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.BasicRequestCycle$TimeoutDaemon.failRequests(BasicRequestCycle.java:373)
INFO | jvm 1 | 2025/07/23 13:26:14 | at com.inductiveautomation.xopc.driver.api.BasicRequestCycle$TimeoutDaemon.run(BasicRequestCycle.java:328)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.FutureTask.runAndReset(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:14 | at java.base/java.lang.Thread.run(Unknown Source)
INFO | jvm 1 | 2025/07/23 13:26:19 | W [d.M.B.B.TimeoutDaemon] [13:26:19.155]: ScheduledRequest[com.inductiveautomation.xopc.drivers.modbus2.requests.ReadCoilsRequest@4515db4] request with key "61" failed due to timeout. device-name=Test Modbus Device

```

## Thoughts

Because I am able to read/write with my Python example code I'm assuming there is some issue with how Ignition expects Modbus data to look and how I'm actually sending it back with my Java Client. I am going to attempt to make a simpler Java proof of concept that works with Ignition just to see if this is viable.

If anyone has any suggestions on what's going wrong here or what I should try let me know. Thanks!

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [July 23, 2025, 6:51pm UTC](https://forum.inductiveautomation.com/t/modbus-communication-issue-between-ignition-and-jlibmodbus-code/108846/2 "2025-07-23T18:51:35Z")

</div>

In Ignition, don't set up a Modbus Address map. Just create OPC tags in the Designer that use the Modbus address syntax described in the user manual.

e.g. `[DeviceName]HR1` or `[DeviceName]1.HR1`.

> **[Modbus Addressing | Ignition User Manual](https://docs.inductiveautomation.com/docs/7.9/opc-ua-and-device-connections/modbus/modbus-addressing)**
>
> Manually Addressing a Modbus Device

The most common problem with addressing is that Ignition will default to unit/slave id 0 and some devices/implementations will default to 1, and not respond to 0 at all.

---

<div class="post-metadata">

**Author:** ![Spencer\_Lommel1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/spencer_lommel1/32/78679_2.png) [@Spencer\_Lommel1](https://forum.inductiveautomation.com/u/Spencer_Lommel1)\
**Post date:** [July 23, 2025, 6:55pm UTC](https://forum.inductiveautomation.com/t/modbus-communication-issue-between-ignition-and-jlibmodbus-code/108846/3 "2025-07-23T18:55:29Z")

</div>

Wow that was it! I thought I already tried that but thank you for the help =D
