Times of The Day Binary Sensor (#20068)
* First commit * Times of the Day binary sensor added * Python 3.5 fixes and logging removed * Code refactored according to reviewer's suggestions * Fixed config template with friendly name support * Finall pep8 fixes * Removed async_generate_entity_id and moved initial calculation to async_added_to_hass * Change the configuration schema to follow the current requirements * Update according latest suggestsion * Fix typos and minor changes * Fix lint issuepull/21094/head
parent
f3786e2f2b
commit
7b19428279
homeassistant/components/binary_sensor
tests/components/binary_sensor
|
@ -0,0 +1,217 @@
|
|||
"""Support for representing current time of the day as binary sensors."""
|
||||
from datetime import datetime, timedelta
|
||||
import logging
|
||||
|
||||
import pytz
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
PLATFORM_SCHEMA, BinarySensorDevice)
|
||||
from homeassistant.const import (
|
||||
CONF_AFTER, CONF_BEFORE, CONF_NAME, SUN_EVENT_SUNRISE, SUN_EVENT_SUNSET)
|
||||
from homeassistant.core import callback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.event import async_track_point_in_utc_time
|
||||
from homeassistant.helpers.sun import (
|
||||
get_astral_event_date, get_astral_event_next)
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTR_AFTER = 'after'
|
||||
ATTR_BEFORE = 'before'
|
||||
ATTR_NEXT_UPDATE = 'next_update'
|
||||
|
||||
CONF_AFTER_OFFSET = 'after_offset'
|
||||
CONF_BEFORE_OFFSET = 'before_offset'
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_AFTER):
|
||||
vol.Any(cv.time, vol.All(vol.Lower, cv.sun_event)),
|
||||
vol.Required(CONF_BEFORE):
|
||||
vol.Any(cv.time, vol.All(vol.Lower, cv.sun_event)),
|
||||
vol.Required(CONF_NAME): cv.string,
|
||||
vol.Optional(CONF_AFTER_OFFSET, default=timedelta(0)): cv.time_period,
|
||||
vol.Optional(CONF_BEFORE_OFFSET, default=timedelta(0)): cv.time_period,
|
||||
})
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the ToD sensors."""
|
||||
if hass.config.time_zone is None:
|
||||
_LOGGER.error("Timezone is not set in Home Assistant configuration")
|
||||
return
|
||||
|
||||
after = config[CONF_AFTER]
|
||||
after_offset = config[CONF_AFTER_OFFSET]
|
||||
before = config[CONF_BEFORE]
|
||||
before_offset = config[CONF_BEFORE_OFFSET]
|
||||
name = config[CONF_NAME]
|
||||
sensor = TodSensor(name, after, after_offset, before, before_offset)
|
||||
|
||||
async_add_entities([sensor])
|
||||
|
||||
|
||||
def is_sun_event(event):
|
||||
"""Return true if event is sun event not time."""
|
||||
return event in (SUN_EVENT_SUNRISE, SUN_EVENT_SUNSET)
|
||||
|
||||
|
||||
class TodSensor(BinarySensorDevice):
|
||||
"""Time of the Day Sensor."""
|
||||
|
||||
def __init__(self, name, after, after_offset, before, before_offset):
|
||||
"""Init the ToD Sensor..."""
|
||||
self._name = name
|
||||
self._time_before = self._time_after = self._next_update = None
|
||||
self._after_offset = after_offset
|
||||
self._before_offset = before_offset
|
||||
self._before = before
|
||||
self._after = after
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Sensor does not need to be polled."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the sensor."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def after(self):
|
||||
"""Return the timestamp for the begining of the period."""
|
||||
return self._time_after
|
||||
|
||||
@property
|
||||
def before(self):
|
||||
"""Return the timestamp for the end of the period."""
|
||||
return self._time_before
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return True is sensor is on."""
|
||||
if self.after < self.before:
|
||||
return self.after <= self.current_datetime < self.before
|
||||
return False
|
||||
|
||||
@property
|
||||
def current_datetime(self):
|
||||
"""Return local current datetime according to hass configuration."""
|
||||
return dt_util.utcnow()
|
||||
|
||||
@property
|
||||
def next_update(self):
|
||||
"""Return the next update point in the UTC time."""
|
||||
return self._next_update
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return the state attributes of the sensor."""
|
||||
return {
|
||||
ATTR_AFTER: self.after.astimezone(
|
||||
self.hass.config.time_zone).isoformat(),
|
||||
ATTR_BEFORE: self.before.astimezone(
|
||||
self.hass.config.time_zone).isoformat(),
|
||||
ATTR_NEXT_UPDATE: self.next_update.astimezone(
|
||||
self.hass.config.time_zone).isoformat(),
|
||||
}
|
||||
|
||||
def _calculate_initial_boudary_time(self):
|
||||
"""Calculate internal absolute time boudaries."""
|
||||
nowutc = self.current_datetime
|
||||
# If after value is a sun event instead of absolute time
|
||||
if is_sun_event(self._after):
|
||||
# Calculate the today's event utc time or
|
||||
# if not available take next
|
||||
after_event_date = \
|
||||
get_astral_event_date(self.hass, self._after, nowutc) or \
|
||||
get_astral_event_next(self.hass, self._after, nowutc)
|
||||
else:
|
||||
# Convert local time provided to UTC today
|
||||
# datetime.combine(date, time, tzinfo) is not supported
|
||||
# in python 3.5. The self._after is provided
|
||||
# with hass configured TZ not system wide
|
||||
after_event_date = datetime.combine(
|
||||
nowutc, self._after.replace(
|
||||
tzinfo=self.hass.config.time_zone)).astimezone(tz=pytz.UTC)
|
||||
|
||||
self._time_after = after_event_date
|
||||
|
||||
# If before value is a sun event instead of absolute time
|
||||
if is_sun_event(self._before):
|
||||
# Calculate the today's event utc time or if not available take
|
||||
# next
|
||||
before_event_date = \
|
||||
get_astral_event_date(self.hass, self._before, nowutc) or \
|
||||
get_astral_event_next(self.hass, self._before, nowutc)
|
||||
# Before is earlier than after
|
||||
if before_event_date < after_event_date:
|
||||
# Take next day for before
|
||||
before_event_date = get_astral_event_next(
|
||||
self.hass, self._before, after_event_date)
|
||||
else:
|
||||
# Convert local time provided to UTC today, see above
|
||||
before_event_date = datetime.combine(
|
||||
nowutc, self._before.replace(
|
||||
tzinfo=self.hass.config.time_zone)).astimezone(tz=pytz.UTC)
|
||||
|
||||
# It is safe to add timedelta days=1 to UTC as there is no DST
|
||||
if before_event_date < after_event_date + self._after_offset:
|
||||
before_event_date += timedelta(days=1)
|
||||
|
||||
self._time_before = before_event_date
|
||||
|
||||
# Add offset to utc boundaries according to the configuration
|
||||
self._time_after += self._after_offset
|
||||
self._time_before += self._before_offset
|
||||
|
||||
def _turn_to_next_day(self):
|
||||
"""Turn to to the next day."""
|
||||
if is_sun_event(self._after):
|
||||
self._time_after = get_astral_event_next(
|
||||
self.hass, self._after,
|
||||
self._time_after - self._after_offset)
|
||||
self._time_after += self._after_offset
|
||||
else:
|
||||
# Offset is already there
|
||||
self._time_after += timedelta(days=1)
|
||||
|
||||
if is_sun_event(self._before):
|
||||
self._time_before = get_astral_event_next(
|
||||
self.hass, self._before,
|
||||
self._time_before - self._before_offset)
|
||||
self._time_before += self._before_offset
|
||||
else:
|
||||
# Offset is already there
|
||||
self._time_before += timedelta(days=1)
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity about to be added to Home Assistant."""
|
||||
await super().async_added_to_hass()
|
||||
self._calculate_initial_boudary_time()
|
||||
self._calculate_next_update()
|
||||
self._point_in_time_listener(dt_util.now())
|
||||
|
||||
def _calculate_next_update(self):
|
||||
"""Datetime when the next update to the state."""
|
||||
now = self.current_datetime
|
||||
if now < self.after:
|
||||
self._next_update = self.after
|
||||
return
|
||||
if now < self.before:
|
||||
self._next_update = self.before
|
||||
return
|
||||
self._turn_to_next_day()
|
||||
self._next_update = self.after
|
||||
|
||||
@callback
|
||||
def _point_in_time_listener(self, now):
|
||||
"""Run when the state of the sensor should be updated."""
|
||||
self._calculate_next_update()
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
async_track_point_in_utc_time(
|
||||
self.hass, self._point_in_time_listener, self.next_update)
|
|
@ -0,0 +1,839 @@
|
|||
"""Test Times of the Day Binary Sensor."""
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
from datetime import timedelta, datetime
|
||||
import pytz
|
||||
|
||||
from homeassistant import setup
|
||||
import homeassistant.core as ha
|
||||
from homeassistant.const import STATE_OFF, STATE_ON
|
||||
import homeassistant.util.dt as dt_util
|
||||
from homeassistant.setup import setup_component
|
||||
from tests.common import (
|
||||
get_test_home_assistant, assert_setup_component)
|
||||
from homeassistant.helpers.sun import (
|
||||
get_astral_event_date, get_astral_event_next)
|
||||
|
||||
|
||||
class TestBinarySensorTod(unittest.TestCase):
|
||||
"""Test for Binary sensor tod platform."""
|
||||
|
||||
hass = None
|
||||
# pylint: disable=invalid-name
|
||||
|
||||
def setup_method(self, method):
|
||||
"""Set up things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.latitute = 50.27583
|
||||
self.hass.config.longitude = 18.98583
|
||||
|
||||
def teardown_method(self, method):
|
||||
"""Stop everything that was started."""
|
||||
self.hass.stop()
|
||||
|
||||
def test_setup(self):
|
||||
"""Test the setup."""
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Early Morning',
|
||||
'after': 'sunrise',
|
||||
'after_offset': '-02:00',
|
||||
'before': '7:00',
|
||||
'before_offset': '1:00'
|
||||
},
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Morning',
|
||||
'after': 'sunrise',
|
||||
'before': '12:00'
|
||||
}
|
||||
],
|
||||
}
|
||||
with assert_setup_component(2):
|
||||
assert setup.setup_component(
|
||||
self.hass, 'binary_sensor', config)
|
||||
|
||||
def test_setup_no_sensors(self):
|
||||
"""Test setup with no sensors."""
|
||||
with assert_setup_component(0):
|
||||
assert setup.setup_component(self.hass, 'binary_sensor', {
|
||||
'binary_sensor': {
|
||||
'platform': 'tod'
|
||||
}
|
||||
})
|
||||
|
||||
def test_in_period_on_start(self):
|
||||
"""Test simple setting."""
|
||||
test_time = datetime(
|
||||
2019, 1, 10, 18, 43, 0, tzinfo=self.hass.config.time_zone)
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Evening',
|
||||
'after': '18:00',
|
||||
'before': '22:00'
|
||||
}
|
||||
]
|
||||
}
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=test_time):
|
||||
setup_component(self.hass, 'binary_sensor', config)
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get('binary_sensor.evening')
|
||||
assert state.state == STATE_ON
|
||||
|
||||
def test_midnight_turnover_before_midnight_inside_period(self):
|
||||
"""Test midnight turnover setting before midnight inside period ."""
|
||||
test_time = datetime(
|
||||
2019, 1, 10, 22, 30, 0, tzinfo=self.hass.config.time_zone)
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Night',
|
||||
'after': '22:00',
|
||||
'before': '5:00'
|
||||
},
|
||||
]
|
||||
}
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=test_time):
|
||||
setup_component(self.hass, 'binary_sensor', config)
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get('binary_sensor.night')
|
||||
assert state.state == STATE_ON
|
||||
|
||||
def test_midnight_turnover_after_midnight_inside_period(self):
|
||||
"""Test midnight turnover setting before midnight inside period ."""
|
||||
test_time = datetime(
|
||||
2019, 1, 10, 21, 00, 0, tzinfo=self.hass.config.time_zone)
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Night',
|
||||
'after': '22:00',
|
||||
'before': '5:00'
|
||||
},
|
||||
]
|
||||
}
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=test_time):
|
||||
setup_component(self.hass, 'binary_sensor', config)
|
||||
|
||||
state = self.hass.states.get('binary_sensor.night')
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=test_time + timedelta(hours=1)):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: test_time + timedelta(hours=1)})
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get('binary_sensor.night')
|
||||
assert state.state == STATE_ON
|
||||
|
||||
def test_midnight_turnover_before_midnight_outside_period(self):
|
||||
"""Test midnight turnover setting before midnight outside period."""
|
||||
test_time = datetime(
|
||||
2019, 1, 10, 20, 30, 0, tzinfo=self.hass.config.time_zone)
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Night',
|
||||
'after': '22:00',
|
||||
'before': '5:00'
|
||||
}
|
||||
]
|
||||
}
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=test_time):
|
||||
setup_component(self.hass, 'binary_sensor', config)
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get('binary_sensor.night')
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
def test_midnight_turnover_after_midnight_outside_period(self):
|
||||
"""Test midnight turnover setting before midnight inside period ."""
|
||||
test_time = datetime(
|
||||
2019, 1, 10, 20, 0, 0, tzinfo=self.hass.config.time_zone)
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Night',
|
||||
'after': '22:00',
|
||||
'before': '5:00'
|
||||
}
|
||||
]
|
||||
}
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=test_time):
|
||||
setup_component(self.hass, 'binary_sensor', config)
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get('binary_sensor.night')
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
switchover_time = datetime(
|
||||
2019, 1, 11, 4, 59, 0, tzinfo=self.hass.config.time_zone)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=switchover_time):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: switchover_time})
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get('binary_sensor.night')
|
||||
assert state.state == STATE_ON
|
||||
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=switchover_time + timedelta(
|
||||
minutes=1, seconds=1)):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: switchover_time + timedelta(
|
||||
minutes=1, seconds=1)})
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get('binary_sensor.night')
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
def test_from_sunrise_to_sunset(self):
|
||||
"""Test period from sunrise to sunset."""
|
||||
test_time = datetime(
|
||||
2019, 1, 12, tzinfo=self.hass.config.time_zone)
|
||||
sunrise = dt_util.as_local(get_astral_event_date(
|
||||
self.hass, 'sunrise', dt_util.as_utc(test_time)))
|
||||
sunset = dt_util.as_local(get_astral_event_date(
|
||||
self.hass, 'sunset', dt_util.as_utc(test_time)))
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Day',
|
||||
'after': 'sunrise',
|
||||
'before': 'sunset'
|
||||
}
|
||||
]
|
||||
}
|
||||
entity_id = 'binary_sensor.day'
|
||||
testtime = sunrise + timedelta(seconds=-1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
setup_component(self.hass, 'binary_sensor', config)
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
testtime = sunrise
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
testtime = sunrise + timedelta(seconds=1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
testtime = sunset + timedelta(seconds=-1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
testtime = sunset
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
testtime = sunset + timedelta(seconds=1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
def test_from_sunset_to_sunrise(self):
|
||||
"""Test period from sunset to sunrise."""
|
||||
test_time = datetime(
|
||||
2019, 1, 12, tzinfo=self.hass.config.time_zone)
|
||||
sunset = dt_util.as_local(get_astral_event_date(
|
||||
self.hass, 'sunset', test_time))
|
||||
sunrise = dt_util.as_local(get_astral_event_next(
|
||||
self.hass, 'sunrise', sunset))
|
||||
# assert sunset == sunrise
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Night',
|
||||
'after': 'sunset',
|
||||
'before': 'sunrise'
|
||||
}
|
||||
]
|
||||
}
|
||||
entity_id = 'binary_sensor.night'
|
||||
testtime = sunset + timedelta(minutes=-1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
setup_component(self.hass, 'binary_sensor', config)
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
testtime = sunset
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
testtime = sunset + timedelta(minutes=1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
testtime = sunrise + timedelta(minutes=-1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
testtime = sunrise
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
self.hass.block_till_done()
|
||||
# assert state == "dupa"
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
testtime = sunrise + timedelta(minutes=1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
def test_offset(self):
|
||||
"""Test offset."""
|
||||
after = datetime(
|
||||
2019, 1, 10, 18, 0, 0,
|
||||
tzinfo=self.hass.config.time_zone) + \
|
||||
timedelta(hours=1, minutes=34)
|
||||
before = datetime(
|
||||
2019, 1, 10, 22, 0, 0,
|
||||
tzinfo=self.hass.config.time_zone) + \
|
||||
timedelta(hours=1, minutes=45)
|
||||
entity_id = 'binary_sensor.evening'
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Evening',
|
||||
'after': '18:00',
|
||||
'after_offset': '1:34',
|
||||
'before': '22:00',
|
||||
'before_offset': '1:45'
|
||||
}
|
||||
]
|
||||
}
|
||||
testtime = after + timedelta(seconds=-1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
setup_component(self.hass, 'binary_sensor', config)
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
testtime = after
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
testtime = before + timedelta(seconds=-1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
testtime = before
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
testtime = before + timedelta(seconds=1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
def test_offset_overnight(self):
|
||||
"""Test offset overnight."""
|
||||
after = datetime(
|
||||
2019, 1, 10, 18, 0, 0,
|
||||
tzinfo=self.hass.config.time_zone) + \
|
||||
timedelta(hours=1, minutes=34)
|
||||
entity_id = 'binary_sensor.evening'
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Evening',
|
||||
'after': '18:00',
|
||||
'after_offset': '1:34',
|
||||
'before': '22:00',
|
||||
'before_offset': '3:00'
|
||||
}
|
||||
]
|
||||
}
|
||||
testtime = after + timedelta(seconds=-1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
setup_component(self.hass, 'binary_sensor', config)
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
testtime = after
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
def test_norwegian_case_winter(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
|
||||
|
||||
test_time = datetime(2010, 1, 1, tzinfo=self.hass.config.time_zone)
|
||||
sunrise = dt_util.as_local(get_astral_event_next(
|
||||
self.hass, 'sunrise', dt_util.as_utc(test_time)))
|
||||
sunset = dt_util.as_local(get_astral_event_next(
|
||||
self.hass, 'sunset', dt_util.as_utc(test_time)))
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Day',
|
||||
'after': 'sunrise',
|
||||
'before': 'sunset'
|
||||
}
|
||||
]
|
||||
}
|
||||
entity_id = 'binary_sensor.day'
|
||||
testtime = test_time
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
setup_component(self.hass, 'binary_sensor', config)
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
testtime = sunrise + timedelta(seconds=-1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
testtime = sunrise
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
testtime = sunrise + timedelta(seconds=1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
testtime = sunset + timedelta(seconds=-1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
testtime = sunset
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
testtime = sunset + timedelta(seconds=1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
def test_norwegian_case_summer(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
|
||||
|
||||
test_time = datetime(2010, 6, 1, tzinfo=self.hass.config.time_zone)
|
||||
sunrise = dt_util.as_local(get_astral_event_next(
|
||||
self.hass, 'sunrise', dt_util.as_utc(test_time)))
|
||||
sunset = dt_util.as_local(get_astral_event_next(
|
||||
self.hass, 'sunset', dt_util.as_utc(test_time)))
|
||||
print(sunrise)
|
||||
print(sunset)
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Day',
|
||||
'after': 'sunrise',
|
||||
'before': 'sunset'
|
||||
}
|
||||
]
|
||||
}
|
||||
entity_id = 'binary_sensor.day'
|
||||
testtime = test_time
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
setup_component(self.hass, 'binary_sensor', config)
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
testtime = sunrise + timedelta(seconds=-1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
testtime = sunrise
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
testtime = sunrise + timedelta(seconds=1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
testtime = sunset + timedelta(seconds=-1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
testtime = sunset
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
testtime = sunset + timedelta(seconds=1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
def test_sun_offset(self):
|
||||
"""Test sun event with offset."""
|
||||
test_time = datetime(
|
||||
2019, 1, 12, tzinfo=self.hass.config.time_zone)
|
||||
sunrise = dt_util.as_local(get_astral_event_date(
|
||||
self.hass, 'sunrise', dt_util.as_utc(test_time)) +
|
||||
timedelta(hours=-1, minutes=-30))
|
||||
sunset = dt_util.as_local(get_astral_event_date(
|
||||
self.hass, 'sunset', dt_util.as_utc(test_time)) +
|
||||
timedelta(hours=1, minutes=30))
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Day',
|
||||
'after': 'sunrise',
|
||||
'after_offset': '-1:30',
|
||||
'before': 'sunset',
|
||||
'before_offset': '1:30'
|
||||
}
|
||||
]
|
||||
}
|
||||
entity_id = 'binary_sensor.day'
|
||||
testtime = sunrise + timedelta(seconds=-1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
setup_component(self.hass, 'binary_sensor', config)
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
testtime = sunrise
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
testtime = sunrise + timedelta(seconds=1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
testtime = sunset + timedelta(seconds=-1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
testtime = sunset
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
testtime = sunset + timedelta(seconds=1)
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
test_time = test_time + timedelta(days=1)
|
||||
sunrise = dt_util.as_local(get_astral_event_date(
|
||||
self.hass, 'sunrise', dt_util.as_utc(test_time)) +
|
||||
timedelta(hours=-1, minutes=-30))
|
||||
testtime = sunrise
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {
|
||||
ha.ATTR_NOW: testtime})
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
def test_dst(self):
|
||||
"""Test sun event with offset."""
|
||||
self.hass.config.time_zone = pytz.timezone('CET')
|
||||
test_time = datetime(
|
||||
2019, 3, 30, 3, 0, 0, tzinfo=self.hass.config.time_zone)
|
||||
config = {
|
||||
'binary_sensor': [
|
||||
{
|
||||
'platform': 'tod',
|
||||
'name': 'Day',
|
||||
'after': '2:30',
|
||||
'before': '2:40'
|
||||
}
|
||||
]
|
||||
}
|
||||
# after 2019-03-30 03:00 CET the next update should ge scheduled
|
||||
# at 3:30 not 2:30 local time
|
||||
# Internally the
|
||||
entity_id = 'binary_sensor.day'
|
||||
testtime = test_time
|
||||
with patch('homeassistant.components.binary_sensor.tod.dt_util.utcnow',
|
||||
return_value=testtime):
|
||||
setup_component(self.hass, 'binary_sensor', config)
|
||||
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get(entity_id)
|
||||
state.attributes['after'] == '2019-03-31T03:30:00+02:00'
|
||||
state.attributes['before'] == '2019-03-31T03:40:00+02:00'
|
||||
state.attributes['next_update'] == '2019-03-31T03:30:00+02:00'
|
||||
assert state.state == STATE_OFF
|
Loading…
Reference in New Issue