Template binary_sensor change flow / add restore (#6343)

* Template binary_sensor change flow / add restore

* fix lint
This commit is contained in:
Pascal Vizeli 2017-03-02 08:50:41 +01:00 committed by GitHub
parent 31bf5b8ff0
commit f3870a8a48
2 changed files with 92 additions and 20 deletions

View File

@ -15,12 +15,14 @@ from homeassistant.components.binary_sensor import (
DEVICE_CLASSES_SCHEMA) DEVICE_CLASSES_SCHEMA)
from homeassistant.const import ( from homeassistant.const import (
ATTR_FRIENDLY_NAME, ATTR_ENTITY_ID, CONF_VALUE_TEMPLATE, ATTR_FRIENDLY_NAME, ATTR_ENTITY_ID, CONF_VALUE_TEMPLATE,
CONF_SENSOR_CLASS, CONF_SENSORS, CONF_DEVICE_CLASS) CONF_SENSOR_CLASS, CONF_SENSORS, CONF_DEVICE_CLASS,
EVENT_HOMEASSISTANT_START)
from homeassistant.exceptions import TemplateError from homeassistant.exceptions import TemplateError
from homeassistant.helpers.entity import async_generate_entity_id
from homeassistant.helpers.event import async_track_state_change
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.deprecation import get_deprecated from homeassistant.helpers.deprecation import get_deprecated
from homeassistant.helpers.entity import async_generate_entity_id
from homeassistant.helpers.event import async_track_state_change
from homeassistant.helpers.restore_state import async_get_last_state
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -83,14 +85,30 @@ class BinarySensorTemplate(BinarySensorDevice):
self._device_class = device_class self._device_class = device_class
self._template = value_template self._template = value_template
self._state = None self._state = None
self._entities = entity_ids
@asyncio.coroutine
def async_added_to_hass(self):
"""Register callbacks."""
state = yield from async_get_last_state(self.hass, self.entity_id)
if state:
self._state = state.state
@callback @callback
def template_bsensor_state_listener(entity, old_state, new_state): def template_bsensor_state_listener(entity, old_state, new_state):
"""Called when the target device changes state.""" """Called when the target device changes state."""
hass.async_add_job(self.async_update_ha_state, True) self.hass.async_add_job(self.async_update_ha_state(True))
async_track_state_change( @callback
hass, entity_ids, template_bsensor_state_listener) def template_bsensor_startup(event):
"""Update template on startup."""
async_track_state_change(
self.hass, self._entities, template_bsensor_state_listener)
self.hass.async_add_job(self.async_update_ha_state(True))
self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_START, template_bsensor_startup)
@property @property
def name(self): def name(self):

View File

@ -1,15 +1,19 @@
"""The tests for the Template Binary sensor platform.""" """The tests for the Template Binary sensor platform."""
import asyncio
import unittest import unittest
from unittest import mock from unittest import mock
from homeassistant.const import EVENT_STATE_CHANGED, MATCH_ALL from homeassistant.core import CoreState, State
from homeassistant.const import MATCH_ALL
import homeassistant.bootstrap as bootstrap import homeassistant.bootstrap as bootstrap
from homeassistant.components.binary_sensor import template from homeassistant.components.binary_sensor import template
from homeassistant.exceptions import TemplateError from homeassistant.exceptions import TemplateError
from homeassistant.helpers import template as template_hlpr from homeassistant.helpers import template as template_hlpr
from homeassistant.util.async import run_callback_threadsafe from homeassistant.util.async import run_callback_threadsafe
from homeassistant.helpers.restore_state import DATA_RESTORE_CACHE
from tests.common import get_test_home_assistant, assert_setup_component from tests.common import (
get_test_home_assistant, assert_setup_component, mock_component)
class TestBinarySensorTemplate(unittest.TestCase): class TestBinarySensorTemplate(unittest.TestCase):
@ -26,8 +30,7 @@ class TestBinarySensorTemplate(unittest.TestCase):
"""Stop everything that was started.""" """Stop everything that was started."""
self.hass.stop() self.hass.stop()
@mock.patch.object(template, 'BinarySensorTemplate') def test_setup(self):
def test_setup(self, mock_template):
""""Test the setup.""" """"Test the setup."""
config = { config = {
'binary_sensor': { 'binary_sensor': {
@ -117,18 +120,34 @@ class TestBinarySensorTemplate(unittest.TestCase):
def test_event(self): def test_event(self):
""""Test the event.""" """"Test the event."""
vs = run_callback_threadsafe( config = {
self.hass.loop, template.BinarySensorTemplate, 'binary_sensor': {
self.hass, 'parent', 'Parent', 'motion', 'platform': 'template',
template_hlpr.Template('{{ 1 > 1 }}', self.hass), MATCH_ALL 'sensors': {
).result() 'test': {
vs.update_ha_state() 'friendly_name': 'virtual thingy',
'value_template':
"{{ states.sensor.test_state.state == 'on' }}",
'device_class': 'motion',
},
},
},
}
with assert_setup_component(1):
assert bootstrap.setup_component(
self.hass, 'binary_sensor', config)
self.hass.start()
self.hass.block_till_done() self.hass.block_till_done()
with mock.patch.object(vs, 'async_update') as mock_update: state = self.hass.states.get('binary_sensor.test')
self.hass.bus.fire(EVENT_STATE_CHANGED) assert state.state == 'off'
self.hass.block_till_done()
assert mock_update.call_count == 1 self.hass.states.set('sensor.test_state', 'on')
self.hass.block_till_done()
state = self.hass.states.get('binary_sensor.test')
assert state.state == 'on'
@mock.patch('homeassistant.helpers.template.Template.render') @mock.patch('homeassistant.helpers.template.Template.render')
def test_update_template_error(self, mock_render): def test_update_template_error(self, mock_render):
@ -143,3 +162,38 @@ class TestBinarySensorTemplate(unittest.TestCase):
mock_render.side_effect = TemplateError( mock_render.side_effect = TemplateError(
"UndefinedError: 'None' has no attribute") "UndefinedError: 'None' has no attribute")
vs.update() vs.update()
@asyncio.coroutine
def test_restore_state(hass):
"""Ensure states are restored on startup."""
hass.data[DATA_RESTORE_CACHE] = {
'binary_sensor.test': State('binary_sensor.test', 'on'),
}
hass.state = CoreState.starting
mock_component(hass, 'recorder')
config = {
'binary_sensor': {
'platform': 'template',
'sensors': {
'test': {
'friendly_name': 'virtual thingy',
'value_template':
"{{ states.sensor.test_state.state == 'on' }}",
'device_class': 'motion',
},
},
},
}
yield from bootstrap.async_setup_component(hass, 'binary_sensor', config)
state = hass.states.get('binary_sensor.test')
assert state.state == 'on'
yield from hass.async_start()
yield from hass.async_block_till_done()
state = hass.states.get('binary_sensor.test')
assert state.state == 'off'