Migrate callbacks to use schedule_update_ha_state (#4426)

* Migrate callbacks to use schedule_update_ha_state

* Migrate MQTT sensor callback to async

* Migrate wemo to not update inside schedule_update_ha_state

* Make MQTT switch async

* Fix nx584 test

* Migrate tellstick callback

* Migrate vera callback

* Alarm control panel - manual: use async callbacks

* Run the switch rest tests that work
This commit is contained in:
Paulus Schoutsen 2016-11-17 07:34:46 -08:00 committed by GitHub
parent 38d201a54a
commit 0f59bb208c
19 changed files with 54 additions and 43 deletions

View file

@ -129,7 +129,7 @@ class ManualAlarm(alarm.AlarmControlPanel):
if self._pending_time: if self._pending_time:
track_point_in_time( track_point_in_time(
self._hass, self.update_ha_state, self._hass, self.async_update_ha_state,
self._state_ts + self._pending_time) self._state_ts + self._pending_time)
def alarm_arm_away(self, code=None): def alarm_arm_away(self, code=None):
@ -143,7 +143,7 @@ class ManualAlarm(alarm.AlarmControlPanel):
if self._pending_time: if self._pending_time:
track_point_in_time( track_point_in_time(
self._hass, self.update_ha_state, self._hass, self.async_update_ha_state,
self._state_ts + self._pending_time) self._state_ts + self._pending_time)
def alarm_trigger(self, code=None): def alarm_trigger(self, code=None):
@ -155,11 +155,11 @@ class ManualAlarm(alarm.AlarmControlPanel):
if self._trigger_time: if self._trigger_time:
track_point_in_time( track_point_in_time(
self._hass, self.update_ha_state, self._hass, self.async_update_ha_state,
self._state_ts + self._pending_time) self._state_ts + self._pending_time)
track_point_in_time( track_point_in_time(
self._hass, self.update_ha_state, self._hass, self.async_update_ha_state,
self._state_ts + self._pending_time + self._trigger_time) self._state_ts + self._pending_time + self._trigger_time)
def _validate_code(self, code, state): def _validate_code(self, code, state):

View file

@ -138,7 +138,7 @@ class FFmpegBinarySensor(BinarySensorDevice):
def _callback(self, state): def _callback(self, state):
"""HA-FFmpeg callback for noise detection.""" """HA-FFmpeg callback for noise detection."""
self._state = state self._state = state
self.update_ha_state() self.schedule_update_ha_state()
def _start_ffmpeg(self, config): def _start_ffmpeg(self, config):
"""Start a FFmpeg instance.""" """Start a FFmpeg instance."""

View file

@ -8,6 +8,7 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback
import homeassistant.components.mqtt as mqtt import homeassistant.components.mqtt as mqtt
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
BinarySensorDevice, SENSOR_CLASSES) BinarySensorDevice, SENSOR_CLASSES)
@ -66,17 +67,18 @@ class MqttBinarySensor(BinarySensorDevice):
self._payload_off = payload_off self._payload_off = payload_off
self._qos = qos self._qos = qos
@callback
def message_received(topic, payload, qos): def message_received(topic, payload, qos):
"""A new MQTT message has been received.""" """A new MQTT message has been received."""
if value_template is not None: if value_template is not None:
payload = value_template.render_with_possible_json_value( payload = value_template.async_render_with_possible_json_value(
payload) payload)
if payload == self._payload_on: if payload == self._payload_on:
self._state = True self._state = True
self.update_ha_state() hass.async_add_job(self.async_update_ha_state())
elif payload == self._payload_off: elif payload == self._payload_off:
self._state = False self._state = False
self.update_ha_state() hass.async_add_job(self.async_update_ha_state())
mqtt.subscribe(hass, self._state_topic, message_received, self._qos) mqtt.subscribe(hass, self._state_topic, message_received, self._qos)

View file

@ -123,7 +123,7 @@ class NX584Watcher(threading.Thread):
if not zone_sensor: if not zone_sensor:
return return
zone_sensor._zone['state'] = event['zone_state'] zone_sensor._zone['state'] = event['zone_state']
zone_sensor.update_ha_state() zone_sensor.schedule_update_ha_state()
def _process_events(self, events): def _process_events(self, events):
for event in events: for event in events:

View file

