From e9e44dbd974220067fa667ca01896b7975a44a6e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 29 Jan 2020 13:59:45 -0800 Subject: [PATCH] Fix callback and async (#31281) * Fix callback and async * Fix a return * Fix test * Fix mqtt tests * Fix some more callbacks --- .../alarm_control_panel/__init__.py | 54 ++---- .../components/anthemav/media_player.py | 4 +- homeassistant/components/api/__init__.py | 1 + .../components/apple_tv/media_player.py | 74 +++----- homeassistant/components/apple_tv/remote.py | 19 +- .../components/asterisk_mbox/mailbox.py | 9 +- .../components/automation/litejet.py | 1 + .../binary_sensor/device_condition.py | 3 +- .../components/broadlink/__init__.py | 105 +++++------ homeassistant/components/camera/__init__.py | 16 +- .../components/climate/device_condition.py | 3 +- homeassistant/components/cover/__init__.py | 96 ++++------ .../components/cover/device_condition.py | 4 +- homeassistant/components/demo/mailbox.py | 2 +- .../device_automation/toggle_entity.py | 3 +- .../device_sun_light_trigger/__init__.py | 26 ++- .../device_tracker/device_condition.py | 4 +- .../components/device_tracker/legacy.py | 27 +-- homeassistant/components/emby/media_player.py | 54 ++---- .../components/esphome/entry_data.py | 5 + homeassistant/components/fan/__init__.py | 42 ++--- .../components/fan/device_condition.py | 4 +- .../components/generic_thermostat/climate.py | 5 +- .../components/google_assistant/helpers.py | 2 + .../components/hangouts/hangouts_bot.py | 3 + .../homekit_controller/air_quality.py | 2 + .../homekit_controller/alarm_control_panel.py | 2 + .../homekit_controller/binary_sensor.py | 2 + .../components/homekit_controller/climate.py | 2 + .../homekit_controller/connection.py | 2 + .../components/homekit_controller/cover.py | 2 + .../components/homekit_controller/fan.py | 2 + .../components/homekit_controller/light.py | 2 + .../components/homekit_controller/lock.py | 2 + .../components/homekit_controller/sensor.py | 2 + .../components/homekit_controller/storage.py | 2 + .../components/homekit_controller/switch.py | 2 + .../components/huawei_lte/device_tracker.py | 2 + homeassistant/components/ihc/util.py | 4 + .../components/image_processing/__init__.py | 9 +- .../components/input_datetime/__init__.py | 1 + homeassistant/components/kira/remote.py | 11 +- homeassistant/components/knx/climate.py | 5 +- homeassistant/components/kodi/media_player.py | 88 ++++------ .../components/light/device_condition.py | 3 +- homeassistant/components/lock/__init__.py | 27 +-- .../components/lock/device_condition.py | 3 +- homeassistant/components/mailbox/__init__.py | 5 +- .../manual_mqtt/alarm_control_panel.py | 12 +- .../components/media_player/__init__.py | 165 +++++++----------- .../media_player/device_condition.py | 3 +- homeassistant/components/mqtt/__init__.py | 42 ++--- homeassistant/components/mqtt/camera.py | 5 +- homeassistant/components/mqtt/server.py | 11 +- .../components/mystrom/binary_sensor.py | 2 + homeassistant/components/notify/__init__.py | 5 +- homeassistant/components/plex/media_player.py | 1 + homeassistant/components/remote/__init__.py | 20 +-- .../components/rest_command/__init__.py | 2 + homeassistant/components/rflink/__init__.py | 8 +- homeassistant/components/rflink/cover.py | 12 +- .../components/russound_rio/media_player.py | 17 +- homeassistant/components/saj/sensor.py | 1 + homeassistant/components/scene/__init__.py | 9 +- .../components/sensor/device_condition.py | 3 +- .../components/shopping_list/__init__.py | 5 +- homeassistant/components/sma/sensor.py | 2 + .../components/squeezebox/media_player.py | 145 ++++++--------- .../components/switch/device_condition.py | 3 +- .../components/switcher_kis/switch.py | 10 +- homeassistant/components/tts/__init__.py | 6 +- .../components/universal/media_player.py | 160 ++++++----------- .../components/vacuum/device_condition.py | 3 +- .../components/volumio/media_player.py | 50 +++--- homeassistant/components/zha/api.py | 2 + homeassistant/components/zha/binary_sensor.py | 1 + homeassistant/components/zha/core/gateway.py | 1 + homeassistant/components/zha/cover.py | 2 + homeassistant/components/zha/entity.py | 3 + homeassistant/components/zha/fan.py | 1 + homeassistant/components/zha/light.py | 1 + homeassistant/components/zha/lock.py | 1 + homeassistant/components/zha/sensor.py | 2 + homeassistant/components/zha/switch.py | 1 + homeassistant/helpers/device_registry.py | 1 + homeassistant/helpers/entity.py | 30 ++-- homeassistant/helpers/restore_state.py | 1 + homeassistant/helpers/script.py | 1 + .../integration/device_condition.py | 4 +- tests/components/mqtt/test_server.py | 8 +- 90 files changed, 627 insertions(+), 883 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index 5fb44a18a0b..67b0309e513 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -121,67 +121,49 @@ class AlarmControlPanel(Entity): """Send disarm command.""" raise NotImplementedError() - def async_alarm_disarm(self, code=None): - """Send disarm command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_executor_job(self.alarm_disarm, code) + async def async_alarm_disarm(self, code=None): + """Send disarm command.""" + await self.hass.async_add_executor_job(self.alarm_disarm, code) def alarm_arm_home(self, code=None): """Send arm home command.""" raise NotImplementedError() - def async_alarm_arm_home(self, code=None): - """Send arm home command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_executor_job(self.alarm_arm_home, code) + async def async_alarm_arm_home(self, code=None): + """Send arm home command.""" + await self.hass.async_add_executor_job(self.alarm_arm_home, code) def alarm_arm_away(self, code=None): """Send arm away command.""" raise NotImplementedError() - def async_alarm_arm_away(self, code=None): - """Send arm away command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_executor_job(self.alarm_arm_away, code) + async def async_alarm_arm_away(self, code=None): + """Send arm away command.""" + await self.hass.async_add_executor_job(self.alarm_arm_away, code) def alarm_arm_night(self, code=None): """Send arm night command.""" raise NotImplementedError() - def async_alarm_arm_night(self, code=None): - """Send arm night command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_executor_job(self.alarm_arm_night, code) + async def async_alarm_arm_night(self, code=None): + """Send arm night command.""" + await self.hass.async_add_executor_job(self.alarm_arm_night, code) def alarm_trigger(self, code=None): """Send alarm trigger command.""" raise NotImplementedError() - def async_alarm_trigger(self, code=None): - """Send alarm trigger command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_executor_job(self.alarm_trigger, code) + async def async_alarm_trigger(self, code=None): + """Send alarm trigger command.""" + await self.hass.async_add_executor_job(self.alarm_trigger, code) def alarm_arm_custom_bypass(self, code=None): """Send arm custom bypass command.""" raise NotImplementedError() - def async_alarm_arm_custom_bypass(self, code=None): - """Send arm custom bypass command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_executor_job(self.alarm_arm_custom_bypass, code) + async def async_alarm_arm_custom_bypass(self, code=None): + """Send arm custom bypass command.""" + await self.hass.async_add_executor_job(self.alarm_arm_custom_bypass, code) @property @abstractmethod diff --git a/homeassistant/components/anthemav/media_player.py b/homeassistant/components/anthemav/media_player.py index f7b385d80a2..f4efd0de355 100644 --- a/homeassistant/components/anthemav/media_player.py +++ b/homeassistant/components/anthemav/media_player.py @@ -20,6 +20,7 @@ from homeassistant.const import ( STATE_OFF, STATE_ON, ) +from homeassistant.core import callback import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) @@ -55,9 +56,10 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= _LOGGER.info("Provisioning Anthem AVR device at %s:%d", host, port) + @callback def async_anthemav_update_callback(message): """Receive notification from transport that new data exists.""" - _LOGGER.info("Received update callback from AVR: %s", message) + _LOGGER.debug("Received update callback from AVR: %s", message) hass.async_create_task(device.async_update_ha_state()) avr = await anthemav.Connection.create( diff --git a/homeassistant/components/api/__init__.py b/homeassistant/components/api/__init__.py index fc2f01d418d..b9638d44d2b 100644 --- a/homeassistant/components/api/__init__.py +++ b/homeassistant/components/api/__init__.py @@ -411,6 +411,7 @@ async def async_services_json(hass): return [{"domain": key, "services": value} for key, value in descriptions.items()] +@ha.callback def async_events_json(hass): """Generate event data to JSONify.""" return [ diff --git a/homeassistant/components/apple_tv/media_player.py b/homeassistant/components/apple_tv/media_player.py index c816be52259..c34a46a8b82 100644 --- a/homeassistant/components/apple_tv/media_player.py +++ b/homeassistant/components/apple_tv/media_player.py @@ -229,62 +229,42 @@ class AppleTvDevice(MediaPlayerDevice): self._playing = None self._power.set_power_on(False) - def async_media_play_pause(self): - """Pause media on media player. + async def async_media_play_pause(self): + """Pause media on media player.""" + if not self._playing: + return + state = self.state + if state == STATE_PAUSED: + await self.atv.remote_control.play() + elif state == STATE_PLAYING: + await self.atv.remote_control.pause() - This method must be run in the event loop and returns a coroutine. - """ + async def async_media_play(self): + """Play media.""" if self._playing: - state = self.state - if state == STATE_PAUSED: - return self.atv.remote_control.play() - if state == STATE_PLAYING: - return self.atv.remote_control.pause() + await self.atv.remote_control.play() - def async_media_play(self): - """Play media. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_media_stop(self): + """Stop the media player.""" if self._playing: - return self.atv.remote_control.play() + await self.atv.remote_control.stop() - def async_media_stop(self): - """Stop the media player. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_media_pause(self): + """Pause the media player.""" if self._playing: - return self.atv.remote_control.stop() + await self.atv.remote_control.pause() - def async_media_pause(self): - """Pause the media player. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_media_next_track(self): + """Send next track command.""" if self._playing: - return self.atv.remote_control.pause() + await self.atv.remote_control.next() - def async_media_next_track(self): - """Send next track command. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_media_previous_track(self): + """Send previous track command.""" if self._playing: - return self.atv.remote_control.next() + await self.atv.remote_control.previous() - def async_media_previous_track(self): - """Send previous track command. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_media_seek(self, position): + """Send seek command.""" if self._playing: - return self.atv.remote_control.previous() - - def async_media_seek(self, position): - """Send seek command. - - This method must be run in the event loop and returns a coroutine. - """ - if self._playing: - return self.atv.remote_control.set_position(position) + await self.atv.remote_control.set_position(position) diff --git a/homeassistant/components/apple_tv/remote.py b/homeassistant/components/apple_tv/remote.py index 1229b756e72..dd784cc449d 100644 --- a/homeassistant/components/apple_tv/remote.py +++ b/homeassistant/components/apple_tv/remote.py @@ -61,17 +61,10 @@ class AppleTVRemote(remote.RemoteDevice): """ self._power.set_power_on(False) - def async_send_command(self, command, **kwargs): - """Send a command to one device. + async def async_send_command(self, command, **kwargs): + """Send a command to one device.""" + for single_command in command: + if not hasattr(self._atv.remote_control, single_command): + continue - This method must be run in the event loop and returns a coroutine. - """ - # Send commands in specified order but schedule only one coroutine - async def _send_commands(): - for single_command in command: - if not hasattr(self._atv.remote_control, single_command): - continue - - await getattr(self._atv.remote_control, single_command)() - - return _send_commands() + await getattr(self._atv.remote_control, single_command)() diff --git a/homeassistant/components/asterisk_mbox/mailbox.py b/homeassistant/components/asterisk_mbox/mailbox.py index 3cd6fe059b6..b3863eeb13f 100644 --- a/homeassistant/components/asterisk_mbox/mailbox.py +++ b/homeassistant/components/asterisk_mbox/mailbox.py @@ -1,4 +1,5 @@ """Support for the Asterisk Voicemail interface.""" +from functools import partial import logging from asterisk_mbox import ServerError @@ -55,7 +56,9 @@ class AsteriskMailbox(Mailbox): client = self.hass.data[ASTERISK_DOMAIN].client try: - return client.mp3(msgid, sync=True) + return await self.hass.async_add_executor_job( + partial(client.mp3, msgid, sync=True) + ) except ServerError as err: raise StreamError(err) @@ -63,9 +66,9 @@ class AsteriskMailbox(Mailbox): """Return a list of the current messages.""" return self.hass.data[ASTERISK_DOMAIN].messages - def async_delete(self, msgid): + async def async_delete(self, msgid): """Delete the specified messages.""" client = self.hass.data[ASTERISK_DOMAIN].client _LOGGER.info("Deleting: %s", msgid) - client.delete(msgid) + await self.hass.async_add_executor_job(client.delete, msgid) return True diff --git a/homeassistant/components/automation/litejet.py b/homeassistant/components/automation/litejet.py index 466fc941a9a..12ffa29b962 100644 --- a/homeassistant/components/automation/litejet.py +++ b/homeassistant/components/automation/litejet.py @@ -92,6 +92,7 @@ async def async_attach_trigger(hass, config, action, automation_info): hass.data["litejet_system"].on_switch_pressed(number, pressed) hass.data["litejet_system"].on_switch_released(number, released) + @callback def async_remove(): """Remove all subscriptions used for this trigger.""" return diff --git a/homeassistant/components/binary_sensor/device_condition.py b/homeassistant/components/binary_sensor/device_condition.py index aa9a9d25e72..63f84b657c1 100644 --- a/homeassistant/components/binary_sensor/device_condition.py +++ b/homeassistant/components/binary_sensor/device_condition.py @@ -5,7 +5,7 @@ import voluptuous as vol from homeassistant.components.device_automation.const import CONF_IS_OFF, CONF_IS_ON from homeassistant.const import ATTR_DEVICE_CLASS, CONF_ENTITY_ID, CONF_FOR, CONF_TYPE -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import condition, config_validation as cv from homeassistant.helpers.entity_registry import ( async_entries_for_device, @@ -232,6 +232,7 @@ async def async_get_conditions( return conditions +@callback def async_condition_from_config( config: ConfigType, config_validation: bool ) -> condition.ConditionCheckerType: diff --git a/homeassistant/components/broadlink/__init__.py b/homeassistant/components/broadlink/__init__.py index 3f9b5cd4597..dd7c02b82ad 100644 --- a/homeassistant/components/broadlink/__init__.py +++ b/homeassistant/components/broadlink/__init__.py @@ -10,6 +10,7 @@ import socket import voluptuous as vol from homeassistant.const import CONF_HOST +from homeassistant.core import callback import homeassistant.helpers.config_validation as cv from homeassistant.util.dt import utcnow @@ -64,67 +65,67 @@ SERVICE_SEND_SCHEMA = vol.Schema( SERVICE_LEARN_SCHEMA = vol.Schema({vol.Required(CONF_HOST): cv.string}) +@callback def async_setup_service(hass, host, device): """Register a device for given host for use in services.""" hass.data.setdefault(DOMAIN, {})[host] = device - if not hass.services.has_service(DOMAIN, SERVICE_LEARN): + if hass.services.has_service(DOMAIN, SERVICE_LEARN): + return - async def _learn_command(call): - """Learn a packet from remote.""" - device = hass.data[DOMAIN][call.data[CONF_HOST]] + async def _learn_command(call): + """Learn a packet from remote.""" + device = hass.data[DOMAIN][call.data[CONF_HOST]] - try: - auth = await hass.async_add_executor_job(device.auth) - except socket.timeout: - _LOGGER.error("Failed to connect to device, timeout") + try: + auth = await hass.async_add_executor_job(device.auth) + except socket.timeout: + _LOGGER.error("Failed to connect to device, timeout") + return + if not auth: + _LOGGER.error("Failed to connect to device") + return + + await hass.async_add_executor_job(device.enter_learning) + + _LOGGER.info("Press the key you want Home Assistant to learn") + start_time = utcnow() + while (utcnow() - start_time) < timedelta(seconds=20): + packet = await hass.async_add_executor_job(device.check_data) + if packet: + data = b64encode(packet).decode("utf8") + log_msg = f"Received packet is: {data}" + _LOGGER.info(log_msg) + hass.components.persistent_notification.async_create( + log_msg, title="Broadlink switch" + ) return - if not auth: - _LOGGER.error("Failed to connect to device") - return - - await hass.async_add_executor_job(device.enter_learning) - - _LOGGER.info("Press the key you want Home Assistant to learn") - start_time = utcnow() - while (utcnow() - start_time) < timedelta(seconds=20): - packet = await hass.async_add_executor_job(device.check_data) - if packet: - data = b64encode(packet).decode("utf8") - log_msg = f"Received packet is: {data}" - _LOGGER.info(log_msg) - hass.components.persistent_notification.async_create( - log_msg, title="Broadlink switch" - ) - return - await asyncio.sleep(1) - _LOGGER.error("No signal was received") - hass.components.persistent_notification.async_create( - "No signal was received", title="Broadlink switch" - ) - - hass.services.async_register( - DOMAIN, SERVICE_LEARN, _learn_command, schema=SERVICE_LEARN_SCHEMA + await asyncio.sleep(1) + _LOGGER.error("No signal was received") + hass.components.persistent_notification.async_create( + "No signal was received", title="Broadlink switch" ) - if not hass.services.has_service(DOMAIN, SERVICE_SEND): + hass.services.async_register( + DOMAIN, SERVICE_LEARN, _learn_command, schema=SERVICE_LEARN_SCHEMA + ) - async def _send_packet(call): - """Send a packet.""" - device = hass.data[DOMAIN][call.data[CONF_HOST]] - packets = call.data[CONF_PACKET] - for packet in packets: - for retry in range(DEFAULT_RETRY): + async def _send_packet(call): + """Send a packet.""" + device = hass.data[DOMAIN][call.data[CONF_HOST]] + packets = call.data[CONF_PACKET] + for packet in packets: + for retry in range(DEFAULT_RETRY): + try: + await hass.async_add_executor_job(device.send_data, packet) + break + except (socket.timeout, ValueError): try: - await hass.async_add_executor_job(device.send_data, packet) - break - except (socket.timeout, ValueError): - try: - await hass.async_add_executor_job(device.auth) - except socket.timeout: - if retry == DEFAULT_RETRY - 1: - _LOGGER.error("Failed to send packet to device") + await hass.async_add_executor_job(device.auth) + except socket.timeout: + if retry == DEFAULT_RETRY - 1: + _LOGGER.error("Failed to send packet to device") - hass.services.async_register( - DOMAIN, SERVICE_SEND, _send_packet, schema=SERVICE_SEND_SCHEMA - ) + hass.services.async_register( + DOMAIN, SERVICE_SEND, _send_packet, schema=SERVICE_SEND_SCHEMA + ) diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index 4fe52a7d164..53c5cf16a98 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -364,19 +364,12 @@ class Camera(Entity): """Return bytes of camera image.""" raise NotImplementedError() - @callback - def async_camera_image(self): - """Return bytes of camera image. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.camera_image) + async def async_camera_image(self): + """Return bytes of camera image.""" + return await self.hass.async_add_job(self.camera_image) async def handle_async_still_stream(self, request, interval): - """Generate an HTTP MJPEG stream from camera images. - - This method must be run in the event loop. - """ + """Generate an HTTP MJPEG stream from camera images.""" return await async_get_still_stream( request, self.async_camera_image, self.content_type, interval ) @@ -386,7 +379,6 @@ class Camera(Entity): This method can be overridden by camera plaforms to proxy a direct stream from the camera. - This method must be run in the event loop. """ return await self.handle_async_still_stream(request, self.frame_interval) diff --git a/homeassistant/components/climate/device_condition.py b/homeassistant/components/climate/device_condition.py index cf393a035ec..8a5b9ceede8 100644 --- a/homeassistant/components/climate/device_condition.py +++ b/homeassistant/components/climate/device_condition.py @@ -11,7 +11,7 @@ from homeassistant.const import ( CONF_ENTITY_ID, CONF_TYPE, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import condition, config_validation as cv, entity_registry from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA from homeassistant.helpers.typing import ConfigType, TemplateVarsType @@ -77,6 +77,7 @@ async def async_get_conditions( return conditions +@callback def async_condition_from_config( config: ConfigType, config_validation: bool ) -> condition.ConditionCheckerType: diff --git a/homeassistant/components/cover/__init__.py b/homeassistant/components/cover/__init__.py index 2fe4022fb39..abefd3263bc 100644 --- a/homeassistant/components/cover/__init__.py +++ b/homeassistant/components/cover/__init__.py @@ -236,23 +236,17 @@ class CoverDevice(Entity): """Open the cover.""" raise NotImplementedError() - def async_open_cover(self, **kwargs): - """Open the cover. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(ft.partial(self.open_cover, **kwargs)) + async def async_open_cover(self, **kwargs): + """Open the cover.""" + await self.hass.async_add_job(ft.partial(self.open_cover, **kwargs)) def close_cover(self, **kwargs: Any) -> None: """Close cover.""" raise NotImplementedError() - def async_close_cover(self, **kwargs): - """Close cover. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(ft.partial(self.close_cover, **kwargs)) + async def async_close_cover(self, **kwargs): + """Close cover.""" + await self.hass.async_add_job(ft.partial(self.close_cover, **kwargs)) def toggle(self, **kwargs: Any) -> None: """Toggle the entity.""" @@ -261,69 +255,52 @@ class CoverDevice(Entity): else: self.close_cover(**kwargs) - def async_toggle(self, **kwargs): - """Toggle the entity. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_toggle(self, **kwargs): + """Toggle the entity.""" if self.is_closed: - return self.async_open_cover(**kwargs) - return self.async_close_cover(**kwargs) + await self.async_open_cover(**kwargs) + else: + await self.async_close_cover(**kwargs) def set_cover_position(self, **kwargs): """Move the cover to a specific position.""" pass - def async_set_cover_position(self, **kwargs): - """Move the cover to a specific position. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(ft.partial(self.set_cover_position, **kwargs)) + async def async_set_cover_position(self, **kwargs): + """Move the cover to a specific position.""" + await self.hass.async_add_job(ft.partial(self.set_cover_position, **kwargs)) def stop_cover(self, **kwargs): """Stop the cover.""" pass - def async_stop_cover(self, **kwargs): - """Stop the cover. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(ft.partial(self.stop_cover, **kwargs)) + async def async_stop_cover(self, **kwargs): + """Stop the cover.""" + await self.hass.async_add_job(ft.partial(self.stop_cover, **kwargs)) def open_cover_tilt(self, **kwargs: Any) -> None: """Open the cover tilt.""" pass - def async_open_cover_tilt(self, **kwargs): - """Open the cover tilt. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(ft.partial(self.open_cover_tilt, **kwargs)) + async def async_open_cover_tilt(self, **kwargs): + """Open the cover tilt.""" + await self.hass.async_add_job(ft.partial(self.open_cover_tilt, **kwargs)) def close_cover_tilt(self, **kwargs: Any) -> None: """Close the cover tilt.""" pass - def async_close_cover_tilt(self, **kwargs): - """Close the cover tilt. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(ft.partial(self.close_cover_tilt, **kwargs)) + async def async_close_cover_tilt(self, **kwargs): + """Close the cover tilt.""" + await self.hass.async_add_job(ft.partial(self.close_cover_tilt, **kwargs)) def set_cover_tilt_position(self, **kwargs): """Move the cover tilt to a specific position.""" pass - def async_set_cover_tilt_position(self, **kwargs): - """Move the cover tilt to a specific position. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job( + async def async_set_cover_tilt_position(self, **kwargs): + """Move the cover tilt to a specific position.""" + await self.hass.async_add_job( ft.partial(self.set_cover_tilt_position, **kwargs) ) @@ -331,12 +308,9 @@ class CoverDevice(Entity): """Stop the cover.""" pass - def async_stop_cover_tilt(self, **kwargs): - """Stop the cover. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(ft.partial(self.stop_cover_tilt, **kwargs)) + async def async_stop_cover_tilt(self, **kwargs): + """Stop the cover.""" + await self.hass.async_add_job(ft.partial(self.stop_cover_tilt, **kwargs)) def toggle_tilt(self, **kwargs: Any) -> None: """Toggle the entity.""" @@ -345,11 +319,9 @@ class CoverDevice(Entity): else: self.close_cover_tilt(**kwargs) - def async_toggle_tilt(self, **kwargs): - """Toggle the entity. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_toggle_tilt(self, **kwargs): + """Toggle the entity.""" if self.current_cover_tilt_position == 0: - return self.async_open_cover_tilt(**kwargs) - return self.async_close_cover_tilt(**kwargs) + await self.async_open_cover_tilt(**kwargs) + else: + await self.async_close_cover_tilt(**kwargs) diff --git a/homeassistant/components/cover/device_condition.py b/homeassistant/components/cover/device_condition.py index ec6da84e5f6..7c6dc5fed72 100644 --- a/homeassistant/components/cover/device_condition.py +++ b/homeassistant/components/cover/device_condition.py @@ -18,7 +18,7 @@ from homeassistant.const import ( STATE_OPEN, STATE_OPENING, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import ( condition, config_validation as cv, @@ -163,6 +163,7 @@ async def async_get_condition_capabilities(hass: HomeAssistant, config: dict) -> } +@callback def async_condition_from_config( config: ConfigType, config_validation: bool ) -> condition.ConditionCheckerType: @@ -196,6 +197,7 @@ def async_condition_from_config( f"{{{{ state.attributes.{position} }}}}" ) + @callback def template_if(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool: """Validate template based if-condition.""" value_template.hass = hass diff --git a/homeassistant/components/demo/mailbox.py b/homeassistant/components/demo/mailbox.py index 77030623c9d..ce9c5cc0ea6 100644 --- a/homeassistant/components/demo/mailbox.py +++ b/homeassistant/components/demo/mailbox.py @@ -71,7 +71,7 @@ class DemoMailbox(Mailbox): reverse=True, ) - def async_delete(self, msgid): + async def async_delete(self, msgid): """Delete the specified messages.""" if msgid in self._messages: _LOGGER.info("Deleting: %s", msgid) diff --git a/homeassistant/components/device_automation/toggle_entity.py b/homeassistant/components/device_automation/toggle_entity.py index 7d84eb921e9..f6bb74edbec 100644 --- a/homeassistant/components/device_automation/toggle_entity.py +++ b/homeassistant/components/device_automation/toggle_entity.py @@ -24,7 +24,7 @@ from homeassistant.const import ( CONF_PLATFORM, CONF_TYPE, ) -from homeassistant.core import CALLBACK_TYPE, Context, HomeAssistant +from homeassistant.core import CALLBACK_TYPE, Context, HomeAssistant, callback from homeassistant.helpers import condition, config_validation as cv from homeassistant.helpers.entity_registry import async_entries_for_device from homeassistant.helpers.typing import ConfigType, TemplateVarsType @@ -121,6 +121,7 @@ async def async_call_action_from_config( ) +@callback def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType: """Evaluate state based on configuration.""" condition_type = config[CONF_TYPE] diff --git a/homeassistant/components/device_sun_light_trigger/__init__.py b/homeassistant/components/device_sun_light_trigger/__init__.py index af6abf544c6..d7986fbb5b4 100644 --- a/homeassistant/components/device_sun_light_trigger/__init__.py +++ b/homeassistant/components/device_sun_light_trigger/__init__.py @@ -113,29 +113,27 @@ async def async_setup(hass, config): return None return next_setting - LIGHT_TRANSITION_TIME * len(light_ids) - def async_turn_on_before_sunset(light_id): + async def async_turn_on_before_sunset(light_id): """Turn on lights.""" if not anyone_home() or light.is_on(light_id): return - hass.async_create_task( - hass.services.async_call( - DOMAIN_LIGHT, - SERVICE_TURN_ON, - { - ATTR_ENTITY_ID: light_id, - ATTR_TRANSITION: LIGHT_TRANSITION_TIME.seconds, - ATTR_PROFILE: light_profile, - }, - ) + await hass.services.async_call( + DOMAIN_LIGHT, + SERVICE_TURN_ON, + { + ATTR_ENTITY_ID: light_id, + ATTR_TRANSITION: LIGHT_TRANSITION_TIME.seconds, + ATTR_PROFILE: light_profile, + }, ) + @callback def async_turn_on_factory(light_id): """Generate turn on callbacks as factory.""" - @callback - def async_turn_on_light(now): + async def async_turn_on_light(now): """Turn on specific light.""" - async_turn_on_before_sunset(light_id) + await async_turn_on_before_sunset(light_id) return async_turn_on_light diff --git a/homeassistant/components/device_tracker/device_condition.py b/homeassistant/components/device_tracker/device_condition.py index 9bdfc12db39..9c102bfa745 100644 --- a/homeassistant/components/device_tracker/device_condition.py +++ b/homeassistant/components/device_tracker/device_condition.py @@ -13,7 +13,7 @@ from homeassistant.const import ( STATE_HOME, STATE_NOT_HOME, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import condition, config_validation as cv, entity_registry from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA from homeassistant.helpers.typing import ConfigType, TemplateVarsType @@ -65,6 +65,7 @@ async def async_get_conditions( return conditions +@callback def async_condition_from_config( config: ConfigType, config_validation: bool ) -> condition.ConditionCheckerType: @@ -76,6 +77,7 @@ def async_condition_from_config( else: state = STATE_NOT_HOME + @callback def test_is_state(hass: HomeAssistant, variables: TemplateVarsType) -> bool: """Test if an entity is a certain state.""" return condition.state(hass, config[ATTR_ENTITY_ID], state) diff --git a/homeassistant/components/device_tracker/legacy.py b/homeassistant/components/device_tracker/legacy.py index 04ecad3b13d..6d343de8cb2 100644 --- a/homeassistant/components/device_tracker/legacy.py +++ b/homeassistant/components/device_tracker/legacy.py @@ -491,34 +491,25 @@ class DeviceScanner: """Scan for devices.""" raise NotImplementedError() - def async_scan_devices(self) -> Any: - """Scan for devices. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.scan_devices) + async def async_scan_devices(self) -> Any: + """Scan for devices.""" + return await self.hass.async_add_job(self.scan_devices) def get_device_name(self, device: str) -> str: """Get the name of a device.""" raise NotImplementedError() - def async_get_device_name(self, device: str) -> Any: - """Get the name of a device. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.get_device_name, device) + async def async_get_device_name(self, device: str) -> Any: + """Get the name of a device.""" + return await self.hass.async_add_job(self.get_device_name, device) def get_extra_attributes(self, device: str) -> dict: """Get the extra attributes of a device.""" raise NotImplementedError() - def async_get_extra_attributes(self, device: str) -> Any: - """Get the extra attributes of a device. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.get_extra_attributes, device) + async def async_get_extra_attributes(self, device: str) -> Any: + """Get the extra attributes of a device.""" + return await self.hass.async_add_job(self.get_extra_attributes, device) async def async_load_config( diff --git a/homeassistant/components/emby/media_player.py b/homeassistant/components/emby/media_player.py index 2fd1014dcdf..b4b05fd6c12 100644 --- a/homeassistant/components/emby/media_player.py +++ b/homeassistant/components/emby/media_player.py @@ -309,44 +309,26 @@ class EmbyDevice(MediaPlayerDevice): return SUPPORT_EMBY return None - def async_media_play(self): - """Play media. + async def async_media_play(self): + """Play media.""" + await self.device.media_play() - This method must be run in the event loop and returns a coroutine. - """ - return self.device.media_play() + async def async_media_pause(self): + """Pause the media player.""" + await self.device.media_pause() - def async_media_pause(self): - """Pause the media player. + async def async_media_stop(self): + """Stop the media player.""" + await self.device.media_stop() - This method must be run in the event loop and returns a coroutine. - """ - return self.device.media_pause() + async def async_media_next_track(self): + """Send next track command.""" + await self.device.media_next() - def async_media_stop(self): - """Stop the media player. + async def async_media_previous_track(self): + """Send next track command.""" + await self.device.media_previous() - This method must be run in the event loop and returns a coroutine. - """ - return self.device.media_stop() - - def async_media_next_track(self): - """Send next track command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.device.media_next() - - def async_media_previous_track(self): - """Send next track command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.device.media_previous() - - def async_media_seek(self, position): - """Send seek command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.device.media_seek(position) + async def async_media_seek(self, position): + """Send seek command.""" + await self.device.media_seek(position) diff --git a/homeassistant/components/esphome/entry_data.py b/homeassistant/components/esphome/entry_data.py index 48f1aea2c2d..c56760e952f 100644 --- a/homeassistant/components/esphome/entry_data.py +++ b/homeassistant/components/esphome/entry_data.py @@ -21,6 +21,7 @@ from aioesphomeapi import ( import attr from homeassistant.config_entries import ConfigEntry +from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.storage import Store from homeassistant.helpers.typing import HomeAssistantType @@ -71,6 +72,7 @@ class RuntimeEntryData: loaded_platforms = attr.ib(type=Set[str], factory=set) platform_load_lock = attr.ib(type=asyncio.Lock, factory=asyncio.Lock) + @callback def async_update_entity( self, hass: HomeAssistantType, component_key: str, key: int ) -> None: @@ -80,6 +82,7 @@ class RuntimeEntryData: ) async_dispatcher_send(hass, signal) + @callback def async_remove_entity( self, hass: HomeAssistantType, component_key: str, key: int ) -> None: @@ -120,11 +123,13 @@ class RuntimeEntryData: signal = DISPATCHER_ON_LIST.format(entry_id=self.entry_id) async_dispatcher_send(hass, signal, infos) + @callback def async_update_state(self, hass: HomeAssistantType, state: EntityState) -> None: """Distribute an update of state information to all platforms.""" signal = DISPATCHER_ON_STATE.format(entry_id=self.entry_id) async_dispatcher_send(hass, signal, state) + @callback def async_update_device_state(self, hass: HomeAssistantType) -> None: """Distribute an update of a core device state like availability.""" signal = DISPATCHER_ON_DEVICE_UPDATE.format(entry_id=self.entry_id) diff --git a/homeassistant/components/fan/__init__.py b/homeassistant/components/fan/__init__.py index 44b33af0c6e..38234a8f832 100644 --- a/homeassistant/components/fan/__init__.py +++ b/homeassistant/components/fan/__init__.py @@ -111,25 +111,20 @@ class FanEntity(ToggleEntity): """Set the speed of the fan.""" raise NotImplementedError() - def async_set_speed(self, speed: str): - """Set the speed of the fan. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_set_speed(self, speed: str): + """Set the speed of the fan.""" if speed is SPEED_OFF: - return self.async_turn_off() - return self.hass.async_add_job(self.set_speed, speed) + await self.async_turn_off() + else: + await self.hass.async_add_job(self.set_speed, speed) def set_direction(self, direction: str) -> None: """Set the direction of the fan.""" raise NotImplementedError() - def async_set_direction(self, direction: str): - """Set the direction of the fan. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.set_direction, direction) + async def async_set_direction(self, direction: str): + """Set the direction of the fan.""" + await self.hass.async_add_job(self.set_direction, direction) # pylint: disable=arguments-differ def turn_on(self, speed: Optional[str] = None, **kwargs) -> None: @@ -137,25 +132,20 @@ class FanEntity(ToggleEntity): raise NotImplementedError() # pylint: disable=arguments-differ - def async_turn_on(self, speed: Optional[str] = None, **kwargs): - """Turn on the fan. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_turn_on(self, speed: Optional[str] = None, **kwargs): + """Turn on the fan.""" if speed is SPEED_OFF: - return self.async_turn_off() - return self.hass.async_add_job(ft.partial(self.turn_on, speed, **kwargs)) + await self.async_turn_off() + else: + await self.hass.async_add_job(ft.partial(self.turn_on, speed, **kwargs)) def oscillate(self, oscillating: bool) -> None: """Oscillate the fan.""" pass - def async_oscillate(self, oscillating: bool): - """Oscillate the fan. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.oscillate, oscillating) + async def async_oscillate(self, oscillating: bool): + """Oscillate the fan.""" + await self.hass.async_add_job(self.oscillate, oscillating) @property def is_on(self): diff --git a/homeassistant/components/fan/device_condition.py b/homeassistant/components/fan/device_condition.py index c69f28c10e9..d3a8aa5c395 100644 --- a/homeassistant/components/fan/device_condition.py +++ b/homeassistant/components/fan/device_condition.py @@ -13,7 +13,7 @@ from homeassistant.const import ( STATE_OFF, STATE_ON, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import condition, config_validation as cv, entity_registry from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA from homeassistant.helpers.typing import ConfigType, TemplateVarsType @@ -64,6 +64,7 @@ async def async_get_conditions( return conditions +@callback def async_condition_from_config( config: ConfigType, config_validation: bool ) -> condition.ConditionCheckerType: @@ -75,6 +76,7 @@ def async_condition_from_config( else: state = STATE_OFF + @callback def test_is_state(hass: HomeAssistant, variables: TemplateVarsType) -> bool: """Test if an entity is a certain state.""" return condition.state(hass, config[ATTR_ENTITY_ID], state) diff --git a/homeassistant/components/generic_thermostat/climate.py b/homeassistant/components/generic_thermostat/climate.py index e179b576f70..23ee049052c 100644 --- a/homeassistant/components/generic_thermostat/climate.py +++ b/homeassistant/components/generic_thermostat/climate.py @@ -453,10 +453,7 @@ class GenericThermostat(ClimateDevice, RestoreEntity): await self.hass.services.async_call(HA_DOMAIN, SERVICE_TURN_OFF, data) async def async_set_preset_mode(self, preset_mode: str): - """Set new preset mode. - - This method must be run in the event loop and returns a coroutine. - """ + """Set new preset mode.""" if preset_mode == PRESET_AWAY and not self._is_away: self._is_away = True self._saved_target_temp = self._target_temp diff --git a/homeassistant/components/google_assistant/helpers.py b/homeassistant/components/google_assistant/helpers.py index 8444ba11c61..983f638656d 100644 --- a/homeassistant/components/google_assistant/helpers.py +++ b/homeassistant/components/google_assistant/helpers.py @@ -122,6 +122,7 @@ class AbstractConfig(ABC): ] await gather(*jobs) + @callback def async_enable_report_state(self): """Enable proactive mode.""" # Circular dep @@ -131,6 +132,7 @@ class AbstractConfig(ABC): if self._unsub_report_state is None: self._unsub_report_state = async_enable_report_state(self.hass, self) + @callback def async_disable_report_state(self): """Disable report state.""" if self._unsub_report_state is not None: diff --git a/homeassistant/components/hangouts/hangouts_bot.py b/homeassistant/components/hangouts/hangouts_bot.py index fd14ec0b094..b3dfdecac2a 100644 --- a/homeassistant/components/hangouts/hangouts_bot.py +++ b/homeassistant/components/hangouts/hangouts_bot.py @@ -7,6 +7,7 @@ import aiohttp import hangups from hangups import ChatMessageEvent, ChatMessageSegment, Client, get_auth, hangouts_pb2 +from homeassistant.core import callback from homeassistant.helpers import dispatcher, intent from homeassistant.helpers.aiohttp_client import async_get_clientsession @@ -75,6 +76,7 @@ class HangoutsBot: return conv return None + @callback def async_update_conversation_commands(self): """Refresh the commands for every conversation.""" self._conversation_intents = {} @@ -110,6 +112,7 @@ class HangoutsBot: self._async_handle_conversation_event ) + @callback def async_resolve_conversations(self, _): """Resolve the list of default and error suppressed conversations.""" self._default_conv_ids = [] diff --git a/homeassistant/components/homekit_controller/air_quality.py b/homeassistant/components/homekit_controller/air_quality.py index 0419c0354e6..41194cb340c 100644 --- a/homeassistant/components/homekit_controller/air_quality.py +++ b/homeassistant/components/homekit_controller/air_quality.py @@ -2,6 +2,7 @@ from homekit.model.characteristics import CharacteristicsTypes from homeassistant.components.air_quality import AirQualityEntity +from homeassistant.core import callback from . import KNOWN_DEVICES, HomeKitEntity @@ -83,6 +84,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): hkid = config_entry.data["AccessoryPairingID"] conn = hass.data[KNOWN_DEVICES][hkid] + @callback def async_add_service(aid, service): if service["stype"] != "air-quality": return False diff --git a/homeassistant/components/homekit_controller/alarm_control_panel.py b/homeassistant/components/homekit_controller/alarm_control_panel.py index 800c988279a..f4f89507fca 100644 --- a/homeassistant/components/homekit_controller/alarm_control_panel.py +++ b/homeassistant/components/homekit_controller/alarm_control_panel.py @@ -17,6 +17,7 @@ from homeassistant.const import ( STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED, ) +from homeassistant.core import callback from . import KNOWN_DEVICES, HomeKitEntity @@ -45,6 +46,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): hkid = config_entry.data["AccessoryPairingID"] conn = hass.data[KNOWN_DEVICES][hkid] + @callback def async_add_service(aid, service): if service["stype"] != "security-system": return False diff --git a/homeassistant/components/homekit_controller/binary_sensor.py b/homeassistant/components/homekit_controller/binary_sensor.py index 9fd93cf732a..0a6a3fca1cf 100644 --- a/homeassistant/components/homekit_controller/binary_sensor.py +++ b/homeassistant/components/homekit_controller/binary_sensor.py @@ -7,6 +7,7 @@ from homeassistant.components.binary_sensor import ( DEVICE_CLASS_SMOKE, BinarySensorDevice, ) +from homeassistant.core import callback from . import KNOWN_DEVICES, HomeKitEntity @@ -98,6 +99,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): hkid = config_entry.data["AccessoryPairingID"] conn = hass.data[KNOWN_DEVICES][hkid] + @callback def async_add_service(aid, service): entity_class = ENTITY_TYPES.get(service["stype"]) if not entity_class: diff --git a/homeassistant/components/homekit_controller/climate.py b/homeassistant/components/homekit_controller/climate.py index ff234f566c7..bbef10d3204 100644 --- a/homeassistant/components/homekit_controller/climate.py +++ b/homeassistant/components/homekit_controller/climate.py @@ -20,6 +20,7 @@ from homeassistant.components.climate.const import ( SUPPORT_TARGET_TEMPERATURE, ) from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS +from homeassistant.core import callback from . import KNOWN_DEVICES, HomeKitEntity @@ -50,6 +51,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): hkid = config_entry.data["AccessoryPairingID"] conn = hass.data[KNOWN_DEVICES][hkid] + @callback def async_add_service(aid, service): if service["stype"] != "thermostat": return False diff --git a/homeassistant/components/homekit_controller/connection.py b/homeassistant/components/homekit_controller/connection.py index f3e728c6cdc..64581da45b1 100644 --- a/homeassistant/components/homekit_controller/connection.py +++ b/homeassistant/components/homekit_controller/connection.py @@ -12,6 +12,7 @@ from homekit.exceptions import ( from homekit.model.characteristics import CharacteristicsTypes from homekit.model.services import ServicesTypes +from homeassistant.core import callback from homeassistant.helpers.event import async_track_time_interval from .const import DOMAIN, ENTITY_MAP, HOMEKIT_ACCESSORY_DISPATCH @@ -116,6 +117,7 @@ class HKDevice: char for char in self.pollable_characteristics if char[0] != accessory_id ] + @callback def async_set_unavailable(self): """Mark state of all entities on this connection as unavailable.""" self.available = False diff --git a/homeassistant/components/homekit_controller/cover.py b/homeassistant/components/homekit_controller/cover.py index dec94771b03..191405a9355 100644 --- a/homeassistant/components/homekit_controller/cover.py +++ b/homeassistant/components/homekit_controller/cover.py @@ -16,6 +16,7 @@ from homeassistant.components.cover import ( CoverDevice, ) from homeassistant.const import STATE_CLOSED, STATE_CLOSING, STATE_OPEN, STATE_OPENING +from homeassistant.core import callback from . import KNOWN_DEVICES, HomeKitEntity @@ -41,6 +42,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): hkid = config_entry.data["AccessoryPairingID"] conn = hass.data[KNOWN_DEVICES][hkid] + @callback def async_add_service(aid, service): info = {"aid": aid, "iid": service["iid"]} if service["stype"] == "garage-door-opener": diff --git a/homeassistant/components/homekit_controller/fan.py b/homeassistant/components/homekit_controller/fan.py index a6c4ae769e2..694ae8a2c09 100644 --- a/homeassistant/components/homekit_controller/fan.py +++ b/homeassistant/components/homekit_controller/fan.py @@ -15,6 +15,7 @@ from homeassistant.components.fan import ( SUPPORT_SET_SPEED, FanEntity, ) +from homeassistant.core import callback from . import KNOWN_DEVICES, HomeKitEntity @@ -235,6 +236,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): hkid = config_entry.data["AccessoryPairingID"] conn = hass.data[KNOWN_DEVICES][hkid] + @callback def async_add_service(aid, service): entity_class = ENTITY_TYPES.get(service["stype"]) if not entity_class: diff --git a/homeassistant/components/homekit_controller/light.py b/homeassistant/components/homekit_controller/light.py index 9ce262291b3..e7d1e4d3273 100644 --- a/homeassistant/components/homekit_controller/light.py +++ b/homeassistant/components/homekit_controller/light.py @@ -12,6 +12,7 @@ from homeassistant.components.light import ( SUPPORT_COLOR_TEMP, Light, ) +from homeassistant.core import callback from . import KNOWN_DEVICES, HomeKitEntity @@ -23,6 +24,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): hkid = config_entry.data["AccessoryPairingID"] conn = hass.data[KNOWN_DEVICES][hkid] + @callback def async_add_service(aid, service): if service["stype"] != "lightbulb": return False diff --git a/homeassistant/components/homekit_controller/lock.py b/homeassistant/components/homekit_controller/lock.py index 5183a636f0f..1799d30d8c8 100644 --- a/homeassistant/components/homekit_controller/lock.py +++ b/homeassistant/components/homekit_controller/lock.py @@ -5,6 +5,7 @@ from homekit.model.characteristics import CharacteristicsTypes from homeassistant.components.lock import LockDevice from homeassistant.const import ATTR_BATTERY_LEVEL, STATE_LOCKED, STATE_UNLOCKED +from homeassistant.core import callback from . import KNOWN_DEVICES, HomeKitEntity @@ -22,6 +23,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): hkid = config_entry.data["AccessoryPairingID"] conn = hass.data[KNOWN_DEVICES][hkid] + @callback def async_add_service(aid, service): if service["stype"] != "lock-mechanism": return False diff --git a/homeassistant/components/homekit_controller/sensor.py b/homeassistant/components/homekit_controller/sensor.py index 0e3680db346..e59dda007d4 100644 --- a/homeassistant/components/homekit_controller/sensor.py +++ b/homeassistant/components/homekit_controller/sensor.py @@ -2,6 +2,7 @@ from homekit.model.characteristics import CharacteristicsTypes from homeassistant.const import DEVICE_CLASS_BATTERY, TEMP_CELSIUS +from homeassistant.core import callback from . import KNOWN_DEVICES, HomeKitEntity @@ -246,6 +247,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): hkid = config_entry.data["AccessoryPairingID"] conn = hass.data[KNOWN_DEVICES][hkid] + @callback def async_add_service(aid, service): entity_class = ENTITY_TYPES.get(service["stype"]) if not entity_class: diff --git a/homeassistant/components/homekit_controller/storage.py b/homeassistant/components/homekit_controller/storage.py index ffc2da5fbf2..ffc5bdc2381 100644 --- a/homeassistant/components/homekit_controller/storage.py +++ b/homeassistant/components/homekit_controller/storage.py @@ -45,6 +45,7 @@ class EntityMapStorage: """Get a pairing cache item.""" return self.storage_data.get(homekit_id) + @callback def async_create_or_update_map(self, homekit_id, config_num, accessories): """Create a new pairing cache.""" data = {"config_num": config_num, "accessories": accessories} @@ -52,6 +53,7 @@ class EntityMapStorage: self._async_schedule_save() return data + @callback def async_delete_map(self, homekit_id): """Delete pairing cache.""" if homekit_id not in self.storage_data: diff --git a/homeassistant/components/homekit_controller/switch.py b/homeassistant/components/homekit_controller/switch.py index 6b71b15daff..60b16c8ddab 100644 --- a/homeassistant/components/homekit_controller/switch.py +++ b/homeassistant/components/homekit_controller/switch.py @@ -4,6 +4,7 @@ import logging from homekit.model.characteristics import CharacteristicsTypes from homeassistant.components.switch import SwitchDevice +from homeassistant.core import callback from . import KNOWN_DEVICES, HomeKitEntity @@ -17,6 +18,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): hkid = config_entry.data["AccessoryPairingID"] conn = hass.data[KNOWN_DEVICES][hkid] + @callback def async_add_service(aid, service): if service["stype"] not in ("switch", "outlet"): return False diff --git a/homeassistant/components/huawei_lte/device_tracker.py b/homeassistant/components/huawei_lte/device_tracker.py index a9c61831fdd..54e8f318cf6 100644 --- a/homeassistant/components/huawei_lte/device_tracker.py +++ b/homeassistant/components/huawei_lte/device_tracker.py @@ -13,6 +13,7 @@ from homeassistant.components.device_tracker import ( ) from homeassistant.components.device_tracker.config_entry import ScannerEntity from homeassistant.const import CONF_URL +from homeassistant.core import callback from homeassistant.helpers import entity_registry from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -70,6 +71,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): async_add_new_entities(hass, router.url, async_add_entities, tracked) +@callback def async_add_new_entities(hass, router_url, async_add_entities, tracked): """Add new entities that are not already being tracked.""" router = hass.data[DOMAIN].routers[router_url] diff --git a/homeassistant/components/ihc/util.py b/homeassistant/components/ihc/util.py index 40434dadc8e..1b6b1dbd3e0 100644 --- a/homeassistant/components/ihc/util.py +++ b/homeassistant/components/ihc/util.py @@ -2,6 +2,8 @@ import asyncio +from homeassistant.core import callback + async def async_pulse(hass, ihc_controller, ihc_id: int): """Send a short on/off pulse to an IHC controller resource.""" @@ -10,6 +12,7 @@ async def async_pulse(hass, ihc_controller, ihc_id: int): await async_set_bool(hass, ihc_controller, ihc_id, False) +@callback def async_set_bool(hass, ihc_controller, ihc_id: int, value: bool): """Set a bool value on an IHC controller resource.""" return hass.async_add_executor_job( @@ -17,6 +20,7 @@ def async_set_bool(hass, ihc_controller, ihc_id: int, value: bool): ) +@callback def async_set_int(hass, ihc_controller, ihc_id: int, value: int): """Set a int value on an IHC controller resource.""" return hass.async_add_executor_job( diff --git a/homeassistant/components/image_processing/__init__.py b/homeassistant/components/image_processing/__init__.py index a8f5f0f097e..84ba5b45fc4 100644 --- a/homeassistant/components/image_processing/__init__.py +++ b/homeassistant/components/image_processing/__init__.py @@ -107,12 +107,9 @@ class ImageProcessingEntity(Entity): """Process image.""" raise NotImplementedError() - def async_process_image(self, image): - """Process image. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.process_image, image) + async def async_process_image(self, image): + """Process image.""" + return await self.hass.async_add_job(self.process_image, image) async def async_update(self): """Update image and process it. diff --git a/homeassistant/components/input_datetime/__init__.py b/homeassistant/components/input_datetime/__init__.py index 03b468313f8..371e0dea185 100644 --- a/homeassistant/components/input_datetime/__init__.py +++ b/homeassistant/components/input_datetime/__init__.py @@ -326,6 +326,7 @@ class InputDatetime(RestoreEntity): """Return unique id of the entity.""" return self._config[CONF_ID] + @callback def async_set_datetime(self, date_val, time_val): """Set a new date / time.""" if self.has_date and self.has_time and date_val and time_val: diff --git a/homeassistant/components/kira/remote.py b/homeassistant/components/kira/remote.py index 8914641dd74..330813a7bff 100644 --- a/homeassistant/components/kira/remote.py +++ b/homeassistant/components/kira/remote.py @@ -48,9 +48,8 @@ class KiraRemote(Entity): _LOGGER.info("Sending Command: %s to %s", *code_tuple) self._kira.sendCode(code_tuple) - def async_send_command(self, command, **kwargs): - """Send a command to a device. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(ft.partial(self.send_command, command, **kwargs)) + async def async_send_command(self, command, **kwargs): + """Send a command to a device.""" + return await self.hass.async_add_job( + ft.partial(self.send_command, command, **kwargs) + ) diff --git a/homeassistant/components/knx/climate.py b/homeassistant/components/knx/climate.py index 819fb1794c3..554ae59f397 100644 --- a/homeassistant/components/knx/climate.py +++ b/homeassistant/components/knx/climate.py @@ -330,10 +330,7 @@ class KNXClimate(ClimateDevice): return list(filter(None, _presets)) async def async_set_preset_mode(self, preset_mode: str) -> None: - """Set new preset mode. - - This method must be run in the event loop and returns a coroutine. - """ + """Set new preset mode.""" if self.device.mode.supports_operation_mode: knx_operation_mode = HVACOperationMode(PRESET_MODES_INV.get(preset_mode)) await self.device.mode.set_operation_mode(knx_operation_mode) diff --git a/homeassistant/components/kodi/media_player.py b/homeassistant/components/kodi/media_player.py index 78355937d15..f326ba60375 100644 --- a/homeassistant/components/kodi/media_player.py +++ b/homeassistant/components/kodi/media_player.py @@ -668,20 +668,14 @@ class KodiDevice(MediaPlayerDevice): assert (await self.server.Input.ExecuteAction("volumedown")) == "OK" @cmd - def async_set_volume_level(self, volume): - """Set volume level, range 0..1. - - This method must be run in the event loop and returns a coroutine. - """ - return self.server.Application.SetVolume(int(volume * 100)) + async def async_set_volume_level(self, volume): + """Set volume level, range 0..1.""" + await self.server.Application.SetVolume(int(volume * 100)) @cmd - def async_mute_volume(self, mute): - """Mute (true) or unmute (false) media player. - - This method must be run in the event loop and returns a coroutine. - """ - return self.server.Application.SetMute(mute) + async def async_mute_volume(self, mute): + """Mute (true) or unmute (false) media player.""" + await self.server.Application.SetMute(mute) async def async_set_play_state(self, state): """Handle play/pause/toggle.""" @@ -691,28 +685,19 @@ class KodiDevice(MediaPlayerDevice): await self.server.Player.PlayPause(players[0]["playerid"], state) @cmd - def async_media_play_pause(self): - """Pause media on media player. - - This method must be run in the event loop and returns a coroutine. - """ - return self.async_set_play_state("toggle") + async def async_media_play_pause(self): + """Pause media on media player.""" + await self.async_set_play_state("toggle") @cmd - def async_media_play(self): - """Play media. - - This method must be run in the event loop and returns a coroutine. - """ - return self.async_set_play_state(True) + async def async_media_play(self): + """Play media.""" + await self.async_set_play_state(True) @cmd - def async_media_pause(self): - """Pause the media player. - - This method must be run in the event loop and returns a coroutine. - """ - return self.async_set_play_state(False) + async def async_media_pause(self): + """Pause the media player.""" + await self.async_set_play_state(False) @cmd async def async_media_stop(self): @@ -735,20 +720,14 @@ class KodiDevice(MediaPlayerDevice): await self.server.Player.GoTo(players[0]["playerid"], direction) @cmd - def async_media_next_track(self): - """Send next track command. - - This method must be run in the event loop and returns a coroutine. - """ - return self._goto("next") + async def async_media_next_track(self): + """Send next track command.""" + await self._goto("next") @cmd - def async_media_previous_track(self): - """Send next track command. - - This method must be run in the event loop and returns a coroutine. - """ - return self._goto("previous") + async def async_media_previous_track(self): + """Send next track command.""" + await self._goto("previous") @cmd async def async_media_seek(self, position): @@ -772,21 +751,18 @@ class KodiDevice(MediaPlayerDevice): await self.server.Player.Seek(players[0]["playerid"], time) @cmd - def async_play_media(self, media_type, media_id, **kwargs): - """Send the play_media command to the media player. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_play_media(self, media_type, media_id, **kwargs): + """Send the play_media command to the media player.""" if media_type == "CHANNEL": - return self.server.Player.Open({"item": {"channelid": int(media_id)}}) - if media_type == "PLAYLIST": - return self.server.Player.Open({"item": {"playlistid": int(media_id)}}) - if media_type == "DIRECTORY": - return self.server.Player.Open({"item": {"directory": str(media_id)}}) - if media_type == "PLUGIN": - return self.server.Player.Open({"item": {"file": str(media_id)}}) - - return self.server.Player.Open({"item": {"file": str(media_id)}}) + await self.server.Player.Open({"item": {"channelid": int(media_id)}}) + elif media_type == "PLAYLIST": + await self.server.Player.Open({"item": {"playlistid": int(media_id)}}) + elif media_type == "DIRECTORY": + await self.server.Player.Open({"item": {"directory": str(media_id)}}) + elif media_type == "PLUGIN": + await self.server.Player.Open({"item": {"file": str(media_id)}}) + else: + await self.server.Player.Open({"item": {"file": str(media_id)}}) async def async_set_shuffle(self, shuffle): """Set shuffle mode, for the first player.""" diff --git a/homeassistant/components/light/device_condition.py b/homeassistant/components/light/device_condition.py index d27953749f6..1d9323907f2 100644 --- a/homeassistant/components/light/device_condition.py +++ b/homeassistant/components/light/device_condition.py @@ -5,7 +5,7 @@ import voluptuous as vol from homeassistant.components.device_automation import toggle_entity from homeassistant.const import CONF_DOMAIN -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.condition import ConditionCheckerType from homeassistant.helpers.typing import ConfigType @@ -16,6 +16,7 @@ CONDITION_SCHEMA = toggle_entity.CONDITION_SCHEMA.extend( ) +@callback def async_condition_from_config( config: ConfigType, config_validation: bool ) -> ConditionCheckerType: diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py index c788a7c3e8c..92da3a03085 100644 --- a/homeassistant/components/lock/__init__.py +++ b/homeassistant/components/lock/__init__.py @@ -104,34 +104,25 @@ class LockDevice(Entity): """Lock the lock.""" raise NotImplementedError() - def async_lock(self, **kwargs): - """Lock the lock. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(ft.partial(self.lock, **kwargs)) + async def async_lock(self, **kwargs): + """Lock the lock.""" + await self.hass.async_add_job(ft.partial(self.lock, **kwargs)) def unlock(self, **kwargs): """Unlock the lock.""" raise NotImplementedError() - def async_unlock(self, **kwargs): - """Unlock the lock. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(ft.partial(self.unlock, **kwargs)) + async def async_unlock(self, **kwargs): + """Unlock the lock.""" + await self.hass.async_add_job(ft.partial(self.unlock, **kwargs)) def open(self, **kwargs): """Open the door latch.""" raise NotImplementedError() - def async_open(self, **kwargs): - """Open the door latch. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(ft.partial(self.open, **kwargs)) + async def async_open(self, **kwargs): + """Open the door latch.""" + await self.hass.async_add_job(ft.partial(self.open, **kwargs)) @property def state_attributes(self): diff --git a/homeassistant/components/lock/device_condition.py b/homeassistant/components/lock/device_condition.py index 44791320669..a25018dc709 100644 --- a/homeassistant/components/lock/device_condition.py +++ b/homeassistant/components/lock/device_condition.py @@ -13,7 +13,7 @@ from homeassistant.const import ( STATE_LOCKED, STATE_UNLOCKED, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import condition, config_validation as cv, entity_registry from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA from homeassistant.helpers.typing import ConfigType, TemplateVarsType @@ -63,6 +63,7 @@ async def async_get_conditions(hass: HomeAssistant, device_id: str) -> List[dict return conditions +@callback def async_condition_from_config( config: ConfigType, config_validation: bool ) -> condition.ConditionCheckerType: diff --git a/homeassistant/components/mailbox/__init__.py b/homeassistant/components/mailbox/__init__.py index 0381d932328..8526f6658c7 100644 --- a/homeassistant/components/mailbox/__init__.py +++ b/homeassistant/components/mailbox/__init__.py @@ -141,6 +141,7 @@ class Mailbox: self.hass = hass self.name = name + @callback def async_update(self): """Send event notification of updated mailbox.""" self.hass.bus.async_fire(EVENT) @@ -168,7 +169,7 @@ class Mailbox: """Return a list of the current messages.""" raise NotImplementedError() - def async_delete(self, msgid): + async def async_delete(self, msgid): """Delete the specified messages.""" raise NotImplementedError() @@ -236,7 +237,7 @@ class MailboxDeleteView(MailboxView): async def delete(self, request, platform, msgid): """Delete items.""" mailbox = self.get_mailbox(platform) - mailbox.async_delete(msgid) + await mailbox.async_delete(msgid) class MailboxMediaView(MailboxView): diff --git a/homeassistant/components/manual_mqtt/alarm_control_panel.py b/homeassistant/components/manual_mqtt/alarm_control_panel.py index f11dac357e6..00a82118ec4 100644 --- a/homeassistant/components/manual_mqtt/alarm_control_panel.py +++ b/homeassistant/components/manual_mqtt/alarm_control_panel.py @@ -29,7 +29,6 @@ from homeassistant.const import ( STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, ) -from homeassistant.core import callback import homeassistant.helpers.config_validation as cv from homeassistant.helpers.event import async_track_state_change, track_point_in_time import homeassistant.util.dt as dt_util @@ -427,17 +426,16 @@ class ManualMQTTAlarm(alarm.AlarmControlPanel): self.hass, self.entity_id, self._async_state_changed_listener ) - @callback - def message_received(msg): + async def message_received(msg): """Run when new MQTT message has been received.""" if msg.payload == self._payload_disarm: - self.async_alarm_disarm(self._code) + await self.async_alarm_disarm(self._code) elif msg.payload == self._payload_arm_home: - self.async_alarm_arm_home(self._code) + await self.async_alarm_arm_home(self._code) elif msg.payload == self._payload_arm_away: - self.async_alarm_arm_away(self._code) + await self.async_alarm_arm_away(self._code) elif msg.payload == self._payload_arm_night: - self.async_alarm_arm_night(self._code) + await self.async_alarm_arm_night(self._code) else: _LOGGER.warning("Received unexpected payload: %s", msg.payload) return diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index b73208402f8..28951df545a 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -485,122 +485,89 @@ class MediaPlayerDevice(Entity): """Turn the media player on.""" raise NotImplementedError() - def async_turn_on(self): - """Turn the media player on. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.turn_on) + async def async_turn_on(self): + """Turn the media player on.""" + await self.hass.async_add_job(self.turn_on) def turn_off(self): """Turn the media player off.""" raise NotImplementedError() - def async_turn_off(self): - """Turn the media player off. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.turn_off) + async def async_turn_off(self): + """Turn the media player off.""" + await self.hass.async_add_job(self.turn_off) def mute_volume(self, mute): """Mute the volume.""" raise NotImplementedError() - def async_mute_volume(self, mute): - """Mute the volume. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.mute_volume, mute) + async def async_mute_volume(self, mute): + """Mute the volume.""" + await self.hass.async_add_job(self.mute_volume, mute) def set_volume_level(self, volume): """Set volume level, range 0..1.""" raise NotImplementedError() - def async_set_volume_level(self, volume): - """Set volume level, range 0..1. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.set_volume_level, volume) + async def async_set_volume_level(self, volume): + """Set volume level, range 0..1.""" + await self.hass.async_add_job(self.set_volume_level, volume) def media_play(self): """Send play command.""" raise NotImplementedError() - def async_media_play(self): - """Send play command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.media_play) + async def async_media_play(self): + """Send play command.""" + await self.hass.async_add_job(self.media_play) def media_pause(self): """Send pause command.""" raise NotImplementedError() - def async_media_pause(self): - """Send pause command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.media_pause) + async def async_media_pause(self): + """Send pause command.""" + await self.hass.async_add_job(self.media_pause) def media_stop(self): """Send stop command.""" raise NotImplementedError() - def async_media_stop(self): - """Send stop command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.media_stop) + async def async_media_stop(self): + """Send stop command.""" + await self.hass.async_add_job(self.media_stop) def media_previous_track(self): """Send previous track command.""" raise NotImplementedError() - def async_media_previous_track(self): - """Send previous track command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.media_previous_track) + async def async_media_previous_track(self): + """Send previous track command.""" + await self.hass.async_add_job(self.media_previous_track) def media_next_track(self): """Send next track command.""" raise NotImplementedError() - def async_media_next_track(self): - """Send next track command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.media_next_track) + async def async_media_next_track(self): + """Send next track command.""" + await self.hass.async_add_job(self.media_next_track) def media_seek(self, position): """Send seek command.""" raise NotImplementedError() - def async_media_seek(self, position): - """Send seek command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.media_seek, position) + async def async_media_seek(self, position): + """Send seek command.""" + await self.hass.async_add_job(self.media_seek, position) def play_media(self, media_type, media_id, **kwargs): """Play a piece of media.""" raise NotImplementedError() - def async_play_media(self, media_type, media_id, **kwargs): - """Play a piece of media. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job( + async def async_play_media(self, media_type, media_id, **kwargs): + """Play a piece of media.""" + await self.hass.async_add_job( ft.partial(self.play_media, media_type, media_id, **kwargs) ) @@ -608,45 +575,33 @@ class MediaPlayerDevice(Entity): """Select input source.""" raise NotImplementedError() - def async_select_source(self, source): - """Select input source. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.select_source, source) + async def async_select_source(self, source): + """Select input source.""" + await self.hass.async_add_job(self.select_source, source) def select_sound_mode(self, sound_mode): """Select sound mode.""" raise NotImplementedError() - def async_select_sound_mode(self, sound_mode): - """Select sound mode. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.select_sound_mode, sound_mode) + async def async_select_sound_mode(self, sound_mode): + """Select sound mode.""" + await self.hass.async_add_job(self.select_sound_mode, sound_mode) def clear_playlist(self): """Clear players playlist.""" raise NotImplementedError() - def async_clear_playlist(self): - """Clear players playlist. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.clear_playlist) + async def async_clear_playlist(self): + """Clear players playlist.""" + await self.hass.async_add_job(self.clear_playlist) def set_shuffle(self, shuffle): """Enable/disable shuffle mode.""" raise NotImplementedError() - def async_set_shuffle(self, shuffle): - """Enable/disable shuffle mode. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.set_shuffle, shuffle) + async def async_set_shuffle(self, shuffle): + """Enable/disable shuffle mode.""" + await self.hass.async_add_job(self.set_shuffle, shuffle) # No need to overwrite these. @property @@ -714,18 +669,17 @@ class MediaPlayerDevice(Entity): """Boolean if shuffle is supported.""" return bool(self.supported_features & SUPPORT_SHUFFLE_SET) - def async_toggle(self): - """Toggle the power on the media player. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_toggle(self): + """Toggle the power on the media player.""" if hasattr(self, "toggle"): # pylint: disable=no-member - return self.hass.async_add_job(self.toggle) + await self.hass.async_add_job(self.toggle) + return if self.state in [STATE_OFF, STATE_IDLE]: - return self.async_turn_on() - return self.async_turn_off() + await self.async_turn_on() + else: + await self.async_turn_off() async def async_volume_up(self): """Turn volume up for media player. @@ -753,18 +707,17 @@ class MediaPlayerDevice(Entity): if self.volume_level > 0 and self.supported_features & SUPPORT_VOLUME_SET: await self.async_set_volume_level(max(0, self.volume_level - 0.1)) - def async_media_play_pause(self): - """Play or pause the media player. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_media_play_pause(self): + """Play or pause the media player.""" if hasattr(self, "media_play_pause"): # pylint: disable=no-member - return self.hass.async_add_job(self.media_play_pause) + await self.hass.async_add_job(self.media_play_pause) + return if self.state == STATE_PLAYING: - return self.async_media_pause() - return self.async_media_play() + await self.async_media_pause() + else: + await self.async_media_play() @property def entity_picture(self): diff --git a/homeassistant/components/media_player/device_condition.py b/homeassistant/components/media_player/device_condition.py index a8091a6aed8..6faa6521b70 100644 --- a/homeassistant/components/media_player/device_condition.py +++ b/homeassistant/components/media_player/device_condition.py @@ -16,7 +16,7 @@ from homeassistant.const import ( STATE_PAUSED, STATE_PLAYING, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import condition, config_validation as cv, entity_registry from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA from homeassistant.helpers.typing import ConfigType, TemplateVarsType @@ -95,6 +95,7 @@ async def async_get_conditions( return conditions +@callback def async_condition_from_config( config: ConfigType, config_validation: bool ) -> condition.ConditionCheckerType: diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index a9d5ac93ebc..a6db90382bf 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -774,27 +774,21 @@ class MQTT: async def async_publish( self, topic: str, payload: PublishPayloadType, qos: int, retain: bool ) -> None: - """Publish a MQTT message. - - This method must be run in the event loop and returns a coroutine. - """ + """Publish a MQTT message.""" async with self._paho_lock: _LOGGER.debug("Transmitting message on %s: %s", topic, payload) - await self.hass.async_add_job( + await self.hass.async_add_executor_job( self._mqttc.publish, topic, payload, qos, retain ) async def async_connect(self) -> str: - """Connect to the host. Does process messages yet. - - This method is a coroutine. - """ + """Connect to the host. Does process messages yet.""" # pylint: disable=import-outside-toplevel import paho.mqtt.client as mqtt result: int = None try: - result = await self.hass.async_add_job( + result = await self.hass.async_add_executor_job( self._mqttc.connect, self.broker, self.port, self.keepalive ) except OSError as err: @@ -808,19 +802,15 @@ class MQTT: self._mqttc.loop_start() return CONNECTION_SUCCESS - @callback - def async_disconnect(self): - """Stop the MQTT client. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_disconnect(self): + """Stop the MQTT client.""" def stop(): """Stop the MQTT client.""" self._mqttc.disconnect() self._mqttc.loop_stop() - return self.hass.async_add_job(stop) + await self.hass.async_add_executor_job(stop) async def async_subscribe( self, @@ -865,7 +855,9 @@ class MQTT: """ async with self._paho_lock: result: int = None - result, _ = await self.hass.async_add_job(self._mqttc.unsubscribe, topic) + result, _ = await self.hass.async_add_executor_job( + self._mqttc.unsubscribe, topic + ) _raise_on_error(result) async def _async_perform_subscription(self, topic: str, qos: int) -> None: @@ -874,7 +866,9 @@ class MQTT: async with self._paho_lock: result: int = None - result, _ = await self.hass.async_add_job(self._mqttc.subscribe, topic, qos) + result, _ = await self.hass.async_add_executor_job( + self._mqttc.subscribe, topic, qos + ) _raise_on_error(result) def _mqtt_on_connect(self, _mqttc, _userdata, _flags, result_code: int) -> None: @@ -1010,10 +1004,7 @@ class MqttAttributes(Entity): self._attributes_config = config async def async_added_to_hass(self) -> None: - """Subscribe MQTT events. - - This method must be run in the event loop and returns a coroutine. - """ + """Subscribe MQTT events.""" await super().async_added_to_hass() await self._attributes_subscribe_topics() @@ -1080,10 +1071,7 @@ class MqttAvailability(Entity): self._avail_config = config async def async_added_to_hass(self) -> None: - """Subscribe MQTT events. - - This method must be run in the event loop and returns a coroutine. - """ + """Subscribe MQTT events.""" await super().async_added_to_hass() await self._availability_subscribe_topics() diff --git a/homeassistant/components/mqtt/camera.py b/homeassistant/components/mqtt/camera.py index 831c47c3621..6cf0865ff6a 100644 --- a/homeassistant/components/mqtt/camera.py +++ b/homeassistant/components/mqtt/camera.py @@ -1,6 +1,4 @@ """Camera that loads a picture from an MQTT topic.""" - -import asyncio import logging import voluptuous as vol @@ -130,8 +128,7 @@ class MqttCamera(MqttDiscoveryUpdate, MqttEntityDeviceInfo, Camera): self.hass, self._sub_state ) - @asyncio.coroutine - def async_camera_image(self): + async def async_camera_image(self): """Return image response.""" return self._last_image diff --git a/homeassistant/components/mqtt/server.py b/homeassistant/components/mqtt/server.py index 3ed2fb71b14..61ba5c392b1 100644 --- a/homeassistant/components/mqtt/server.py +++ b/homeassistant/components/mqtt/server.py @@ -1,5 +1,4 @@ """Support for a local MQTT broker.""" -import asyncio import logging import tempfile @@ -29,8 +28,7 @@ HBMQTT_CONFIG_SCHEMA = vol.Any( ) -@asyncio.coroutine -def async_start(hass, password, server_config): +async def async_start(hass, password, server_config): """Initialize MQTT Server. This method is a coroutine. @@ -47,17 +45,16 @@ def async_start(hass, password, server_config): server_config = gen_server_config broker = Broker(server_config, hass.loop) - yield from broker.start() + await broker.start() except BrokerException: _LOGGER.exception("Error initializing MQTT server") return False, None finally: passwd.close() - @asyncio.coroutine - def async_shutdown_mqtt_server(event): + async def async_shutdown_mqtt_server(event): """Shut down the MQTT server.""" - yield from broker.shutdown() + await broker.shutdown() hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_shutdown_mqtt_server) diff --git a/homeassistant/components/mystrom/binary_sensor.py b/homeassistant/components/mystrom/binary_sensor.py index ff0063a380e..3da77d6d943 100644 --- a/homeassistant/components/mystrom/binary_sensor.py +++ b/homeassistant/components/mystrom/binary_sensor.py @@ -4,6 +4,7 @@ import logging from homeassistant.components.binary_sensor import DOMAIN, BinarySensorDevice from homeassistant.components.http import HomeAssistantView from homeassistant.const import HTTP_UNPROCESSABLE_ENTITY +from homeassistant.core import callback _LOGGER = logging.getLogger(__name__) @@ -81,6 +82,7 @@ class MyStromBinarySensor(BinarySensorDevice): """Return true if the binary sensor is on.""" return self._state + @callback def async_on_update(self, value): """Receive an update.""" self._state = value diff --git a/homeassistant/components/notify/__init__.py b/homeassistant/components/notify/__init__.py index 8211fdc0828..1ea0b9aa6d5 100644 --- a/homeassistant/components/notify/__init__.py +++ b/homeassistant/components/notify/__init__.py @@ -177,10 +177,9 @@ class BaseNotificationService: """ raise NotImplementedError() - def async_send_message(self, message, **kwargs): + async def async_send_message(self, message, **kwargs): """Send a message. kwargs can contain ATTR_TITLE to specify a title. - This method must be run in the event loop and returns a coroutine. """ - return self.hass.async_add_job(partial(self.send_message, message, **kwargs)) + await self.hass.async_add_job(partial(self.send_message, message, **kwargs)) diff --git a/homeassistant/components/plex/media_player.py b/homeassistant/components/plex/media_player.py index 46b797976ab..d8155d1a43b 100644 --- a/homeassistant/components/plex/media_player.py +++ b/homeassistant/components/plex/media_player.py @@ -59,6 +59,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): server_id = config_entry.data[CONF_SERVER_IDENTIFIER] registry = await async_get_registry(hass) + @callback def async_new_media_players(new_entities): _async_add_entities( hass, registry, config_entry, async_add_entities, server_id, new_entities diff --git a/homeassistant/components/remote/__init__.py b/homeassistant/components/remote/__init__.py index 2abd5844001..a3feccaf10c 100644 --- a/homeassistant/components/remote/__init__.py +++ b/homeassistant/components/remote/__init__.py @@ -119,12 +119,9 @@ class RemoteDevice(ToggleEntity): """Send a command to a device.""" raise NotImplementedError() - def async_send_command(self, command, **kwargs): - """Send a command to a device. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_executor_job( + async def async_send_command(self, command, **kwargs): + """Send a command to a device.""" + await self.hass.async_add_executor_job( ft.partial(self.send_command, command, **kwargs) ) @@ -132,11 +129,6 @@ class RemoteDevice(ToggleEntity): """Learn a command from a device.""" raise NotImplementedError() - def async_learn_command(self, **kwargs): - """Learn a command from a device. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_executor_job( - ft.partial(self.learn_command, **kwargs) - ) + async def async_learn_command(self, **kwargs): + """Learn a command from a device.""" + await self.hass.async_add_executor_job(ft.partial(self.learn_command, **kwargs)) diff --git a/homeassistant/components/rest_command/__init__.py b/homeassistant/components/rest_command/__init__.py index 7dfbb964167..bb2ede6d555 100644 --- a/homeassistant/components/rest_command/__init__.py +++ b/homeassistant/components/rest_command/__init__.py @@ -16,6 +16,7 @@ from homeassistant.const import ( CONF_USERNAME, CONF_VERIFY_SSL, ) +from homeassistant.core import callback from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv @@ -55,6 +56,7 @@ CONFIG_SCHEMA = vol.Schema( async def async_setup(hass, config): """Set up the REST command component.""" + @callback def async_register_rest_command(name, command_config): """Create service for rest command.""" websession = async_get_clientsession(hass, command_config.get(CONF_VERIFY_SSL)) diff --git a/homeassistant/components/rflink/__init__.py b/homeassistant/components/rflink/__init__.py index 2e5875b9d08..b8665fae9ef 100644 --- a/homeassistant/components/rflink/__init__.py +++ b/homeassistant/components/rflink/__init__.py @@ -552,10 +552,10 @@ class SwitchableRflinkDevice(RflinkCommand, RestoreEntity): elif command in ["off", "alloff"]: self._state = False - def async_turn_on(self, **kwargs): + async def async_turn_on(self, **kwargs): """Turn the device on.""" - return self._async_handle_command("turn_on") + await self._async_handle_command("turn_on") - def async_turn_off(self, **kwargs): + async def async_turn_off(self, **kwargs): """Turn the device off.""" - return self._async_handle_command("turn_off") + await self._async_handle_command("turn_off") diff --git a/homeassistant/components/rflink/cover.py b/homeassistant/components/rflink/cover.py index f41c4cde2f7..5db82a1d4e8 100644 --- a/homeassistant/components/rflink/cover.py +++ b/homeassistant/components/rflink/cover.py @@ -146,17 +146,17 @@ class RflinkCover(RflinkCommand, CoverDevice, RestoreEntity): """Return True because covers can be stopped midway.""" return True - def async_close_cover(self, **kwargs): + async def async_close_cover(self, **kwargs): """Turn the device close.""" - return self._async_handle_command("close_cover") + await self._async_handle_command("close_cover") - def async_open_cover(self, **kwargs): + async def async_open_cover(self, **kwargs): """Turn the device open.""" - return self._async_handle_command("open_cover") + await self._async_handle_command("open_cover") - def async_stop_cover(self, **kwargs): + async def async_stop_cover(self, **kwargs): """Turn the device stop.""" - return self._async_handle_command("stop_cover") + await self._async_handle_command("stop_cover") class InvertedRflinkCover(RflinkCover): diff --git a/homeassistant/components/russound_rio/media_player.py b/homeassistant/components/russound_rio/media_player.py index c954553160e..a1fe057d9fb 100644 --- a/homeassistant/components/russound_rio/media_player.py +++ b/homeassistant/components/russound_rio/media_player.py @@ -185,22 +185,23 @@ class RussoundZoneDevice(MediaPlayerDevice): """ return float(self._zone_var("volume", 0)) / 50.0 - def async_turn_off(self): + async def async_turn_off(self): """Turn off the zone.""" - return self._russ.send_zone_event(self._zone_id, "ZoneOff") + await self._russ.send_zone_event(self._zone_id, "ZoneOff") - def async_turn_on(self): + async def async_turn_on(self): """Turn on the zone.""" - return self._russ.send_zone_event(self._zone_id, "ZoneOn") + await self._russ.send_zone_event(self._zone_id, "ZoneOn") - def async_set_volume_level(self, volume): + async def async_set_volume_level(self, volume): """Set the volume level.""" rvol = int(volume * 50.0) - return self._russ.send_zone_event(self._zone_id, "KeyPress", "Volume", rvol) + await self._russ.send_zone_event(self._zone_id, "KeyPress", "Volume", rvol) - def async_select_source(self, source): + async def async_select_source(self, source): """Select the source input for this zone.""" for source_id, name in self._sources: if name.lower() != source.lower(): continue - return self._russ.send_zone_event(self._zone_id, "SelectSource", source_id) + await self._russ.send_zone_event(self._zone_id, "SelectSource", source_id) + break diff --git a/homeassistant/components/saj/sensor.py b/homeassistant/components/saj/sensor.py index 704e9996d2d..30399640088 100644 --- a/homeassistant/components/saj/sensor.py +++ b/homeassistant/components/saj/sensor.py @@ -225,6 +225,7 @@ class SAJsensor(Entity): """Return the date when the sensor was last updated.""" return self._sensor.date + @callback def async_update_values(self, unknown_state=False): """Update this sensor.""" update = False diff --git a/homeassistant/components/scene/__init__.py b/homeassistant/components/scene/__init__.py index 8b530e1e728..46b06b93698 100644 --- a/homeassistant/components/scene/__init__.py +++ b/homeassistant/components/scene/__init__.py @@ -94,9 +94,6 @@ class Scene(Entity): """Activate scene. Try to get entities into requested state.""" raise NotImplementedError() - def async_activate(self): - """Activate scene. Try to get entities into requested state. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(self.activate) + async def async_activate(self): + """Activate scene. Try to get entities into requested state.""" + await self.hass.async_add_job(self.activate) diff --git a/homeassistant/components/sensor/device_condition.py b/homeassistant/components/sensor/device_condition.py index 7417765f9f4..bb0348eb6a7 100644 --- a/homeassistant/components/sensor/device_condition.py +++ b/homeassistant/components/sensor/device_condition.py @@ -22,7 +22,7 @@ from homeassistant.const import ( DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_TIMESTAMP, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import condition, config_validation as cv from homeassistant.helpers.entity_registry import ( async_entries_for_device, @@ -128,6 +128,7 @@ async def async_get_conditions( return conditions +@callback def async_condition_from_config( config: ConfigType, config_validation: bool ) -> condition.ConditionCheckerType: diff --git a/homeassistant/components/shopping_list/__init__.py b/homeassistant/components/shopping_list/__init__.py index 856ea0784ba..50d317c9095 100644 --- a/homeassistant/components/shopping_list/__init__.py +++ b/homeassistant/components/shopping_list/__init__.py @@ -153,15 +153,14 @@ class ShoppingData: self.items = [itm for itm in self.items if not itm["complete"]] self.hass.async_add_job(self.save) - @asyncio.coroutine - def async_load(self): + async def async_load(self): """Load items.""" def load(): """Load the items synchronously.""" return load_json(self.hass.config.path(PERSISTENCE), default=[]) - self.items = yield from self.hass.async_add_job(load) + self.items = await self.hass.async_add_executor_job(load) def save(self): """Save the items.""" diff --git a/homeassistant/components/sma/sensor.py b/homeassistant/components/sma/sensor.py index 8caebb4f871..40ec4179cd1 100644 --- a/homeassistant/components/sma/sensor.py +++ b/homeassistant/components/sma/sensor.py @@ -16,6 +16,7 @@ from homeassistant.const import ( CONF_VERIFY_SSL, EVENT_HOMEASSISTANT_STOP, ) +from homeassistant.core import callback from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity @@ -210,6 +211,7 @@ class SMAsensor(Entity): """SMA sensors are updated & don't poll.""" return False + @callback def async_update_values(self): """Update this sensor.""" update = False diff --git a/homeassistant/components/squeezebox/media_player.py b/homeassistant/components/squeezebox/media_player.py index 94c497e4db6..0610d4d9cf2 100644 --- a/homeassistant/components/squeezebox/media_player.py +++ b/homeassistant/components/squeezebox/media_player.py @@ -281,12 +281,9 @@ class SqueezeBoxDevice(MediaPlayerDevice): return STATE_IDLE return None - def async_query(self, *parameters): - """Send a command to the LMS. - - This method must be run in the event loop and returns a coroutine. - """ - return self._lms.async_query(*parameters, player=self._id) + async def async_query(self, *parameters): + """Send a command to the LMS.""" + return await self._lms.async_query(*parameters, player=self._id) async def async_update(self): """Retrieve the current state of the player.""" @@ -420,121 +417,85 @@ class SqueezeBoxDevice(MediaPlayerDevice): """Flag media player features that are supported.""" return SUPPORT_SQUEEZEBOX - def async_turn_off(self): - """Turn off media player. + async def async_turn_off(self): + """Turn off media player.""" + await self.async_query("power", "0") - This method must be run in the event loop and returns a coroutine. - """ - return self.async_query("power", "0") + async def async_volume_up(self): + """Volume up media player.""" + await self.async_query("mixer", "volume", "+5") - def async_volume_up(self): - """Volume up media player. + async def async_volume_down(self): + """Volume down media player.""" + await self.async_query("mixer", "volume", "-5") - This method must be run in the event loop and returns a coroutine. - """ - return self.async_query("mixer", "volume", "+5") - - def async_volume_down(self): - """Volume down media player. - - This method must be run in the event loop and returns a coroutine. - """ - return self.async_query("mixer", "volume", "-5") - - def async_set_volume_level(self, volume): - """Set volume level, range 0..1. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_set_volume_level(self, volume): + """Set volume level, range 0..1.""" volume_percent = str(int(volume * 100)) - return self.async_query("mixer", "volume", volume_percent) + await self.async_query("mixer", "volume", volume_percent) - def async_mute_volume(self, mute): - """Mute (true) or unmute (false) media player. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_mute_volume(self, mute): + """Mute (true) or unmute (false) media player.""" mute_numeric = "1" if mute else "0" - return self.async_query("mixer", "muting", mute_numeric) + await self.async_query("mixer", "muting", mute_numeric) - def async_media_play_pause(self): - """Send pause command to media player. + async def async_media_play_pause(self): + """Send pause command to media player.""" + await self.async_query("pause") - This method must be run in the event loop and returns a coroutine. - """ - return self.async_query("pause") + async def async_media_play(self): + """Send play command to media player.""" + await self.async_query("play") - def async_media_play(self): - """Send play command to media player. + async def async_media_pause(self): + """Send pause command to media player.""" + await self.async_query("pause", "1") - This method must be run in the event loop and returns a coroutine. - """ - return self.async_query("play") + async def async_media_next_track(self): + """Send next track command.""" + await self.async_query("playlist", "index", "+1") - def async_media_pause(self): - """Send pause command to media player. + async def async_media_previous_track(self): + """Send next track command.""" + await self.async_query("playlist", "index", "-1") - This method must be run in the event loop and returns a coroutine. - """ - return self.async_query("pause", "1") + async def async_media_seek(self, position): + """Send seek command.""" + await self.async_query("time", position) - def async_media_next_track(self): - """Send next track command. + async def async_turn_on(self): + """Turn the media player on.""" + await self.async_query("power", "1") - This method must be run in the event loop and returns a coroutine. - """ - return self.async_query("playlist", "index", "+1") - - def async_media_previous_track(self): - """Send next track command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.async_query("playlist", "index", "-1") - - def async_media_seek(self, position): - """Send seek command. - - This method must be run in the event loop and returns a coroutine. - """ - return self.async_query("time", position) - - def async_turn_on(self): - """Turn the media player on. - - This method must be run in the event loop and returns a coroutine. - """ - return self.async_query("power", "1") - - def async_play_media(self, media_type, media_id, **kwargs): + async def async_play_media(self, media_type, media_id, **kwargs): """ Send the play_media command to the media player. If ATTR_MEDIA_ENQUEUE is True, add `media_id` to the current playlist. - This method must be run in the event loop and returns a coroutine. """ if kwargs.get(ATTR_MEDIA_ENQUEUE): - return self._add_uri_to_playlist(media_id) + await self._add_uri_to_playlist(media_id) + return - return self._play_uri(media_id) + await self._play_uri(media_id) - def _play_uri(self, media_id): + async def _play_uri(self, media_id): """Replace the current play list with the uri.""" - return self.async_query("playlist", "play", media_id) + await self.async_query("playlist", "play", media_id) - def _add_uri_to_playlist(self, media_id): + async def _add_uri_to_playlist(self, media_id): """Add an item to the existing playlist.""" - return self.async_query("playlist", "add", media_id) + await self.async_query("playlist", "add", media_id) - def async_set_shuffle(self, shuffle): + async def async_set_shuffle(self, shuffle): """Enable/disable shuffle mode.""" - return self.async_query("playlist", "shuffle", int(shuffle)) + await self.async_query("playlist", "shuffle", int(shuffle)) - def async_clear_playlist(self): + async def async_clear_playlist(self): """Send the media player the command for clear playlist.""" - return self.async_query("playlist", "clear") + await self.async_query("playlist", "clear") - def async_call_method(self, command, parameters=None): + async def async_call_method(self, command, parameters=None): """ Call Squeezebox JSON/RPC method. @@ -545,4 +506,4 @@ class SqueezeBoxDevice(MediaPlayerDevice): if parameters: for parameter in parameters: all_params.append(parameter) - return self.async_query(*all_params) + await self.async_query(*all_params) diff --git a/homeassistant/components/switch/device_condition.py b/homeassistant/components/switch/device_condition.py index 87aefdb616d..c928deef01a 100644 --- a/homeassistant/components/switch/device_condition.py +++ b/homeassistant/components/switch/device_condition.py @@ -5,7 +5,7 @@ import voluptuous as vol from homeassistant.components.device_automation import toggle_entity from homeassistant.const import CONF_DOMAIN -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.condition import ConditionCheckerType from homeassistant.helpers.typing import ConfigType @@ -16,6 +16,7 @@ CONDITION_SCHEMA = toggle_entity.CONDITION_SCHEMA.extend( ) +@callback def async_condition_from_config( config: ConfigType, config_validation: bool ) -> ConditionCheckerType: diff --git a/homeassistant/components/switcher_kis/switch.py b/homeassistant/components/switcher_kis/switch.py index c8eaddcb5bd..8c9c9e1a6fa 100644 --- a/homeassistant/components/switcher_kis/switch.py +++ b/homeassistant/components/switcher_kis/switch.py @@ -124,17 +124,11 @@ class SwitcherControl(SwitchDevice): self.async_schedule_update_ha_state() async def async_turn_on(self, **kwargs: Dict) -> None: - """Turn the entity on. - - This method must be run in the event loop and returns a coroutine. - """ + """Turn the entity on.""" await self._control_device(True) async def async_turn_off(self, **kwargs: Dict) -> None: - """Turn the entity off. - - This method must be run in the event loop and returns a coroutine. - """ + """Turn the entity off.""" await self._control_device(False) async def _control_device(self, send_on: bool) -> None: diff --git a/homeassistant/components/tts/__init__.py b/homeassistant/components/tts/__init__.py index 8ae06771618..318101605e8 100644 --- a/homeassistant/components/tts/__init__.py +++ b/homeassistant/components/tts/__init__.py @@ -501,14 +501,12 @@ class Provider: """Load tts audio file from provider.""" raise NotImplementedError() - def async_get_tts_audio(self, message, language, options=None): + async def async_get_tts_audio(self, message, language, options=None): """Load tts audio file from provider. Return a tuple of file extension and data as bytes. - - This method must be run in the event loop and returns a coroutine. """ - return self.hass.async_add_job( + return await self.hass.async_add_job( ft.partial(self.get_tts_audio, message, language, options=options) ) diff --git a/homeassistant/components/universal/media_player.py b/homeassistant/components/universal/media_player.py index 37d4cf138f2..803793d0683 100644 --- a/homeassistant/components/universal/media_player.py +++ b/homeassistant/components/universal/media_player.py @@ -137,10 +137,7 @@ class UniversalMediaPlayer(MediaPlayerDevice): self._state_template.hass = hass async def async_added_to_hass(self): - """Subscribe to children and template state changes. - - This method must be run in the event loop and returns a coroutine. - """ + """Subscribe to children and template state changes.""" @callback def async_on_dependency_update(*_): @@ -416,132 +413,79 @@ class UniversalMediaPlayer(MediaPlayerDevice): """When was the position of the current playing media valid.""" return self._child_attr(ATTR_MEDIA_POSITION_UPDATED_AT) - def async_turn_on(self): - """Turn the media player on. + async def async_turn_on(self): + """Turn the media player on.""" + await self._async_call_service(SERVICE_TURN_ON, allow_override=True) - This method must be run in the event loop and returns a coroutine. - """ - return self._async_call_service(SERVICE_TURN_ON, allow_override=True) + async def async_turn_off(self): + """Turn the media player off.""" + await self._async_call_service(SERVICE_TURN_OFF, allow_override=True) - def async_turn_off(self): - """Turn the media player off. - - This method must be run in the event loop and returns a coroutine. - """ - return self._async_call_service(SERVICE_TURN_OFF, allow_override=True) - - def async_mute_volume(self, mute): - """Mute the volume. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_mute_volume(self, mute): + """Mute the volume.""" data = {ATTR_MEDIA_VOLUME_MUTED: mute} - return self._async_call_service(SERVICE_VOLUME_MUTE, data, allow_override=True) + await self._async_call_service(SERVICE_VOLUME_MUTE, data, allow_override=True) - def async_set_volume_level(self, volume): - """Set volume level, range 0..1. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_set_volume_level(self, volume): + """Set volume level, range 0..1.""" data = {ATTR_MEDIA_VOLUME_LEVEL: volume} - return self._async_call_service(SERVICE_VOLUME_SET, data, allow_override=True) + await self._async_call_service(SERVICE_VOLUME_SET, data, allow_override=True) - def async_media_play(self): - """Send play command. + async def async_media_play(self): + """Send play command.""" + await self._async_call_service(SERVICE_MEDIA_PLAY) - This method must be run in the event loop and returns a coroutine. - """ - return self._async_call_service(SERVICE_MEDIA_PLAY) + async def async_media_pause(self): + """Send pause command.""" + await self._async_call_service(SERVICE_MEDIA_PAUSE) - def async_media_pause(self): - """Send pause command. + async def async_media_stop(self): + """Send stop command.""" + await self._async_call_service(SERVICE_MEDIA_STOP) - This method must be run in the event loop and returns a coroutine. - """ - return self._async_call_service(SERVICE_MEDIA_PAUSE) + async def async_media_previous_track(self): + """Send previous track command.""" + await self._async_call_service(SERVICE_MEDIA_PREVIOUS_TRACK) - def async_media_stop(self): - """Send stop command. + async def async_media_next_track(self): + """Send next track command.""" + await self._async_call_service(SERVICE_MEDIA_NEXT_TRACK) - This method must be run in the event loop and returns a coroutine. - """ - return self._async_call_service(SERVICE_MEDIA_STOP) - - def async_media_previous_track(self): - """Send previous track command. - - This method must be run in the event loop and returns a coroutine. - """ - return self._async_call_service(SERVICE_MEDIA_PREVIOUS_TRACK) - - def async_media_next_track(self): - """Send next track command. - - This method must be run in the event loop and returns a coroutine. - """ - return self._async_call_service(SERVICE_MEDIA_NEXT_TRACK) - - def async_media_seek(self, position): - """Send seek command. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_media_seek(self, position): + """Send seek command.""" data = {ATTR_MEDIA_SEEK_POSITION: position} - return self._async_call_service(SERVICE_MEDIA_SEEK, data) + await self._async_call_service(SERVICE_MEDIA_SEEK, data) - def async_play_media(self, media_type, media_id, **kwargs): - """Play a piece of media. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_play_media(self, media_type, media_id, **kwargs): + """Play a piece of media.""" data = {ATTR_MEDIA_CONTENT_TYPE: media_type, ATTR_MEDIA_CONTENT_ID: media_id} - return self._async_call_service(SERVICE_PLAY_MEDIA, data) + await self._async_call_service(SERVICE_PLAY_MEDIA, data) - def async_volume_up(self): - """Turn volume up for media player. + async def async_volume_up(self): + """Turn volume up for media player.""" + await self._async_call_service(SERVICE_VOLUME_UP, allow_override=True) - This method must be run in the event loop and returns a coroutine. - """ - return self._async_call_service(SERVICE_VOLUME_UP, allow_override=True) + async def async_volume_down(self): + """Turn volume down for media player.""" + await self._async_call_service(SERVICE_VOLUME_DOWN, allow_override=True) - def async_volume_down(self): - """Turn volume down for media player. + async def async_media_play_pause(self): + """Play or pause the media player.""" + await self._async_call_service(SERVICE_MEDIA_PLAY_PAUSE) - This method must be run in the event loop and returns a coroutine. - """ - return self._async_call_service(SERVICE_VOLUME_DOWN, allow_override=True) - - def async_media_play_pause(self): - """Play or pause the media player. - - This method must be run in the event loop and returns a coroutine. - """ - return self._async_call_service(SERVICE_MEDIA_PLAY_PAUSE) - - def async_select_source(self, source): - """Set the input source. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_select_source(self, source): + """Set the input source.""" data = {ATTR_INPUT_SOURCE: source} - return self._async_call_service( - SERVICE_SELECT_SOURCE, data, allow_override=True - ) + await self._async_call_service(SERVICE_SELECT_SOURCE, data, allow_override=True) - def async_clear_playlist(self): - """Clear players playlist. + async def async_clear_playlist(self): + """Clear players playlist.""" + await self._async_call_service(SERVICE_CLEAR_PLAYLIST) - This method must be run in the event loop and returns a coroutine. - """ - return self._async_call_service(SERVICE_CLEAR_PLAYLIST) - - def async_set_shuffle(self, shuffle): - """Enable/disable shuffling. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_set_shuffle(self, shuffle): + """Enable/disable shuffling.""" data = {ATTR_MEDIA_SHUFFLE: shuffle} - return self._async_call_service(SERVICE_SHUFFLE_SET, data, allow_override=True) + await self._async_call_service(SERVICE_SHUFFLE_SET, data, allow_override=True) async def async_update(self): """Update state in HA.""" diff --git a/homeassistant/components/vacuum/device_condition.py b/homeassistant/components/vacuum/device_condition.py index 5a2eefd94f2..cb17505f6e1 100644 --- a/homeassistant/components/vacuum/device_condition.py +++ b/homeassistant/components/vacuum/device_condition.py @@ -11,7 +11,7 @@ from homeassistant.const import ( CONF_ENTITY_ID, CONF_TYPE, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import condition, config_validation as cv, entity_registry from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA from homeassistant.helpers.typing import ConfigType, TemplateVarsType @@ -62,6 +62,7 @@ async def async_get_conditions( return conditions +@callback def async_condition_from_config( config: ConfigType, config_validation: bool ) -> condition.ConditionCheckerType: diff --git a/homeassistant/components/volumio/media_player.py b/homeassistant/components/volumio/media_player.py index f62a74345b1..369b9c33c0d 100644 --- a/homeassistant/components/volumio/media_player.py +++ b/homeassistant/components/volumio/media_player.py @@ -251,73 +251,75 @@ class Volumio(MediaPlayerDevice): """Flag of media commands that are supported.""" return SUPPORT_VOLUMIO - def async_media_next_track(self): + async def async_media_next_track(self): """Send media_next command to media player.""" - return self.send_volumio_msg("commands", params={"cmd": "next"}) + await self.send_volumio_msg("commands", params={"cmd": "next"}) - def async_media_previous_track(self): + async def async_media_previous_track(self): """Send media_previous command to media player.""" - return self.send_volumio_msg("commands", params={"cmd": "prev"}) + await self.send_volumio_msg("commands", params={"cmd": "prev"}) - def async_media_play(self): + async def async_media_play(self): """Send media_play command to media player.""" - return self.send_volumio_msg("commands", params={"cmd": "play"}) + await self.send_volumio_msg("commands", params={"cmd": "play"}) - def async_media_pause(self): + async def async_media_pause(self): """Send media_pause command to media player.""" if self._state["trackType"] == "webradio": - return self.send_volumio_msg("commands", params={"cmd": "stop"}) - return self.send_volumio_msg("commands", params={"cmd": "pause"}) + await self.send_volumio_msg("commands", params={"cmd": "stop"}) + else: + await self.send_volumio_msg("commands", params={"cmd": "pause"}) - def async_set_volume_level(self, volume): + async def async_set_volume_level(self, volume): """Send volume_up command to media player.""" - return self.send_volumio_msg( + await self.send_volumio_msg( "commands", params={"cmd": "volume", "volume": int(volume * 100)} ) - def async_volume_up(self): + async def async_volume_up(self): """Service to send the Volumio the command for volume up.""" - return self.send_volumio_msg( + await self.send_volumio_msg( "commands", params={"cmd": "volume", "volume": "plus"} ) - def async_volume_down(self): + async def async_volume_down(self): """Service to send the Volumio the command for volume down.""" - return self.send_volumio_msg( + await self.send_volumio_msg( "commands", params={"cmd": "volume", "volume": "minus"} ) - def async_mute_volume(self, mute): + async def async_mute_volume(self, mute): """Send mute command to media player.""" mutecmd = "mute" if mute else "unmute" if mute: # mute is implemented as 0 volume, do save last volume level self._lastvol = self._state["volume"] - return self.send_volumio_msg( + await self.send_volumio_msg( "commands", params={"cmd": "volume", "volume": mutecmd} ) + return - return self.send_volumio_msg( + await self.send_volumio_msg( "commands", params={"cmd": "volume", "volume": self._lastvol} ) - def async_set_shuffle(self, shuffle): + async def async_set_shuffle(self, shuffle): """Enable/disable shuffle mode.""" - return self.send_volumio_msg( + await self.send_volumio_msg( "commands", params={"cmd": "random", "value": str(shuffle).lower()} ) - def async_select_source(self, source): + async def async_select_source(self, source): """Choose a different available playlist and play it.""" self._currentplaylist = source - return self.send_volumio_msg( + await self.send_volumio_msg( "commands", params={"cmd": "playplaylist", "name": source} ) - def async_clear_playlist(self): + async def async_clear_playlist(self): """Clear players playlist.""" self._currentplaylist = None - return self.send_volumio_msg("commands", params={"cmd": "clearQueue"}) + await self.send_volumio_msg("commands", params={"cmd": "clearQueue"}) @Throttle(PLAYLIST_UPDATE_INTERVAL) async def _async_update_playlists(self, **kwargs): diff --git a/homeassistant/components/zha/api.py b/homeassistant/components/zha/api.py index fe628d90e90..ea5586ef96f 100644 --- a/homeassistant/components/zha/api.py +++ b/homeassistant/components/zha/api.py @@ -780,6 +780,7 @@ async def async_binding_operation(zha_gateway, source_ieee, target_ieee, operati zdo.debug(fmt, *(log_msg[2] + (outcome,))) +@callback def async_load_api(hass): """Set up the web socket API.""" zha_gateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY] @@ -1058,6 +1059,7 @@ def async_load_api(hass): websocket_api.async_register_command(hass, websocket_unbind_devices) +@callback def async_unload_api(hass): """Unload the ZHA API.""" hass.services.async_remove(DOMAIN, SERVICE_PERMIT) diff --git a/homeassistant/components/zha/binary_sensor.py b/homeassistant/components/zha/binary_sensor.py index d25410a0667..58b671a340f 100644 --- a/homeassistant/components/zha/binary_sensor.py +++ b/homeassistant/components/zha/binary_sensor.py @@ -125,6 +125,7 @@ class BinarySensor(ZhaEntity, BinarySensorDevice): """Return device class from component DEVICE_CLASSES.""" return self._device_class + @callback def async_set_state(self, state): """Set the state.""" self._state = bool(state) diff --git a/homeassistant/components/zha/core/gateway.py b/homeassistant/components/zha/core/gateway.py index 9456b8e9088..e5a199c5bbd 100644 --- a/homeassistant/components/zha/core/gateway.py +++ b/homeassistant/components/zha/core/gateway.py @@ -273,6 +273,7 @@ class ZHAGateway: """Return Group for given group id.""" return self.groups.get(group_id) + @callback def async_get_group_by_name(self, group_name): """Get ZHA group by name.""" for group in self.groups.values(): diff --git a/homeassistant/components/zha/cover.py b/homeassistant/components/zha/cover.py index d4fff97c021..3eeb73a23fd 100644 --- a/homeassistant/components/zha/cover.py +++ b/homeassistant/components/zha/cover.py @@ -113,6 +113,7 @@ class ZhaCover(ZhaEntity, CoverDevice): """ return self._current_position + @callback def async_set_position(self, pos): """Handle position update from channel.""" _LOGGER.debug("setting position: %s", pos) @@ -123,6 +124,7 @@ class ZhaCover(ZhaEntity, CoverDevice): self._state = STATE_OPEN self.async_schedule_update_ha_state() + @callback def async_set_state(self, state): """Handle state update from channel.""" _LOGGER.debug("state=%s", state) diff --git a/homeassistant/components/zha/entity.py b/homeassistant/components/zha/entity.py index 0b001bdedbc..6a9dfc63432 100644 --- a/homeassistant/components/zha/entity.py +++ b/homeassistant/components/zha/entity.py @@ -99,16 +99,19 @@ class ZhaEntity(RestoreEntity, LogMixin, entity.Entity): """Return entity availability.""" return self._available + @callback def async_set_available(self, available): """Set entity availability.""" self._available = available self.async_schedule_update_ha_state() + @callback def async_update_state_attribute(self, key, value): """Update a single device state attribute.""" self._device_state_attributes.update({key: value}) self.async_schedule_update_ha_state() + @callback def async_set_state(self, state): """Set the entity state.""" pass diff --git a/homeassistant/components/zha/fan.py b/homeassistant/components/zha/fan.py index 50e9f63a067..6ad13d1c802 100644 --- a/homeassistant/components/zha/fan.py +++ b/homeassistant/components/zha/fan.py @@ -136,6 +136,7 @@ class ZhaFan(ZhaEntity, FanEntity): """Return state attributes.""" return self.state_attributes + @callback def async_set_state(self, state): """Handle state update from channel.""" self._state = VALUE_TO_SPEED.get(state, self._state) diff --git a/homeassistant/components/zha/light.py b/homeassistant/components/zha/light.py index 11fa87d4618..409cd339122 100644 --- a/homeassistant/components/zha/light.py +++ b/homeassistant/components/zha/light.py @@ -170,6 +170,7 @@ class Light(ZhaEntity, light.Light): """Flag supported features.""" return self._supported_features + @callback def async_set_state(self, state): """Set the state.""" self._state = bool(state) diff --git a/homeassistant/components/zha/lock.py b/homeassistant/components/zha/lock.py index 584df99fe08..b173c166a77 100644 --- a/homeassistant/components/zha/lock.py +++ b/homeassistant/components/zha/lock.py @@ -125,6 +125,7 @@ class ZhaDoorLock(ZhaEntity, LockDevice): await super().async_update() await self.async_get_state() + @callback def async_set_state(self, state): """Handle state update from channel.""" self._state = VALUE_TO_STATE.get(state, self._state) diff --git a/homeassistant/components/zha/sensor.py b/homeassistant/components/zha/sensor.py index 52d4660a467..8b7dd894973 100644 --- a/homeassistant/components/zha/sensor.py +++ b/homeassistant/components/zha/sensor.py @@ -149,6 +149,7 @@ class Sensor(ZhaEntity): return None return self._state + @callback def async_set_state(self, state): """Handle state update from channel.""" if state is not None: @@ -202,6 +203,7 @@ class Battery(Sensor): state_attrs["battery_quantity"] = battery_quantity return state_attrs + @callback def async_update_state_attribute(self, key, value): """Update a single device state attribute.""" if key == "battery_voltage": diff --git a/homeassistant/components/zha/switch.py b/homeassistant/components/zha/switch.py index a68fca76af4..1280ace34dc 100644 --- a/homeassistant/components/zha/switch.py +++ b/homeassistant/components/zha/switch.py @@ -93,6 +93,7 @@ class Switch(ZhaEntity, SwitchDevice): self._state = False self.async_schedule_update_ha_state() + @callback def async_set_state(self, state): """Handle state update from channel.""" self._state = bool(state) diff --git a/homeassistant/helpers/device_registry.py b/homeassistant/helpers/device_registry.py index 41c78a2f070..0821b909dc7 100644 --- a/homeassistant/helpers/device_registry.py +++ b/homeassistant/helpers/device_registry.py @@ -260,6 +260,7 @@ class DeviceRegistry: return new + @callback def async_remove_device(self, device_id: str) -> None: """Remove a device from the device registry.""" del self.devices[device_id] diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index b9d1a73351c..a2a0ae840e0 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -596,23 +596,17 @@ class ToggleEntity(Entity): """Turn the entity on.""" raise NotImplementedError() - def async_turn_on(self, **kwargs): - """Turn the entity on. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(ft.partial(self.turn_on, **kwargs)) + async def async_turn_on(self, **kwargs): + """Turn the entity on.""" + await self.hass.async_add_job(ft.partial(self.turn_on, **kwargs)) def turn_off(self, **kwargs: Any) -> None: """Turn the entity off.""" raise NotImplementedError() - def async_turn_off(self, **kwargs): - """Turn the entity off. - - This method must be run in the event loop and returns a coroutine. - """ - return self.hass.async_add_job(ft.partial(self.turn_off, **kwargs)) + async def async_turn_off(self, **kwargs): + """Turn the entity off.""" + await self.hass.async_add_job(ft.partial(self.turn_off, **kwargs)) def toggle(self, **kwargs: Any) -> None: """Toggle the entity.""" @@ -621,11 +615,9 @@ class ToggleEntity(Entity): else: self.turn_on(**kwargs) - def async_toggle(self, **kwargs): - """Toggle the entity. - - This method must be run in the event loop and returns a coroutine. - """ + async def async_toggle(self, **kwargs): + """Toggle the entity.""" if self.is_on: - return self.async_turn_off(**kwargs) - return self.async_turn_on(**kwargs) + await self.async_turn_off(**kwargs) + else: + await self.async_turn_on(**kwargs) diff --git a/homeassistant/helpers/restore_state.py b/homeassistant/helpers/restore_state.py index 0c3dbe96bc5..e8f0f9a6bac 100644 --- a/homeassistant/helpers/restore_state.py +++ b/homeassistant/helpers/restore_state.py @@ -115,6 +115,7 @@ class RestoreStateData: self.last_states: Dict[str, StoredState] = {} self.entity_ids: Set[str] = set() + @callback def async_get_stored_states(self) -> List[StoredState]: """Get the set of states which should be stored. diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 837a561181d..0d973afcfe9 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -214,6 +214,7 @@ class Script: """Stop running script.""" run_callback_threadsafe(self.hass.loop, self.async_stop).result() + @callback def async_stop(self) -> None: """Stop running script.""" if self._cur == -1: diff --git a/script/scaffold/templates/device_condition/integration/device_condition.py b/script/scaffold/templates/device_condition/integration/device_condition.py index 1414636474d..cb2489e4279 100644 --- a/script/scaffold/templates/device_condition/integration/device_condition.py +++ b/script/scaffold/templates/device_condition/integration/device_condition.py @@ -13,7 +13,7 @@ from homeassistant.const import ( STATE_OFF, STATE_ON, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import condition, config_validation as cv, entity_registry from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA from homeassistant.helpers.typing import ConfigType, TemplateVarsType @@ -67,6 +67,7 @@ async def async_get_conditions( return conditions +@callback def async_condition_from_config( config: ConfigType, config_validation: bool ) -> condition.ConditionCheckerType: @@ -78,6 +79,7 @@ def async_condition_from_config( else: state = STATE_OFF + @callback def test_is_state(hass: HomeAssistant, variables: TemplateVarsType) -> bool: """Test if an entity is a certain state.""" return condition.state(hass, config[ATTR_ENTITY_ID], state) diff --git a/tests/components/mqtt/test_server.py b/tests/components/mqtt/test_server.py index 3627c95040e..95f31b67826 100644 --- a/tests/components/mqtt/test_server.py +++ b/tests/components/mqtt/test_server.py @@ -1,5 +1,7 @@ """The tests for the MQTT component embedded server.""" -from unittest.mock import MagicMock, Mock, patch +from unittest.mock import MagicMock, Mock + +from asynctest import CoroutineMock, patch import homeassistant.components.mqtt as mqtt from homeassistant.const import CONF_PASSWORD @@ -21,7 +23,7 @@ class TestMQTT: @patch("passlib.apps.custom_app_context", Mock(return_value="")) @patch("tempfile.NamedTemporaryFile", Mock(return_value=MagicMock())) - @patch("hbmqtt.broker.Broker", Mock(return_value=MagicMock())) + @patch("hbmqtt.broker.Broker", Mock(return_value=MagicMock(start=CoroutineMock()))) @patch("hbmqtt.broker.Broker.start", Mock(return_value=mock_coro())) @patch("homeassistant.components.mqtt.MQTT") def test_creating_config_with_pass_and_no_http_pass(self, mock_mqtt): @@ -43,7 +45,7 @@ class TestMQTT: @patch("passlib.apps.custom_app_context", Mock(return_value="")) @patch("tempfile.NamedTemporaryFile", Mock(return_value=MagicMock())) - @patch("hbmqtt.broker.Broker", Mock(return_value=MagicMock())) + @patch("hbmqtt.broker.Broker", Mock(return_value=MagicMock(start=CoroutineMock()))) @patch("hbmqtt.broker.Broker.start", Mock(return_value=mock_coro())) @patch("homeassistant.components.mqtt.MQTT") def test_creating_config_with_pass_and_http_pass(self, mock_mqtt):