mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +00:00
Support longer-than-60-second scan_interval and interval_seconds (#5147)
* Update scan_interval and interval_seconds max to 1 day vs. 60 seconds * Format fixes * Add docstring on unittest. * Added and implemented new async_track_time_interval helper. * Format fixes, removed unused import. * Undid whoops on unsub_polling. * Updated unit tests for scan_interval. * Added unit test for track_time_interval. * Allow other forms of time interval input for scan_interval and interval_seconds
This commit is contained in:
parent
f88b5a9c5e
commit
a36ca62445
@ -24,6 +24,7 @@ from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers import config_per_platform, discovery
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
from homeassistant.helpers.typing import GPSType, ConfigType, HomeAssistantType
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
import homeassistant.util as util
|
||||
@ -71,7 +72,7 @@ ATTR_BATTERY = 'battery'
|
||||
ATTR_ATTRIBUTES = 'attributes'
|
||||
|
||||
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_SCAN_INTERVAL): cv.positive_int, # seconds
|
||||
vol.Optional(CONF_SCAN_INTERVAL): cv.time_period,
|
||||
vol.Optional(CONF_TRACK_NEW, default=DEFAULT_TRACK_NEW): cv.boolean,
|
||||
vol.Optional(CONF_CONSIDER_HOME,
|
||||
default=timedelta(seconds=DEFAULT_CONSIDER_HOME)): vol.All(
|
||||
@ -639,8 +640,9 @@ def async_setup_scanner_platform(hass: HomeAssistantType, config: ConfigType,
|
||||
seen.add(mac)
|
||||
hass.async_add_job(async_see_device(mac=mac, host_name=host_name))
|
||||
|
||||
async_track_utc_time_change(
|
||||
hass, async_device_tracker_scan, second=range(0, 60, interval))
|
||||
async_track_time_interval(
|
||||
hass, async_device_tracker_scan,
|
||||
timedelta(seconds=interval))
|
||||
|
||||
hass.async_add_job(async_device_tracker_scan, None)
|
||||
|
||||
|
@ -405,8 +405,7 @@ def key_dependency(key, dependency):
|
||||
|
||||
PLATFORM_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_PLATFORM): string,
|
||||
vol.Optional(CONF_SCAN_INTERVAL):
|
||||
vol.All(vol.Coerce(int), vol.Range(min=1)),
|
||||
vol.Optional(CONF_SCAN_INTERVAL): time_period
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
EVENT_SCHEMA = vol.Schema({
|
||||
|
@ -1,5 +1,6 @@
|
||||
"""Helpers for components that manage entities."""
|
||||
import asyncio
|
||||
from datetime import timedelta
|
||||
|
||||
from homeassistant import config as conf_util
|
||||
from homeassistant.bootstrap import (
|
||||
@ -12,7 +13,7 @@ from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.loader import get_component
|
||||
from homeassistant.helpers import config_per_platform, discovery
|
||||
from homeassistant.helpers.entity import async_generate_entity_id
|
||||
from homeassistant.helpers.event import async_track_utc_time_change
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
from homeassistant.helpers.service import extract_entity_ids
|
||||
from homeassistant.util.async import (
|
||||
run_callback_threadsafe, run_coroutine_threadsafe)
|
||||
@ -324,9 +325,10 @@ class EntityPlatform(object):
|
||||
in self.platform_entities):
|
||||
return
|
||||
|
||||
self._async_unsub_polling = async_track_utc_time_change(
|
||||
self._async_unsub_polling = async_track_time_interval(
|
||||
self.component.hass, self._update_entity_states,
|
||||
second=range(0, 60, self.scan_interval))
|
||||
timedelta(seconds=self.scan_interval)
|
||||
)
|
||||
|
||||
@asyncio.coroutine
|
||||
def _async_process_entity(self, new_entity, update_before_add):
|
||||
|
@ -85,7 +85,7 @@ track_state_change = threaded_listener_factory(async_track_state_change)
|
||||
|
||||
|
||||
def async_track_point_in_time(hass, action, point_in_time):
|
||||
"""Add a listener that fires once after a spefic point in time."""
|
||||
"""Add a listener that fires once after a specific point in time."""
|
||||
utc_point_in_time = dt_util.as_utc(point_in_time)
|
||||
|
||||
@callback
|
||||
@ -133,6 +133,33 @@ track_point_in_utc_time = threaded_listener_factory(
|
||||
async_track_point_in_utc_time)
|
||||
|
||||
|
||||
def async_track_time_interval(hass, action, interval):
|
||||
"""Add a listener that fires repetitively at every timedelta interval."""
|
||||
def next_interval():
|
||||
"""Return the next interval."""
|
||||
return dt_util.utcnow() + interval
|
||||
|
||||
@callback
|
||||
def interval_listener(now):
|
||||
"""Called when when the interval has elapsed."""
|
||||
nonlocal remove
|
||||
remove = async_track_point_in_utc_time(
|
||||
hass, interval_listener, next_interval())
|
||||
hass.async_run_job(action, now)
|
||||
|
||||
remove = async_track_point_in_utc_time(
|
||||
hass, interval_listener, next_interval())
|
||||
|
||||
def remove_listener():
|
||||
"""Remove interval listener."""
|
||||
remove()
|
||||
|
||||
return remove_listener
|
||||
|
||||
|
||||
track_time_interval = threaded_listener_factory(async_track_time_interval)
|
||||
|
||||
|
||||
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
|
||||
|
@ -5,12 +5,15 @@ from collections import OrderedDict
|
||||
import logging
|
||||
import unittest
|
||||
from unittest.mock import patch, Mock
|
||||
from datetime import timedelta
|
||||
|
||||
import homeassistant.core as ha
|
||||
import homeassistant.loader as loader
|
||||
from homeassistant.components import group
|
||||
from homeassistant.helpers.entity import Entity, generate_entity_id
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.helpers.entity_component import (
|
||||
EntityComponent, DEFAULT_SCAN_INTERVAL)
|
||||
|
||||
from homeassistant.helpers import discovery
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
@ -106,7 +109,7 @@ class TestHelpersEntityComponent(unittest.TestCase):
|
||||
no_poll_ent.async_update.reset_mock()
|
||||
poll_ent.async_update.reset_mock()
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(second=0))
|
||||
fire_time_changed(self.hass, dt_util.utcnow() + timedelta(seconds=20))
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert not no_poll_ent.async_update.called
|
||||
@ -123,7 +126,10 @@ class TestHelpersEntityComponent(unittest.TestCase):
|
||||
assert 1 == len(self.hass.states.entity_ids())
|
||||
ent2.update = lambda *_: component.add_entities([ent1])
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(second=0))
|
||||
fire_time_changed(
|
||||
self.hass, dt_util.utcnow() +
|
||||
timedelta(seconds=DEFAULT_SCAN_INTERVAL)
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert 2 == len(self.hass.states.entity_ids())
|
||||
@ -311,7 +317,7 @@ class TestHelpersEntityComponent(unittest.TestCase):
|
||||
mock_setup.call_args[0]
|
||||
|
||||
@patch('homeassistant.helpers.entity_component.'
|
||||
'async_track_utc_time_change')
|
||||
'async_track_time_interval')
|
||||
def test_set_scan_interval_via_config(self, mock_track):
|
||||
"""Test the setting of the scan interval via configuration."""
|
||||
def platform_setup(hass, config, add_devices, discovery_info=None):
|
||||
@ -331,10 +337,10 @@ class TestHelpersEntityComponent(unittest.TestCase):
|
||||
})
|
||||
|
||||
assert mock_track.called
|
||||
assert [0, 30] == list(mock_track.call_args[1]['second'])
|
||||
assert timedelta(seconds=30) == mock_track.call_args[0][2]
|
||||
|
||||
@patch('homeassistant.helpers.entity_component.'
|
||||
'async_track_utc_time_change')
|
||||
'async_track_time_interval')
|
||||
def test_set_scan_interval_via_platform(self, mock_track):
|
||||
"""Test the setting of the scan interval via platform."""
|
||||
def platform_setup(hass, config, add_devices, discovery_info=None):
|
||||
@ -355,7 +361,7 @@ class TestHelpersEntityComponent(unittest.TestCase):
|
||||
})
|
||||
|
||||
assert mock_track.called
|
||||
assert [0, 30] == list(mock_track.call_args[1]['second'])
|
||||
assert timedelta(seconds=30) == mock_track.call_args[0][2]
|
||||
|
||||
def test_set_entity_namespace_via_config(self):
|
||||
"""Test setting an entity namespace."""
|
||||
|
@ -15,6 +15,7 @@ from homeassistant.helpers.event import (
|
||||
track_utc_time_change,
|
||||
track_time_change,
|
||||
track_state_change,
|
||||
track_time_interval,
|
||||
track_sunrise,
|
||||
track_sunset,
|
||||
)
|
||||
@ -187,6 +188,34 @@ class TestEventHelpers(unittest.TestCase):
|
||||
self.assertEqual(5, len(wildcard_runs))
|
||||
self.assertEqual(6, len(wildercard_runs))
|
||||
|
||||
def test_track_time_interval(self):
|
||||
"""Test tracking time interval."""
|
||||
specific_runs = []
|
||||
|
||||
utc_now = dt_util.utcnow()
|
||||
unsub = track_time_interval(
|
||||
self.hass, lambda x: specific_runs.append(1),
|
||||
timedelta(seconds=10)
|
||||
)
|
||||
|
||||
self._send_time_changed(utc_now + timedelta(seconds=5))
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(0, len(specific_runs))
|
||||
|
||||
self._send_time_changed(utc_now + timedelta(seconds=13))
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(1, len(specific_runs))
|
||||
|
||||
self._send_time_changed(utc_now + timedelta(minutes=20))
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(2, len(specific_runs))
|
||||
|
||||
unsub()
|
||||
|
||||
self._send_time_changed(utc_now + timedelta(seconds=30))
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(2, len(specific_runs))
|
||||
|
||||
def test_track_sunrise(self):
|
||||
"""Test track the sunrise."""
|
||||
latitude = 32.87336
|
||||
|
Loading…
x
Reference in New Issue
Block a user