Update rokuecp to 0.13.1 (#65814)

pull/65845/head
Chris Talkington 2022-02-05 22:17:31 -06:00 committed by GitHub
parent 2da4d280b2
commit 15e5f516d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 56 additions and 30 deletions

View File

@ -152,6 +152,7 @@ homeassistant.components.remote.*
homeassistant.components.renault.* homeassistant.components.renault.*
homeassistant.components.ridwell.* homeassistant.components.ridwell.*
homeassistant.components.rituals_perfume_genie.* homeassistant.components.rituals_perfume_genie.*
homeassistant.components.roku.*
homeassistant.components.rpi_power.* homeassistant.components.rpi_power.*
homeassistant.components.rtsp_to_webrtc.* homeassistant.components.rtsp_to_webrtc.*
homeassistant.components.samsungtv.* homeassistant.components.samsungtv.*

View File

@ -1,6 +1,7 @@
"""Support for Roku.""" """Support for Roku."""
from __future__ import annotations from __future__ import annotations
from collections.abc import Callable
import logging import logging
from rokuecp import RokuConnectionError, RokuError from rokuecp import RokuConnectionError, RokuError
@ -46,10 +47,10 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return unload_ok return unload_ok
def roku_exception_handler(func): def roku_exception_handler(func: Callable) -> Callable:
"""Decorate Roku calls to handle Roku exceptions.""" """Decorate Roku calls to handle Roku exceptions."""
async def handler(self, *args, **kwargs): async def handler(self, *args, **kwargs) -> None: # type: ignore
try: try:
await func(self, *args, **kwargs) await func(self, *args, **kwargs)
except RokuConnectionError as error: except RokuConnectionError as error:

View File

@ -69,12 +69,12 @@ def get_thumbnail_url_full(
async def async_browse_media( async def async_browse_media(
hass, hass: HomeAssistant,
coordinator: RokuDataUpdateCoordinator, coordinator: RokuDataUpdateCoordinator,
get_browse_image_url: GetBrowseImageUrlType, get_browse_image_url: GetBrowseImageUrlType,
media_content_id: str | None, media_content_id: str | None,
media_content_type: str | None, media_content_type: str | None,
): ) -> BrowseMedia:
"""Browse media.""" """Browse media."""
if media_content_id is None: if media_content_id is None:
return await root_payload( return await root_payload(
@ -113,7 +113,7 @@ async def root_payload(
hass: HomeAssistant, hass: HomeAssistant,
coordinator: RokuDataUpdateCoordinator, coordinator: RokuDataUpdateCoordinator,
get_browse_image_url: GetBrowseImageUrlType, get_browse_image_url: GetBrowseImageUrlType,
): ) -> BrowseMedia:
"""Return root payload for Roku.""" """Return root payload for Roku."""
device = coordinator.data device = coordinator.data
@ -223,7 +223,7 @@ def item_payload(
item: dict, item: dict,
coordinator: RokuDataUpdateCoordinator, coordinator: RokuDataUpdateCoordinator,
get_browse_image_url: GetBrowseImageUrlType, get_browse_image_url: GetBrowseImageUrlType,
): ) -> BrowseMedia:
""" """
Create response payload for a single media item. Create response payload for a single media item.

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
from typing import Any
from urllib.parse import urlparse from urllib.parse import urlparse
from rokuecp import Roku, RokuError from rokuecp import Roku, RokuError
@ -24,7 +25,7 @@ ERROR_UNKNOWN = "unknown"
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
async def validate_input(hass: HomeAssistant, data: dict) -> dict: async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, Any]:
"""Validate the user input allows us to connect. """Validate the user input allows us to connect.
Data has the keys from DATA_SCHEMA with values provided by the user. Data has the keys from DATA_SCHEMA with values provided by the user.
@ -44,12 +45,14 @@ class RokuConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 1 VERSION = 1
def __init__(self): discovery_info: dict[str, Any]
def __init__(self) -> None:
"""Set up the instance.""" """Set up the instance."""
self.discovery_info = {} self.discovery_info = {}
@callback @callback
def _show_form(self, errors: dict | None = None) -> FlowResult: def _show_form(self, errors: dict[str, Any] | None = None) -> FlowResult:
"""Show the form to the user.""" """Show the form to the user."""
return self.async_show_form( return self.async_show_form(
step_id="user", step_id="user",
@ -57,7 +60,9 @@ class RokuConfigFlow(ConfigFlow, domain=DOMAIN):
errors=errors or {}, errors=errors or {},
) )
async def async_step_user(self, user_input: dict | None = None) -> FlowResult: async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle a flow initialized by the user.""" """Handle a flow initialized by the user."""
if not user_input: if not user_input:
return self._show_form() return self._show_form()

View File

@ -17,7 +17,7 @@ class RokuEntity(CoordinatorEntity):
def __init__( def __init__(
self, self,
*, *,
device_id: str, device_id: str | None,
coordinator: RokuDataUpdateCoordinator, coordinator: RokuDataUpdateCoordinator,
description: EntityDescription | None = None, description: EntityDescription | None = None,
) -> None: ) -> None:
@ -28,10 +28,11 @@ class RokuEntity(CoordinatorEntity):
if description is not None: if description is not None:
self.entity_description = description self.entity_description = description
self._attr_name = f"{coordinator.data.info.name} {description.name}" self._attr_name = f"{coordinator.data.info.name} {description.name}"
self._attr_unique_id = f"{device_id}_{description.key}" if device_id is not None:
self._attr_unique_id = f"{device_id}_{description.key}"
@property @property
def device_info(self) -> DeviceInfo: def device_info(self) -> DeviceInfo | None:
"""Return device information about this Roku device.""" """Return device information about this Roku device."""
if self._device_id is None: if self._device_id is None:
return None return None

View File

@ -2,7 +2,7 @@
"domain": "roku", "domain": "roku",
"name": "Roku", "name": "Roku",
"documentation": "https://www.home-assistant.io/integrations/roku", "documentation": "https://www.home-assistant.io/integrations/roku",
"requirements": ["rokuecp==0.12.0"], "requirements": ["rokuecp==0.13.1"],
"homekit": { "homekit": {
"models": ["3810X", "4660X", "7820X", "C105X", "C135X"] "models": ["3810X", "4660X", "7820X", "C105X", "C135X"]
}, },

View File

@ -117,7 +117,9 @@ async def async_setup_entry(
class RokuMediaPlayer(RokuEntity, MediaPlayerEntity): class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
"""Representation of a Roku media player on the network.""" """Representation of a Roku media player on the network."""
def __init__(self, unique_id: str, coordinator: RokuDataUpdateCoordinator) -> None: def __init__(
self, unique_id: str | None, coordinator: RokuDataUpdateCoordinator
) -> None:
"""Initialize the Roku device.""" """Initialize the Roku device."""
super().__init__( super().__init__(
coordinator=coordinator, coordinator=coordinator,
@ -231,7 +233,7 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
@property @property
def media_duration(self) -> int | None: def media_duration(self) -> int | None:
"""Duration of current playing media in seconds.""" """Duration of current playing media in seconds."""
if self._media_playback_trackable(): if self.coordinator.data.media is not None and self._media_playback_trackable():
return self.coordinator.data.media.duration return self.coordinator.data.media.duration
return None return None
@ -239,7 +241,7 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
@property @property
def media_position(self) -> int | None: def media_position(self) -> int | None:
"""Position of current playing media in seconds.""" """Position of current playing media in seconds."""
if self._media_playback_trackable(): if self.coordinator.data.media is not None and self._media_playback_trackable():
return self.coordinator.data.media.position return self.coordinator.data.media.position
return None return None
@ -247,7 +249,7 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
@property @property
def media_position_updated_at(self) -> dt.datetime | None: def media_position_updated_at(self) -> dt.datetime | None:
"""When was the position of the current playing media valid.""" """When was the position of the current playing media valid."""
if self._media_playback_trackable(): if self.coordinator.data.media is not None and self._media_playback_trackable():
return self.coordinator.data.media.at return self.coordinator.data.media.at
return None return None
@ -263,10 +265,12 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
@property @property
def source_list(self) -> list: def source_list(self) -> list:
"""List of available input sources.""" """List of available input sources."""
return ["Home"] + sorted(app.name for app in self.coordinator.data.apps) return ["Home"] + sorted(
app.name for app in self.coordinator.data.apps if app.name is not None
)
@roku_exception_handler @roku_exception_handler
async def search(self, keyword): async def search(self, keyword: str) -> None:
"""Emulate opening the search screen and entering the search keyword.""" """Emulate opening the search screen and entering the search keyword."""
await self.coordinator.roku.search(keyword) await self.coordinator.roku.search(keyword)
@ -343,7 +347,7 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
await self.coordinator.async_request_refresh() await self.coordinator.async_request_refresh()
@roku_exception_handler @roku_exception_handler
async def async_mute_volume(self, mute) -> None: async def async_mute_volume(self, mute: bool) -> None:
"""Mute the volume.""" """Mute the volume."""
await self.coordinator.roku.remote("volume_mute") await self.coordinator.roku.remote("volume_mute")
await self.coordinator.async_request_refresh() await self.coordinator.async_request_refresh()
@ -359,7 +363,9 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
await self.coordinator.roku.remote("volume_down") await self.coordinator.roku.remote("volume_down")
@roku_exception_handler @roku_exception_handler
async def async_play_media(self, media_type: str, media_id: str, **kwargs) -> None: async def async_play_media(
self, media_type: str, media_id: str, **kwargs: Any
) -> None:
"""Play media from a URL or file, launch an application, or tune to a channel.""" """Play media from a URL or file, launch an application, or tune to a channel."""
extra: dict[str, Any] = kwargs.get(ATTR_MEDIA_EXTRA) or {} extra: dict[str, Any] = kwargs.get(ATTR_MEDIA_EXTRA) or {}
@ -433,7 +439,6 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
None, None,
) )
if appl is not None: if appl is not None and appl.app_id is not None:
await self.coordinator.roku.launch(appl.app_id) await self.coordinator.roku.launch(appl.app_id)
await self.coordinator.async_request_refresh()
await self.coordinator.async_request_refresh()

View File

@ -1,6 +1,8 @@
"""Support for the Roku remote.""" """Support for the Roku remote."""
from __future__ import annotations from __future__ import annotations
from typing import Any
from homeassistant.components.remote import ATTR_NUM_REPEATS, RemoteEntity from homeassistant.components.remote import ATTR_NUM_REPEATS, RemoteEntity
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -42,19 +44,19 @@ class RokuRemote(RokuEntity, RemoteEntity):
return not self.coordinator.data.state.standby return not self.coordinator.data.state.standby
@roku_exception_handler @roku_exception_handler
async def async_turn_on(self, **kwargs) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on.""" """Turn the device on."""
await self.coordinator.roku.remote("poweron") await self.coordinator.roku.remote("poweron")
await self.coordinator.async_request_refresh() await self.coordinator.async_request_refresh()
@roku_exception_handler @roku_exception_handler
async def async_turn_off(self, **kwargs) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the device off.""" """Turn the device off."""
await self.coordinator.roku.remote("poweroff") await self.coordinator.roku.remote("poweroff")
await self.coordinator.async_request_refresh() await self.coordinator.async_request_refresh()
@roku_exception_handler @roku_exception_handler
async def async_send_command(self, command: list, **kwargs) -> None: async def async_send_command(self, command: list, **kwargs: Any) -> None:
"""Send a command to one device.""" """Send a command to one device."""
num_repeats = kwargs[ATTR_NUM_REPEATS] num_repeats = kwargs[ATTR_NUM_REPEATS]

View File

@ -1489,6 +1489,17 @@ no_implicit_optional = true
warn_return_any = true warn_return_any = true
warn_unreachable = true warn_unreachable = true
[mypy-homeassistant.components.roku.*]
check_untyped_defs = true
disallow_incomplete_defs = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
no_implicit_optional = true
warn_return_any = true
warn_unreachable = true
[mypy-homeassistant.components.rpi_power.*] [mypy-homeassistant.components.rpi_power.*]
check_untyped_defs = true check_untyped_defs = true
disallow_incomplete_defs = true disallow_incomplete_defs = true

View File

@ -2111,7 +2111,7 @@ rjpl==0.3.6
rocketchat-API==0.6.1 rocketchat-API==0.6.1
# homeassistant.components.roku # homeassistant.components.roku
rokuecp==0.12.0 rokuecp==0.13.1
# homeassistant.components.roomba # homeassistant.components.roomba
roombapy==1.6.5 roombapy==1.6.5

View File

@ -1300,7 +1300,7 @@ rflink==0.0.62
ring_doorbell==0.7.2 ring_doorbell==0.7.2
# homeassistant.components.roku # homeassistant.components.roku
rokuecp==0.12.0 rokuecp==0.13.1
# homeassistant.components.roomba # homeassistant.components.roomba
roombapy==1.6.5 roombapy==1.6.5