Repository navigation
Conversation
Adding a timedelta to a timezone-aware datetime is wall-clock arithmetic
and resets `fold`. Inside the autumn DST fold `candidate + timedelta(
seconds=1)` can therefore land a full hour BEFORE `candidate` in absolute
time, so the `while search_pos < ...` loops in TransitSensor and
AntitransitSensor keep re-finding the same event and never terminate.
Because the search runs synchronously in `async_added_to_hass`, the whole
Home Assistant event loop is blocked: the instance accepts TCP connections
on 8123 but never answers them.
Reproduced with Europe/Warsaw on 2026-10-25, when the Uranus transit fell
at 02:00:24 fold=1:
candidate -> UTC 2026-10-25 01:00:24
candidate + 1s -> UTC 2026-10-25 00:00:25 (one hour earlier)
Since `_RISE_SET_PRIOR_WINDOW_DAYS` is 14, every restart in the two weeks
after a DST change hits this.
Fix: `_advance_one_second()` performs the step in UTC, keeping it
monotonic, and three `if candidate <= last_found: break` guards make the
loops terminate even if another non-monotonic step is ever introduced.
Verified offline against real ephemerides with ZoneInfo('Europe/Warsaw'):
uranus went from >300 iterations without terminating to 4 iterations in
0.1 s; mercury, saturn and neptune returned identical results before and
after.
Refs: okkine#3, okkine#2
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Keeps the fork installable from HACS as a custom repository until the DST fix lands upstream (okkine#4). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
next_transit, previous_transit, next_antitransit and previous_antitransit set the find_discrete step to 0.4 * window_days. Skyfield's almanac.meridian_transits() ships step_days = 0.4, which is half the ~0.5 day spacing between an upper and a lower transit, so any window longer than a day makes the sampler step over whole transits and miss them. The window may now only shrink the step, never grow it. Checked against a reference search at step_days = 0.05 for 10 bodies over 6 window lengths (0.25, 1, 2, 7, 14 and 30 days) at 53.5 N 14.5 E: 39 of 60 combinations returned the wrong set of transits before, 0 after. Windows of a day or less are unaffected. Cost is unchanged: a 14 day search for Uranus takes 29.0 ms at the old step and 31.5 ms at 0.4, because find_discrete refines around each crossing either way. The 14 day window is the one TransitSensor uses for the "previous" attribute, where the old step found 18 of the 28 transits actually in the window. Co-Authored-By: Claude Opus 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.
next_transit,previous_transit,next_antitransitandprevious_antitransiteach setSkyfield ships
step_days = 0.4on the functionmeridian_transits()returns ("twice a day"), which is half the spacing between an upper and a lower transit. Scaling that step with the search window means any window longer than a day samples the sign function too coarsely andfind_discretesteps over whole transits.This PR lets the window shrink the step but never grow it.
What it costs today
Checked against a reference search at
step_days = 0.05, 10 bodies, 6 window lengths, 53.5 N 14.5 E:39 of 60 combinations returned the wrong set of transits before, 0 after.
The 14 day window is the one
TransitSensoruses for itspreviousattribute (_RISE_SET_PRIOR_WINDOW_DAYS): the old step found 18 of the 28 transits actually in the window, which is also why the code needs the "keep searching forward" loop afterwards.A concrete miss, 2 day window over 2026-10-26 Europe/Warsaw:
What it costs in time
Nothing measurable. A 14 day Uranus search takes 29.0 ms at the old step and 31.5 ms at 0.4, because
find_discreterefines around each crossing either way.🤖 Generated with Claude Code