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:
Adam Mills 2017-05-09 03:03:34 -04:00 committed by Paulus Schoutsen
parent 419d97fc06
commit 40d27cde0e
19 changed files with 754 additions and 756 deletions

View File

@ -16,8 +16,6 @@ from homeassistant.const import (
from homeassistant.helpers.event import async_track_sunrise, async_track_sunset
import homeassistant.helpers.config_validation as cv
DEPENDENCIES = ['sun']
_LOGGER = logging.getLogger(__name__)
TRIGGER_SCHEMA = vol.Schema({

View File

@ -14,12 +14,13 @@ from homeassistant.core import callback
import homeassistant.util.dt as dt_util
from homeassistant.const import STATE_HOME, STATE_NOT_HOME
from homeassistant.helpers.event import (
async_track_point_in_time, async_track_state_change)
async_track_point_in_utc_time, async_track_state_change)
from homeassistant.helpers.sun import is_up, get_astral_event_next
from homeassistant.loader import get_component
import homeassistant.helpers.config_validation as cv
DOMAIN = 'device_sun_light_trigger'
DEPENDENCIES = ['light', 'device_tracker', 'group', 'sun']
DEPENDENCIES = ['light', 'device_tracker', 'group']
CONF_DEVICE_GROUP = 'device_group'
CONF_DISABLE_TURN_OFF = 'disable_turn_off'
@ -50,7 +51,6 @@ def async_setup(hass, config):
device_tracker = get_component('device_tracker')
group = get_component('group')
light = get_component('light')
sun = get_component('sun')
conf = config[DOMAIN]
disable_turn_off = conf.get(CONF_DISABLE_TURN_OFF)
light_group = conf.get(CONF_LIGHT_GROUP, light.ENTITY_ID_ALL_LIGHTS)
@ -78,7 +78,7 @@ def async_setup(hass, config):
Async friendly.
"""
next_setting = sun.next_setting(hass)
next_setting = get_astral_event_next(hass, 'sunset')
if not next_setting:
return None
return next_setting - LIGHT_TRANSITION_TIME * len(light_ids)
@ -103,7 +103,7 @@ def async_setup(hass, config):
# Track every time sun rises so we can schedule a time-based
# pre-sun set event
@callback
def schedule_light_turn_on(entity, old_state, new_state):
def schedule_light_turn_on(now):
"""Turn on all the lights at the moment sun sets.
We will schedule to have each light start after one another
@ -114,26 +114,26 @@ def async_setup(hass, config):
return
for index, light_id in enumerate(light_ids):
async_track_point_in_time(
async_track_point_in_utc_time(
hass, async_turn_on_factory(light_id),
start_point + index * LIGHT_TRANSITION_TIME)
async_track_state_change(hass, sun.ENTITY_ID, schedule_light_turn_on,
sun.STATE_BELOW_HORIZON, sun.STATE_ABOVE_HORIZON)
async_track_point_in_utc_time(hass, schedule_light_turn_on,
get_astral_event_next(hass, 'sunrise'))
# If the sun is already above horizon schedule the time-based pre-sun set
# event.
if sun.is_on(hass):
schedule_light_turn_on(None, None, None)
if is_up(hass):
schedule_light_turn_on(None)
@callback
def check_light_on_dev_state_change(entity, old_state, new_state):
"""Handle tracked device state changes."""
lights_are_on = group.is_on(hass, light_group)
light_needed = not (lights_are_on or sun.is_on(hass))
light_needed = not (lights_are_on or is_up(hass))
# These variables are needed for the elif check
now = dt_util.now()
now = dt_util.utcnow()
start_point = calc_time_for_light_when_sunset()
# Do we need lights?
@ -146,7 +146,7 @@ def async_setup(hass, config):
# Check this by seeing if current time is later then the point
# in time when we would start putting the lights on.
elif (start_point and
start_point < now < sun.next_setting(hass)):
start_point < now < get_astral_event_next(hass, 'sunset')):
# Check for every light if it would be on if someone was home
# when the fading in started and turn it on if so

View File

@ -15,8 +15,6 @@ import homeassistant.util.dt as dt_util
from homeassistant.helpers.entity import Entity
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['astral==1.4']
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'Moon'

View File

@ -4,20 +4,18 @@ Support for functionality to keep track of the sun.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/sun/
"""
import asyncio
import logging
from datetime import timedelta
import voluptuous as vol
from homeassistant.const import CONF_ELEVATION
from homeassistant.core import callback
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import (
track_point_in_utc_time, track_utc_time_change)
async_track_point_in_utc_time, async_track_utc_time_change)
from homeassistant.helpers.sun import (
get_astral_location, get_astral_event_next)
from homeassistant.util import dt as dt_util
import homeassistant.helpers.config_validation as cv
import homeassistant.util as util
REQUIREMENTS = ['astral==1.4']
_LOGGER = logging.getLogger(__name__)
@ -37,223 +35,16 @@ STATE_ATTR_NEXT_NOON = 'next_noon'
STATE_ATTR_NEXT_RISING = 'next_rising'
STATE_ATTR_NEXT_SETTING = 'next_setting'
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Optional(CONF_ELEVATION): cv.positive_int,
}),
}, extra=vol.ALLOW_EXTRA)
def is_on(hass, entity_id=None):
"""Test 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_dawn(hass, entity_id=None):
"""Local datetime object of the next dawn.
Async friendly.
"""
utc_next = next_dawn_utc(hass, entity_id)
return dt_util.as_local(utc_next) if utc_next else None
def next_dawn_utc(hass, entity_id=None):
"""UTC datetime object of the next dawn.
Async friendly.
"""
entity_id = entity_id or ENTITY_ID
state = hass.states.get(ENTITY_ID)
try:
return dt_util.parse_datetime(
state.attributes[STATE_ATTR_NEXT_DAWN])
except (AttributeError, KeyError):
# AttributeError if state is None
# KeyError if STATE_ATTR_NEXT_DAWN does not exist
return None
def next_dusk(hass, entity_id=None):
"""Local datetime object of the next dusk.
Async friendly.
"""
utc_next = next_dusk_utc(hass, entity_id)
return dt_util.as_local(utc_next) if utc_next else None
def next_dusk_utc(hass, entity_id=None):
"""UTC datetime object of the next dusk.
Async friendly.
"""
entity_id = entity_id or ENTITY_ID
state = hass.states.get(ENTITY_ID)
try:
return dt_util.parse_datetime(
state.attributes[STATE_ATTR_NEXT_DUSK])
except (AttributeError, KeyError):
# AttributeError if state is None
# KeyError if STATE_ATTR_NEXT_DUSK does not exist
return None
def next_midnight(hass, entity_id=None):
"""Local datetime object of the next midnight.
Async friendly.
"""
utc_next = next_midnight_utc(hass, entity_id)
return dt_util.as_local(utc_next) if utc_next else None
def next_midnight_utc(hass, entity_id=None):
"""UTC datetime object of the next midnight.
Async friendly.
"""
entity_id = entity_id or ENTITY_ID
state = hass.states.get(ENTITY_ID)
try:
return dt_util.parse_datetime(
state.attributes[STATE_ATTR_NEXT_MIDNIGHT])
except (AttributeError, KeyError):
# AttributeError if state is None
# KeyError if STATE_ATTR_NEXT_MIDNIGHT does not exist
return None
def next_noon(hass, entity_id=None):
"""Local datetime object of the next solar noon.
Async friendly.
"""
utc_next = next_noon_utc(hass, entity_id)
return dt_util.as_local(utc_next) if utc_next else None
def next_noon_utc(hass, entity_id=None):
"""UTC datetime object of the next noon.
Async friendly.
"""
entity_id = entity_id or ENTITY_ID
state = hass.states.get(ENTITY_ID)
try:
return dt_util.parse_datetime(
state.attributes[STATE_ATTR_NEXT_NOON])
except (AttributeError, KeyError):
# AttributeError if state is None
# KeyError if STATE_ATTR_NEXT_NOON does not exist
return None
def next_setting(hass, entity_id=None):
"""Local datetime object of the next sun setting.
Async friendly.
"""
utc_next = next_setting_utc(hass, entity_id)
return dt_util.as_local(utc_next) if utc_next else None
def next_setting_utc(hass, entity_id=None):
"""UTC datetime object of the next sun setting.
Async friendly.
"""
entity_id = entity_id or ENTITY_ID
state = hass.states.get(ENTITY_ID)
try:
return dt_util.parse_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, entity_id=None):
"""Local datetime object of the next sun rising.
Async friendly.
"""
utc_next = next_rising_utc(hass, entity_id)
return dt_util.as_local(utc_next) if utc_next else None
def next_rising_utc(hass, entity_id=None):
"""UTC datetime object of the next sun rising.
Async friendly.
"""
entity_id = entity_id or ENTITY_ID
state = hass.states.get(ENTITY_ID)
try:
return dt_util.parse_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):
@asyncio.coroutine
def async_setup(hass, config):
"""Track the state of the sun."""
if None in (hass.config.latitude, hass.config.longitude):
_LOGGER.error("Latitude or longitude not set in Home Assistant config")
return False
if config.get(CONF_ELEVATION) is not None:
_LOGGER.warning(
"Elevation is now configured in home assistant core. "
"See https://home-assistant.io/docs/configuration/basic/")
latitude = util.convert(hass.config.latitude, float)
longitude = util.convert(hass.config.longitude, float)
errors = []
if latitude is None:
errors.append('Latitude needs to be a decimal value')
elif -90 > latitude < 90:
errors.append('Latitude needs to be -90 .. 90')
if longitude is None:
errors.append('Longitude needs to be a decimal value')
elif -180 > longitude < 180:
errors.append('Longitude needs to be -180 .. 180')
if errors:
_LOGGER.error('Invalid configuration received: %s', ", ".join(errors))
return False
platform_config = config.get(DOMAIN, {})
elevation = platform_config.get(CONF_ELEVATION)
if elevation is None:
elevation = hass.config.elevation or 0
from astral import Location
location = Location(('', '', latitude, longitude,
hass.config.time_zone.zone, elevation))
sun = Sun(hass, location)
sun = Sun(hass, get_astral_location(hass))
sun.point_in_time_listener(dt_util.utcnow())
return True
@ -273,7 +64,7 @@ class Sun(Entity):
self.next_midnight = self.next_noon = None
self.solar_elevation = self.solar_azimuth = 0
track_utc_time_change(hass, self.timer_update, second=30)
async_track_utc_time_change(hass, self.timer_update, second=30)
@property
def name(self):
@ -308,64 +99,41 @@ class Sun(Entity):
return min(self.next_dawn, self.next_dusk, self.next_midnight,
self.next_noon, self.next_rising, self.next_setting)
@staticmethod
def get_next_solar_event(callable_on_astral_location,
utc_point_in_time, mod, increment):
"""Calculate sun state at a point in UTC time."""
import astral
while True:
try:
next_dt = callable_on_astral_location(
utc_point_in_time + timedelta(days=mod), local=False)
if next_dt > utc_point_in_time:
break
except astral.AstralError:
pass
mod += increment
return next_dt
@callback
def update_as_of(self, utc_point_in_time):
"""Update the attributes containing solar events."""
self.next_dawn = Sun.get_next_solar_event(
self.location.dawn, utc_point_in_time, -1, 1)
self.next_dusk = Sun.get_next_solar_event(
self.location.dusk, utc_point_in_time, -1, 1)
self.next_midnight = Sun.get_next_solar_event(
self.location.solar_midnight, utc_point_in_time, -1, 1)
self.next_noon = Sun.get_next_solar_event(
self.location.solar_noon, utc_point_in_time, -1, 1)
self.next_rising = Sun.get_next_solar_event(
self.location.sunrise, utc_point_in_time, -1, 1)
self.next_setting = Sun.get_next_solar_event(
self.location.sunset, utc_point_in_time, -1, 1)
self.next_dawn = get_astral_event_next(
self.hass, 'dawn', utc_point_in_time)
self.next_dusk = get_astral_event_next(
self.hass, 'dusk', utc_point_in_time)
self.next_midnight = get_astral_event_next(
self.hass, 'solar_midnight', utc_point_in_time)
self.next_noon = get_astral_event_next(
self.hass, 'solar_noon', utc_point_in_time)
self.next_rising = get_astral_event_next(
self.hass, 'sunrise', utc_point_in_time)
self.next_setting = get_astral_event_next(
self.hass, 'sunset', utc_point_in_time)
@callback
def update_sun_position(self, utc_point_in_time):
"""Calculate the position of the sun."""
from astral import Astral
self.solar_azimuth = Astral().solar_azimuth(
utc_point_in_time,
self.location.latitude,
self.location.longitude)
self.solar_elevation = Astral().solar_elevation(
utc_point_in_time,
self.location.latitude,
self.location.longitude)
self.solar_azimuth = self.location.solar_azimuth(utc_point_in_time)
self.solar_elevation = self.location.solar_elevation(utc_point_in_time)
@callback
def point_in_time_listener(self, now):
"""Run when the state of the sun has changed."""
self.update_as_of(now)
self.schedule_update_ha_state()
self.hass.async_add_job(self.async_update_ha_state())
# Schedule next update at next_change+1 second so sun state has changed
track_point_in_utc_time(
async_track_point_in_utc_time(
self.hass, self.point_in_time_listener,
self.next_change + timedelta(seconds=1))
@callback
def timer_update(self, time):
"""Needed to update solar elevation and azimuth."""
self.update_sun_position(time)
self.schedule_update_ha_state()
self.hass.async_add_job(self.async_update_ha_state())

View File

@ -11,18 +11,18 @@ import logging
import voluptuous as vol
from homeassistant.components.light import is_on, turn_on
from homeassistant.components.sun import next_setting, next_rising
from homeassistant.components.switch import DOMAIN, SwitchDevice
from homeassistant.const import CONF_NAME, CONF_PLATFORM
from homeassistant.helpers.event import track_time_change
from homeassistant.helpers.sun import get_astral_event_date
from homeassistant.util.color import (
color_temperature_to_rgb, color_RGB_to_xy,
color_temperature_kelvin_to_mired)
from homeassistant.util.dt import now as dt_now
import homeassistant.helpers.config_validation as cv
DEPENDENCIES = ['sun', 'light']
SUN = "sun.sun"
DEPENDENCIES = ['light']
_LOGGER = logging.getLogger(__name__)
CONF_LIGHTS = 'lights'
@ -159,8 +159,7 @@ class FluxSwitch(SwitchDevice):
"""Update all the lights using flux."""
if now is None:
now = dt_now()
sunset = next_setting(self.hass, SUN).replace(
day=now.day, month=now.month, year=now.year)
sunset = get_astral_event_date(self.hass, 'sunset', now.date())
start_time = self.find_start_time(now)
stop_time = now.replace(
hour=self._stop_time.hour, minute=self._stop_time.minute,
@ -221,6 +220,5 @@ class FluxSwitch(SwitchDevice):
hour=self._start_time.hour, minute=self._start_time.minute,
second=0)
else:
sunrise = next_rising(self.hass, SUN).replace(
day=now.day, month=now.month, year=now.year)
sunrise = get_astral_event_date(self.hass, 'sunrise', now.date())
return sunrise

View File

@ -7,8 +7,7 @@ import sys
from homeassistant.helpers.typing import ConfigType
from homeassistant.core import HomeAssistant
from homeassistant.components import (
zone as zone_cmp, sun as sun_cmp)
from homeassistant.components import zone as zone_cmp
from homeassistant.const import (
ATTR_GPS_ACCURACY, ATTR_LATITUDE, ATTR_LONGITUDE,
CONF_ENTITY_ID, CONF_VALUE_TEMPLATE, CONF_CONDITION,
@ -17,6 +16,7 @@ from homeassistant.const import (
CONF_BELOW, CONF_ABOVE)
from homeassistant.exceptions import TemplateError, HomeAssistantError
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.sun import get_astral_event_date
import homeassistant.util.dt as dt_util
from homeassistant.util.async import run_callback_threadsafe
@ -234,24 +234,34 @@ def state_from_config(config, config_validation=True):
def sun(hass, before=None, after=None, before_offset=None, after_offset=None):
"""Test if current time matches sun requirements."""
now = dt_util.now().time()
utcnow = dt_util.utcnow()
today = dt_util.as_local(utcnow).date()
before_offset = before_offset or timedelta(0)
after_offset = after_offset or timedelta(0)
if before == SUN_EVENT_SUNRISE and now > (sun_cmp.next_rising(hass) +
before_offset).time():
sunrise = get_astral_event_date(hass, 'sunrise', today)
sunset = get_astral_event_date(hass, 'sunset', today)
if sunrise is None and (before == SUN_EVENT_SUNRISE or
after == SUN_EVENT_SUNRISE):
# There is no sunrise today
return False
elif before == SUN_EVENT_SUNSET and now > (sun_cmp.next_setting(hass) +
before_offset).time():
if sunset is None and (before == SUN_EVENT_SUNSET or
after == SUN_EVENT_SUNSET):
# There is no sunset today
return False
if after == SUN_EVENT_SUNRISE and now < (sun_cmp.next_rising(hass) +
after_offset).time():
if before == SUN_EVENT_SUNRISE and utcnow > sunrise + before_offset:
return False
elif after == SUN_EVENT_SUNSET and now < (sun_cmp.next_setting(hass) +
after_offset).time():
elif before == SUN_EVENT_SUNSET and utcnow > sunset + before_offset:
return False
if after == SUN_EVENT_SUNRISE and utcnow < sunrise + after_offset:
return False
elif after == SUN_EVENT_SUNSET and utcnow < sunset + after_offset:
return False
return True

View File

@ -1,7 +1,7 @@
"""Helpers for listening to events."""
import functools as ft
from datetime import timedelta
from homeassistant.helpers.sun import get_astral_event_next
from ..core import HomeAssistant, callback
from ..const import (
ATTR_NOW, EVENT_STATE_CHANGED, EVENT_TIME_CHANGED, MATCH_ALL)
@ -197,29 +197,20 @@ track_time_interval = threaded_listener_factory(async_track_time_interval)
@callback
def async_track_sunrise(hass, action, offset=None):
"""Add a listener that will fire a specified offset from sunrise daily."""
from homeassistant.components import sun
offset = offset or timedelta()
remove = None
def next_rise():
"""Return the next sunrise."""
next_time = sun.next_rising_utc(hass) + offset
while next_time < dt_util.utcnow():
next_time = next_time + timedelta(days=1)
return next_time
@callback
def sunrise_automation_listener(now):
"""Handle points in time to execute actions."""
nonlocal remove
remove = async_track_point_in_utc_time(
hass, sunrise_automation_listener, next_rise())
hass, sunrise_automation_listener, get_astral_event_next(
hass, 'sunrise', offset=offset))
hass.async_run_job(action)
remove = async_track_point_in_utc_time(
hass, sunrise_automation_listener, next_rise())
hass, sunrise_automation_listener, get_astral_event_next(
hass, 'sunrise', offset=offset))
def remove_listener():
"""Remove sunset listener."""
@ -234,29 +225,20 @@ track_sunrise = threaded_listener_factory(async_track_sunrise)
@callback
def async_track_sunset(hass, action, offset=None):
"""Add a listener that will fire a specified offset from sunset daily."""
from homeassistant.components import sun
offset = offset or timedelta()
remove = None
def next_set():
"""Return next sunrise."""
next_time = sun.next_setting_utc(hass) + offset
while next_time < dt_util.utcnow():
next_time = next_time + timedelta(days=1)
return next_time
@callback
def sunset_automation_listener(now):
"""Handle points in time to execute actions."""
nonlocal remove
remove = async_track_point_in_utc_time(
hass, sunset_automation_listener, next_set())
hass, sunset_automation_listener, get_astral_event_next(
hass, 'sunset', offset=offset))
hass.async_run_job(action)
remove = async_track_point_in_utc_time(
hass, sunset_automation_listener, next_set())
hass, sunset_automation_listener, get_astral_event_next(
hass, 'sunset', offset=offset))
def remove_listener():
"""Remove sunset listener."""

