A major change to the bootstrapping of Home Assistant decoupling the knowledge in bootstrap for a more dynamic approach. This refactoring also prepares the code for different configuration backends and the loading components from different places.
111 lines
3.4 KiB
Python
111 lines
3.4 KiB
Python
"""
|
|
homeassistant.components.sun
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Provides functionality to keep track of the sun.
|
|
"""
|
|
import logging
|
|
from datetime import timedelta
|
|
|
|
import homeassistant as ha
|
|
import homeassistant.util as util
|
|
|
|
DEPENDENCIES = []
|
|
DOMAIN = "sun"
|
|
ENTITY_ID = "sun.sun"
|
|
|
|
STATE_ABOVE_HORIZON = "above_horizon"
|
|
STATE_BELOW_HORIZON = "below_horizon"
|
|
|
|
STATE_ATTR_NEXT_RISING = "next_rising"
|
|
STATE_ATTR_NEXT_SETTING = "next_setting"
|
|
|
|
|
|
def is_on(hass, entity_id=None):
|
|
""" Returns if the sun is currently up based on the statemachine. """
|
|
entity_id = entity_id or ENTITY_ID
|
|
|
|
return hass.states.is_state(entity_id, STATE_ABOVE_HORIZON)
|
|
|
|
|
|
def next_setting(hass):
|
|
""" Returns the datetime object representing the next sun setting. """
|
|
state = hass.states.get(ENTITY_ID)
|
|
|
|
try:
|
|
return util.str_to_datetime(state.attributes[STATE_ATTR_NEXT_SETTING])
|
|
except (AttributeError, KeyError):
|
|
# AttributeError if state is None
|
|
# KeyError if STATE_ATTR_NEXT_SETTING does not exist
|
|
return None
|
|
|
|
|
|
def next_rising(hass):
|
|
""" Returns the datetime object representing the next sun rising. """
|
|
state = hass.states.get(ENTITY_ID)
|
|
|
|
try:
|
|
return util.str_to_datetime(state.attributes[STATE_ATTR_NEXT_RISING])
|
|
except (AttributeError, KeyError):
|
|
# AttributeError if state is None
|
|
# KeyError if STATE_ATTR_NEXT_RISING does not exist
|
|
return None
|
|
|
|
|
|
def setup(hass, config):
|
|
""" Tracks the state of the sun. """
|
|
logger = logging.getLogger(__name__)
|
|
|
|
if not util.validate_config(config,
|
|
{ha.DOMAIN: [ha.CONF_LATITUDE,
|
|
ha.CONF_LONGITUDE]},
|
|
logger):
|
|
return False
|
|
|
|
try:
|
|
import ephem
|
|
except ImportError:
|
|
logger.exception("TrackSun:Error while importing dependency ephem.")
|
|
return False
|
|
|
|
sun = ephem.Sun() # pylint: disable=no-member
|
|
|
|
latitude = config[ha.DOMAIN][ha.CONF_LATITUDE]
|
|
longitude = config[ha.DOMAIN][ha.CONF_LONGITUDE]
|
|
|
|
def update_sun_state(now): # pylint: disable=unused-argument
|
|
""" Method to update the current state of the sun and
|
|
set time of next setting and rising. """
|
|
observer = ephem.Observer()
|
|
observer.lat = latitude # pylint: disable=assigning-non-slot
|
|
observer.long = longitude # pylint: disable=assigning-non-slot
|
|
|
|
next_rising_dt = ephem.localtime(observer.next_rising(sun))
|
|
next_setting_dt = ephem.localtime(observer.next_setting(sun))
|
|
|
|
if next_rising_dt > next_setting_dt:
|
|
new_state = STATE_ABOVE_HORIZON
|
|
next_change = next_setting_dt
|
|
|
|
else:
|
|
new_state = STATE_BELOW_HORIZON
|
|
next_change = next_rising_dt
|
|
|
|
logger.info(
|
|
"Sun:{}. Next change: {}".format(new_state,
|
|
next_change.strftime("%H:%M")))
|
|
|
|
state_attributes = {
|
|
STATE_ATTR_NEXT_RISING: util.datetime_to_str(next_rising_dt),
|
|
STATE_ATTR_NEXT_SETTING: util.datetime_to_str(next_setting_dt)
|
|
}
|
|
|
|
hass.states.set(ENTITY_ID, new_state, state_attributes)
|
|
|
|
# +10 seconds to be sure that the change has occured
|
|
hass.track_point_in_time(update_sun_state,
|
|
next_change + timedelta(seconds=10))
|
|
|
|
update_sun_state(None)
|
|
|
|
return True
|