Skip to content

Commit

Permalink
Merge pull request #2 from ScratMan/master
Browse files Browse the repository at this point in the history
Add sound settings configuration service
  • Loading branch information
osk2 authored Feb 5, 2023
2 parents e7ba556 + 49d1891 commit 5a4106a
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 7 deletions.
32 changes: 32 additions & 0 deletions custom_components/linkplay/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
SERVICE_REST = 'restore'
SERVICE_LIST = 'get_tracks'
SERVICE_PLAY = 'play_track'
SERVICE_SOUND = 'sound_settings'

ATTR_MASTER = 'master'
ATTR_PRESET = 'preset'
Expand All @@ -29,6 +30,12 @@
ATTR_SELECT = 'input_select'
ATTR_SOURCE = 'source'
ATTR_TRACK = 'track'
ATTR_SOUND = 'sound_program'
ATTR_SUB = 'subwoofer_volume'
ATTR_SURROUND = 'surround'
ATTR_VOICE = 'clear_voice'
ATTR_BASS = 'bass_extension'
ATTR_MUTE = 'mute'

SERVICE_SCHEMA = vol.Schema({
vol.Optional(ATTR_ENTITY_ID): cv.comp_entity_ids
Expand Down Expand Up @@ -63,6 +70,16 @@
vol.Required(ATTR_TRACK): cv.template
})

SOUND_SERVICE_SCHEMA = vol.Schema({
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
vol.Optional(ATTR_SOUND): cv.string,
vol.Optional(ATTR_SUB): int,
vol.Optional(ATTR_SURROUND): cv.boolean,
vol.Optional(ATTR_VOICE): cv.boolean,
vol.Optional(ATTR_BASS): cv.boolean,
vol.Optional(ATTR_MUTE): cv.boolean,
})

_LOGGER = logging.getLogger(__name__)

def setup(hass, config):
Expand Down Expand Up @@ -137,6 +154,19 @@ async def async_service_handle(service):
_LOGGER.debug("**PLAY TRACK** entity: %s; track: %s", device.entity_id, track)
await device.async_play_track(track)

elif service.service == SERVICE_SOUND:
settings = {key: service.data.get(key) for key in [ATTR_SOUND,
ATTR_SUB,
ATTR_SURROUND,
ATTR_VOICE,
ATTR_BASS,
ATTR_MUTE]}
for device in entities:
if device.entity_id in entity_ids:
_LOGGER.debug("**SET SOUND** entity: %s; settings: %s", device.entity_id,
settings)
await device.async_set_sound(settings)


hass.services.async_register(
DOMAIN, SERVICE_JOIN, async_service_handle, schema=JOIN_SERVICE_SCHEMA)
Expand All @@ -152,5 +182,7 @@ async def async_service_handle(service):
DOMAIN, SERVICE_REST, async_service_handle, schema=REST_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_PLAY, async_service_handle, schema=PLYTRK_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_SOUND, async_service_handle, schema=SOUND_SERVICE_SCHEMA)

return True
54 changes: 47 additions & 7 deletions custom_components/linkplay/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ async def async_call_linkplay_httpapi(self, cmd, jsn):
return False

finally:
await websession.close()
await websession.close()

if response.status == HTTPStatus.OK:
if jsn:
Expand Down Expand Up @@ -2605,6 +2605,46 @@ async def async_play_track(self, track):
else:
await self._master.async_play_track(track)

async def async_set_sound(self, settings):
"""Play media track by name found in the tracks list."""
sound_program = settings.get('sound_program', None)
subwoofer_volume = settings.get('subwoofer_volume', None)
surround = settings.get('surround', None)
clear_voice = settings.get('clear_voice', None)
bass_extension = settings.get('bass_extension', None)
mute = settings.get('mute', None)
power_saving = settings.get('power_saving', None)
cmd = "YAMAHA_DATA_SET:{"
end = '}'
sentences = []
if subwoofer_volume is not None:
sentences.append(f"%22subwoofer%20volume%22:%22{subwoofer_volume}%22")
if surround is not None:
sentences.append(f"%223D%20surround%22:%22{int(surround)}%22")
if clear_voice is not None:
sentences.append(f"%22clear%20voice%22:%22{int(clear_voice)}%22")
if bass_extension is not None:
sentences.append(f"%22bass%20extension%22:%22{int(bass_extension)}%22")
if mute is not None:
sentences.append(f"%22mute%22:%22{int(mute)}%22")
if power_saving is not None:
sentences.append(f"%22power%20saving%22:%22{int(power_saving)}%22")
if sound_program is not None:
sentences.append(f"%22sound%20program%22:%22{sound_program.replace(' ', '%20')}%22")

for sentence in sentences:
setting, value = sentence.replace('%20', ' ').replace('%22', '').split(':')
for tentative in range(10):
await self.async_call_linkplay_httpapi("YAMAHA_DATA_GET", True)
await self.async_call_linkplay_httpapi(f"{cmd + sentence + end}", None)
await asyncio.sleep(0.1 * tentative)
status = await self.async_call_linkplay_httpapi("YAMAHA_DATA_GET", True)
_LOGGER.debug("Received data: '%s: %s'", setting, status[setting])
if status[setting] == value:
break
_LOGGER.debug("Tentative %i to set '%s: %s' failed, value is %s", tentative,
setting, value, status[setting])

async def async_update_via_upnp(self):
"""Update track info via UPNP."""
import validators
Expand Down Expand Up @@ -2694,12 +2734,12 @@ async def async_tracklist_via_upnp(self, media):

trackq = []
for playlist in xml_tree:
for tracks in playlist:
for track in tracks:
if track.tag == 'URL':
if rootdir in track.text:
tracku = track.text.replace(rootdir, '')
trackq.append(tracku)
for tracks in playlist:
for track in tracks:
if track.tag == 'URL':
if rootdir in track.text:
tracku = track.text.replace(rootdir, '')
trackq.append(tracku)

if len(trackq) > 0:
self._trackq = trackq
Expand Down
65 changes: 65 additions & 0 deletions custom_components/linkplay/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,71 @@ command:
selector:
boolean:

sound_settings:
name: Sound Settings
description: Set the sound options
fields:
entity_id:
name: Entity ID
description: Entity ID of the player on which the playback wil be execuded.
example: media_player.sound_room1
required: true
selector:
entity:
integration: linkplay
sound_program:
name: Sound Program
description: Select the sound preset
required: false
selector:
select:
options:
- music
- sports
- tv program
- game
- movie
- stereo
subwoofer_volume:
name: Subwoofer Volume
description: Set the subwoofer volume
required: false
selector:
number:
min: -4
max: 4
step: 1
surround:
name: 3D Surround
description: Set the 3D surround option on or off
required: false
selector:
boolean:
clear_voice:
name: Clear Voice
description: Set the clear voice option on or off
required: false
selector:
boolean:
bass_extension:
name: Bass Extension
description: Set the bass extension option on or off
required: false
selector:
boolean:
mute:
name: Mute
description: Set the mute on or off
required: false
selector:
boolean:
# power_saving:
# name: Power Saving
# description: Set the power saving option on or off
# required: false
# selector:
# boolean:

play_track:
name: Play track
description: Play media track by name found in the tracks list.
Expand Down

0 comments on commit 5a4106a

Please sign in to comment.