Compare commits

...

1 Commits

Author SHA1 Message Date
abmantis 6dea67e8c9 Add override decorator to components C to E 2026-05-24 19:42:28 +01:00
580 changed files with 3024 additions and 407 deletions
+6 -1
View File
@@ -3,7 +3,7 @@
from datetime import datetime
from functools import partial
import logging
from typing import Any
from typing import Any, override
import caldav
from caldav.lib.error import DAVError
@@ -204,17 +204,20 @@ class WebDavCalendarEntity(CoordinatorEntity[CalDavUpdateCoordinator], CalendarE
self._attr_unique_id = unique_id
self._supports_offset = supports_offset
@override
@property
def event(self) -> CalendarEvent | None:
"""Return the next upcoming event."""
return self._event
@override
async def async_get_events(
self, hass: HomeAssistant, start_date: datetime, end_date: datetime
) -> list[CalendarEvent]:
"""Get all events in a specific time frame."""
return await self.coordinator.async_get_events(hass, start_date, end_date)
@override
async def async_create_event(self, **kwargs: Any) -> None:
"""Create a new event in the calendar."""
_LOGGER.debug("Event: %s", kwargs)
@@ -240,6 +243,7 @@ class WebDavCalendarEntity(CoordinatorEntity[CalDavUpdateCoordinator], CalendarE
except (requests.ConnectionError, requests.Timeout, DAVError) as err:
raise HomeAssistantError(f"CalDAV save error: {err}") from err
@override
@callback
def _handle_coordinator_update(self) -> None:
"""Update event data."""
@@ -255,6 +259,7 @@ class WebDavCalendarEntity(CoordinatorEntity[CalDavUpdateCoordinator], CalendarE
}
super()._handle_coordinator_update()
@override
async def async_added_to_hass(self) -> None:
"""When entity is added to hass update state from existing coordinator data."""
await super().async_added_to_hass()
@@ -2,7 +2,7 @@
from collections.abc import Mapping
import logging
from typing import Any
from typing import Any, override
import caldav
from caldav.lib.error import AuthorizationError, DAVError
@@ -33,6 +33,7 @@ class CalDavConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 1
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -4,7 +4,7 @@ from datetime import date, datetime, time, timedelta
from functools import partial
import logging
import re
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, override
import caldav
@@ -90,6 +90,7 @@ class CalDavUpdateCoordinator(DataUpdateCoordinator[CalendarEvent | None]):
return event_list
@override
async def _async_update_data(self) -> CalendarEvent | None:
"""Get the latest data."""
start_of_today = dt_util.start_of_local_day()
+4 -1
View File
@@ -4,7 +4,7 @@ import asyncio
from datetime import date, datetime, timedelta
from functools import partial
import logging
from typing import Any, cast
from typing import Any, cast, override
import caldav
from caldav.lib.error import DAVError, NotFoundError
@@ -121,6 +121,7 @@ class WebDavTodoListEntity(TodoListEntity):
if (todo_item := _todo_item(resource)) is not None
]
@override
async def async_create_todo_item(self, item: TodoItem) -> None:
"""Add an item to the To-do list."""
item_data: dict[str, Any] = {}
@@ -141,6 +142,7 @@ class WebDavTodoListEntity(TodoListEntity):
except (requests.ConnectionError, requests.Timeout, DAVError) as err:
raise HomeAssistantError(f"CalDAV save error: {err}") from err
@override
async def async_update_todo_item(self, item: TodoItem) -> None:
"""Update a To-do item."""
uid: str = cast(str, item.uid)
@@ -177,6 +179,7 @@ class WebDavTodoListEntity(TodoListEntity):
except (requests.ConnectionError, requests.Timeout, DAVError) as err:
raise HomeAssistantError(f"CalDAV save error: {err}") from err
@override
async def async_delete_todo_items(self, uids: list[str]) -> None:
"""Delete To-do items."""
tasks = (
@@ -7,7 +7,7 @@ from http import HTTPStatus
from itertools import groupby
import logging
import re
from typing import Any, Final, cast, final
from typing import Any, Final, cast, final, override
from aiohttp import web
from dateutil.rrule import rrulestr
@@ -546,6 +546,7 @@ class CalendarEntity(Entity):
return self.entity_description.initial_color
return None
@override
def get_initial_entity_options(self) -> er.EntityOptionsType | None:
"""Return initial entity options."""
if self.initial_color is None:
@@ -564,6 +565,7 @@ class CalendarEntity(Entity):
"""Return the next upcoming event."""
raise NotImplementedError
@override
@final
@property
def state_attributes(self) -> dict[str, Any] | None:
@@ -580,6 +582,7 @@ class CalendarEntity(Entity):
"description": event.description or "",
}
@override
@final
@property
def state(self) -> str:
@@ -594,6 +597,7 @@ class CalendarEntity(Entity):
return STATE_OFF
@override
@callback
def _async_write_ha_state(self) -> None:
"""Write the state to the state machine.
@@ -653,6 +657,7 @@ class CalendarEntity(Entity):
self._event_listener_debouncer.async_cancel()
self._event_listener_debouncer = None
@override
async def async_will_remove_from_hass(self) -> None:
"""Run when entity will be removed from hass.
+9 -1
View File
@@ -5,7 +5,7 @@ from collections.abc import Awaitable, Callable
from dataclasses import dataclass
import datetime
import logging
from typing import TYPE_CHECKING, Any, cast
from typing import TYPE_CHECKING, Any, cast, override
import voluptuous as vol
@@ -113,6 +113,7 @@ class Timespan:
"""
return Timespan(self.end, max(self.end, now) + interval)
@override
def __str__(self) -> str:
"""Return a string representing the half open interval time span."""
return f"[{self.start}, {self.end})"
@@ -325,6 +326,7 @@ class TargetCalendarEventListener(TargetEntityChangeTracker):
self._pending_listener_task: asyncio.Task[None] | None = None
self._calendar_event_listener: CalendarEventListener | None = None
@override
@callback
def _handle_entities_update(self, tracked_entities: set[str]) -> None:
"""Restart listeners when tracked target entities update."""
@@ -351,6 +353,7 @@ class TargetCalendarEventListener(TargetEntityChangeTracker):
)
await self._calendar_event_listener.async_attach()
@override
def _unsubscribe(self) -> None:
"""Unsubscribe from all events."""
super()._unsubscribe()
@@ -367,6 +370,7 @@ class SingleEntityEventTrigger(Trigger):
_options: dict[str, Any]
@override
@classmethod
async def async_validate_complete_config(
cls, hass: HomeAssistant, complete_config: ConfigType
@@ -377,6 +381,7 @@ class SingleEntityEventTrigger(Trigger):
)
return await super().async_validate_complete_config(hass, complete_config)
@override
@classmethod
async def async_validate_config(
cls, hass: HomeAssistant, config: ConfigType
@@ -392,6 +397,7 @@ class SingleEntityEventTrigger(Trigger):
assert config.options is not None
self._options = config.options
@override
async def async_attach_runner(
self, run_action: TriggerActionRunner
) -> CALLBACK_TYPE:
@@ -426,6 +432,7 @@ class EventTrigger(Trigger):
_options: dict[str, Any]
_event_type: str
@override
@classmethod
async def async_validate_config(
cls, hass: HomeAssistant, config: ConfigType
@@ -443,6 +450,7 @@ class EventTrigger(Trigger):
self._target = config.target
self._options = config.options
@override
async def async_attach_runner(
self, run_action: TriggerActionRunner
) -> CALLBACK_TYPE:
@@ -1,7 +1,7 @@
"""Config flow for Cambridge Audio."""
import asyncio
from typing import Any
from typing import Any, override
from aiostreammagic import StreamMagicClient
import voluptuous as vol
@@ -29,6 +29,7 @@ class CambridgeAudioConfigFlow(ConfigFlow, domain=DOMAIN):
"""Initialize the config flow."""
self.data: dict[str, Any] = {}
@override
async def async_step_zeroconf(
self, discovery_info: ZeroconfServiceInfo
) -> ConfigFlowResult:
@@ -81,6 +82,7 @@ class CambridgeAudioConfigFlow(ConfigFlow, domain=DOMAIN):
)
return await self.async_step_user(user_input)
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -2,7 +2,7 @@
from collections.abc import Awaitable, Callable, Coroutine
from functools import wraps
from typing import Any, Concatenate
from typing import Any, Concatenate, override
from aiostreammagic import StreamMagicClient
from aiostreammagic.models import CallbackType
@@ -60,15 +60,18 @@ class CambridgeAudioEntity(Entity):
"""Call when the device is notified of changes."""
self.async_write_ha_state()
@override
@property
def available(self) -> bool:
"""Return True if entity is available."""
return self.client.is_connected()
@override
async def async_added_to_hass(self) -> None:
"""Register callback handlers."""
await self.client.register_state_update_callbacks(self._state_update_callback)
@override
async def async_will_remove_from_hass(self) -> None:
"""Remove callbacks."""
self.client.unregister_state_update_callbacks(self._state_update_callback)
@@ -1,7 +1,7 @@
"""Support for Cambridge Audio AV Receiver."""
from datetime import datetime
from typing import Any
from typing import Any, override
from aiostreammagic import (
RepeatMode as CambridgeRepeatMode,
@@ -83,6 +83,7 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
super().__init__(client)
self._attr_unique_id = client.info.unit_id
@override
@property
def supported_features(self) -> MediaPlayerEntityFeature:
"""Supported features for the media player."""
@@ -100,6 +101,7 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
features |= feature
return features
@override
@property
def state(self) -> MediaPlayerState:
"""Return the state of the device."""
@@ -118,11 +120,13 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
return MediaPlayerState.ON
return MediaPlayerState.OFF
@override
@property
def source_list(self) -> list[str]:
"""Return a list of available input sources."""
return [item.name for item in self.client.sources]
@override
@property
def source(self) -> str | None:
"""Return the current input source."""
@@ -135,11 +139,13 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
None,
)
@override
@property
def media_title(self) -> str | None:
"""Title of current playing media."""
return self.client.play_state.metadata.title
@override
@property
def media_artist(self) -> str | None:
"""Artist of current playing media, music track only."""
@@ -151,52 +157,62 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
return self.client.play_state.metadata.station
return self.client.play_state.metadata.artist
@override
@property
def media_album_name(self) -> str | None:
"""Album name of current playing media, music track only."""
return self.client.play_state.metadata.album
@override
@property
def media_image_url(self) -> str | None:
"""Image url of current playing media."""
return self.client.play_state.metadata.art_url
@override
@property
def media_duration(self) -> int | None:
"""Duration of the current media."""
return self.client.play_state.metadata.duration
@override
@property
def media_position(self) -> int | None:
"""Position of the current media."""
return self.client.play_state.position
@override
@property
def media_position_updated_at(self) -> datetime:
"""Last time the media position was updated."""
return self.client.position_last_updated
@override
@property
def media_channel(self) -> str | None:
"""Channel currently playing."""
return self.client.play_state.metadata.station
@override
@property
def is_volume_muted(self) -> bool | None:
"""Volume mute status."""
return self.client.state.mute
@override
@property
def volume_level(self) -> float | None:
"""Current pre-amp volume level."""
volume = self.client.state.volume_percent or 0
return volume / 100
@override
@property
def shuffle(self) -> bool:
"""Current shuffle configuration."""
return self.client.play_state.mode_shuffle != ShuffleMode.OFF
@override
@property
def repeat(self) -> RepeatMode | None:
"""Current repeat configuration."""
@@ -205,11 +221,13 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
mode_repeat = RepeatMode.ALL
return mode_repeat
@override
@command
async def async_media_play_pause(self) -> None:
"""Toggle play/pause the current media."""
await self.client.play_pause()
@override
@command
async def async_media_pause(self) -> None:
"""Pause the current media."""
@@ -222,11 +240,13 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
else:
await self.client.pause()
@override
@command
async def async_media_stop(self) -> None:
"""Stop the current media."""
await self.client.stop()
@override
@command
async def async_media_play(self) -> None:
"""Play the current media."""
@@ -239,16 +259,19 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
else:
await self.client.play()
@override
@command
async def async_media_next_track(self) -> None:
"""Skip to the next track."""
await self.client.next_track()
@override
@command
async def async_media_previous_track(self) -> None:
"""Skip to the previous track."""
await self.client.previous_track()
@override
@command
async def async_select_source(self, source: str) -> None:
"""Select the source."""
@@ -257,41 +280,49 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
await self.client.set_source_by_id(src.id)
break
@override
@command
async def async_turn_on(self) -> None:
"""Power on the device."""
await self.client.power_on()
@override
@command
async def async_turn_off(self) -> None:
"""Power off the device."""
await self.client.power_off()
@override
@command
async def async_volume_up(self) -> None:
"""Step the volume up."""
await self.client.volume_up()
@override
@command
async def async_volume_down(self) -> None:
"""Step the volume down."""
await self.client.volume_down()
@override
@command
async def async_set_volume_level(self, volume: float) -> None:
"""Set the volume level."""
await self.client.set_volume(int(volume * 100))
@override
@command
async def async_mute_volume(self, mute: bool) -> None:
"""Set the mute state."""
await self.client.set_mute(mute)
@override
@command
async def async_media_seek(self, position: float) -> None:
"""Seek to a position in the current media."""
await self.client.media_seek(int(position))
@override
@command
async def async_set_shuffle(self, shuffle: bool) -> None:
"""Set the shuffle mode for the current queue."""
@@ -300,6 +331,7 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
shuffle_mode = ShuffleMode.ALL
await self.client.set_shuffle(shuffle_mode)
@override
@command
async def async_set_repeat(self, repeat: RepeatMode) -> None:
"""Set the repeat mode for the current queue."""
@@ -308,6 +340,7 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
repeat_mode = CambridgeRepeatMode.ALL
await self.client.set_repeat(repeat_mode)
@override
@command
async def async_play_media(
self, media_type: MediaType | str, media_id: str, **kwargs: Any
@@ -353,6 +386,7 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
if media_type == CAMBRIDGE_MEDIA_TYPE_INTERNET_RADIO:
await self.client.play_radio_url("Radio", media_id)
@override
async def async_browse_media(
self,
media_content_type: MediaType | str | None = None,
@@ -2,7 +2,7 @@
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, override
from aiostreammagic import StreamMagicClient
@@ -90,16 +90,19 @@ class CambridgeAudioNumber(CambridgeAudioEntity, NumberEntity):
self.entity_description = description
self._attr_unique_id = f"{client.info.unit_id}-{description.key}"
@override
@property
def native_value(self) -> int | None:
"""Return the state of the number."""
return self.entity_description.value_fn(self.client)
@override
@command
async def async_set_native_value(self, value: float) -> None:
"""Set the selected value."""
await self.entity_description.set_value_fn(self.client, int(value))
@override
@property
def available(self) -> bool:
"""Return True if entity is available."""
@@ -2,6 +2,7 @@
from collections.abc import Awaitable, Callable
from dataclasses import dataclass, field
from typing import override
from aiostreammagic import StreamMagicClient
from aiostreammagic.models import ControlBusMode, DisplayBrightness
@@ -127,11 +128,13 @@ class CambridgeAudioSelect(CambridgeAudioEntity, SelectEntity):
if options_fn:
self._attr_options = options_fn
@override
@property
def current_option(self) -> str | None:
"""Return the state of the select."""
return self.entity_description.value_fn(self.client)
@override
@command
async def async_select_option(self, option: str) -> None:
"""Change the selected option."""
@@ -2,7 +2,7 @@
from collections.abc import Awaitable, Callable
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, override
from aiostreammagic import StreamMagicClient
@@ -103,16 +103,19 @@ class CambridgeAudioSwitch(CambridgeAudioEntity, SwitchEntity):
self.entity_description = description
self._attr_unique_id = f"{client.info.unit_id}-{description.key}"
@override
@property
def is_on(self) -> bool:
"""Return the state of the switch."""
return self.entity_description.value_fn(self.client)
@override
@command
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the switch on."""
await self.entity_description.set_value_fn(self.client, True)
@override
@command
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the switch off."""
+11 -1
View File
@@ -12,7 +12,7 @@ import logging
import os
from random import SystemRandom
import time
from typing import Any, Final, final
from typing import Any, Final, final, override
from aiohttp import hdrs, web
import attr
@@ -455,6 +455,7 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
!= Camera.async_handle_async_webrtc_offer
)
@override
@cached_property
def entity_picture(self) -> str:
"""Return a link to the camera feed as entity picture."""
@@ -467,6 +468,7 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
"""Whether or not to use stream to generate stills."""
return False
@override
@cached_property
def supported_features(self) -> CameraEntityFeature:
"""Flag supported features."""
@@ -502,6 +504,7 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
"""Return the interval between frames of the mjpeg stream."""
return self._attr_frame_interval
@override
@property
def available(self) -> bool:
"""Return True if entity is available."""
@@ -595,6 +598,7 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
"""
return await self.handle_async_still_stream(request, self.frame_interval)
@override
@property
@final
def state(self) -> str:
@@ -642,6 +646,7 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
"""Call the job and disable motion detection."""
await self.hass.async_add_executor_job(self.disable_motion_detection)
@override
@final
@property
def state_attributes(self) -> dict[str, str | None]:
@@ -665,6 +670,7 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
self.access_tokens.append(hex(_RND.getrandbits(256))[2:])
self.__dict__.pop("entity_picture", None)
@override
async def async_internal_added_to_hass(self) -> None:
"""Run when entity about to be added to hass."""
await super().async_internal_added_to_hass()
@@ -758,6 +764,7 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
return CameraCapabilities(frontend_stream_types)
@override
@callback
def _async_write_ha_state(self) -> None:
"""Write the state to the state machine.
@@ -817,6 +824,7 @@ class CameraImageView(CameraView):
url = "/api/camera_proxy/{entity_id}"
name = "api:camera:image"
@override
async def handle(self, request: web.Request, camera: Camera) -> web.Response:
"""Serve camera image."""
width = request.query.get("width")
@@ -840,6 +848,7 @@ class CameraMjpegStream(CameraView):
url = "/api/camera_proxy_stream/{entity_id}"
name = "api:camera:stream"
@override
async def handle(self, request: web.Request, camera: Camera) -> web.StreamResponse:
"""Serve camera stream, possibly with interval."""
if (interval_str := request.query.get("interval")) is None:
@@ -985,6 +994,7 @@ class _TemplateCameraEntity:
self._report_issue()
return getattr(self._camera, name)
@override
def __str__(self) -> str:
"""Forward to the camera entity."""
self._report_issue()
@@ -1,6 +1,7 @@
"""Expose cameras as media sources."""
import asyncio
from typing import override
from homeassistant.components.media_player import BrowseError, MediaClass
from homeassistant.components.media_source import (
@@ -54,6 +55,7 @@ class CameraMediaSource(MediaSource):
super().__init__(DOMAIN)
self.hass = hass
@override
async def async_resolve_media(self, item: MediaSourceItem) -> PlayMedia:
"""Resolve media to a url."""
component = self.hass.data[DATA_COMPONENT]
@@ -82,6 +84,7 @@ class CameraMediaSource(MediaSource):
return PlayMedia(url, FORMAT_CONTENT_TYPE[HLS_PROVIDER])
@override
async def async_browse_media(
self,
item: MediaSourceItem,
+2 -1
View File
@@ -6,7 +6,7 @@ from collections.abc import Awaitable, Callable
from dataclasses import asdict, dataclass, field
from functools import cache, partial, wraps
import logging
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, override
from mashumaro import MissingField
import voluptuous as vol
@@ -73,6 +73,7 @@ class WebRTCCandidate(WebRTCMessage):
candidate: RTCIceCandidate | RTCIceCandidateInit
@override
def as_dict(self) -> dict[str, Any]:
"""Return a dict representation of the message."""
return {
@@ -1,6 +1,6 @@
"""Support for Canary alarm."""
from typing import Any
from typing import Any, override
from canary.const import LOCATION_MODE_AWAY, LOCATION_MODE_HOME, LOCATION_MODE_NIGHT
from canary.model import Location
@@ -58,6 +58,7 @@ class CanaryAlarm(
"""Return information about the location."""
return self.coordinator.data["locations"][self._location_id]
@override
@property
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the device."""
@@ -74,25 +75,30 @@ class CanaryAlarm(
return None
@override
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes."""
return {"private": self.location.is_private}
@override
def alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
self.coordinator.canary.set_location_mode(
self._location_id, self.location.mode.name, True
)
@override
def alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
self.coordinator.canary.set_location_mode(self._location_id, LOCATION_MODE_HOME)
@override
def alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
self.coordinator.canary.set_location_mode(self._location_id, LOCATION_MODE_AWAY)
@override
def alarm_arm_night(self, code: str | None = None) -> None:
"""Send arm night command."""
self.coordinator.canary.set_location_mode(
+5 -1
View File
@@ -2,7 +2,7 @@
from datetime import timedelta
import logging
from typing import Final
from typing import Final, override
from aiohttp.web import Request, StreamResponse
from canary.live_stream_api import LiveStreamSession
@@ -108,16 +108,19 @@ class CanaryCamera(CoordinatorEntity[CanaryDataUpdateCoordinator], Camera):
"""Return information about the location."""
return self.coordinator.data["locations"][self._location_id]
@override
@property
def is_recording(self) -> bool:
"""Return true if the device is recording."""
return self.location.is_recording # type: ignore[no-any-return]
@override
@property
def motion_detection_enabled(self) -> bool:
"""Return the camera motion detection status."""
return not self.location.is_recording
@override
async def async_camera_image(
self, width: int | None = None, height: int | None = None
) -> bytes | None:
@@ -150,6 +153,7 @@ class CanaryCamera(CoordinatorEntity[CanaryDataUpdateCoordinator], Camera):
return self._image
@override
async def handle_async_mjpeg_stream(
self, request: Request
) -> StreamResponse | None:
@@ -1,7 +1,7 @@
"""Config flow for Canary."""
import logging
from typing import Any, Final
from typing import Any, Final, override
from canary.api import Api
from requests.exceptions import ConnectTimeout, HTTPError
@@ -46,12 +46,14 @@ class CanaryConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 1
@override
@staticmethod
@callback
def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow:
"""Get the options flow for this handler."""
return CanaryOptionsFlowHandler()
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -4,6 +4,7 @@ import asyncio
from collections.abc import ValuesView
from datetime import timedelta
import logging
from typing import override
from canary.api import Api
from canary.model import Location, Reading
@@ -60,6 +61,7 @@ class CanaryDataUpdateCoordinator(DataUpdateCoordinator[CanaryData]):
"readings": readings_by_device_id,
}
@override
async def _async_update_data(self) -> CanaryData:
"""Fetch data from Canary."""
+3 -1
View File
@@ -1,6 +1,6 @@
"""Support for Canary sensors."""
from typing import Final
from typing import Final, override
from canary.model import Device, Location, SensorType
@@ -143,11 +143,13 @@ class CanarySensor(CoordinatorEntity[CanaryDataUpdateCoordinator], SensorEntity)
return None
@override
@property
def native_value(self) -> float | None:
"""Return the state of the sensor."""
return self.reading
@override
@property
def extra_state_attributes(self) -> dict[str, str] | None:
"""Return the state attributes."""
@@ -1,5 +1,7 @@
"""Casper Glow integration binary sensor platform."""
from typing import override
from pycasperglow import GlowState
from homeassistant.components.binary_sensor import (
@@ -43,6 +45,7 @@ class CasperGlowPausedBinarySensor(CasperGlowEntity, BinarySensorEntity):
if coordinator.device.state.is_paused is not None:
self._attr_is_on = coordinator.device.state.is_paused
@override
async def async_added_to_hass(self) -> None:
"""Register state update callback when entity is added."""
await super().async_added_to_hass()
@@ -71,6 +74,7 @@ class CasperGlowChargingBinarySensor(CasperGlowEntity, BinarySensorEntity):
if coordinator.device.state.is_charging is not None:
self._attr_is_on = coordinator.device.state.is_charging
@override
async def async_added_to_hass(self) -> None:
"""Register state update callback when entity is added."""
await super().async_added_to_hass()
@@ -2,6 +2,7 @@
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from typing import override
from pycasperglow import CasperGlow
@@ -66,6 +67,7 @@ class CasperGlowButton(CasperGlowEntity, ButtonEntity):
f"{format_mac(coordinator.device.address)}_{description.key}"
)
@override
async def async_press(self) -> None:
"""Press the button."""
await self._async_command(self.entity_description.press_fn(self._device))
@@ -1,7 +1,7 @@
"""Config flow for Casper Glow integration."""
import logging
from typing import Any
from typing import Any, override
from bluetooth_data_tools import human_readable_name
from pycasperglow import CasperGlow, CasperGlowError
@@ -31,6 +31,7 @@ class CasperGlowConfigFlow(ConfigFlow, domain=DOMAIN):
self._discovery_info: BluetoothServiceInfoBleak | None = None
self._discovered_devices: dict[str, BluetoothServiceInfoBleak] = {}
@override
async def async_step_bluetooth(
self, discovery_info: BluetoothServiceInfoBleak
) -> ConfigFlowResult:
@@ -73,6 +74,7 @@ class CasperGlowConfigFlow(ConfigFlow, domain=DOMAIN):
description_placeholders=self.context["title_placeholders"],
)
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -1,6 +1,7 @@
"""Coordinator for the Casper Glow integration."""
import logging
from typing import override
from bleak import BleakError
from bluetooth_data_tools import monotonic_time_coarse
@@ -74,6 +75,7 @@ class CasperGlowCoordinator(ActiveBluetoothDataUpdateCoordinator[None]):
"""Poll device state."""
await self.device.query_state()
@override
async def _async_poll(self) -> None:
"""Poll the device and log availability changes."""
assert self._last_service_info
@@ -99,6 +101,7 @@ class CasperGlowCoordinator(ActiveBluetoothDataUpdateCoordinator[None]):
self._async_handle_bluetooth_poll()
@override
@callback
def _async_handle_bluetooth_event(
self,
@@ -1,6 +1,6 @@
"""Casper Glow integration light platform."""
from typing import Any
from typing import Any, override
from pycasperglow import GlowState
@@ -54,6 +54,7 @@ class CasperGlowLight(CasperGlowEntity, LightEntity):
self._attr_unique_id = format_mac(coordinator.device.address)
self._update_from_state(coordinator.device.state)
@override
async def async_added_to_hass(self) -> None:
"""Register state update callback when entity is added."""
await super().async_added_to_hass()
@@ -77,6 +78,7 @@ class CasperGlowLight(CasperGlowEntity, LightEntity):
self._update_from_state(state)
self.async_write_ha_state()
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on."""
brightness_pct: int | None = None
@@ -98,6 +100,7 @@ class CasperGlowLight(CasperGlowEntity, LightEntity):
self._attr_brightness = _device_pct_to_ha_brightness(brightness_pct)
self.coordinator.last_brightness_pct = brightness_pct
@override
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the light off."""
await self._async_command(self._device.turn_off())
@@ -1,5 +1,7 @@
"""Casper Glow integration select platform for dimming time."""
from typing import override
from pycasperglow import GlowState
from homeassistant.components.select import SelectEntity
@@ -38,6 +40,7 @@ class CasperGlowDimmingTimeSelect(CasperGlowEntity, SelectEntity, RestoreEntity)
super().__init__(coordinator)
self._attr_unique_id = f"{format_mac(coordinator.device.address)}_dimming_time"
@override
@property
def current_option(self) -> str | None:
"""Return the currently selected dimming time from the coordinator."""
@@ -45,6 +48,7 @@ class CasperGlowDimmingTimeSelect(CasperGlowEntity, SelectEntity, RestoreEntity)
return None
return str(self.coordinator.last_dimming_time_minutes)
@override
async def async_added_to_hass(self) -> None:
"""Restore last known dimming time and register state update callback."""
await super().async_added_to_hass()
@@ -75,6 +79,7 @@ class CasperGlowDimmingTimeSelect(CasperGlowEntity, SelectEntity, RestoreEntity)
# to update the current state.
self.async_write_ha_state()
@override
async def async_select_option(self, option: str) -> None:
"""Set the dimming time."""
await self._async_command(
@@ -1,6 +1,7 @@
"""Casper Glow integration sensor platform."""
from datetime import datetime, timedelta
from typing import override
from pycasperglow import GlowState
@@ -51,6 +52,7 @@ class CasperGlowBatterySensor(CasperGlowEntity, SensorEntity):
if coordinator.device.state.battery_level is not None:
self._attr_native_value = coordinator.device.state.battery_level.percentage
@override
async def async_added_to_hass(self) -> None:
"""Register state update callback when entity is added."""
await super().async_added_to_hass()
@@ -93,6 +95,7 @@ class CasperGlowDimmingEndTimeSensor(CasperGlowEntity, SensorEntity):
"""Calculate projected dimming end time from remaining milliseconds."""
return utcnow() + timedelta(milliseconds=remaining_ms)
@override
async def async_added_to_hass(self) -> None:
"""Register state update callback when entity is added."""
await super().async_added_to_hass()
+4 -1
View File
@@ -1,6 +1,6 @@
"""Config flow for Cast."""
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, override
import voluptuous as vol
@@ -47,6 +47,7 @@ class FlowHandler(ConfigFlow, domain=DOMAIN):
VERSION = 1
@override
@staticmethod
@callback
def async_get_options_flow(
@@ -55,12 +56,14 @@ class FlowHandler(ConfigFlow, domain=DOMAIN):
"""Get the options flow for this handler."""
return CastOptionsFlowHandler()
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle a flow initialized by the user."""
return await self.async_step_config()
@override
async def async_step_zeroconf(
self, discovery_info: ZeroconfServiceInfo
) -> ConfigFlowResult:
+4 -1
View File
@@ -2,7 +2,7 @@
import logging
import threading
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, override
import pychromecast.discovery
import pychromecast.models
@@ -67,14 +67,17 @@ def setup_internal_discovery(
class CastListener(pychromecast.discovery.AbstractCastListener):
"""Listener for discovering chromecasts."""
@override
def add_cast(self, uuid, _):
"""Handle zeroconf discovery of a new chromecast."""
discover_chromecast(hass, browser.devices[uuid], config_entry)
@override
def update_cast(self, uuid, _):
"""Handle zeroconf discovery of an updated chromecast."""
discover_chromecast(hass, browser.devices[uuid], config_entry)
@override
def remove_cast(self, uuid, service, cast_info):
"""Handle zeroconf discovery of a removed chromecast."""
_remove_chromecast(
+9 -1
View File
@@ -3,7 +3,7 @@
import configparser
from dataclasses import dataclass
import logging
from typing import TYPE_CHECKING, ClassVar
from typing import TYPE_CHECKING, ClassVar, override
from urllib.parse import urlparse
from uuid import UUID
@@ -180,37 +180,45 @@ class CastStatusListener(
if not cast_device._cast_info.is_audio_group: # noqa: SLF001
self._mz_mgr.register_listener(chromecast.uuid, self)
@override
def new_cast_status(self, status):
"""Handle reception of a new CastStatus."""
if self._valid:
self._cast_device.new_cast_status(status)
@override
def new_media_status(self, status):
"""Handle reception of a new MediaStatus."""
if self._valid:
self._cast_device.new_media_status(status)
@override
def load_media_failed(self, queue_item_id, error_code):
"""Handle reception of a new MediaStatus."""
if self._valid:
self._cast_device.load_media_failed(queue_item_id, error_code)
@override
def new_connection_status(self, status):
"""Handle reception of a new ConnectionStatus."""
if self._valid:
self._cast_device.new_connection_status(status)
@override
def added_to_multizone(self, group_uuid):
"""Handle the cast added to a group."""
@override
def removed_from_multizone(self, group_uuid):
"""Handle the cast removed from a group."""
if self._valid:
self._cast_device.multizone_new_media_status(group_uuid, None)
@override
def multizone_new_cast_status(self, group_uuid, cast_status):
"""Handle reception of a new CastStatus for a group."""
@override
def multizone_new_media_status(self, group_uuid, media_status):
"""Handle reception of a new MediaStatus for a group."""
if self._valid:
+37 -1
View File
@@ -6,7 +6,7 @@ from datetime import datetime
from functools import wraps
import json
import logging
from typing import TYPE_CHECKING, Any, Concatenate
from typing import TYPE_CHECKING, Any, Concatenate, override
import pychromecast.config
import pychromecast.const
@@ -338,6 +338,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
]:
self._attr_device_class = MediaPlayerDeviceClass.SPEAKER
@override
async def async_added_to_hass(self) -> None:
"""Create chromecast object when added to hass."""
self._async_setup(self.entity_id)
@@ -346,6 +347,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
self.hass, SIGNAL_HASS_CAST_SHOW_VIEW, self._handle_signal_show_view
)
@override
async def async_will_remove_from_hass(self) -> None:
"""Disconnect Chromecast object when removed."""
await self._async_tear_down()
@@ -354,6 +356,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
self._cast_view_remove_handler()
self._cast_view_remove_handler = None
@override
async def _async_connect_to_chromecast(self):
"""Set up the chromecast object."""
await super()._async_connect_to_chromecast()
@@ -363,6 +366,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
self.media_status = self._chromecast.media_controller.status
self.async_write_ha_state()
@override
async def _async_disconnect(self):
"""Disconnect Chromecast object if it is set."""
await super()._async_disconnect()
@@ -370,6 +374,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
self._attr_available = False
self.async_write_ha_state()
@override
def _invalidate(self):
"""Invalidate some attributes."""
super()._invalidate()
@@ -528,6 +533,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
"""Start an app."""
self._get_chromecast().start_app(app_id)
@override
def turn_on(self) -> None:
"""Turn on the cast device."""
@@ -547,51 +553,60 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
else:
self._start_app(pychromecast.config.APP_MEDIA_RECEIVER)
@override
@api_error
def turn_off(self) -> None:
"""Turn off the cast device."""
self._get_chromecast().quit_app()
@override
@api_error
def mute_volume(self, mute: bool) -> None:
"""Mute the volume."""
self._get_chromecast().set_volume_muted(mute)
@override
@api_error
def set_volume_level(self, volume: float) -> None:
"""Set volume level, range 0..1."""
self._get_chromecast().set_volume(volume)
@override
@api_error
def media_play(self) -> None:
"""Send play command."""
media_controller = self._media_controller()
media_controller.play()
@override
@api_error
def media_pause(self) -> None:
"""Send pause command."""
media_controller = self._media_controller()
media_controller.pause()
@override
@api_error
def media_stop(self) -> None:
"""Send stop command."""
media_controller = self._media_controller()
media_controller.stop()
@override
@api_error
def media_previous_track(self) -> None:
"""Send previous track command."""
media_controller = self._media_controller()
media_controller.queue_prev()
@override
@api_error
def media_next_track(self) -> None:
"""Send next track command."""
media_controller = self._media_controller()
media_controller.queue_next()
@override
@api_error
def media_seek(self, position: float) -> None:
"""Seek the media to a specific location."""
@@ -636,6 +651,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
children=sorted(children, key=lambda c: c.title),
)
@override
async def async_browse_media(
self,
media_content_type: MediaType | str | None = None,
@@ -675,6 +691,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
self.hass, media_content_id, content_filter=content_filter
)
@override
async def async_play_media(
self, media_type: MediaType | str, media_id: str, **kwargs: Any
) -> None:
@@ -816,6 +833,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
return (media_status, media_status_received)
@override
@property
def state(self) -> MediaPlayerState | None:
"""Return the state of the player."""
@@ -858,6 +876,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
return MediaPlayerState.IDLE
@override
@property
def media_content_id(self) -> str | None:
"""Content ID of current playing media."""
@@ -867,6 +886,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
media_status = self._media_status()[0]
return media_status.content_id if media_status else None
@override
@property
def media_content_type(self) -> MediaType | None:
"""Content type of current playing media."""
@@ -891,6 +911,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
return MediaType.VIDEO
@override
@property
def media_duration(self):
"""Duration of current playing media in seconds."""
@@ -900,6 +921,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
media_status = self._media_status()[0]
return media_status.duration if media_status else None
@override
@property
def media_image_url(self):
"""Image url of current playing media."""
@@ -910,64 +932,75 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
return images[0].url if images and images[0].url else None
@override
@property
def media_title(self):
"""Title of current playing media."""
media_status = self._media_status()[0]
return media_status.title if media_status else None
@override
@property
def media_artist(self):
"""Artist of current playing media (Music track only)."""
media_status = self._media_status()[0]
return media_status.artist if media_status else None
@override
@property
def media_album_name(self):
"""Album of current playing media (Music track only)."""
media_status = self._media_status()[0]
return media_status.album_name if media_status else None
@override
@property
def media_album_artist(self):
"""Album artist of current playing media (Music track only)."""
media_status = self._media_status()[0]
return media_status.album_artist if media_status else None
@override
@property
def media_track(self):
"""Track number of current playing media (Music track only)."""
media_status = self._media_status()[0]
return media_status.track if media_status else None
@override
@property
def media_series_title(self):
"""Return the title of the series of current playing media."""
media_status = self._media_status()[0]
return media_status.series_title if media_status else None
@override
@property
def media_season(self):
"""Season of current playing media (TV Show only)."""
media_status = self._media_status()[0]
return media_status.season if media_status else None
@override
@property
def media_episode(self):
"""Episode of current playing media (TV Show only)."""
media_status = self._media_status()[0]
return media_status.episode if media_status else None
@override
@property
def app_id(self):
"""Return the ID of the current running app."""
return self._chromecast.app_id if self._chromecast else None
@override
@property
def app_name(self):
"""Name of the current running app."""
return self._chromecast.app_display_name if self._chromecast else None
@override
@property
def supported_features(self) -> MediaPlayerEntityFeature:
"""Flag media player features that are supported."""
@@ -1006,6 +1039,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
return support
@override
@property
def media_position(self):
"""Position of current playing media in seconds."""
@@ -1021,6 +1055,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
return None
return media_status.current_time
@override
@property
def media_position_updated_at(self):
"""When was the position of the current playing media valid.
@@ -1075,6 +1110,7 @@ class DynamicCastGroup(CastDevice):
"""Create chromecast object."""
self._async_setup("Dynamic group")
@override
async def _async_cast_removed(self, discover: ChromecastInfo):
"""Handle removal of Chromecast."""
if self._cast_info.uuid != discover.uuid:
+13 -1
View File
@@ -1,7 +1,7 @@
"""Climate device for CCM15 coordinator."""
import logging
from typing import Any
from typing import Any, override
from ccm15 import CCM15DeviceState, CCM15SlaveDevice
@@ -93,6 +93,7 @@ class CCM15Climate(CoordinatorEntity[CCM15Coordinator], ClimateEntity):
"""Return device data."""
return self.coordinator.get_ac_data(self._ac_index)
@override
@property
def current_temperature(self) -> int | None:
"""Return current temperature."""
@@ -100,6 +101,7 @@ class CCM15Climate(CoordinatorEntity[CCM15Coordinator], ClimateEntity):
return data.temperature
return None
@override
@property
def target_temperature(self) -> int | None:
"""Return target temperature."""
@@ -107,6 +109,7 @@ class CCM15Climate(CoordinatorEntity[CCM15Coordinator], ClimateEntity):
return data.temperature_setpoint
return None
@override
@property
def hvac_mode(self) -> HVACMode | None:
"""Return hvac mode."""
@@ -115,6 +118,7 @@ class CCM15Climate(CoordinatorEntity[CCM15Coordinator], ClimateEntity):
return CONST_CMD_STATE_MAP[mode]
return None
@override
@property
def fan_mode(self) -> str | None:
"""Return fan mode."""
@@ -123,6 +127,7 @@ class CCM15Climate(CoordinatorEntity[CCM15Coordinator], ClimateEntity):
return CONST_CMD_FAN_MAP[mode]
return None
@override
@property
def swing_mode(self) -> str | None:
"""Return swing mode."""
@@ -130,11 +135,13 @@ class CCM15Climate(CoordinatorEntity[CCM15Coordinator], ClimateEntity):
return SWING_ON if data.is_swing_on else SWING_OFF
return None
@override
@property
def available(self) -> bool:
"""Return the availability of the entity."""
return self.data is not None
@override
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the optional state attributes."""
@@ -142,6 +149,7 @@ class CCM15Climate(CoordinatorEntity[CCM15Coordinator], ClimateEntity):
return {"error_code": data.error_code}
return {}
@override
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set the target temperature."""
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is not None:
@@ -149,18 +157,22 @@ class CCM15Climate(CoordinatorEntity[CCM15Coordinator], ClimateEntity):
self._ac_index, self.data, temperature, kwargs.get(ATTR_HVAC_MODE)
)
@override
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set the hvac mode."""
await self.coordinator.async_set_hvac_mode(self._ac_index, self.data, hvac_mode)
@override
async def async_set_fan_mode(self, fan_mode: str) -> None:
"""Set the fan mode."""
await self.coordinator.async_set_fan_mode(self._ac_index, self.data, fan_mode)
@override
async def async_turn_off(self) -> None:
"""Turn off."""
await self.async_set_hvac_mode(HVACMode.OFF)
@override
async def async_turn_on(self) -> None:
"""Turn on."""
await self.async_set_hvac_mode(HVACMode.AUTO)
@@ -1,7 +1,7 @@
"""Config flow for Midea ccm15 AC Controller integration."""
import logging
from typing import Any
from typing import Any, override
from ccm15 import CCM15Device
import voluptuous as vol
@@ -27,6 +27,7 @@ class CCM15ConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 1
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -2,6 +2,7 @@
import datetime
import logging
from typing import override
from ccm15 import CCM15Device, CCM15DeviceState, CCM15SlaveDevice
import httpx
@@ -44,6 +45,7 @@ class CCM15Coordinator(DataUpdateCoordinator[CCM15DeviceState]):
"""Get the host."""
return self._host
@override
async def _async_update_data(self) -> CCM15DeviceState:
"""Fetch data from Rain Bird device."""
try:
@@ -1,7 +1,7 @@
"""Config flow for the CentriConnect/MyPropane API integration."""
import logging
from typing import Any
from typing import Any, override
from aiocentriconnect import CentriConnect
from aiocentriconnect.exceptions import (
@@ -58,6 +58,7 @@ class CentriConnectConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 1
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -6,6 +6,7 @@ Responsible for polling the device API endpoint and normalizing data for entitie
from dataclasses import dataclass
from datetime import timedelta
import logging
from typing import override
from aiocentriconnect import CentriConnect, Tank
from aiocentriconnect.exceptions import CentriConnectConnectionError, CentriConnectError
@@ -65,6 +66,7 @@ class CentriConnectCoordinator(DataUpdateCoordinator[Tank]):
session=async_get_clientsession(hass),
)
@override
async def _async_setup(self) -> None:
try:
tank_data = await self.api_client.async_get_tank_data()
@@ -79,6 +81,7 @@ class CentriConnectCoordinator(DataUpdateCoordinator[Tank]):
tank_size_unit=tank_data.tank_size_unit,
)
@override
async def _async_update_data(self) -> Tank:
"""Fetch device state."""
try:
@@ -4,6 +4,7 @@ from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime
from enum import StrEnum
from typing import override
from homeassistant.components.sensor import (
EntityCategory,
@@ -236,6 +237,7 @@ class CentriConnectSensor(CentriConnectBaseEntity, SensorEntity):
entity_description: CentriConnectSensorEntityDescription
@override
@property
def native_value(self) -> StateType | datetime | None:
"""Return the state of the sensor."""
@@ -1,7 +1,7 @@
"""Config flow for the Cert Expiry platform."""
from collections.abc import Mapping
from typing import Any
from typing import Any, override
import voluptuous as vol
@@ -53,6 +53,7 @@ class CertexpiryConfigFlow(ConfigFlow, domain=DOMAIN):
return True
return False
@override
async def async_step_user(
self,
user_input: Mapping[str, Any] | None = None,
@@ -2,6 +2,7 @@
from datetime import datetime, timedelta
import logging
from typing import override
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
@@ -46,6 +47,7 @@ class CertExpiryDataUpdateCoordinator(DataUpdateCoordinator[datetime | None]):
always_update=False,
)
@override
async def _async_update_data(self) -> datetime | None:
"""Fetch certificate."""
try:
@@ -1,6 +1,6 @@
"""Counter for the days until an HTTPS (TLS) certificate will expire."""
from typing import Any
from typing import Any, override
from homeassistant.helpers.update_coordinator import CoordinatorEntity
@@ -12,6 +12,7 @@ class CertExpiryEntity(CoordinatorEntity[CertExpiryDataUpdateCoordinator]):
_attr_has_entity_name = True
@override
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return additional sensor state attributes."""
@@ -1,6 +1,7 @@
"""Counter for the days until an HTTPS (TLS) certificate will expire."""
from datetime import datetime
from typing import override
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity
from homeassistant.core import HomeAssistant
@@ -44,6 +45,7 @@ class SSLCertificateTimestamp(CertExpiryEntity, SensorEntity):
entry_type=DeviceEntryType.SERVICE,
)
@override
@property
def native_value(self) -> datetime | None:
"""Return the state of the sensor."""
@@ -1,7 +1,7 @@
"""Config flow for chacon_dio integration."""
import logging
from typing import Any
from typing import Any, override
from dio_chacon_wifi_api import DIOChaconAPIClient
from dio_chacon_wifi_api.exceptions import DIOChaconAPIError, DIOChaconInvalidAuthError
@@ -25,6 +25,7 @@ DATA_SCHEMA = vol.Schema(
class ChaconDioConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for chacon_dio."""
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
+6 -1
View File
@@ -1,7 +1,7 @@
"""Cover Platform for Chacon Dio REV-SHUTTER devices."""
import logging
from typing import Any
from typing import Any, override
from dio_chacon_wifi_api.const import DeviceTypeEnum, ShutterMoveEnum
@@ -49,6 +49,7 @@ class ChaconDioCover(ChaconDioEntity, CoverEntity):
| CoverEntityFeature.SET_POSITION
)
@override
def _update_attr(self, data: dict[str, Any]) -> None:
"""Recompute the attribute values on init or state change."""
self._attr_available = data["connected"]
@@ -57,6 +58,7 @@ class ChaconDioCover(ChaconDioEntity, CoverEntity):
self._attr_is_opening = data["movement"] == ShutterMoveEnum.UP.value
self._attr_is_closed = self._attr_current_cover_position == 0
@override
async def async_close_cover(self, **kwargs: Any) -> None:
"""Close the cover.
@@ -80,6 +82,7 @@ class ChaconDioCover(ChaconDioEntity, CoverEntity):
self.target_id, ShutterMoveEnum.DOWN
)
@override
async def async_open_cover(self, **kwargs: Any) -> None:
"""Open the cover.
@@ -101,6 +104,7 @@ class ChaconDioCover(ChaconDioEntity, CoverEntity):
await self.client.move_shutter_direction(self.target_id, ShutterMoveEnum.UP)
@override
async def async_stop_cover(self, **kwargs: Any) -> None:
"""Stop the cover."""
@@ -112,6 +116,7 @@ class ChaconDioCover(ChaconDioEntity, CoverEntity):
await self.client.move_shutter_direction(self.target_id, ShutterMoveEnum.STOP)
@override
async def async_set_cover_position(self, **kwargs: Any) -> None:
"""Set the cover open position in percentage.
@@ -1,7 +1,7 @@
"""Base entity for the Chacon Dio entity."""
import logging
from typing import Any
from typing import Any, override
from dio_chacon_wifi_api import DIOChaconAPIClient
@@ -38,6 +38,7 @@ class ChaconDioEntity(Entity):
def _update_attr(self, data: dict[str, Any]) -> None:
"""Recomputes the attributes values."""
@override
async def async_added_to_hass(self) -> None:
"""Register the callback for server side events."""
await super().async_added_to_hass()
@@ -1,7 +1,7 @@
"""Switch Platform for Chacon Dio REV-LIGHT and switch plug devices."""
import logging
from typing import Any
from typing import Any, override
from dio_chacon_wifi_api.const import DeviceTypeEnum
@@ -38,11 +38,13 @@ class ChaconDioSwitch(ChaconDioEntity, SwitchEntity):
_attr_device_class = SwitchDeviceClass.SWITCH
_attr_name = None
@override
def _update_attr(self, data: dict[str, Any]) -> None:
"""Recompute the attribute values on init or state change."""
self._attr_available = data["connected"]
self._attr_is_on = data["is_on"]
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on the switch.
@@ -59,6 +61,7 @@ class ChaconDioSwitch(ChaconDioEntity, SwitchEntity):
await self.client.switch_switch(self.target_id, True)
@override
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the switch.
@@ -1,6 +1,6 @@
"""Support for interfacing with an instance of getchannels.com."""
from typing import Any
from typing import Any, override
from pychannels import Channels
import voluptuous as vol
@@ -138,11 +138,13 @@ class ChannelsPlayer(MediaPlayerEntity):
self.now_playing_summary = None
self.now_playing_image_url = None
@override
@property
def name(self):
"""Return the name of the player."""
return self._name
@override
@property
def state(self) -> MediaPlayerState | None:
"""Return the state of the player."""
@@ -162,21 +164,25 @@ class ChannelsPlayer(MediaPlayerEntity):
self.update_favorite_channels()
self.update_state(self.client.status())
@override
@property
def source_list(self):
"""List of favorite channels."""
return [channel["name"] for channel in self.favorite_channels]
@override
@property
def is_volume_muted(self):
"""Boolean if volume is currently muted."""
return self.muted
@override
@property
def media_content_id(self):
"""Content ID of current playing channel."""
return self.channel_number
@override
@property
def media_image_url(self):
"""Image url of current playing media."""
@@ -187,6 +193,7 @@ class ChannelsPlayer(MediaPlayerEntity):
return "https://getchannels.com/assets/img/icon-1024.png"
@override
@property
def media_title(self):
"""Title of current playing media."""
@@ -195,38 +202,45 @@ class ChannelsPlayer(MediaPlayerEntity):
return None
@override
def mute_volume(self, mute: bool) -> None:
"""Mute (true) or unmute (false) player."""
if mute != self.muted:
response = self.client.toggle_muted()
self.update_state(response)
@override
def media_stop(self) -> None:
"""Send media_stop command to player."""
self.status = "stopped"
response = self.client.stop()
self.update_state(response)
@override
def media_play(self) -> None:
"""Send media_play command to player."""
response = self.client.resume()
self.update_state(response)
@override
def media_pause(self) -> None:
"""Send media_pause command to player."""
response = self.client.pause()
self.update_state(response)
@override
def media_next_track(self) -> None:
"""Seek ahead."""
response = self.client.skip_forward()
self.update_state(response)
@override
def media_previous_track(self) -> None:
"""Seek back."""
response = self.client.skip_backward()
self.update_state(response)
@override
def select_source(self, source: str) -> None:
"""Select a channel to tune to."""
for channel in self.favorite_channels:
@@ -235,6 +249,7 @@ class ChannelsPlayer(MediaPlayerEntity):
self.update_state(response)
break
@override
def play_media(
self, media_type: MediaType | str, media_id: str, **kwargs: Any
) -> None:
@@ -1,7 +1,7 @@
"""Config flow for the Chess.com integration."""
import logging
from typing import Any
from typing import Any, override
from chess_com_api import ChessComClient, NotFoundError
import voluptuous as vol
@@ -18,6 +18,7 @@ _LOGGER = logging.getLogger(__name__)
class ChessConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Chess.com."""
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -3,6 +3,7 @@
from dataclasses import dataclass
from datetime import timedelta
import logging
from typing import override
from chess_com_api import ChessComAPIError, ChessComClient, Player, PlayerStats
@@ -45,6 +46,7 @@ class ChessCoordinator(DataUpdateCoordinator[ChessData]):
)
self.client = ChessComClient(session=async_get_clientsession(hass))
@override
async def _async_update_data(self) -> ChessData:
"""Update data from Chess.com."""
try:
+3 -1
View File
@@ -2,7 +2,7 @@
from collections.abc import Callable
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, override
from chess_com_api import PlayerStats
@@ -121,6 +121,7 @@ class ChessPlayerSensor(ChessEntity, SensorEntity):
self.entity_description = description
self._attr_unique_id = f"{coordinator.config_entry.unique_id}.{description.key}"
@override
@property
def native_value(self) -> float:
"""Return the state of the sensor."""
@@ -148,6 +149,7 @@ class ChessGameModeSensor(ChessEntity, SensorEntity):
)
self._attr_translation_key = f"{game_mode}_{description.translation_key}"
@override
@property
def native_value(self) -> float:
"""Return the state of the sensor."""
+27 -1
View File
@@ -2,7 +2,7 @@
import asyncio
from collections.abc import Callable, Coroutine
from typing import Any, Concatenate
from typing import Any, Concatenate, override
from cieloconnectapi.exceptions import AuthenticationError
@@ -103,6 +103,7 @@ class CieloClimate(CieloDeviceEntity, ClimateEntity):
super().__init__(coordinator, device_id)
self._attr_unique_id = device_id
@override
@property
def temperature_unit(self) -> str:
"""Return the unit of temperature in Home Assistant format.
@@ -124,6 +125,7 @@ class CieloClimate(CieloDeviceEntity, ClimateEntity):
return UnitOfTemperature.CELSIUS
@override
@property
def supported_features(self) -> ClimateEntityFeature:
"""Return dynamic feature flags based on the current mode."""
@@ -147,6 +149,7 @@ class CieloClimate(CieloDeviceEntity, ClimateEntity):
return flags
@override
@property
def current_humidity(self) -> int | None:
"""Return the current humidity, if available."""
@@ -154,58 +157,69 @@ class CieloClimate(CieloDeviceEntity, ClimateEntity):
return self.device_data.humidity
return None
@override
@property
def target_temperature_low(self) -> float | None:
"""Return the low target temperature for HEAT_COOL mode."""
return self.client.target_temperature_low(self.temperature_unit)
@override
@property
def target_temperature_high(self) -> float | None:
"""Return the high target temperature for HEAT_COOL mode."""
return self.client.target_temperature_high(self.temperature_unit)
@override
@property
def hvac_mode(self) -> HVACMode | None:
"""Return the current HVAC mode."""
mode = self.client.hvac_mode()
return CIELO_TO_HA_HVAC.get(mode, mode)
@override
@property
def hvac_modes(self) -> list[HVACMode]:
"""Return the list of available HVAC modes."""
modes = self.client.hvac_modes() or []
return [CIELO_TO_HA_HVAC.get(m, m) for m in modes]
@override
@property
def current_temperature(self) -> float | None:
"""Return the current indoor temperature."""
return self.client.current_temperature()
@override
@property
def target_temperature(self) -> float | None:
"""Return the target temperature."""
return self.client.target_temperature()
@override
@property
def min_temp(self) -> float:
"""Return the minimum possible target temperature."""
return self.client.min_temp()
@override
@property
def max_temp(self) -> float:
"""Return the maximum possible target temperature."""
return self.client.max_temp()
@override
@property
def target_temperature_step(self) -> float | None:
"""Return the precision of the thermostat."""
return self.client.target_temperature_step(self.temperature_unit)
@override
@property
def fan_mode(self) -> str | None:
"""Return the current fan mode."""
return self.client.fan_mode()
@override
@property
def fan_modes(self) -> list[str] | None:
"""Return the list of available fan modes.
@@ -217,6 +231,7 @@ class CieloClimate(CieloDeviceEntity, ClimateEntity):
"""
return self.client.fan_modes()
@override
@property
def swing_modes(self) -> list[str] | None:
"""Return the list of available swing modes.
@@ -228,11 +243,13 @@ class CieloClimate(CieloDeviceEntity, ClimateEntity):
"""
return self.client.swing_modes()
@override
@property
def preset_mode(self) -> str | None:
"""Return the current preset mode."""
return self.client.preset_mode()
@override
@property
def preset_modes(self) -> list[str] | None:
"""Return the list of available preset modes.
@@ -244,16 +261,19 @@ class CieloClimate(CieloDeviceEntity, ClimateEntity):
"""
return self.client.preset_modes()
@override
@property
def swing_mode(self) -> str | None:
"""Return the current swing mode."""
return self.device_data.swing_mode if self.device_data else None
@override
@property
def precision(self) -> float:
"""Return the precision of the thermostat."""
return self.client.precision(self.temperature_unit)
@override
@async_handle_api_call
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
@@ -270,27 +290,32 @@ class CieloClimate(CieloDeviceEntity, ClimateEntity):
**{ATTR_TEMPERATURE: kwargs.get(ATTR_TEMPERATURE)},
)
@override
@async_handle_api_call
async def async_set_fan_mode(self, fan_mode: str) -> None:
"""Set new fan mode."""
return await self.client.async_set_fan_mode(fan_mode)
@override
@async_handle_api_call
async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set new preset mode."""
return await self.client.async_set_preset_mode(preset_mode)
@override
@async_handle_api_call
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new HVAC mode."""
cielo_mode = HA_TO_CIELO_HVAC.get(hvac_mode)
return await self.client.async_set_hvac_mode(cielo_mode)
@override
@async_handle_api_call
async def async_set_swing_mode(self, swing_mode: str) -> None:
"""Set new swing mode."""
return await self.client.async_set_swing_mode(swing_mode)
@override
async def async_turn_on(self) -> None:
"""Turn the climate device on."""
modes = self.hvac_modes or []
@@ -303,6 +328,7 @@ class CieloClimate(CieloDeviceEntity, ClimateEntity):
raise HomeAssistantError("No non-off HVAC modes available to turn on device")
@override
async def async_turn_off(self) -> None:
"""Turn the climate device off."""
await self.async_set_hvac_mode(HVACMode.OFF)
@@ -1,6 +1,6 @@
"""Config Flow for Cielo integration."""
from typing import Any, Final
from typing import Any, Final, override
from aiohttp import ClientError
from cieloconnectapi import CieloClient
@@ -61,6 +61,7 @@ class CieloConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return client.user_id, {CONF_TOKEN: token}
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -3,7 +3,7 @@
from copy import copy
from dataclasses import dataclass
from datetime import timedelta
from typing import Any, Final
from typing import Any, Final, override
from aiohttp import ClientError
from cieloconnectapi import CieloClient
@@ -59,6 +59,7 @@ class CieloDataUpdateCoordinator(DataUpdateCoordinator[CieloData]):
),
)
@override
async def _async_update_data(self) -> CieloData:
"""Fetch data from the API."""
try:
@@ -1,5 +1,7 @@
"""Base entity for Cielo integration."""
from typing import override
from cieloconnectapi.device import CieloDeviceAPI
from cieloconnectapi.model import CieloDevice
@@ -31,6 +33,7 @@ class CieloBaseEntity(CoordinatorEntity[CieloDataUpdateCoordinator]):
coordinator.client, coordinator.data.parsed[device_id]
)
@override
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
if (dev := self.device_data) is not None:
@@ -42,6 +45,7 @@ class CieloBaseEntity(CoordinatorEntity[CieloDataUpdateCoordinator]):
"""Return the device data from the coordinator."""
return self.coordinator.data.parsed.get(self._device_id)
@override
@property
def available(self) -> bool:
"""Return if the device is available and online."""
@@ -1,6 +1,7 @@
"""Support for Cisco IOS Routers."""
import logging
from typing import override
from pexpect import pxssh
import voluptuous as vol
@@ -50,10 +51,12 @@ class CiscoDeviceScanner(DeviceScanner):
self.success_init = self._update_info()
@override
async def async_get_device_name(self, device: str) -> str | None:
"""Get the firmware doesn't save the name of the wireless device."""
return None
@override
def scan_devices(self):
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
@@ -1,6 +1,7 @@
"""Support for Cisco Mobility Express."""
import logging
from typing import override
from ciscomobilityexpress.ciscome import CiscoMobilityExpress
import voluptuous as vol
@@ -62,12 +63,14 @@ class CiscoMEDeviceScanner(DeviceScanner):
self.controller = controller
self.last_results = {}
@override
def scan_devices(self):
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
return [device.macaddr for device in self.last_results]
@override
def get_device_name(self, device):
"""Return the name of the given device or None if we don't know."""
return next(
@@ -75,6 +78,7 @@ class CiscoMEDeviceScanner(DeviceScanner):
None,
)
@override
def get_extra_attributes(self, device):
"""Get extra attributes of a device.
@@ -1,7 +1,7 @@
"""Cisco Webex notify component."""
import logging
from typing import Any
from typing import Any, override
import voluptuous as vol
from webexpythonsdk import ApiError, WebexAPI, exceptions
@@ -50,6 +50,7 @@ class CiscoWebexNotificationService(BaseNotificationService):
self.room = room
self.client = client
@override
def send_message(self, message: str = "", **kwargs: Any) -> None:
"""Send a message to a user."""
@@ -2,6 +2,7 @@
from datetime import timedelta
import time
from typing import override
from clementineremote import ClementineRemote
import voluptuous as vol
@@ -108,6 +109,7 @@ class ClementineDevice(MediaPlayerEntity):
self._attr_state = MediaPlayerState.OFF
raise
@override
def select_source(self, source: str) -> None:
"""Select input source."""
client = self._client
@@ -115,6 +117,7 @@ class ClementineDevice(MediaPlayerEntity):
if len(sources) == 1:
client.change_song(sources[0]["id"], 0)
@override
async def async_get_media_image(self) -> tuple[bytes | None, str | None]:
"""Fetch media image of current playing image."""
if self._client.current_track:
@@ -123,10 +126,12 @@ class ClementineDevice(MediaPlayerEntity):
return None, None
@override
def mute_volume(self, mute: bool) -> None:
"""Send mute command."""
self._client.set_volume(0)
@override
def set_volume_level(self, volume: float) -> None:
"""Set volume level."""
self._client.set_volume(int(100 * volume))
@@ -138,20 +143,24 @@ class ClementineDevice(MediaPlayerEntity):
else:
self.media_play()
@override
def media_play(self) -> None:
"""Send play command."""
self._attr_state = MediaPlayerState.PLAYING
self._client.play()
@override
def media_pause(self) -> None:
"""Send media pause command to media player."""
self._attr_state = MediaPlayerState.PAUSED
self._client.pause()
@override
def media_next_track(self) -> None:
"""Send next track command."""
self._client.next()
@override
def media_previous_track(self) -> None:
"""Send the previous track command."""
self._client.previous()
@@ -2,7 +2,7 @@
from http import HTTPStatus
import logging
from typing import Any
from typing import Any, override
import requests
import voluptuous as vol
@@ -44,6 +44,7 @@ class ClickatellNotificationService(BaseNotificationService):
self.api_key: str = config[CONF_API_KEY]
self.recipient: str = config[CONF_RECIPIENT]
@override
def send_message(self, message: str = "", **kwargs: Any) -> None:
"""Send a message to a user."""
data = {"apiKey": self.api_key, "to": self.recipient, "content": message}
+2 -1
View File
@@ -3,7 +3,7 @@
from http import HTTPStatus
import json
import logging
from typing import Any
from typing import Any, override
import requests
import voluptuous as vol
@@ -64,6 +64,7 @@ class ClicksendNotificationService(BaseNotificationService):
self.recipients: list[str] = config[CONF_RECIPIENT]
self.sender: str = config[CONF_SENDER]
@override
def send_message(self, message: str = "", **kwargs: Any) -> None:
"""Send a message to a user."""
data: dict[str, Any] = {"messages": []}
@@ -3,7 +3,7 @@
from http import HTTPStatus
import json
import logging
from typing import Any
from typing import Any, override
import requests
import voluptuous as vol
@@ -81,6 +81,7 @@ class ClicksendNotificationService(BaseNotificationService):
self.language = config[CONF_LANGUAGE]
self.voice = config[CONF_VOICE]
@override
def send_message(self, message: str = "", **kwargs: Any) -> None:
"""Send a voice call to a user."""
data = {
+5 -1
View File
@@ -3,7 +3,7 @@
from datetime import timedelta
import functools as ft
import logging
from typing import Any, Literal, final
from typing import Any, Literal, final, override
from propcache.api import cached_property
import voluptuous as vol
@@ -283,6 +283,7 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
_attr_target_temperature: float | None = None
_attr_temperature_unit: str
@override
@final
@property
def state(self) -> str | None:
@@ -304,6 +305,7 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
return PRECISION_TENTHS
return PRECISION_WHOLE
@override
@property
def capability_attributes(self) -> dict[str, Any] | None:
"""Return the capability attributes."""
@@ -342,6 +344,7 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
return data
@override
@final
@property
def state_attributes(self) -> dict[str, Any]:
@@ -700,6 +703,7 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
else:
await self.async_turn_off()
@override
@cached_property
def supported_features(self) -> ClimateEntityFeature:
"""Return the list of supported features."""
@@ -1,6 +1,6 @@
"""Provides conditions for climates."""
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, override
import voluptuous as vol
@@ -47,6 +47,7 @@ class ClimateHVACModeCondition(EntityConditionBase):
assert config.options is not None
self._hvac_modes: set[str] = set(config.options[CONF_HVAC_MODE])
@override
def is_valid_state(self, entity_state: State) -> bool:
"""Check if the state matches any of the expected HVAC modes."""
return entity_state.state in self._hvac_modes
@@ -59,6 +60,7 @@ class ClimateTargetTemperatureCondition(EntityNumericalConditionWithUnitBase):
_domain_specs = {DOMAIN: DomainSpec(value_source=ATTR_TEMPERATURE)}
_unit_converter = TemperatureConverter
@override
def _should_include(self, state: State) -> bool:
"""Skip climate entities that do not expose a target temperature."""
return (
@@ -66,6 +68,7 @@ class ClimateTargetTemperatureCondition(EntityNumericalConditionWithUnitBase):
and state.attributes.get(ATTR_TEMPERATURE) is not None
)
@override
def _get_entity_unit(self, entity_state: State) -> str | None:
"""Get the temperature unit of a climate entity from its state."""
# Climate entities convert temperatures to the system unit via show_temp
@@ -78,6 +81,7 @@ class ClimateTargetHumidityCondition(EntityNumericalConditionBase):
_domain_specs = {DOMAIN: DomainSpec(value_source=ATTR_HUMIDITY)}
_valid_unit = "%"
@override
def _should_include(self, state: State) -> bool:
"""Skip climate entities that do not expose a target humidity."""
return (
@@ -1,5 +1,7 @@
"""Intents for the climate integration."""
from typing import override
import voluptuous as vol
from homeassistant.const import ATTR_ENTITY_ID
@@ -35,6 +37,7 @@ class SetTemperatureIntent(intent.IntentHandler):
}
platforms = {DOMAIN}
@override
async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse:
"""Handle the intent."""
hass = intent_obj.hass
@@ -1,5 +1,7 @@
"""Provides triggers for climates."""
from typing import override
import voluptuous as vol
from homeassistant.const import ATTR_TEMPERATURE, CONF_OPTIONS, UnitOfTemperature
@@ -56,6 +58,7 @@ class _ClimateTargetTemperatureTriggerMixin(EntityNumericalStateTriggerWithUnitB
_domain_specs = {DOMAIN: DomainSpec(value_source=ATTR_TEMPERATURE)}
_unit_converter = TemperatureConverter
@override
def _should_include(self, state: State) -> bool:
"""Skip climate entities that do not expose a target temperature."""
return (
@@ -63,6 +66,7 @@ class _ClimateTargetTemperatureTriggerMixin(EntityNumericalStateTriggerWithUnitB
and state.attributes.get(ATTR_TEMPERATURE) is not None
)
@override
def _get_entity_unit(self, state: State) -> str | None:
"""Get the temperature unit of a climate entity from its state."""
# Climate entities convert temperatures to the system unit via show_temp
@@ -89,6 +93,7 @@ class _ClimateTargetHumidityTriggerMixin(EntityNumericalStateTriggerBase):
_domain_specs = {DOMAIN: DomainSpec(value_source=ATTR_HUMIDITY)}
_valid_unit = "%"
@override
def _should_include(self, state: State) -> bool:
"""Skip climate entities that do not expose a target humidity."""
return (
@@ -2,7 +2,7 @@
from datetime import datetime
import logging
from typing import Any
from typing import Any, override
import aiohttp
from awesomeversion import AwesomeVersion
@@ -95,16 +95,19 @@ class CloudOAuth2Implementation(config_entry_oauth2_flow.AbstractOAuth2Implement
self.hass = hass
self.service = service
@override
@property
def name(self) -> str:
"""Name of the implementation."""
return "Home Assistant Cloud"
@override
@property
def domain(self) -> str:
"""Domain that is providing the implementation."""
return DOMAIN
@override
async def async_generate_authorize_url(self, flow_id: str) -> str:
"""Generate a url for the user to authorize."""
helper = account_link.AuthorizeAccountHelper(
@@ -138,12 +141,14 @@ class CloudOAuth2Implementation(config_entry_oauth2_flow.AbstractOAuth2Implement
return authorize_url
@override
async def async_resolve_external_data(self, external_data: Any) -> dict:
"""Resolve external data to tokens."""
# We already passed in tokens
dict_data: dict = external_data
return dict_data
@override
async def _async_refresh_token(self, token: dict) -> dict:
"""Refresh a token."""
new_token = await account_link.async_fetch_access_token(
@@ -3,6 +3,7 @@
import io
from json import JSONDecodeError
import logging
from typing import override
from hass_nabucasa.llm import (
LLMAuthenticationError,
@@ -108,11 +109,13 @@ class CloudAITaskEntity(BaseCloudLLMEntity, ai_task.AITaskEntity):
_attr_translation_key = "cloud_ai"
_attr_unique_id = AI_TASK_ENTITY_UNIQUE_ID
@override
@property
def available(self) -> bool:
"""Return if the entity is available."""
return self._cloud.is_logged_in and self._cloud.valid_subscription
@override
async def _async_generate_data(
self,
task: ai_task.GenDataTask,
@@ -150,6 +153,7 @@ class CloudAITaskEntity(BaseCloudLLMEntity, ai_task.AITaskEntity):
data=data,
)
@override
async def _async_generate_image(
self,
task: ai_task.GenImageTask,
+11 -1
View File
@@ -5,7 +5,7 @@ from collections.abc import Callable
from contextlib import suppress
from datetime import datetime, timedelta
import logging
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, override
import aiohttp
from hass_nabucasa import AlexaApiError, Cloud
@@ -162,11 +162,13 @@ class CloudAlexaConfig(alexa_config.AbstractConfig):
and self._prefs.alexa_enabled
)
@override
@property
def supports_auth(self) -> bool:
"""Return if config supports auth."""
return True
@override
@property
def should_report_state(self) -> bool:
"""Return if states should be proactively reported."""
@@ -176,6 +178,7 @@ class CloudAlexaConfig(alexa_config.AbstractConfig):
and self.authorized
)
@override
@property
def endpoint(self) -> str | URL | None:
"""Endpoint for report state."""
@@ -184,17 +187,20 @@ class CloudAlexaConfig(alexa_config.AbstractConfig):
return self._endpoint
@override
@property
def locale(self) -> str:
"""Return config locale."""
# Not clear how to determine locale atm.
return "en-US"
@override
@property
def entity_config(self) -> dict[str, Any]:
"""Return entity config."""
return self._config.get(CONF_ENTITY_CONFIG) or {}
@override
@callback
def user_identifier(self) -> str:
"""Return an identifier for the user that represents this config."""
@@ -217,6 +223,7 @@ class CloudAlexaConfig(alexa_config.AbstractConfig):
self._should_expose_legacy(entity_id),
)
@override
async def async_initialize(self) -> None:
"""Initialize the Alexa config."""
await super().async_initialize()
@@ -299,6 +306,7 @@ class CloudAlexaConfig(alexa_config.AbstractConfig):
and entity_supported(self.hass, entity_id)
)
@override
@callback
def should_expose(self, entity_id: str) -> bool:
"""If an entity should be exposed."""
@@ -308,11 +316,13 @@ class CloudAlexaConfig(alexa_config.AbstractConfig):
return async_should_expose(self.hass, CLOUD_ALEXA, entity_id)
@override
@callback
def async_invalidate_access_token(self) -> None:
"""Invalidate access token."""
self._token_valid = None
@override
async def async_get_access_token(self) -> str | None:
"""Get an access token."""
details: AlexaAccessTokenDetails | None
+6 -1
View File
@@ -5,7 +5,7 @@ from collections.abc import AsyncIterator, Callable, Coroutine, Mapping
from http import HTTPStatus
import logging
import random
from typing import Any
from typing import Any, override
from aiohttp import ClientError, ClientResponseError
from hass_nabucasa import Cloud, CloudApiError, CloudApiNonRetryableError, CloudError
@@ -79,6 +79,7 @@ class CloudBackupAgent(BackupAgent):
self._cloud = cloud
self._hass = hass
@override
async def async_download_backup(
self,
backup_id: str,
@@ -100,6 +101,7 @@ class CloudBackupAgent(BackupAgent):
return ChunkAsyncStreamIterator(content)
@override
async def async_upload_backup(
self,
*,
@@ -170,6 +172,7 @@ class CloudBackupAgent(BackupAgent):
)
await asyncio.sleep(retry_timer)
@override
async def async_delete_backup(
self,
backup_id: str,
@@ -188,6 +191,7 @@ class CloudBackupAgent(BackupAgent):
except (ClientError, CloudError) as err:
raise BackupAgentError("Failed to delete backup") from err
@override
async def async_list_backups(self, **kwargs: Any) -> list[AgentBackup]:
"""List backups."""
backups = await self._async_list_backups()
@@ -203,6 +207,7 @@ class CloudBackupAgent(BackupAgent):
_LOGGER.debug("Cloud backups: %s", backups)
return backups
@override
async def async_get_backup(
self,
backup_id: str,
@@ -1,7 +1,7 @@
"""Support for Home Assistant Cloud binary sensors."""
import asyncio
from typing import Any
from typing import Any, override
from hass_nabucasa import Cloud
@@ -44,16 +44,19 @@ class CloudRemoteBinary(BinarySensorEntity):
"""Initialize the binary sensor."""
self.cloud = cloud
@override
@property
def is_on(self) -> bool:
"""Return true if the binary sensor is on."""
return self.cloud.remote.is_connected
@override
@property
def available(self) -> bool:
"""Return True if entity is available."""
return self.cloud.remote.certificate is not None
@override
async def async_added_to_hass(self) -> None:
"""Register update dispatcher."""
+24 -1
View File
@@ -6,7 +6,7 @@ from datetime import datetime
from http import HTTPStatus
import logging
from pathlib import Path
from typing import Any, Literal
from typing import Any, Literal, override
import aiohttp
from hass_nabucasa.client import CloudClient as Interface, RemoteActivationNotAllowed
@@ -71,6 +71,7 @@ class CloudClient(Interface):
self._cloud_ice_servers_listener: Callable[[], None] | None = None
self._ice_servers: list[RTCIceServer] = []
@override
@property
def base_path(self) -> Path:
"""Return path to base dir."""
@@ -81,31 +82,37 @@ class CloudClient(Interface):
"""Return Cloud preferences."""
return self._prefs
@override
@property
def loop(self) -> asyncio.AbstractEventLoop:
"""Return client loop."""
return self._hass.loop
@override
@property
def websession(self) -> aiohttp.ClientSession:
"""Return client session for aiohttp."""
return self._websession
@override
@property
def aiohttp_runner(self) -> aiohttp.web.AppRunner | None:
"""Return client webinterface aiohttp application."""
return self._hass.http.runner
@override
@property
def cloudhooks(self) -> dict[str, dict[str, str | bool]]:
"""Return list of cloudhooks."""
return self._prefs.cloudhooks
@override
@property
def remote_autostart(self) -> bool:
"""Return true if we want start a remote connection."""
return self._prefs.remote_enabled
@override
@property
def client_name(self) -> str:
"""Return the client name that will be used for API calls."""
@@ -165,6 +172,7 @@ class CloudClient(Interface):
return self._google_config
@override
async def cloud_connected(self) -> None:
"""When cloud is connected."""
_LOGGER.debug("cloud_connected")
@@ -258,18 +266,22 @@ class CloudClient(Interface):
if tasks:
await asyncio.gather(*(task(None) for task in tasks))
@override
async def cloud_disconnected(self) -> None:
"""When cloud disconnected."""
_LOGGER.debug("cloud_disconnected")
if self._google_config:
self._google_config.async_disable_local_sdk()
@override
async def cloud_started(self) -> None:
"""When cloud is started."""
@override
async def cloud_stopped(self) -> None:
"""When the cloud is stopped."""
@override
async def logout_cleanups(self) -> None:
"""Cleanup some stuff after logout."""
self._ice_servers = []
@@ -287,23 +299,27 @@ class CloudClient(Interface):
self._cloud_ice_servers_listener()
self._cloud_ice_servers_listener = None
@override
@callback
def user_message(self, identifier: str, title: str, message: str) -> None:
"""Create a message for user to UI."""
persistent_notification.async_create(self._hass, message, title, identifier)
@override
@callback
def dispatcher_message(self, identifier: str, data: Any = None) -> None:
"""Match cloud notification to dispatcher."""
if identifier.startswith("remote_"):
async_dispatcher_send(self._hass, DISPATCHER_REMOTE_UPDATE, data)
@override
async def async_cloud_connect_update(self, connect: bool) -> None:
"""Process cloud remote message to client."""
if not self._prefs.remote_allow_remote_enable:
raise RemoteActivationNotAllowed
await self._prefs.async_update(remote_enabled=connect)
@override
async def async_cloud_connection_info(
self, payload: dict[str, Any]
) -> dict[str, Any]:
@@ -321,6 +337,7 @@ class CloudClient(Interface):
"name": self._hass.config.location_name,
}
@override
async def async_alexa_message(self, payload: dict[Any, Any]) -> dict[Any, Any]:
"""Process cloud alexa message to client."""
cloud_user = await self._prefs.get_cloud_user()
@@ -333,6 +350,7 @@ class CloudClient(Interface):
enabled=self._prefs.alexa_enabled,
)
@override
async def async_google_message(self, payload: dict[Any, Any]) -> dict[Any, Any]:
"""Process cloud google message to client."""
gconf = await self.get_google_config()
@@ -356,6 +374,7 @@ class CloudClient(Interface):
google_assistant.SOURCE_CLOUD,
)
@override
async def async_webhook_message(self, payload: dict[Any, Any]) -> dict[Any, Any]:
"""Process cloud webhook message to client."""
cloudhook_id = payload["cloudhook_id"]
@@ -395,17 +414,20 @@ class CloudClient(Interface):
"headers": {"Content-Type": response.content_type},
}
@override
async def async_system_message(self, payload: dict[Any, Any] | None) -> None:
"""Handle system messages."""
if payload and (region := payload.get("region")):
self._relayer_region = region
@override
async def async_cloudhooks_update(
self, data: dict[str, dict[str, str | bool]]
) -> None:
"""Update local list of cloudhooks."""
await self._prefs.async_update(cloudhooks=data)
@override
async def async_create_repair_issue(
self,
identifier: str,
@@ -432,6 +454,7 @@ class CloudClient(Interface):
is_fixable=False,
)
@override
async def async_delete_repair_issue(self, identifier: str) -> None:
"""Delete a repair issue."""
async_delete_issue(hass=self._hass, domain=DOMAIN, issue_id=identifier)
@@ -1,6 +1,6 @@
"""Conversation support for Home Assistant Cloud."""
from typing import Literal
from typing import Literal, override
from homeassistant.components import conversation
from homeassistant.config_entries import ConfigEntry
@@ -35,16 +35,19 @@ class CloudConversationEntity(
_attr_unique_id = CONVERSATION_ENTITY_UNIQUE_ID
_attr_supported_features = conversation.ConversationEntityFeature.CONTROL
@override
@property
def available(self) -> bool:
"""Return if the entity is available."""
return self._cloud.is_logged_in and self._cloud.valid_subscription
@override
@property
def supported_languages(self) -> list[str] | Literal["*"]:
"""Return a list of supported languages."""
return MATCH_ALL
@override
async def _async_handle_message(
self,
user_input: conversation.ConversationInput,
@@ -3,7 +3,7 @@
import asyncio
from http import HTTPStatus
import logging
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, override
from hass_nabucasa import Cloud
from hass_nabucasa.google_report_state import ErrorResponse
@@ -145,6 +145,7 @@ class CloudGoogleConfig(AbstractConfig):
self._cloud = cloud
self._sync_entities_lock = asyncio.Lock()
@override
@property
def enabled(self) -> bool:
"""Return if Google is enabled."""
@@ -154,25 +155,30 @@ class CloudGoogleConfig(AbstractConfig):
and self._prefs.google_enabled
)
@override
@property
def entity_config(self) -> dict[str, Any]:
"""Return entity config."""
return self._config.get(CONF_ENTITY_CONFIG) or {}
@override
@property
def secure_devices_pin(self) -> str | None:
"""Return entity config."""
return self._prefs.google_secure_devices_pin
@override
@property
def should_report_state(self) -> bool:
"""Return if states should be proactively reported."""
return self.enabled and self._prefs.google_report_state
@override
def get_local_webhook_id(self, agent_user_id: Any) -> str:
"""Return the webhook ID for actions for an agent user id via the local SDK."""
return self._prefs.google_local_webhook_id
@override
def get_local_user_id(self, webhook_id: Any) -> str:
"""Map webhook ID to a Home Assistant user ID.
@@ -211,6 +217,7 @@ class CloudGoogleConfig(AbstractConfig):
_2fa_disabled,
)
@override
async def async_initialize(self) -> None:
"""Perform async initialization of config."""
_LOGGER.debug("async_initialize")
@@ -275,6 +282,7 @@ class CloudGoogleConfig(AbstractConfig):
)
)
@override
def should_expose(self, state: State) -> bool:
"""If a state object should be exposed."""
return self._should_expose_entity_id(state.entity_id)
@@ -326,10 +334,12 @@ class CloudGoogleConfig(AbstractConfig):
"""Return if we have a Agent User Id registered."""
return len(self.async_get_agent_users()) > 0
@override
def get_agent_user_id_from_context(self, context: Any) -> str:
"""Get agent user ID making request."""
return self.agent_user_id
@override
def get_agent_user_id_from_webhook(self, webhook_id: str) -> str | None:
"""Map webhook ID to a Google agent user ID.
@@ -346,6 +356,7 @@ class CloudGoogleConfig(AbstractConfig):
entity_config = entity_configs.get(entity_id, {})
return entity_config.get(PREF_DISABLE_2FA)
@override
def should_2fa(self, state: State) -> bool:
"""If an entity should be checked for 2FA."""
try:
@@ -357,6 +368,7 @@ class CloudGoogleConfig(AbstractConfig):
assistant_options = settings.get(CLOUD_GOOGLE, {})
return not assistant_options.get(PREF_DISABLE_2FA, DEFAULT_DISABLE_2FA)
@override
async def async_report_state(
self, message: Any, agent_user_id: str, event_id: str | None = None
) -> None:
@@ -366,6 +378,7 @@ class CloudGoogleConfig(AbstractConfig):
except ErrorResponse as err:
_LOGGER.warning("Error reporting state - %s: %s", err.code, err.message)
@override
async def _async_request_sync_devices(self, agent_user_id: str) -> HTTPStatus | int:
"""Trigger a sync with Google."""
if self._sync_entities_lock.locked():
@@ -375,6 +388,7 @@ class CloudGoogleConfig(AbstractConfig):
resp = await self._cloud.google_report_state.request_sync()
return resp.status
@override
async def async_connect_agent_user(self, agent_user_id: str) -> None:
"""Add a synced and known agent_user_id.
@@ -382,6 +396,7 @@ class CloudGoogleConfig(AbstractConfig):
"""
await self._prefs.async_update(google_connected=True)
@override
async def async_disconnect_agent_user(self, agent_user_id: str) -> None:
"""Turn off report state and disable further state reporting.
@@ -392,6 +407,7 @@ class CloudGoogleConfig(AbstractConfig):
"""
await self._prefs.async_update(google_connected=False)
@override
@callback
def async_get_agent_users(self) -> tuple:
"""Return known agent users."""
@@ -2,6 +2,7 @@
from collections import deque
import logging
from typing import override
from homeassistant.core import HomeAssistant
@@ -16,6 +17,7 @@ class FixedSizeQueueLogHandler(logging.Handler):
super().__init__()
self._records: deque[logging.LogRecord] = deque(maxlen=self.MAX_RECORDS)
@override
def emit(self, record: logging.LogRecord) -> None:
"""Store log message."""
self._records.append(record)
+4 -1
View File
@@ -2,7 +2,7 @@
from collections.abc import Callable, Coroutine
from functools import wraps
from typing import TYPE_CHECKING, Any, Concatenate
from typing import TYPE_CHECKING, Any, Concatenate, override
from aiohttp import web
from aiohttp.web_exceptions import HTTPUnauthorized
@@ -64,6 +64,7 @@ class CloudForgotPasswordView(
url = "/api/onboarding/cloud/forgot_password"
name = "api:onboarding:cloud:forgot_password"
@override
@ensure_not_done
async def post(self, request: web.Request) -> web.Response:
"""Handle forgot password request."""
@@ -76,6 +77,7 @@ class CloudLoginView(NoAuthBaseOnboardingView, cloud_http.CloudLoginView):
url = "/api/onboarding/cloud/login"
name = "api:onboarding:cloud:login"
@override
@ensure_not_done
async def post(self, request: web.Request) -> web.Response:
"""Handle login request."""
@@ -88,6 +90,7 @@ class CloudLogoutView(NoAuthBaseOnboardingView, cloud_http.CloudLogoutView):
url = "/api/onboarding/cloud/logout"
name = "api:onboarding:cloud:logout"
@override
@ensure_not_done
async def post(self, request: web.Request) -> web.Response:
"""Handle logout request."""
+2 -1
View File
@@ -1,7 +1,7 @@
"""Preference management for cloud."""
from collections.abc import Callable, Coroutine
from typing import Any
from typing import Any, override
import uuid
from hass_nabucasa.voice import MAP_VOICE, Gender
@@ -58,6 +58,7 @@ GOOGLE_SETTINGS_VERSION = 3
class CloudPreferencesStore(Store):
"""Store cloud preferences."""
@override
async def _async_migrate_func(
self, old_major_version: int, old_minor_version: int, old_data: dict[str, Any]
) -> dict[str, Any]:
+9
View File
@@ -2,6 +2,7 @@
from collections.abc import AsyncIterable
import logging
from typing import override
from hass_nabucasa import Cloud
from hass_nabucasa.voice import STT_LANGUAGES, VoiceError
@@ -52,36 +53,43 @@ class CloudProviderEntity(SpeechToTextEntity):
"""Initialize cloud Speech to text entity."""
self.cloud = cloud
@override
@property
def supported_languages(self) -> list[str]:
"""Return a list of supported languages."""
return STT_LANGUAGES
@override
@property
def supported_formats(self) -> list[AudioFormats]:
"""Return a list of supported formats."""
return [AudioFormats.WAV, AudioFormats.OGG]
@override
@property
def supported_codecs(self) -> list[AudioCodecs]:
"""Return a list of supported codecs."""
return [AudioCodecs.PCM, AudioCodecs.OPUS]
@override
@property
def supported_bit_rates(self) -> list[AudioBitRates]:
"""Return a list of supported bitrates."""
return [AudioBitRates.BITRATE_16]
@override
@property
def supported_sample_rates(self) -> list[AudioSampleRates]:
"""Return a list of supported samplerates."""
return [AudioSampleRates.SAMPLERATE_16000]
@override
@property
def supported_channels(self) -> list[AudioChannels]:
"""Return a list of supported channels."""
return [AudioChannels.CHANNEL_MONO]
@override
async def async_added_to_hass(self) -> None:
"""Run when entity is about to be added to hass."""
@@ -97,6 +105,7 @@ class CloudProviderEntity(SpeechToTextEntity):
async_when_setup(self.hass, "assist_pipeline", pipeline_setup)
@override
async def async_process_audio_stream(
self, metadata: SpeechMetadata, stream: AsyncIterable[bytes]
) -> SpeechResult:
+15 -1
View File
@@ -1,7 +1,7 @@
"""Support for the cloud for text-to-speech service."""
import logging
from typing import Any
from typing import Any, override
from hass_nabucasa import Cloud
from hass_nabucasa.voice import MAP_VOICE, AudioOutput, Gender, VoiceError
@@ -323,11 +323,13 @@ class CloudTTSEntity(TextToSpeechEntity):
"""Sync preferences."""
self._language, self._voice = prefs.tts_default_voice
@override
@property
def default_language(self) -> str:
"""Return the default language."""
return self._language
@override
@property
def default_options(self) -> dict[str, str]:
"""Return a dict include default options."""
@@ -335,17 +337,20 @@ class CloudTTSEntity(TextToSpeechEntity):
ATTR_AUDIO_OUTPUT: AudioOutput.MP3.value,
}
@override
@property
def supported_languages(self) -> list[str]:
"""Return list of supported languages."""
return SUPPORT_LANGUAGES
@override
@property
def supported_options(self) -> list[str]:
"""Return list of supported options like voice, emotion."""
# The gender option is deprecated and will be removed in 2024.10.0.
return [ATTR_GENDER, ATTR_VOICE, ATTR_AUDIO_OUTPUT]
@override
async def async_added_to_hass(self) -> None:
"""Handle entity which will be added."""
await super().async_added_to_hass()
@@ -366,6 +371,7 @@ class CloudTTSEntity(TextToSpeechEntity):
self.cloud.client.prefs.async_listen_updates(self._sync_prefs)
)
@override
@callback
def async_get_supported_voices(self, language: str) -> list[Voice] | None:
"""Return a list of supported voices for a language."""
@@ -404,6 +410,7 @@ class CloudTTSEntity(TextToSpeechEntity):
return result
@override
async def async_get_tts_audio(
self, message: str, language: str, options: dict[str, Any]
) -> TtsAudioType:
@@ -433,6 +440,7 @@ class CloudTTSEntity(TextToSpeechEntity):
return (options[ATTR_AUDIO_OUTPUT], data)
@override
async def async_stream_tts_audio(
self, request: TTSAudioRequest
) -> TTSAudioResponse:
@@ -473,22 +481,26 @@ class CloudProvider(Provider):
"""Sync preferences."""
self._language, self._voice = prefs.tts_default_voice
@override
@property
def default_language(self) -> str | None:
"""Return the default language."""
return self._language
@override
@property
def supported_languages(self) -> list[str]:
"""Return list of supported languages."""
return SUPPORT_LANGUAGES
@override
@property
def supported_options(self) -> list[str]:
"""Return list of supported options like voice, emotion."""
# The gender option is deprecated and will be removed in 2024.10.0.
return [ATTR_GENDER, ATTR_VOICE, ATTR_AUDIO_OUTPUT]
@override
@callback
def async_get_supported_voices(self, language: str) -> list[Voice] | None:
"""Return a list of supported voices for a language."""
@@ -527,6 +539,7 @@ class CloudProvider(Provider):
return result
@override
@property
def default_options(self) -> dict[str, str]:
"""Return a dict include default options."""
@@ -534,6 +547,7 @@ class CloudProvider(Provider):
ATTR_AUDIO_OUTPUT: AudioOutput.MP3,
}
@override
async def async_get_tts_audio(
self, message: str, language: str, options: dict[str, Any]
) -> TtsAudioType:
@@ -2,7 +2,7 @@
from collections.abc import Mapping
import logging
from typing import Any
from typing import Any, override
import pycfdns
import voluptuous as vol
@@ -111,6 +111,7 @@ class CloudflareConfigFlow(ConfigFlow, domain=DOMAIN):
errors=errors,
)
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -4,6 +4,7 @@ import asyncio
from datetime import timedelta
from logging import getLogger
import socket
from typing import override
import pycfdns
@@ -42,6 +43,7 @@ class CloudflareCoordinator(DataUpdateCoordinator[None]):
update_interval=timedelta(minutes=DEFAULT_UPDATE_INTERVAL),
)
@override
async def _async_setup(self) -> None:
"""Set up the coordinator."""
self.client = pycfdns.Client(
@@ -60,6 +62,7 @@ class CloudflareCoordinator(DataUpdateCoordinator[None]):
except pycfdns.ComunicationException as e:
raise UpdateFailed("Error communicating with API") from e
@override
async def _async_update_data(self) -> None:
"""Update records."""
_LOGGER.debug("Starting update for zone %s", self.zone["name"])
@@ -5,7 +5,7 @@ import functools
import json
import logging
from time import time
from typing import Any, cast
from typing import Any, cast, override
from botocore.exceptions import BotoCoreError
@@ -106,6 +106,7 @@ class R2BackupAgent(BackupAgent):
return key
return f"{self._prefix}/{key}"
@override
@handle_boto_errors
async def async_download_backup(
self,
@@ -125,6 +126,7 @@ class R2BackupAgent(BackupAgent):
)
return response["Body"].iter_chunks()
@override
async def async_upload_backup(
self,
*,
@@ -287,6 +289,7 @@ class R2BackupAgent(BackupAgent):
_LOGGER.exception("Failed to abort multipart upload")
raise
@override
@handle_boto_errors
async def async_delete_backup(
self,
@@ -311,12 +314,14 @@ class R2BackupAgent(BackupAgent):
# Reset cache after successful deletion
self._cache_expiration = time()
@override
@handle_boto_errors
async def async_list_backups(self, **kwargs: Any) -> list[AgentBackup]:
"""List backups."""
backups = await self._list_backups()
return list(backups.values())
@override
@handle_boto_errors
async def async_get_backup(
self,
@@ -1,6 +1,6 @@
"""Config flow for the Cloudflare R2 integration."""
from typing import Any
from typing import Any, override
from urllib.parse import urlparse
from aiobotocore.session import AioSession
@@ -50,6 +50,7 @@ STEP_USER_DATA_SCHEMA = vol.Schema(
class R2ConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Cloudflare R2."""
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
+11 -1
View File
@@ -1,7 +1,7 @@
"""Support for interacting with and controlling the cmus music player."""
import logging
from typing import Any
from typing import Any, override
from pycmus import exceptions, remote
import voluptuous as vol
@@ -140,14 +140,17 @@ class CmusDevice(MediaPlayerEntity):
_LOGGER.warning("Received no status from cmus")
@override
def turn_off(self) -> None:
"""Service to send the CMUS the command to stop playing."""
self._remote.cmus.player_stop()
@override
def turn_on(self) -> None:
"""Service to send the CMUS the command to start playing."""
self._remote.cmus.player_play()
@override
def set_volume_level(self, volume: float) -> None:
"""Set volume level, range 0..1."""
self._remote.cmus.set_volume(int(volume * 100))
@@ -176,6 +179,7 @@ class CmusDevice(MediaPlayerEntity):
if current_volume <= 100:
self._remote.cmus.set_volume(int(current_volume) - 5)
@override
def play_media(
self, media_type: MediaType | str, media_id: str, **kwargs: Any
) -> None:
@@ -190,26 +194,32 @@ class CmusDevice(MediaPlayerEntity):
MediaType.PLAYLIST,
)
@override
def media_pause(self) -> None:
"""Send the pause command."""
self._remote.cmus.player_pause()
@override
def media_next_track(self) -> None:
"""Send next track command."""
self._remote.cmus.player_next()
@override
def media_previous_track(self) -> None:
"""Send next track command."""
self._remote.cmus.player_prev()
@override
def media_seek(self, position: float) -> None:
"""Send seek command."""
self._remote.cmus.seek(position)
@override
def media_play(self) -> None:
"""Send the play command."""
self._remote.cmus.player_play()
@override
def media_stop(self) -> None:
"""Send the stop command."""
self._remote.cmus.stop()
@@ -2,7 +2,7 @@
from collections.abc import Mapping
import logging
from typing import Any
from typing import Any, override
from aioelectricitymaps import (
ElectricityMaps,
@@ -47,6 +47,7 @@ class ElectricityMapsConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 1
_data: dict | None
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -2,6 +2,7 @@
from datetime import timedelta
import logging
from typing import override
from aioelectricitymaps import (
ElectricityMaps,
@@ -49,6 +50,7 @@ class CO2SignalCoordinator(DataUpdateCoordinator[HomeAssistantCarbonIntensityRes
"""Return entry ID."""
return self.config_entry.entry_id
@override
async def _async_update_data(self) -> HomeAssistantCarbonIntensityResponse:
"""Fetch the latest data from the source."""
@@ -2,6 +2,7 @@
from collections.abc import Callable
from dataclasses import dataclass
from typing import override
from aioelectricitymaps import HomeAssistantCarbonIntensityResponse
@@ -90,11 +91,13 @@ class CO2Sensor(CoordinatorEntity[CO2SignalCoordinator], SensorEntity):
f"{coordinator.entry_id}_{description.unique_id or description.key}"
)
@override
@property
def native_value(self) -> float | None:
"""Return sensor state."""
return self.entity_description.value_fn(self.coordinator.data)
@override
@property
def native_unit_of_measurement(self) -> str | None:
"""Return the unit of measurement."""
@@ -2,7 +2,7 @@
from collections.abc import Mapping
import logging
from typing import Any
from typing import Any, override
from coinbase.rest import RESTClient
from coinbase.rest.rest_base import HTTPError
@@ -114,6 +114,7 @@ class CoinbaseConfigFlow(ConfigFlow, domain=DOMAIN):
reauth_entry: CoinbaseConfigEntry
@override
async def async_step_user(
self, user_input: dict[str, str] | None = None
) -> ConfigFlowResult:
@@ -199,6 +200,7 @@ class CoinbaseConfigFlow(ConfigFlow, domain=DOMAIN):
errors=errors,
)
@override
@staticmethod
@callback
def async_get_options_flow(
@@ -1,6 +1,7 @@
"""Support for Coinbase sensors."""
import logging
from typing import override
from homeassistant.components.sensor import SensorEntity, SensorStateClass
from homeassistant.core import HomeAssistant
@@ -153,6 +154,7 @@ class AccountSensor(SensorEntity):
name=f"Coinbase {self._coinbase_data.user_id[-4:]}",
)
@override
@property
def extra_state_attributes(self) -> dict[str, str]:
"""Return the state attributes of the sensor."""
@@ -1,6 +1,6 @@
"""Config flow to configure the Color extractor integration."""
from typing import Any
from typing import Any, override
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
@@ -12,6 +12,7 @@ class ColorExtractorConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 1
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -1,7 +1,7 @@
"""Support for Comelit VEDO system."""
import logging
from typing import TYPE_CHECKING, cast
from typing import TYPE_CHECKING, cast, override
from aiocomelit.api import ComelitVedoAreaObject
from aiocomelit.const import ALARM_AREA, AlarmAreaState
@@ -107,6 +107,7 @@ class ComelitAlarmEntity(
ComelitVedoAreaObject, self.coordinator.data[ALARM_AREA][self._area_index]
)
@override
@property
def available(self) -> bool:
"""Return True if alarm is available."""
@@ -114,6 +115,7 @@ class ComelitAlarmEntity(
return False
return super().available
@override
@property
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the alarm."""
@@ -144,6 +146,7 @@ class ComelitAlarmEntity(
self._area.armed = armed
self.async_write_ha_state()
@override
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
if code != str(self.coordinator.api.device_pin):
@@ -155,6 +158,7 @@ class ComelitAlarmEntity(
AlarmAreaState.DISARMED, ALARM_AREA_ARMED_STATUS[DISABLE]
)
@override
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
await self.coordinator.api.set_zone_status(
@@ -164,6 +168,7 @@ class ComelitAlarmEntity(
AlarmAreaState.ARMED, ALARM_AREA_ARMED_STATUS[AWAY]
)
@override
async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
await self.coordinator.api.set_zone_status(
@@ -173,6 +178,7 @@ class ComelitAlarmEntity(
AlarmAreaState.ARMED, ALARM_AREA_ARMED_STATUS[HOME_P1]
)
@override
async def async_alarm_arm_night(self, code: str | None = None) -> None:
"""Send arm night command."""
await self.coordinator.api.set_zone_status(
@@ -2,7 +2,7 @@
from collections.abc import Callable
from dataclasses import dataclass
from typing import TYPE_CHECKING, Final, cast
from typing import TYPE_CHECKING, Final, cast, override
from aiocomelit.api import ComelitVedoAreaObject, ComelitVedoZoneObject
from aiocomelit.const import ALARM_AREA, ALARM_ZONE, AlarmAreaState, AlarmZoneState
@@ -159,6 +159,7 @@ class ComelitVedoBinarySensorEntity(
self.coordinator.data[self._object_type][self._object_index],
)
@override
@property
def available(self) -> bool:
"""Return True if object is available."""
@@ -166,6 +167,7 @@ class ComelitVedoBinarySensorEntity(
return False
return super().available
@override
@property
def is_on(self) -> bool:
"""Return object binary sensor state."""
+5 -1
View File
@@ -1,7 +1,7 @@
"""Support for climates."""
from enum import StrEnum
from typing import Any, TypedDict, cast
from typing import Any, TypedDict, cast, override
from aiocomelit import ComelitSerialBridgeObject
from aiocomelit.const import CLIMATE
@@ -159,12 +159,14 @@ class ComelitClimateEntity(ComelitBridgeBaseEntity, ClimateEntity):
self._attr_target_temperature = values[4] / 10
@override
@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._update_attributes()
super()._handle_coordinator_update()
@override
@bridge_api_call
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
@@ -181,6 +183,7 @@ class ComelitClimateEntity(ComelitBridgeBaseEntity, ClimateEntity):
self._attr_target_temperature = target_temp
self.async_write_ha_state()
@override
@bridge_api_call
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set hvac mode."""
@@ -195,6 +198,7 @@ class ComelitClimateEntity(ComelitBridgeBaseEntity, ClimateEntity):
self._attr_hvac_mode = hvac_mode
self.async_write_ha_state()
@override
async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set new target preset mode."""
@@ -3,7 +3,7 @@
from asyncio.exceptions import TimeoutError
from collections.abc import Mapping
import re
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, override
from aiocomelit import (
ComeliteSerialBridgeApi,
@@ -93,6 +93,7 @@ class ComelitConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 1
MINOR_VERSION = 2
@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@@ -3,7 +3,7 @@
from abc import abstractmethod
from collections.abc import Mapping
from datetime import timedelta
from typing import TypeVar, cast
from typing import TypeVar, cast, override
from aiocomelit.api import ComelitCommonApi, ComeliteSerialBridgeApi, ComelitVedoApi
from aiocomelit.const import (
@@ -100,6 +100,7 @@ class ComelitBaseCoordinator(DataUpdateCoordinator[T]):
hw_version=self._hw_version,
)
@override
async def _async_update_data(self) -> T:
"""Update device data."""
_LOGGER.debug("Polling Comelit %s host: %s", self._device, self._host)
@@ -175,6 +176,7 @@ class ComelitSerialBridge(ComelitBaseCoordinator[T]):
self.vedo_pin = vedo_pin
super().__init__(hass, entry, BRIDGE, host)
@override
async def _async_update_system_data(
self,
) -> T:
@@ -218,6 +220,7 @@ class ComelitVedoSystem(ComelitBaseCoordinator[T]):
self.vedo_pin = pin
super().__init__(hass, entry, VEDO, host)
@override
async def _async_update_system_data(
self,
) -> T:
+8 -1
View File
@@ -1,6 +1,6 @@
"""Support for covers."""
from typing import Any, cast
from typing import Any, cast, override
from aiocomelit import ComelitSerialBridgeObject
from aiocomelit.const import COVER, STATE_COVER, STATE_OFF, STATE_ON
@@ -72,6 +72,7 @@ class ComelitCoverEntity(ComelitBridgeBaseEntity, RestoreEntity, CoverEntity):
"""Return current device status."""
return cast("int", self.coordinator.data[COVER][self._device.index].status)
@override
@property
def is_closed(self) -> bool | None:
"""Return if the cover is closed."""
@@ -81,11 +82,13 @@ class ComelitCoverEntity(ComelitBridgeBaseEntity, RestoreEntity, CoverEntity):
return None
@override
@property
def is_closing(self) -> bool:
"""Return if the cover is closing."""
return bool(self._current_action("closing"))
@override
@property
def is_opening(self) -> bool:
"""Return if the cover is opening."""
@@ -98,14 +101,17 @@ class ComelitCoverEntity(ComelitBridgeBaseEntity, RestoreEntity, CoverEntity):
self.coordinator.data[COVER][self._device.index].status = state
self.async_write_ha_state()
@override
async def async_close_cover(self, **kwargs: Any) -> None:
"""Close cover."""
await self._cover_set_state(STATE_OFF, 2)
@override
async def async_open_cover(self, **kwargs: Any) -> None:
"""Open cover."""
await self._cover_set_state(STATE_ON, 1)
@override
async def async_stop_cover(self, **_kwargs: Any) -> None:
"""Stop the cover."""
if not self.is_closing and not self.is_opening:
@@ -114,6 +120,7 @@ class ComelitCoverEntity(ComelitBridgeBaseEntity, RestoreEntity, CoverEntity):
action = STATE_ON if self.is_closing else STATE_OFF
await self._cover_set_state(action, 0)
@override
async def async_added_to_hass(self) -> None:
"""Handle entity which will be added."""
@@ -1,7 +1,7 @@
"""Support for humidifiers."""
from enum import StrEnum
from typing import Any, cast
from typing import Any, cast, override
from aiocomelit import ComelitSerialBridgeObject
from aiocomelit.const import CLIMATE
@@ -156,12 +156,14 @@ class ComelitHumidifierEntity(ComelitBridgeBaseEntity, HumidifierEntity):
self._attr_mode = MODE_AUTO if _automatic else MODE_NORMAL
self._attr_target_humidity = values[4] / 10
@override
@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._update_attributes()
super()._handle_coordinator_update()
@override
@bridge_api_call
async def async_set_humidity(self, humidity: int) -> None:
"""Set new target humidity."""
@@ -180,6 +182,7 @@ class ComelitHumidifierEntity(ComelitBridgeBaseEntity, HumidifierEntity):
self._attr_target_humidity = humidity
self.async_write_ha_state()
@override
@bridge_api_call
async def async_set_mode(self, mode: str) -> None:
"""Set humidifier mode."""
@@ -189,6 +192,7 @@ class ComelitHumidifierEntity(ComelitBridgeBaseEntity, HumidifierEntity):
self._attr_mode = mode
self.async_write_ha_state()
@override
@bridge_api_call
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on."""
@@ -198,6 +202,7 @@ class ComelitHumidifierEntity(ComelitBridgeBaseEntity, HumidifierEntity):
self._attr_is_on = True
self.async_write_ha_state()
@override
@bridge_api_call
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off."""
+4 -1
View File
@@ -1,6 +1,6 @@
"""Support for lights."""
from typing import Any, cast
from typing import Any, cast, override
from aiocomelit.const import LIGHT, STATE_OFF, STATE_ON
@@ -55,14 +55,17 @@ class ComelitLightEntity(ComelitBridgeBaseEntity, LightEntity):
self.coordinator.data[LIGHT][self._device.index].status = state
self.async_write_ha_state()
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on."""
await self._light_set_state(STATE_ON)
@override
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the light off."""
await self._light_set_state(STATE_OFF)
@override
@property
def is_on(self) -> bool:
"""Return True if light is on."""
+4 -1
View File
@@ -1,6 +1,6 @@
"""Support for sensors."""
from typing import TYPE_CHECKING, Final, cast
from typing import TYPE_CHECKING, Final, cast, override
from aiocomelit.api import ComelitSerialBridgeObject, ComelitVedoZoneObject
from aiocomelit.const import ALARM_ZONE, OTHER, AlarmZoneState
@@ -120,6 +120,7 @@ class ComelitBridgeSensorEntity(ComelitBridgeBaseEntity, SensorEntity):
self.entity_description = description
@override
@property
def native_value(self) -> StateType:
"""Sensor value."""
@@ -163,11 +164,13 @@ class ComelitVedoSensorEntity(
ComelitVedoZoneObject, self.coordinator.data[ALARM_ZONE][self._zone_index]
)
@override
@property
def available(self) -> bool:
"""Sensor availability."""
return self._zone_object.human_status is not AlarmZoneState.UNAVAILABLE
@override
@property
def native_value(self) -> StateType:
"""Sensor value."""
+4 -1
View File
@@ -1,6 +1,6 @@
"""Support for switches."""
from typing import Any, cast
from typing import Any, cast, override
from aiocomelit import ComelitSerialBridgeObject
from aiocomelit.const import IRRIGATION, OTHER, STATE_OFF, STATE_ON
@@ -69,14 +69,17 @@ class ComelitSwitchEntity(ComelitBridgeBaseEntity, SwitchEntity):
self.coordinator.data[self._device.type][self._device.index].status = state
self.async_write_ha_state()
@override
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the switch on."""
await self._switch_set_state(STATE_ON)
@override
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the switch off."""
await self._switch_set_state(STATE_OFF)
@override
@property
def is_on(self) -> bool:
"""Return True if switch is on."""
+8 -1
View File
@@ -2,7 +2,7 @@
import logging
import math
from typing import Any
from typing import Any, override
from pycomfoconnect import (
CMD_FAN_MODE_AWAY,
@@ -77,6 +77,7 @@ class ComfoConnectFan(FanEntity):
self._attr_unique_id = ccb.unique_id
self._attr_preset_mode = None
@override
async def async_added_to_hass(self) -> None:
"""Register for sensor updates."""
_LOGGER.debug("Registering for fan speed")
@@ -119,6 +120,7 @@ class ComfoConnectFan(FanEntity):
self._attr_preset_mode = PRESET_MODE_AUTO if value == -1 else None
self.schedule_update_ha_state()
@override
@property
def percentage(self) -> int | None:
"""Return the current speed percentage."""
@@ -126,11 +128,13 @@ class ComfoConnectFan(FanEntity):
return None
return ranged_value_to_percentage(SPEED_RANGE, self.current_speed)
@override
@property
def speed_count(self) -> int:
"""Return the number of speeds the fan supports."""
return int_states_in_range(SPEED_RANGE)
@override
def turn_on(
self,
percentage: int | None = None,
@@ -147,10 +151,12 @@ class ComfoConnectFan(FanEntity):
else:
self.set_percentage(percentage)
@override
def turn_off(self, **kwargs: Any) -> None:
"""Turn off the fan (to away)."""
self.set_percentage(0)
@override
def set_percentage(self, percentage: int) -> None:
"""Set fan speed percentage."""
_LOGGER.debug("Changing fan speed percentage to %s", percentage)
@@ -163,6 +169,7 @@ class ComfoConnectFan(FanEntity):
self._ccb.comfoconnect.cmd_rmi_request(cmd)
@override
def set_preset_mode(self, preset_mode: str) -> None:
"""Set new preset mode."""
if not self.preset_modes or preset_mode not in self.preset_modes:
@@ -2,6 +2,7 @@
from dataclasses import dataclass
import logging
from typing import override
from pycomfoconnect import (
SENSOR_BYPASS_STATE,
@@ -305,6 +306,7 @@ class ComfoConnectSensor(SensorEntity):
self._attr_name = f"{ccb.name} {description.name}"
self._attr_unique_id = f"{ccb.unique_id}-{description.key}"
@override
async def async_added_to_hass(self) -> None:
"""Register for sensor updates."""
_LOGGER.debug(

Some files were not shown because too many files have changed in this diff Show More