CARVIEW |
Select Language
HTTP/2 200
date: Sun, 20 Jul 2025 22:10:22 GMT
content-type: text/html; charset=utf-8
vary: X-PJAX, X-PJAX-Container, Turbo-Visit, Turbo-Frame, X-Requested-With,Accept-Encoding, Accept, X-Requested-With
x-robots-tag: none
etag: W/"2e94d46c7fd784dc07d09d5caef8223f"
cache-control: max-age=0, private, must-revalidate
strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
x-xss-protection: 0
referrer-policy: no-referrer-when-downgrade
content-security-policy: default-src 'none'; base-uri 'self'; child-src github.githubassets.com github.com/assets-cdn/worker/ github.com/assets/ gist.github.com/assets-cdn/worker/; connect-src 'self' uploads.github.com www.githubstatus.com collector.github.com raw.githubusercontent.com api.github.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com *.rel.tunnels.api.visualstudio.com wss://*.rel.tunnels.api.visualstudio.com objects-origin.githubusercontent.com copilot-proxy.githubusercontent.com proxy.individual.githubcopilot.com proxy.business.githubcopilot.com proxy.enterprise.githubcopilot.com *.actions.githubusercontent.com wss://*.actions.githubusercontent.com productionresultssa0.blob.core.windows.net/ productionresultssa1.blob.core.windows.net/ productionresultssa2.blob.core.windows.net/ productionresultssa3.blob.core.windows.net/ productionresultssa4.blob.core.windows.net/ productionresultssa5.blob.core.windows.net/ productionresultssa6.blob.core.windows.net/ productionresultssa7.blob.core.windows.net/ productionresultssa8.blob.core.windows.net/ productionresultssa9.blob.core.windows.net/ productionresultssa10.blob.core.windows.net/ productionresultssa11.blob.core.windows.net/ productionresultssa12.blob.core.windows.net/ productionresultssa13.blob.core.windows.net/ productionresultssa14.blob.core.windows.net/ productionresultssa15.blob.core.windows.net/ productionresultssa16.blob.core.windows.net/ productionresultssa17.blob.core.windows.net/ productionresultssa18.blob.core.windows.net/ productionresultssa19.blob.core.windows.net/ github-production-repository-image-32fea6.s3.amazonaws.com github-production-release-asset-2e65be.s3.amazonaws.com insights.github.com wss://alive.github.com api.githubcopilot.com api.individual.githubcopilot.com api.business.githubcopilot.com api.enterprise.githubcopilot.com; font-src github.githubassets.com; form-action 'self' github.com gist.github.com copilot-workspace.githubnext.com objects-origin.githubusercontent.com; frame-ancestors 'none'; frame-src viewscreen.githubusercontent.com notebooks.githubusercontent.com; img-src 'self' data: blob: github.githubassets.com media.githubusercontent.com camo.githubusercontent.com identicons.github.com avatars.githubusercontent.com private-avatars.githubusercontent.com github-cloud.s3.amazonaws.com objects.githubusercontent.com release-assets.githubusercontent.com secured-user-images.githubusercontent.com/ user-images.githubusercontent.com/ private-user-images.githubusercontent.com opengraph.githubassets.com copilotprodattachments.blob.core.windows.net/github-production-copilot-attachments/ github-production-user-asset-6210df.s3.amazonaws.com customer-stories-feed.github.com spotlights-feed.github.com objects-origin.githubusercontent.com *.githubusercontent.com; manifest-src 'self'; media-src github.com user-images.githubusercontent.com/ secured-user-images.githubusercontent.com/ private-user-images.githubusercontent.com github-production-user-asset-6210df.s3.amazonaws.com gist.github.com; script-src github.githubassets.com; style-src 'unsafe-inline' github.githubassets.com; upgrade-insecure-requests; worker-src github.githubassets.com github.com/assets-cdn/worker/ github.com/assets/ gist.github.com/assets-cdn/worker/
server: github.com
content-encoding: gzip
accept-ranges: bytes
set-cookie: _gh_sess=1MNUTS5XNchw35TaKVYzQMx5t%2Fe40Mf5AF3YrAJibrYdPkeghPPqFN3edjgx1pxIOLxzeSt6NwWsbXuwKRk%2FPkRDXI%2BvwQpaQ%2BbDpHh85IO%2BtON5y9XSxUC8XHxZVKMQE5f0ebPV9OgKvah1KhgmsO3niw7IJg%2BUEKFquH5kRcLhzKIZ33F1aciBBaYUO53jWvXXqFAv0nJisVtcacJgVY%2B4RPQ9pnQwEBMLE6Q%2BdOpsSmioT4Xq3ASQc%2BeelbAqhJEWMatAzd%2Fq76wD7oRS0g%3D%3D--oIWFNl5bwkQhI1Nu--m1gw4ghXfxpIuEe5zYoTPA%3D%3D; Path=/; HttpOnly; Secure; SameSite=Lax
set-cookie: _octo=GH1.1.1985627880.1753049422; Path=/; Domain=github.com; Expires=Mon, 20 Jul 2026 22:10:22 GMT; Secure; SameSite=Lax
set-cookie: logged_in=no; Path=/; Domain=github.com; Expires=Mon, 20 Jul 2026 22:10:22 GMT; HttpOnly; Secure; SameSite=Lax
x-github-request-id: DAAA:10A6BA:11A8DD2:16D0C72:687D694E
Manage Google Nest speaker groups · custom-components/pyscript Wiki · GitHub
Skip to content
Navigation Menu
{{ message }}
-
Notifications
You must be signed in to change notification settings - Fork 55
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
])
You can’t perform that action at this time.