Skip to content

[knx] KNX/IP routing link remains closed after temporary network outage caused by router restart` #21401

Description

@quensen

Expected Behavior

When the router or internet connection is temporarily unavailable, the KNX binding should recover automatically once the network is reachable again.

In particular, for a KNX/IP Routing setup using multicast udp://224.0.23.12:3671, a short network interruption should not leave the KNX link permanently closed. After connectivity is restored, commands to KNX group addresses should be sent again without requiring a restart of openHAB or manual intervention.

Current Behavior

When my router restarts, the internet connection and network connectivity are briefly interrupted. During this outage, openHAB logs a java.net.SocketException: Network is unreachable from Calimero / KNX/IP Routing.

After that, the KNX binding reports that the link is closed and commands can no longer be sent to the KNX bus. The command is dropped with Giving up now.

Relevant log excerpt:

2026-08-13 15:52:49.274 [WARN ] [io.openhabcloud.internal.CloudClient] - Socket.IO disconnected: ping timeout
2026-08-13 15:52:49.275 [INFO ] [io.openhabcloud.internal.CloudClient] - Disconnected from the openHAB Cloud service (UUID = 89...76, base URL = http://localhost:8080)

2026-08-13 15:53:00.274 [ERROR] [et/IP Routing udp://224.0.23.12:3671] - close connection - communication failure
java.net.SocketException: Network is unreachable
	at java.base/sun.nio.ch.DatagramChannelImpl.send0(Native Method)
	at java.base/sun.nio.ch.DatagramChannelImpl.sendFromNativeBuffer(DatagramChannelImpl.java:1005)
	at java.base/sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:981)
	at java.base/sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:889)
	at io.calimero.knxnetip.KNXnetIPRouting.send(KNXnetIPRouting.java:590)
	at io.calimero.knxnetip.ConnectionBase.send(ConnectionBase.java:241)
	at io.calimero.knxnetip.KNXnetIPRouting.send(KNXnetIPRouting.java:248)
	at io.calimero.link.KNXNetworkLinkIP.doSend(KNXNetworkLinkIP.java:521)
	at io.calimero.link.KNXNetworkLinkIP.onSend(KNXNetworkLinkIP.java:509)
	at io.calimero.link.AbstractLink.send(AbstractLink.java:410)
	at io.calimero.link.KNXNetworkLinkIP.sendRequestWait(KNXNetworkLinkIP.java:486)
	at io.calimero.process.ProcessCommunicatorImpl.send(ProcessCommunicatorImpl.java:485)
	at io.calimero.process.ProcessCommunicatorImpl.write(ProcessCommunicatorImpl.java:435)
	at io.calimero.process.ProcessCommunicatorImpl.write(ProcessCommunicatorImpl.java:391)
	at org.openhab.binding.knx.internal.client.AbstractKNXClient.sendToKNX(AbstractKNXClient.java:606)
	at org.openhab.binding.knx.internal.client.AbstractKNXClient.writeToKNX(AbstractKNXClient.java:562)
	at org.openhab.binding.knx.internal.handler.DeviceThingHandler.handleCommand(DeviceThingHandler.java:282)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.openhab.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:149)
	at org.openhab.core.internal.common.InvocationHandlerSync.invoke(InvocationHandlerSync.java:59)
	at jdk.proxy135673/jdk.proxy135673.$Proxy135816.handleCommand(Unknown Source)
	at org.openhab.core.thing.internal.profiles.ProfileCallbackImpl.handleCommand(ProfileCallbackImpl.java:97)
	at org.openhab.core.thing.internal.profiles.SystemDefaultProfile.onCommandFromItem(SystemDefaultProfile.java:49)
	at org.openhab.core.thing.profiles.StateProfile.onCommandFromItem(StateProfile.java:42)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.openhab.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:149)
	at org.openhab.core.internal.common.Invocation.call(Invocation.java:52)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1583)

2026-08-13 15:53:00.293 [WARN ] [nx.internal.client.AbstractKNXClient] - Value '22' could not be sent to KNX bus using datapoint 'command DP 0/6/0 'knx:ip:router', DPT 5.005, low priority': link closed. Giving up now.
2026-08-13 15:53:00.293 [WARN ] [.internal.handler.DeviceThingHandler] - An error occurred while handling command '22' on channel 'knx:device:router:ga:ping_challenge': link closed

2026-08-13 15:53:02.159 [ERROR] [o.client.mqttv3.internal.ClientState] - XxXxXxXx: Timed out as no activity, keepAlive=30,000,000,000 lastOutboundActivity=348,043,801,141,428 lastInboundActivity=348,013,813,856,311 time=348,073,785,410,023 lastPing=348,043,785,408,568

2026-08-13 15:53:23.519 [INFO ] [io.openhabcloud.internal.CloudClient] - Connected to the openHAB Cloud service (UUID = 89...76, base URL = http://localhost:8080)

The openHAB Cloud connection recovers automatically after the router/network comes back. MQTT also reports a timeout during the same outage. However, the KNX/IP Routing link appears to be closed due to the temporary Network is unreachable condition, and command handling fails with link closed.

Possible Solution

The KNX binding or the underlying KNX/IP Routing client should probably treat temporary Network is unreachable errors as recoverable.

Possible approaches:

  • Recreate or reopen the KNX/IP Routing link after a network interface outage.
  • Retry sending after a short delay once the network becomes reachable again.
  • Detect that the multicast routing socket/link was closed and automatically reinitialize it.
  • Mark the Thing as offline during the outage and bring it online again after successful reconnect/reinitialization.

The issue seems less related to the actual KNX bus and more to recovery after the host network stack temporarily loses connectivity.

Steps to Reproduce (for Bugs)

  1. Configure openHAB with the KNX binding using KNX/IP Routing via multicast udp://224.0.23.12:3671.
  2. Restart the router or otherwise interrupt the network briefly so that the openHAB host temporarily has no reachable network.
  3. Send a command to a KNX group address during or shortly after the outage.
  4. Observe the java.net.SocketException: Network is unreachable error.
  5. After the router/network connection is restored, send another command to the KNX bus.
  6. Observe that the KNX binding reports link closed and the command is not sent.

Context

This affects reliability after normal network maintenance or router restarts.

A short router restart should not require manual recovery of the KNX binding. Other services, such as the openHAB Cloud connection, recover automatically after the network comes back. The KNX binding should ideally behave similarly and restore KNX/IP Routing communication without requiring an openHAB restart.

The affected datapoint in the shown log is:

command DP 0/6/0 'knx:ip:router', DPT 5.005, low priority

The command that failed in this example was:

Value '22'

Your Environment

  • Version used: openHAB 5.2.1 - Release Build
  • Add-on: KNX binding
  • KNX connection type: KNX/IP Routing
  • KNX/IP Routing address: udp://224.0.23.12:3671
  • Environment name and version:
    • Java: OpenJDK 21.0.12 LTS
    • Runtime: Azul Zulu 21.52+15-CA
    • javac: 21.0.12
  • Operating System and version:
    • openHABian on Raspberry Pi
    • Debian GNU/Linux 12 (bookworm)
    • Kernel: Linux 6.12.96+rpt-rpi-2712

Java version output:

openjdk version "21.0.12" 2026-07-21 LTS
OpenJDK Runtime Environment Zulu21.52+15-CA (build 21.0.12+8-LTS)
OpenJDK 64-Bit Server VM Zulu21.52+15-CA (build 21.0.12+8-LTS, mixed mode, sharing)
javac 21.0.12

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions