- Notifications
You must be signed in to change notification settings - Fork 58
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 ])