Template switch change flow / add restore (#6356)

* Template switch change flow / add restore

* fix tests

* fix binary_sensor template
This commit is contained in:
Pascal Vizeli 2017-03-02 14:09:53 +01:00 committed by GitHub
parent 597ae2e716
commit 55dc483c91
4 changed files with 128 additions and 12 deletions

View file

@ -16,7 +16,7 @@ from homeassistant.components.binary_sensor import (
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) EVENT_HOMEASSISTANT_START, STATE_ON)
from homeassistant.exceptions import TemplateError from homeassistant.exceptions import TemplateError
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
@ -92,7 +92,7 @@ class BinarySensorTemplate(BinarySensorDevice):
"""Register callbacks.""" """Register callbacks."""
state = yield from async_get_last_state(self.hass, self.entity_id) state = yield from async_get_last_state(self.hass, self.entity_id)
if state: if state:
self._state = state.state self._state = state.state == STATE_ON
@callback @callback
def template_bsensor_state_listener(entity, old_state, new_state): def template_bsensor_state_listener(entity, old_state, new_state):

View file

@ -14,12 +14,13 @@ from homeassistant.components.switch import (
ENTITY_ID_FORMAT, SwitchDevice, PLATFORM_SCHEMA) ENTITY_ID_FORMAT, SwitchDevice, PLATFORM_SCHEMA)
from homeassistant.const import ( from homeassistant.const import (
ATTR_FRIENDLY_NAME, CONF_VALUE_TEMPLATE, STATE_OFF, STATE_ON, ATTR_FRIENDLY_NAME, CONF_VALUE_TEMPLATE, STATE_OFF, STATE_ON,
ATTR_ENTITY_ID, CONF_SWITCHES) ATTR_ENTITY_ID, CONF_SWITCHES, EVENT_HOMEASSISTANT_START)
from homeassistant.exceptions import TemplateError from homeassistant.exceptions import TemplateError
import homeassistant.helpers.config_validation as cv
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_state_change from homeassistant.helpers.event import async_track_state_change
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.helpers.script import Script from homeassistant.helpers.script import Script
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
_VALID_STATES = [STATE_ON, STATE_OFF, 'true', 'false'] _VALID_STATES = [STATE_ON, STATE_OFF, 'true', 'false']
@ -88,14 +89,30 @@ class SwitchTemplate(SwitchDevice):
self._on_script = Script(hass, on_action) self._on_script = Script(hass, on_action)
self._off_script = Script(hass, off_action) self._off_script = Script(hass, off_action)
self._state = False self._state = False
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 == STATE_ON
@callback @callback
def template_switch_state_listener(entity, old_state, new_state): def template_switch_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_switch_state_listener) def template_switch_startup(event):
"""Update template on startup."""
async_track_state_change(
self.hass, self._entities, template_switch_state_listener)
self.hass.async_add_job(self.async_update_ha_state(True))
self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_START, template_switch_startup)
@property @property
def name(self): def name(self):

View file

@ -39,6 +39,7 @@ class TestTemplateSensor:
}) })
self.hass.start() self.hass.start()
self.hass.block_till_done()
state = self.hass.states.get('sensor.test_template_sensor') state = self.hass.states.get('sensor.test_template_sensor')
assert state.state == 'It .' assert state.state == 'It .'
@ -68,6 +69,7 @@ class TestTemplateSensor:
}) })
self.hass.start() self.hass.start()
self.hass.block_till_done()
state = self.hass.states.get('sensor.test_template_sensor') state = self.hass.states.get('sensor.test_template_sensor')
assert 'icon' not in state.attributes assert 'icon' not in state.attributes
@ -93,6 +95,7 @@ class TestTemplateSensor:
}) })
self.hass.start() self.hass.start()
self.hass.block_till_done()
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_template_attribute_missing(self): def test_template_attribute_missing(self):
@ -111,6 +114,7 @@ class TestTemplateSensor:
}) })
self.hass.start() self.hass.start()
self.hass.block_till_done()
state = self.hass.states.get('sensor.test_template_sensor') state = self.hass.states.get('sensor.test_template_sensor')
assert state.state == 'unknown' assert state.state == 'unknown'
@ -131,6 +135,8 @@ class TestTemplateSensor:
}) })
self.hass.start() self.hass.start()
self.hass.block_till_done()
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_invalid_sensor_does_not_create(self): def test_invalid_sensor_does_not_create(self):
@ -146,6 +152,7 @@ class TestTemplateSensor:
}) })
self.hass.start() self.hass.start()
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_no_sensors_does_not_create(self): def test_no_sensors_does_not_create(self):
@ -158,6 +165,8 @@ class TestTemplateSensor:
}) })
self.hass.start() self.hass.start()
self.hass.block_till_done()
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_missing_template_does_not_create(self): def test_missing_template_does_not_create(self):
@ -176,6 +185,8 @@ class TestTemplateSensor:
}) })
self.hass.start() self.hass.start()
self.hass.block_till_done()
assert self.hass.states.all() == [] assert self.hass.states.all() == []