View 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

View File

@ -8,3 +8,4 @@ typing>=3,<4
aiohttp==2.0.7
async_timeout==1.2.1
chardet==3.0.2
astral==1.4

View File

@ -9,6 +9,7 @@ typing>=3,<4
aiohttp==2.0.7
async_timeout==1.2.1
chardet==3.0.2
astral==1.4
# homeassistant.components.nuimo_controller
--only-binary=all https://github.com/getSenic/nuimo-linux-python/archive/29fc42987f74d8090d0e2382e8f248ff5990b8c9.zip#nuimo==1.0.0
@ -66,10 +67,6 @@ apcaccess==0.0.4
# homeassistant.components.notify.apns
apns2==0.1.1
# homeassistant.components.sun
# homeassistant.components.sensor.moon
astral==1.4
# homeassistant.components.light.avion
# avion==0.6

View File

@ -37,10 +37,6 @@ aiohttp_cors==0.5.3
# homeassistant.components.notify.apns
apns2==0.1.1
# homeassistant.components.sun
# homeassistant.components.sensor.moon
astral==1.4
# homeassistant.components.datadog
datadog==0.15.0

View File

@ -24,7 +24,8 @@ REQUIRES = [
'typing>=3,<4',
'aiohttp==2.0.7',
'async_timeout==1.2.1',
'chardet==3.0.2'
'chardet==3.0.2',
'astral==1.4',
]
setup(

View File

@ -3,7 +3,6 @@ import asyncio
import functools as ft
import os
import sys
from datetime import timedelta
from unittest.mock import patch, MagicMock, Mock
from io import StringIO
import logging
@ -25,7 +24,7 @@ from homeassistant.const import (
STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME, EVENT_TIME_CHANGED,
EVENT_STATE_CHANGED, EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE,
ATTR_DISCOVERED, SERVER_PORT, EVENT_HOMEASSISTANT_CLOSE)
from homeassistant.components import sun, mqtt, recorder
from homeassistant.components import mqtt, recorder
from homeassistant.components.http.auth import auth_middleware
from homeassistant.components.http.const import (
KEY_USE_X_FORWARDED_FOR, KEY_BANS_ENABLED, KEY_TRUSTED_NETWORKS)
@ -213,20 +212,6 @@ def fire_service_discovered(hass, service, info):
})
def ensure_sun_risen(hass):
"""Trigger sun to rise if below horizon."""
if sun.is_on(hass):
return
fire_time_changed(hass, sun.next_rising_utc(hass) + timedelta(seconds=10))
def ensure_sun_set(hass):
"""Trigger sun to set if above horizon."""
if not sun.is_on(hass):
return
fire_time_changed(hass, sun.next_setting_utc(hass) + timedelta(seconds=10))
def load_fixture(filename):
"""Load a fixture."""
path = os.path.join(os.path.dirname(__file__), 'fixtures', filename)

