Repository navigation
The review of Evok 3.1.0: a failed step, the watchdog timeout, the alias before the write - #280
Merged
Merged
Conversation
…ias before the write - sequencer: a failed step is written again every STEP_RETRY_DELAY (1 s) until it succeeds or the sequence is cancelled, it is logged once; the last step ends the sequence after its successful write. A failed end of a pulse (e.g. a noise on the bus) ended the sequence before the write, the relay stayed on and finish_all() did not write it either. finish_all() does not write the final state of a sequence writing its last step again - Watchdog: a changed timeout is an event; the timeout is checked before any change, a whole number of ms (it was cut by int()), an invalid one enabled the watchdog and set the alias before the error - set_devices() checks the aliases of the assignments before the first write (Devices.check_alias()): the output was switched and then the request failed on a used, invalid or reserved alias - AccessorBit writes with its pin - docs: the retried step, the watchdog timeout, the alias in the API changes and sequencer.md - tests: the retried step and the end after the write, the failed end of a DO pulse written again, the watchdog timeout, the alias, the bit without a pin Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… errors, the aliases in order - finish_all() writes the final state of a sequence whose last step was being written and failed (Running.finished after the successful write), it left the relay on - only the errors of the communication are written again (UnitCommunicationError, TModbusError, TimeoutError, OSError), another error ends the sequence and is logged; a value refused by the output was written again forever and the output refused every change - the step is done after its successful write, a step written again was reported as done - set_devices() checks the aliases in the order of the changes (by the units), with the aliases released and taken by the earlier assignments: the same alias twice in one request passed the check, an alias moved to another device was refused - set_alias() checks the alias by check_alias(), the rules in one place - docs, tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ams, a non-string alias - a step refused by the unit (an exception response Illegal Function, Data Address or Data Value, an invalid request) is not written again, it was an error of the communication (TModbusError) and was retried forever - a step which ends its sequence by an error writes the final state of the sequence, the output stayed in its state - the delay of a failed step doubles from 1 s up to 30 s, a missing unit does not load its bus every second; the failure is logged again when the error (with its cause) changes and every 5 minutes - Watchdog.set() checks value and reset before any change too, an invalid one set the alias, enabled the watchdog or wrote the timeout before the error - an alias which is not a string (0, false) is refused as invalid before the write, it passed as a reset and failed by TypeError after the write - docs, tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on responses, the alias type - the final state after a refused step is written as the last step of the sequence while it runs: it ended before, a new pulse or a change in the gap was overwritten by the old final state and finish_all() did not wait for it; an error of the communication writes it again, a noise lost it - every exception response of the unit is a refused request (e.g. Server Device Failure was retried forever) except Server Device Busy, Acknowledge and the errors of a gateway, which are written again - a failed step is logged again when the kind of its error changes, the text of a timeout differs by each attempt and was logged each time - _check_aliases() checks the alias by check_alias() before the taken ones, a list alias raised TypeError (500) - docs: the final state only of a sequence which has one, the watchdog timeout is cut to 65535 - tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… without the coil - _check_aliases() skips an alias null as not given: it was checked as a reset and released the alias for another device, set_alias() keeps it and the duplicate failed after the write - the final state after a refused step is not written when it is the refused step itself, e.g. the end of a pulse was sent again and logged twice - Watchdog.set() ignores reset of a unit without the reset coil as before, an invalid one was refused - docs: the PRs of the new entries of the API changes - tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
miroslav-ondra
added a commit
that referenced
this pull request
Oct 26, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged
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.
The findings of the review of #276 (Evok 3.1.0), fixed in
dev-3.1before the release.Changes
A failed end of a pulse left the output on (
blocks/sequencer.py)finish_all()at the shutdown did not write it either. A failed middle step lost thefinalof a sequence the same way.UnitCommunicationError,TModbusError,TimeoutError,OSError) is written again until it succeeds or the sequence is cancelled or replaced, the sequence stays running meanwhile. The delay starts atSTEP_RETRY_DELAY(1 s) and doubles up toSTEP_RETRY_MAX_DELAY(30 s), a missing unit does not load its bus every second. The failure is logged, again when the kind of the error (its root cause) changes and every 5 minutes, a later success too.finish_all()waits for it, an error of the communication writes it again; it is not written by a task the sequence no longer owns, nor when it is the refused step itself (the end of a pulse).stepof the state) after its successful write; the last step ends the sequence after it (under the lock of the unit, the state read after it is not running).finish_all()waits for the steps being written, then writes the final state of the sequences whose last step was not written (Running.finished): a failed end of a pulse while Evok stops is written by the final state.Watchdog (
modbus/special.py)timeoutis an event, the clients kept the old one.timeout,valueandresetare checked before any change,timeoutmust be a whole number of ms:{"value": 1, "timeout": "1.5"}enabled the watchdog and set the alias beforeint()failed (400 after a partial change),2.9was cut to 2, an invalidvalueorresetset the alias or wrote the registers before;resetof a unit without the reset coil is ignored as before.An invalid alias after the write (
modbus/base.py,devices.py)set_devices()checks the aliases of all assignments (Devices.check_alias()) before the first write, in the order of the changes (by the units), with the aliases released and taken by the earlier assignments. A used, invalid, reserved alias or one equal to a circuit switched the output and then the request failed with 400; the same alias twice in one bulk is refused, an alias moved to another device in one bulk works; an alias which is not a string (0,false, a list) is refused as invalid;alias: nullis not given, the alias is kept. All APIs set the devices byset_devices();set_alias()uses the same check.AccessorBitwrites with itspin(#279), a bit accessor withpin=Falsewas pinned.Docs: the retried step in
sequencer.mdand the API changes, the watchdog timeout, the alias.Testing
pytest tests: 1302 passed; new tests:alias: nullkeeping the alias, the refused end of a pulse sent once,resetof a watchdog without the coil, the final state written while the sequence runs (also again after a noise),finish_all()waiting for it, Server Device Failure refused and Server Device Busy retried, an error with a changing text logged once, a step refused by the unit ending the sequence with its final state, the doubling delay, the changed error logged, the invalid watchdog value and reset, an alias which is not a string, the failed step written again and logged once, a refused step ending the sequence, the step done after its write, the last step ending the sequence after its write, the failed end of a DO pulse written again, the final state after a failed last step at the shutdown, the same alias twice in a request, an alias moved in a request, an alias released by a later unit, the watchdog timeout as an event, the invalid timeouts (1.5,2.9,-1,x) without any change, a whole timeout as a string, the invalid aliases before the write, the bit without a pin. Each fails without its fix.ruff checkandruff format --check srcclean.led ext2_01;{"value": 1, "alias": "tmpx"}withtmpxused byext2_02is 400 and the LED stays off;wd ext3{"value": 1, "timeout": "1.5"}is 400 and the watchdog stays disabled with its timeout; a bulk moving the aliaspumpfromled ext2_02toled ext2_03succeeds;wd ext3{"alias": "wdx", "value": "maybe"}is 400 without the alias.🤖 Generated with Claude Code