Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for scenes over multiple hue bridges #19997

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 33 additions & 1 deletion homeassistant/components/hue/__init__.py
Expand Up @@ -6,6 +6,7 @@
"""
import ipaddress
import logging
import asyncio

import voluptuous as vol

Expand All @@ -15,7 +16,8 @@
config_validation as cv, device_registry as dr)

from .const import DOMAIN
from .bridge import HueBridge
from .bridge import (HueBridge, SERVICE_HUE_SCENE,
SCENE_SCHEMA, ATTR_GROUP_NAME, ATTR_SCENE_NAME)
# Loading the config flow file will register the flow
from .config_flow import configured_hosts

Expand Down Expand Up @@ -54,13 +56,42 @@

async def async_setup(hass, config):
"""Set up the Hue platform."""
async def hue_activate_scene(call, skip_reload=True):
"""Handle activation of Hue scene."""
# Get parameters
group_name = call.data[ATTR_GROUP_NAME]
scene_name = call.data[ATTR_SCENE_NAME]

# Call the set scene function on each bridge
tasks = [bridge.hue_activate_scene(call,
updated=skip_reload,
hide_warnings=skip_reload)
for bridge in hass.data[DOMAIN].values()
if isinstance(bridge, HueBridge)]
results = await asyncio.gather(*tasks)

# Did *any* bridge succeed? If not, refresh / retry
# Note that we'll get a "None" value for a successful call
if None not in results:
if skip_reload:
return await hue_activate_scene(call,
skip_reload=False)
_LOGGER.warning("No bridge was able to activate "
"scene %s in group %s", scene_name, group_name)

# Set up the Hue platform.
conf = config.get(DOMAIN)
if conf is None:
conf = {}

hass.data[DOMAIN] = {}
configured = configured_hosts(hass)

# Register a local handler for scene activation
hass.services.async_register(
DOMAIN, SERVICE_HUE_SCENE, hue_activate_scene,
schema=SCENE_SCHEMA)

# User has configured bridges
if CONF_BRIDGES not in conf:
return True
Expand Down Expand Up @@ -134,4 +165,5 @@ async def async_setup_entry(hass, entry):
async def async_unload_entry(hass, entry):
"""Unload a config entry."""
bridge = hass.data[DOMAIN].pop(entry.data['host'])
hass.services.async_remove(DOMAIN, SERVICE_HUE_SCENE)
return await bridge.async_reset()
26 changes: 12 additions & 14 deletions homeassistant/components/hue/bridge.py
Expand Up @@ -82,10 +82,6 @@ async def retry_setup(_now):
hass.async_create_task(hass.config_entries.async_forward_entry_setup(
self.config_entry, 'light'))

hass.services.async_register(
DOMAIN, SERVICE_HUE_SCENE, self.hue_activate_scene,
schema=SCENE_SCHEMA)

return True

async def async_reset(self):
Expand All @@ -109,14 +105,13 @@ async def async_reset(self):
if self.api is None:
return True

self.hass.services.async_remove(DOMAIN, SERVICE_HUE_SCENE)

# If setup was successful, we set api variable, forwarded entry and
# register service
return await self.hass.config_entries.async_forward_entry_unload(
self.config_entry, 'light')

async def hue_activate_scene(self, call, updated=False):
async def hue_activate_scene(self, call, updated=False,
hide_warnings=False):
"""Service to call directly into bridge to set scenes."""
group_name = call.data[ATTR_GROUP_NAME]
scene_name = call.data[ATTR_SCENE_NAME]
Expand All @@ -137,18 +132,21 @@ async def hue_activate_scene(self, call, updated=False):
if not updated and (group is None or scene is None):
await self.api.groups.update()
await self.api.scenes.update()
await self.hue_activate_scene(call, updated=True)
return
return await self.hue_activate_scene(call, updated=True)

if group is None:
LOGGER.warning('Unable to find group %s', group_name)
return
if not hide_warnings:
LOGGER.warning('Unable to find group %s'
' on bridge %s', group_name, self.host)
return False

if scene is None:
LOGGER.warning('Unable to find scene %s', scene_name)
return
if not hide_warnings:
LOGGER.warning('Unable to find scene %s'
' on bridge %s', scene_name, self.host)
return False

await group.set_action(scene=scene.id)
return await group.set_action(scene=scene.id)


async def get_bridge(hass, host, username=None):
Expand Down
2 changes: 0 additions & 2 deletions tests/components/hue/test_bridge.py
Expand Up @@ -102,12 +102,10 @@ async def test_reset_unloads_entry_if_setup():
with patch.object(bridge, 'get_bridge', return_value=mock_coro(Mock())):
assert await hue_bridge.async_setup() is True

assert len(hass.services.async_register.mock_calls) == 1
assert len(hass.config_entries.async_forward_entry_setup.mock_calls) == 1

hass.config_entries.async_forward_entry_unload.return_value = \
mock_coro(True)
assert await hue_bridge.async_reset()

assert len(hass.config_entries.async_forward_entry_unload.mock_calls) == 1
assert len(hass.services.async_remove.mock_calls) == 1