View File

@ -22,7 +22,8 @@ class TestAutomationSun(unittest.TestCase):
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
mock_component(self.hass, 'group')
mock_component(self.hass, 'sun')
setup_component(self.hass, sun.DOMAIN, {
sun.DOMAIN: {sun.CONF_ELEVATION: 0}})
self.calls = []
@ -39,10 +40,6 @@ class TestAutomationSun(unittest.TestCase):
def test_sunset_trigger(self):
"""Test the sunset trigger."""
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
sun.STATE_ATTR_NEXT_SETTING: '2015-09-16T02:00:00Z',
})
now = datetime(2015, 9, 15, 23, tzinfo=dt_util.UTC)
trigger_time = datetime(2015, 9, 16, 2, tzinfo=dt_util.UTC)
@ -78,10 +75,6 @@ class TestAutomationSun(unittest.TestCase):
def test_sunrise_trigger(self):
"""Test the sunrise trigger."""
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
})
now = datetime(2015, 9, 13, 23, tzinfo=dt_util.UTC)
trigger_time = datetime(2015, 9, 16, 14, tzinfo=dt_util.UTC)
@ -105,10 +98,6 @@ class TestAutomationSun(unittest.TestCase):
def test_sunset_trigger_with_offset(self):
"""Test the sunset trigger with offset."""
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
sun.STATE_ATTR_NEXT_SETTING: '2015-09-16T02:00:00Z',
})
now = datetime(2015, 9, 15, 23, tzinfo=dt_util.UTC)
trigger_time = datetime(2015, 9, 16, 2, 30, tzinfo=dt_util.UTC)
@ -139,10 +128,6 @@ class TestAutomationSun(unittest.TestCase):
def test_sunrise_trigger_with_offset(self):
"""Test the runrise trigger with offset."""
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
})
now = datetime(2015, 9, 13, 23, tzinfo=dt_util.UTC)
trigger_time = datetime(2015, 9, 16, 13, 30, tzinfo=dt_util.UTC)
@ -167,10 +152,6 @@ class TestAutomationSun(unittest.TestCase):
def test_if_action_before(self):
"""Test if action was before."""
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
})
setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
@ -188,14 +169,14 @@ class TestAutomationSun(unittest.TestCase):
})
now = datetime(2015, 9, 16, 15, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.now',
with patch('homeassistant.util.dt.utcnow',
return_value=now):
self.hass.bus.fire('test_event')
self.hass.block_till_done()
self.assertEqual(0, len(self.calls))
now = datetime(2015, 9, 16, 10, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.now',
with patch('homeassistant.util.dt.utcnow',
return_value=now):
self.hass.bus.fire('test_event')
self.hass.block_till_done()
@ -203,10 +184,6 @@ class TestAutomationSun(unittest.TestCase):
def test_if_action_after(self):
"""Test if action was after."""
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
})
setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
@ -224,14 +201,14 @@ class TestAutomationSun(unittest.TestCase):
})
now = datetime(2015, 9, 16, 13, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.now',
with patch('homeassistant.util.dt.utcnow',
return_value=now):
self.hass.bus.fire('test_event')
self.hass.block_till_done()
self.assertEqual(0, len(self.calls))
now = datetime(2015, 9, 16, 15, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.now',
with patch('homeassistant.util.dt.utcnow',
return_value=now):
self.hass.bus.fire('test_event')
self.hass.block_till_done()
@ -239,10 +216,6 @@ class TestAutomationSun(unittest.TestCase):
def test_if_action_before_with_offset(self):
"""Test if action was before offset."""
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
})
setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
@ -260,15 +233,15 @@ class TestAutomationSun(unittest.TestCase):
}
})
now = datetime(2015, 9, 16, 15, 1, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.now',
now = datetime(2015, 9, 16, 14, 32, 44, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.utcnow',
return_value=now):
self.hass.bus.fire('test_event')
self.hass.block_till_done()
self.assertEqual(0, len(self.calls))
now = datetime(2015, 9, 16, 15, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.now',
now = datetime(2015, 9, 16, 14, 32, 43, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.utcnow',
return_value=now):
self.hass.bus.fire('test_event')
self.hass.block_till_done()
@ -276,10 +249,6 @@ class TestAutomationSun(unittest.TestCase):
def test_if_action_after_with_offset(self):
"""Test if action was after offset."""
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
})
setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
@ -297,15 +266,15 @@ class TestAutomationSun(unittest.TestCase):
}
})
now = datetime(2015, 9, 16, 14, 59, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.now',
now = datetime(2015, 9, 16, 14, 32, 42, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.utcnow',
return_value=now):
self.hass.bus.fire('test_event')
self.hass.block_till_done()
self.assertEqual(0, len(self.calls))
now = datetime(2015, 9, 16, 15, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.now',
now = datetime(2015, 9, 16, 14, 32, 43, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.utcnow',
return_value=now):
self.hass.bus.fire('test_event')
self.hass.block_till_done()
@ -313,11 +282,6 @@ class TestAutomationSun(unittest.TestCase):
def test_if_action_before_and_after_during(self):
"""Test if action was before and after during."""
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T10:00:00Z',
sun.STATE_ATTR_NEXT_SETTING: '2015-09-16T15:00:00Z',
})
setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
@ -335,62 +299,22 @@ class TestAutomationSun(unittest.TestCase):
}
})
now = datetime(2015, 9, 16, 9, 59, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.now',
now = datetime(2015, 9, 16, 13, 8, 51, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.utcnow',
return_value=now):
self.hass.bus.fire('test_event')
self.hass.block_till_done()
self.assertEqual(0, len(self.calls))
now = datetime(2015, 9, 16, 15, 1, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.now',
now = datetime(2015, 9, 17, 2, 25, 18, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.utcnow',
return_value=now):
self.hass.bus.fire('test_event')
self.hass.block_till_done()
self.assertEqual(0, len(self.calls))
now = datetime(2015, 9, 16, 12, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.now',
return_value=now):
self.hass.bus.fire('test_event')
self.hass.block_till_done()
self.assertEqual(1, len(self.calls))
def test_if_action_after_different_tz(self):
"""Test if action was after in a different timezone."""
import pytz
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON, {
sun.STATE_ATTR_NEXT_SETTING: '2015-09-16T17:30:00Z',
})
setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: {
'trigger': {
'platform': 'event',
'event_type': 'test_event',
},
'condition': {
'condition': 'sun',
'after': 'sunset',
},
'action': {
'service': 'test.automation'
}
}
})
# Before
now = datetime(2015, 9, 16, 17, tzinfo=pytz.timezone('US/Mountain'))
with patch('homeassistant.util.dt.now',
return_value=now):
self.hass.bus.fire('test_event')
self.hass.block_till_done()
self.assertEqual(0, len(self.calls))
# After
now = datetime(2015, 9, 16, 18, tzinfo=pytz.timezone('US/Mountain'))
with patch('homeassistant.util.dt.now',
now = datetime(2015, 9, 16, 16, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.utcnow',
return_value=now):
self.hass.bus.fire('test_event')
self.hass.block_till_done()

View File

@ -1,5 +1,4 @@
"""The tests for the Flux switch platform."""
from datetime import timedelta
import unittest
from unittest.mock import patch
@ -86,28 +85,30 @@ class TestSwitchFlux(unittest.TestCase):
self.assertIsNone(state.attributes.get('xy_color'))
self.assertIsNone(state.attributes.get('brightness'))
test_time = dt_util.now().replace(hour=10, minute=30,
second=0)
sunset_time = test_time.replace(hour=17, minute=0,
second=0)
sunrise_time = test_time.replace(hour=5, minute=0,
second=0) + timedelta(days=1)
test_time = dt_util.now().replace(hour=10, minute=30, second=0)
sunset_time = test_time.replace(hour=17, minute=0, second=0)
sunrise_time = test_time.replace(hour=5, minute=0, second=0)
def event_date(hass, event, now=None):
if event == 'sunrise':
return sunrise_time
else:
return sunset_time
with patch('homeassistant.util.dt.now', return_value=test_time):
with patch('homeassistant.components.sun.next_rising',
return_value=sunrise_time):
with patch('homeassistant.components.sun.next_setting',
return_value=sunset_time):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id]
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
with patch('homeassistant.helpers.sun.get_astral_event_date',
side_effect=event_date):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id]
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
self.assertEqual(0, len(turn_on_calls))
def test_flux_before_sunrise(self):
@ -126,30 +127,32 @@ class TestSwitchFlux(unittest.TestCase):
self.assertIsNone(state.attributes.get('xy_color'))
self.assertIsNone(state.attributes.get('brightness'))
test_time = dt_util.now().replace(hour=2, minute=30,
second=0)
sunset_time = test_time.replace(hour=17, minute=0,
second=0)
sunrise_time = test_time.replace(hour=5, minute=0,
second=0) + timedelta(days=1)
test_time = dt_util.now().replace(hour=2, minute=30, second=0)
sunset_time = test_time.replace(hour=17, minute=0, second=0)
sunrise_time = test_time.replace(hour=5, minute=0, second=0)
def event_date(hass, event, now=None):
if event == 'sunrise':
return sunrise_time
else:
return sunset_time
with patch('homeassistant.util.dt.now', return_value=test_time):
with patch('homeassistant.components.sun.next_rising',
return_value=sunrise_time):
with patch('homeassistant.components.sun.next_setting',
return_value=sunset_time):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id]
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
with patch('homeassistant.helpers.sun.get_astral_event_date',
side_effect=event_date):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id]
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
call = turn_on_calls[-1]
self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 119)
self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.591, 0.395])
@ -173,28 +176,30 @@ class TestSwitchFlux(unittest.TestCase):
test_time = dt_util.now().replace(hour=8, minute=30, second=0)
sunset_time = test_time.replace(hour=17, minute=0, second=0)
sunrise_time = test_time.replace(hour=5,
minute=0,
second=0) + timedelta(days=1)
sunrise_time = test_time.replace(hour=5, minute=0, second=0)
def event_date(hass, event, now=None):
if event == 'sunrise':
return sunrise_time
else:
return sunset_time
with patch('homeassistant.util.dt.now', return_value=test_time):
with patch('homeassistant.components.sun.next_rising',
return_value=sunrise_time):
with patch('homeassistant.components.sun.next_setting',
return_value=sunset_time):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id]
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
with patch('homeassistant.helpers.sun.get_astral_event_date',
side_effect=event_date):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id]
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
call = turn_on_calls[-1]
self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 180)
self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.431, 0.38])
@ -218,28 +223,30 @@ class TestSwitchFlux(unittest.TestCase):
test_time = dt_util.now().replace(hour=17, minute=30, second=0)
sunset_time = test_time.replace(hour=17, minute=0, second=0)
sunrise_time = test_time.replace(hour=5,
minute=0,
second=0) + timedelta(days=1)
sunrise_time = test_time.replace(hour=5, minute=0, second=0)
def event_date(hass, event, now=None):
if event == 'sunrise':
return sunrise_time
else:
return sunset_time
with patch('homeassistant.util.dt.now', return_value=test_time):
with patch('homeassistant.components.sun.next_rising',
return_value=sunrise_time):
with patch('homeassistant.components.sun.next_setting',
return_value=sunset_time):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id]
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
with patch('homeassistant.helpers.sun.get_astral_event_date',
side_effect=event_date):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id]
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
call = turn_on_calls[-1]
self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 153)
self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.496, 0.397])
@ -263,28 +270,30 @@ class TestSwitchFlux(unittest.TestCase):
test_time = dt_util.now().replace(hour=23, minute=30, second=0)
sunset_time = test_time.replace(hour=17, minute=0, second=0)
sunrise_time = test_time.replace(hour=5,
minute=0,
second=0) + timedelta(days=1)
sunrise_time = test_time.replace(hour=5, minute=0, second=0)
def event_date(hass, event, now=None):
if event == 'sunrise':
return sunrise_time
else:
return sunset_time
with patch('homeassistant.util.dt.now', return_value=test_time):
with patch('homeassistant.components.sun.next_rising',
return_value=sunrise_time):
with patch('homeassistant.components.sun.next_setting',
return_value=sunset_time):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id]
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
with patch('homeassistant.helpers.sun.get_astral_event_date',
side_effect=event_date):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id]
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
call = turn_on_calls[-1]
self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 119)
self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.591, 0.395])
@ -308,30 +317,32 @@ class TestSwitchFlux(unittest.TestCase):
test_time = dt_util.now().replace(hour=17, minute=30, second=0)
sunset_time = test_time.replace(hour=17, minute=0, second=0)
sunrise_time = test_time.replace(hour=5,
minute=0,
second=0) + timedelta(days=1)
sunrise_time = test_time.replace(hour=5, minute=0, second=0)
def event_date(hass, event, now=None):
if event == 'sunrise':
return sunrise_time
else:
return sunset_time
with patch('homeassistant.util.dt.now', return_value=test_time):
with patch('homeassistant.components.sun.next_rising',
return_value=sunrise_time):
with patch('homeassistant.components.sun.next_setting',
return_value=sunset_time):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id],
'start_time': '6:00',
'stop_time': '23:30'
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
with patch('homeassistant.helpers.sun.get_astral_event_date',
side_effect=event_date):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id],
'start_time': '6:00',
'stop_time': '23:30'
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
call = turn_on_calls[-1]
self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 154)
self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.494, 0.397])
@ -355,30 +366,32 @@ class TestSwitchFlux(unittest.TestCase):
test_time = dt_util.now().replace(hour=17, minute=30, second=0)
sunset_time = test_time.replace(hour=17, minute=0, second=0)
sunrise_time = test_time.replace(hour=5,
minute=0,
second=0) + timedelta(days=1)
sunrise_time = test_time.replace(hour=5, minute=0, second=0)
def event_date(hass, event, now=None):
if event == 'sunrise':
return sunrise_time
else:
return sunset_time
with patch('homeassistant.util.dt.now', return_value=test_time):
with patch('homeassistant.components.sun.next_rising',
return_value=sunrise_time):
with patch('homeassistant.components.sun.next_setting',
return_value=sunset_time):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id],
'start_colortemp': '1000',
'stop_colortemp': '6000'
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
with patch('homeassistant.helpers.sun.get_astral_event_date',
side_effect=event_date):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id],
'start_colortemp': '1000',
'stop_colortemp': '6000'
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
call = turn_on_calls[-1]
self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 167)
self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.461, 0.389])
@ -402,29 +415,31 @@ class TestSwitchFlux(unittest.TestCase):
test_time = dt_util.now().replace(hour=17, minute=30, second=0)
sunset_time = test_time.replace(hour=17, minute=0, second=0)
sunrise_time = test_time.replace(hour=5,
minute=0,
second=0) + timedelta(days=1)
sunrise_time = test_time.replace(hour=5, minute=0, second=0)
def event_date(hass, event, now=None):
if event == 'sunrise':
return sunrise_time
else:
return sunset_time
with patch('homeassistant.util.dt.now', return_value=test_time):
with patch('homeassistant.components.sun.next_rising',
return_value=sunrise_time):
with patch('homeassistant.components.sun.next_setting',
return_value=sunset_time):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id],
'brightness': 255
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
with patch('homeassistant.helpers.sun.get_astral_event_date',
side_effect=event_date):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id],
'brightness': 255
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
call = turn_on_calls[-1]
self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 255)
self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.496, 0.397])
@ -460,30 +475,34 @@ class TestSwitchFlux(unittest.TestCase):
test_time = dt_util.now().replace(hour=12, minute=0, second=0)
sunset_time = test_time.replace(hour=17, minute=0, second=0)
sunrise_time = test_time.replace(hour=5,
minute=0,
second=0) + timedelta(days=1)
sunrise_time = test_time.replace(hour=5, minute=0, second=0)
def event_date(hass, event, now=None):
if event == 'sunrise':
print('sunrise {}'.format(sunrise_time))
return sunrise_time
else:
print('sunset {}'.format(sunset_time))
return sunset_time
with patch('homeassistant.util.dt.now', return_value=test_time):
with patch('homeassistant.components.sun.next_rising',
return_value=sunrise_time):
with patch('homeassistant.components.sun.next_setting',
return_value=sunset_time):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id,
dev2.entity_id,
dev3.entity_id]
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
with patch('homeassistant.helpers.sun.get_astral_event_date',
side_effect=event_date):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id,
dev2.entity_id,
dev3.entity_id]
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
call = turn_on_calls[-1]
self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 171)
self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.452, 0.386])
@ -511,28 +530,30 @@ class TestSwitchFlux(unittest.TestCase):
test_time = dt_util.now().replace(hour=8, minute=30, second=0)
sunset_time = test_time.replace(hour=17, minute=0, second=0)
sunrise_time = test_time.replace(hour=5,
minute=0,
second=0) + timedelta(days=1)
sunrise_time = test_time.replace(hour=5, minute=0, second=0)
def event_date(hass, event, now=None):
if event == 'sunrise':
return sunrise_time
else:
return sunset_time
with patch('homeassistant.util.dt.now', return_value=test_time):
with patch('homeassistant.components.sun.next_rising',
return_value=sunrise_time):
with patch('homeassistant.components.sun.next_setting',
return_value=sunset_time):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id],
'mode': 'mired'
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
with patch('homeassistant.helpers.sun.get_astral_event_date',
side_effect=event_date):
assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: {
'platform': 'flux',
'name': 'flux',
'lights': [dev1.entity_id],
'mode': 'mired'
}
})
turn_on_calls = mock_service(
self.hass, light.DOMAIN, SERVICE_TURN_ON)
switch.turn_on(self.hass, 'switch.flux')
self.hass.block_till_done()
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
call = turn_on_calls[-1]
self.assertEqual(call.data[light.ATTR_COLOR_TEMP], 269)

