Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make async_track_time_change smarter #17199

Merged
merged 9 commits into from Oct 9, 2018

Conversation

OttoWinter
Copy link
Member

@OttoWinter OttoWinter commented Oct 6, 2018

Description:

Implement algorithm from home-assistant/architecture#88 into events base.

This will enable:

This does not:

  • Make async_track_time_change more efficient. Or at least not much. The listener still fires for each second.

This does:

  • Fix situations when the timer got out of sync and some time triggers wouldn't fire. For example if I have a time trigger at 02:30 in the morning but the timer for some reason didn't fire events between 02:28 and 02:32
  • Remove the day, month and year kwargs from async_track_utc_time_change. They can be re-added later but they weren't used anywhere except for the tests.

Questions:

  • event.py might not be the best place for _find_next_time_expression_time as it doesn't have too much to do with events. Should I move it to dt.py?

Checklist:

  • The code change is tested and works locally.
  • Local tests pass with tox. Your PR cannot be merged unless tests pass

If the code does not interact with devices:

  • Tests have been added to verify that the new code works.

parameter = float(parameter[1:])
return lambda time: time % parameter == 0
res = [x for x in range(min_value, max_value + 1)
if x % parameter == 0]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why this is a float (cron syntax doesn't allow it), but I added it here to prevent a potential breaking change.

return res


def _find_next_time_expression_time(now, seconds, minutes, hours):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that is a utils.dt function

@OttoWinter OttoWinter changed the title [WIP] Make async_track_time_change smarter Make async_track_time_change smarter Oct 7, 2018
now = dt_util.as_local(now)
# Prevent "can't compare offset-naive and offset-aware" errors,
# let's make everything timezone-aware
if now.tzinfo is None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can't happen. time changed events are send by the timer and are always UTC?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes missed that. The tests were failiing because of it and I didn't investigate it in the timer source, but here.

# let's make everything timezone-aware
if now.tzinfo is None:
# pylint: disable=no-value-for-parameter
now = pytz.UTC.localize(now)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also use our own helpers in util.dt.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that as_utc would in this case first make the dt object timezone-aware with the "default" timezone and then convert it back to utc. So if you input datetime(8.10.2018 14:31, tzinfo=None) it might output datetime(8.10.2018 12:31, tzinfo=UTC)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well I guess it doesn't matter as we can remove this whole if-statement 😄


self.assertRaises(ValueError, dt_util.parse_time_expression, 61, 0, 60)

def test_find_next_time_expression_time_basic(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day it's time you learn how to write the modern style tests 😉

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing? That's overrated 😉 Just write a bunch of changes, publish a new version and hope nothing breaks #esphomelib 😅

I really should learn that :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

async def test_something(hass):
    assert len(hass.states.async_all()) == 0

that's it :)

@@ -1,10 +1,14 @@
"""Helper methods to handle the time in Home Assistant."""
import datetime as dt
import re
from typing import Any, Dict, Union, Optional, Tuple # noqa pylint: disable=unused-import
from typing import Any, Union, Optional, Tuple, \

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'typing.Dict' imported but unused

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants