Stop the fans from signalling each other back and forth forever master
After exhausting MAX_ATTEMPTS, a fan signalled the other fan back to its own last known good set point, to keep the two from drifting apart and putting the house under or over pressure. If the bus itself was down, that fan failed too and signalled back, and neither ever stopped. A slow churn rather than a spin — roughly four attempts at a 5 s timeout plus backoff per round — but it never terminated and kept cycling the Modbus mutex. The signal now carries where the set point came from, as RequestedSetPoint::FromUser or FromOtherFan, and only a request from a user pushes the other fan back when it fails. That is option A of the two sketched in place, a retry strategy on the signal set to once, except the "once" falls out of what the value means instead of being counted. A correction that fails is not the two fans disagreeing, it is the bus being down, and there is nothing left for a second correction to fix: the pushing fan is at its own set point and the fan being pushed already failed at that exact value. Answering it with another correction is what bounced the same value back and forth. So a correction is applied and retried like anything else but never produces another one, and every round of signalling now ends after at most two: one if a single fan failed, two if both were commanded at once and both failed. This does leave the fans genuinely out of sync when a fan fails to apply a correction. That is the honest outcome, because nothing else can be tried until the bus comes back, and it is not silent: the display state is only updated on a confirmed write, so the LEDs blink the out-of-sync pattern until a later command succeeds. Option B, a counter that detects the loop, is not needed on top of this. It would spot the same situation later and without saying why it happened. Untested on hardware, and hard to reach on purpose: it needs both fans to fail after their retries, which means pulling the bus rather than anything Home Assistant can ask for. With this the four ranked items in TODO.md are done. The write-ups stay there because each records what was wrong and what has never run on hardware. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>