View File

@ -1,17 +1,19 @@
"""The tests device sun light trigger component."""
# pylint: disable=protected-access
from datetime import datetime
import os
import unittest
from unittest.mock import patch
from homeassistant.setup import setup_component
import homeassistant.loader as loader
from homeassistant.const import CONF_PLATFORM, STATE_HOME, STATE_NOT_HOME
from homeassistant.components import (
device_tracker, light, sun, device_sun_light_trigger)
device_tracker, light, device_sun_light_trigger)
from homeassistant.util import dt as dt_util
from tests.common import (
get_test_config_dir, get_test_home_assistant, ensure_sun_risen,
ensure_sun_set)
get_test_config_dir, get_test_home_assistant, fire_time_changed)
KNOWN_DEV_YAML_PATH = os.path.join(get_test_config_dir(),
@ -61,26 +63,26 @@ class TestDeviceSunLightTrigger(unittest.TestCase):
light.DOMAIN: {CONF_PLATFORM: 'test'}
}))
self.assertTrue(setup_component(self.hass, sun.DOMAIN, {
sun.DOMAIN: {sun.CONF_ELEVATION: 0}}))
def tearDown(self): # pylint: disable=invalid-name
"""Stop everything that was started."""
self.hass.stop()
def test_lights_on_when_sun_sets(self):
"""Test lights go on when there is someone home and the sun sets."""
self.assertTrue(setup_component(
self.hass, device_sun_light_trigger.DOMAIN, {
device_sun_light_trigger.DOMAIN: {}}))
test_time = datetime(2017, 4, 5, 1, 2, 3, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.utcnow', return_value=test_time):
self.assertTrue(setup_component(
self.hass, device_sun_light_trigger.DOMAIN, {
device_sun_light_trigger.DOMAIN: {}}))
ensure_sun_risen(self.hass)
light.turn_off(self.hass)
self.hass.block_till_done()
ensure_sun_set(self.hass)
self.hass.block_till_done()
test_time = test_time.replace(hour=3)
with patch('homeassistant.util.dt.utcnow', return_value=test_time):
fire_time_changed(self.hass, test_time)
self.hass.block_till_done()
self.assertTrue(light.is_on(self.hass))
@ -105,17 +107,17 @@ class TestDeviceSunLightTrigger(unittest.TestCase):
def test_lights_turn_on_when_coming_home_after_sun_set(self): \
# pylint: disable=invalid-name
"""Test lights turn on when coming home after sun set."""
light.turn_off(self.hass)
ensure_sun_set(self.hass)
test_time = datetime(2017, 4, 5, 3, 2, 3, tzinfo=dt_util.UTC)
with patch('homeassistant.util.dt.utcnow', return_value=test_time):
light.turn_off(self.hass)
self.hass.block_till_done()
self.hass.block_till_done()
self.assertTrue(setup_component(
self.hass, device_sun_light_trigger.DOMAIN, {
device_sun_light_trigger.DOMAIN: {}}))
self.assertTrue(setup_component(
self.hass, device_sun_light_trigger.DOMAIN, {
device_sun_light_trigger.DOMAIN: {}}))
self.hass.states.set(
device_tracker.ENTITY_ID_FORMAT.format('device_2'), STATE_HOME)
self.hass.states.set(
device_tracker.ENTITY_ID_FORMAT.format('device_2'), STATE_HOME)
self.hass.block_till_done()
self.hass.block_till_done()
self.assertTrue(light.is_on(self.hass))

View File

@ -24,118 +24,111 @@ class TestSun(unittest.TestCase):
"""Stop everything that was started."""
self.hass.stop()
def test_is_on(self):
"""Test is_on method."""
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON)
self.assertTrue(sun.is_on(self.hass))
self.hass.states.set(sun.ENTITY_ID, sun.STATE_BELOW_HORIZON)
self.assertFalse(sun.is_on(self.hass))
def test_setting_rising(self):
"""Test retrieving sun setting and rising."""
setup_component(self.hass, sun.DOMAIN, {
sun.DOMAIN: {sun.CONF_ELEVATION: 0}})
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
with patch('homeassistant.helpers.condition.dt_util.utcnow',
return_value=utc_now):
setup_component(self.hass, sun.DOMAIN, {
sun.DOMAIN: {sun.CONF_ELEVATION: 0}})
self.hass.block_till_done()
state = self.hass.states.get(sun.ENTITY_ID)
from astral import Astral
astral = Astral()
utc_now = dt_util.utcnow()
utc_today = utc_now.date()
latitude = self.hass.config.latitude
longitude = self.hass.config.longitude
mod = -1
while True:
next_dawn = (astral.dawn_utc(utc_now +
timedelta(days=mod), latitude, longitude))
next_dawn = (astral.dawn_utc(
utc_today + timedelta(days=mod), latitude, longitude))
if next_dawn > utc_now:
break
mod += 1
mod = -1
while True:
next_dusk = (astral.dusk_utc(utc_now +
timedelta(days=mod), latitude, longitude))
next_dusk = (astral.dusk_utc(
utc_today + timedelta(days=mod), latitude, longitude))
if next_dusk > utc_now:
break
mod += 1
mod = -1
while True:
next_midnight = (astral.solar_midnight_utc(utc_now +
timedelta(days=mod), longitude))
next_midnight = (astral.solar_midnight_utc(
utc_today + timedelta(days=mod), longitude))
if next_midnight > utc_now:
break
mod += 1
mod = -1
while True:
next_noon = (astral.solar_noon_utc(utc_now +
timedelta(days=mod), longitude))
next_noon = (astral.solar_noon_utc(
utc_today + timedelta(days=mod), longitude))
if next_noon > utc_now:
break
mod += 1
mod = -1
while True:
next_rising = (astral.sunrise_utc(utc_now +
timedelta(days=mod), latitude, longitude))
next_rising = (astral.sunrise_utc(
utc_today + timedelta(days=mod), latitude, longitude))
if next_rising > utc_now:
break
mod += 1
mod = -1
while True:
next_setting = (astral.sunset_utc(utc_now +
timedelta(days=mod), latitude, longitude))
next_setting = (astral.sunset_utc(
utc_today + timedelta(days=mod), latitude, longitude))
if next_setting > utc_now:
break
mod += 1
self.assertEqual(next_dawn, sun.next_dawn_utc(self.hass))
self.assertEqual(next_dusk, sun.next_dusk_utc(self.hass))
self.assertEqual(next_midnight, sun.next_midnight_utc(self.hass))
self.assertEqual(next_noon, sun.next_noon_utc(self.hass))
self.assertEqual(next_rising, sun.next_rising_utc(self.hass))
self.assertEqual(next_setting, sun.next_setting_utc(self.hass))
# Point it at a state without the proper attributes
self.hass.states.set(sun.ENTITY_ID, sun.STATE_ABOVE_HORIZON)
self.assertIsNone(sun.next_dawn(self.hass))
self.assertIsNone(sun.next_dusk(self.hass))
self.assertIsNone(sun.next_midnight(self.hass))
self.assertIsNone(sun.next_noon(self.hass))
self.assertIsNone(sun.next_rising(self.hass))
self.assertIsNone(sun.next_setting(self.hass))
# Point it at a non-existing state
self.assertIsNone(sun.next_dawn(self.hass, 'non.existing'))
self.assertIsNone(sun.next_dusk(self.hass, 'non.existing'))
self.assertIsNone(sun.next_midnight(self.hass, 'non.existing'))
self.assertIsNone(sun.next_noon(self.hass, 'non.existing'))
self.assertIsNone(sun.next_rising(self.hass, 'non.existing'))
self.assertIsNone(sun.next_setting(self.hass, 'non.existing'))
self.assertEqual(next_dawn, dt_util.parse_datetime(
state.attributes[sun.STATE_ATTR_NEXT_DAWN]))
self.assertEqual(next_dusk, dt_util.parse_datetime(
state.attributes[sun.STATE_ATTR_NEXT_DUSK]))
self.assertEqual(next_midnight, dt_util.parse_datetime(
state.attributes[sun.STATE_ATTR_NEXT_MIDNIGHT]))
self.assertEqual(next_noon, dt_util.parse_datetime(
state.attributes[sun.STATE_ATTR_NEXT_NOON]))
self.assertEqual(next_rising, dt_util.parse_datetime(
state.attributes[sun.STATE_ATTR_NEXT_RISING]))
self.assertEqual(next_setting, dt_util.parse_datetime(
state.attributes[sun.STATE_ATTR_NEXT_SETTING]))
def test_state_change(self):
"""Test if the state changes at next setting/rising."""
setup_component(self.hass, sun.DOMAIN, {
sun.DOMAIN: {sun.CONF_ELEVATION: 0}})
now = datetime(2016, 6, 1, 8, 0, 0, tzinfo=dt_util.UTC)
with patch('homeassistant.helpers.condition.dt_util.utcnow',
return_value=now):
setup_component(self.hass, sun.DOMAIN, {
sun.DOMAIN: {sun.CONF_ELEVATION: 0}})
if sun.is_on(self.hass):
test_state = sun.STATE_BELOW_HORIZON
test_time = sun.next_setting(self.hass)
else:
test_state = sun.STATE_ABOVE_HORIZON
test_time = sun.next_rising(self.hass)
self.hass.block_till_done()
test_time = dt_util.parse_datetime(
self.hass.states.get(sun.ENTITY_ID)
.attributes[sun.STATE_ATTR_NEXT_RISING])
self.assertIsNotNone(test_time)
self.assertEqual(sun.STATE_BELOW_HORIZON,
self.hass.states.get(sun.ENTITY_ID).state)
self.hass.bus.fire(ha.EVENT_TIME_CHANGED,
{ha.ATTR_NOW: test_time + timedelta(seconds=5)})
self.hass.block_till_done()
self.assertEqual(test_state, self.hass.states.get(sun.ENTITY_ID).state)
self.assertEqual(sun.STATE_ABOVE_HORIZON,
self.hass.states.get(sun.ENTITY_ID).state)
def test_norway_in_june(self):
"""Test location in Norway where the sun doesn't set in summer."""
@ -150,9 +143,11 @@ class TestSun(unittest.TestCase):
sun.DOMAIN: {sun.CONF_ELEVATION: 0}})
state = self.hass.states.get(sun.ENTITY_ID)
assert state is not None
assert sun.next_rising_utc(self.hass) == \
assert dt_util.parse_datetime(
state.attributes[sun.STATE_ATTR_NEXT_RISING]) == \
datetime(2016, 7, 25, 23, 23, 39, tzinfo=dt_util.UTC)
assert sun.next_setting_utc(self.hass) == \
assert dt_util.parse_datetime(
state.attributes[sun.STATE_ATTR_NEXT_SETTING]) == \
datetime(2016, 7, 26, 22, 19, 1, tzinfo=dt_util.UTC)

View File

@ -25,6 +25,7 @@ from homeassistant.components import sun
import homeassistant.util.dt as dt_util
from tests.common import get_test_home_assistant
from unittest.mock import patch
class TestEventHelpers(unittest.TestCase):
@ -302,24 +303,27 @@ class TestEventHelpers(unittest.TestCase):
# Get next sunrise/sunset
astral = Astral()
utc_now = dt_util.utcnow()
utc_now = datetime(2014, 5, 24, 12, 0, 0, tzinfo=dt_util.UTC)
utc_today = utc_now.date()
mod = -1
while True:
next_rising = (astral.sunrise_utc(utc_now +
timedelta(days=mod), latitude, longitude))
next_rising = (astral.sunrise_utc(
utc_today + timedelta(days=mod), latitude, longitude))
if next_rising > utc_now:
break
mod += 1
# Track sunrise
runs = []
unsub = track_sunrise(self.hass, lambda: runs.append(1))
with patch('homeassistant.util.dt.utcnow', return_value=utc_now):
unsub = track_sunrise(self.hass, lambda: runs.append(1))
offset_runs = []
offset = timedelta(minutes=30)
unsub2 = track_sunrise(self.hass, lambda: offset_runs.append(1),
offset)
with patch('homeassistant.util.dt.utcnow', return_value=utc_now):
unsub2 = track_sunrise(self.hass, lambda: offset_runs.append(1),
offset)
# run tests
self._send_time_changed(next_rising - offset)
@ -334,7 +338,7 @@ class TestEventHelpers(unittest.TestCase):
self._send_time_changed(next_rising + offset)
self.hass.block_till_done()
self.assertEqual(2, len(runs))
self.assertEqual(1, len(runs))
self.assertEqual(1, len(offset_runs))
unsub()
@ -342,7 +346,7 @@ class TestEventHelpers(unittest.TestCase):
self._send_time_changed(next_rising + offset)
self.hass.block_till_done()
self.assertEqual(2, len(runs))
self.assertEqual(1, len(runs))
self.assertEqual(1, len(offset_runs))
def test_track_sunset(self):
@ -358,23 +362,27 @@ class TestEventHelpers(unittest.TestCase):
# Get next sunrise/sunset
astral = Astral()
utc_now = dt_util.utcnow()
utc_now = datetime(2014, 5, 24, 12, 0, 0, tzinfo=dt_util.UTC)
utc_today = utc_now.date()
mod = -1
while True:
next_setting = (astral.sunset_utc(utc_now +
timedelta(days=mod), latitude, longitude))
next_setting = (astral.sunset_utc(
utc_today + timedelta(days=mod), latitude, longitude))
if next_setting > utc_now:
break
mod += 1
# Track sunset
runs = []
unsub = track_sunset(self.hass, lambda: runs.append(1))
with patch('homeassistant.util.dt.utcnow', return_value=utc_now):
unsub = track_sunset(self.hass, lambda: runs.append(1))
offset_runs = []
offset = timedelta(minutes=30)
unsub2 = track_sunset(self.hass, lambda: offset_runs.append(1), offset)
with patch('homeassistant.util.dt.utcnow', return_value=utc_now):
unsub2 = track_sunset(
self.hass, lambda: offset_runs.append(1), offset)
# Run tests
self._send_time_changed(next_setting - offset)
@ -389,7 +397,7 @@ class TestEventHelpers(unittest.TestCase):
self._send_time_changed(next_setting + offset)
self.hass.block_till_done()
self.assertEqual(2, len(runs))
self.assertEqual(1, len(runs))
self.assertEqual(1, len(offset_runs))
unsub()
@ -397,7 +405,7 @@ class TestEventHelpers(unittest.TestCase):
self._send_time_changed(next_setting + offset)
self.hass.block_till_done()
self.assertEqual(2, len(runs))
self.assertEqual(1, len(runs))
self.assertEqual(1, len(offset_runs))
def _send_time_changed(self, now):

