Repository navigation
feat(covers): close the covers on the sun's elevation, and name those… - #25
Merged
Merged
Conversation
… left up
Two changes to the evening close, kept in one commit because they land in the
same files and the same screens.
**The closing time now comes from the sun's elevation.** "Sunset + N minutes"
is a delay you have to guess at; degrees above the horizon are a light level,
the value sun.sun already publishes. Covers close when the descending sun
reaches the configured elevation. Degrees say nothing about clock time, so
the form turns the setting into tonight's time from the instance's own
location — "At -2°, that is 21:41 tonight."
The minute offset is gone rather than kept alongside: two settings for one
decision, with only one of them live, is a trap. The v3 -> v4 migration
converts each entry's stored offset into the elevation it was landing on,
averaged over the equinoxes and solstices and rounded to the half degree the
form offers, so covers keep moving at the time they moved before. Measured
with astral at 43.5N: sunset + 10 min is -2.5, sunset - 10 min is +1.5. The
range offered (+-25) holds every value the old +-120 minutes could express,
and an entry that never touched the offset is converted from the default it
was silently running on.
Default is -2°: that is where the old default of sunset + 10 min landed, at
every season, so a fresh install behaves like the old one.
The form refuses an elevation the sun never reaches at that location, checked
against both solstices, instead of leaving the runtime to discover it at
nightfall months later. What that rejects depends entirely on latitude:
nothing at 43N, where the sun sweeps the whole range every day; +10 at 60N,
where the midwinter sun stops at 6.6; everything above the polar circle in
June. A rejected submission redisplays what was typed. The runtime keeps a
fallback to plain sunset for what the form cannot check — a home that moved,
an entry restored elsewhere — and the Cover Close Time sensor reports which
of the two produced tonight's time.
**binary_sensor.covers_left_open** raises the skipped-cover warning where it
can be acted on. A cover whose window sensor reads open is left up and, until
now, only mentioned in the log, which nobody reads. The entity is a
device_class problem, on as soon as one cover was skipped, listing the covers
and the sensor that blocked each of them so a notification can name them. It
clears when the next day's schedule is computed, not when the window closes:
closing the window does not bring the cover down, so the warning has to
outlive its cause. The list is persisted, so a reboot the same evening does
not silence it.
Supporting changes: _covers_behind_an_open_window returns {cover: sensor}
rather than a set, since the entity has to name the sensor and the callers
only needed membership; _async_run_cover_checks pushes state to the entities,
because the open/close timers fire between polls and the warning would
otherwise show the previous value for up to five minutes; the astral lookups
live at module level in cover_manager so the config flow and the migration
can use them without a CoverManager, and go through get_astral_observer,
since get_astral_location is deprecated for removal in HA 2027.7.
59 new tests (338 -> 397).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…s moving CI was testing Home Assistant 2026.2.3 while the local image ran 2026.9.2, and get_astral_observer was added between the two — so the import failed only on CI. The version was never chosen: the workflow pins Python 3.13, which caps the resolvable pytest-homeassistant-custom-component, and that caps Home Assistant. This integration targets 2026.9 and above, so the workflows now run on Python 3.14 (which resolves 2026.9.3), hacs.json refuses installation below 2026.9.0 instead of 2026.2.2, and the README says so. The astral observer is built from hass.config.latitude / longitude / elevation rather than imported. With the floor raised, get_astral_observer would be available — but homeassistant.helpers.sun has already moved this ground once, get_astral_location is deprecated for removal in 2027.7, and building the observer is the single line that helper contains, against config attributes that have been stable for years. Verified on containers matching both jobs (python:3.14 + requirements_test.txt, Home Assistant 2026.9.3): 397 passed, py_compile and validate.sh clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The closing elevation sat between "Earliest Open Time" and the per-mode opening times, splitting the opening settings in two. It now comes first, on its own, so the step reads as one closing field followed by everything about opening. The translation files are reordered to match, which keeps them diffable against the form. 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.
… left up
Two changes to the evening close, kept in one commit because they land in the same files and the same screens.
The closing time now comes from the sun's elevation. "Sunset + N minutes" is a delay you have to guess at; degrees above the horizon are a light level, the value sun.sun already publishes. Covers close when the descending sun reaches the configured elevation. Degrees say nothing about clock time, so the form turns the setting into tonight's time from the instance's own location — "At -2°, that is 21:41 tonight."
The minute offset is gone rather than kept alongside: two settings for one decision, with only one of them live, is a trap. The v3 -> v4 migration converts each entry's stored offset into the elevation it was landing on, averaged over the equinoxes and solstices and rounded to the half degree the form offers, so covers keep moving at the time they moved before. Measured with astral at 43.5N: sunset + 10 min is -2.5, sunset - 10 min is +1.5. The range offered (+-25) holds every value the old +-120 minutes could express, and an entry that never touched the offset is converted from the default it was silently running on.
Default is -2°: that is where the old default of sunset + 10 min landed, at every season, so a fresh install behaves like the old one.
The form refuses an elevation the sun never reaches at that location, checked against both solstices, instead of leaving the runtime to discover it at nightfall months later. What that rejects depends entirely on latitude: nothing at 43N, where the sun sweeps the whole range every day; +10 at 60N, where the midwinter sun stops at 6.6; everything above the polar circle in June. A rejected submission redisplays what was typed. The runtime keeps a fallback to plain sunset for what the form cannot check — a home that moved, an entry restored elsewhere — and the Cover Close Time sensor reports which of the two produced tonight's time.
binary_sensor.covers_left_open raises the skipped-cover warning where it can be acted on. A cover whose window sensor reads open is left up and, until now, only mentioned in the log, which nobody reads. The entity is a device_class problem, on as soon as one cover was skipped, listing the covers and the sensor that blocked each of them so a notification can name them. It clears when the next day's schedule is computed, not when the window closes: closing the window does not bring the cover down, so the warning has to outlive its cause. The list is persisted, so a reboot the same evening does not silence it.
Supporting changes: _covers_behind_an_open_window returns {cover: sensor} rather than a set, since the entity has to name the sensor and the callers only needed membership; _async_run_cover_checks pushes state to the entities, because the open/close timers fire between polls and the warning would otherwise show the previous value for up to five minutes; the astral lookups live at module level in cover_manager so the config flow and the migration can use them without a CoverManager, and go through get_astral_observer, since get_astral_location is deprecated for removal in HA 2027.7.
59 new tests (338 -> 397).