Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions homeassistant/components/lastfm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,30 @@

from __future__ import annotations

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant

from .const import DOMAIN, PLATFORMS
from .coordinator import LastFMDataUpdateCoordinator
from .const import PLATFORMS
from .coordinator import LastFMConfigEntry, LastFMDataUpdateCoordinator


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_setup_entry(hass: HomeAssistant, entry: LastFMConfigEntry) -> bool:
"""Set up lastfm from a config entry."""

coordinator = LastFMDataUpdateCoordinator(hass, entry)
await coordinator.async_config_entry_first_refresh()
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator
entry.runtime_data = coordinator

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
entry.async_on_unload(entry.add_update_listener(update_listener))

return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_unload_entry(hass: HomeAssistant, entry: LastFMConfigEntry) -> bool:
"""Unload lastfm config entry."""

return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)


async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
async def update_listener(hass: HomeAssistant, entry: LastFMConfigEntry) -> None:
"""Handle options update."""
await hass.config_entries.async_reload(entry.entry_id)
12 changes: 5 additions & 7 deletions homeassistant/components/lastfm/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@
from pylast import LastFMNetwork, PyLastError, User, WSError
import voluptuous as vol

from homeassistant.config_entries import (
ConfigEntry,
ConfigFlow,
ConfigFlowResult,
OptionsFlow,
)
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult, OptionsFlow
from homeassistant.const import CONF_API_KEY
from homeassistant.core import callback
from homeassistant.helpers.selector import (
Expand All @@ -23,6 +18,7 @@
)

from .const import CONF_MAIN_USER, CONF_USERS, DOMAIN
from .coordinator import LastFMConfigEntry

PLACEHOLDERS = {"api_account_url": "https://www.last.fm/api/account/create"}

