ha-core/homeassistant/helpers/sun.py

93 lines
2.5 KiB
Python

"""Helpers for sun events."""
import datetime
from homeassistant.core import callback
from homeassistant.util import dt as dt_util
from homeassistant.loader import bind_hass
DATA_LOCATION_CACHE = 'astral_location_cache'
@callback
@bind_hass
def get_astral_location(hass):
"""Get an astral location for the current Home Assistant 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
@bind_hass
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
@bind_hass
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
@bind_hass
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