Skip to content

ZHA / bellows loses EZSP TCP radio connection with ConnectionResetError 104 and does not recover #819

Description

@mtdnet

ZHA / bellows loses connection to EZSP radio over TCP (ConnectionResetError 104)

Summary

ZHA devices become unavailable after Home Assistant has been running for some time. Restarting Home Assistant temporarily restores the devices. Debug logging shows that ZHA/bellows loses the serial-over-TCP connection to the EZSP radio with:

ConnectionResetError(104, 'Connection reset by peer')
Connection to the radio has been lost

This happens while the ZHA watchdog is reading EZSP counters.

Environment

  • Home Assistant: TODO: add exact HA version
  • ZHA
  • Radio type: EZSP / Silicon Labs
  • Transport: TCP socket
  • ZHA radio path: socket://192.168.10.2:8888
  • Coordinator hardware: Sonoff ZBBridge / ESP8266
  • Coordinator firmware: Tasmota 15.5.0.1 (aec8e23-zbbridge)
  • EZSP stack/protocol from log:
    • bellows@0.49.2
    • EZSP protocol version: 8
    • Stack version: 6.7.9.0 build 405
    • Coordinator IEEE: 2c:11:65:ff:fe:88:25:23
  • Zigbee devices:
    • 3x LEDVANCE Plug Z3
  • Zigbee network:
    • Channel: 25
    • PAN ID: 0x80FE

Symptoms

  1. Home Assistant starts and ZHA devices are available.
  2. After some runtime, all ZHA devices become unavailable / cannot be controlled.
  3. Restarting Home Assistant restores operation temporarily.
  4. Restarting only the bridge did not reliably resolve the issue.
  5. The issue appears to affect the ZHA radio connection, not individual Zigbee devices.

Relevant log excerpt

2026-07-07 18:44:22.001 DEBUG (MainThread) [bellows.zigbee.application] Free buffers status EzspStatus.SUCCESS, value: 243
2026-07-07 18:44:22.001 DEBUG (MainThread) [bellows.zigbee.application] ezsp_counters: [MAC_RX_BROADCAST = 930, MAC_TX_BROADCAST = 336, MAC_RX_UNICAST = 51, MAC_TX_UNICAST_SUCCESS = 45, MAC_TX_UNICAST_RETRY = 77, MAC_TX_UNICAST_FAILED = 16, APS_DATA_RX_BROADCAST = 1, APS_DATA_TX_BROADCAST = 1, APS_DATA_RX_UNICAST = 25, APS_DATA_TX_UNICAST_SUCCESS = 20, APS_DATA_TX_UNICAST_RETRY = 5, APS_DATA_TX_UNICAST_FAILED = 0, ROUTE_DISCOVERY_INITIATED = 4, NEIGHBOR_ADDED = 3, NEIGHBOR_REMOVED = 0, NEIGHBOR_STALE = 2, ... EZSP_FREE_BUFFERS = 243]
2026-07-07 18:44:32.004 DEBUG (MainThread) [zigpy.application] Feeding watchdog
2026-07-07 18:44:32.004 DEBUG (MainThread) [bellows.ezsp.protocol] Sending command  readCounters: () {}
2026-07-07 18:44:32.006 DEBUG (bellows.thread_0) [bellows.ash] Sending frame DataFrame(frm_num=3, re_tx=False, ack_num=4, ezsp_frame=b'\x9a\x00\x01\xf1\x00') FLAG
2026-07-07 18:44:32.006 DEBUG (bellows.thread_0) [bellows.ash] Sending data  34d821a9a52a17a67e
2026-07-07 18:44:32.010 DEBUG (bellows.thread_0) [zigpy.serial] Connection lost: ConnectionResetError(104, 'Connection reset by peer')
2026-07-07 18:44:32.011 DEBUG (bellows.thread_0) [bellows.uart] Connection lost: ConnectionResetError(104, 'Connection reset by peer')
2026-07-07 18:44:32.012 DEBUG (MainThread) [zigpy.application] Connection to the radio has been lost: ConnectionResetError(104, 'Connection reset by peer')
2026-07-07 18:44:32.012 DEBUG (MainThread) [homeassistant.components.zha.helpers] Connection to the radio was lost: ConnectionLostEvent(event_type='zha_gateway_message', event='connection_lost', exception=ConnectionResetError(104, 'Connection reset by peer'))
2026-07-07 18:44:32.037 WARNING (bellows.thread_0) [py.warnings] /usr/local/lib/python3.14/asyncio/base_events.py:744: RuntimeWarning: coroutine 'SerialProtocol.disconnect' was never awaited
  self._ready.clear()

What looks important

  • Before the disconnect, EZSP counters and free buffers look healthy.
  • The actual failure is not a Zigbee end-device timeout. It is the TCP/serial connection to the EZSP radio being reset.
  • The log ends immediately after the disconnect. There is no visible successful reconnect in this captured log.
  • There is also a Python warning:
    RuntimeWarning: coroutine 'SerialProtocol.disconnect' was never awaited
    which may indicate cleanup/reconnect handling problem after the TCP reset.

Expected behavior

If the TCP connection to an EZSP radio is reset, ZHA/bellows should recover automatically and reconnect without requiring a full Home Assistant restart.

Actual behavior

After the connection reset, ZHA devices remain unavailable until Home Assistant is restarted.

Reproduction

  1. Configure ZHA with EZSP radio over TCP:
    socket://192.168.10.2:8888
  2. Start Home Assistant.
  3. Wait until devices become unavailable.
  4. Observe the log around the time of failure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions