Cleanup and simplitfy the async state update (#9390)

* Cleanup and simplitfy the async state update

* Update test_entity.py
This commit is contained in:
Pascal Vizeli 2017-09-12 10:01:03 +02:00 committed by GitHub
parent c84a099b0f
commit 90f9a6bc0a
47 changed files with 128 additions and 102 deletions

View File

@ -57,19 +57,19 @@ class AlarmDecoderAlarmPanel(alarm.AlarmControlPanel):
if message.alarm_sounding or message.fire_alarm:
if self._state != STATE_ALARM_TRIGGERED:
self._state = STATE_ALARM_TRIGGERED
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
elif message.armed_away:
if self._state != STATE_ALARM_ARMED_AWAY:
self._state = STATE_ALARM_ARMED_AWAY
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
elif message.armed_home:
if self._state != STATE_ALARM_ARMED_HOME:
self._state = STATE_ALARM_ARMED_HOME
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
else:
if self._state != STATE_ALARM_DISARMED:
self._state = STATE_ALARM_DISARMED
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@property
def name(self):

View File

@ -106,7 +106,7 @@ class EnvisalinkAlarm(EnvisalinkDevice, alarm.AlarmControlPanel):
def _update_callback(self, partition):
"""Update Home Assistant state, if needed."""
if partition is None or int(partition) == self._partition_number:
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@property
def code_format(self):

View File

@ -87,7 +87,7 @@ class MqttAlarm(alarm.AlarmControlPanel):
_LOGGER.warning("Received unexpected payload: %s", payload)
return
self._state = payload
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
return mqtt.async_subscribe(
self.hass, self._state_topic, message_received, self._qos)

View File

@ -263,7 +263,7 @@ class AndroidIPCamEntity(Entity):
"""Update callback."""
if self._host != host:
return
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
async_dispatcher_connect(
self.hass, SIGNAL_UPDATE_DATA, async_ipcam_update)

View File

@ -102,11 +102,11 @@ class AlarmDecoderBinarySensor(BinarySensorDevice):
"""Update the zone's state, if needed."""
if zone is None or int(zone) == self._zone_number:
self._state = 1
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@callback
def _restore_callback(self, zone):
"""Update the zone's state, if needed."""
if zone is None or int(zone) == self._zone_number:
self._state = 0
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()

View File

@ -80,4 +80,4 @@ class EnvisalinkBinarySensor(EnvisalinkDevice, BinarySensorDevice):
def _update_callback(self, zone):
"""Update the zone's state, if needed."""
if zone is None or int(zone) == self._zone_number:
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()

View File

@ -73,7 +73,7 @@ class FFmpegBinarySensor(FFmpegBase, BinarySensorDevice):
def _async_callback(self, state):
"""HA-FFmpeg callback for noise detection."""
self._state = state
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@property
def is_on(self):

View File

@ -86,7 +86,7 @@ class MqttBinarySensor(BinarySensorDevice):
elif payload == self._payload_off:
self._state = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
return mqtt.async_subscribe(
self.hass, self._state_topic, message_received, self._qos)

View File

@ -92,4 +92,4 @@ class MyStromBinarySensor(BinarySensorDevice):
def async_on_update(self, value):
"""Receive an update."""
self._state = value
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()

View File

@ -161,7 +161,7 @@ class BinarySensorTemplate(BinarySensorDevice):
def set_state():
"""Set state of template binary sensor."""
self._state = state
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
# state without delay
if (state and not self._delay_on) or \

View File

@ -211,7 +211,7 @@ class GenericThermostat(ClimateDevice):
"""Handle heater switch state changes."""
if new_state is None:
return
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@callback
def _async_keep_alive(self, time):

View File

@ -215,7 +215,7 @@ class KNXCover(CoverDevice):
def auto_updater_hook(self, now):
"""Callback for autoupdater."""
# pylint: disable=unused-argument
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self.device.position_reached():
self.stop_auto_updater()

View File

@ -178,7 +178,7 @@ class MqttCover(CoverDevice):
level = self.find_percentage_in_range(float(payload))
self._tilt_value = level
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@callback
def message_received(topic, payload, qos):
@ -203,7 +203,7 @@ class MqttCover(CoverDevice):
payload)
return
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._state_topic is None:
# Force into optimistic mode.
@ -275,7 +275,7 @@ class MqttCover(CoverDevice):
if self._optimistic:
# Optimistically assume that cover has changed state.
self._state = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_close_cover(self, **kwargs):
@ -289,7 +289,7 @@ class MqttCover(CoverDevice):
if self._optimistic:
# Optimistically assume that cover has changed state.
self._state = True
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_stop_cover(self, **kwargs):
@ -309,7 +309,7 @@ class MqttCover(CoverDevice):
self._retain)
if self._tilt_optimistic:
self._tilt_value = self._tilt_open_position
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_close_cover_tilt(self, **kwargs):
@ -319,7 +319,7 @@ class MqttCover(CoverDevice):
self._retain)
if self._tilt_optimistic:
self._tilt_value = self._tilt_closed_position
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_set_cover_tilt_position(self, **kwargs):

