mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 04:37:06 +00:00
Add KEF services for DSP (#31967)
* add services for DSP * add homeassistant/components/kef/const.py * add services.yaml * fix set_mode * fix services * media_player.py fixes * bump aiokef to 0.2.9 * update requirements_all.txt * add basic sensor.py * add DSP settings as attributes * add message about kef.update_dsp * remove sensor.py * fix pylint issues * update_dsp inside async_added_to_hass * use {...} instead of dict(...) * get DSP settings when connecting to HA or once on update * simplify condition * do not get mode twice * remove async_added_to_hass * use async_register_entity_service * remove entity_id from schema and prepend _value * invalidate self._dsp after setting a DSP setting * schedule update_dsp every hour * subscribe and unsubscribe on adding and removing to HA * don't pass hass and set _update_dsp_task_remover to None after removing
This commit is contained in:
parent
bcd1eb952c
commit
3e0ccd2e86
@ -4,5 +4,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/kef",
|
||||
"dependencies": [],
|
||||
"codeowners": ["@basnijholt"],
|
||||
"requirements": ["aiokef==0.2.7", "getmac==0.8.1"]
|
||||
"requirements": ["aiokef==0.2.9", "getmac==0.8.1"]
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
"""Platform for the KEF Wireless Speakers."""
|
||||
|
||||
import asyncio
|
||||
from datetime import timedelta
|
||||
from functools import partial
|
||||
import ipaddress
|
||||
import logging
|
||||
|
||||
from aiokef import AsyncKefSpeaker
|
||||
from aiokef.aiokef import DSP_OPTION_MAPPING
|
||||
from getmac import get_mac_address
|
||||
import voluptuous as vol
|
||||
|
||||
@ -31,7 +33,8 @@ from homeassistant.const import (
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
)
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -55,6 +58,17 @@ CONF_INVERSE_SPEAKER_MODE = "inverse_speaker_mode"
|
||||
CONF_SUPPORTS_ON = "supports_on"
|
||||
CONF_STANDBY_TIME = "standby_time"
|
||||
|
||||
SERVICE_MODE = "set_mode"
|
||||
SERVICE_DESK_DB = "set_desk_db"
|
||||
SERVICE_WALL_DB = "set_wall_db"
|
||||
SERVICE_TREBLE_DB = "set_treble_db"
|
||||
SERVICE_HIGH_HZ = "set_high_hz"
|
||||
SERVICE_LOW_HZ = "set_low_hz"
|
||||
SERVICE_SUB_DB = "set_sub_db"
|
||||
SERVICE_UPDATE_DSP = "update_dsp"
|
||||
|
||||
DSP_SCAN_INTERVAL = 3600
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
@ -118,6 +132,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
||||
inverse_speaker_mode,
|
||||
supports_on,
|
||||
sources,
|
||||
speaker_type,
|
||||
ioloop=hass.loop,
|
||||
unique_id=unique_id,
|
||||
)
|
||||
@ -128,6 +143,36 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
||||
hass.data[DOMAIN][host] = media_player
|
||||
async_add_entities([media_player], update_before_add=True)
|
||||
|
||||
platform = entity_platform.current_platform.get()
|
||||
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_MODE,
|
||||
{
|
||||
vol.Optional("desk_mode"): cv.boolean,
|
||||
vol.Optional("wall_mode"): cv.boolean,
|
||||
vol.Optional("phase_correction"): cv.boolean,
|
||||
vol.Optional("high_pass"): cv.boolean,
|
||||
vol.Optional("sub_polarity"): vol.In(["-", "+"]),
|
||||
vol.Optional("bass_extension"): vol.In(["Less", "Standard", "Extra"]),
|
||||
},
|
||||
"set_mode",
|
||||
)
|
||||
platform.async_register_entity_service(SERVICE_UPDATE_DSP, {}, "update_dsp")
|
||||
|
||||
def add_service(name, which, option):
|
||||
platform.async_register_entity_service(
|
||||
name,
|
||||
{vol.Required(option): vol.In(DSP_OPTION_MAPPING[which])},
|
||||
f"set_{which}",
|
||||
)
|
||||
|
||||
add_service(SERVICE_DESK_DB, "desk_db", "db_value")
|
||||
add_service(SERVICE_WALL_DB, "wall_db", "db_value")
|
||||
add_service(SERVICE_TREBLE_DB, "treble_db", "db_value")
|
||||
add_service(SERVICE_HIGH_HZ, "high_hz", "hz_value")
|
||||
add_service(SERVICE_LOW_HZ, "low_hz", "hz_value")
|
||||
add_service(SERVICE_SUB_DB, "sub_db", "db_value")
|
||||
|
||||
|
||||
class KefMediaPlayer(MediaPlayerDevice):
|
||||
"""Kef Player Object."""
|
||||
@ -143,6 +188,7 @@ class KefMediaPlayer(MediaPlayerDevice):
|
||||
inverse_speaker_mode,
|
||||
supports_on,
|
||||
sources,
|
||||
speaker_type,
|
||||
ioloop,
|
||||
unique_id,
|
||||
):
|
||||
@ -160,12 +206,15 @@ class KefMediaPlayer(MediaPlayerDevice):
|
||||
)
|
||||
self._unique_id = unique_id
|
||||
self._supports_on = supports_on
|
||||
self._speaker_type = speaker_type
|
||||
|
||||
self._state = None
|
||||
self._muted = None
|
||||
self._source = None
|
||||
self._volume = None
|
||||
self._is_online = None
|
||||
self._dsp = None
|
||||
self._update_dsp_task_remover = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
@ -190,6 +239,9 @@ class KefMediaPlayer(MediaPlayerDevice):
|
||||
state = await self._speaker.get_state()
|
||||
self._source = state.source
|
||||
self._state = STATE_ON if state.is_on else STATE_OFF
|
||||
if self._dsp is None:
|
||||
# Only do this when necessary because it is a slow operation
|
||||
await self.update_dsp()
|
||||
else:
|
||||
self._muted = None
|
||||
self._source = None
|
||||
@ -291,11 +343,11 @@ class KefMediaPlayer(MediaPlayerDevice):
|
||||
|
||||
async def async_media_play(self):
|
||||
"""Send play command."""
|
||||
await self._speaker.play_pause()
|
||||
await self._speaker.set_play_pause()
|
||||
|
||||
async def async_media_pause(self):
|
||||
"""Send pause command."""
|
||||
await self._speaker.play_pause()
|
||||
await self._speaker.set_play_pause()
|
||||
|
||||
async def async_media_previous_track(self):
|
||||
"""Send previous track command."""
|
||||
@ -304,3 +356,87 @@ class KefMediaPlayer(MediaPlayerDevice):
|
||||
async def async_media_next_track(self):
|
||||
"""Send next track command."""
|
||||
await self._speaker.next_track()
|
||||
|
||||
async def update_dsp(self) -> None:
|
||||
"""Update the DSP settings."""
|
||||
if self._speaker_type == "LS50" and self._state == STATE_OFF:
|
||||
# The LSX is able to respond when off the LS50 has to be on.
|
||||
return
|
||||
|
||||
(mode, *rest) = await asyncio.gather(
|
||||
self._speaker.get_mode(),
|
||||
self._speaker.get_desk_db(),
|
||||
self._speaker.get_wall_db(),
|
||||
self._speaker.get_treble_db(),
|
||||
self._speaker.get_high_hz(),
|
||||
self._speaker.get_low_hz(),
|
||||
self._speaker.get_sub_db(),
|
||||
)
|
||||
keys = ["desk_db", "wall_db", "treble_db", "high_hz", "low_hz", "sub_db"]
|
||||
self._dsp = dict(zip(keys, rest), **mode._asdict())
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Subscribe to DSP updates."""
|
||||
self._update_dsp_task_remover = async_track_time_interval(
|
||||
self.hass, self.update_dsp, DSP_SCAN_INTERVAL
|
||||
)
|
||||
|
||||
async def async_will_remove_from_hass(self):
|
||||
"""Unsubscribe to DSP updates."""
|
||||
self._update_dsp_task_remover()
|
||||
self._update_dsp_task_remover = None
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return the DSP settings of the KEF device."""
|
||||
return self._dsp or {}
|
||||
|
||||
async def set_mode(
|
||||
self,
|
||||
desk_mode=None,
|
||||
wall_mode=None,
|
||||
phase_correction=None,
|
||||
high_pass=None,
|
||||
sub_polarity=None,
|
||||
bass_extension=None,
|
||||
):
|
||||
"""Set the speaker mode."""
|
||||
await self._speaker.set_mode(
|
||||
desk_mode=desk_mode,
|
||||
wall_mode=wall_mode,
|
||||
phase_correction=phase_correction,
|
||||
high_pass=high_pass,
|
||||
sub_polarity=sub_polarity,
|
||||
bass_extension=bass_extension,
|
||||
)
|
||||
self._dsp = None
|
||||
|
||||
async def set_desk_db(self, db_value):
|
||||
"""Set desk_db of the KEF speakers."""
|
||||
await self._speaker.set_desk_db(db_value)
|
||||
self._dsp = None
|
||||
|
||||
async def set_wall_db(self, db_value):
|
||||
"""Set wall_db of the KEF speakers."""
|
||||
await self._speaker.set_wall_db(db_value)
|
||||
self._dsp = None
|
||||
|
||||
async def set_treble_db(self, db_value):
|
||||
"""Set treble_db of the KEF speakers."""
|
||||
await self._speaker.set_treble_db(db_value)
|
||||
self._dsp = None
|
||||
|
||||
async def set_high_hz(self, hz_value):
|
||||
"""Set high_hz of the KEF speakers."""
|
||||
await self._speaker.set_high_hz(hz_value)
|
||||
self._dsp = None
|
||||
|
||||
async def set_low_hz(self, hz_value):
|
||||
"""Set low_hz of the KEF speakers."""
|
||||
await self._speaker.set_low_hz(hz_value)
|
||||
self._dsp = None
|
||||
|
||||
async def set_sub_db(self, db_value):
|
||||
"""Set sub_db of the KEF speakers."""
|
||||
await self._speaker.set_sub_db(db_value)
|
||||
self._dsp = None
|
||||
|
97
homeassistant/components/kef/services.yaml
Normal file
97
homeassistant/components/kef/services.yaml
Normal file
@ -0,0 +1,97 @@
|
||||
update_dsp:
|
||||
description: Update all DSP settings.
|
||||
fields:
|
||||
entity_id:
|
||||
description: The entity_id of the KEF speaker.
|
||||
example: media_player.kef_lsx
|
||||
|
||||
set_mode:
|
||||
description: Set the mode of the speaker.
|
||||
fields:
|
||||
entity_id:
|
||||
description: The entity_id of the KEF speaker.
|
||||
example: media_player.kef_lsx
|
||||
desk_mode:
|
||||
description: >
|
||||
"Desk mode" (true or false)
|
||||
example: true
|
||||
wall_mode:
|
||||
description: >
|
||||
"Wall mode" (true or false)
|
||||
example: true
|
||||
phase_correction:
|
||||
description: >
|
||||
"Phase correction" (true or false)
|
||||
example: true
|
||||
high_pass:
|
||||
description: >
|
||||
"High-pass mode" (true or false)
|
||||
example: true
|
||||
sub_polarity:
|
||||
description: >
|
||||
"Sub polarity" ("-" or "+")
|
||||
example: "+"
|
||||
bass_extension:
|
||||
description: >
|
||||
"Bass extension" selector ("Less", "Standard", or "Extra")
|
||||
example: "Extra"
|
||||
|
||||
set_desk_db:
|
||||
description: Set the "Desk mode" slider of the speaker in dB.
|
||||
fields:
|
||||
entity_id:
|
||||
description: The entity_id of the KEF speaker.
|
||||
example: media_player.kef_lsx
|
||||
db_value:
|
||||
description: Value of the slider (-6 to 0 with steps of 0.5)
|
||||
example: 0.0
|
||||
|
||||
set_wall_db:
|
||||
description: Set the "Wall mode" slider of the speaker in dB.
|
||||
fields:
|
||||
entity_id:
|
||||
description: The entity_id of the KEF speaker.
|
||||
example: media_player.kef_lsx
|
||||
db_value:
|
||||
description: Value of the slider (-6 to 0 with steps of 0.5)
|
||||
example: 0.0
|
||||
|
||||
set_treble_db:
|
||||
description: Set desk the "Treble trim" slider of the speaker in dB.
|
||||
fields:
|
||||
entity_id:
|
||||
description: The entity_id of the KEF speaker.
|
||||
example: media_player.kef_lsx
|
||||
db_value:
|
||||
description: Value of the slider (-2 to 2 with steps of 0.5)
|
||||
example: 0.0
|
||||
|
||||
set_high_hz:
|
||||
description: Set the "High-pass mode" slider of the speaker in Hz.
|
||||
fields:
|
||||
entity_id:
|
||||
description: The entity_id of the KEF speaker.
|
||||
example: media_player.kef_lsx
|
||||
hz_value:
|
||||
description: Value of the slider (50 to 120 with steps of 5)
|
||||
example: 95
|
||||
|
||||
set_low_hz:
|
||||
description: Set the "Sub out low-pass frequency" slider of the speaker in Hz.
|
||||
fields:
|
||||
entity_id:
|
||||
description: The entity_id of the KEF speaker.
|
||||
example: media_player.kef_lsx
|
||||
hz_value:
|
||||
description: Value of the slider (40 to 250 with steps of 5)
|
||||
example: 80
|
||||
|
||||
set_sub_db:
|
||||
description: Set the "Sub gain" slider of the speaker in dB.
|
||||
fields:
|
||||
entity_id:
|
||||
description: The entity_id of the KEF speaker.
|
||||
example: media_player.kef_lsx
|
||||
db_value:
|
||||
description: Value of the slider (-10 to 10 with steps of 1)
|
||||
example: 0
|
@ -184,7 +184,7 @@ aioimaplib==0.7.15
|
||||
aiokafka==0.5.1
|
||||
|
||||
# homeassistant.components.kef
|
||||
aiokef==0.2.7
|
||||
aiokef==0.2.9
|
||||
|
||||
# homeassistant.components.lifx
|
||||
aiolifx==0.6.7
|
||||
|
Loading…
x
Reference in New Issue
Block a user