mirror of
https://github.com/home-assistant/core
synced 2024-07-03 08:18:59 +00:00
Improve typing in Sony Bravia TV integration (#52438)
* Strict typing * Variables typing * Suggested change * Fix pylint * Use suppress instead of try..except * Remove unused variables * Suggested change * Fix pylint * Fix typing for unique_id
This commit is contained in:
parent
69b9a9c4ee
commit
0cb61b628d
|
@ -18,6 +18,7 @@ homeassistant.components.automation.*
|
|||
homeassistant.components.binary_sensor.*
|
||||
homeassistant.components.bluetooth_tracker.*
|
||||
homeassistant.components.bond.*
|
||||
homeassistant.components.braviatv.*
|
||||
homeassistant.components.brother.*
|
||||
homeassistant.components.calendar.*
|
||||
homeassistant.components.camera.*
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
"""The Bravia TV component."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Iterable
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Final
|
||||
|
||||
from bravia_tv import BraviaRC
|
||||
from bravia_tv.braviarc import NoIPControl
|
||||
|
||||
from homeassistant.components.media_player import DOMAIN as MEDIA_PLAYER_DOMAIN
|
||||
from homeassistant.components.remote import DOMAIN as REMOTE_DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.debounce import Debouncer
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
|
@ -16,11 +22,11 @@ from .const import CLIENTID_PREFIX, CONF_IGNORED_SOURCES, DOMAIN, NICKNAME
|
|||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PLATFORMS = [MEDIA_PLAYER_DOMAIN, REMOTE_DOMAIN]
|
||||
SCAN_INTERVAL = timedelta(seconds=10)
|
||||
PLATFORMS: Final[list[str]] = [MEDIA_PLAYER_DOMAIN, REMOTE_DOMAIN]
|
||||
SCAN_INTERVAL: Final = timedelta(seconds=10)
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry):
|
||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||
"""Set up a config entry."""
|
||||
host = config_entry.data[CONF_HOST]
|
||||
mac = config_entry.data[CONF_MAC]
|
||||
|
@ -40,7 +46,7 @@ async def async_setup_entry(hass, config_entry):
|
|||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass, config_entry):
|
||||
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(
|
||||
config_entry, PLATFORMS
|
||||
|
@ -52,7 +58,7 @@ async def async_unload_entry(hass, config_entry):
|
|||
return unload_ok
|
||||
|
||||
|
||||
async def update_listener(hass, config_entry):
|
||||
async def update_listener(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
|
||||
"""Handle options update."""
|
||||
await hass.config_entries.async_reload(config_entry.entry_id)
|
||||
|
||||
|
@ -64,28 +70,33 @@ class BraviaTVCoordinator(DataUpdateCoordinator[None]):
|
|||
several platforms.
|
||||
"""
|
||||
|
||||
def __init__(self, hass, host, mac, pin, ignored_sources):
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
host: str,
|
||||
mac: str,
|
||||
pin: str,
|
||||
ignored_sources: list[str],
|
||||
) -> None:
|
||||
"""Initialize Bravia TV Client."""
|
||||
|
||||
self.braviarc = BraviaRC(host, mac)
|
||||
self.pin = pin
|
||||
self.ignored_sources = ignored_sources
|
||||
self.muted = False
|
||||
self.channel_name = None
|
||||
self.channel_number = None
|
||||
self.media_title = None
|
||||
self.source = None
|
||||
self.source_list = []
|
||||
self.original_content_list = []
|
||||
self.content_mapping = {}
|
||||
self.duration = None
|
||||
self.content_uri = None
|
||||
self.start_date_time = None
|
||||
self.program_media_type = None
|
||||
self.audio_output = None
|
||||
self.min_volume = None
|
||||
self.max_volume = None
|
||||
self.volume_level = None
|
||||
self.muted: bool = False
|
||||
self.channel_name: str | None = None
|
||||
self.media_title: str | None = None
|
||||
self.source: str | None = None
|
||||
self.source_list: list[str] = []
|
||||
self.original_content_list: list[str] = []
|
||||
self.content_mapping: dict[str, str] = {}
|
||||
self.duration: int | None = None
|
||||
self.content_uri: str | None = None
|
||||
self.program_media_type: str | None = None
|
||||
self.audio_output: str | None = None
|
||||
self.min_volume: int | None = None
|
||||
self.max_volume: int | None = None
|
||||
self.volume_level: float | None = None
|
||||
self.is_on = False
|
||||
# Assume that the TV is in Play mode
|
||||
self.playing = True
|
||||
|
@ -101,19 +112,20 @@ class BraviaTVCoordinator(DataUpdateCoordinator[None]):
|
|||
),
|
||||
)
|
||||
|
||||
def _send_command(self, command, repeats=1):
|
||||
def _send_command(self, command: str, repeats: int = 1) -> None:
|
||||
"""Send a command to the TV."""
|
||||
for _ in range(repeats):
|
||||
for cmd in command:
|
||||
self.braviarc.send_command(cmd)
|
||||
|
||||
def _get_source(self):
|
||||
def _get_source(self) -> str | None:
|
||||
"""Return the name of the source."""
|
||||
for key, value in self.content_mapping.items():
|
||||
if value == self.content_uri:
|
||||
return key
|
||||
return None
|
||||
|
||||
def _refresh_volume(self):
|
||||
def _refresh_volume(self) -> bool:
|
||||
"""Refresh volume information."""
|
||||
volume_info = self.braviarc.get_volume_info(self.audio_output)
|
||||
if volume_info is not None:
|
||||
|
@ -122,11 +134,11 @@ class BraviaTVCoordinator(DataUpdateCoordinator[None]):
|
|||
self.audio_output = volume_info.get("target")
|
||||
self.min_volume = volume_info.get("minVolume")
|
||||
self.max_volume = volume_info.get("maxVolume")
|
||||
self.muted = volume_info.get("mute")
|
||||
self.muted = volume_info.get("mute", False)
|
||||
return True
|
||||
return False
|
||||
|
||||
def _refresh_channels(self):
|
||||
def _refresh_channels(self) -> bool:
|
||||
"""Refresh source and channels list."""
|
||||
if not self.source_list:
|
||||
self.content_mapping = self.braviarc.load_source_list()
|
||||
|
@ -138,17 +150,15 @@ class BraviaTVCoordinator(DataUpdateCoordinator[None]):
|
|||
self.source_list.append(key)
|
||||
return True
|
||||
|
||||
def _refresh_playing_info(self):
|
||||
def _refresh_playing_info(self) -> None:
|
||||
"""Refresh playing information."""
|
||||
playing_info = self.braviarc.get_playing_info()
|
||||
program_name = playing_info.get("programTitle")
|
||||
self.channel_name = playing_info.get("title")
|
||||
self.program_media_type = playing_info.get("programMediaType")
|
||||
self.channel_number = playing_info.get("dispNum")
|
||||
self.content_uri = playing_info.get("uri")
|
||||
self.source = self._get_source()
|
||||
self.duration = playing_info.get("durationSec")
|
||||
self.start_date_time = playing_info.get("startDateTime")
|
||||
if not playing_info:
|
||||
self.channel_name = "App"
|
||||
if self.channel_name is not None:
|
||||
|
@ -158,7 +168,7 @@ class BraviaTVCoordinator(DataUpdateCoordinator[None]):
|
|||
else:
|
||||
self.media_title = None
|
||||
|
||||
def _update_tv_data(self):
|
||||
def _update_tv_data(self) -> None:
|
||||
"""Connect and update TV info."""
|
||||
power_status = self.braviarc.get_power_status()
|
||||
|
||||
|
@ -182,26 +192,26 @@ class BraviaTVCoordinator(DataUpdateCoordinator[None]):
|
|||
|
||||
self.is_on = False
|
||||
|
||||
async def _async_update_data(self):
|
||||
async def _async_update_data(self) -> None:
|
||||
"""Fetch the latest data."""
|
||||
if self.state_lock.locked():
|
||||
return
|
||||
|
||||
await self.hass.async_add_executor_job(self._update_tv_data)
|
||||
|
||||
async def async_turn_on(self):
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn the device on."""
|
||||
async with self.state_lock:
|
||||
await self.hass.async_add_executor_job(self.braviarc.turn_on)
|
||||
await self.async_request_refresh()
|
||||
|
||||
async def async_turn_off(self):
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn off device."""
|
||||
async with self.state_lock:
|
||||
await self.hass.async_add_executor_job(self.braviarc.turn_off)
|
||||
await self.async_request_refresh()
|
||||
|
||||
async def async_set_volume_level(self, volume):
|
||||
async def async_set_volume_level(self, volume: float) -> None:
|
||||
"""Set volume level, range 0..1."""
|
||||
async with self.state_lock:
|
||||
await self.hass.async_add_executor_job(
|
||||
|
@ -209,7 +219,7 @@ class BraviaTVCoordinator(DataUpdateCoordinator[None]):
|
|||
)
|
||||
await self.async_request_refresh()
|
||||
|
||||
async def async_volume_up(self):
|
||||
async def async_volume_up(self) -> None:
|
||||
"""Send volume up command to device."""
|
||||
async with self.state_lock:
|
||||
await self.hass.async_add_executor_job(
|
||||
|
@ -217,7 +227,7 @@ class BraviaTVCoordinator(DataUpdateCoordinator[None]):
|
|||
)
|
||||
await self.async_request_refresh()
|
||||
|
||||
async def async_volume_down(self):
|
||||
async def async_volume_down(self) -> None:
|
||||
"""Send volume down command to device."""
|
||||
async with self.state_lock:
|
||||
await self.hass.async_add_executor_job(
|
||||
|
@ -225,46 +235,46 @@ class BraviaTVCoordinator(DataUpdateCoordinator[None]):
|
|||
)
|
||||
await self.async_request_refresh()
|
||||
|
||||
async def async_volume_mute(self, mute):
|
||||
async def async_volume_mute(self, mute: bool) -> None:
|
||||
"""Send mute command to device."""
|
||||
async with self.state_lock:
|
||||
await self.hass.async_add_executor_job(self.braviarc.mute_volume, mute)
|
||||
await self.async_request_refresh()
|
||||
|
||||
async def async_media_play(self):
|
||||
async def async_media_play(self) -> None:
|
||||
"""Send play command to device."""
|
||||
async with self.state_lock:
|
||||
await self.hass.async_add_executor_job(self.braviarc.media_play)
|
||||
self.playing = True
|
||||
await self.async_request_refresh()
|
||||
|
||||
async def async_media_pause(self):
|
||||
async def async_media_pause(self) -> None:
|
||||
"""Send pause command to device."""
|
||||
async with self.state_lock:
|
||||
await self.hass.async_add_executor_job(self.braviarc.media_pause)
|
||||
self.playing = False
|
||||
await self.async_request_refresh()
|
||||
|
||||
async def async_media_stop(self):
|
||||
async def async_media_stop(self) -> None:
|
||||
"""Send stop command to device."""
|
||||
async with self.state_lock:
|
||||
await self.hass.async_add_executor_job(self.braviarc.media_stop)
|
||||
self.playing = False
|
||||
await self.async_request_refresh()
|
||||
|
||||
async def async_media_next_track(self):
|
||||
async def async_media_next_track(self) -> None:
|
||||
"""Send next track command."""
|
||||
async with self.state_lock:
|
||||
await self.hass.async_add_executor_job(self.braviarc.media_next_track)
|
||||
await self.async_request_refresh()
|
||||
|
||||
async def async_media_previous_track(self):
|
||||
async def async_media_previous_track(self) -> None:
|
||||
"""Send previous track command."""
|
||||
async with self.state_lock:
|
||||
await self.hass.async_add_executor_job(self.braviarc.media_previous_track)
|
||||
await self.async_request_refresh()
|
||||
|
||||
async def async_select_source(self, source):
|
||||
async def async_select_source(self, source: str) -> None:
|
||||
"""Set the input source."""
|
||||
if source in self.content_mapping:
|
||||
uri = self.content_mapping[source]
|
||||
|
@ -272,7 +282,7 @@ class BraviaTVCoordinator(DataUpdateCoordinator[None]):
|
|||
await self.hass.async_add_executor_job(self.braviarc.play_content, uri)
|
||||
await self.async_request_refresh()
|
||||
|
||||
async def async_send_command(self, command, repeats):
|
||||
async def async_send_command(self, command: Iterable[str], repeats: int) -> None:
|
||||
"""Send command to device."""
|
||||
async with self.state_lock:
|
||||
await self.hass.async_add_executor_job(self._send_command, command, repeats)
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
"""Adds config flow for Bravia TV integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import suppress
|
||||
import ipaddress
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from bravia_tv import BraviaRC
|
||||
from bravia_tv.braviarc import NoIPControl
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries, exceptions
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PIN
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from .const import (
|
||||
|
@ -22,14 +28,13 @@ from .const import (
|
|||
)
|
||||
|
||||
|
||||
def host_valid(host):
|
||||
def host_valid(host: str) -> bool:
|
||||
"""Return True if hostname or IP address is valid."""
|
||||
try:
|
||||
with suppress(ValueError):
|
||||
if ipaddress.ip_address(host).version in [4, 6]:
|
||||
return True
|
||||
except ValueError:
|
||||
disallowed = re.compile(r"[^a-zA-Z\d\-]")
|
||||
return all(x and not disallowed.search(x) for x in host.split("."))
|
||||
disallowed = re.compile(r"[^a-zA-Z\d\-]")
|
||||
return all(x and not disallowed.search(x) for x in host.split("."))
|
||||
|
||||
|
||||
class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
@ -37,15 +42,16 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
|
||||
VERSION = 1
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
"""Initialize."""
|
||||
self.braviarc = None
|
||||
self.host = None
|
||||
self.title = None
|
||||
self.mac = None
|
||||
self.braviarc: BraviaRC | None = None
|
||||
self.host: str | None = None
|
||||
self.title = ""
|
||||
self.mac: str | None = None
|
||||
|
||||
async def init_device(self, pin):
|
||||
async def init_device(self, pin: str) -> None:
|
||||
"""Initialize Bravia TV device."""
|
||||
assert self.braviarc is not None
|
||||
await self.hass.async_add_executor_job(
|
||||
self.braviarc.connect, pin, CLIENTID_PREFIX, NICKNAME
|
||||
)
|
||||
|
@ -68,13 +74,15 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(config_entry):
|
||||
def async_get_options_flow(config_entry: ConfigEntry) -> BraviaTVOptionsFlowHandler:
|
||||
"""Bravia TV options callback."""
|
||||
return BraviaTVOptionsFlowHandler(config_entry)
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Handle the initial step."""
|
||||
errors = {}
|
||||
errors: dict[str, str] = {}
|
||||
|
||||
if user_input is not None:
|
||||
if host_valid(user_input[CONF_HOST]):
|
||||
|
@ -91,9 +99,11 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
errors=errors,
|
||||
)
|
||||
|
||||
async def async_step_authorize(self, user_input=None):
|
||||
async def async_step_authorize(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Get PIN from the Bravia TV device."""
|
||||
errors = {}
|
||||
errors: dict[str, str] = {}
|
||||
|
||||
if user_input is not None:
|
||||
try:
|
||||
|
@ -106,9 +116,9 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
user_input[CONF_HOST] = self.host
|
||||
user_input[CONF_MAC] = self.mac
|
||||
return self.async_create_entry(title=self.title, data=user_input)
|
||||
|
||||
# Connecting with th PIN "0000" to start the pairing process on the TV.
|
||||
try:
|
||||
assert self.braviarc is not None
|
||||
await self.hass.async_add_executor_job(
|
||||
self.braviarc.connect, "0000", CLIENTID_PREFIX, NICKNAME
|
||||
)
|
||||
|
@ -125,31 +135,34 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
class BraviaTVOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
"""Config flow options for Bravia TV."""
|
||||
|
||||
def __init__(self, config_entry):
|
||||
def __init__(self, config_entry: ConfigEntry) -> None:
|
||||
"""Initialize Bravia TV options flow."""
|
||||
self.braviarc = None
|
||||
self.config_entry = config_entry
|
||||
self.pin = config_entry.data[CONF_PIN]
|
||||
self.ignored_sources = config_entry.options.get(CONF_IGNORED_SOURCES)
|
||||
self.source_list = []
|
||||
self.source_list: dict[str, str] = {}
|
||||
|
||||
async def async_step_init(self, user_input=None):
|
||||
async def async_step_init(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Manage the options."""
|
||||
coordinator = self.hass.data[DOMAIN][self.config_entry.entry_id]
|
||||
self.braviarc = coordinator.braviarc
|
||||
connected = await self.hass.async_add_executor_job(self.braviarc.is_connected)
|
||||
braviarc = coordinator.braviarc
|
||||
connected = await self.hass.async_add_executor_job(braviarc.is_connected)
|
||||
if not connected:
|
||||
await self.hass.async_add_executor_job(
|
||||
self.braviarc.connect, self.pin, CLIENTID_PREFIX, NICKNAME
|
||||
braviarc.connect, self.pin, CLIENTID_PREFIX, NICKNAME
|
||||
)
|
||||
|
||||
content_mapping = await self.hass.async_add_executor_job(
|
||||
self.braviarc.load_source_list
|
||||
braviarc.load_source_list
|
||||
)
|
||||
self.source_list = [*content_mapping]
|
||||
self.source_list = {item: item for item in [*content_mapping]}
|
||||
return await self.async_step_user()
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Handle a flow initialized by the user."""
|
||||
if user_input is not None:
|
||||
return self.async_create_entry(title="", data=user_input)
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
"""Constants for Bravia TV integration."""
|
||||
ATTR_CID = "cid"
|
||||
ATTR_MAC = "macAddr"
|
||||
ATTR_MANUFACTURER = "Sony"
|
||||
ATTR_MODEL = "model"
|
||||
from __future__ import annotations
|
||||
|
||||
CONF_IGNORED_SOURCES = "ignored_sources"
|
||||
from typing import Final
|
||||
|
||||
BRAVIA_CONFIG_FILE = "bravia.conf"
|
||||
CLIENTID_PREFIX = "HomeAssistant"
|
||||
DEFAULT_NAME = f"{ATTR_MANUFACTURER} Bravia TV"
|
||||
DOMAIN = "braviatv"
|
||||
NICKNAME = "Home Assistant"
|
||||
ATTR_CID: Final = "cid"
|
||||
ATTR_MAC: Final = "macAddr"
|
||||
ATTR_MANUFACTURER: Final = "Sony"
|
||||
ATTR_MODEL: Final = "model"
|
||||
|
||||
CONF_IGNORED_SOURCES: Final = "ignored_sources"
|
||||
|
||||
BRAVIA_CONFIG_FILE: Final = "bravia.conf"
|
||||
CLIENTID_PREFIX: Final = "HomeAssistant"
|
||||
DEFAULT_NAME: Final = f"{ATTR_MANUFACTURER} Bravia TV"
|
||||
DOMAIN: Final = "braviatv"
|
||||
NICKNAME: Final = "Home Assistant"
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
"""Support for interface with a Bravia TV."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Final
|
||||
|
||||
from homeassistant.components.media_player import DEVICE_CLASS_TV, MediaPlayerEntity
|
||||
from homeassistant.components.media_player.const import (
|
||||
SUPPORT_NEXT_TRACK,
|
||||
|
@ -13,12 +17,17 @@ from homeassistant.components.media_player.const import (
|
|||
SUPPORT_VOLUME_SET,
|
||||
SUPPORT_VOLUME_STEP,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_OFF, STATE_PAUSED, STATE_PLAYING
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from . import BraviaTVCoordinator
|
||||
from .const import ATTR_MANUFACTURER, DEFAULT_NAME, DOMAIN
|
||||
|
||||
SUPPORT_BRAVIA = (
|
||||
SUPPORT_BRAVIA: Final = (
|
||||
SUPPORT_PAUSE
|
||||
| SUPPORT_VOLUME_STEP
|
||||
| SUPPORT_VOLUME_MUTE
|
||||
|
@ -33,12 +42,17 @@ SUPPORT_BRAVIA = (
|
|||
)
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Bravia TV Media Player from a config_entry."""
|
||||
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
unique_id = config_entry.unique_id
|
||||
device_info = {
|
||||
assert unique_id is not None
|
||||
device_info: DeviceInfo = {
|
||||
"identifiers": {(DOMAIN, unique_id)},
|
||||
"name": DEFAULT_NAME,
|
||||
"manufacturer": ATTR_MANUFACTURER,
|
||||
|
@ -53,10 +67,17 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
class BraviaTVMediaPlayer(CoordinatorEntity, MediaPlayerEntity):
|
||||
"""Representation of a Bravia TV Media Player."""
|
||||
|
||||
coordinator: BraviaTVCoordinator
|
||||
_attr_device_class = DEVICE_CLASS_TV
|
||||
_attr_supported_features = SUPPORT_BRAVIA
|
||||
|
||||
def __init__(self, coordinator, name, unique_id, device_info):
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: BraviaTVCoordinator,
|
||||
name: str,
|
||||
unique_id: str,
|
||||
device_info: DeviceInfo,
|
||||
) -> None:
|
||||
"""Initialize the entity."""
|
||||
|
||||
self._attr_device_info = device_info
|
||||
|
@ -66,91 +87,91 @@ class BraviaTVMediaPlayer(CoordinatorEntity, MediaPlayerEntity):
|
|||
super().__init__(coordinator)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
def state(self) -> str | None:
|
||||
"""Return the state of the device."""
|
||||
if self.coordinator.is_on:
|
||||
return STATE_PLAYING if self.coordinator.playing else STATE_PAUSED
|
||||
return STATE_OFF
|
||||
|
||||
@property
|
||||
def source(self):
|
||||
def source(self) -> str | None:
|
||||
"""Return the current input source."""
|
||||
return self.coordinator.source
|
||||
|
||||
@property
|
||||
def source_list(self):
|
||||
def source_list(self) -> list[str]:
|
||||
"""List of available input sources."""
|
||||
return self.coordinator.source_list
|
||||
|
||||
@property
|
||||
def volume_level(self):
|
||||
def volume_level(self) -> float | None:
|
||||
"""Volume level of the media player (0..1)."""
|
||||
return self.coordinator.volume_level
|
||||
|
||||
@property
|
||||
def is_volume_muted(self):
|
||||
def is_volume_muted(self) -> bool:
|
||||
"""Boolean if volume is currently muted."""
|
||||
return self.coordinator.muted
|
||||
|
||||
@property
|
||||
def media_title(self):
|
||||
def media_title(self) -> str | None:
|
||||
"""Title of current playing media."""
|
||||
return self.coordinator.media_title
|
||||
|
||||
@property
|
||||
def media_content_id(self):
|
||||
def media_content_id(self) -> str | None:
|
||||
"""Content ID of current playing media."""
|
||||
return self.coordinator.channel_name
|
||||
|
||||
@property
|
||||
def media_duration(self):
|
||||
def media_duration(self) -> int | None:
|
||||
"""Duration of current playing media in seconds."""
|
||||
return self.coordinator.duration
|
||||
|
||||
async def async_turn_on(self):
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn the device on."""
|
||||
await self.coordinator.async_turn_on()
|
||||
|
||||
async def async_turn_off(self):
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn the device off."""
|
||||
await self.coordinator.async_turn_off()
|
||||
|
||||
async def async_set_volume_level(self, volume):
|
||||
async def async_set_volume_level(self, volume: float) -> None:
|
||||
"""Set volume level, range 0..1."""
|
||||
await self.coordinator.async_set_volume_level(volume)
|
||||
|
||||
async def async_volume_up(self):
|
||||
async def async_volume_up(self) -> None:
|
||||
"""Send volume up command."""
|
||||
await self.coordinator.async_volume_up()
|
||||
|
||||
async def async_volume_down(self):
|
||||
async def async_volume_down(self) -> None:
|
||||
"""Send volume down command."""
|
||||
await self.coordinator.async_volume_down()
|
||||
|
||||
async def async_mute_volume(self, mute):
|
||||
async def async_mute_volume(self, mute: bool) -> None:
|
||||
"""Send mute command."""
|
||||
await self.coordinator.async_volume_mute(mute)
|
||||
|
||||
async def async_select_source(self, source):
|
||||
async def async_select_source(self, source: str) -> None:
|
||||
"""Set the input source."""
|
||||
await self.coordinator.async_select_source(source)
|
||||
|
||||
async def async_media_play(self):
|
||||
async def async_media_play(self) -> None:
|
||||
"""Send play command."""
|
||||
await self.coordinator.async_media_play()
|
||||
|
||||
async def async_media_pause(self):
|
||||
async def async_media_pause(self) -> None:
|
||||
"""Send pause command."""
|
||||
await self.coordinator.async_media_pause()
|
||||
|
||||
async def async_media_stop(self):
|
||||
async def async_media_stop(self) -> None:
|
||||
"""Send media stop command to media player."""
|
||||
await self.coordinator.async_media_stop()
|
||||
|
||||
async def async_media_next_track(self):
|
||||
async def async_media_next_track(self) -> None:
|
||||
"""Send next track command."""
|
||||
await self.coordinator.async_media_next_track()
|
||||
|
||||
async def async_media_previous_track(self):
|
||||
async def async_media_previous_track(self) -> None:
|
||||
"""Send previous track command."""
|
||||
await self.coordinator.async_media_previous_track()
|
||||
|
|
|
@ -1,17 +1,31 @@
|
|||
"""Remote control support for Bravia TV."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Iterable
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.remote import ATTR_NUM_REPEATS, RemoteEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from . import BraviaTVCoordinator
|
||||
from .const import ATTR_MANUFACTURER, DEFAULT_NAME, DOMAIN
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Bravia TV Remote from a config entry."""
|
||||
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
unique_id = config_entry.unique_id
|
||||
device_info = {
|
||||
assert unique_id is not None
|
||||
device_info: DeviceInfo = {
|
||||
"identifiers": {(DOMAIN, unique_id)},
|
||||
"name": DEFAULT_NAME,
|
||||
"manufacturer": ATTR_MANUFACTURER,
|
||||
|
@ -26,7 +40,15 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
class BraviaTVRemote(CoordinatorEntity, RemoteEntity):
|
||||
"""Representation of a Bravia TV Remote."""
|
||||
|
||||
def __init__(self, coordinator, name, unique_id, device_info):
|
||||
coordinator: BraviaTVCoordinator
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: BraviaTVCoordinator,
|
||||
name: str,
|
||||
unique_id: str,
|
||||
device_info: DeviceInfo,
|
||||
) -> None:
|
||||
"""Initialize the entity."""
|
||||
|
||||
self._attr_device_info = device_info
|
||||
|
@ -36,19 +58,19 @@ class BraviaTVRemote(CoordinatorEntity, RemoteEntity):
|
|||
super().__init__(coordinator)
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
def is_on(self) -> bool:
|
||||
"""Return true if device is on."""
|
||||
return self.coordinator.is_on
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the device on."""
|
||||
await self.coordinator.async_turn_on()
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the device off."""
|
||||
await self.coordinator.async_turn_off()
|
||||
|
||||
async def async_send_command(self, command, **kwargs):
|
||||
async def async_send_command(self, command: Iterable[str], **kwargs: Any) -> None:
|
||||
"""Send a command to device."""
|
||||
repeats = kwargs[ATTR_NUM_REPEATS]
|
||||
await self.coordinator.async_send_command(command, repeats)
|
||||
|
|
11
mypy.ini
11
mypy.ini
|
@ -209,6 +209,17 @@ no_implicit_optional = true
|
|||
warn_return_any = true
|
||||
warn_unreachable = true
|
||||
|
||||
[mypy-homeassistant.components.braviatv.*]
|
||||
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.brother.*]
|
||||
check_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
|
|
Loading…
Reference in New Issue
Block a user