Improve entity type hints [s] (part 2/2) (#77882)

This commit is contained in:
epenet 2022-09-06 13:36:44 +02:00 committed by GitHub
parent 458001a06e
commit 3ec231c911
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 112 additions and 88 deletions

View File

@ -280,7 +280,7 @@ class SolarEdgeSensor(SensorEntity):
pass
return None
def update(self):
def update(self) -> None:
"""Get the latest data from the sensor and update the state."""
self._data.update()
self._attr_native_value = self._data.data[self.entity_description.key]

View File

@ -45,7 +45,7 @@ class SomaSensor(SomaEntity, SensorEntity):
return self.battery_state
@Throttle(MIN_TIME_BETWEEN_UPDATES)
async def async_update(self):
async def async_update(self) -> None:
"""Update the sensor with the latest data."""
response = await self.get_battery_level_from_api()

View File

@ -119,11 +119,11 @@ class SongpalEntity(MediaPlayerEntity):
self._active_source = None
self._sources = {}
async def async_added_to_hass(self):
async def async_added_to_hass(self) -> None:
"""Run when entity is added to hass."""
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."""
await self._dev.stop_listen_notifications()
@ -232,7 +232,7 @@ class SongpalEntity(MediaPlayerEntity):
_LOGGER.debug("Calling set_sound_setting with %s: %s", 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."""
try:
if self._sysinfo is None:
@ -281,7 +281,7 @@ class SongpalEntity(MediaPlayerEntity):
_LOGGER.error("Unable to update: %s", ex)
self._available = False
async def async_select_source(self, source):
async def async_select_source(self, source: str) -> None:
"""Select source."""
for out in self._sources.values():
if out.title == source:
@ -314,29 +314,29 @@ class SongpalEntity(MediaPlayerEntity):
volume = self._volume / self._volume_max
return volume
async def async_set_volume_level(self, volume):
async def async_set_volume_level(self, volume: float) -> None:
"""Set volume level."""
volume = int(volume * self._volume_max)
_LOGGER.debug("Setting volume to %s", 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."""
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."""
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."""
return await self._dev.set_power(True)
async def async_turn_off(self):
async def async_turn_off(self) -> None:
"""Turn the device off."""
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."""
_LOGGER.debug("Set mute: %s", mute)
return await self._volume_control.set_mute(mute)

View File

@ -23,6 +23,7 @@ from homeassistant.components.media_player import (
MediaPlayerEntityFeature,
async_process_play_media_url,
)
from homeassistant.components.media_player.browse_media import BrowseMedia
from homeassistant.components.media_player.const import (
ATTR_INPUT_SOURCE,
ATTR_MEDIA_ENQUEUE,
@ -715,7 +716,7 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
async def async_browse_media(
self, media_content_type: str | None = None, media_content_id: str | None = None
) -> Any:
) -> BrowseMedia:
"""Implement the websocket media browsing helper."""
return await media_browser.async_browse_media(
self.hass,

View File

@ -2,6 +2,7 @@
from __future__ import annotations
import logging
from typing import Any
import pysdcp
import voluptuous as vol
@ -78,7 +79,7 @@ class SonyProjector(SwitchEntity):
"""Return state attributes."""
return self._attributes
def update(self):
def update(self) -> None:
"""Get the latest state from the projector."""
try:
self._state = self._sdcp.get_power()
@ -87,7 +88,7 @@ class SonyProjector(SwitchEntity):
_LOGGER.error("Projector connection refused")
self._available = False
def turn_on(self, **kwargs):
def turn_on(self, **kwargs: Any) -> None:
"""Turn the projector on."""
_LOGGER.debug("Powering on projector '%s'", self.name)
if self._sdcp.set_power(True):
@ -96,7 +97,7 @@ class SonyProjector(SwitchEntity):
else:
_LOGGER.error("Power on command was not successful")
def turn_off(self, **kwargs):
def turn_off(self, **kwargs: Any) -> None:
"""Turn the projector off."""
_LOGGER.debug("Powering off projector '%s'", self.name)
if self._sdcp.set_power(False):

View File

@ -6,7 +6,9 @@ from requests import RequestException
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.components.zeroconf import ZeroconfServiceInfo
from homeassistant.const import CONF_HOST
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import config_validation as cv
from .const import DOMAIN
@ -60,7 +62,9 @@ class SoundtouchConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
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."""
self.host = discovery_info.host

View File

@ -4,6 +4,7 @@ from __future__ import annotations
from functools import partial
import logging
import re
from typing import Any
from libsoundtouch.device import SoundTouchDevice
from libsoundtouch.utils import Source
@ -17,6 +18,7 @@ from homeassistant.components.media_player import (
MediaPlayerEntityFeature,
)
from homeassistant.components.media_player.browse_media import (
BrowseMedia,
async_process_play_media_url,
)
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
@ -154,7 +156,7 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
"""Return SoundTouch device."""
return self._device
def update(self):
def update(self) -> None:
"""Retrieve the latest data."""
self._status = self._device.status()
self._volume = self._device.volume()
@ -194,47 +196,47 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
"""Boolean if volume is currently muted."""
return self._volume.muted
def turn_off(self):
def turn_off(self) -> None:
"""Turn off media player."""
self._device.power_off()
def turn_on(self):
def turn_on(self) -> None:
"""Turn on media player."""
self._device.power_on()
def volume_up(self):
def volume_up(self) -> None:
"""Volume up the media player."""
self._device.volume_up()
def volume_down(self):
def volume_down(self) -> None:
"""Volume down media player."""
self._device.volume_down()
def set_volume_level(self, volume):
def set_volume_level(self, volume: float) -> None:
"""Set volume level, range 0..1."""
self._device.set_volume(int(volume * 100))
def mute_volume(self, mute):
def mute_volume(self, mute: bool) -> None:
"""Send mute command."""
self._device.mute()
def media_play_pause(self):
def media_play_pause(self) -> None:
"""Simulate play pause media player."""
self._device.play_pause()
def media_play(self):
def media_play(self) -> None:
"""Send play command."""
self._device.play()
def media_pause(self):
def media_pause(self) -> None:
"""Send media pause command to media player."""
self._device.pause()
def media_next_track(self):
def media_next_track(self) -> None:
"""Send next track command."""
self._device.next_track()
def media_previous_track(self):
def media_previous_track(self) -> None:
"""Send the previous track command."""
self._device.previous_track()
@ -273,7 +275,7 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
"""Album name of current playing media."""
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."""
@callback
@ -285,7 +287,9 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
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."""
if media_source.is_media_source_id(media_id):
play_item = await media_source.async_resolve_media(
@ -297,7 +301,7 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
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."""
_LOGGER.debug("Starting media with media_id: %s", media_id)
if re.match(r"http?://", str(media_id)):
@ -319,7 +323,7 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
else:
_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."""
if source == Source.AUX.value:
_LOGGER.debug("Selecting source AUX")
@ -399,7 +403,9 @@ class SoundTouchMediaPlayer(MediaPlayerEntity):
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."""
return await media_source.async_browse_media(self.hass, media_content_id)

View File

@ -1,4 +1,6 @@
"""Support for Spider thermostats."""
from typing import Any
from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import ClimateEntityFeature, HVACMode
from homeassistant.config_entries import ConfigEntry
@ -59,7 +61,7 @@ class SpiderThermostat(ClimateEntity):
)
@property
def supported_features(self):
def supported_features(self) -> int:
"""Return the list of supported features."""
if self.thermostat.has_fan_mode:
return (
@ -112,7 +114,7 @@ class SpiderThermostat(ClimateEntity):
"""Return the list of available operation modes."""
return self.support_hvac
def set_temperature(self, **kwargs):
def set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
return
@ -128,7 +130,7 @@ class SpiderThermostat(ClimateEntity):
"""Return the fan setting."""
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."""
self.thermostat.set_fan_speed(fan_mode)
@ -137,6 +139,6 @@ class SpiderThermostat(ClimateEntity):
"""List of available fan modes."""
return self.support_fan
def update(self):
def update(self) -> None:
"""Get the latest data."""
self.thermostat = self.api.get_thermostat(self.unique_id)

View File

@ -1,4 +1,6 @@
"""Support for Spider switches."""
from typing import Any
from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
@ -56,18 +58,18 @@ class SpiderPowerPlug(SwitchEntity):
return self.power_plug.is_on
@property
def available(self):
def available(self) -> bool:
"""Return true if switch is available."""
return self.power_plug.is_available
def turn_on(self, **kwargs):
def turn_on(self, **kwargs: Any) -> None:
"""Turn device on."""
self.power_plug.turn_on()
def turn_off(self, **kwargs):
def turn_off(self, **kwargs: Any) -> None:
"""Turn device off."""
self.power_plug.turn_off()
def update(self):
def update(self) -> None:
"""Get the latest data."""
self.power_plug = self.api.get_power_plug(self.power_plug.id)

View File

@ -5,6 +5,7 @@ from asyncio import run_coroutine_threadsafe
import datetime as dt
from datetime import timedelta
import logging
from typing import Any
import requests
from spotipy import SpotifyException
@ -273,7 +274,7 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
return REPEAT_MODE_MAPPING_TO_HA.get(repeat_state)
@spotify_exception_handler
def set_volume_level(self, volume: int) -> None:
def set_volume_level(self, volume: float) -> None:
"""Set the volume level."""
self.data.client.volume(int(volume * 100))
@ -298,12 +299,12 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
self.data.client.next_track()
@spotify_exception_handler
def media_seek(self, position):
def media_seek(self, position: float) -> None:
"""Send seek command."""
self.data.client.seek_track(int(position * 1000))
@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."""
if media_type.startswith(MEDIA_PLAYER_PREFIX):
media_type = media_type[len(MEDIA_PLAYER_PREFIX) :]

View File

@ -4,6 +4,7 @@ from __future__ import annotations
import asyncio
import json
import logging
from typing import Any
from pysqueezebox import Server, async_discover
import voluptuous as vol
@ -296,7 +297,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
return SQUEEZEBOX_MODE.get(self._player.mode)
return None
async def async_update(self):
async def async_update(self) -> None:
"""Update the Player() object."""
# only update available players, newly available players will be rediscovered and marked available
if self._available:
@ -313,7 +314,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
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."""
self.hass.data[DOMAIN][KNOWN_PLAYERS].remove(self)
@ -419,60 +420,62 @@ class SqueezeBoxEntity(MediaPlayerEntity):
"""Return the result from the call_query service."""
return self._query_result
async def async_turn_off(self):
async def async_turn_off(self) -> None:
"""Turn off media player."""
await self._player.async_set_power(False)
async def async_volume_up(self):
async def async_volume_up(self) -> None:
"""Volume up media player."""
await self._player.async_set_volume("+5")
async def async_volume_down(self):
async def async_volume_down(self) -> None:
"""Volume down media player."""
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."""
volume_percent = str(int(volume * 100))
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."""
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."""
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."""
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."""
await self._player.async_play()
async def async_media_pause(self):
async def async_media_pause(self) -> None:
"""Send pause command to media player."""
await self._player.async_pause()
async def async_media_next_track(self):
async def async_media_next_track(self) -> None:
"""Send next track command."""
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."""
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."""
await self._player.async_time(position)
async def async_turn_on(self):
async def async_turn_on(self) -> None:
"""Turn the media player on."""
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."""
index = None
@ -528,7 +531,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
if index is not None:
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."""
if repeat == REPEAT_MODE_ALL:
repeat_mode = "playlist"
@ -539,12 +542,12 @@ class SqueezeBoxEntity(MediaPlayerEntity):
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."""
shuffle_mode = "song" if shuffle else "none"
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."""
await self._player.async_clear_playlist()
@ -575,7 +578,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
self._query_result = await self._player.async_query(*all_params)
_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.
@ -601,7 +604,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
)
await self.async_join_players([other_player])
async def async_unjoin_player(self):
async def async_unjoin_player(self) -> None:
"""Unsync this Squeezebox player."""
await self._player.async_unsync()

View File

@ -153,7 +153,7 @@ class SrpEntity(SensorEntity):
"""Return the state class."""
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."""
self.async_on_remove(
self.coordinator.async_add_listener(self.async_write_ha_state)
@ -161,7 +161,7 @@ class SrpEntity(SensorEntity):
if self.coordinator.data:
self._state = self.coordinator.data
async def async_update(self):
async def async_update(self) -> None:
"""Update the entity.
Only used by the generic entity update service.

View File

@ -2,6 +2,7 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.config_entries import ConfigEntry
@ -88,7 +89,7 @@ class StarlineSwitch(StarlineEntity, SwitchEntity):
self.entity_description = description
@property
def available(self):
def available(self) -> bool:
"""Return True if entity is available."""
return super().available and self._device.online
@ -120,11 +121,11 @@ class StarlineSwitch(StarlineEntity, SwitchEntity):
return False
return self._device.car_state.get(self._key)
def turn_on(self, **kwargs):
def turn_on(self, **kwargs: Any) -> None:
"""Turn the entity on."""
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."""
if self._key == "poke":
return

View File

@ -105,7 +105,7 @@ class StarlingBalanceSensor(SensorEntity):
"""Return the entity icon."""
return ICON
def update(self):
def update(self) -> None:
"""Fetch new state data for the sensor."""
self._starling_account.update_balance_data()
if self._balance_data_type == "cleared_balance":

View File

@ -163,7 +163,7 @@ class StartcaSensor(SensorEntity):
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."""
await self.startcadata.async_update()
sensor_type = self.entity_description.key

View File

@ -2,6 +2,7 @@
from __future__ import annotations
import logging
from typing import Any
from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
@ -87,7 +88,7 @@ class StiebelEltron(ClimateEntity):
self._force_update = False
self._ste_data = ste_data
def update(self):
def update(self) -> None:
"""Update unit attributes."""
self._ste_data.update(no_throttle=self._force_update)
self._force_update = False
@ -168,7 +169,7 @@ class StiebelEltron(ClimateEntity):
self._ste_data.api.set_operation(new_mode)
self._force_update = True
def set_temperature(self, **kwargs):
def set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
target_temperature = kwargs.get(ATTR_TEMPERATURE)
if target_temperature is not None:
@ -176,7 +177,7 @@ class StiebelEltron(ClimateEntity):
self._ste_data.api.set_target_temp(target_temperature)
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."""
new_mode = HA_TO_STE_PRESET.get(preset_mode)
_LOGGER.debug("set_hvac_mode: %s -> %s", self._operation, new_mode)

View File

@ -75,6 +75,6 @@ class StreamlabsAwayMode(BinarySensorEntity):
"""Return if away mode is on."""
return self._streamlabs_location_data.is_away()
def update(self):
def update(self) -> None:
"""Retrieve the latest location data and away mode state."""
self._streamlabs_location_data.update()

View File

@ -106,7 +106,7 @@ class StreamLabsDailyUsage(SensorEntity):
"""Return gallons as the unit measurement for water."""
return VOLUME_GALLONS
def update(self):
def update(self) -> None:
"""Retrieve the latest daily usage."""
self._streamlabs_usage_data.update()

View File

@ -265,7 +265,7 @@ class SubaruSensor(SubaruEntity, SensorEntity):
return self.api_unit
@property
def available(self):
def available(self) -> bool:
"""Return if entity is available."""
last_update_success = super().available
if last_update_success and self.vin not in self.coordinator.data:

View File

@ -118,7 +118,7 @@ class SuezSensor(SensorEntity):
self._available = False
_LOGGER.warning("Unable to fetch data")
def update(self):
def update(self) -> None:
"""Return the latest collected data from Linky."""
self._fetch_data()
_LOGGER.debug("Suez data state is: %s", self._state)

View File

@ -79,7 +79,7 @@ class SupervisorProcessSensor(SensorEntity):
ATTR_GROUP: self._info.get("group"),
}
def update(self):
def update(self) -> None:
"""Update device state."""
try:
self._info = self._server.supervisor.getProcessInfo(

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import logging
from pprint import pformat
from typing import Any
from homeassistant.components.switch import SwitchEntity
from homeassistant.core import HomeAssistant
@ -44,11 +45,11 @@ async def async_setup_platform(
class SuplaSwitch(SuplaChannel, SwitchEntity):
"""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."""
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."""
await self.async_action("TURN_OFF")

View File

@ -145,7 +145,7 @@ class SwissHydrologicalDataSensor(SensorEntity):
"""Icon to use in the frontend."""
return self._icon
def update(self):
def update(self) -> None:
"""Get the latest data and update the state."""
self.hydro_data.update()
self._data = self.hydro_data.data

View File

@ -131,7 +131,7 @@ class SwissPublicTransportSensor(SensorEntity):
"""Icon to use in the frontend, if any."""
return ICON
async def async_update(self):
async def async_update(self) -> None:
"""Get the latest data from opendata.ch and update the states."""
try:

View File

@ -2,6 +2,7 @@
from __future__ import annotations
from datetime import timedelta
from typing import Any
from switchmate import Switchmate
import voluptuous as vol
@ -74,10 +75,10 @@ class SwitchmateEntity(SwitchEntity):
"""Return true if it is on."""
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."""
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."""
await self._device.turn_off()

View File

@ -173,7 +173,7 @@ class FolderSensor(SensorEntity):
self._unsub_timer()
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."""
@callback