8000 2021.12.7 by frenck · Pull Request #63004 · home-assistant/core · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

2021.12.7 #63004

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

Merged
merged 18 commits into from
Dec 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion homeassistant/components/flux_led/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Flux LED/MagicHome",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/flux_led",
"requirements": ["flux_led==0.27.13"],
"requirements": ["flux_led==0.27.21"],
"quality_scale": "platinum",
"codeowners": ["@icemanch"],
"iot_class": "local_push",
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/frontend/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Home Assistant Frontend",
"documentation": "https://www.home-assistant.io/integrations/frontend",
"requirements": [
"home-assistant-frontend==20211227.0"
"home-assistant-frontend==20211229.0"
],
"dependencies": [
"api",
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/hue/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Philips Hue",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/hue",
"requirements": ["aiohue==3.0.10"],
"requirements": ["aiohue==3.0.11"],
"ssdp": [
{
"manufacturer": "Royal Philips Electronics",
Expand Down
83 changes: 60 additions & 23 deletions homeassistant/components/hue/v2/group.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Support for Hue groups (room/zone)."""
from __future__ import annotations

import asyncio
from typing import Any

from aiohue.v2 import HueBridgeV2
Expand All @@ -18,6 +19,7 @@
COLOR_MODE_COLOR_TEMP,
COLOR_MODE_ONOFF,
COLOR_MODE_XY,
FLASH_SHORT,
SUPPORT_FLASH,
SUPPORT_TRANSITION,
LightEntity,
Expand All @@ -29,14 +31,17 @@
from ..bridge import HueBridge
from ..const import CONF_ALLOW_HUE_GROUPS, DOMAIN
from .entity import HueBaseEntity
from .helpers import normalize_hue_brightness, normalize_hue_transition
from .helpers import (
normalize_hue_brightness,
normalize_hue_colortemp,
normalize_hue_transition,
)

ALLOWED_ERRORS = [
"device (groupedLight) has communication issues, command (on) may not have effect",
'device (groupedLight) is "soft off", command (on) may not have effect',
"device (light) has communication issues, command (on) may not have effect",
'device (light) is "soft off", command (on) may not have effect',
"attribute (supportedAlertActions) cannot be written",
]


Expand Down Expand Up @@ -150,10 +155,15 @@ async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on."""
transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
xy_color = kwargs.get(ATTR_XY_COLOR)
color_temp = kwargs.get(ATTR_COLOR_TEMP)
color_temp = normalize_hue_colortemp(kwargs.get(ATTR_COLOR_TEMP))
brightness = normalize_hue_brightness(kwargs.get(ATTR_BRIGHTNESS))
flash = kwargs.get(ATTR_FLASH)

if flash is not None:
await self.async_set_flash(flash)
# flash can not be sent with other commands at the same time
return

# NOTE: a grouped_light can only handle turn on/off
# To set other features, you'll have to control the attached lights
if (
Expand All @@ -173,22 +183,32 @@ async def async_turn_on(self, **kwargs: Any) -> None:

# redirect all other feature commands to underlying lights
# note that this silently ignores params sent to light that are not supported
for light in self.controller.get_lights(self.resource.id):
await self.bridge.async_request_call(
self.api.lights.set_state,
light.id,
on=True,
brightness=brightness if light.supports_dimming else None,
color_xy=xy_color if light.supports_color else None,
color_temp=color_temp if light.supports_color_temperature else None,
transition_time=transition,
alert=AlertEffectType.BREATHE if flash is not None else None,
allowed_errors=ALLOWED_ERRORS,
)
await asyncio.gather(
*[
self.bridge.async_request_call(
self.api.lights.set_state,
light.id,
on=True,
brightness=brightness if light.supports_dimming else None,
color_xy=xy_color if light.supports_color else None,
color_temp=color_temp if light.supports_color_temperature else None,
transition_time=transition,
alert=AlertEffectType.BREATHE if flash is not None else None,
allowed_errors=ALLOWED_ERRORS,
)
for light in self.controller.get_lights(self.resource.id)
]
)

async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the light off."""
transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
flash = kwargs.get(ATTR_FLASH)

if flash is not None:
await self.async_set_flash(flash)
# flash can not be sent with other commands at the same time
return

# NOTE: a grouped_light can only handle turn on/off
# To set other features, you'll have to control the attached lights
Expand All @@ -202,14 +222,31 @@ async def async_turn_off(self, **kwargs: Any) -> None:
return

# redirect all other feature commands to underlying lights
for light in self.controller.get_lights(self.resource.id):
await self.bridge.async_request_call(
self.api.lights.set_state,
light.id,
on=False,
transition_time=transition,
allowed_errors=ALLOWED_ERRORS,
)
await asyncio.gather(
*[
self.bridge.async_request_call(
self.api.lights.set_state,
light.id,
on=False,
transition_time=transition,
allowed_errors=ALLOWED_ERRORS,
)
for light in self.controller.get_lights(self.resource.id)
]
)

async def async_set_flash(self, flash: str) -> None:
"""Send flash command to light."""
await asyncio.gather(
*[
self.bridge.async_request_call(
self.api.lights.set_flash,
id=light.id,
short=flash == FLASH_SHORT,
)
for light in self.controller.get_lights(self.resource.id)
]
)

@callback
def on_update(self) -> None:
Expand Down
14 changes: 12 additions & 2 deletions homeassistant/components/hue/v2/helpers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""Helper functions for Philips Hue v2."""
from __future__ import annotations


def normalize_hue_brightness(brightness):
def normalize_hue_brightness(brightness: float | None) -> float | None:
"""Return calculated brightness values."""
if brightness is not None:
# Hue uses a range of [0, 100] to control brightness.
Expand All @@ -10,10 +11,19 @@ def normalize_hue_brightness(brightness):
return brightness


def normalize_hue_transition(transition):
def normalize_hue_transition(transition: float | None) -> float | None:
"""Return rounded transition values."""
if transition is not None:
# hue transition duration is in milliseconds and round them to 100ms
transition = int(round(transition, 1) * 1000)

return transition


def normalize_hue_colortemp(colortemp: int | None) -> int | None:
"""Return color temperature within Hue's ranges."""
if colortemp is not None:
# Hue only accepts a range between 153..500
colortemp = min(colortemp, 500)
colortemp = max(colortemp, 153)
return colortemp
21 changes: 3 additions & 18 deletions homeassistant/components/hue/v2/hue_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from aiohue.v2 import HueBridgeV2
from aiohue.v2.controllers.events import EventType
from aiohue.v2.models.button import Button, ButtonEvent
from aiohue.v2.models.button import Button

from homeassistant.const import CONF_DEVICE_ID, CONF_ID, CONF_TYPE, CONF_UNIQUE_ID
from homeassistant.core import callback
Expand All @@ -27,11 +27,6 @@ async def async_setup_hue_events(bridge: "HueBridge"):
api: HueBridgeV2 = bridge.api # to satisfy typing
conf_entry = bridge.config_entry
dev_reg = device_registry.async_get(hass)
last_state = {
x.id: x.button.last_event
for x in api.sensors.button.items
if x.button is not None
}

# at this time the `button` resource is the only source of hue events
btn_controller = api.sensors.button
Expand All @@ -45,26 +40,16 @@ def handle_button_event(evt_type: EventType, hue_resource: Button) -> None:
if hue_resource.button is None:
return

cur_event = hue_resource.button.last_event
last_event = last_state.get(hue_resource.id)
# ignore the event if the last_event value is exactly the same
# this may happen if some other metadata of the button resource is adjusted
if cur_event == last_event:
return
if cur_event != ButtonEvent.REPEAT:
# do not store repeat event
last_state[hue_resource.id] = cur_event

hue_device = btn_controller.get_device(hue_resource.id)
device = dev_reg.async_get_device({(DOMAIN, hue_device.id)})

# Fire event
data = {
# send slugified entity name as id = backwards compatibility with previous version
CONF_ID: slugify(f"{hue_device.metadata.name}: Button"),
CONF_ID: slugify(f"{hue_device.metadata.name} Button"),
CONF_DEVICE_ID: device.id, # type: ignore
CONF_UNIQUE_ID: hue_resource.id,
CONF_TYPE: cur_event.value,
CONF_TYPE: hue_resource.button.last_event.value,
CONF_SUBTYPE: hue_resource.metadata.control_id,
}
hass.bus.async_fire(ATTR_HUE_EVENT, data)
Expand Down
39 changes: 32 additions & 7 deletions homeassistant/components/hue/v2/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from aiohue import HueBridgeV2
from aiohue.v2.controllers.events import EventType
from aiohue.v2.controllers.lights import LightsController
from aiohue.v2.models.feature import AlertEffectType
from aiohue.v2.models.light import Light

from homeassistant.components.light import (
Expand All @@ -19,6 +18,7 @@
COLOR_MODE_COLOR_TEMP,
COLOR_MODE_ONOFF,
COLOR_MODE_XY,
FLASH_SHORT,
SUPPORT_FLASH,
SUPPORT_TRANSITION,
LightEntity,
Expand All @@ -30,12 +30,15 @@
from ..bridge import HueBridge
from ..const import DOMAIN
from .entity import HueBaseEntity
from .helpers import normalize_hue_brightness, normalize_hue_transition
from .helpers import (
normalize_hue_brightness,
normalize_hue_colortemp,
normalize_hue_transition,
)

ALLOWED_ERRORS = [
"device (light) has communication issues, command (on) may not have effect",
'device (light) is "soft off", command (on) may not have effect',
"attribute (supportedAlertActions) cannot be written",
]


Expand Down Expand Up @@ -73,7 +76,8 8000 @@ def __init__(
) -> None:
"""Initialize the light."""
super().__init__(bridge, controller, resource)
self._attr_supported_features |= SUPPORT_FLASH
if self.resource.alert and self.resource.alert.action_values:
self._attr_supported_features |= SUPPORT_FLASH
self.resource = resource
self.controller = controller
self._supported_color_modes = set()
Expand Down Expand Up @@ -158,10 +162,18 @@ async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on."""
transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
xy_color = kwargs.get(ATTR_XY_COLOR)
color_temp = kwargs.get(ATTR_COLOR_TEMP)
color_temp = normalize_hue_colortemp(kwargs.get(ATTR_COLOR_TEMP))
brightness = normalize_hue_brightness(kwargs.get(ATTR_BRIGHTNESS))
flash = kwargs.get(ATTR_FLASH)

if flash is not None:
await self.async_set_flash(flash)
# flash can not be sent with other commands at the same time or result will be flaky
# Hue's default behavior is that a light returns to its previous state for short
# flash (identify) and the light is kept turned on for long flash (breathe effect)
# Why is this flash alert/effect hidden in the turn_on/off commands ?
return

await self.bridge.async_request_call(
self.controller.set_state,
id=self.resource.id,
Expand All @@ -170,7 +182,6 @@ async def async_turn_on(self, **kwargs: Any) -> None:
color_xy=xy_color,
color_temp=color_temp,
transition_time=transition,
alert=AlertEffectType.BREATHE if flash is not None else None,
allowed_errors=ALLOWED_ERRORS,
)

Expand All @@ -179,11 +190,25 @@ async def async_turn_off(self, **kwargs: Any) -> None:
transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
flash = kwargs.get(ATTR_FLASH)

if flash is not None:
await self.async_set_flash(flash)
# flash can not be sent with other commands at the same time or result will be flaky
# Hue's default behavior is that a light returns to its previous state for short
# flash (identify) and the light is kept turned on for long flash (breathe effect)
return

await self.bridge.async_request_call(
self.controller.set_state,
id=self.resource.id,
on=False,
transition_time=transition,
alert=AlertEffectType.BREATHE if flash is not None else None,
allowed_errors=ALLOWED_ERRORS,
)

async def async_set_flash(self, flash: str) -> None:
"""Send flash command to light."""
await self.bridge.async_request_call(
self.controller.set_flash,
id=self.resource.id,
short=flash == FLASH_SHORT,
)
9 changes: 9 additions & 0 deletions homeassistant/components/nuki/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
DOMAIN,
ERROR_STATES,
)
from .helpers import parse_id

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -80,6 +81,14 @@ async def async_setup_entry(hass, entry):

hass.data.setdefault(DOMAIN, {})

# Migration of entry unique_id
if isinstance(entry.unique_id, int):
new_id = parse_id(entry.unique_id)
params = {"unique_id": new_id}
if entry.title == entry.unique_id:
params["title"] = new_id
hass.config_entries.async_update_entry(entry, **params)

try:
bridge = await hass.async_add_executor_job(
NukiBridge,
Expand Down
Loading
0