Skip to content

Commit

Permalink
Fix loop in tod binary sensor (#51491)
Browse files Browse the repository at this point in the history
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
  • Loading branch information
bdraco and balloob committed Jun 7, 2021
1 parent a383198 commit a3146ad
Show file tree
Hide file tree
Showing 2 changed files with 237 additions and 4 deletions.
22 changes: 21 additions & 1 deletion homeassistant/components/tod/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,26 @@ def _calculate_boudary_time(self):
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."""
self._calculate_boudary_time()
Expand All @@ -182,7 +202,7 @@ def _calculate_next_update(self):
if now < self._time_before:
self._next_update = self._time_before
return
self._calculate_boudary_time()
self._turn_to_next_day()
self._next_update = self._time_after

@callback
Expand Down
219 changes: 216 additions & 3 deletions tests/components/tod/test_binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

from tests.common import assert_setup_component

ORIG_TIMEZONE = dt_util.DEFAULT_TIME_ZONE


@pytest.fixture(autouse=True)
def mock_legacy_time(legacy_patchable_time):
Expand All @@ -26,6 +28,13 @@ def setup_fixture(hass):
hass.config.longitude = 18.98583


@pytest.fixture(autouse=True)
def restore_timezone(hass):
"""Make sure we change timezone."""
yield
dt_util.set_default_time_zone(ORIG_TIMEZONE)


async def test_setup(hass):
"""Test the setup."""
config = {
Expand Down Expand Up @@ -863,6 +872,7 @@ async def test_sun_offset(hass):
async def test_dst(hass):
"""Test sun event with offset."""
hass.config.time_zone = "CET"
dt_util.set_default_time_zone(dt_util.get_time_zone("CET"))
test_time = datetime(2019, 3, 30, 3, 0, 0, tzinfo=dt_util.UTC)
config = {
"binary_sensor": [
Expand All @@ -882,7 +892,210 @@ async def test_dst(hass):

await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.attributes["after"] == "2019-03-30T03:30:00+01:00"
assert state.attributes["before"] == "2019-03-30T03:40:00+01:00"
assert state.attributes["next_update"] == "2019-03-30T03:30:00+01:00"
assert state.attributes["after"] == "2019-03-31T03:30:00+02:00"
assert state.attributes["before"] == "2019-03-31T03:40:00+02:00"
assert state.attributes["next_update"] == "2019-03-31T03:30:00+02:00"
assert state.state == STATE_OFF


async def test_simple_before_after_does_not_loop_utc_not_in_range(hass):
"""Test simple before after."""
hass.config.time_zone = "UTC"
dt_util.set_default_time_zone(dt_util.UTC)
test_time = datetime(2019, 1, 10, 18, 43, 0, tzinfo=dt_util.UTC)
config = {
"binary_sensor": [
{
"platform": "tod",
"name": "Night",
"before": "06:00",
"after": "22:00",
}
]
}
with patch(
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
return_value=test_time,
):
await async_setup_component(hass, "binary_sensor", config)
await hass.async_block_till_done()

state = hass.states.get("binary_sensor.night")
assert state.state == STATE_OFF
assert state.attributes["after"] == "2019-01-10T22:00:00+00:00"
assert state.attributes["before"] == "2019-01-11T06:00:00+00:00"
assert state.attributes["next_update"] == "2019-01-10T22:00:00+00:00"


async def test_simple_before_after_does_not_loop_utc_in_range(hass):
"""Test simple before after."""
hass.config.time_zone = "UTC"
dt_util.set_default_time_zone(dt_util.UTC)
test_time = datetime(2019, 1, 10, 22, 43, 0, tzinfo=dt_util.UTC)
config = {
"binary_sensor": [
{
"platform": "tod",
"name": "Night",
"before": "06:00",
"after": "22:00",
}
]
}
with patch(
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
return_value=test_time,
):
await async_setup_component(hass, "binary_sensor", config)
await hass.async_block_till_done()

state = hass.states.get("binary_sensor.night")
assert state.state == STATE_ON
assert state.attributes["after"] == "2019-01-10T22:00:00+00:00"
assert state.attributes["before"] == "2019-01-11T06:00:00+00:00"
assert state.attributes["next_update"] == "2019-01-11T06:00:00+00:00"


async def test_simple_before_after_does_not_loop_utc_fire_at_before(hass):
"""Test simple before after."""
hass.config.time_zone = "UTC"
dt_util.set_default_time_zone(dt_util.UTC)
test_time = datetime(2019, 1, 11, 6, 0, 0, tzinfo=dt_util.UTC)
config = {
"binary_sensor": [
{
"platform": "tod",
"name": "Night",
"before": "06:00",
"after": "22:00",
}
]
}
with patch(
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
return_value=test_time,
):
await async_setup_component(hass, "binary_sensor", config)
await hass.async_block_till_done()

state = hass.states.get("binary_sensor.night")
assert state.state == STATE_OFF
assert state.attributes["after"] == "2019-01-11T22:00:00+00:00"
assert state.attributes["before"] == "2019-01-12T06:00:00+00:00"
assert state.attributes["next_update"] == "2019-01-11T22:00:00+00:00"


async def test_simple_before_after_does_not_loop_utc_fire_at_after(hass):
"""Test simple before after."""
hass.config.time_zone = "UTC"
dt_util.set_default_time_zone(dt_util.UTC)
test_time = datetime(2019, 1, 10, 22, 0, 0, tzinfo=dt_util.UTC)
config = {
"binary_sensor": [
{
"platform": "tod",
"name": "Night",
"before": "06:00",
"after": "22:00",
}
]
}
with patch(
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
return_value=test_time,
):
await async_setup_component(hass, "binary_sensor", config)
await hass.async_block_till_done()

state = hass.states.get("binary_sensor.night")
assert state.state == STATE_ON
assert state.attributes["after"] == "2019-01-10T22:00:00+00:00"
assert state.attributes["before"] == "2019-01-11T06:00:00+00:00"
assert state.attributes["next_update"] == "2019-01-11T06:00:00+00:00"


async def test_simple_before_after_does_not_loop_utc_both_before_now(hass):
"""Test simple before after."""
hass.config.time_zone = "UTC"
dt_util.set_default_time_zone(dt_util.UTC)
test_time = datetime(2019, 1, 10, 22, 0, 0, tzinfo=dt_util.UTC)
config = {
"binary_sensor": [
{
"platform": "tod",
"name": "Morning",
"before": "08:00",
"after": "00:00",
}
]
}
with patch(
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
return_value=test_time,
):
await async_setup_component(hass, "binary_sensor", config)
await hass.async_block_till_done()

state = hass.states.get("binary_sensor.morning")
assert state.state == STATE_OFF
assert state.attributes["after"] == "2019-01-11T00:00:00+00:00"
assert state.attributes["before"] == "2019-01-11T08:00:00+00:00"
assert state.attributes["next_update"] == "2019-01-11T00:00:00+00:00"


async def test_simple_before_after_does_not_loop_berlin_not_in_range(hass):
"""Test simple before after."""
hass.config.time_zone = "Europe/Berlin"
dt_util.set_default_time_zone(dt_util.get_time_zone("Europe/Berlin"))
test_time = datetime(2019, 1, 10, 18, 43, 0, tzinfo=dt_util.UTC)
config = {
"binary_sensor": [
{
"platform": "tod",
"name": "Dark",
"before": "06:00",
"after": "00:00",
}
]
}
with patch(
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
return_value=test_time,
):
await async_setup_component(hass, "binary_sensor", config)
await hass.async_block_till_done()

state = hass.states.get("binary_sensor.dark")
assert state.state == STATE_OFF
assert state.attributes["after"] == "2019-01-11T00:00:00+01:00"
assert state.attributes["before"] == "2019-01-11T06:00:00+01:00"
assert state.attributes["next_update"] == "2019-01-11T00:00:00+01:00"


async def test_simple_before_after_does_not_loop_berlin_in_range(hass):
"""Test simple before after."""
hass.config.time_zone = "Europe/Berlin"
dt_util.set_default_time_zone(dt_util.get_time_zone("Europe/Berlin"))
test_time = datetime(2019, 1, 10, 23, 43, 0, tzinfo=dt_util.UTC)
config = {
"binary_sensor": [
{
"platform": "tod",
"name": "Dark",
"before": "06:00",
"after": "00:00",
}
]
}
with patch(
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
return_value=test_time,
):
await async_setup_component(hass, "binary_sensor", config)
await hass.async_block_till_done()

state = hass.states.get("binary_sensor.dark")
assert state.state == STATE_ON
assert state.attributes["after"] == "2019-01-11T00:00:00+01:00"
assert state.attributes["before"] == "2019-01-11T06:00:00+01:00"
assert state.attributes["next_update"] == "2019-01-11T06:00:00+01:00"

0 comments on commit a3146ad

Please sign in to comment.