@ -72,7 +72,7 @@ class RPiGPIOBinarySensor(BinarySensorDevice):
def read_gpio(port): def read_gpio(port):
"""Read state from GPIO.""" """Read state from GPIO."""
self._state = rpi_gpio.read_input(self._port) self._state = rpi_gpio.read_input(self._port)
self.update_ha_state() self.schedule_update_ha_state()
rpi_gpio.edge_detect(self._port, read_gpio, self._bouncetime) rpi_gpio.edge_detect(self._port, read_gpio, self._bouncetime)

View file

@ -4,8 +4,11 @@ A sensor that monitors trands in other components.
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.trend/ https://home-assistant.io/components/sensor.trend/
""" """
import asyncio
import logging import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
@ -87,13 +90,12 @@ class SensorTrend(BinarySensorDevice):
self.from_state = None self.from_state = None
self.to_state = None self.to_state = None
self.update() @callback
def trend_sensor_state_listener(entity, old_state, new_state): def trend_sensor_state_listener(entity, old_state, new_state):
"""Called when the target device changes state.""" """Called when the target device changes state."""
self.from_state = old_state self.from_state = old_state
self.to_state = new_state self.to_state = new_state
self.update_ha_state(True) hass.async_add_job(self.async_update_ha_state(True))
track_state_change(hass, target_entity, track_state_change(hass, target_entity,
trend_sensor_state_listener) trend_sensor_state_listener)
@ -118,7 +120,8 @@ class SensorTrend(BinarySensorDevice):
"""No polling needed.""" """No polling needed."""
return False return False
def update(self): @asyncio.coroutine
def async_update(self):
"""Get the latest data and update the states.""" """Get the latest data and update the states."""
if self.from_state is None or self.to_state is None: if self.from_state is None or self.to_state is None:
return return

View file

@ -45,10 +45,10 @@ class WemoBinarySensor(BinarySensorDevice):
_LOGGER.info( _LOGGER.info(
'Subscription update for %s', 'Subscription update for %s',
_device) _device)
self.update()
if not hasattr(self, 'hass'): if not hasattr(self, 'hass'):
self.update()
return return
self.update_ha_state(True) self.schedule_update_ha_state()
@property @property
def should_poll(self): def should_poll(self):

View file

@ -96,7 +96,7 @@ class ZWaveBinarySensor(BinarySensorDevice, zwave.ZWaveDeviceEntity, Entity):
"""Called when a value has changed on the network.""" """Called when a value has changed on the network."""
if self._value.value_id == value.value_id or \ if self._value.value_id == value.value_id or \
self._value.node == value.node: self._value.node == value.node:
self.update_ha_state() self.schedule_update_ha_state()
class ZWaveTriggerSensor(ZWaveBinarySensor, Entity): class ZWaveTriggerSensor(ZWaveBinarySensor, Entity):
@ -112,19 +112,19 @@ class ZWaveTriggerSensor(ZWaveBinarySensor, Entity):
# If it's active make sure that we set the timeout tracker # If it's active make sure that we set the timeout tracker
if sensor_value.data: if sensor_value.data:
track_point_in_time( track_point_in_time(
self._hass, self.update_ha_state, self._hass, self.async_update_ha_state,
self.invalidate_after) self.invalidate_after)
def value_changed(self, value): def value_changed(self, value):
"""Called when a value has changed on the network.""" """Called when a value has changed on the network."""
if self._value.value_id == value.value_id: if self._value.value_id == value.value_id:
self.update_ha_state() self.schedule_update_ha_state()
if value.data: if value.data:
# only allow this value to be true for re_arm secs # only allow this value to be true for re_arm secs
self.invalidate_after = dt_util.utcnow() + datetime.timedelta( self.invalidate_after = dt_util.utcnow() + datetime.timedelta(
seconds=self.re_arm_sec) seconds=self.re_arm_sec)
track_point_in_time( track_point_in_time(
self._hass, self.update_ha_state, self._hass, self.async_update_ha_state,
self.invalidate_after) self.invalidate_after)
@property @property

View file

@ -158,7 +158,7 @@ class GenericThermostat(ClimateDevice):
self._update_temp(new_state) self._update_temp(new_state)
self._control_heating() self._control_heating()
self.update_ha_state() self.schedule_update_ha_state()
def _update_temp(self, state): def _update_temp(self, state):
"""Update thermostat with latest state from sensor.""" """Update thermostat with latest state from sensor."""

View file

@ -89,7 +89,7 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
if self._value.value_id == value.value_id or \ if self._value.value_id == value.value_id or \
self._value.node == value.node: self._value.node == value.node:
self.update_properties() self.update_properties()
self.update_ha_state() self.schedule_update_ha_state()
_LOGGER.debug("Value changed on network %s", value) _LOGGER.debug("Value changed on network %s", value)
def update_properties(self): def update_properties(self):

