mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Move Sonos bass & treble controls to number entities (#60498)
This commit is contained in:
parent
3aa35e15c2
commit
a88cc8b98c
@ -19,6 +19,7 @@ from homeassistant.components.media_player.const import (
|
||||
MEDIA_TYPE_PLAYLIST,
|
||||
MEDIA_TYPE_TRACK,
|
||||
)
|
||||
from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||
|
||||
@ -27,7 +28,13 @@ UPNP_ST = "urn:schemas-upnp-org:device:ZonePlayer:1"
|
||||
DOMAIN = "sonos"
|
||||
DATA_SONOS = "sonos_media_player"
|
||||
DATA_SONOS_DISCOVERY_MANAGER = "sonos_discovery_manager"
|
||||
PLATFORMS = {BINARY_SENSOR_DOMAIN, MP_DOMAIN, SENSOR_DOMAIN, SWITCH_DOMAIN}
|
||||
PLATFORMS = {
|
||||
BINARY_SENSOR_DOMAIN,
|
||||
MP_DOMAIN,
|
||||
NUMBER_DOMAIN,
|
||||
SENSOR_DOMAIN,
|
||||
SWITCH_DOMAIN,
|
||||
}
|
||||
|
||||
SONOS_ARTIST = "artists"
|
||||
SONOS_ALBUM = "albums"
|
||||
@ -139,6 +146,7 @@ SONOS_CHECK_ACTIVITY = "sonos_check_activity"
|
||||
SONOS_CREATE_ALARM = "sonos_create_alarm"
|
||||
SONOS_CREATE_BATTERY = "sonos_create_battery"
|
||||
SONOS_CREATE_SWITCHES = "sonos_create_switches"
|
||||
SONOS_CREATE_LEVELS = "sonos_create_levels"
|
||||
SONOS_CREATE_MEDIA_PLAYER = "sonos_create_media_player"
|
||||
SONOS_ENTITY_CREATED = "sonos_entity_created"
|
||||
SONOS_POLL_UPDATE = "sonos_poll_update"
|
||||
|
@ -108,7 +108,6 @@ SERVICE_RESTORE = "restore"
|
||||
SERVICE_SET_TIMER = "set_sleep_timer"
|
||||
SERVICE_CLEAR_TIMER = "clear_sleep_timer"
|
||||
SERVICE_UPDATE_ALARM = "update_alarm"
|
||||
SERVICE_SET_OPTION = "set_option"
|
||||
SERVICE_PLAY_QUEUE = "play_queue"
|
||||
SERVICE_REMOVE_FROM_QUEUE = "remove_from_queue"
|
||||
|
||||
@ -120,8 +119,6 @@ ATTR_INCLUDE_LINKED_ZONES = "include_linked_zones"
|
||||
ATTR_MASTER = "master"
|
||||
ATTR_WITH_GROUP = "with_group"
|
||||
ATTR_QUEUE_POSITION = "queue_position"
|
||||
ATTR_EQ_BASS = "bass_level"
|
||||
ATTR_EQ_TREBLE = "treble_level"
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
@ -225,19 +222,6 @@ async def async_setup_entry(
|
||||
"set_alarm",
|
||||
)
|
||||
|
||||
platform.async_register_entity_service( # type: ignore
|
||||
SERVICE_SET_OPTION,
|
||||
{
|
||||
vol.Optional(ATTR_EQ_BASS): vol.All(
|
||||
vol.Coerce(int), vol.Range(min=-10, max=10)
|
||||
),
|
||||
vol.Optional(ATTR_EQ_TREBLE): vol.All(
|
||||
vol.Coerce(int), vol.Range(min=-10, max=10)
|
||||
),
|
||||
},
|
||||
"set_option",
|
||||
)
|
||||
|
||||
platform.async_register_entity_service( # type: ignore
|
||||
SERVICE_PLAY_QUEUE,
|
||||
{vol.Optional(ATTR_QUEUE_POSITION): cv.positive_int},
|
||||
@ -605,19 +589,6 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
|
||||
alarm.include_linked_zones = include_linked_zones
|
||||
alarm.save()
|
||||
|
||||
@soco_error()
|
||||
def set_option(
|
||||
self,
|
||||
bass_level: int | None = None,
|
||||
treble_level: int | None = None,
|
||||
) -> None:
|
||||
"""Modify playback options."""
|
||||
if bass_level is not None:
|
||||
self.soco.bass = bass_level
|
||||
|
||||
if treble_level is not None:
|
||||
self.soco.treble = treble_level
|
||||
|
||||
@soco_error()
|
||||
def play_queue(self, queue_position: int = 0) -> None:
|
||||
"""Start playing the queue."""
|
||||
@ -635,12 +606,6 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
|
||||
ATTR_SONOS_GROUP: self.speaker.sonos_group_entities
|
||||
}
|
||||
|
||||
if self.speaker.bass_level is not None:
|
||||
attributes[ATTR_EQ_BASS] = self.speaker.bass_level
|
||||
|
||||
if self.speaker.treble_level is not None:
|
||||
attributes[ATTR_EQ_TREBLE] = self.speaker.treble_level
|
||||
|
||||
if self.media.queue_position is not None:
|
||||
attributes[ATTR_QUEUE_POSITION] = self.media.queue_position
|
||||
|
||||
|
64
homeassistant/components/sonos/number.py
Normal file
64
homeassistant/components/sonos/number.py
Normal file
@ -0,0 +1,64 @@
|
||||
"""Entity representing a Sonos number control."""
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.components.number import NumberEntity
|
||||
from homeassistant.const import ENTITY_CATEGORY_CONFIG
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
from .const import SONOS_CREATE_LEVELS
|
||||
from .entity import SonosEntity
|
||||
from .helpers import soco_error
|
||||
from .speaker import SonosSpeaker
|
||||
|
||||
LEVEL_TYPES = ("bass", "treble")
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up the Sonos number platform from a config entry."""
|
||||
|
||||
async def _async_create_entities(speaker: SonosSpeaker) -> None:
|
||||
entities = []
|
||||
for level_type in LEVEL_TYPES:
|
||||
entities.append(SonosLevelEntity(speaker, level_type))
|
||||
async_add_entities(entities)
|
||||
|
||||
config_entry.async_on_unload(
|
||||
async_dispatcher_connect(hass, SONOS_CREATE_LEVELS, _async_create_entities)
|
||||
)
|
||||
|
||||
|
||||
class SonosLevelEntity(SonosEntity, NumberEntity):
|
||||
"""Representation of a Sonos level entity."""
|
||||
|
||||
_attr_entity_category = ENTITY_CATEGORY_CONFIG
|
||||
_attr_min_value = -10
|
||||
_attr_max_value = 10
|
||||
|
||||
def __init__(self, speaker: SonosSpeaker, level_type: str) -> None:
|
||||
"""Initialize the level entity."""
|
||||
super().__init__(speaker)
|
||||
self.level_type = level_type
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique ID."""
|
||||
return f"{self.soco.uid}-{self.level_type}"
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name."""
|
||||
return f"{self.speaker.zone_name} {self.level_type.capitalize()}"
|
||||
|
||||
async def _async_poll(self) -> None:
|
||||
"""Poll the value if subscriptions are not working."""
|
||||
# Handled by SonosSpeaker
|
||||
|
||||
@soco_error()
|
||||
def set_value(self, value: float) -> None:
|
||||
"""Set a new value."""
|
||||
setattr(self.soco, self.level_type, value)
|
||||
|
||||
@property
|
||||
def value(self) -> float:
|
||||
"""Return the current value."""
|
||||
return getattr(self.speaker, self.level_type)
|
@ -87,30 +87,6 @@ clear_sleep_timer:
|
||||
device:
|
||||
integration: sonos
|
||||
|
||||
set_option:
|
||||
name: Set option
|
||||
description: Set Sonos sound options.
|
||||
target:
|
||||
device:
|
||||
integration: sonos
|
||||
fields:
|
||||
bass_level:
|
||||
name: Bass Level
|
||||
description: Bass level for EQ.
|
||||
selector:
|
||||
number:
|
||||
min: -10
|
||||
max: 10
|
||||
mode: box
|
||||
treble_level:
|
||||
name: Treble Level
|
||||
description: Treble level for EQ.
|
||||
selector:
|
||||
number:
|
||||
min: -10
|
||||
max: 10
|
||||
mode: box
|
||||
|
||||
play_queue:
|
||||
name: Play queue
|
||||
description: Start playing the queue from the first item.
|
||||
|
@ -46,6 +46,7 @@ from .const import (
|
||||
SONOS_CHECK_ACTIVITY,
|
||||
SONOS_CREATE_ALARM,
|
||||
SONOS_CREATE_BATTERY,
|
||||
SONOS_CREATE_LEVELS,
|
||||
SONOS_CREATE_MEDIA_PLAYER,
|
||||
SONOS_CREATE_SWITCHES,
|
||||
SONOS_ENTITY_CREATED,
|
||||
@ -192,8 +193,8 @@ class SonosSpeaker:
|
||||
self.night_mode: bool | None = None
|
||||
self.dialog_mode: bool | None = None
|
||||
self.cross_fade: bool | None = None
|
||||
self.bass_level: int | None = None
|
||||
self.treble_level: int | None = None
|
||||
self.bass: int | None = None
|
||||
self.treble: int | None = None
|
||||
|
||||
# Misc features
|
||||
self.buttons_enabled: bool | None = None
|
||||
@ -234,6 +235,8 @@ class SonosSpeaker:
|
||||
)
|
||||
future.result(timeout=10)
|
||||
|
||||
dispatcher_send(self.hass, SONOS_CREATE_LEVELS, self)
|
||||
|
||||
if battery_info := fetch_battery_info_or_none(self.soco):
|
||||
self.battery_info = battery_info
|
||||
# Battery events can be infrequent, polling is still necessary
|
||||
@ -490,11 +493,11 @@ class SonosSpeaker:
|
||||
if "dialog_level" in variables:
|
||||
self.dialog_mode = variables["dialog_level"] == "1"
|
||||
|
||||
if "bass_level" in variables:
|
||||
self.bass_level = variables["bass_level"]
|
||||
if "bass" in variables:
|
||||
self.bass = variables["bass"]
|
||||
|
||||
if "treble_level" in variables:
|
||||
self.treble_level = variables["treble_level"]
|
||||
if "treble" in variables:
|
||||
self.treble = variables["treble"]
|
||||
|
||||
self.async_write_entity_states()
|
||||
|
||||
@ -968,8 +971,8 @@ class SonosSpeaker:
|
||||
self.muted = self.soco.mute
|
||||
self.night_mode = self.soco.night_mode
|
||||
self.dialog_mode = self.soco.dialog_mode
|
||||
self.bass_level = self.soco.bass
|
||||
self.treble_level = self.soco.treble
|
||||
self.bass = self.soco.bass
|
||||
self.treble = self.soco.treble
|
||||
|
||||
try:
|
||||
self.cross_fade = self.soco.cross_fade
|
||||
|
@ -70,6 +70,8 @@ def soco_fixture(music_library, speaker_info, battery_info, alarm_clock):
|
||||
mock_soco.night_mode = True
|
||||
mock_soco.dialog_mode = True
|
||||
mock_soco.volume = 19
|
||||
mock_soco.bass = 1
|
||||
mock_soco.treble = -1
|
||||
mock_soco.get_battery_info.return_value = battery_info
|
||||
mock_soco.all_zones = [mock_soco]
|
||||
yield mock_soco
|
||||
|
Loading…
x
Reference in New Issue
Block a user