Skip to content

GoodWe Modbus TCP stale socket after controller reboot #522

Description

@frahlg

Bug description

A GoodWe GW8KN-ET with WiFi/LAN dongle can get stuck after the forty-two-watts controller is power-cycled/rebooted without a clean TCP close.

The driver enters a rapid modbus reconnected loop. TCP connects to port 502 succeed, but Modbus frames receive no response until the GoodWe dongle/inverter is physically power-cycled.

Reported environment

  • Device: GoodWe GW8KN-ET
  • Connectivity: GoodWe WiFi/LAN dongle
  • Protocol: Modbus TCP on port 502
  • Reporter: Discord user frekes

Suspected cause

The dongle appears to allow only one Modbus TCP client/session. If the controller disappears without sending FIN (power loss / hard reboot), the dongle may hold the old socket as established for a long time. A new TCP handshake succeeds, but the Modbus application layer may still be bound to the ghost socket and ignore the new client's frames.

Current go/internal/modbus/client.go uses simonvetter/modbus, which dials TCP via net.DialTimeout and does not expose TCP keepalive configuration. The 42W wrapper reconnects on transport errors, but that does not help if the dongle accepts the TCP connection while ignoring Modbus frames.

Proposed fix

Enable TCP keepalive on Modbus TCP sockets, ideally with a short period (for example 15-30s) so ghost sockets clear within roughly a minute after controller power loss.

Implementation may require one of:

  • upstream change/fork/wrapper in simonvetter/modbus to set keepalive on the TCP conn before newTCPTransport, or
  • replacing the TCP transport path with a 42W-owned dialer/transport that uses net.Dialer{KeepAlive: ...} / (*net.TCPConn).SetKeepAlivePeriod(...).

Workaround

Physically power-cycle the GoodWe dongle/inverter after a controller hard reboot if it gets stuck in this state.

Acceptance criteria

  • Modbus TCP client sockets have TCP keepalive enabled with a configurable or documented short period.
  • Reconnection after controller hard reboot recovers without requiring GoodWe dongle power cycle.
  • Add regression coverage where practical for the dialer/socket setup.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    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