From 0f59bb208c8e412dfde17d20db8f08513a1c5dfa Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 17 Nov 2016 07:34:46 -0800 Subject: [PATCH] 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 --- .../components/alarm_control_panel/manual.py | 8 ++++---- homeassistant/components/binary_sensor/ffmpeg.py | 2 +- homeassistant/components/binary_sensor/mqtt.py | 8 +++++--- homeassistant/components/binary_sensor/nx584.py | 2 +- homeassistant/components/binary_sensor/rpi_gpio.py | 2 +- homeassistant/components/binary_sensor/trend.py | 11 +++++++---- homeassistant/components/binary_sensor/wemo.py | 4 ++-- homeassistant/components/binary_sensor/zwave.py | 8 ++++---- .../components/climate/generic_thermostat.py | 2 +- homeassistant/components/climate/zwave.py | 2 +- homeassistant/components/cover/mqtt.py | 12 +++++++----- homeassistant/components/media_player/cast.py | 4 ++-- homeassistant/components/sensor/mqtt.py | 6 ++++-- homeassistant/components/switch/mqtt.py | 12 +++++++----- homeassistant/components/switch/wemo.py | 4 ++-- homeassistant/components/tellstick.py | 2 +- homeassistant/components/vera.py | 3 ++- tests/components/binary_sensor/test_nx584.py | 4 ++-- tests/components/switch/test_rest.py | 1 - 19 files changed, 54 insertions(+), 43 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/manual.py b/homeassistant/components/alarm_control_panel/manual.py index 9a7efbeaf5a..073d55508ed 100644 --- a/homeassistant/components/alarm_control_panel/manual.py +++ b/homeassistant/components/alarm_control_panel/manual.py @@ -129,7 +129,7 @@ class ManualAlarm(alarm.AlarmControlPanel): if self._pending_time: track_point_in_time( - self._hass, self.update_ha_state, + self._hass, self.async_update_ha_state, self._state_ts + self._pending_time) def alarm_arm_away(self, code=None): @@ -143,7 +143,7 @@ class ManualAlarm(alarm.AlarmControlPanel): if self._pending_time: track_point_in_time( - self._hass, self.update_ha_state, + self._hass, self.async_update_ha_state, self._state_ts + self._pending_time) def alarm_trigger(self, code=None): @@ -155,11 +155,11 @@ class ManualAlarm(alarm.AlarmControlPanel): if self._trigger_time: track_point_in_time( - self._hass, self.update_ha_state, + self._hass, self.async_update_ha_state, self._state_ts + self._pending_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) def _validate_code(self, code, state): diff --git a/homeassistant/components/binary_sensor/ffmpeg.py b/homeassistant/components/binary_sensor/ffmpeg.py index 72140936e18..818a6b5b387 100644 --- a/homeassistant/components/binary_sensor/ffmpeg.py +++ b/homeassistant/components/binary_sensor/ffmpeg.py @@ -138,7 +138,7 @@ class FFmpegBinarySensor(BinarySensorDevice): def _callback(self, state): """HA-FFmpeg callback for noise detection.""" self._state = state - self.update_ha_state() + self.schedule_update_ha_state() def _start_ffmpeg(self, config): """Start a FFmpeg instance.""" diff --git a/homeassistant/components/binary_sensor/mqtt.py b/homeassistant/components/binary_sensor/mqtt.py index 53c8e9a60b6..28d9566b2ab 100644 --- a/homeassistant/components/binary_sensor/mqtt.py +++ b/homeassistant/components/binary_sensor/mqtt.py @@ -8,6 +8,7 @@ import logging import voluptuous as vol +from homeassistant.core import callback import homeassistant.components.mqtt as mqtt from homeassistant.components.binary_sensor import ( BinarySensorDevice, SENSOR_CLASSES) @@ -66,17 +67,18 @@ class MqttBinarySensor(BinarySensorDevice): self._payload_off = payload_off self._qos = qos + @callback def message_received(topic, payload, qos): """A new MQTT message has been received.""" if value_template is not None: - payload = value_template.render_with_possible_json_value( + payload = value_template.async_render_with_possible_json_value( payload) if payload == self._payload_on: self._state = True - self.update_ha_state() + hass.async_add_job(self.async_update_ha_state()) elif payload == self._payload_off: 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) diff --git a/homeassistant/components/binary_sensor/nx584.py b/homeassistant/components/binary_sensor/nx584.py index e158da02f2b..b21e40dc5dd 100644 --- a/homeassistant/components/binary_sensor/nx584.py +++ b/homeassistant/components/binary_sensor/nx584.py @@ -123,7 +123,7 @@ class NX584Watcher(threading.Thread): if not zone_sensor: return zone_sensor._zone['state'] = event['zone_state'] - zone_sensor.update_ha_state() + zone_sensor.schedule_update_ha_state() def _process_events(self, events): for event in events: diff --git a/homeassistant/components/binary_sensor/rpi_gpio.py b/homeassistant/components/binary_sensor/rpi_gpio.py index 13dd7d0b860..03978ac625b 100644 --- a/homeassistant/components/binary_sensor/rpi_gpio.py +++ b/homeassistant/components/binary_sensor/rpi_gpio.py @@ -72,7 +72,7 @@ class RPiGPIOBinarySensor(BinarySensorDevice): def read_gpio(port): """Read state from GPIO.""" 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) diff --git a/homeassistant/components/binary_sensor/trend.py b/homeassistant/components/binary_sensor/trend.py index 2ef9c487d82..7c38d4505ae 100644 --- a/homeassistant/components/binary_sensor/trend.py +++ b/homeassistant/components/binary_sensor/trend.py @@ -4,8 +4,11 @@ A sensor that monitors trands in other components. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.trend/ """ +import asyncio import logging import voluptuous as vol + +from homeassistant.core import callback import homeassistant.helpers.config_validation as cv from homeassistant.components.binary_sensor import ( @@ -87,13 +90,12 @@ class SensorTrend(BinarySensorDevice): self.from_state = None self.to_state = None - self.update() - + @callback def trend_sensor_state_listener(entity, old_state, new_state): """Called when the target device changes state.""" self.from_state = old_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, trend_sensor_state_listener) @@ -118,7 +120,8 @@ class SensorTrend(BinarySensorDevice): """No polling needed.""" return False - def update(self): + @asyncio.coroutine + def async_update(self): """Get the latest data and update the states.""" if self.from_state is None or self.to_state is None: return diff --git a/homeassistant/components/binary_sensor/wemo.py b/homeassistant/components/binary_sensor/wemo.py index 0e3259a3a96..07deea02f6e 100644 --- a/homeassistant/components/binary_sensor/wemo.py +++ b/homeassistant/components/binary_sensor/wemo.py @@ -45,10 +45,10 @@ class WemoBinarySensor(BinarySensorDevice): _LOGGER.info( 'Subscription update for %s', _device) + self.update() if not hasattr(self, 'hass'): - self.update() return - self.update_ha_state(True) + self.schedule_update_ha_state() @property def should_poll(self): diff --git a/homeassistant/components/binary_sensor/zwave.py b/homeassistant/components/binary_sensor/zwave.py index 69688c7e4f6..e99a2625ea2 100644 --- a/homeassistant/components/binary_sensor/zwave.py +++ b/homeassistant/components/binary_sensor/zwave.py @@ -96,7 +96,7 @@ class ZWaveBinarySensor(BinarySensorDevice, zwave.ZWaveDeviceEntity, Entity): """Called when a value has changed on the network.""" if self._value.value_id == value.value_id or \ self._value.node == value.node: - self.update_ha_state() + self.schedule_update_ha_state() 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 sensor_value.data: track_point_in_time( - self._hass, self.update_ha_state, + self._hass, self.async_update_ha_state, self.invalidate_after) def value_changed(self, value): """Called when a value has changed on the network.""" if self._value.value_id == value.value_id: - self.update_ha_state() + self.schedule_update_ha_state() if value.data: # only allow this value to be true for re_arm secs self.invalidate_after = dt_util.utcnow() + datetime.timedelta( seconds=self.re_arm_sec) track_point_in_time( - self._hass, self.update_ha_state, + self._hass, self.async_update_ha_state, self.invalidate_after) @property diff --git a/homeassistant/components/climate/generic_thermostat.py b/homeassistant/components/climate/generic_thermostat.py index baa09439c2c..1a0b20dc11e 100644 --- a/homeassistant/components/climate/generic_thermostat.py +++ b/homeassistant/components/climate/generic_thermostat.py @@ -158,7 +158,7 @@ class GenericThermostat(ClimateDevice): self._update_temp(new_state) self._control_heating() - self.update_ha_state() + self.schedule_update_ha_state() def _update_temp(self, state): """Update thermostat with latest state from sensor.""" diff --git a/homeassistant/components/climate/zwave.py b/homeassistant/components/climate/zwave.py index e0da5d48c5f..5e5d8d4e54a 100755 --- a/homeassistant/components/climate/zwave.py +++ b/homeassistant/components/climate/zwave.py @@ -89,7 +89,7 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice): if self._value.value_id == value.value_id or \ self._value.node == value.node: self.update_properties() - self.update_ha_state() + self.schedule_update_ha_state() _LOGGER.debug("Value changed on network %s", value) def update_properties(self): diff --git a/homeassistant/components/cover/mqtt.py b/homeassistant/components/cover/mqtt.py index 27b30e5e013..44b59133d21 100644 --- a/homeassistant/components/cover/mqtt.py +++ b/homeassistant/components/cover/mqtt.py @@ -8,6 +8,7 @@ import logging import voluptuous as vol +from homeassistant.core import callback import homeassistant.components.mqtt as mqtt from homeassistant.components.cover import CoverDevice from homeassistant.const import ( @@ -89,29 +90,30 @@ class MqttCover(CoverDevice): self._retain = retain self._optimistic = optimistic or state_topic is None + @callback def message_received(topic, payload, qos): """A new MQTT message has been received.""" if value_template is not None: - payload = value_template.render_with_possible_json_value( + payload = value_template.async_render_with_possible_json_value( payload) if payload == self._state_open: self._state = False - _LOGGER.warning("state=%s", int(self._state)) - self.update_ha_state() + hass.async_add_job(self.async_update_ha_state()) elif payload == self._state_closed: self._state = True - self.update_ha_state() + hass.async_add_job(self.async_update_ha_state()) elif payload.isnumeric() and 0 <= int(payload) <= 100: if int(payload) > 0: self._state = False else: self._state = True self._position = int(payload) - self.update_ha_state() + hass.async_add_job(self.async_update_ha_state()) else: _LOGGER.warning( "Payload is not True, False, or integer (0-100): %s", payload) + if self._state_topic is None: # Force into optimistic mode. self._optimistic = True diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 5d6289587be..1ec61cc621a 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -280,9 +280,9 @@ class CastDevice(MediaPlayerDevice): def new_cast_status(self, status): """Called when a new cast status is received.""" self.cast_status = status - self.update_ha_state() + self.schedule_update_ha_state() def new_media_status(self, status): """Called when a new media status is received.""" self.media_status = status - self.update_ha_state() + self.schedule_update_ha_state() diff --git a/homeassistant/components/sensor/mqtt.py b/homeassistant/components/sensor/mqtt.py index ae9eeeafb32..81267cfc45e 100644 --- a/homeassistant/components/sensor/mqtt.py +++ b/homeassistant/components/sensor/mqtt.py @@ -8,6 +8,7 @@ import logging import voluptuous as vol +from homeassistant.core import callback from homeassistant.components.mqtt import CONF_STATE_TOPIC, CONF_QOS from homeassistant.const import ( CONF_NAME, CONF_VALUE_TEMPLATE, STATE_UNKNOWN, CONF_UNIT_OF_MEASUREMENT) @@ -55,13 +56,14 @@ class MqttSensor(Entity): self._qos = qos self._unit_of_measurement = unit_of_measurement + @callback def message_received(topic, payload, qos): """A new MQTT message has been received.""" 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) 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) diff --git a/homeassistant/components/switch/mqtt.py b/homeassistant/components/switch/mqtt.py index 794a0f0ced3..a7dfab62fb4 100644 --- a/homeassistant/components/switch/mqtt.py +++ b/homeassistant/components/switch/mqtt.py @@ -8,6 +8,7 @@ import logging import voluptuous as vol +from homeassistant.core import callback from homeassistant.components.mqtt import ( CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN) from homeassistant.components.switch import SwitchDevice @@ -71,17 +72,18 @@ class MqttSwitch(SwitchDevice): self._payload_off = payload_off self._optimistic = optimistic + @callback def message_received(topic, payload, qos): """A new MQTT message has been received.""" if value_template is not None: - payload = value_template.render_with_possible_json_value( + payload = value_template.async_render_with_possible_json_value( payload) if payload == self._payload_on: self._state = True - self.update_ha_state() + hass.async_add_job(self.async_update_ha_state()) elif payload == self._payload_off: self._state = False - self.update_ha_state() + hass.async_add_job(self.async_update_ha_state()) if self._state_topic is None: # Force into optimistic mode. @@ -117,7 +119,7 @@ class MqttSwitch(SwitchDevice): if self._optimistic: # Optimistically assume that switch has changed state. self._state = True - self.schedule_update_ha_state() + self.update_ha_state() def turn_off(self, **kwargs): """Turn the device off.""" @@ -126,4 +128,4 @@ class MqttSwitch(SwitchDevice): if self._optimistic: # Optimistically assume that switch has changed state. self._state = False - self.schedule_update_ha_state() + self.update_ha_state() diff --git a/homeassistant/components/switch/wemo.py b/homeassistant/components/switch/wemo.py index d4f6b721e9d..2d3d5ea5547 100644 --- a/homeassistant/components/switch/wemo.py +++ b/homeassistant/components/switch/wemo.py @@ -63,10 +63,10 @@ class WemoSwitch(SwitchDevice): _LOGGER.info( 'Subscription update for %s', _device) + self.update() if not hasattr(self, 'hass'): - self.update() return - self.update_ha_state(True) + self.schedule_update_ha_state() @property def should_poll(self): diff --git a/homeassistant/components/tellstick.py b/homeassistant/components/tellstick.py index d2e296d61b6..6d8ad967ad2 100644 --- a/homeassistant/components/tellstick.py +++ b/homeassistant/components/tellstick.py @@ -111,7 +111,7 @@ class TellstickRegistry(object): entity = self._id_to_entity_map.get(tellstick_id, None) if entity is not None: entity.set_tellstick_state(method, data) - entity.update_ha_state() + entity.schedule_update_ha_state() def _setup_device_callback(self, hass, tellcore_lib): """Register the callback handler.""" diff --git a/homeassistant/components/vera.py b/homeassistant/components/vera.py index 6dcea6c9354..c1cc5d7cbf7 100644 --- a/homeassistant/components/vera.py +++ b/homeassistant/components/vera.py @@ -132,7 +132,8 @@ class VeraDevice(Entity): self.update() def _update_callback(self, _device): - self.update_ha_state(True) + self.update() + self.schedule_update_ha_state() @property def name(self): diff --git a/tests/components/binary_sensor/test_nx584.py b/tests/components/binary_sensor/test_nx584.py index 49147279711..6ed2ae476f3 100644 --- a/tests/components/binary_sensor/test_nx584.py +++ b/tests/components/binary_sensor/test_nx584.py @@ -137,7 +137,7 @@ class TestNX584ZoneSensor(unittest.TestCase): class TestNX584Watcher(unittest.TestCase): """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): """Test the processing of zone events.""" zone1 = {'number': 1, 'name': 'foo', 'state': True} @@ -151,7 +151,7 @@ class TestNX584Watcher(unittest.TestCase): self.assertFalse(zone1['state']) 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): """Test the processing of zone events with missing zones.""" watcher = nx584.NX584Watcher(None, {}) diff --git a/tests/components/switch/test_rest.py b/tests/components/switch/test_rest.py index 85a178dcc42..dc6c58db928 100644 --- a/tests/components/switch/test_rest.py +++ b/tests/components/switch/test_rest.py @@ -12,7 +12,6 @@ from homeassistant.bootstrap import setup_component from tests.common import get_test_home_assistant, assert_setup_component -@pytest.mark.skip class TestRestSwitchSetup(unittest.TestCase): """Tests for setting up the REST switch platform."""