View File

@ -197,7 +197,7 @@ class CoverTemplate(CoverDevice):
@callback
def template_cover_state_listener(entity, old_state, new_state):
"""Handle target device state changes."""
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
@callback
def template_cover_startup(event):
@ -205,7 +205,7 @@ class CoverTemplate(CoverDevice):
async_track_state_change(
self.hass, self._entities, template_cover_state_listener)
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_START, template_cover_startup)
@ -271,7 +271,7 @@ class CoverTemplate(CoverDevice):
yield from self._position_script.async_run({"position": 100})
if self._optimistic:
self._position = 100
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_close_cover(self, **kwargs):
@ -282,7 +282,7 @@ class CoverTemplate(CoverDevice):
yield from self._position_script.async_run({"position": 0})
if self._optimistic:
self._position = 0
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_stop_cover(self, **kwargs):
@ -297,7 +297,7 @@ class CoverTemplate(CoverDevice):
yield from self._position_script.async_run(
{"position": self._position})
if self._optimistic:
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_open_cover_tilt(self, **kwargs):
@ -305,7 +305,7 @@ class CoverTemplate(CoverDevice):
self._tilt_value = 100
yield from self._tilt_script.async_run({"tilt": self._tilt_value})
if self._tilt_optimistic:
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_close_cover_tilt(self, **kwargs):
@ -314,7 +314,7 @@ class CoverTemplate(CoverDevice):
yield from self._tilt_script.async_run(
{"tilt": self._tilt_value})
if self._tilt_optimistic:
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_set_cover_tilt_position(self, **kwargs):
@ -322,7 +322,7 @@ class CoverTemplate(CoverDevice):
self._tilt_value = kwargs[ATTR_TILT_POSITION]
yield from self._tilt_script.async_run({"tilt": self._tilt_value})
if self._tilt_optimistic:
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_update(self):

View File

@ -209,7 +209,7 @@ class EightSleepUserEntity(Entity):
@callback
def async_eight_user_update():
"""Update callback."""
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
async_dispatcher_connect(
self.hass, SIGNAL_UPDATE_USER, async_eight_user_update)
@ -233,7 +233,7 @@ class EightSleepHeatEntity(Entity):
@callback
def async_eight_heat_update():
"""Update callback."""
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
async_dispatcher_connect(
self.hass, SIGNAL_UPDATE_HEAT, async_eight_heat_update)

View File

