mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Improve entity type hints [s] (part 2/2) (#77882)
This commit is contained in:
parent
458001a06e
commit
3ec231c911
@ -280,7 +280,7 @@ class SolarEdgeSensor(SensorEntity):
|
|||||||
pass
|
pass
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Get the latest data from the sensor and update the state."""
|
"""Get the latest data from the sensor and update the state."""
|
||||||
self._data.update()
|
self._data.update()
|
||||||
self._attr_native_value = self._data.data[self.entity_description.key]
|
self._attr_native_value = self._data.data[self.entity_description.key]
|
||||||
|
@ -45,7 +45,7 @@ class SomaSensor(SomaEntity, SensorEntity):
|
|||||||
return self.battery_state
|
return self.battery_state
|
||||||
|
|
||||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||||
async def async_update(self):
|
async def async_update(self) -> None:
|
||||||
"""Update the sensor with the latest data."""
|
"""Update the sensor with the latest data."""
|
||||||
response = await self.get_battery_level_from_api()
|
response = await self.get_battery_level_from_api()
|
||||||
|
|
||||||
|
@ -119,11 +119,11 @@ class SongpalEntity(MediaPlayerEntity):
|
|||||||
self._active_source = None
|
self._active_source = None
|
||||||
self._sources = {}
|
self._sources = {}
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Run when entity is added to hass."""
|
"""Run when entity is added to hass."""
|
||||||
await self.async_activate_websocket()
|
await self.async_activate_websocket()
|
||||||
|
|
||||||
async def async_will_remove_from_hass(self):
|
async def async_will_remove_from_hass(self) -> None:
|
||||||
"""Run when entity will be removed from hass."""
|
"""Run when entity will be removed from hass."""
|
||||||
await self._dev.stop_listen_notifications()
|
await self._dev.stop_listen_notifications()
|
||||||
|
|
||||||
@ -232,7 +232,7 @@ class SongpalEntity(MediaPlayerEntity):
|
|||||||
_LOGGER.debug("Calling set_sound_setting with %s: %s", name, value)
|
_LOGGER.debug("Calling set_sound_setting with %s: %s", name, value)
|
||||||
await self._dev.set_sound_settings(name, value)
|
await self._dev.set_sound_settings(name, value)
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self) -> None:
|
||||||
"""Fetch updates from the device."""
|
"""Fetch updates from the device."""
|
||||||
try:
|
try:
|
||||||
if self._sysinfo is None:
|
if self._sysinfo is None:
|
||||||
@ -281,7 +281,7 @@ class SongpalEntity(MediaPlayerEntity):
|
|||||||
_LOGGER.error("Unable to update: %s", ex)
|
_LOGGER.error("Unable to update: %s", ex)
|
||||||
self._available = False
|
self._available = False
|
||||||
|
|
||||||
async def async_select_source(self, source):
|
async def async_select_source(self, source: str) -> None:
|
||||||
"""Select source."""
|
"""Select source."""
|
||||||
for out in self._sources.values():
|
for out in self._sources.values():
|
||||||
if out.title == source:
|
if out.title == source:
|
||||||
@ -314,29 +314,29 @@ class SongpalEntity(MediaPlayerEntity):
|
|||||||
volume = self._volume / self._volume_max
|
volume = self._volume / self._volume_max
|
||||||
return volume
|
return volume
|
||||||
|
|
||||||
async def async_set_volume_level(self, volume):
|
async def async_set_volume_level(self, volume: float) -> None:
|
||||||
"""Set volume level."""
|
"""Set volume level."""
|
||||||
volume = int(volume * self._volume_max)
|
volume = int(volume * self._volume_max)
|
||||||
_LOGGER.debug("Setting volume to %s", volume)
|
_LOGGER.debug("Setting volume to %s", volume)
|
||||||
return await self._volume_control.set_volume(volume)
|
return await self._volume_control.set_volume(volume)
|
||||||
|
|
||||||
async def async_volume_up(self):
|
async def async_volume_up(self) -> None:
|
||||||
"""Set volume up."""
|
"""Set volume up."""
|
||||||
return await self._volume_control.set_volume(self._volume + 1)
|
return await self._volume_control.set_volume(self._volume + 1)
|
||||||
|
|
||||||
async def async_volume_down(self):
|
async def async_volume_down(self) -> None:
|
||||||
"""Set volume down."""
|
"""Set volume down."""
|
||||||
return await self._volume_control.set_volume(self._volume - 1)
|
return await self._volume_control.set_volume(self._volume - 1)
|
||||||
|
|
||||||
async def async_turn_on(self):
|
async def async_turn_on(self) -> None:
|
||||||
"""Turn the device on."""
|
"""Turn the device on."""
|
||||||
return await self._dev.set_power(True)
|
return await self._dev.set_power(True)
|
||||||
|
|
||||||
async def async_turn_off(self):
|
async def async_turn_off(self) -> None:
|
||||||
"""Turn the device off."""
|
"""Turn the device off."""
|
||||||
return await self._dev.set_power(False)
|
return await self._dev.set_power(False)
|
||||||
|
|
||||||
async def async_mute_volume(self, mute):
|
async def async_mute_volume(self, mute: bool) -> None:
|
||||||
"""Mute or unmute the device."""
|
"""Mute or unmute the device."""
|
||||||
_LOGGER.debug("Set mute: %s", mute)
|
_LOGGER.debug("Set mute: %s", mute)
|
||||||
return await self._volume_control.set_mute(mute)
|
return await self._volume_control.set_mute(mute)
|
||||||
|
@ -23,6 +23,7 @@ from homeassistant.components.media_player import (
|
|||||||
MediaPlayerEntityFeature,
|
MediaPlayerEntityFeature,
|
||||||
async_process_play_media_url,
|
async_process_play_media_url,
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.media_player.browse_media import BrowseMedia
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
ATTR_INPUT_SOURCE,
|
ATTR_INPUT_SOURCE,
|
||||||
ATTR_MEDIA_ENQUEUE,
|
ATTR_MEDIA_ENQUEUE,
|
||||||
@ -715,7 +716,7 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
|
|||||||
|
|
||||||
async def async_browse_media(
|
async def async_browse_media(
|
||||||
self, media_content_type: str | None = None, media_content_id: str | None = None
|
self, media_content_type: str | None = None, media_content_id: str | None = None
|
||||||
) -> Any:
|
) -> BrowseMedia:
|
||||||
"""Implement the websocket media browsing helper."""
|
"""Implement the websocket media browsing helper."""
|
||||||
return await media_browser.async_browse_media(
|
return await media_browser.async_browse_media(
|
||||||
self.hass,
|
self.hass,
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import pysdcp
|
import pysdcp
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
@ -78,7 +79,7 @@ class SonyProjector(SwitchEntity):
|
|||||||
"""Return state attributes."""
|
"""Return state attributes."""
|
||||||
return self._attributes
|
return self._attributes
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Get the latest state from the projector."""
|
"""Get the latest state from the projector."""
|
||||||
try:
|
try:
|
||||||
self._state = self._sdcp.get_power()
|
self._state = self._sdcp.get_power()
|
||||||
@ -87,7 +88,7 @@ class SonyProjector(SwitchEntity):
|
|||||||
_LOGGER.error("Projector connection refused")
|
_LOGGER.error("Projector connection refused")
|
||||||
self._available = False
|
self._available = False
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
def turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the projector on."""
|
"""Turn the projector on."""
|
||||||
_LOGGER.debug("Powering on projector '%s'", self.name)
|
_LOGGER.debug("Powering on projector '%s'", self.name)
|
||||||
if self._sdcp.set_power(True):
|
if self._sdcp.set_power(True):
|
||||||
@ -96,7 +97,7 @@ class SonyProjector(SwitchEntity):
|
|||||||
else:
|
else:
|
||||||
_LOGGER.error("Power on command was not successful")
|
_LOGGER.error("Power on command was not successful")
|
||||||
|
|
||||||
def turn_off(self, **kwargs):
|
def turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn the projector off."""
|
"""Turn the projector off."""
|
||||||
_LOGGER.debug("Powering off projector '%s'", self.name)
|
_LOGGER.debug("Powering off projector '%s'", self.name)
|
||||||
if self._sdcp.set_power(False):
|
if self._sdcp.set_power(False):
|
||||||
|
@ -6,7 +6,9 @@ from requests import RequestException
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
|
from homeassistant.components.zeroconf import ZeroconfServiceInfo
|
||||||
from homeassistant.const import CONF_HOST
|
from homeassistant.const import CONF_HOST
|
||||||
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
@ -60,7 +62,9 @@ class SoundtouchConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
errors=errors,
|
errors=errors,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_step_zeroconf(self, discovery_info):
|
async def async_step_zeroconf(
|
||||||
|
self, discovery_info: ZeroconfServiceInfo
|
||||||
|
) -> FlowResult:
|
||||||
"""Handle a flow initiated by a zeroconf discovery."""
|
"""Handle a flow initiated by a zeroconf discovery."""
|
||||||
self.host = discovery_info.host
|
self.host = discovery_info.host
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from libsoundtouch.device import SoundTouchDevice
|
from libsoundtouch.device import SoundTouchDevice
|
||||||
from libsoundtouch.utils import Source
|
from libsoundtouch.utils import Source
|
||||||
@ -17,6 +18,7 @@ from homeassistant.components.media_player import (
|
|||||||
MediaPlayerEntityFeature,
|
MediaPlayerEntityFeature,
|
||||||
)
|
)
|
||||||
from homeassistant.components.media_player.browse_media import (
|
from homeassistant.components.media_player.browse_media import (
|
||||||
|
BrowseMedia,
|
||||||
async_process_play_media_url,
|
async_process_play_media_url,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||||
@ -154,7 +156,7 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
|
|||||||
"""Return SoundTouch device."""
|
"""Return SoundTouch device."""
|
||||||
return self._device
|
return self._device
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Retrieve the latest data."""
|
"""Retrieve the latest data."""
|
||||||
self._status = self._device.status()
|
self._status = self._device.status()
|
||||||
self._volume = self._device.volume()
|
self._volume = self._device.volume()
|
||||||
@ -194,47 +196,47 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
|
|||||||
"""Boolean if volume is currently muted."""
|
"""Boolean if volume is currently muted."""
|
||||||
return self._volume.muted
|
return self._volume.muted
|
||||||
|
|
||||||
def turn_off(self):
|
def turn_off(self) -> None:
|
||||||
"""Turn off media player."""
|
"""Turn off media player."""
|
||||||
self._device.power_off()
|
self._device.power_off()
|
||||||
|
|
||||||
def turn_on(self):
|
def turn_on(self) -> None:
|
||||||
"""Turn on media player."""
|
"""Turn on media player."""
|
||||||
self._device.power_on()
|
self._device.power_on()
|
||||||
|
|
||||||
def volume_up(self):
|
def volume_up(self) -> None:
|
||||||
"""Volume up the media player."""
|
"""Volume up the media player."""
|
||||||
self._device.volume_up()
|
self._device.volume_up()
|
||||||
|
|
||||||
def volume_down(self):
|
def volume_down(self) -> None:
|
||||||
"""Volume down media player."""
|
"""Volume down media player."""
|
||||||
self._device.volume_down()
|
self._device.volume_down()
|
||||||
|
|
||||||
def set_volume_level(self, volume):
|
def set_volume_level(self, volume: float) -> None:
|
||||||
"""Set volume level, range 0..1."""
|
"""Set volume level, range 0..1."""
|
||||||
self._device.set_volume(int(volume * 100))
|
self._device.set_volume(int(volume * 100))
|
||||||
|
|
||||||
def mute_volume(self, mute):
|
def mute_volume(self, mute: bool) -> None:
|
||||||
"""Send mute command."""
|
"""Send mute command."""
|
||||||
self._device.mute()
|
self._device.mute()
|
||||||
|
|
||||||
def media_play_pause(self):
|
def media_play_pause(self) -> None:
|
||||||
"""Simulate play pause media player."""
|
"""Simulate play pause media player."""
|
||||||
self._device.play_pause()
|
self._device.play_pause()
|
||||||
|
|
||||||
def media_play(self):
|
def media_play(self) -> None:
|
||||||
"""Send play command."""
|
"""Send play command."""
|
||||||
self._device.play()
|
self._device.play()
|
||||||
|
|
||||||
def media_pause(self):
|
def media_pause(self) -> None:
|
||||||
"""Send media pause command to media player."""
|
"""Send media pause command to media player."""
|
||||||
self._device.pause()
|
self._device.pause()
|
||||||
|
|
||||||
def media_next_track(self):
|
def media_next_track(self) -> None:
|
||||||
"""Send next track command."""
|
"""Send next track command."""
|
||||||
self._device.next_track()
|
self._device.next_track()
|
||||||
|
|
||||||
def media_previous_track(self):
|
def media_previous_track(self) -> None:
|
||||||
"""Send the previous track command."""
|
"""Send the previous track command."""
|
||||||
self._device.previous_track()
|
self._device.previous_track()
|
||||||
|
|
||||||
@ -273,7 +275,7 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
|
|||||||
"""Album name of current playing media."""
|
"""Album name of current playing media."""
|
||||||
return self._status.album
|
return self._status.album
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Populate zone info which requires entity_id."""
|
"""Populate zone info which requires entity_id."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@ -285,7 +287,9 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
|
|||||||
EVENT_HOMEASSISTANT_START, async_update_on_start
|
EVENT_HOMEASSISTANT_START, async_update_on_start
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_play_media(self, media_type, media_id, **kwargs):
|
async def async_play_media(
|
||||||
|
self, media_type: str, media_id: str, **kwargs: Any
|
||||||
|
) -> None:
|
||||||
"""Play a piece of media."""
|
"""Play a piece of media."""
|
||||||
if media_source.is_media_source_id(media_id):
|
if media_source.is_media_source_id(media_id):
|
||||||
play_item = await media_source.async_resolve_media(
|
play_item = await media_source.async_resolve_media(
|
||||||
@ -297,7 +301,7 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
|
|||||||
partial(self.play_media, media_type, media_id, **kwargs)
|
partial(self.play_media, media_type, media_id, **kwargs)
|
||||||
)
|
)
|
||||||
|
|
||||||
def play_media(self, media_type, media_id, **kwargs):
|
def play_media(self, media_type: str, media_id: str, **kwargs: Any) -> None:
|
||||||
"""Play a piece of media."""
|
"""Play a piece of media."""
|
||||||
_LOGGER.debug("Starting media with media_id: %s", media_id)
|
_LOGGER.debug("Starting media with media_id: %s", media_id)
|
||||||
if re.match(r"http?://", str(media_id)):
|
if re.match(r"http?://", str(media_id)):
|
||||||
@ -319,7 +323,7 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
|
|||||||
else:
|
else:
|
||||||
_LOGGER.warning("Unable to find preset with id %s", media_id)
|
_LOGGER.warning("Unable to find preset with id %s", media_id)
|
||||||
|
|
||||||
def select_source(self, source):
|
def select_source(self, source: str) -> None:
|
||||||
"""Select input source."""
|
"""Select input source."""
|
||||||
if source == Source.AUX.value:
|
if source == Source.AUX.value:
|
||||||
_LOGGER.debug("Selecting source AUX")
|
_LOGGER.debug("Selecting source AUX")
|
||||||
@ -399,7 +403,9 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
|
|||||||
|
|
||||||
return attributes
|
return attributes
|
||||||
|
|
||||||
async def async_browse_media(self, media_content_type=None, media_content_id=None):
|
async def async_browse_media(
|
||||||
|
self, media_content_type: str | None = None, media_content_id: str | None = None
|
||||||
|
) -> BrowseMedia:
|
||||||
"""Implement the websocket media browsing helper."""
|
"""Implement the websocket media browsing helper."""
|
||||||
return await media_source.async_browse_media(self.hass, media_content_id)
|
return await media_source.async_browse_media(self.hass, media_content_id)
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
"""Support for Spider thermostats."""
|
"""Support for Spider thermostats."""
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from homeassistant.components.climate import ClimateEntity
|
from homeassistant.components.climate import ClimateEntity
|
||||||
from homeassistant.components.climate.const import ClimateEntityFeature, HVACMode
|
from homeassistant.components.climate.const import ClimateEntityFeature, HVACMode
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
@ -59,7 +61,7 @@ class SpiderThermostat(ClimateEntity):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self) -> int:
|
||||||
"""Return the list of supported features."""
|
"""Return the list of supported features."""
|
||||||
if self.thermostat.has_fan_mode:
|
if self.thermostat.has_fan_mode:
|
||||||
return (
|
return (
|
||||||
@ -112,7 +114,7 @@ class SpiderThermostat(ClimateEntity):
|
|||||||
"""Return the list of available operation modes."""
|
"""Return the list of available operation modes."""
|
||||||
return self.support_hvac
|
return self.support_hvac
|
||||||
|
|
||||||
def set_temperature(self, **kwargs):
|
def set_temperature(self, **kwargs: Any) -> None:
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
|
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
|
||||||
return
|
return
|
||||||
@ -128,7 +130,7 @@ class SpiderThermostat(ClimateEntity):
|
|||||||
"""Return the fan setting."""
|
"""Return the fan setting."""
|
||||||
return self.thermostat.current_fan_speed
|
return self.thermostat.current_fan_speed
|
||||||
|
|
||||||
def set_fan_mode(self, fan_mode):
|
def set_fan_mode(self, fan_mode: str) -> None:
|
||||||
"""Set fan mode."""
|
"""Set fan mode."""
|
||||||
self.thermostat.set_fan_speed(fan_mode)
|
self.thermostat.set_fan_speed(fan_mode)
|
||||||
|
|
||||||
@ -137,6 +139,6 @@ class SpiderThermostat(ClimateEntity):
|
|||||||
"""List of available fan modes."""
|
"""List of available fan modes."""
|
||||||
return self.support_fan
|
return self.support_fan
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Get the latest data."""
|
"""Get the latest data."""
|
||||||
self.thermostat = self.api.get_thermostat(self.unique_id)
|
self.thermostat = self.api.get_thermostat(self.unique_id)
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
"""Support for Spider switches."""
|
"""Support for Spider switches."""
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchEntity
|
from homeassistant.components.switch import SwitchEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
@ -56,18 +58,18 @@ class SpiderPowerPlug(SwitchEntity):
|
|||||||
return self.power_plug.is_on
|
return self.power_plug.is_on
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self) -> bool:
|
||||||
"""Return true if switch is available."""
|
"""Return true if switch is available."""
|
||||||
return self.power_plug.is_available
|
return self.power_plug.is_available
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
def turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn device on."""
|
"""Turn device on."""
|
||||||
self.power_plug.turn_on()
|
self.power_plug.turn_on()
|
||||||
|
|
||||||
def turn_off(self, **kwargs):
|
def turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn device off."""
|
"""Turn device off."""
|
||||||
self.power_plug.turn_off()
|
self.power_plug.turn_off()
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Get the latest data."""
|
"""Get the latest data."""
|
||||||
self.power_plug = self.api.get_power_plug(self.power_plug.id)
|
self.power_plug = self.api.get_power_plug(self.power_plug.id)
|
||||||
|
@ -5,6 +5,7 @@ from asyncio import run_coroutine_threadsafe
|
|||||||
import datetime as dt
|
import datetime as dt
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from spotipy import SpotifyException
|
from spotipy import SpotifyException
|
||||||
@ -273,7 +274,7 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
|
|||||||
return REPEAT_MODE_MAPPING_TO_HA.get(repeat_state)
|
return REPEAT_MODE_MAPPING_TO_HA.get(repeat_state)
|
||||||
|
|
||||||
@spotify_exception_handler
|
@spotify_exception_handler
|
||||||
def set_volume_level(self, volume: int) -> None:
|
def set_volume_level(self, volume: float) -> None:
|
||||||
"""Set the volume level."""
|
"""Set the volume level."""
|
||||||
self.data.client.volume(int(volume * 100))
|
self.data.client.volume(int(volume * 100))
|
||||||
|
|
||||||
@ -298,12 +299,12 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
|
|||||||
self.data.client.next_track()
|
self.data.client.next_track()
|
||||||
|
|
||||||
@spotify_exception_handler
|
@spotify_exception_handler
|
||||||
def media_seek(self, position):
|
def media_seek(self, position: float) -> None:
|
||||||
"""Send seek command."""
|
"""Send seek command."""
|
||||||
self.data.client.seek_track(int(position * 1000))
|
self.data.client.seek_track(int(position * 1000))
|
||||||
|
|
||||||
@spotify_exception_handler
|
@spotify_exception_handler
|
||||||
def play_media(self, media_type: str, media_id: str, **kwargs) -> None:
|
def play_media(self, media_type: str, media_id: str, **kwargs: Any) -> None:
|
||||||
"""Play media."""
|
"""Play media."""
|
||||||
if media_type.startswith(MEDIA_PLAYER_PREFIX):
|
if media_type.startswith(MEDIA_PLAYER_PREFIX):
|
||||||
media_type = media_type[len(MEDIA_PLAYER_PREFIX) :]
|
media_type = media_type[len(MEDIA_PLAYER_PREFIX) :]
|
||||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from pysqueezebox import Server, async_discover
|
from pysqueezebox import Server, async_discover
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
@ -296,7 +297,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
return SQUEEZEBOX_MODE.get(self._player.mode)
|
return SQUEEZEBOX_MODE.get(self._player.mode)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self) -> None:
|
||||||
"""Update the Player() object."""
|
"""Update the Player() object."""
|
||||||
# only update available players, newly available players will be rediscovered and marked available
|
# only update available players, newly available players will be rediscovered and marked available
|
||||||
if self._available:
|
if self._available:
|
||||||
@ -313,7 +314,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
self.hass, SIGNAL_PLAYER_REDISCOVERED, self.rediscovered
|
self.hass, SIGNAL_PLAYER_REDISCOVERED, self.rediscovered
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_will_remove_from_hass(self):
|
async def async_will_remove_from_hass(self) -> None:
|
||||||
"""Remove from list of known players when removed from hass."""
|
"""Remove from list of known players when removed from hass."""
|
||||||
self.hass.data[DOMAIN][KNOWN_PLAYERS].remove(self)
|
self.hass.data[DOMAIN][KNOWN_PLAYERS].remove(self)
|
||||||
|
|
||||||
@ -419,60 +420,62 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
"""Return the result from the call_query service."""
|
"""Return the result from the call_query service."""
|
||||||
return self._query_result
|
return self._query_result
|
||||||
|
|
||||||
async def async_turn_off(self):
|
async def async_turn_off(self) -> None:
|
||||||
"""Turn off media player."""
|
"""Turn off media player."""
|
||||||
await self._player.async_set_power(False)
|
await self._player.async_set_power(False)
|
||||||
|
|
||||||
async def async_volume_up(self):
|
async def async_volume_up(self) -> None:
|
||||||
"""Volume up media player."""
|
"""Volume up media player."""
|
||||||
await self._player.async_set_volume("+5")
|
await self._player.async_set_volume("+5")
|
||||||
|
|
||||||
async def async_volume_down(self):
|
async def async_volume_down(self) -> None:
|
||||||
"""Volume down media player."""
|
"""Volume down media player."""
|
||||||
await self._player.async_set_volume("-5")
|
await self._player.async_set_volume("-5")
|
||||||
|
|
||||||
async def async_set_volume_level(self, volume):
|
async def async_set_volume_level(self, volume: float) -> None:
|
||||||
"""Set volume level, range 0..1."""
|
"""Set volume level, range 0..1."""
|
||||||
volume_percent = str(int(volume * 100))
|
volume_percent = str(int(volume * 100))
|
||||||
await self._player.async_set_volume(volume_percent)
|
await self._player.async_set_volume(volume_percent)
|
||||||
|
|
||||||
async def async_mute_volume(self, mute):
|
async def async_mute_volume(self, mute: bool) -> None:
|
||||||
"""Mute (true) or unmute (false) media player."""
|
"""Mute (true) or unmute (false) media player."""
|
||||||
await self._player.async_set_muting(mute)
|
await self._player.async_set_muting(mute)
|
||||||
|
|
||||||
async def async_media_stop(self):
|
async def async_media_stop(self) -> None:
|
||||||
"""Send stop command to media player."""
|
"""Send stop command to media player."""
|
||||||
await self._player.async_stop()
|
await self._player.async_stop()
|
||||||
|
|
||||||
async def async_media_play_pause(self):
|
async def async_media_play_pause(self) -> None:
|
||||||
"""Send pause command to media player."""
|
"""Send pause command to media player."""
|
||||||
await self._player.async_toggle_pause()
|
await self._player.async_toggle_pause()
|
||||||
|
|
||||||
async def async_media_play(self):
|
async def async_media_play(self) -> None:
|
||||||
"""Send play command to media player."""
|
"""Send play command to media player."""
|
||||||
await self._player.async_play()
|
await self._player.async_play()
|
||||||
|
|
||||||
async def async_media_pause(self):
|
async def async_media_pause(self) -> None:
|
||||||
"""Send pause command to media player."""
|
"""Send pause command to media player."""
|
||||||
await self._player.async_pause()
|
await self._player.async_pause()
|
||||||
|
|
||||||
async def async_media_next_track(self):
|
async def async_media_next_track(self) -> None:
|
||||||
"""Send next track command."""
|
"""Send next track command."""
|
||||||
await self._player.async_index("+1")
|
await self._player.async_index("+1")
|
||||||
|
|
||||||
async def async_media_previous_track(self):
|
async def async_media_previous_track(self) -> None:
|
||||||
"""Send next track command."""
|
"""Send next track command."""
|
||||||
await self._player.async_index("-1")
|
await self._player.async_index("-1")
|
||||||
|
|
||||||
async def async_media_seek(self, position):
|
async def async_media_seek(self, position: float) -> None:
|
||||||
"""Send seek command."""
|
"""Send seek command."""
|
||||||
await self._player.async_time(position)
|
await self._player.async_time(position)
|
||||||
|
|
||||||
async def async_turn_on(self):
|
async def async_turn_on(self) -> None:
|
||||||
"""Turn the media player on."""
|
"""Turn the media player on."""
|
||||||
await self._player.async_set_power(True)
|
await self._player.async_set_power(True)
|
||||||
|
|
||||||
async def async_play_media(self, media_type, media_id, **kwargs):
|
async def async_play_media(
|
||||||
|
self, media_type: str, media_id: str, **kwargs: Any
|
||||||
|
) -> None:
|
||||||
"""Send the play_media command to the media player."""
|
"""Send the play_media command to the media player."""
|
||||||
index = None
|
index = None
|
||||||
|
|
||||||
@ -528,7 +531,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
if index is not None:
|
if index is not None:
|
||||||
await self._player.async_index(index)
|
await self._player.async_index(index)
|
||||||
|
|
||||||
async def async_set_repeat(self, repeat):
|
async def async_set_repeat(self, repeat: str) -> None:
|
||||||
"""Set the repeat mode."""
|
"""Set the repeat mode."""
|
||||||
if repeat == REPEAT_MODE_ALL:
|
if repeat == REPEAT_MODE_ALL:
|
||||||
repeat_mode = "playlist"
|
repeat_mode = "playlist"
|
||||||
@ -539,12 +542,12 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
|
|
||||||
await self._player.async_set_repeat(repeat_mode)
|
await self._player.async_set_repeat(repeat_mode)
|
||||||
|
|
||||||
async def async_set_shuffle(self, shuffle):
|
async def async_set_shuffle(self, shuffle: bool) -> None:
|
||||||
"""Enable/disable shuffle mode."""
|
"""Enable/disable shuffle mode."""
|
||||||
shuffle_mode = "song" if shuffle else "none"
|
shuffle_mode = "song" if shuffle else "none"
|
||||||
await self._player.async_set_shuffle(shuffle_mode)
|
await self._player.async_set_shuffle(shuffle_mode)
|
||||||
|
|
||||||
async def async_clear_playlist(self):
|
async def async_clear_playlist(self) -> None:
|
||||||
"""Send the media player the command for clear playlist."""
|
"""Send the media player the command for clear playlist."""
|
||||||
await self._player.async_clear_playlist()
|
await self._player.async_clear_playlist()
|
||||||
|
|
||||||
@ -575,7 +578,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
self._query_result = await self._player.async_query(*all_params)
|
self._query_result = await self._player.async_query(*all_params)
|
||||||
_LOGGER.debug("call_query got result %s", self._query_result)
|
_LOGGER.debug("call_query got result %s", self._query_result)
|
||||||
|
|
||||||
async def async_join_players(self, group_members):
|
async def async_join_players(self, group_members: list[str]) -> None:
|
||||||
"""
|
"""
|
||||||
Add other Squeezebox players to this player's sync group.
|
Add other Squeezebox players to this player's sync group.
|
||||||
|
|
||||||
@ -601,7 +604,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
)
|
)
|
||||||
await self.async_join_players([other_player])
|
await self.async_join_players([other_player])
|
||||||
|
|
||||||
async def async_unjoin_player(self):
|
async def async_unjoin_player(self) -> None:
|
||||||
"""Unsync this Squeezebox player."""
|
"""Unsync this Squeezebox player."""
|
||||||
await self._player.async_unsync()
|
await self._player.async_unsync()
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ class SrpEntity(SensorEntity):
|
|||||||
"""Return the state class."""
|
"""Return the state class."""
|
||||||
return SensorStateClass.TOTAL_INCREASING
|
return SensorStateClass.TOTAL_INCREASING
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self) -> None:
|
||||||
"""When entity is added to hass."""
|
"""When entity is added to hass."""
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
self.coordinator.async_add_listener(self.async_write_ha_state)
|
self.coordinator.async_add_listener(self.async_write_ha_state)
|
||||||
@ -161,7 +161,7 @@ class SrpEntity(SensorEntity):
|
|||||||
if self.coordinator.data:
|
if self.coordinator.data:
|
||||||
self._state = self.coordinator.data
|
self._state = self.coordinator.data
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self) -> None:
|
||||||
"""Update the entity.
|
"""Update the entity.
|
||||||
|
|
||||||
Only used by the generic entity update service.
|
Only used by the generic entity update service.
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
|
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
@ -88,7 +89,7 @@ class StarlineSwitch(StarlineEntity, SwitchEntity):
|
|||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self) -> bool:
|
||||||
"""Return True if entity is available."""
|
"""Return True if entity is available."""
|
||||||
return super().available and self._device.online
|
return super().available and self._device.online
|
||||||
|
|
||||||
@ -120,11 +121,11 @@ class StarlineSwitch(StarlineEntity, SwitchEntity):
|
|||||||
return False
|
return False
|
||||||
return self._device.car_state.get(self._key)
|
return self._device.car_state.get(self._key)
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
def turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the entity on."""
|
"""Turn the entity on."""
|
||||||
self._account.api.set_car_state(self._device.device_id, self._key, True)
|
self._account.api.set_car_state(self._device.device_id, self._key, True)
|
||||||
|
|
||||||
def turn_off(self, **kwargs) -> None:
|
def turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn the entity off."""
|
"""Turn the entity off."""
|
||||||
if self._key == "poke":
|
if self._key == "poke":
|
||||||
return
|
return
|
||||||
|
@ -105,7 +105,7 @@ class StarlingBalanceSensor(SensorEntity):
|
|||||||
"""Return the entity icon."""
|
"""Return the entity icon."""
|
||||||
return ICON
|
return ICON
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Fetch new state data for the sensor."""
|
"""Fetch new state data for the sensor."""
|
||||||
self._starling_account.update_balance_data()
|
self._starling_account.update_balance_data()
|
||||||
if self._balance_data_type == "cleared_balance":
|
if self._balance_data_type == "cleared_balance":
|
||||||
|
@ -163,7 +163,7 @@ class StartcaSensor(SensorEntity):
|
|||||||
|
|
||||||
self._attr_name = f"{name} {description.name}"
|
self._attr_name = f"{name} {description.name}"
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self) -> None:
|
||||||
"""Get the latest data from Start.ca and update the state."""
|
"""Get the latest data from Start.ca and update the state."""
|
||||||
await self.startcadata.async_update()
|
await self.startcadata.async_update()
|
||||||
sensor_type = self.entity_description.key
|
sensor_type = self.entity_description.key
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from homeassistant.components.climate import ClimateEntity
|
from homeassistant.components.climate import ClimateEntity
|
||||||
from homeassistant.components.climate.const import (
|
from homeassistant.components.climate.const import (
|
||||||
@ -87,7 +88,7 @@ class StiebelEltron(ClimateEntity):
|
|||||||
self._force_update = False
|
self._force_update = False
|
||||||
self._ste_data = ste_data
|
self._ste_data = ste_data
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Update unit attributes."""
|
"""Update unit attributes."""
|
||||||
self._ste_data.update(no_throttle=self._force_update)
|
self._ste_data.update(no_throttle=self._force_update)
|
||||||
self._force_update = False
|
self._force_update = False
|
||||||
@ -168,7 +169,7 @@ class StiebelEltron(ClimateEntity):
|
|||||||
self._ste_data.api.set_operation(new_mode)
|
self._ste_data.api.set_operation(new_mode)
|
||||||
self._force_update = True
|
self._force_update = True
|
||||||
|
|
||||||
def set_temperature(self, **kwargs):
|
def set_temperature(self, **kwargs: Any) -> None:
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
target_temperature = kwargs.get(ATTR_TEMPERATURE)
|
target_temperature = kwargs.get(ATTR_TEMPERATURE)
|
||||||
if target_temperature is not None:
|
if target_temperature is not None:
|
||||||
@ -176,7 +177,7 @@ class StiebelEltron(ClimateEntity):
|
|||||||
self._ste_data.api.set_target_temp(target_temperature)
|
self._ste_data.api.set_target_temp(target_temperature)
|
||||||
self._force_update = True
|
self._force_update = True
|
||||||
|
|
||||||
def set_preset_mode(self, preset_mode: str):
|
def set_preset_mode(self, preset_mode: str) -> None:
|
||||||
"""Set new preset mode."""
|
"""Set new preset mode."""
|
||||||
new_mode = HA_TO_STE_PRESET.get(preset_mode)
|
new_mode = HA_TO_STE_PRESET.get(preset_mode)
|
||||||
_LOGGER.debug("set_hvac_mode: %s -> %s", self._operation, new_mode)
|
_LOGGER.debug("set_hvac_mode: %s -> %s", self._operation, new_mode)
|
||||||
|
@ -75,6 +75,6 @@ class StreamlabsAwayMode(BinarySensorEntity):
|
|||||||
"""Return if away mode is on."""
|
"""Return if away mode is on."""
|
||||||
return self._streamlabs_location_data.is_away()
|
return self._streamlabs_location_data.is_away()
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Retrieve the latest location data and away mode state."""
|
"""Retrieve the latest location data and away mode state."""
|
||||||
self._streamlabs_location_data.update()
|
self._streamlabs_location_data.update()
|
||||||
|
@ -106,7 +106,7 @@ class StreamLabsDailyUsage(SensorEntity):
|
|||||||
"""Return gallons as the unit measurement for water."""
|
"""Return gallons as the unit measurement for water."""
|
||||||
return VOLUME_GALLONS
|
return VOLUME_GALLONS
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Retrieve the latest daily usage."""
|
"""Retrieve the latest daily usage."""
|
||||||
self._streamlabs_usage_data.update()
|
self._streamlabs_usage_data.update()
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ class SubaruSensor(SubaruEntity, SensorEntity):
|
|||||||
return self.api_unit
|
return self.api_unit
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self) -> bool:
|
||||||
"""Return if entity is available."""
|
"""Return if entity is available."""
|
||||||
last_update_success = super().available
|
last_update_success = super().available
|
||||||
if last_update_success and self.vin not in self.coordinator.data:
|
if last_update_success and self.vin not in self.coordinator.data:
|
||||||
|
@ -118,7 +118,7 @@ class SuezSensor(SensorEntity):
|
|||||||
self._available = False
|
self._available = False
|
||||||
_LOGGER.warning("Unable to fetch data")
|
_LOGGER.warning("Unable to fetch data")
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Return the latest collected data from Linky."""
|
"""Return the latest collected data from Linky."""
|
||||||
self._fetch_data()
|
self._fetch_data()
|
||||||
_LOGGER.debug("Suez data state is: %s", self._state)
|
_LOGGER.debug("Suez data state is: %s", self._state)
|
||||||
|
@ -79,7 +79,7 @@ class SupervisorProcessSensor(SensorEntity):
|
|||||||
ATTR_GROUP: self._info.get("group"),
|
ATTR_GROUP: self._info.get("group"),
|
||||||
}
|
}
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Update device state."""
|
"""Update device state."""
|
||||||
try:
|
try:
|
||||||
self._info = self._server.supervisor.getProcessInfo(
|
self._info = self._server.supervisor.getProcessInfo(
|
||||||
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchEntity
|
from homeassistant.components.switch import SwitchEntity
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
@ -44,11 +45,11 @@ async def async_setup_platform(
|
|||||||
class SuplaSwitch(SuplaChannel, SwitchEntity):
|
class SuplaSwitch(SuplaChannel, SwitchEntity):
|
||||||
"""Representation of a Supla Switch."""
|
"""Representation of a Supla Switch."""
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs):
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn on the switch."""
|
"""Turn on the switch."""
|
||||||
await self.async_action("TURN_ON")
|
await self.async_action("TURN_ON")
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs):
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn off the switch."""
|
"""Turn off the switch."""
|
||||||
await self.async_action("TURN_OFF")
|
await self.async_action("TURN_OFF")
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ class SwissHydrologicalDataSensor(SensorEntity):
|
|||||||
"""Icon to use in the frontend."""
|
"""Icon to use in the frontend."""
|
||||||
return self._icon
|
return self._icon
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Get the latest data and update the state."""
|
"""Get the latest data and update the state."""
|
||||||
self.hydro_data.update()
|
self.hydro_data.update()
|
||||||
self._data = self.hydro_data.data
|
self._data = self.hydro_data.data
|
||||||
|
@ -131,7 +131,7 @@ class SwissPublicTransportSensor(SensorEntity):
|
|||||||
"""Icon to use in the frontend, if any."""
|
"""Icon to use in the frontend, if any."""
|
||||||
return ICON
|
return ICON
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self) -> None:
|
||||||
"""Get the latest data from opendata.ch and update the states."""
|
"""Get the latest data from opendata.ch and update the states."""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from switchmate import Switchmate
|
from switchmate import Switchmate
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
@ -74,10 +75,10 @@ class SwitchmateEntity(SwitchEntity):
|
|||||||
"""Return true if it is on."""
|
"""Return true if it is on."""
|
||||||
return self._device.state
|
return self._device.state
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the switch on."""
|
"""Turn the switch on."""
|
||||||
await self._device.turn_on()
|
await self._device.turn_on()
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn the switch off."""
|
"""Turn the switch off."""
|
||||||
await self._device.turn_off()
|
await self._device.turn_off()
|
||||||
|
@ -173,7 +173,7 @@ class FolderSensor(SensorEntity):
|
|||||||
self._unsub_timer()
|
self._unsub_timer()
|
||||||
self._unsub_timer = None
|
self._unsub_timer = None
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Handle entity which will be added."""
|
"""Handle entity which will be added."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
Loading…
x
Reference in New Issue
Block a user