diff --git a/blog/2023-12-05-scaling-utils.md b/blog/2023-12-05-scaling-utils.md new file mode 100644 index 00000000..a5ebd7e2 --- /dev/null +++ b/blog/2023-12-05-scaling-utils.md @@ -0,0 +1,119 @@ +--- +author: Jan Bouwhuis +authorURL: https://github.com/jbouwh +authorImageURL: https://avatars.githubusercontent.com/u/7188918?s=96&v=4 +title: New scaling utils and import changes +--- + +## New utils for scaling brightness + +Multiple integrations have implemented there own scaling algorithm to scale brightness. New utils are introduced now to simplify the implementation of brightness scaling in `homeassistant.util.color`: + +```python +def brightness_to_value(low_high_range: tuple[float, float], brightness: int) -> float: + """Given a brightness_scale convert a brightness to a single value. + + Do not include 0 if the light is off for value 0. + + Given a brightness low_high_range of (1,100) this function + will return: + + 255: 100.0 + 127: ~49.8039 + 10: ~3.9216 + """ + ... +``` + +If you'd rather like to scale brightness to an integer range you can also use `scale_ranged_value_to_int_range`, described [here](#background). + +```python +def value_to_brightness(low_high_range: tuple[float, float], value: float) -> int: + """Given a brightness_scale convert a single value to a brightness. + + Do not include 0 if the light is off for value 0. + + Given a brightness low_high_range of (1,100) this function + will return: + + 100: 255 + 50: 127 + 4: 10 + + The value will be clamped between 1..255 to ensure valid value. + """ + ... +``` + +This also ensures a valid brightness value is returned. + +### Background + +To scale fan speed percentage we already have some utils `homeassistant.utils.percentage`: + +```python +def ranged_value_to_percentage( + low_high_range: tuple[float, float], value: float +) -> int: + ... +``` + +and + +```python +def percentage_to_ranged_value( + low_high_range: tuple[float, float], percentage: int +) -> float: + ... +``` + +These percentage utils will now use new generic scaling utils in `homeassistant.utils.scaling`: + +`scale_ranged_value_to_int_range` and `scale_to_ranged_value` + +```python +def scale_ranged_value_to_int_range( + source_low_high_range: tuple[float, float], + target_low_high_range: tuple[float, float], + value: float, +) -> int: + """Given a range of low and high values convert a single value to another range. + + Given a source low value of 1 and a high value of 255 and + a target range from 1 to 100 this function + will return: + + (1,255), 255: 100 + (1,255), 127: 50 + (1,255), 10: 4 + """ + ... +``` + +and + +```python +def scale_to_ranged_value( + source_low_high_range: tuple[float, float], + target_low_high_range: tuple[float, float], + value: int, +) -> float: + """Given a range of low and high values convert a single value to another range. + + Do not include 0 in a range if 0 means off, + e.g. for brightness or fan speed. + + Given a source low value of 1 and a high value of 255 and + a target range from 1 to 100 this function + will return: + + (1,255), 255: 100 + (1,255), 127: ~49.8039 + (1,255), 10: ~3.9216 + """ + ... +``` + +## Utils `int_states_in_range` and `states_in_range` are moved + +These utils are now under `homeassistant.util.scaling`. If these are used in your custom integration, make sure you update the import to the new module. diff --git a/docs/core/entity/fan.md b/docs/core/entity/fan.md index c5363405..630edd7d 100644 --- a/docs/core/entity/fan.md +++ b/docs/core/entity/fan.md @@ -119,7 +119,8 @@ named_speed = percentage_to_ordered_list_item(ORDERED_NAMED_FAN_SPEEDS, 23) If the device has a numeric range of speeds: ```python -from homeassistant.util.percentage import int_states_in_range, ranged_value_to_percentage, percentage_to_ranged_value +from homeassistant.util.percentage import ranged_value_to_percentage, percentage_to_ranged_value +from homeassistant.util.scaling import int_states_in_range SPEED_RANGE = (1, 255) # off is not included diff --git a/docs/core/entity/light.md b/docs/core/entity/light.md index 7893356d..4eda9631 100644 --- a/docs/core/entity/light.md +++ b/docs/core/entity/light.md @@ -104,6 +104,44 @@ It is guaranteed that the integration will only receive a single color attribute | rgbww_color | Will be removed from the service call if not supported. | xy_color | Will be removed from the service call if not supported and translated to `hs_color`, `rgb_color`, `rgbw_color` or `rgbww_color` if supported by the light. +:::tip Scaling brightness + +Home Assistant includes a utility to scale brightness. + +If the light supports brightness, sometimes the brightness value needs scaling: + +```python +from homeassistant.util.color import value_to_brightness + +BRIGHTNESS_SCALE = (1, 1023) + +... + + @property + def brightness(self) -> Optional[int]: + """Return the current brightness.""" + return value_to_brightness(BRIGHTNESS_SCALE, self._device.brightness) + +``` + +To scale the brightness to the device range: + +```python +from homeassistant.util.color import value_to_brightness + +BRIGHTNESS_SCALE = (1, 1023) + +... + +class MyLightEntity(LightEntity): + async def async_turn_on(self, **kwargs) -> None: + """Turn device on.""" + + ... + + value_in_range = math.ceil(percentage_to_ranged_value(BRIGHTNESS_SCALE, kwargs[ATTR_BRIGHTNESS])) + +::: ### Turn Off Light Device