mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 22:27:07 +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.aiohttp_client import async_get_clientsession
|
||||||
from homeassistant.helpers import config_per_platform, discovery
|
from homeassistant.helpers import config_per_platform, discovery
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
from homeassistant.helpers.typing import GPSType, ConfigType, HomeAssistantType
|
from homeassistant.helpers.typing import GPSType, ConfigType, HomeAssistantType
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
import homeassistant.util as util
|
import homeassistant.util as util
|
||||||
@ -71,7 +72,7 @@ ATTR_BATTERY = 'battery'
|
|||||||
ATTR_ATTRIBUTES = 'attributes'
|
ATTR_ATTRIBUTES = 'attributes'
|
||||||
|
|
||||||
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
|
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_TRACK_NEW, default=DEFAULT_TRACK_NEW): cv.boolean,
|
||||||
vol.Optional(CONF_CONSIDER_HOME,
|
vol.Optional(CONF_CONSIDER_HOME,
|
||||||
default=timedelta(seconds=DEFAULT_CONSIDER_HOME)): vol.All(
|
default=timedelta(seconds=DEFAULT_CONSIDER_HOME)): vol.All(
|
||||||
@ -639,8 +640,9 @@ def async_setup_scanner_platform(hass: HomeAssistantType, config: ConfigType,
|
|||||||
seen.add(mac)
|
seen.add(mac)
|
||||||
hass.async_add_job(async_see_device(mac=mac, host_name=host_name))
|
hass.async_add_job(async_see_device(mac=mac, host_name=host_name))
|
||||||
|
|
||||||
async_track_utc_time_change(
|
async_track_time_interval(
|
||||||
hass, async_device_tracker_scan, second=range(0, 60, interval))
|
hass, async_device_tracker_scan,
|
||||||
|
timedelta(seconds=interval))
|
||||||
|
|
||||||
hass.async_add_job(async_device_tracker_scan, None)
|
hass.async_add_job(async_device_tracker_scan, None)
|
||||||
|
|
||||||
|
@ -405,8 +405,7 @@ def key_dependency(key, dependency):
|
|||||||
|
|
||||||
PLATFORM_SCHEMA = vol.Schema({
|
PLATFORM_SCHEMA = vol.Schema({
|
||||||
vol.Required(CONF_PLATFORM): string,
|
vol.Required(CONF_PLATFORM): string,
|
||||||
vol.Optional(CONF_SCAN_INTERVAL):
|
vol.Optional(CONF_SCAN_INTERVAL): time_period
|
||||||
vol.All(vol.Coerce(int), vol.Range(min=1)),
|
|
||||||
}, extra=vol.ALLOW_EXTRA)
|
}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
EVENT_SCHEMA = vol.Schema({
|
EVENT_SCHEMA = vol.Schema({
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
"""Helpers for components that manage entities."""
|
"""Helpers for components that manage entities."""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from homeassistant import config as conf_util
|
from homeassistant import config as conf_util
|
||||||
from homeassistant.bootstrap import (
|
from homeassistant.bootstrap import (
|
||||||
@ -12,7 +13,7 @@ from homeassistant.exceptions import HomeAssistantError
|
|||||||
from homeassistant.loader import get_component
|
from homeassistant.loader import get_component
|
||||||
from homeassistant.helpers import config_per_platform, discovery
|
from homeassistant.helpers import config_per_platform, discovery
|
||||||
from homeassistant.helpers.entity import async_generate_entity_id
|
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.helpers.service import extract_entity_ids
|
||||||
from homeassistant.util.async import (
|
from homeassistant.util.async import (
|
||||||
run_callback_threadsafe, run_coroutine_threadsafe)
|
run_callback_threadsafe, run_coroutine_threadsafe)
|
||||||
@ -324,9 +325,10 @@ class EntityPlatform(object):
|
|||||||
in self.platform_entities):
|
in self.platform_entities):
|
||||||
return
|
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,
|
self.component.hass, self._update_entity_states,
|
||||||
second=range(0, 60, self.scan_interval))
|
timedelta(seconds=self.scan_interval)
|
||||||
|
)
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def _async_process_entity(self, new_entity, update_before_add):
|
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):
|
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)
|
utc_point_in_time = dt_util.as_utc(point_in_time)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@ -133,6 +133,33 @@ track_point_in_utc_time = threaded_listener_factory(
|
|||||||
async_track_point_in_utc_time)
|
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):
|
def async_track_sunrise(hass, action, offset=None):
|
||||||
"""Add a listener that will fire a specified offset from sunrise daily."""
|
"""Add a listener that will fire a specified offset from sunrise daily."""
|
||||||
from homeassistant.components import sun
|
from homeassistant.components import sun
|
||||||
|
@ -5,12 +5,15 @@ from collections import OrderedDict
|
|||||||
import logging
|
import logging
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import patch, Mock
|
from unittest.mock import patch, Mock
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
import homeassistant.core as ha
|
import homeassistant.core as ha
|
||||||
import homeassistant.loader as loader
|
import homeassistant.loader as loader
|
||||||
from homeassistant.components import group
|
from homeassistant.components import group
|
||||||
from homeassistant.helpers.entity import Entity, generate_entity_id
|
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
|
from homeassistant.helpers import discovery
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
@ -106,7 +109,7 @@ class TestHelpersEntityComponent(unittest.TestCase):
|
|||||||
no_poll_ent.async_update.reset_mock()
|
no_poll_ent.async_update.reset_mock()
|
||||||
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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
assert not no_poll_ent.async_update.called
|
assert not no_poll_ent.async_update.called
|
||||||
@ -123,7 +126,10 @@ class TestHelpersEntityComponent(unittest.TestCase):
|
|||||||
assert 1 == len(self.hass.states.entity_ids())
|
assert 1 == len(self.hass.states.entity_ids())
|
||||||
ent2.update = lambda *_: component.add_entities([ent1])
|
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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
assert 2 == len(self.hass.states.entity_ids())
|
assert 2 == len(self.hass.states.entity_ids())
|
||||||
@ -311,7 +317,7 @@ class TestHelpersEntityComponent(unittest.TestCase):
|
|||||||
mock_setup.call_args[0]
|
mock_setup.call_args[0]
|
||||||
|
|
||||||
@patch('homeassistant.helpers.entity_component.'
|
@patch('homeassistant.helpers.entity_component.'
|
||||||
'async_track_utc_time_change')
|
'async_track_time_interval')
|
||||||
def test_set_scan_interval_via_config(self, mock_track):
|
def test_set_scan_interval_via_config(self, mock_track):
|
||||||
"""Test the setting of the scan interval via configuration."""
|
"""Test the setting of the scan interval via configuration."""
|
||||||
def platform_setup(hass, config, add_devices, discovery_info=None):
|
def platform_setup(hass, config, add_devices, discovery_info=None):
|
||||||
@ -331,10 +337,10 @@ class TestHelpersEntityComponent(unittest.TestCase):
|
|||||||
})
|
})
|
||||||
|
|
||||||
assert mock_track.called
|
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.'
|
@patch('homeassistant.helpers.entity_component.'
|
||||||
'async_track_utc_time_change')
|
'async_track_time_interval')
|
||||||
def test_set_scan_interval_via_platform(self, mock_track):
|
def test_set_scan_interval_via_platform(self, mock_track):
|
||||||
"""Test the setting of the scan interval via platform."""
|
"""Test the setting of the scan interval via platform."""
|
||||||
def platform_setup(hass, config, add_devices, discovery_info=None):
|
def platform_setup(hass, config, add_devices, discovery_info=None):
|
||||||
@ -355,7 +361,7 @@ class TestHelpersEntityComponent(unittest.TestCase):
|
|||||||
})
|
})
|
||||||
|
|
||||||
assert mock_track.called
|
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):
|
def test_set_entity_namespace_via_config(self):
|
||||||
"""Test setting an entity namespace."""
|
"""Test setting an entity namespace."""
|
||||||
|
@ -15,6 +15,7 @@ from homeassistant.helpers.event import (
|
|||||||
track_utc_time_change,
|
track_utc_time_change,
|
||||||
track_time_change,
|
track_time_change,
|
||||||
track_state_change,
|
track_state_change,
|
||||||
|
track_time_interval,
|
||||||
track_sunrise,
|
track_sunrise,
|
||||||
track_sunset,
|
track_sunset,
|
||||||
)
|
)
|
||||||
@ -187,6 +188,34 @@ class TestEventHelpers(unittest.TestCase):
|
|||||||
self.assertEqual(5, len(wildcard_runs))
|
self.assertEqual(5, len(wildcard_runs))
|
||||||
self.assertEqual(6, len(wildercard_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):
|
def test_track_sunrise(self):
|
||||||
"""Test track the sunrise."""
|
"""Test track the sunrise."""
|
||||||
latitude = 32.87336
|
latitude = 32.87336
|
||||||
|
Loading…
x
Reference in New Issue
Block a user