@ -160,7 +160,7 @@ class MqttFan(FanEntity):
self._state = True
elif payload == self._payload[STATE_OFF]:
self._state = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._topic[CONF_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
@ -177,7 +177,7 @@ class MqttFan(FanEntity):
self._speed = SPEED_MEDIUM
elif payload == self._payload[SPEED_HIGH]:
self._speed = SPEED_HIGH
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._topic[CONF_SPEED_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
@ -193,7 +193,7 @@ class MqttFan(FanEntity):
self._oscillation = True
elif payload == self._payload[OSCILLATE_OFF_PAYLOAD]:
self._oscillation = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._topic[CONF_OSCILLATION_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
@ -287,7 +287,7 @@ class MqttFan(FanEntity):
if self._optimistic_speed:
self._speed = speed
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_oscillate(self, oscillating: bool) -> None:
@ -309,4 +309,4 @@ class MqttFan(FanEntity):
if self._optimistic_oscillation:
self._oscillation = oscillating
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()

View File

@ -242,7 +242,7 @@ class FFmpegBase(Entity):
def async_start_handle(event):
"""Start FFmpeg process."""
yield from self._async_start_ffmpeg(None)
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_START, async_start_handle)

View File

@ -220,7 +220,7 @@ class MqttLight(Light):
self._state = True
elif payload == self._payload['off']:
self._state = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._topic[CONF_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
@ -233,7 +233,7 @@ class MqttLight(Light):
device_value = float(templates[CONF_BRIGHTNESS](payload))
percent_bright = device_value / self._brightness_scale
self._brightness = int(percent_bright * 255)
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._topic[CONF_BRIGHTNESS_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
@ -250,7 +250,7 @@ class MqttLight(Light):
"""Handle new MQTT messages for RGB."""
self._rgb = [int(val) for val in
templates[CONF_RGB](payload).split(',')]
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._topic[CONF_RGB_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
@ -266,7 +266,7 @@ class MqttLight(Light):
def color_temp_received(topic, payload, qos):
"""Handle new MQTT messages for color temperature."""
self._color_temp = int(templates[CONF_COLOR_TEMP](payload))
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._topic[CONF_COLOR_TEMP_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
@ -282,7 +282,7 @@ class MqttLight(Light):
def effect_received(topic, payload, qos):
"""Handle new MQTT messages for effect."""
self._effect = templates[CONF_EFFECT](payload)
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._topic[CONF_EFFECT_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
@ -300,7 +300,7 @@ class MqttLight(Light):
device_value = float(templates[CONF_WHITE_VALUE](payload))
percent_white = device_value / self._white_value_scale
self._white_value = int(percent_white * 255)
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._topic[CONF_WHITE_VALUE_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
@ -317,7 +317,7 @@ class MqttLight(Light):
"""Handle new MQTT messages for color."""
self._xy = [float(val) for val in
templates[CONF_XY](payload).split(',')]
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._topic[CONF_XY_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
@ -483,7 +483,7 @@ class MqttLight(Light):
should_update = True
if should_update:
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_turn_off(self, **kwargs):
@ -498,4 +498,4 @@ class MqttLight(Light):
if self._optimistic:
# Optimistically assume that switch has changed state.
self._state = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()

View File

@ -226,7 +226,7 @@ class MqttJson(Light):
except ValueError:
_LOGGER.warning("Invalid XY color value received")
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._topic[CONF_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
@ -373,7 +373,7 @@ class MqttJson(Light):
should_update = True
if should_update:
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_turn_off(self, **kwargs):
@ -393,4 +393,4 @@ class MqttJson(Light):
if self._optimistic:
# Optimistically assume that the light has changed state.
self._state = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()

View File

@ -211,7 +211,7 @@ class MqttTemplate(Light):
else:
_LOGGER.warning("Unsupported effect value received")
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._topics[CONF_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
@ -323,7 +323,7 @@ class MqttTemplate(Light):
)
if self._optimistic:
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_turn_off(self, **kwargs):
@ -345,7 +345,7 @@ class MqttTemplate(Light):
)
if self._optimistic:
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@property
def supported_features(self):

View File

@ -155,7 +155,7 @@ class LightTemplate(Light):
@callback
def template_light_state_listener(entity, old_state, new_state):
"""Handle target device state changes."""
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
@callback
def template_light_startup(event):
@ -165,7 +165,7 @@ class LightTemplate(Light):
async_track_state_change(
self.hass, self._entities, template_light_state_listener)
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_START, template_light_startup)
@ -192,7 +192,7 @@ class LightTemplate(Light):
self.hass.async_add_job(self._on_script.async_run())
if optimistic_set:
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_turn_off(self, **kwargs):
@ -200,7 +200,7 @@ class LightTemplate(Light):
self.hass.async_add_job(self._off_script.async_run())
if self._template is None:
self._state = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_update(self):

View File

@ -105,19 +105,19 @@ class Light(zha.Entity, light.Light):
duration
)
self._state = 1
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
return
yield from self._endpoint.on_off.on()
self._state = 1
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_turn_off(self, **kwargs):
"""Turn the entity off."""
yield from self._endpoint.on_off.off()
self._state = 0
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@property
def brightness(self):

View File

@ -93,7 +93,7 @@ class MqttLock(LockDevice):
elif payload == self._payload_unlock:
self._state = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._state_topic is None:
# Force into optimistic mode.
@ -134,7 +134,7 @@ class MqttLock(LockDevice):
if self._optimistic:
# Optimistically assume that switch has changed state.
self._state = True
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_unlock(self, **kwargs):
@ -148,4 +148,4 @@ class MqttLock(LockDevice):
if self._optimistic:
# Optimistically assume that switch has changed state.
self._state = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()

View File

@ -111,7 +111,7 @@ class MailboxEntity(Entity):
@callback
def _mailbox_updated(event):
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
hass.bus.async_listen(EVENT, _mailbox_updated)

View File

@ -112,7 +112,7 @@ class AppleTvDevice(MediaPlayerDevice):
def playstatus_update(self, updater, playing):
"""Print what is currently playing when it changes."""
self._playing = playing
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@callback
def playstatus_error(self, updater, exception):
@ -126,7 +126,7 @@ class AppleTvDevice(MediaPlayerDevice):
# implemented here later.
updater.start(initial_delay=10)
self._playing = None
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@property
def media_content_type(self):

View File

@ -159,7 +159,7 @@ class EmbyDevice(MediaPlayerDevice):
self.media_status_last_position = None
self.media_status_received = None
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@property
def hidden(self):

View File

@ -325,7 +325,7 @@ class KodiDevice(MediaPlayerDevice):
# If a new item is playing, force a complete refresh
force_refresh = data['item']['id'] != self._item.get('id')
self.hass.async_add_job(self.async_update_ha_state(force_refresh))
self.async_schedule_update_ha_state(force_refresh)
@callback
def async_on_stop(self, sender, data):
@ -337,14 +337,14 @@ class KodiDevice(MediaPlayerDevice):
self._players = []
self._properties = {}
self._item = {}
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@callback
def async_on_volume_changed(self, sender, data):
"""Handle the volume changes."""
self._app_properties['volume'] = data['volume']
self._app_properties['muted'] = data['muted']
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@callback
def async_on_quit(self, sender, data):
@ -403,7 +403,7 @@ class KodiDevice(MediaPlayerDevice):
# to reconnect on the next poll.
pass
# Update HA state after Kodi disconnects
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
# Create a task instead of adding a tracking job, since this task will
# run until the websocket connection is closed.

View File

@ -159,19 +159,19 @@ class SnapcastGroupDevice(MediaPlayerDevice):
streams = self._group.streams_by_name()
if source in streams:
yield from self._group.set_stream(streams[source].identifier)
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_mute_volume(self, mute):
"""Send the mute command."""
yield from self._group.set_muted(mute)
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_set_volume_level(self, volume):
"""Set the volume level."""
yield from self._group.set_volume(round(volume * 100))
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
def snapshot(self):
"""Snapshot the group state."""
@ -235,13 +235,13 @@ class SnapcastClientDevice(MediaPlayerDevice):
def async_mute_volume(self, mute):
"""Send the mute command."""
yield from self._client.set_muted(mute)
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_set_volume_level(self, volume):
"""Set the volume level."""
yield from self._client.set_volume(round(volume * 100))
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
def snapshot(self):
"""Snapshot the client state."""

View File

@ -148,7 +148,7 @@ class UniversalMediaPlayer(MediaPlayerDevice):
@callback
def async_on_dependency_update(*_):
"""Update ha state when dependencies update."""
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
depend = copy(children)
for entity in attributes.values():

View File

@ -637,7 +637,7 @@ class MySensorsEntity(MySensorsDevice, Entity):
def _async_update_callback(self):
"""Update the entity."""
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
@asyncio.coroutine
def async_added_to_hass(self):

View File

@ -212,7 +212,7 @@ class Plant(Entity):
self._icon = 'mdi:thumb-up'
self._problems = PROBLEM_NONE
_LOGGER.debug("New data processed")
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@property
def should_poll(self):

View File

@ -272,7 +272,7 @@ class RflinkDevice(Entity):
self._handle_event(event)
# Propagate changes through ha
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
# Put command onto bus for user to subscribe to
if self._should_fire_event and identify_event_type(

View File

@ -50,7 +50,7 @@ class AlarmDecoderSensor(Entity):
def _message_callback(self, message):
if self._display != message.text:
self._display = message.text
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@property
def icon(self):

View File

@ -123,7 +123,7 @@ class ArwnSensor(Entity):
"""Update the sensor with the most recent event."""
self.event = {}
self.event.update(event)
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@property
def state(self):

View File

@ -77,4 +77,4 @@ class EnvisalinkSensor(EnvisalinkDevice, Entity):
def _update_callback(self, partition):
"""Update the partition state in HA, if needed."""
if partition is None or int(partition) == self._partition_number:
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()

View File

@ -100,7 +100,7 @@ class MqttSensor(Entity):
payload = self._template.async_render_with_possible_json_value(
payload, self._state)
self._state = payload
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
return mqtt.async_subscribe(
self.hass, self._state_topic, message_received, self._qos)
@ -110,7 +110,7 @@ class MqttSensor(Entity):
"""Triggered when value is expired."""
self._expiration_trigger = None
self._state = STATE_UNKNOWN
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@property
def should_poll(self):

View File

@ -96,7 +96,7 @@ class MQTTRoomSensor(Entity):
self._distance = distance
self._updated = dt.utcnow()
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@callback
def message_received(topic, payload, qos):

View File

@ -62,7 +62,7 @@ class TOTPSensor(Entity):
@callback
def _call_loop(self):
self._state = self._otp.now()
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
# Update must occur at even TIME_STEP, e.g. 12:00:00, 12:00:30,
# 12:01:00, etc. in order to have synced time (see RFC6238)

View File

@ -100,7 +100,7 @@ class SensorTemplate(Entity):
@callback
def template_sensor_state_listener(entity, old_state, new_state):
"""Handle device state changes."""
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
@callback
def template_sensor_startup(event):
@ -108,7 +108,7 @@ class SensorTemplate(Entity):
async_track_state_change(
self.hass, self._entities, template_sensor_state_listener)
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_START, template_sensor_startup)

View File

@ -129,6 +129,6 @@ class TimeDateSensor(Entity):
def point_in_time_listener(self, time_date):
"""Get the latest data and update state."""
self._update_internal_state(time_date)
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
async_track_point_in_utc_time(
self.hass, self.point_in_time_listener, self.get_next_interval())

View File

@ -141,4 +141,4 @@ class TorqueSensor(Entity):
def async_on_update(self, value):
"""Receive an update."""
self._state = value
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()

View File

@ -126,7 +126,7 @@ class Sun(Entity):
"""Run when the state of the sun has changed."""
self.update_sun_position(now)
self.update_as_of(now)
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
# Schedule next update at next_change+1 second so sun state has changed
async_track_point_in_utc_time(
@ -137,4 +137,4 @@ class Sun(Entity):
def timer_update(self, time):
"""Needed to update solar elevation and azimuth."""
self.update_sun_position(time)
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()

View File

@ -72,7 +72,7 @@ class IPWebcamSettingsSwitch(AndroidIPCamEntity, SwitchDevice):
else:
yield from self._ipcam.change_setting(self._setting, True)
self._state = True
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_turn_off(self, **kwargs):
@ -86,7 +86,7 @@ class IPWebcamSettingsSwitch(AndroidIPCamEntity, SwitchDevice):
else:
yield from self._ipcam.change_setting(self._setting, False)
self._state = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@property
def icon(self):

View File

@ -111,7 +111,7 @@ class MqttSwitch(SwitchDevice):
elif payload == self._payload_off:
self._state = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@callback
def availability_message_received(topic, payload, qos):
@ -121,7 +121,7 @@ class MqttSwitch(SwitchDevice):
elif payload == self._payload_not_available:
self._available = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
if self._state_topic is None:
# Force into optimistic mode.
@ -173,7 +173,7 @@ class MqttSwitch(SwitchDevice):
if self._optimistic:
# Optimistically assume that switch has changed state.
self._state = True
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_turn_off(self, **kwargs):
@ -187,4 +187,4 @@ class MqttSwitch(SwitchDevice):
if self._optimistic:
# Optimistically assume that switch has changed state.
self._state = False
self.hass.async_add_job(self.async_update_ha_state())
self.async_schedule_update_ha_state()

View File

@ -103,7 +103,7 @@ class SwitchTemplate(SwitchDevice):
@callback
def template_switch_state_listener(entity, old_state, new_state):
"""Handle target device state changes."""
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
@callback
def template_switch_startup(event):
@ -111,7 +111,7 @@ class SwitchTemplate(SwitchDevice):
async_track_state_change(
self.hass, self._entities, template_switch_state_listener)
self.hass.async_add_job(self.async_update_ha_state(True))
self.async_schedule_update_ha_state(True)
self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_START, template_switch_startup)

View File

@ -297,10 +297,14 @@ class Entity(object):
def schedule_update_ha_state(self, force_refresh=False):
"""Schedule a update ha state change task.
That is only needed on executor to not block.
That avoid executor dead looks.
"""
self.hass.add_job(self.async_update_ha_state(force_refresh))
def async_schedule_update_ha_state(self, force_refresh=False):
"""Schedule a update ha state change task."""
self.hass.async_add_job(self.async_update_ha_state(force_refresh))
def remove(self) -> None:
"""Remove entity from HASS."""
run_coroutine_threadsafe(

View File

@ -191,3 +191,25 @@ def test_warn_slow_update_with_exception(hass):
assert mock_call().cancel.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."""
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
mock_entity.async_schedule_update_ha_state(True)
yield from hass.async_block_till_done()
assert update_call is True