-
Notifications
You must be signed in to change notification settings - Fork 47
Manage Google Nest speaker groups
Nate edited this page Nov 18, 2020
·
9 revisions
This is an app that was created for managing Groups of Google Nest speakers.
Some of its features:
- When playing music on a group, change the volume to
musicVolume
unless the volume has been overridden--in which case, use that. - Switch between a "speaking" volume when not playing music and restore the volume to your prior music volume.
- Adjust the volume based on a day mode and night mode (e.g. once it's sunset, make Assistant talk quieter than during the day).
Hope this helps someone get more familiar with this awesome tool!
pyscript:
apps:
speaker_group_manager:
- group: media_player.downstairs_group
speakers: # the speakers in the group
media_player.living_room_speaker:
volumeOverride: None # this is here so we can write a little less code in the script ;)
musicVolume: 0.25 # default volume for media
speakingVolume: 0.50 # default volume for the Assistant
media_player.kitchen_speaker:
volumeOverride: None
musicVolume: 0.30
speakingVolume: 0.50
registered_triggers = []
def loadApp(app_name, factory):
if 'apps' not in pyscript.config:
return
if app_name not in pyscript.config['apps']:
return
for app in pyscript.config['apps'][app_name]:
factory(app)
@time_trigger('startup')
def speakerGroupStartup():
loadApp('speaker_group_manager', buildSpeakerGroup)
def buildSpeakerGroup(config):
global registered_triggers
### Day/Night mode variables ###
startNightMode = '22:30:00'
dayMode = f'range(sunrise, {startNightMode})'
nightMode = f'range({startNightMode}, sunrise)'
### config variables ###
group = config.get('group')
speakers = config.get('speakers')
### conditionals used in the @state_triggers ##
useMusicVol = f'{group} == "playing"'
useSpeakingVol = f'{group} != "playing"'
### Day mode versions ###
@time_active(dayMode)
@state_trigger(useMusicVol)
def restoreGroupMusicVolume():
setMusicVolume()
@time_active(dayMode)
@state_trigger(useSpeakingVol)
def restoreGroupSpeakingVolume():
handleSpeakingVolume()
### Night mode versions ###
@time_active(nightMode)
@state_trigger(useMusicVol)
def restoreGroupNightMusicVolume():
setMusicVolume(nightMode=True)
@time_active(nightMode)
@state_trigger(useSpeakingVol)
def restoreGroupNightSpeakingVolume():
handleSpeakingVolume(nightMode=True)
### Time triggers ###
# Reset group overrides to defaults at sunrise
@time_trigger('once(sunrise)')
def resetGroupOverrides():
global speakers
speakers = config.get('speakers')
# Change group speaker volumes to night mode
@state_active(f'{group} != "playing"')
@time_trigger(f'once({startNightMode})')
def setGroupNightSpeakingVolume():
setSpeakingVolume(nightMode=True)
### Pièce de résistance ###
# Sets volume overrides for group speakers
@task_unique(f'monitor_{group}_volume')
@state_active(f'{group} == "playing"')
@state_trigger(f'{group}.volume_level')
def monitorGroupVolume():
for speaker, volumes in speakers.items():
volume = state.get(f'{speaker}.volume_level')
volumes['volumeOverride'] = round(volume, 2)
### Helper functions ###
def setMusicVolume(nightMode=False):
for speaker, volumes in speakers.items():
volOverride = volumes['volumeOverride']
musicVol = volumes['musicVolume'] if (
volOverride == 'None' or volOverride is None) else volOverride
volume = musicVol if not nightMode else musicVol - 0.07
media_player.volume_set(entity_id=speaker, volume_level=volume)
def setSpeakingVolume(nightMode=False):
for speaker, volumes in speakers.items():
speakingVol = volumes['speakingVolume']
volume = speakingVol if not nightMode else speakingVol - 0.15 # -15 speaking volume when in night mode: arbitrary
media_player.volume_set(entity_id=speaker, volume_level=volume)
def handleSpeakingVolume(nightMode=False):
spotifyDelay = 0.85
# sometimes the speakers become 'unavailable' while playing
if state.get(group) != 'unavailable':
# Spotify changes to 'paused' between songs; wait to alter volume
if (state.getattr(group)).get('app_name') == 'Spotify':
waitUntilPlaying = task.wait_until(
state_trigger=(f'{group} == "playing"'),
timeout=spotifyDelay
)
if waitUntilPlaying['trigger_type'] == 'timeout':
setSpeakingVolume(nightMode)
else:
setSpeakingVolume(nightMode)
# register to global scope
registered_triggers.append([
monitorGroupVolume,
restoreGroupMusicVolume,
restoreGroupSpeakingVolume,
restoreGroupNightMusicVolume,
restoreGroupNightSpeakingVolume,
resetGroupOverrides,
setGroupNightSpeakingVolume
])