fix(s7commplus): reconnect around symbolic reads so browse() works on RST-happy firmware - #801
Merged
gijzelaerr merged 1 commit intoAug 4, 2026
Conversation
… RST-happy firmware
browse() does an EXPLORE (list_datablocks) then a symbolic GetMultiVariables
read (_read_typeinfo_rid) then another EXPLORE (type-info container). On
firmware that sends a TCP RST after the first symbolic read per connection
(e.g. S7-1200 FW V4.1 — the behaviour already documented in read_symbolic's
docstring), the final EXPLORE runs on a dead socket and browse() raises
S7ConnectionError("Not connected").
Add a lazy reconnect-and-retry: connect() now stores its arguments, and a new
_with_reconnect() helper retries an operation once on a fresh session if the
PLC dropped the socket. browse() wraps the per-DB reads and the container
EXPLORE with it; _read_typeinfo_rid propagates S7ConnectionError so the retry
can act. Well-behaved firmware never triggers the retry (the first call
succeeds), so there is no behaviour change there.
Also downgrade the misleading "CreateObject returned error ... PLC may require
TLS" warning to debug when TLS is already active: this PLC returns a non-zero
CreateObject value on a fully functional TLS session.
Validated live on an S7-1200 FW V4.1 over TLS: browse() now returns the full
I/Q/M symbol tree with correct types (input_1 BOOL, mtag_byte BYTE %MB100,
mtag_word WORD %MW102, ...). Tests: 107 passed, ruff + format clean.
Refs gijzelaerr#793, gijzelaerr#775
gijzelaerr
added a commit
that referenced
this pull request
Aug 4, 2026
…connect Add `rst_after_symbolic_read` flag to S7CommPlusServer that closes the TCP connection after responding to GetMultiVariables — matching the behaviour of S7-1200 FW V4.1 that RSTs after a symbolic read. This lets the reconnect logic from PR #801 be exercised without real hardware.
4 tasks
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.
Follow-up to the TLS validation in #793, on top of #775 (
fix-tls-layering-v2).Problem
browse()runs an EXPLORE (list_datablocks) → a symbolicGetMultiVariablesread (_read_typeinfo_rid) → another EXPLORE (the type-info container). On firmware that sends a TCP RST after the first symbolic read per connection — e.g. S7-1200 FW V4.1, the behaviour already documented inread_symbolic()'s own docstring ("TCP RST after first I/Q/M read… reconnect before each I/Q/M read") — the final EXPLORE runs on a dead socket andbrowse()blows up:Fix
A lazy reconnect-and-retry:
connect()stores its arguments; a new_open_connection()/_reconnect()rebuild the session with them._with_reconnect(op)runsopand, only if the PLC dropped the socket (S7ConnectionError), reconnects once and retries. Well-behaved firmware never triggers the retry (the first call succeeds), so there is no behaviour change there.browse()wraps the per-DB reads and the container EXPLORE with it;_read_typeinfo_ridnow propagatesS7ConnectionError(other errors still mean "skip DB").Also: downgrade the misleading
"CreateObject returned error … PLC may require TLS"warning todebugwhen TLS is already active — this PLC returns a non-zero CreateObject value on a fully functional TLS session, so the warning is noise.Validation
Live on an S7-1200 FW V4.1 over TLS (secure PG/PC comms). Before:
browse()raisedNot connected. After:Types and addresses cross-checked against TIA Portal.
pytest tests/test_client.py tests/test_tag_browser.py tests/test_client_e2e.py→ 107 passed, 48 skippedruff check+ruff formatcleanRefs #793, #775