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
2 changes: 1 addition & 1 deletion homeassistant/components/html5/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"services": {
"dismiss": {
"name": "Dismiss",
"description": "Dismisses a html5 notification.",
"description": "Dismisses an HTML5 notification.",
"fields": {
"target": {
"name": "Target",
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/lifx/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
}

LIFX_CEILING_PRODUCT_IDS = {176, 177, 201, 202}
LIFX_128ZONE_CEILING_PRODUCT_IDS = {201, 202}

_LOGGER = logging.getLogger(__package__)

Expand Down
50 changes: 49 additions & 1 deletion homeassistant/components/lifx/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
DEFAULT_ATTEMPTS,
DOMAIN,
IDENTIFY_WAVEFORM,
LIFX_128ZONE_CEILING_PRODUCT_IDS,
MAX_ATTEMPTS_PER_UPDATE_REQUEST_MESSAGE,
MAX_UPDATE_TIME,
MESSAGE_RETRIES,
Expand Down Expand Up @@ -183,6 +184,11 @@ def is_matrix(self) -> bool:
"""Return true if this is a matrix device."""
return bool(lifx_features(self.device)["matrix"])

@cached_property
def is_128zone_matrix(self) -> bool:
"""Return true if this is a 128-zone matrix device."""
return bool(self.device.product in LIFX_128ZONE_CEILING_PRODUCT_IDS)

async def diagnostics(self) -> dict[str, Any]:
"""Return diagnostic information about the device."""
features = lifx_features(self.device)
Expand Down Expand Up @@ -216,6 +222,16 @@ async def diagnostics(self) -> dict[str, Any]:
"last_result": self.device.last_hev_cycle_result,
}

if features["matrix"] is True:
device_data["matrix"] = {
"effect": self.device.effect,
"chain": self.device.chain,
"chain_length": self.device.chain_length,
"tile_devices": self.device.tile_devices,
"tile_devices_count": self.device.tile_devices_count,
"tile_device_width": self.device.tile_device_width,
}

if features["infrared"] is True:
device_data["infrared"] = {"brightness": self.device.infrared_brightness}

Expand Down Expand Up @@ -291,6 +307,37 @@ def _wrapped_callback(

return calls

@callback
def _async_build_get64_update_requests(self) -> list[Callable]:
"""Build one or more get64 update requests."""
if self.device.tile_device_width == 0:
return []

calls: list[Callable] = []
calls.append(
partial(
self.device.get64,
tile_index=0,
length=1,
x=0,
y=0,
width=self.device.tile_device_width,
)
)
if self.is_128zone_matrix:
# For 128-zone ceiling devices, we need another get64 request for the next set of zones
calls.append(
partial(
self.device.get64,
tile_index=0,
length=1,
x=0,
y=4,
width=self.device.tile_device_width,
)
)
return calls

async def _async_update_data(self) -> None:
"""Fetch all device data from the api."""
device = self.device
Expand All @@ -312,9 +359,9 @@ async def _async_update_data(self) -> None:
[
self.device.get_tile_effect,
self.device.get_device_chain,
self.device.get64,
]
)
methods.extend(self._async_build_get64_update_requests())
if self.is_extended_multizone:
methods.append(self.device.get_extended_color_zones)
elif self.is_legacy_multizone:
Expand All @@ -339,6 +386,7 @@ async def _async_update_data(self) -> None:

if self.is_matrix or self.is_extended_multizone or self.is_legacy_multizone:
self.active_effect = FirmwareEffect[self.device.effect.get("effect", "OFF")]

if self.is_legacy_multizone and num_zones != self.get_number_of_zones():
# The number of zones has changed so we need
# to update the zones again. This happens rarely.
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/linkplay/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ class LinkPlaySharedData:
DOMAIN = "linkplay"
SHARED_DATA = "shared_data"
SHARED_DATA_KEY: HassKey[LinkPlaySharedData] = HassKey(SHARED_DATA)
PLATFORMS = [Platform.BUTTON, Platform.MEDIA_PLAYER]
PLATFORMS = [Platform.BUTTON, Platform.MEDIA_PLAYER, Platform.SELECT]
DATA_SESSION = "session"
5 changes: 5 additions & 0 deletions homeassistant/components/linkplay/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
"timesync": {
"default": "mdi:clock"
}
},
"select": {
"audio_output_hardware_mode": {
"default": "mdi:transit-connection-horizontal"
}
}
},
"services": {
Expand Down
112 changes: 112 additions & 0 deletions homeassistant/components/linkplay/select.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
"""Support for LinkPlay select."""

from __future__ import annotations

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

from linkplay.bridge import LinkPlayBridge, LinkPlayPlayer
from linkplay.consts import AudioOutputHwMode
from linkplay.manufacturers import MANUFACTURER_WIIM

from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import LinkPlayConfigEntry
from .entity import LinkPlayBaseEntity, exception_wrap

_LOGGER = logging.getLogger(__name__)

AUDIO_OUTPUT_HW_MODE_MAP: dict[AudioOutputHwMode, str] = {
AudioOutputHwMode.OPTICAL: "optical",
AudioOutputHwMode.LINE_OUT: "line_out",
AudioOutputHwMode.COAXIAL: "coaxial",
AudioOutputHwMode.HEADPHONES: "headphones",
}

AUDIO_OUTPUT_HW_MODE_MAP_INV: dict[str, AudioOutputHwMode] = {
v: k for k, v in AUDIO_OUTPUT_HW_MODE_MAP.items()
}


async def _get_current_option(bridge: LinkPlayBridge) -> str:
"""Get the current hardware mode."""
modes = await bridge.player.get_audio_output_hw_mode()
return AUDIO_OUTPUT_HW_MODE_MAP[modes.hardware]


@dataclass(frozen=True, kw_only=True)
class LinkPlaySelectEntityDescription(SelectEntityDescription):
"""Class describing LinkPlay select entities."""

set_option_fn: Callable[[LinkPlayPlayer, str], Coroutine[Any, Any, None]]
current_option_fn: Callable[[LinkPlayPlayer], Awaitable[str]]


SELECT_TYPES_WIIM: tuple[LinkPlaySelectEntityDescription, ...] = (
LinkPlaySelectEntityDescription(
key="audio_output_hardware_mode",
translation_key="audio_output_hardware_mode",
current_option_fn=_get_current_option,
set_option_fn=(
lambda linkplay_bridge,
option: linkplay_bridge.player.set_audio_output_hw_mode(
AUDIO_OUTPUT_HW_MODE_MAP_INV[option]
)
),
options=list(AUDIO_OUTPUT_HW_MODE_MAP_INV),
),
)


async def async_setup_entry(
hass: HomeAssistant,
config_entry: LinkPlayConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the LinkPlay select from config entry."""

# add entities
if config_entry.runtime_data.bridge.device.manufacturer == MANUFACTURER_WIIM:
async_add_entities(
LinkPlaySelect(config_entry.runtime_data.bridge, description)
for description in SELECT_TYPES_WIIM
)


class LinkPlaySelect(LinkPlayBaseEntity, SelectEntity):
"""Representation of LinkPlay select."""

entity_description: LinkPlaySelectEntityDescription

def __init__(
self,
bridge: LinkPlayPlayer,
description: LinkPlaySelectEntityDescription,
) -> None:
"""Initialize LinkPlay select."""
super().__init__(bridge)
self.entity_description = description
self._attr_unique_id = f"{bridge.device.uuid}-{description.key}"

async def async_update(self) -> None:
"""Get the current value from the device."""
try:
# modes = await self.entity_description.current_option_fn(self._bridge)
self._attr_current_option = await self.entity_description.current_option_fn(
self._bridge
)

except ValueError as ex:
_LOGGER.debug(
"Cannot retrieve hardware mode value from device with error:, %s", ex
)
self._attr_current_option = None

@exception_wrap
async def async_select_option(self, option: str) -> None:
"""Set the option."""
await self.entity_description.set_option_fn(self._bridge, option)
11 changes: 11 additions & 0 deletions homeassistant/components/linkplay/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@
"timesync": {
"name": "Sync time"
}
},
"select": {
"audio_output_hardware_mode": {
"name": "Audio output hardware mode",
"state": {
"optical": "Optical",
"line_out": "Line out",
"coaxial": "Coaxial",
"headphones": "Headphones"
}
}
}
},
"exceptions": {
Expand Down
12 changes: 7 additions & 5 deletions homeassistant/components/wallbox/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@

from wallbox import Wallbox

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed

from .const import UPDATE_INTERVAL
from .coordinator import InvalidAuth, WallboxCoordinator, async_validate_input
from .coordinator import (
InvalidAuth,
WallboxConfigEntry,
WallboxCoordinator,
async_validate_input,
)

PLATFORMS = [
Platform.LOCK,
Expand All @@ -20,8 +24,6 @@
Platform.SWITCH,
]

type WallboxConfigEntry = ConfigEntry[WallboxCoordinator]


async def async_setup_entry(hass: HomeAssistant, entry: WallboxConfigEntry) -> bool:
"""Set up Wallbox from a config entry."""
Expand All @@ -45,6 +47,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: WallboxConfigEntry) -> b
return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_unload_entry(hass: HomeAssistant, entry: WallboxConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
6 changes: 4 additions & 2 deletions homeassistant/components/wallbox/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@
210: ChargerStatus.LOCKED_CAR_CONNECTED,
}

type WallboxConfigEntry = ConfigEntry[WallboxCoordinator]


def _require_authentication[_WallboxCoordinatorT: WallboxCoordinator, **_P](
func: Callable[Concatenate[_WallboxCoordinatorT, _P], Any],
Expand Down Expand Up @@ -118,10 +120,10 @@ async def async_validate_input(hass: HomeAssistant, wallbox: Wallbox) -> None:
class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]):
"""Wallbox Coordinator class."""

config_entry: ConfigEntry
config_entry: WallboxConfigEntry

def __init__(
self, hass: HomeAssistant, config_entry: ConfigEntry, wallbox: Wallbox
self, hass: HomeAssistant, config_entry: WallboxConfigEntry, wallbox: Wallbox
) -> None:
"""Initialize."""
self._station = config_entry.data[CONF_STATION]
Expand Down
5 changes: 2 additions & 3 deletions homeassistant/components/wallbox/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from typing import Any

from homeassistant.components.lock import LockEntity, LockEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

Expand All @@ -14,7 +13,7 @@
CHARGER_LOCKED_UNLOCKED_KEY,
CHARGER_SERIAL_NUMBER_KEY,
)
from .coordinator import WallboxCoordinator
from .coordinator import WallboxConfigEntry, WallboxCoordinator
from .entity import WallboxEntity

LOCK_TYPES: dict[str, LockEntityDescription] = {
Expand All @@ -27,7 +26,7 @@

async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: WallboxConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Create wallbox lock entities in HASS."""
Expand Down
7 changes: 3 additions & 4 deletions homeassistant/components/wallbox/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from typing import cast

from homeassistant.components.number import NumberEntity, NumberEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

Expand All @@ -24,7 +23,7 @@
CHARGER_PART_NUMBER_KEY,
CHARGER_SERIAL_NUMBER_KEY,
)
from .coordinator import WallboxCoordinator
from .coordinator import WallboxConfigEntry, WallboxCoordinator
from .entity import WallboxEntity


Expand Down Expand Up @@ -79,7 +78,7 @@ class WallboxNumberEntityDescription(NumberEntityDescription):

async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: WallboxConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Create wallbox number entities in HASS."""
Expand All @@ -103,7 +102,7 @@ class WallboxNumber(WallboxEntity, NumberEntity):
def __init__(
self,
coordinator: WallboxCoordinator,
entry: ConfigEntry,
entry: WallboxConfigEntry,
description: WallboxNumberEntityDescription,
) -> None:
"""Initialize a Wallbox number entity."""
Expand Down
Loading
Loading