Check for fullcolorsupport in fritzbox light (#136850)

This commit is contained in:
Lars 2025-01-29 17:15:54 +01:00 committed by GitHub
parent b2ec72d75f
commit fa6df1cc25
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 14 additions and 34 deletions

View File

@ -4,8 +4,6 @@ from __future__ import annotations
from typing import Any, cast from typing import Any, cast
from requests.exceptions import HTTPError
from homeassistant.components.light import ( from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP_KELVIN, ATTR_COLOR_TEMP_KELVIN,
@ -124,27 +122,22 @@ class FritzboxLight(FritzBoxDeviceEntity, LightEntity):
level = kwargs[ATTR_BRIGHTNESS] level = kwargs[ATTR_BRIGHTNESS]
await self.hass.async_add_executor_job(self.data.set_level, level, True) await self.hass.async_add_executor_job(self.data.set_level, level, True)
if kwargs.get(ATTR_HS_COLOR) is not None: if kwargs.get(ATTR_HS_COLOR) is not None:
# Try setunmappedcolor first. This allows free color selection, # HA gives 0..360 for hue, fritz light only supports 0..359
# but we don't know if its supported by all devices. unmapped_hue = int(kwargs[ATTR_HS_COLOR][0] % 360)
try: unmapped_saturation = round(
# HA gives 0..360 for hue, fritz light only supports 0..359 cast(float, kwargs[ATTR_HS_COLOR][1]) * 255.0 / 100.0
unmapped_hue = int(kwargs[ATTR_HS_COLOR][0] % 360) )
unmapped_saturation = round( if self.data.fullcolorsupport:
cast(float, kwargs[ATTR_HS_COLOR][1]) * 255.0 / 100.0 LOGGER.debug("device has fullcolorsupport, using 'setunmappedcolor'")
)
await self.hass.async_add_executor_job( await self.hass.async_add_executor_job(
self.data.set_unmapped_color, self.data.set_unmapped_color,
(unmapped_hue, unmapped_saturation), (unmapped_hue, unmapped_saturation),
0, 0,
True, True,
) )
# This will raise 400 BAD REQUEST if the setunmappedcolor is not available else:
except HTTPError as err:
if err.response.status_code != 400:
raise
LOGGER.debug( LOGGER.debug(
"fritzbox does not support method 'setunmappedcolor', fallback to" "device has no fullcolorsupport, using supported colors with 'setcolor'"
" 'setcolor'"
) )
# find supported hs values closest to what user selected # find supported hs values closest to what user selected
hue = min( hue = min(

View File

@ -3,7 +3,6 @@
from datetime import timedelta from datetime import timedelta
from unittest.mock import Mock, call from unittest.mock import Mock, call
import pytest
from requests.exceptions import HTTPError from requests.exceptions import HTTPError
from homeassistant.components.fritzbox.const import ( from homeassistant.components.fritzbox.const import (
@ -166,6 +165,7 @@ async def test_turn_on_color(hass: HomeAssistant, fritz: Mock) -> None:
device.get_colors.return_value = { device.get_colors.return_value = {
"Red": [("100", "70", "10"), ("100", "50", "10"), ("100", "30", "10")] "Red": [("100", "70", "10"), ("100", "50", "10"), ("100", "30", "10")]
} }
device.fullcolorsupport = True
assert await setup_config_entry( assert await setup_config_entry(
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
) )
@ -178,13 +178,14 @@ async def test_turn_on_color(hass: HomeAssistant, fritz: Mock) -> None:
assert device.set_state_on.call_count == 1 assert device.set_state_on.call_count == 1
assert device.set_level.call_count == 1 assert device.set_level.call_count == 1
assert device.set_unmapped_color.call_count == 1 assert device.set_unmapped_color.call_count == 1
assert device.set_color.call_count == 0
assert device.set_level.call_args_list == [call(100, True)] assert device.set_level.call_args_list == [call(100, True)]
assert device.set_unmapped_color.call_args_list == [ assert device.set_unmapped_color.call_args_list == [
call((100, round(70 * 255.0 / 100.0)), 0, True) call((100, round(70 * 255.0 / 100.0)), 0, True)
] ]
async def test_turn_on_color_unsupported_api_method( async def test_turn_on_color_no_fullcolorsupport(
hass: HomeAssistant, fritz: Mock hass: HomeAssistant, fritz: Mock
) -> None: ) -> None:
"""Test turn device on in mapped color mode if unmapped is not supported.""" """Test turn device on in mapped color mode if unmapped is not supported."""
@ -193,16 +194,11 @@ async def test_turn_on_color_unsupported_api_method(
device.get_colors.return_value = { device.get_colors.return_value = {
"Red": [("100", "70", "10"), ("100", "50", "10"), ("100", "30", "10")] "Red": [("100", "70", "10"), ("100", "50", "10"), ("100", "30", "10")]
} }
device.fullcolorsupport = False
assert await setup_config_entry( assert await setup_config_entry(
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
) )
# test fallback to `setcolor`
error = HTTPError("Bad Request")
error.response = Mock()
error.response.status_code = 400
device.set_unmapped_color.side_effect = error
await hass.services.async_call( await hass.services.async_call(
LIGHT_DOMAIN, LIGHT_DOMAIN,
SERVICE_TURN_ON, SERVICE_TURN_ON,
@ -212,19 +208,10 @@ async def test_turn_on_color_unsupported_api_method(
assert device.set_state_on.call_count == 1 assert device.set_state_on.call_count == 1
assert device.set_level.call_count == 1 assert device.set_level.call_count == 1
assert device.set_color.call_count == 1 assert device.set_color.call_count == 1
assert device.set_unmapped_color.call_count == 0
assert device.set_level.call_args_list == [call(100, True)] assert device.set_level.call_args_list == [call(100, True)]
assert device.set_color.call_args_list == [call((100, 70), 0, True)] assert device.set_color.call_args_list == [call((100, 70), 0, True)]
# test for unknown error
error.response.status_code = 500
with pytest.raises(HTTPError, match="Bad Request"):
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_BRIGHTNESS: 100, ATTR_HS_COLOR: (100, 70)},
True,
)
async def test_turn_off(hass: HomeAssistant, fritz: Mock) -> None: async def test_turn_off(hass: HomeAssistant, fritz: Mock) -> None:
"""Test turn device off.""" """Test turn device off."""