227
tests/helpers/test_sun.py Normal file
View File

@ -0,0 +1,227 @@
"""The tests for the Sun helpers."""
# pylint: disable=protected-access
import unittest
from unittest.mock import patch
from datetime import timedelta, datetime
import homeassistant.util.dt as dt_util
import homeassistant.helpers.sun as sun
from tests.common import get_test_home_assistant
# pylint: disable=invalid-name
class TestSun(unittest.TestCase):
"""Test the sun helpers."""
def setUp(self):
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
def tearDown(self):
"""Stop everything that was started."""
self.hass.stop()
def test_next_events(self):
"""Test retrieving next sun events."""
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
from astral import Astral
astral = Astral()
utc_today = utc_now.date()
latitude = self.hass.config.latitude
longitude = self.hass.config.longitude
mod = -1
while True:
next_dawn = (astral.dawn_utc(
utc_today + timedelta(days=mod), latitude, longitude))
if next_dawn > utc_now:
break
mod += 1
mod = -1
while True:
next_dusk = (astral.dusk_utc(
utc_today + timedelta(days=mod), latitude, longitude))
if next_dusk > utc_now:
break
mod += 1
mod = -1
while True:
next_midnight = (astral.solar_midnight_utc(
utc_today + timedelta(days=mod), longitude))
if next_midnight > utc_now:
break
mod += 1
mod = -1
while True:
next_noon = (astral.solar_noon_utc(
utc_today + timedelta(days=mod), longitude))
if next_noon > utc_now:
break
mod += 1
mod = -1
while True:
next_rising = (astral.sunrise_utc(
utc_today + timedelta(days=mod), latitude, longitude))
if next_rising > utc_now:
break
mod += 1
mod = -1
while True:
next_setting = (astral.sunset_utc(
utc_today + timedelta(days=mod), latitude, longitude))
if next_setting > utc_now:
break
mod += 1
with patch('homeassistant.helpers.condition.dt_util.utcnow',
return_value=utc_now):
self.assertEqual(next_dawn, sun.get_astral_event_next(
self.hass, 'dawn'))
self.assertEqual(next_dusk, sun.get_astral_event_next(
self.hass, 'dusk'))
self.assertEqual(next_midnight, sun.get_astral_event_next(
self.hass, 'solar_midnight'))
self.assertEqual(next_noon, sun.get_astral_event_next(
self.hass, 'solar_noon'))
self.assertEqual(next_rising, sun.get_astral_event_next(
self.hass, 'sunrise'))
self.assertEqual(next_setting, sun.get_astral_event_next(
self.hass, 'sunset'))
def test_date_events(self):
"""Test retrieving next sun events."""
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
from astral import Astral
astral = Astral()
utc_today = utc_now.date()
latitude = self.hass.config.latitude
longitude = self.hass.config.longitude
dawn = astral.dawn_utc(utc_today, latitude, longitude)
dusk = astral.dusk_utc(utc_today, latitude, longitude)
midnight = astral.solar_midnight_utc(utc_today, longitude)
noon = astral.solar_noon_utc(utc_today, longitude)
sunrise = astral.sunrise_utc(utc_today, latitude, longitude)
sunset = astral.sunset_utc(utc_today, latitude, longitude)
self.assertEqual(dawn, sun.get_astral_event_date(
self.hass, 'dawn', utc_today))
self.assertEqual(dusk, sun.get_astral_event_date(
self.hass, 'dusk', utc_today))
self.assertEqual(midnight, sun.get_astral_event_date(
self.hass, 'solar_midnight', utc_today))
self.assertEqual(noon, sun.get_astral_event_date(
self.hass, 'solar_noon', utc_today))
self.assertEqual(sunrise, sun.get_astral_event_date(
self.hass, 'sunrise', utc_today))
self.assertEqual(sunset, sun.get_astral_event_date(
self.hass, 'sunset', utc_today))
def test_date_events_default_date(self):
"""Test retrieving next sun events."""
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
from astral import Astral
astral = Astral()
utc_today = utc_now.date()
latitude = self.hass.config.latitude
longitude = self.hass.config.longitude
dawn = astral.dawn_utc(utc_today, latitude, longitude)
dusk = astral.dusk_utc(utc_today, latitude, longitude)
midnight = astral.solar_midnight_utc(utc_today, longitude)
noon = astral.solar_noon_utc(utc_today, longitude)
sunrise = astral.sunrise_utc(utc_today, latitude, longitude)
sunset = astral.sunset_utc(utc_today, latitude, longitude)
with patch('homeassistant.util.dt.now', return_value=utc_now):
self.assertEqual(dawn, sun.get_astral_event_date(
self.hass, 'dawn', utc_today))
self.assertEqual(dusk, sun.get_astral_event_date(
self.hass, 'dusk', utc_today))
self.assertEqual(midnight, sun.get_astral_event_date(
self.hass, 'solar_midnight', utc_today))
self.assertEqual(noon, sun.get_astral_event_date(
self.hass, 'solar_noon', utc_today))
self.assertEqual(sunrise, sun.get_astral_event_date(
self.hass, 'sunrise', utc_today))
self.assertEqual(sunset, sun.get_astral_event_date(
self.hass, 'sunset', utc_today))
def test_date_events_accepts_datetime(self):
"""Test retrieving next sun events."""
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
from astral import Astral
astral = Astral()
utc_today = utc_now.date()
latitude = self.hass.config.latitude
longitude = self.hass.config.longitude
dawn = astral.dawn_utc(utc_today, latitude, longitude)
dusk = astral.dusk_utc(utc_today, latitude, longitude)
midnight = astral.solar_midnight_utc(utc_today, longitude)
noon = astral.solar_noon_utc(utc_today, longitude)
sunrise = astral.sunrise_utc(utc_today, latitude, longitude)
sunset = astral.sunset_utc(utc_today, latitude, longitude)
self.assertEqual(dawn, sun.get_astral_event_date(
self.hass, 'dawn', utc_now))
self.assertEqual(dusk, sun.get_astral_event_date(
self.hass, 'dusk', utc_now))
self.assertEqual(midnight, sun.get_astral_event_date(
self.hass, 'solar_midnight', utc_now))
self.assertEqual(noon, sun.get_astral_event_date(
self.hass, 'solar_noon', utc_now))
self.assertEqual(sunrise, sun.get_astral_event_date(
self.hass, 'sunrise', utc_now))
self.assertEqual(sunset, sun.get_astral_event_date(
self.hass, 'sunset', utc_now))
def test_is_up(self):
"""Test retrieving next sun events."""
utc_now = datetime(2016, 11, 1, 12, 0, 0, tzinfo=dt_util.UTC)
with patch('homeassistant.helpers.condition.dt_util.utcnow',
return_value=utc_now):
self.assertFalse(sun.is_up(self.hass))
utc_now = datetime(2016, 11, 1, 18, 0, 0, tzinfo=dt_util.UTC)
with patch('homeassistant.helpers.condition.dt_util.utcnow',
return_value=utc_now):
self.assertTrue(sun.is_up(self.hass))
def test_norway_in_june(self):
"""Test location in Norway where the sun doesn't set in summer."""
self.hass.config.latitude = 69.6
self.hass.config.longitude = 18.8
june = datetime(2016, 6, 1, tzinfo=dt_util.UTC)
print(sun.get_astral_event_date(self.hass, 'sunrise',
datetime(2017, 7, 25)))
print(sun.get_astral_event_date(self.hass, 'sunset',
datetime(2017, 7, 25)))
print(sun.get_astral_event_date(self.hass, 'sunrise',
datetime(2017, 7, 26)))
print(sun.get_astral_event_date(self.hass, 'sunset',
datetime(2017, 7, 26)))
assert sun.get_astral_event_next(self.hass, 'sunrise', june) == \
datetime(2016, 7, 25, 23, 23, 39, tzinfo=dt_util.UTC)
assert sun.get_astral_event_next(self.hass, 'sunset', june) == \
datetime(2016, 7, 26, 22, 19, 1, tzinfo=dt_util.UTC)
assert sun.get_astral_event_date(self.hass, 'sunrise', june) is None
assert sun.get_astral_event_date(self.hass, 'sunset', june) is None