fix: replace deprecated get_astral_location with get_astral_observer (#1482)

* fix: replace deprecated get_astral_location with get_astral_observer (#1481)

HA 2026.7 deprecates homeassistant.helpers.sun.get_astral_location
(removal planned for 2027.7) in favor of get_astral_observer, causing a
deprecation warning in the HA logs.

- Switch SunEvents/SunLightSettings from astral.location.Location to
  astral.Observer, using the astral.sun module functions (which return
  UTC times by default, matching the previous local=False calls).
- Use get_astral_observer in switch.py, with a fallback for HA < 2026.7
  that constructs the Observer directly from the HA config.
- Update tests and the webapp simulator accordingly.

* ci: handle removal of requirements_test_all.txt in HA 2026.8 dev

HA core removed requirements_test_all.txt (home-assistant/core#171530),
which made test_dependencies.py crash with FileNotFoundError and broke
the dev pytest job and the Docker builds. Fall back to
requirements_all.txt, which carries the same per-integration
'# homeassistant.components.x' annotations. Also extend the
aiohasupervisor pin lookup in scripts/setup-dependencies accordingly.

* test: support modern template light config for HA 2026.6+

HA 2026.6 removed the legacy `light: platform: template` YAML format
(home-assistant/core#169615), so setup_lights found no template platform
on HA dev and every test using it failed with IndexError. Detect legacy
support at runtime (PLATFORM_SCHEMA presence) and fall back to the
modern `template:` config format. The group platform is set up before
the template integration in the modern path, because setting up
`template` also sets up the `light` domain, which would make a later
async_setup_component(hass, LIGHT_DOMAIN, ...) a no-op.
This commit is contained in:
Bas Nijholt 2026-07-01 23:00:35 -07:00 committed by GitHub
commit d4d3d50ada
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 159 additions and 94 deletions

View file

@ -11,17 +11,15 @@ from dataclasses import dataclass
from datetime import UTC, timedelta
from enum import Enum
from functools import cached_property, partial
from typing import TYPE_CHECKING, Any, Literal, cast
from typing import Any, Literal, cast
import astral.sun
from homeassistant.util.color import (
color_RGB_to_xy,
color_temperature_to_rgb,
color_xy_to_hs,
)
if TYPE_CHECKING:
import astral.location
class SunEvent(str, Enum):
"""A set of sun events that happen during a day."""
@ -48,7 +46,7 @@ class SunEvents:
"""Track the state of the sun and associated light settings."""
name: str
astral_location: astral.location.Location
astral_observer: astral.Observer
sunrise_time: datetime.time | None
min_sunrise_time: datetime.time | None
max_sunrise_time: datetime.time | None
@ -62,7 +60,7 @@ class SunEvents:
def sunrise(self, dt: datetime.date) -> datetime.datetime:
"""Return the (adjusted) sunrise time for the given datetime."""
sunrise = (
self.astral_location.sunrise(dt, local=False)
astral.sun.sunrise(self.astral_observer, dt)
if self.sunrise_time is None
else self._replace_time(dt, self.sunrise_time)
) + self.sunrise_offset
@ -77,7 +75,7 @@ class SunEvents:
def sunset(self, dt: datetime.date) -> datetime.datetime:
"""Return the (adjusted) sunset time for the given datetime."""
sunset = (
self.astral_location.sunset(dt, local=False)
astral.sun.sunset(self.astral_observer, dt)
if self.sunset_time is None
else self._replace_time(dt, self.sunset_time)
) + self.sunset_offset
@ -113,8 +111,8 @@ class SunEvents:
and self.min_sunset_time is None
and self.max_sunset_time is None
):
solar_noon = self.astral_location.noon(dt, local=False)
solar_midnight = self.astral_location.midnight(dt, local=False)
solar_noon = astral.sun.noon(self.astral_observer, dt)
solar_midnight = astral.sun.midnight(self.astral_observer, dt)
return solar_noon, solar_midnight
if sunset is None:
@ -208,7 +206,7 @@ class SunLightSettings:
"""Track the state of the sun and associated light settings."""
name: str
astral_location: astral.location.Location
astral_observer: astral.Observer
adapt_until_sleep: bool
max_brightness: int
max_color_temp: int
@ -236,7 +234,7 @@ class SunLightSettings:
"""Return the SunEvents object."""
return SunEvents(
name=self.name,
astral_location=self.astral_location,
astral_observer=self.astral_observer,
sunrise_time=self.sunrise_time,
sunrise_offset=self.sunrise_offset,
min_sunrise_time=self.min_sunrise_time,

View file

@ -66,7 +66,6 @@ from homeassistant.helpers.event import (
async_track_time_interval,
)
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.sun import get_astral_location
from homeassistant.util import slugify
from homeassistant.util.color import (
color_temperature_to_rgb,
@ -164,6 +163,19 @@ if TYPE_CHECKING:
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import NoEventData, VolDictType
try:
from homeassistant.helpers.sun import get_astral_observer
except ImportError: # `get_astral_observer` was added in HA 2026.7
from astral import Observer
def get_astral_observer(hass: HomeAssistant) -> Observer:
"""Get an astral observer for the current HA configuration."""
return Observer(
hass.config.latitude,
hass.config.longitude,
hass.config.elevation,
)
_LOGGER = logging.getLogger(__name__)
@ -944,11 +956,11 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
)
self._multi_light_intercept = False
self._expand_light_groups() # updates manual control timers
location, _ = get_astral_location(self.hass)
observer = get_astral_observer(self.hass)
self._sun_light_settings = SunLightSettings(
name=self._name,
astral_location=location,
astral_observer=observer,
adapt_until_sleep=data[CONF_ADAPT_UNTIL_SLEEP],
max_brightness=data[CONF_MAX_BRIGHTNESS],
max_color_temp=data[CONF_MAX_COLOR_TEMP],