View file

@ -8,6 +8,7 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback
import homeassistant.components.mqtt as mqtt import homeassistant.components.mqtt as mqtt
from homeassistant.components.cover import CoverDevice from homeassistant.components.cover import CoverDevice
from homeassistant.const import ( from homeassistant.const import (
@ -89,29 +90,30 @@ class MqttCover(CoverDevice):
self._retain = retain self._retain = retain
self._optimistic = optimistic or state_topic is None self._optimistic = optimistic or state_topic is None
@callback
def message_received(topic, payload, qos): def message_received(topic, payload, qos):
"""A new MQTT message has been received.""" """A new MQTT message has been received."""
if value_template is not None: if value_template is not None:
payload = value_template.render_with_possible_json_value( payload = value_template.async_render_with_possible_json_value(
payload) payload)
if payload == self._state_open: if payload == self._state_open:
self._state = False self._state = False
_LOGGER.warning("state=%s", int(self._state)) hass.async_add_job(self.async_update_ha_state())
self.update_ha_state()
elif payload == self._state_closed: elif payload == self._state_closed:
self._state = True self._state = True
self.update_ha_state() hass.async_add_job(self.async_update_ha_state())
elif payload.isnumeric() and 0 <= int(payload) <= 100: elif payload.isnumeric() and 0 <= int(payload) <= 100:
if int(payload) > 0: if int(payload) > 0:
self._state = False self._state = False
else: else:
self._state = True self._state = True
self._position = int(payload) self._position = int(payload)
self.update_ha_state() hass.async_add_job(self.async_update_ha_state())
else: else:
_LOGGER.warning( _LOGGER.warning(
"Payload is not True, False, or integer (0-100): %s", "Payload is not True, False, or integer (0-100): %s",
payload) payload)
if self._state_topic is None: if self._state_topic is None:
# Force into optimistic mode. # Force into optimistic mode.
self._optimistic = True self._optimistic = True

View file

@ -280,9 +280,9 @@ class CastDevice(MediaPlayerDevice):
def new_cast_status(self, status): def new_cast_status(self, status):
"""Called when a new cast status is received.""" """Called when a new cast status is received."""
self.cast_status = status self.cast_status = status
self.update_ha_state() self.schedule_update_ha_state()
def new_media_status(self, status): def new_media_status(self, status):
"""Called when a new media status is received.""" """Called when a new media status is received."""
self.media_status = status self.media_status = status
self.update_ha_state() self.schedule_update_ha_state()

View file

@ -8,6 +8,7 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback
from homeassistant.components.mqtt import CONF_STATE_TOPIC, CONF_QOS from homeassistant.components.mqtt import CONF_STATE_TOPIC, CONF_QOS
from homeassistant.const import ( from homeassistant.const import (
CONF_NAME, CONF_VALUE_TEMPLATE, STATE_UNKNOWN, CONF_UNIT_OF_MEASUREMENT) CONF_NAME, CONF_VALUE_TEMPLATE, STATE_UNKNOWN, CONF_UNIT_OF_MEASUREMENT)
@ -55,13 +56,14 @@ class MqttSensor(Entity):
self._qos = qos self._qos = qos
self._unit_of_measurement = unit_of_measurement self._unit_of_measurement = unit_of_measurement
@callback
def message_received(topic, payload, qos): def message_received(topic, payload, qos):
"""A new MQTT message has been received.""" """A new MQTT message has been received."""
if value_template is not None: if value_template is not None:
payload = value_template.render_with_possible_json_value( payload = value_template.async_render_with_possible_json_value(
payload, self._state) payload, self._state)
self._state = payload self._state = payload
self.update_ha_state() hass.async_add_job(self.async_update_ha_state())
mqtt.subscribe(hass, self._state_topic, message_received, self._qos) mqtt.subscribe(hass, self._state_topic, message_received, self._qos)

View file

@ -8,6 +8,7 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback
from homeassistant.components.mqtt import ( from homeassistant.components.mqtt import (
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN) CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN)
from homeassistant.components.switch import SwitchDevice from homeassistant.components.switch import SwitchDevice
@ -71,17 +72,18 @@ class MqttSwitch(SwitchDevice):
self._payload_off = payload_off self._payload_off = payload_off
self._optimistic = optimistic self._optimistic = optimistic
@callback
def message_received(topic, payload, qos): def message_received(topic, payload, qos):
"""A new MQTT message has been received.""" """A new MQTT message has been received."""
if value_template is not None: if value_template is not None:
payload = value_template.render_with_possible_json_value( payload = value_template.async_render_with_possible_json_value(
payload) payload)
if payload == self._payload_on: if payload == self._payload_on:
self._state = True self._state = True
self.update_ha_state() hass.async_add_job(self.async_update_ha_state())
elif payload == self._payload_off: elif payload == self._payload_off:
self._state = False self._state = False
self.update_ha_state() hass.async_add_job(self.async_update_ha_state())
if self._state_topic is None: if self._state_topic is None:
# Force into optimistic mode. # Force into optimistic mode.
@ -117,7 +119,7 @@ class MqttSwitch(SwitchDevice):
if self._optimistic: if self._optimistic:
# Optimistically assume that switch has changed state. # Optimistically assume that switch has changed state.
self._state = True self._state = True
self.schedule_update_ha_state() self.update_ha_state()
def turn_off(self, **kwargs): def turn_off(self, **kwargs):
"""Turn the device off.""" """Turn the device off."""
@ -126,4 +128,4 @@ class MqttSwitch(SwitchDevice):
if self._optimistic: if self._optimistic:
# Optimistically assume that switch has changed state. # Optimistically assume that switch has changed state.
self._state = False self._state = False
self.schedule_update_ha_state() self.update_ha_state()

View file

@ -63,10 +63,10 @@ class WemoSwitch(SwitchDevice):
_LOGGER.info( _LOGGER.info(
'Subscription update for %s', 'Subscription update for %s',
_device) _device)
self.update()
if not hasattr(self, 'hass'): if not hasattr(self, 'hass'):
self.update()
return return
self.update_ha_state(True) self.schedule_update_ha_state()
@property @property
def should_poll(self): def should_poll(self):

View file

@ -111,7 +111,7 @@ class TellstickRegistry(object):
entity = self._id_to_entity_map.get(tellstick_id, None) entity = self._id_to_entity_map.get(tellstick_id, None)
if entity is not None: if entity is not None:
entity.set_tellstick_state(method, data) entity.set_tellstick_state(method, data)
entity.update_ha_state() entity.schedule_update_ha_state()
def _setup_device_callback(self, hass, tellcore_lib): def _setup_device_callback(self, hass, tellcore_lib):
"""Register the callback handler.""" """Register the callback handler."""

View file

@ -132,7 +132,8 @@ class VeraDevice(Entity):
self.update() self.update()
def _update_callback(self, _device): def _update_callback(self, _device):
self.update_ha_state(True) self.update()
self.schedule_update_ha_state()
@property @property
def name(self): def name(self):

View file

@ -137,7 +137,7 @@ class TestNX584ZoneSensor(unittest.TestCase):
class TestNX584Watcher(unittest.TestCase): class TestNX584Watcher(unittest.TestCase):
"""Test the NX584 watcher.""" """Test the NX584 watcher."""
@mock.patch.object(nx584.NX584ZoneSensor, 'update_ha_state') @mock.patch.object(nx584.NX584ZoneSensor, 'schedule_update_ha_state')
def test_process_zone_event(self, mock_update): def test_process_zone_event(self, mock_update):
"""Test the processing of zone events.""" """Test the processing of zone events."""
zone1 = {'number': 1, 'name': 'foo', 'state': True} zone1 = {'number': 1, 'name': 'foo', 'state': True}
@ -151,7 +151,7 @@ class TestNX584Watcher(unittest.TestCase):
self.assertFalse(zone1['state']) self.assertFalse(zone1['state'])
self.assertEqual(1, mock_update.call_count) self.assertEqual(1, mock_update.call_count)
@mock.patch.object(nx584.NX584ZoneSensor, 'update_ha_state') @mock.patch.object(nx584.NX584ZoneSensor, 'schedule_update_ha_state')
def test_process_zone_event_missing_zone(self, mock_update): def test_process_zone_event_missing_zone(self, mock_update):
"""Test the processing of zone events with missing zones.""" """Test the processing of zone events with missing zones."""
watcher = nx584.NX584Watcher(None, {}) watcher = nx584.NX584Watcher(None, {})

View file

@ -12,7 +12,6 @@ from homeassistant.bootstrap import setup_component
from tests.common import get_test_home_assistant, assert_setup_component from tests.common import get_test_home_assistant, assert_setup_component
@pytest.mark.skip
class TestRestSwitchSetup(unittest.TestCase): class TestRestSwitchSetup(unittest.TestCase):
"""Tests for setting up the REST switch platform.""" """Tests for setting up the REST switch platform."""