Skip to content

Commit c42ff81

Browse files
0xAHAclaude
andcommitted
fix: flush stale bytes before each shared poll + increase lock timeout (v1.0.9)
Two fixes for shared connection mode (issue #351): 1. Pre-poll buffer flush: after acquiring the hub lock, drain any bytes left in the adapter's TCP receive buffer before starting reads. With a persistent shared connection, late RS485 responses from the previous slave's poll can arrive after the lock is released and sit in the buffer until the next slave picks them up, causing transaction ID mismatches. Flushing before each locked poll cycle prevents this. 2. SHARED_LOCK_TIMEOUT increased from 30s to 60s: the 3000-range register block has no skip-on-failure caching, so each failing chunk costs a full TCP timeout (10s). Multiple failing chunks can push poll time past 30s, triggering spurious lock timeout warnings and skipped polls on the other coordinator. 60s accommodates realistic worst-case poll times. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2d44c11 commit c42ff81

5 files changed

Lines changed: 28 additions & 3 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Growatt Modbus Integration for Home Assistant ☀️
44

55
![HACS Badge](https://img.shields.io/badge/HACS-Custom-orange.svg)
6-
![Version](https://img.shields.io/badge/Version-1.0.8-blue.svg)
6+
![Version](https://img.shields.io/badge/Version-1.0.9-blue.svg)
77
[![GitHub Issues](https://img.shields.io/github/issues/0xAHA/Growatt_ModbusTCP.svg)](https://github.com/0xAHA/Growatt_ModbusTCP/issues)
88
[![GitHub Stars](https://img.shields.io/github/stars/0xAHA/Growatt_ModbusTCP.svg?style=social)](https://github.com/0xAHA/Growatt_ModbusTCP)
99

RELEASENOTES.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,26 @@
44

55
---
66

7+
## v1.0.9
8+
9+
Issues: #351
10+
11+
- **Fix: Remaining transaction ID mismatches in shared connection mode (#351):**
12+
With a persistent shared TCP connection, late RS485 responses from a previous slave's poll
13+
could arrive in the adapter's buffer after the lock was released. When the next slave acquired
14+
the lock and started reading, those stale bytes produced transaction ID mismatches
15+
("request ask for id=X but got id=Y"). Fix: the receive buffer is now flushed at the start
16+
of every locked poll cycle, not just on reconnect.
17+
18+
- **Fix: Shared connection lock timeout with slow/failing register blocks (#351):**
19+
The 3000-range register block does not have the same skip-on-failure caching as the VPP 31000
20+
range. A failing 3000-range chunk costs a full TCP timeout (10s) per chunk, and multiple
21+
failing chunks could push the total poll time past the 30s lock timeout, causing the other
22+
coordinator to log "Shared Modbus connection busy (lock timeout 30s)" and skip its poll.
23+
`SHARED_LOCK_TIMEOUT` increased from 30s to 60s to accommodate realistic worst-case poll times.
24+
25+
---
26+
727
## v1.0.8
828

929
Issues: #351

custom_components/growatt_modbus/const.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
# When two TCP entries share the same host:port, a single ModbusTcpClient is
6666
# reused with a threading.Lock to serialize reads and prevent RS485 cross-talk.
6767
# ============================================================================
68-
SHARED_LOCK_TIMEOUT = 30 # seconds to wait for shared bus lock before giving up
68+
SHARED_LOCK_TIMEOUT = 60 # seconds to wait for shared bus lock before giving up
6969
DEFAULT_INTER_SLAVE_DELAY_MS = 50 # ms pause after each slave poll to let RS485 bus settle
7070

7171
# ============================================================================

custom_components/growatt_modbus/coordinator.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,11 @@ def _fetch_data_shared(self) -> GrowattData | None:
933933
)
934934
return None
935935

936+
# Flush any stale bytes left in the adapter's TCP buffer by the
937+
# previous slave's poll (late RS485 responses that arrived after the
938+
# lock was released cause transaction ID mismatches on this slave's reads).
939+
hub._flush_receive_buffer()
940+
936941
self._client._battery_voltage_range = self.config_entry.options.get(
937942
"battery_voltage_range", "Auto-detect"
938943
)

custom_components/growatt_modbus/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@
1212
"pymodbus>=3.0.0",
1313
"pyserial>=3.4"
1414
],
15-
"version": "1.0.8"
15+
"version": "1.0.9"
1616
}

0 commit comments

Comments
 (0)