View file

@ -1,12 +1,14 @@
"""The tests for the Template switch platform.""" """The tests for the Template switch platform."""
from homeassistant.core import callback import asyncio
from homeassistant.core import callback, State, CoreState
import homeassistant.bootstrap as bootstrap import homeassistant.bootstrap as bootstrap
import homeassistant.components as core import homeassistant.components as core
from homeassistant.const import ( from homeassistant.const import STATE_ON, STATE_OFF
STATE_ON, from homeassistant.helpers.restore_state import DATA_RESTORE_CACHE
STATE_OFF)
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 TestTemplateSwitch: class TestTemplateSwitch:
@ -55,6 +57,9 @@ class TestTemplateSwitch:
} }
}) })
self.hass.start()
self.hass.block_till_done()
state = self.hass.states.set('switch.test_state', STATE_ON) state = self.hass.states.set('switch.test_state', STATE_ON)
self.hass.block_till_done() self.hass.block_till_done()
@ -90,6 +95,9 @@ class TestTemplateSwitch:
} }
}) })
self.hass.start()
self.hass.block_till_done()
state = self.hass.states.get('switch.test_template_switch') state = self.hass.states.get('switch.test_template_switch')
assert state.state == STATE_ON assert state.state == STATE_ON
@ -116,6 +124,9 @@ class TestTemplateSwitch:
} }
}) })
self.hass.start()
self.hass.block_till_done()
state = self.hass.states.get('switch.test_template_switch') state = self.hass.states.get('switch.test_template_switch')
assert state.state == STATE_OFF assert state.state == STATE_OFF
@ -141,6 +152,10 @@ class TestTemplateSwitch:
} }
} }
}) })
self.hass.start()
self.hass.block_till_done()
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_invalid_name_does_not_create(self): def test_invalid_name_does_not_create(self):
@ -165,6 +180,10 @@ class TestTemplateSwitch:
} }
} }
}) })
self.hass.start()
self.hass.block_till_done()
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_invalid_switch_does_not_create(self): def test_invalid_switch_does_not_create(self):
@ -178,6 +197,10 @@ class TestTemplateSwitch:
} }
} }
}) })
self.hass.start()
self.hass.block_till_done()
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_no_switches_does_not_create(self): def test_no_switches_does_not_create(self):
@ -188,6 +211,10 @@ class TestTemplateSwitch:
'platform': 'template' 'platform': 'template'
} }
}) })
self.hass.start()
self.hass.block_till_done()
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_missing_template_does_not_create(self): def test_missing_template_does_not_create(self):
@ -212,6 +239,10 @@ class TestTemplateSwitch:
} }
} }
}) })
self.hass.start()
self.hass.block_till_done()
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_missing_on_does_not_create(self): def test_missing_on_does_not_create(self):
@ -236,6 +267,10 @@ class TestTemplateSwitch:
} }
} }
}) })
self.hass.start()
self.hass.block_till_done()
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_missing_off_does_not_create(self): def test_missing_off_does_not_create(self):
@ -260,6 +295,10 @@ class TestTemplateSwitch:
} }
} }
}) })
self.hass.start()
self.hass.block_till_done()
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_on_action(self): def test_on_action(self):
@ -282,6 +321,10 @@ class TestTemplateSwitch:
} }
} }
}) })
self.hass.start()
self.hass.block_till_done()
self.hass.states.set('switch.test_state', STATE_OFF) self.hass.states.set('switch.test_state', STATE_OFF)
self.hass.block_till_done() self.hass.block_till_done()
@ -314,6 +357,10 @@ class TestTemplateSwitch:
} }
} }
}) })
self.hass.start()
self.hass.block_till_done()
self.hass.states.set('switch.test_state', STATE_ON) self.hass.states.set('switch.test_state', STATE_ON)
self.hass.block_till_done() self.hass.block_till_done()
@ -324,3 +371,44 @@ class TestTemplateSwitch:
self.hass.block_till_done() self.hass.block_till_done()
assert len(self.calls) == 1 assert len(self.calls) == 1
@asyncio.coroutine
def test_restore_state(hass):
"""Ensure states are restored on startup."""
hass.data[DATA_RESTORE_CACHE] = {
'switch.test_template_switch':
State('switch.test_template_switch', 'on'),
}
hass.state = CoreState.starting
mock_component(hass, 'recorder')
yield from bootstrap.async_setup_component(hass, 'switch', {
'switch': {
'platform': 'template',
'switches': {
'test_template_switch': {
'value_template':
"{{ states.switch.test_state.state }}",
'turn_on': {
'service': 'switch.turn_on',
'entity_id': 'switch.test_state'
},
'turn_off': {
'service': 'switch.turn_off',
'entity_id': 'switch.test_state'
},
}
}
}
})
state = hass.states.get('switch.test_template_switch')
assert state.state == 'on'
yield from hass.async_start()
yield from hass.async_block_till_done()
state = hass.states.get('switch.test_template_switch')
assert state.state == 'unavailable'