Compare commits

..

7 Commits
0.56 ... 0.56.2

Author SHA1 Message Date
Pascal Vizeli
e620479cc8 Merge pull request #10069 from home-assistant/release-0-56-2
0.56.2
2017-10-23 17:40:58 +02:00
Fabian Affolter
79d71c6727 Version bump to 0.56.2 2017-10-23 16:09:26 +02:00
Fabian Affolter
32f58baa85 Fix merge conflict 2017-10-23 13:49:45 +02:00
Pascal Vizeli
9794336113 Remove warning 2017-10-23 13:48:25 +02:00
Teemu R
ed82f23da3 switch.tplink: fix overlooked issue with statically defined names (#10053) 2017-10-23 13:46:00 +02:00
Maciej Bieniek
48c86e07fa fix gateway illumination sensor value (#10045) 2017-10-23 13:45:34 +02:00
Paulus Schoutsen
106bf467f8 0.56.1 (#10035)
* Version bump to 0.56.1

* Fix device update / entity_id with names (#10029)

* Fix device update

* Add tests

* add test for disabled warning

* fix temperature/humidity sensors valid values (#10024)
2017-10-22 19:56:20 +02:00
8 changed files with 109 additions and 68 deletions

View File

@@ -31,16 +31,17 @@ def async_trigger(hass, config, action):
event_type = config.get(CONF_EVENT_TYPE)
event_data_schema = vol.Schema(
config.get(CONF_EVENT_DATA),
extra=vol.ALLOW_EXTRA)
extra=vol.ALLOW_EXTRA) if config.get(CONF_EVENT_DATA) else None
@callback
def handle_event(event):
"""Listen for events and calls the action when data matches."""
try:
event_data_schema(event.data)
except vol.Invalid:
# If event data doesn't match requested schema, skip event
return
if event_data_schema:
try:
event_data_schema(event.data)
except vol.Invalid:
# If event data doesn't match requested schema, skip event
return
hass.async_run_job(action, {
'trigger': {

View File

@@ -67,17 +67,15 @@ class XiaomiSensor(XiaomiDevice):
if value is None:
return False
value = float(value)
if self._data_key == 'temperature' and (value < -20 or value > 60):
return False
elif self._data_key == 'humidity' and (value <= 0 or value > 100):
return False
elif self._data_key == 'illumination' and value == 0:
return False
elif self._data_key == 'pressure' and value == 0:
return False
if self._data_key in ['temperature', 'humidity', 'pressure']:
value /= 100
elif self._data_key in ['illumination']:
value = max(value - 300, 0)
if self._data_key == 'temperature' and (value < -20 or value > 60):
return False
elif self._data_key == 'humidity' and (value <= 0 or value > 100):
return False
elif self._data_key == 'pressure' and value == 0:
return False
self._state = round(value, 2)
return True

View File

@@ -45,7 +45,7 @@ class SmartPlugSwitch(SwitchDevice):
def __init__(self, smartplug, name):
"""Initialize the switch."""
self.smartplug = smartplug
self._name = None
self._name = name
self._state = None
# Set up emeter cache
self._emeter_params = {}

View File

@@ -2,7 +2,7 @@
"""Constants used by Home Assistant components."""
MAJOR_VERSION = 0
MINOR_VERSION = 56
PATCH_VERSION = '0'
PATCH_VERSION = '2'
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
REQUIRED_PYTHON_VER = (3, 4, 2)

View File

@@ -200,34 +200,11 @@ class Entity(object):
# update entity data
if force_refresh:
if self._update_staged:
return
self._update_staged = True
# Process update sequential
if self.parallel_updates:
yield from self.parallel_updates.acquire()
update_warn = self.hass.loop.call_later(
SLOW_UPDATE_WARNING, _LOGGER.warning,
"Update of %s is taking over %s seconds", self.entity_id,
SLOW_UPDATE_WARNING
)
try:
if hasattr(self, 'async_update'):
# pylint: disable=no-member
yield from self.async_update()
else:
yield from self.hass.async_add_job(self.update)
yield from self.async_device_update()
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Update for %s fails", self.entity_id)
return
finally:
self._update_staged = False
update_warn.cancel()
if self.parallel_updates:
self.parallel_updates.release()
start = timer()
@@ -304,6 +281,39 @@ class Entity(object):
"""Schedule a update ha state change task."""
self.hass.async_add_job(self.async_update_ha_state(force_refresh))
def async_device_update(self, warning=True):
"""Process 'update' or 'async_update' from entity.
This method is a coroutine.
"""
if self._update_staged:
return
self._update_staged = True
# Process update sequential
if self.parallel_updates:
yield from self.parallel_updates.acquire()
if warning:
update_warn = self.hass.loop.call_later(
SLOW_UPDATE_WARNING, _LOGGER.warning,
"Update of %s is taking over %s seconds", self.entity_id,
SLOW_UPDATE_WARNING
)
try:
if hasattr(self, 'async_update'):
# pylint: disable=no-member
yield from self.async_update()
else:
yield from self.hass.async_add_job(self.update)
finally:
self._update_staged = False
if warning:
update_warn.cancel()
if self.parallel_updates:
self.parallel_updates.release()
def remove(self) -> None:
"""Remove entity from HASS."""
run_coroutine_threadsafe(

View File

@@ -210,6 +210,15 @@ class EntityComponent(object):
entity.hass = self.hass
# Update properties before we generate the entity_id
if update_before_add:
try:
yield from entity.async_device_update(warning=False)
except Exception: # pylint: disable=broad-except
self.logger.exception("Error on device update!")
return False
# Write entity_id to entity
if getattr(entity, 'entity_id', None) is None:
object_id = entity.name or DEVICE_DEFAULT_NAME
@@ -234,7 +243,7 @@ class EntityComponent(object):
if hasattr(entity, 'async_added_to_hass'):
yield from entity.async_added_to_hass()
yield from entity.async_update_ha_state(update_before_add)
yield from entity.async_update_ha_state()
return True
@@ -361,12 +370,14 @@ class EntityPlatform(object):
def add_entities(self, new_entities, update_before_add=False):
"""Add entities for a single platform."""
# That avoid deadlocks
if update_before_add:
for entity in new_entities:
entity.update()
self.component.logger.warning(
"Call 'add_entities' with update_before_add=True "
"only inside tests or you can run into a deadlock!")
run_coroutine_threadsafe(
self.async_add_entities(list(new_entities), False),
self.async_add_entities(list(new_entities), update_before_add),
self.component.hass.loop).result()
@asyncio.coroutine

View File

@@ -193,6 +193,30 @@ def test_warn_slow_update_with_exception(hass):
assert update_call
@asyncio.coroutine
def test_warn_slow_device_update_disabled(hass):
"""Disable slow update warning with async_device_update."""
update_call = False
@asyncio.coroutine
def async_update():
"""Mock async update."""
nonlocal update_call
update_call = True
mock_entity = entity.Entity()
mock_entity.hass = hass
mock_entity.entity_id = 'comp_test.test_entity'
mock_entity.async_update = async_update
with patch.object(hass.loop, 'call_later', MagicMock()) \
as mock_call:
yield from mock_entity.async_device_update(warning=False)
assert not mock_call.called
assert update_call
@asyncio.coroutine
def test_async_schedule_update_ha_state(hass):
"""Warn we log when entity update takes a long time and trow exception."""

View File

@@ -208,30 +208,6 @@ class TestHelpersEntityComponent(unittest.TestCase):
assert 1 == len(self.hass.states.entity_ids())
assert not ent.update.called
def test_adds_entities_with_update_befor_add_true_deadlock_protect(self):
"""Test if call update before add to state machine.
It need to run update inside executor and never call
async_add_entities with True
"""
call = []
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@asyncio.coroutine
def async_add_entities_fake(entities, update_befor_add):
"""Fake add_entities_call."""
call.append(update_befor_add)
component._platforms['core'].async_add_entities = \
async_add_entities_fake
ent = EntityTest()
ent.update = Mock(spec_set=True)
component.add_entities([ent], True)
assert ent.update.called
assert len(call) == 1
assert not call[0]
def test_not_adding_duplicate_entities(self):
"""Test for not adding duplicate entities."""
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@@ -654,3 +630,24 @@ def test_pararell_updates_sync_platform(hass):
handle = list(component._platforms.values())[-1]
assert handle.parallel_updates is not None
@asyncio.coroutine
def test_raise_error_on_update(hass):
"""Test the add entity if they raise an error on update."""
updates = []
component = EntityComponent(_LOGGER, DOMAIN, hass)
entity1 = EntityTest(name='test_1')
entity2 = EntityTest(name='test_2')
def _raise():
"""Helper to raise a exception."""
raise AssertionError
entity1.update = _raise
entity2.update = lambda: updates.append(1)
yield from component.async_add_entities([entity1, entity2], True)
assert len(updates) == 1
assert 1 in updates