-
-
Save jjensn/83dd60d96330bbf66e58dfae336187bf to your computer and use it in GitHub Desktop.
Grouped light platform for Home Assistant
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import logging | |
# Import the device class from the component that you want to support | |
from homeassistant.components import light | |
from homeassistant.const import (STATE_OFF, STATE_ON, SERVICE_TURN_ON, | |
SERVICE_TURN_OFF, ATTR_ENTITY_ID) | |
from homeassistant.components.light import (SUPPORT_BRIGHTNESS, | |
SUPPORT_RGB_COLOR, | |
SUPPORT_COLOR_TEMP, | |
SUPPORT_TRANSITION) | |
CONF_NAME = 'name' | |
CONF_ENTITIES = 'entities' # | |
_LOGGER = logging.getLogger(__name__) | |
SUPPORT_GROUP_LIGHT = (SUPPORT_BRIGHTNESS | SUPPORT_RGB_COLOR | | |
SUPPORT_COLOR_TEMP | SUPPORT_TRANSITION) | |
def setup_platform(hass, config, add_devices, discovery_info=None): | |
"""Initialize grouped light platform.""" | |
name = config.get(CONF_NAME) | |
entity_ids = config.get(CONF_ENTITIES) | |
if name is None or entity_ids is None or len(entity_ids) == 0: | |
_LOGGER.error('Invalid config. Excepted %s and %s', CONF_NAME, CONF_ENTITIES) | |
return False | |
add_devices([GroupedLight(hass, name, entity_ids)]) | |
class GroupedLight(light.Light): | |
"""Represents an Grouped Light in Home Assistant.""" | |
def __init__(self, hass, name, entity_ids): | |
"""Initialize a Grouped Light.""" | |
self.hass = hass | |
self._name = name | |
self._entity_ids = entity_ids | |
@property | |
def name(self): | |
return self._name | |
@property | |
def brightness(self): | |
"""Brightness of the light group""" | |
brightness = 0 | |
for state in self._light_states(): | |
if not 'brightness' in state.attributes: | |
return None | |
brightness += state.attributes.get('brightness') | |
brightness = brightness / float(len(self._entity_ids)) | |
return brightness | |
@property | |
def color_temp(self): | |
"""Return the CT color value.""" | |
for state in self._light_states(): | |
if not 'color_temp' in state.attributes: | |
return None | |
return state.attributes.get('color_temp') | |
@property | |
def xy_color(self): | |
"""Return the XY color value.""" | |
for state in self._light_states(): | |
if not 'xy_color' in state.attributes: | |
return None | |
#return the first value we get since merging color values does not make sense | |
return state.attributes.get('xy_color') | |
@property | |
def rgb_color(self): | |
"""Return the RGB color value.""" | |
for state in self._light_states(): | |
if not 'rgb_color' in state.attributes: | |
return None | |
#return the first value we get since merging color values does not make sense | |
return state.attributes.get('rgb_color') | |
@property | |
def is_on(self): | |
"""If light is on.""" | |
for state in self._light_states(): | |
if state.state == STATE_ON: | |
return True | |
return False | |
@property | |
def supported_features(self): | |
"""Flag supported features.""" | |
return SUPPORT_GROUP_LIGHT | |
def _light_states(self): | |
"""The states that the group is tracking.""" | |
states = [] | |
for entity_id in self._entity_ids: | |
state = self.hass.states.get(entity_id) | |
if state is not None: | |
states.append(state) | |
return states | |
def turn_on(self, **kwargs): | |
"""Forward the turn_on command to all lights in the group""" | |
for entity_id in self._entity_ids: | |
kwargs[ATTR_ENTITY_ID] = entity_id | |
self.hass.services.call('light', SERVICE_TURN_ON, kwargs, blocking=True) | |
def turn_off(self, **kwargs): | |
"""Forward the turn_off command to all lights in the group""" | |
for entity_id in self._entity_ids: | |
kwargs[ATTR_ENTITY_ID] = entity_id | |
self.hass.services.call('light', SERVICE_TURN_OFF, kwargs, blocking=True) | |
Here is a version which updates when the other entities change. I also changed the way some properties are computed since the old version assumed all entities were in sync (or so it seamed)
import asyncio
import logging
# Import the device class from the component that you want to support
from homeassistant.core import callback
from homeassistant.components import light
from homeassistant.const import (STATE_OFF, STATE_ON, SERVICE_TURN_ON,
SERVICE_TURN_OFF, ATTR_ENTITY_ID)
from homeassistant.components.light import (SUPPORT_BRIGHTNESS,
SUPPORT_RGB_COLOR,
SUPPORT_COLOR_TEMP,
SUPPORT_TRANSITION)
from homeassistant.helpers.event import async_track_state_change
CONF_NAME = 'name'
CONF_ENTITIES = 'entities' #
_LOGGER = logging.getLogger(__name__)
SUPPORT_GROUP_LIGHT = (SUPPORT_BRIGHTNESS | SUPPORT_RGB_COLOR |
SUPPORT_COLOR_TEMP | SUPPORT_TRANSITION)
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Initialize grouped light platform."""
name = config.get(CONF_NAME)
entity_ids = config.get(CONF_ENTITIES)
if entity_ids is None:
_LOGGER.error('No entity_ids')
return False
if name is None or entity_ids is None or len(entity_ids) == 0:
_LOGGER.error('Invalid config. Excepted %s and %s', CONF_NAME, CONF_ENTITIES)
return False
lights = [GroupedLight(hass, name, entity_ids)]
async_add_devices(lights)
return True
class GroupedLight(light.Light):
"""Represents an Grouped Light in Home Assistant."""
def __init__(self, hass, name, entity_ids):
"""Initialize a Grouped Light."""
self.hass = hass
self._name = name
self._entity_ids = entity_ids
self._tracking = tuple(ent_id.lower() for ent_id in entity_ids)
#@callback
def async_state_changed_listener(entity_id, old_state, new_state):
"""Respond to a member state changing."""
self.hass.async_add_job(self.async_update_ha_state, True)
async_track_state_change(
self.hass, self._tracking, async_state_changed_listener
)
@property
def name(self):
return self._name
@property
def brightness(self):
"""Brightness of the light group"""
brightness = 0
count = 0
for state in self._light_states():
if 'brightness' in state.attributes and state.state == STATE_ON:
brightness += state.attributes.get('brightness')
count += 1
brightness = brightness / float(count or 1)
return brightness
@property
def color_temp(self):
"""Return the CT color value."""
for state in self._light_states():
if 'color_temp' in state.attributes and state.state == STATE_ON:
return state.attributes.get('color_temp')
return None
@property
def xy_color(self):
"""Return the XY color value."""
for state in self._light_states():
if 'xy_color' in state.attributes and state.state == STATE_ON:
return state.attributes.get('xy_color')
return None
@property
def rgb_color(self):
"""Return the RGB color value."""
for state in self._light_states():
if 'rgb_color' in state.attributes and state.state == STATE_ON:
return state.attributes.get('rgb_color')
return None
@property
def is_on(self):
"""If light is on."""
for state in self._light_states():
if state.state == STATE_ON:
return True
return False
@property
def supported_features(self):
"""Flag supported features."""
return SUPPORT_GROUP_LIGHT
def _light_states(self):
"""The states that the group is tracking."""
states = []
for entity_id in self._entity_ids:
state = self.hass.states.get(entity_id)
if state is not None:
states.append(state)
return states
def turn_on(self, **kwargs):
"""Forward the turn_on command to all lights in the group"""
for entity_id in self._entity_ids:
kwargs[ATTR_ENTITY_ID] = entity_id
self.hass.services.call('light', SERVICE_TURN_ON, kwargs, blocking=True)
def turn_off(self, **kwargs):
"""Forward the turn_off command to all lights in the group"""
for entity_id in self._entity_ids:
kwargs[ATTR_ENTITY_ID] = entity_id
self.hass.services.call('light', SERVICE_TURN_OFF, kwargs, blocking=True)
Wow I had no idea people were still using this
I have created a repo and will take everyone's PR requests:
https://github.com/jjensn/home-assistant-grouped-lights
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Great work with this custom component. Works very well. Shame it is not part of home-assistant by default.
Is it possible to add an event callback/listener so that if all the lights in the group are turned off, the grouped_light will change its state to off (like how the normal group component works)? Right now, if I turn off the individual lights instead of the grouped_light, the grouped_light for those individual lights are still considered to be "on".