Repository navigation
Detect lost link, validate setpoint writes, batch read_all_* (v1.15.0) - #3
Merged
Merged
Conversation
The connected flag was only cleared by close(), so a dropped link was never noticed: _ensure_connected() never reconnected and every block of every poll fell back to per-entity reads, each waiting for its own timeout (68 transactions per get_all_data() poll, 101 per get_all_entities()). Link failures (ConnectionException, ModbusIOException, OSError) now mark the client disconnected and close the pymodbus transport, so the next poll reconnects with backoff. After a failed block, the first single read acts as a probe; if it also hits a link failure the poll stops, capping a dead link at 2 transactions. get_all_data() returns None when the link is lost mid-poll. Modbus error replies keep the per-entity fallback. The warn-once read-failure log now re-arms when a target reads fine again, so a later outage is logged at WARNING again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
write_setpoint() sent any value to the controller, including NaN, inf and out-of-range temperatures. EntityDef gains optional min_value and max_value; the four writable setpoints get the ranges both HA integrations already expose (DHW 40-65, heating 20-65, cooling 7-25 C). Non-finite and out-of-range values are refused before any Modbus traffic. 16-bit writes now round instead of truncating (21.9 wrote 21) and refuse values that do not fit the register. set_sg_ready_mode() wrote coil 65 and 66 in two requests, so a failed second write left the pump in an unintended mode. Both coils are now written in one write_coils request, falling back to the old two single writes if the device rejects it. get_sg_ready_mode() reads both coils in one request. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
read_all_sensors(), read_all_binary_sensors() and read_all_switches() issued one Modbus request per entity (94 together). They now use the batched block reader (9 requests), returning the same keys, key order and values as before. HA core calls read_all_switches() every poll. async_get_mac_address() resolved the host with socket.gethostbyname() and read /proc/net/arp on the event loop; both now run in a worker thread. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MattieGit
added a commit
that referenced
this pull request
Oct 20, 2026
#3) * fix: detect lost Modbus link, stop polls early and reconnect The connected flag was only cleared by close(), so a dropped link was never noticed: _ensure_connected() never reconnected and every block of every poll fell back to per-entity reads, each waiting for its own timeout (68 transactions per get_all_data() poll, 101 per get_all_entities()). Link failures (ConnectionException, ModbusIOException, OSError) now mark the client disconnected and close the pymodbus transport, so the next poll reconnects with backoff. After a failed block, the first single read acts as a probe; if it also hits a link failure the poll stops, capping a dead link at 2 transactions. get_all_data() returns None when the link is lost mid-poll. Modbus error replies keep the per-entity fallback. The warn-once read-failure log now re-arms when a target reads fine again, so a later outage is logged at WARNING again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: validate setpoint writes and set SG Ready mode atomically write_setpoint() sent any value to the controller, including NaN, inf and out-of-range temperatures. EntityDef gains optional min_value and max_value; the four writable setpoints get the ranges both HA integrations already expose (DHW 40-65, heating 20-65, cooling 7-25 C). Non-finite and out-of-range values are refused before any Modbus traffic. 16-bit writes now round instead of truncating (21.9 wrote 21) and refuse values that do not fit the register. set_sg_ready_mode() wrote coil 65 and 66 in two requests, so a failed second write left the pump in an unintended mode. Both coils are now written in one write_coils request, falling back to the old two single writes if the device rejects it. get_sg_ready_mode() reads both coils in one request. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * perf: batch read_all_* helpers and keep MAC lookup off the event loop read_all_sensors(), read_all_binary_sensors() and read_all_switches() issued one Modbus request per entity (94 together). They now use the batched block reader (9 requests), returning the same keys, key order and values as before. HA core calls read_all_switches() every poll. async_get_mac_address() resolved the host with socket.gethostbyname() and read /proc/net/arp on the event loop; both now run in a worker thread. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: bump version to 1.15.0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Connection handling, write safety and request batching (v1.15.0).
close(), so a dropped link was never noticed and the reconnect backoff never ran. Link failures (ConnectionException,ModbusIOException,OSError) now mark the client disconnected and close the pymodbus transport; the next poll reconnects.get_all_data()returnsNonewhen the link is lost mid-poll. Modbus error replies keep the per-entity fallback.EntityDefgains optionalmin_value/max_value; the four writable setpoints use the ranges both HA integrations already expose (DHW 40–65, heating 20–65, cooling 7–25 °C). NaN, inf and out-of-range values are refused before any Modbus traffic. 16-bit writes round instead of truncating and refuse values that do not fit.write_coilsrequest (falls back to two single writes if the device rejects it);get_sg_ready_mode()reads both coils in one request.read_all_*batched: 94 → 9 requests, same keys, key order and values.async_get_mac_address()no longer blocks the event loop (DNS lookup and/proc/net/arpread run in a thread).get_all_data()poll, device unreachableNone, reconnects next pollread_all_sensors+read_all_binary_sensors+read_all_switchesCompatibility
EntityDeffields are optional and appended at the end.get_all_data()returningNoneon a lost link is within its documented contract; the HA core coordinator already raisesUpdateFailedonNone.write_registerservice are now refused.Test plan
ruff checkandruff format --checkcleantests/components/hr_energy_qubeagainst this branch: 30 passed (same as 1.12.0 and main)Nonewithout delay, restart → reconnect, silent device → 24 s