1
0
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:
Maciej Bieniek 2021-07-03 15:37:54 +02:00 committed by GitHub
parent 69b9a9c4ee
commit 0cb61b628d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 195 additions and 113 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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