mirror of
https://github.com/home-assistant/core.git
synced 2025-08-10 08:05:06 +02:00
Fixes
This commit is contained in:
@@ -7,7 +7,7 @@ https://home-assistant.io/components/light.group/
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import itertools
|
import itertools
|
||||||
from typing import List, Tuple, Optional, Iterator, Any
|
from typing import List, Tuple, Optional, Iterator, Any, Callable
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
@@ -75,8 +75,8 @@ class GroupLight(light.Light):
|
|||||||
"""Register callbacks"""
|
"""Register callbacks"""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_state_changed_listener(self, entity_id: str,
|
def async_state_changed_listener(entity_id: str, old_state: State,
|
||||||
old_state: State, new_state: State):
|
new_state: State):
|
||||||
"""Handle child updates."""
|
"""Handle child updates."""
|
||||||
self.async_schedule_update_ha_state(True)
|
self.async_schedule_update_ha_state(True)
|
||||||
|
|
||||||
@@ -168,7 +168,7 @@ class GroupLight(light.Light):
|
|||||||
payload = deepcopy(kwargs)
|
payload = deepcopy(kwargs)
|
||||||
payload[ATTR_ENTITY_ID] = entity_id
|
payload[ATTR_ENTITY_ID] = entity_id
|
||||||
tasks.append(self.hass.services.async_call(
|
tasks.append(self.hass.services.async_call(
|
||||||
'light', SERVICE_TURN_OFF, payload, blocking=True))
|
'light', service, payload, blocking=True))
|
||||||
|
|
||||||
if tasks:
|
if tasks:
|
||||||
await asyncio.wait(tasks, loop=self.hass.loop)
|
await asyncio.wait(tasks, loop=self.hass.loop)
|
||||||
@@ -184,20 +184,22 @@ class GroupLight(light.Light):
|
|||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Query all members and determine the group state."""
|
"""Query all members and determine the group state."""
|
||||||
states = self._child_states()
|
states = self._child_states()
|
||||||
|
on_states = [state for state in states if state.state == STATE_ON]
|
||||||
|
|
||||||
self._state = _determine_on_off_state(states)
|
self._state = _determine_on_off_state(states)
|
||||||
self._brightness = _reduce_attribute(states, 'brightness')
|
self._brightness = _reduce_attribute(on_states, 'brightness')
|
||||||
self._xy_color = _reduce_attribute(states, 'xy_color')
|
self._xy_color = _reduce_attribute(
|
||||||
self._rgb_color = _reduce_attribute(states, 'rgb_color')
|
on_states, 'xy_color', reduce=_average_tuple)
|
||||||
self._color_temp = _reduce_attribute(states, 'color_temp')
|
self._rgb_color = _reduce_attribute(
|
||||||
|
on_states, 'rgb_color', reduce=_average_tuple)
|
||||||
|
self._white_value = _reduce_attribute(on_states, 'white_value')
|
||||||
|
self._color_temp = _reduce_attribute(on_states, 'color_temp')
|
||||||
self._min_mireds = _reduce_attribute(
|
self._min_mireds = _reduce_attribute(
|
||||||
states, 'min_mireds', default=154, force_on=False)
|
states, 'min_mireds', default=154, reduce=min)
|
||||||
self._max_mireds = _reduce_attribute(
|
self._max_mireds = _reduce_attribute(
|
||||||
states, 'max_mireds', default=500, force_on=False)
|
states, 'max_mireds', default=500, reduce=max)
|
||||||
self._white_value = _reduce_attribute(states, 'white_value')
|
|
||||||
|
|
||||||
all_effect_lists = list(
|
all_effect_lists = list(_find_state_attributes(states, 'effect_list'))
|
||||||
_find_state_attributes(states, 'effect_list', force_on=False))
|
|
||||||
self._effect_list = None
|
self._effect_list = None
|
||||||
if all_effect_lists:
|
if all_effect_lists:
|
||||||
# Merge all effects from all effect_lists with a union merge.
|
# Merge all effects from all effect_lists with a union merge.
|
||||||
@@ -206,14 +208,13 @@ class GroupLight(light.Light):
|
|||||||
all_effects = list(_find_state_attributes(states, 'effect'))
|
all_effects = list(_find_state_attributes(states, 'effect'))
|
||||||
self._effect = None
|
self._effect = None
|
||||||
if all_effects:
|
if all_effects:
|
||||||
flat_effects = list(itertools.chain(*all_effect_lists))
|
flat_effects = list(itertools.chain(all_effects))
|
||||||
# Report the most common effect.
|
# Report the most common effect.
|
||||||
effects_count = Counter(flat_effects)
|
effects_count = Counter(flat_effects)
|
||||||
self._effect = effects_count.most_common(1)[0][0]
|
self._effect = effects_count.most_common(1)[0][0]
|
||||||
|
|
||||||
self._supported_features = 0
|
self._supported_features = 0
|
||||||
for support in _find_state_attributes(
|
for support in _find_state_attributes(states, 'supported_features'):
|
||||||
states, 'supported_features', force_on=False):
|
|
||||||
# Merge supported features by emulating support for every feature
|
# Merge supported features by emulating support for every feature
|
||||||
# we find.
|
# we find.
|
||||||
self._supported_features |= support
|
self._supported_features |= support
|
||||||
@@ -228,27 +229,37 @@ class GroupLight(light.Light):
|
|||||||
|
|
||||||
|
|
||||||
def _find_state_attributes(states: List[State],
|
def _find_state_attributes(states: List[State],
|
||||||
key: str,
|
key: str) -> Iterator[Any]:
|
||||||
force_on: bool = True) -> Iterator[Any]:
|
"""Find attributes with matching key from states."""
|
||||||
"""Find attributes with matching key from states.
|
|
||||||
|
|
||||||
Only return attributes of enabled lights when force_on is True.
|
|
||||||
"""
|
|
||||||
for state in states:
|
for state in states:
|
||||||
assume_on = (not force_on) or state.state == STATE_ON
|
if key in state.attributes:
|
||||||
if assume_on and key in state.attributes:
|
|
||||||
yield state.attributes.get(key)
|
yield state.attributes.get(key)
|
||||||
|
|
||||||
|
|
||||||
|
def _average(*args):
|
||||||
|
"""Return the average of the supplied values."""
|
||||||
|
return sum(args) / len(args)
|
||||||
|
|
||||||
|
|
||||||
|
def _average_tuple(*args):
|
||||||
|
"""Return the average values along the columns of the supplied values."""
|
||||||
|
return tuple(sum(l) / len(l) for l in zip(*args))
|
||||||
|
|
||||||
|
|
||||||
def _reduce_attribute(states: List[State],
|
def _reduce_attribute(states: List[State],
|
||||||
key: str,
|
key: str,
|
||||||
default: Optional[Any] = None,
|
default: Optional[Any] = None,
|
||||||
force_on: bool = True) -> Any:
|
reduce: Callable[..., Any] = _average) -> Any:
|
||||||
"""Find the first attribute matching key from states.
|
"""Find the first attribute matching key from states.
|
||||||
|
|
||||||
If none are found, return default.
|
If none are found, return default.
|
||||||
"""
|
"""
|
||||||
return next(_find_state_attributes(states, key, force_on), default)
|
attrs = list(_find_state_attributes(states, key))
|
||||||
|
|
||||||
|
if not attrs:
|
||||||
|
return default
|
||||||
|
|
||||||
|
return reduce(*attrs)
|
||||||
|
|
||||||
|
|
||||||
def _determine_on_off_state(states: List[State]) -> str:
|
def _determine_on_off_state(states: List[State]) -> str:
|
||||||
|
Reference in New Issue
Block a user