mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Openhome component now uses asyncio and handles unavailability (#49574)
This commit is contained in:
parent
42b92748f6
commit
5ac81ccb4c
@ -2,7 +2,7 @@
|
||||
"domain": "openhome",
|
||||
"name": "Linn / OpenHome",
|
||||
"documentation": "https://www.home-assistant.io/integrations/openhome",
|
||||
"requirements": ["openhomedevice==0.7.2"],
|
||||
"requirements": ["openhomedevice==2.0.1"],
|
||||
"codeowners": ["@bazwilliams"],
|
||||
"iot_class": "local_polling"
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
"""Support for Openhome Devices."""
|
||||
import asyncio
|
||||
import functools
|
||||
import logging
|
||||
|
||||
from openhomedevice.Device import Device
|
||||
import aiohttp
|
||||
from async_upnp_client.client import UpnpError
|
||||
from openhomedevice.device import Device
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.media_player import MediaPlayerEntity
|
||||
@ -43,25 +47,45 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
||||
|
||||
_LOGGER.info("Openhome device found: %s", name)
|
||||
device = await hass.async_add_executor_job(Device, description)
|
||||
await device.init()
|
||||
|
||||
# if device has already been discovered
|
||||
if device.Uuid() in openhome_data:
|
||||
if device.uuid() in openhome_data:
|
||||
return True
|
||||
|
||||
entity = OpenhomeDevice(hass, device)
|
||||
|
||||
async_add_entities([entity])
|
||||
openhome_data.add(device.Uuid())
|
||||
openhome_data.add(device.uuid())
|
||||
|
||||
platform = entity_platform.async_get_current_platform()
|
||||
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_INVOKE_PIN,
|
||||
{vol.Required(ATTR_PIN_INDEX): cv.positive_int},
|
||||
"invoke_pin",
|
||||
"async_invoke_pin",
|
||||
)
|
||||
|
||||
|
||||
def catch_request_errors():
|
||||
"""Catch asyncio.TimeoutError, aiohttp.ClientError, UpnpError errors."""
|
||||
|
||||
def call_wrapper(func):
|
||||
"""Call wrapper for decorator."""
|
||||
|
||||
@functools.wraps(func)
|
||||
async def wrapper(self, *args, **kwargs):
|
||||
"""Catch asyncio.TimeoutError, aiohttp.ClientError, UpnpError errors."""
|
||||
try:
|
||||
return await func(self, *args, **kwargs)
|
||||
except (asyncio.TimeoutError, aiohttp.ClientError, UpnpError):
|
||||
_LOGGER.error("Error during call %s", func.__name__)
|
||||
|
||||
return wrapper
|
||||
|
||||
return call_wrapper
|
||||
|
||||
|
||||
class OpenhomeDevice(MediaPlayerEntity):
|
||||
"""Representation of an Openhome device."""
|
||||
|
||||
@ -80,64 +104,80 @@ class OpenhomeDevice(MediaPlayerEntity):
|
||||
self._source = {}
|
||||
self._name = None
|
||||
self._state = STATE_PLAYING
|
||||
self._available = True
|
||||
|
||||
def update(self):
|
||||
@property
|
||||
def available(self):
|
||||
"""Device is available."""
|
||||
return self._available
|
||||
|
||||
async def async_update(self):
|
||||
"""Update state of device."""
|
||||
self._in_standby = self._device.IsInStandby()
|
||||
self._transport_state = self._device.TransportState()
|
||||
self._track_information = self._device.TrackInfo()
|
||||
self._source = self._device.Source()
|
||||
self._name = self._device.Room().decode("utf-8")
|
||||
self._supported_features = SUPPORT_OPENHOME
|
||||
source_index = {}
|
||||
source_names = []
|
||||
try:
|
||||
self._in_standby = await self._device.is_in_standby()
|
||||
self._transport_state = await self._device.transport_state()
|
||||
self._track_information = await self._device.track_info()
|
||||
self._source = await self._device.source()
|
||||
self._name = await self._device.room()
|
||||
self._supported_features = SUPPORT_OPENHOME
|
||||
source_index = {}
|
||||
source_names = []
|
||||
|
||||
if self._device.VolumeEnabled():
|
||||
self._supported_features |= (
|
||||
SUPPORT_VOLUME_STEP | SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET
|
||||
)
|
||||
self._volume_level = self._device.VolumeLevel() / 100.0
|
||||
self._volume_muted = self._device.IsMuted()
|
||||
if self._device.volume_enabled:
|
||||
self._supported_features |= (
|
||||
SUPPORT_VOLUME_STEP | SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET
|
||||
)
|
||||
self._volume_level = await self._device.volume() / 100.0
|
||||
self._volume_muted = await self._device.is_muted()
|
||||
|
||||
for source in self._device.Sources():
|
||||
source_names.append(source["name"])
|
||||
source_index[source["name"]] = source["index"]
|
||||
for source in await self._device.sources():
|
||||
source_names.append(source["name"])
|
||||
source_index[source["name"]] = source["index"]
|
||||
|
||||
self._source_index = source_index
|
||||
self._source_names = source_names
|
||||
self._source_index = source_index
|
||||
self._source_names = source_names
|
||||
|
||||
if self._source["type"] == "Radio":
|
||||
self._supported_features |= SUPPORT_STOP | SUPPORT_PLAY | SUPPORT_PLAY_MEDIA
|
||||
if self._source["type"] in ("Playlist", "Spotify"):
|
||||
self._supported_features |= (
|
||||
SUPPORT_PREVIOUS_TRACK
|
||||
| SUPPORT_NEXT_TRACK
|
||||
| SUPPORT_PAUSE
|
||||
| SUPPORT_PLAY
|
||||
| SUPPORT_PLAY_MEDIA
|
||||
)
|
||||
if self._source["type"] == "Radio":
|
||||
self._supported_features |= (
|
||||
SUPPORT_STOP | SUPPORT_PLAY | SUPPORT_PLAY_MEDIA
|
||||
)
|
||||
if self._source["type"] in ("Playlist", "Spotify"):
|
||||
self._supported_features |= (
|
||||
SUPPORT_PREVIOUS_TRACK
|
||||
| SUPPORT_NEXT_TRACK
|
||||
| SUPPORT_PAUSE
|
||||
| SUPPORT_PLAY
|
||||
| SUPPORT_PLAY_MEDIA
|
||||
)
|
||||
|
||||
if self._in_standby:
|
||||
self._state = STATE_OFF
|
||||
elif self._transport_state == "Paused":
|
||||
self._state = STATE_PAUSED
|
||||
elif self._transport_state in ("Playing", "Buffering"):
|
||||
self._state = STATE_PLAYING
|
||||
elif self._transport_state == "Stopped":
|
||||
self._state = STATE_IDLE
|
||||
else:
|
||||
# Device is playing an external source with no transport controls
|
||||
self._state = STATE_PLAYING
|
||||
if self._in_standby:
|
||||
self._state = STATE_OFF
|
||||
elif self._transport_state == "Paused":
|
||||
self._state = STATE_PAUSED
|
||||
elif self._transport_state in ("Playing", "Buffering"):
|
||||
self._state = STATE_PLAYING
|
||||
elif self._transport_state == "Stopped":
|
||||
self._state = STATE_IDLE
|
||||
else:
|
||||
# Device is playing an external source with no transport controls
|
||||
self._state = STATE_PLAYING
|
||||
|
||||
def turn_on(self):
|
||||
self._available = True
|
||||
except (asyncio.TimeoutError, aiohttp.ClientError, UpnpError):
|
||||
self._available = False
|
||||
|
||||
@catch_request_errors()
|
||||
async def async_turn_on(self):
|
||||
"""Bring device out of standby."""
|
||||
self._device.SetStandby(False)
|
||||
await self._device.set_standby(False)
|
||||
|
||||
def turn_off(self):
|
||||
@catch_request_errors()
|
||||
async def async_turn_off(self):
|
||||
"""Put device in standby."""
|
||||
self._device.SetStandby(True)
|
||||
await self._device.set_standby(True)
|
||||
|
||||
def play_media(self, media_type, media_id, **kwargs):
|
||||
@catch_request_errors()
|
||||
async def async_play_media(self, media_type, media_id, **kwargs):
|
||||
"""Send the play_media command to the media player."""
|
||||
if media_type != MEDIA_TYPE_MUSIC:
|
||||
_LOGGER.error(
|
||||
@ -147,35 +187,48 @@ class OpenhomeDevice(MediaPlayerEntity):
|
||||
)
|
||||
return
|
||||
track_details = {"title": "Home Assistant", "uri": media_id}
|
||||
self._device.PlayMedia(track_details)
|
||||
await self._device.play_media(track_details)
|
||||
|
||||
def media_pause(self):
|
||||
@catch_request_errors()
|
||||
async def async_media_pause(self):
|
||||
"""Send pause command."""
|
||||
self._device.Pause()
|
||||
await self._device.pause()
|
||||
|
||||
def media_stop(self):
|
||||
@catch_request_errors()
|
||||
async def async_media_stop(self):
|
||||
"""Send stop command."""
|
||||
self._device.Stop()
|
||||
await self._device.stop()
|
||||
|
||||
def media_play(self):
|
||||
@catch_request_errors()
|
||||
async def async_media_play(self):
|
||||
"""Send play command."""
|
||||
self._device.Play()
|
||||
await self._device.play()
|
||||
|
||||
def media_next_track(self):
|
||||
@catch_request_errors()
|
||||
async def async_media_next_track(self):
|
||||
"""Send next track command."""
|
||||
self._device.Skip(1)
|
||||
await self._device.skip(1)
|
||||
|
||||
def media_previous_track(self):
|
||||
@catch_request_errors()
|
||||
async def async_media_previous_track(self):
|
||||
"""Send previous track command."""
|
||||
self._device.Skip(-1)
|
||||
await self._device.skip(-1)
|
||||
|
||||
def select_source(self, source):
|
||||
@catch_request_errors()
|
||||
async def async_select_source(self, source):
|
||||
"""Select input source."""
|
||||
self._device.SetSource(self._source_index[source])
|
||||
await self._device.set_source(self._source_index[source])
|
||||
|
||||
def invoke_pin(self, pin):
|
||||
@catch_request_errors()
|
||||
async def async_invoke_pin(self, pin):
|
||||
"""Invoke pin."""
|
||||
self._device.InvokePin(pin)
|
||||
try:
|
||||
if self._device.pins_enabled:
|
||||
await self._device.invoke_pin(pin)
|
||||
else:
|
||||
_LOGGER.error("Pins service not supported")
|
||||
except (UpnpError):
|
||||
_LOGGER.error("Error invoking pin %s", pin)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
@ -190,7 +243,7 @@ class OpenhomeDevice(MediaPlayerEntity):
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return a unique ID."""
|
||||
return self._device.Uuid()
|
||||
return self._device.uuid()
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
@ -239,18 +292,22 @@ class OpenhomeDevice(MediaPlayerEntity):
|
||||
"""Return true if volume is muted."""
|
||||
return self._volume_muted
|
||||
|
||||
def volume_up(self):
|
||||
@catch_request_errors()
|
||||
async def async_volume_up(self):
|
||||
"""Volume up media player."""
|
||||
self._device.IncreaseVolume()
|
||||
await self._device.increase_volume()
|
||||
|
||||
def volume_down(self):
|
||||
@catch_request_errors()
|
||||
async def async_volume_down(self):
|
||||
"""Volume down media player."""
|
||||
self._device.DecreaseVolume()
|
||||
await self._device.decrease_volume()
|
||||
|
||||
def set_volume_level(self, volume):
|
||||
@catch_request_errors()
|
||||
async def async_set_volume_level(self, volume):
|
||||
"""Set volume level, range 0..1."""
|
||||
self._device.SetVolumeLevel(int(volume * 100))
|
||||
await self._device.set_volume(int(volume * 100))
|
||||
|
||||
def mute_volume(self, mute):
|
||||
@catch_request_errors()
|
||||
async def async_mute_volume(self, mute):
|
||||
"""Mute (true) or unmute (false) media player."""
|
||||
self._device.SetMute(mute)
|
||||
await self._device.set_mute(mute)
|
||||
|
@ -1076,7 +1076,7 @@ openerz-api==0.1.0
|
||||
openevsewifi==1.1.0
|
||||
|
||||
# homeassistant.components.openhome
|
||||
openhomedevice==0.7.2
|
||||
openhomedevice==2.0.1
|
||||
|
||||
# homeassistant.components.opensensemap
|
||||
opensensemap-api==0.1.5
|
||||
|
Loading…
x
Reference in New Issue
Block a user