Free color selection for Fritz!Smarthome lights (#66213)

* Fritz light free color selection

* Use setcolor as fallback

* better debug log message

Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com>

* change if-clause

Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com>
This commit is contained in:
Lars 2022-05-25 09:28:36 +02:00 committed by GitHub
parent 1e4690626f
commit 804c888098
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 11 deletions

View File

@ -3,6 +3,8 @@ from __future__ import annotations
from typing import Any
from requests.exceptions import HTTPError
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
@ -21,6 +23,7 @@ from .const import (
COLOR_TEMP_MODE,
CONF_COORDINATOR,
DOMAIN as FRITZBOX_DOMAIN,
LOGGER,
)
from .coordinator import FritzboxDataUpdateCoordinator
@ -135,16 +138,33 @@ class FritzboxLight(FritzBoxEntity, LightEntity):
level = kwargs[ATTR_BRIGHTNESS]
await self.hass.async_add_executor_job(self.device.set_level, level)
if kwargs.get(ATTR_HS_COLOR) is not None:
hass_hue = int(kwargs[ATTR_HS_COLOR][0])
hass_saturation = round(kwargs[ATTR_HS_COLOR][1] * 255.0 / 100.0)
# find supported hs values closest to what user selected
hue = min(self._supported_hs.keys(), key=lambda x: abs(x - hass_hue))
saturation = min(
self._supported_hs[hue], key=lambda x: abs(x - hass_saturation)
)
await self.hass.async_add_executor_job(
self.device.set_color, (hue, saturation)
)
# Try setunmappedcolor first. This allows free color selection,
# but we don't know if its supported by all devices.
try:
# HA gives 0..360 for hue, fritz light only supports 0..359
unmapped_hue = int(kwargs[ATTR_HS_COLOR][0] % 360)
unmapped_saturation = round(kwargs[ATTR_HS_COLOR][1] * 255.0 / 100.0)
await self.hass.async_add_executor_job(
self.device.set_unmapped_color, (unmapped_hue, unmapped_saturation)
)
# This will raise 400 BAD REQUEST if the setunmappedcolor is not available
except HTTPError as err:
if err.response.status_code != 400:
raise
LOGGER.debug(
"fritzbox does not support method 'setunmappedcolor', fallback to 'setcolor'"
)
# find supported hs values closest to what user selected
hue = min(
self._supported_hs.keys(), key=lambda x: abs(x - unmapped_hue)
)
saturation = min(
self._supported_hs[hue],
key=lambda x: abs(x - unmapped_saturation),
)
await self.hass.async_add_executor_job(
self.device.set_color, (hue, saturation)
)
if kwargs.get(ATTR_COLOR_TEMP) is not None:
kelvin = color.color_temperature_kelvin_to_mired(kwargs[ATTR_COLOR_TEMP])

View File

@ -113,7 +113,34 @@ async def test_turn_on_color(hass: HomeAssistant, fritz: Mock):
assert await setup_config_entry(
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
)
assert await hass.services.async_call(
DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_BRIGHTNESS: 100, ATTR_HS_COLOR: (100, 70)},
True,
)
assert device.set_state_on.call_count == 1
assert device.set_level.call_count == 1
assert device.set_unmapped_color.call_count == 1
async def test_turn_on_color_unsupported_api_method(hass: HomeAssistant, fritz: Mock):
"""Test turn device on in mapped color mode if unmapped is not supported."""
device = FritzDeviceLightMock()
device.get_color_temps.return_value = [2700, 6500]
device.get_colors.return_value = {
"Red": [("100", "70", "10"), ("100", "50", "10"), ("100", "30", "10")]
}
mockresponse = Mock()
mockresponse.status_code = 400
error = HTTPError("Bad Request")
error.response = mockresponse
device.set_unmapped_color.side_effect = error
assert await setup_config_entry(
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
)
assert await hass.services.async_call(
DOMAIN,
SERVICE_TURN_ON,
@ -135,7 +162,6 @@ async def test_turn_off(hass: HomeAssistant, fritz: Mock):
assert await setup_config_entry(
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
)
assert await hass.services.async_call(
DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: ENTITY_ID}, True
)