Fix callback and async (#31281)

* Fix callback and async

* Fix a return

* Fix test

* Fix mqtt tests

* Fix some more callbacks
pull/31290/head
Paulus Schoutsen 2020-01-29 13:59:45 -08:00 committed by GitHub
parent ee602e40a6
commit e9e44dbd97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
90 changed files with 627 additions and 883 deletions

View File

@ -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

View File

@ -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(

View File

@ -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 [

View File

@ -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)

View File

@ -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)()

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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
)

View File

@ -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)

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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]

View File

@ -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

View File

@ -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)

View File

@ -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(

View File

@ -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)

View File

@ -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)

View File

@ -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):

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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 = []

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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":

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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]

View File

@ -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(

View File

@ -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.

View File

@ -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:

View File

@ -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)
)

View File

@ -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)

View File

@ -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."""

View File

@ -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:

View File

@ -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):

View File

@ -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:

View File

@ -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):

View File

@ -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

View File

@ -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):

View File

@ -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:

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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))

View File

@ -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))

View File

@ -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")

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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."""

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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:

View File

@ -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)
)

View File

@ -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."""

View File

@ -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:

View File

@ -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):

View File

@ -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)

View File

@ -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)

View File

@ -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():

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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":

View File

@ -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)

View File

@ -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]

View File

@ -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)

View File

@ -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.

View File

@ -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:

View File

@ -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)

View File

@ -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):