mirror of
https://github.com/home-assistant/core.git
synced 2025-07-29 18:28:14 +02:00
Refactor sun component for correctness (#7295)
* Refactor sun component for correctness * Convert datetimes to dates for astral * Fix tests for updated code * Fix times now that calcs are fixed * Move sun functions to helpers * Fix flake on new file * Additional tweaks from review * Update requirements
This commit is contained in:
committed by
Paulus Schoutsen
parent
419d97fc06
commit
40d27cde0e
87
homeassistant/helpers/sun.py
Normal file
87
homeassistant/helpers/sun.py
Normal file
@ -0,0 +1,87 @@
|
||||
"""Helpers for sun events."""
|
||||
import datetime
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
DATA_LOCATION_CACHE = 'astral_location_cache'
|
||||
|
||||
|
||||
@callback
|
||||
def get_astral_location(hass):
|
||||
"""Get an astral location for the current hass configuration."""
|
||||
from astral import Location
|
||||
|
||||
latitude = hass.config.latitude
|
||||
longitude = hass.config.longitude
|
||||
timezone = hass.config.time_zone.zone
|
||||
elevation = hass.config.elevation
|
||||
info = ('', '', latitude, longitude, timezone, elevation)
|
||||
|
||||
# Cache astral locations so they aren't recreated with the same args
|
||||
if DATA_LOCATION_CACHE not in hass.data:
|
||||
hass.data[DATA_LOCATION_CACHE] = {}
|
||||
|
||||
if info not in hass.data[DATA_LOCATION_CACHE]:
|
||||
hass.data[DATA_LOCATION_CACHE][info] = Location(info)
|
||||
|
||||
return hass.data[DATA_LOCATION_CACHE][info]
|
||||
|
||||
|
||||
@callback
|
||||
def get_astral_event_next(hass, event, utc_point_in_time=None, offset=None):
|
||||
"""Calculate the next specified solar event."""
|
||||
import astral
|
||||
|
||||
location = get_astral_location(hass)
|
||||
|
||||
if offset is None:
|
||||
offset = datetime.timedelta()
|
||||
|
||||
if utc_point_in_time is None:
|
||||
utc_point_in_time = dt_util.utcnow()
|
||||
|
||||
mod = -1
|
||||
while True:
|
||||
try:
|
||||
next_dt = getattr(location, event)(
|
||||
dt_util.as_local(utc_point_in_time).date() +
|
||||
datetime.timedelta(days=mod),
|
||||
local=False) + offset
|
||||
if next_dt > utc_point_in_time:
|
||||
return next_dt
|
||||
except astral.AstralError:
|
||||
pass
|
||||
mod += 1
|
||||
|
||||
|
||||
@callback
|
||||
def get_astral_event_date(hass, event, date=None):
|
||||
"""Calculate the astral event time for the specified date."""
|
||||
import astral
|
||||
|
||||
location = get_astral_location(hass)
|
||||
|
||||
if date is None:
|
||||
date = dt_util.now().date()
|
||||
|
||||
if isinstance(date, datetime.datetime):
|
||||
date = dt_util.as_local(date).date()
|
||||
|
||||
try:
|
||||
return getattr(location, event)(date, local=False)
|
||||
except astral.AstralError:
|
||||
# Event never occurs for specified date.
|
||||
return None
|
||||
|
||||
|
||||
@callback
|
||||
def is_up(hass, utc_point_in_time=None):
|
||||
"""Calculate if the sun is currently up."""
|
||||
if utc_point_in_time is None:
|
||||
utc_point_in_time = dt_util.utcnow()
|
||||
|
||||
next_sunrise = get_astral_event_next(hass, 'sunrise', utc_point_in_time)
|
||||
next_sunset = get_astral_event_next(hass, 'sunset', utc_point_in_time)
|
||||
|
||||
return next_sunrise > next_sunset
|
Reference in New Issue
Block a user