Expand Down Expand Up @@ -81,7 +77,7 @@ class LastFmConfigFlowHandler(ConfigFlow, domain=DOMAIN):
@staticmethod
@callback
def async_get_options_flow(
config_entry: ConfigEntry,
config_entry: LastFMConfigEntry,
) -> LastFmOptionsFlowHandler:
"""Get the options flow for this handler."""
return LastFmOptionsFlowHandler()
Expand Down Expand Up @@ -162,6 +158,8 @@ async def async_step_friends(
class LastFmOptionsFlowHandler(OptionsFlow):
"""LastFm Options flow handler."""

config_entry: LastFMConfigEntry

async def async_step_init(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/lastfm/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

from .const import CONF_USERS, DOMAIN, LOGGER

type LastFMConfigEntry = ConfigEntry[LastFMDataUpdateCoordinator]


def format_track(track: Track | None) -> str | None:
"""Format the track."""
Expand Down
7 changes: 3 additions & 4 deletions homeassistant/components/lastfm/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from typing import Any

from homeassistant.components.sensor import SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
Expand All @@ -21,17 +20,17 @@
DOMAIN,
STATE_NOT_SCROBBLING,
)
from .coordinator import LastFMDataUpdateCoordinator, LastFMUserData
from .coordinator import LastFMConfigEntry, LastFMDataUpdateCoordinator, LastFMUserData


async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: LastFMConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Initialize the entries."""

coordinator: LastFMDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
coordinator = entry.runtime_data
async_add_entities(
(
LastFmSensor(coordinator, username, entry.entry_id)
Expand Down
5 changes: 0 additions & 5 deletions homeassistant/components/rachio/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@
from homeassistant.util import dt as dt_util

from .const import (
KEY_ADDRESS,
KEY_DURATION_SECONDS,
KEY_ID,
KEY_LOCALITY,
KEY_PROGRAM_ID,
KEY_PROGRAM_NAME,
KEY_RUN_SUMMARIES,
Expand Down Expand Up @@ -65,7 +63,6 @@ def __init__(
super().__init__(coordinator)
self.base_station = base_station
self._event: CalendarEvent | None = None
self._location = coordinator.base_station[KEY_ADDRESS][KEY_LOCALITY]
self._attr_translation_placeholders = {
"base": coordinator.base_station[KEY_SERIAL_NUMBER]
}
Expand All @@ -87,7 +84,6 @@ def event(self) -> CalendarEvent | None:
end=dt_util.as_local(start_time)
+ timedelta(seconds=int(event[KEY_TOTAL_RUN_DURATION])),
description=valves,
location=self._location,
)

def _handle_upcoming_event(self) -> dict[str, Any] | None:
Expand Down Expand Up @@ -155,7 +151,6 @@ async def async_get_events(
start=event_start,
end=event_end,
description=valves,
location=self._location,
uid=f"{run[KEY_PROGRAM_ID]}/{run[KEY_START_TIME]}",
)
event_list.append(event)
Expand Down
2 changes: 0 additions & 2 deletions homeassistant/components/rachio/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@
KEY_PROGRAM_NAME = "programName"
KEY_PROGRAM_RUN_SUMMARIES = "valveProgramRunSummaries"
KEY_TOTAL_RUN_DURATION = "totalRunDurationSeconds"
KEY_ADDRESS = "address"
KEY_LOCALITY = "locality"
KEY_SKIP = "skip"
KEY_SKIPPABLE = "skippable"

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/russound_rio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from .const import DOMAIN, RUSSOUND_RIO_EXCEPTIONS

PLATFORMS = [Platform.MEDIA_PLAYER, Platform.NUMBER]
PLATFORMS = [Platform.MEDIA_PLAYER, Platform.NUMBER, Platform.SWITCH]

_LOGGER = logging.getLogger(__name__)

Expand Down
12 changes: 12 additions & 0 deletions homeassistant/components/russound_rio/icons.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"entity": {
"switch": {
"loudness": {
"default": "mdi:volume-high",
"state": {
"off": "mdi:volume-low"
}
}
}
}
}
5 changes: 5 additions & 0 deletions homeassistant/components/russound_rio/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
"turn_on_volume": {
"name": "Turn-on volume"
}
},
"switch": {
"loudness": {
"name": "Loudness"
}
}
},
"exceptions": {
Expand Down
85 changes: 85 additions & 0 deletions homeassistant/components/russound_rio/switch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"""Support for Russound RIO switch entities."""

from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from typing import Any

from aiorussound.rio import Controller, ZoneControlSurface

from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import RussoundConfigEntry
from .entity import RussoundBaseEntity, command

PARALLEL_UPDATES = 0


@dataclass(frozen=True, kw_only=True)
class RussoundZoneSwitchEntityDescription(SwitchEntityDescription):
"""Describes Russound RIO switch entity description."""

value_fn: Callable[[ZoneControlSurface], bool]
set_value_fn: Callable[[ZoneControlSurface, bool], Awaitable[None]]


CONTROL_ENTITIES: tuple[RussoundZoneSwitchEntityDescription, ...] = (
RussoundZoneSwitchEntityDescription(
key="loudness",
translation_key="loudness",
entity_category=EntityCategory.CONFIG,
value_fn=lambda zone: zone.loudness,
set_value_fn=lambda zone, value: zone.set_loudness(value),
),
)


async def async_setup_entry(
hass: HomeAssistant,
entry: RussoundConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up Russound RIO switch entities based on a config entry."""
client = entry.runtime_data
async_add_entities(
RussoundSwitchEntity(controller, zone_id, description)
for controller in client.controllers.values()
for zone_id in controller.zones
for description in CONTROL_ENTITIES
)


class RussoundSwitchEntity(RussoundBaseEntity, SwitchEntity):
"""Defines a Russound RIO switch entity."""

entity_description: RussoundZoneSwitchEntityDescription

def __init__(
self,
controller: Controller,
zone_id: int,
description: RussoundZoneSwitchEntityDescription,
) -> None:
"""Initialize Russound RIO switch."""
super().__init__(controller, zone_id)
self.entity_description = description
self._attr_unique_id = (
f"{self._primary_mac_address}-{self._zone.device_str}-{description.key}"
)

@property
def is_on(self) -> bool:
"""Return the state of the switch."""
return self.entity_description.value_fn(self._zone)

@command
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the switch on."""
await self.entity_description.set_value_fn(self._zone, True)

@command
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the switch off."""
await self.entity_description.set_value_fn(self._zone, False)
11 changes: 6 additions & 5 deletions homeassistant/components/unifi/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
from typing import TYPE_CHECKING, Any

import aiounifi
from aiounifi.interfaces.api_handlers import ItemEvent
from aiounifi.interfaces.api_handlers import APIHandler, ItemEvent
from aiounifi.interfaces.devices import Devices
from aiounifi.interfaces.ports import Ports
from aiounifi.interfaces.wlans import Wlans
from aiounifi.models.api import ApiItemT
from aiounifi.models.api import ApiItem
from aiounifi.models.device import (
Device,
DevicePowerCyclePortRequest,
Expand All @@ -35,7 +35,6 @@

from . import UnifiConfigEntry
from .entity import (
HandlerT,
UnifiEntity,
UnifiEntityDescription,
async_device_available_fn,
Expand Down Expand Up @@ -81,7 +80,7 @@ async def async_regenerate_password_control_fn(


@dataclass(frozen=True, kw_only=True)
class UnifiButtonEntityDescription(
class UnifiButtonEntityDescription[HandlerT: APIHandler, ApiItemT: ApiItem](
ButtonEntityDescription, UnifiEntityDescription[HandlerT, ApiItemT]
):
"""Class describing UniFi button entity."""
Expand Down Expand Up @@ -143,7 +142,9 @@ async def async_setup_entry(
)


class UnifiButtonEntity(UnifiEntity[HandlerT, ApiItemT], ButtonEntity):
class UnifiButtonEntity[HandlerT: APIHandler, ApiItemT: ApiItem](
UnifiEntity[HandlerT, ApiItemT], ButtonEntity
):
"""Base representation of a UniFi button."""

entity_description: UnifiButtonEntityDescription[HandlerT, ApiItemT]
Expand Down
17 changes: 7 additions & 10 deletions homeassistant/components/unifi/device_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
from typing import Any

import aiounifi
from aiounifi.interfaces.api_handlers import ItemEvent
from aiounifi.interfaces.api_handlers import APIHandler, ItemEvent
from aiounifi.interfaces.clients import Clients
from aiounifi.interfaces.devices import Devices
from aiounifi.models.api import ApiItemT
from aiounifi.models.api import ApiItem
from aiounifi.models.client import Client
from aiounifi.models.device import Device
from aiounifi.models.event import Event, EventKey
Expand All @@ -31,12 +31,7 @@

from . import UnifiConfigEntry
from .const import DOMAIN
from .entity import (
HandlerT,
UnifiEntity,
UnifiEntityDescription,
async_device_available_fn,
)
from .entity import UnifiEntity, UnifiEntityDescription, async_device_available_fn
from .hub import UnifiHub

LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -142,7 +137,7 @@ def async_device_heartbeat_timedelta_fn(hub: UnifiHub, obj_id: str) -> timedelta


@dataclass(frozen=True, kw_only=True)
class UnifiTrackerEntityDescription(
class UnifiTrackerEntityDescription[HandlerT: APIHandler, ApiItemT: ApiItem](
UnifiEntityDescription[HandlerT, ApiItemT], ScannerEntityDescription
):
"""Class describing UniFi device tracker entity."""
Expand Down Expand Up @@ -229,7 +224,9 @@ async def async_setup_entry(
)


class UnifiScannerEntity(UnifiEntity[HandlerT, ApiItemT], ScannerEntity):
class UnifiScannerEntity[HandlerT: APIHandler, ApiItemT: ApiItem](
UnifiEntity[HandlerT, ApiItemT], ScannerEntity
):
"""Representation of a UniFi scanner."""

entity_description: UnifiTrackerEntityDescription
Expand Down
Loading
Loading