mirror of
https://github.com/home-assistant/core.git
synced 2026-09-25 07:51:46 -05:00
Fix Prana fan percentage rounding so displayed values map to the same step (#180718)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from enum import StrEnum
|
||||
import math
|
||||
from typing import Any, override
|
||||
|
||||
from prana_local_api_client.models.prana_state import FanState
|
||||
@@ -137,11 +136,14 @@ class PranaFan(PranaBaseEntity, FanEntity):
|
||||
await self.async_turn_off()
|
||||
return
|
||||
await self.coordinator.api_client.set_speed(
|
||||
math.ceil(
|
||||
percentage_to_ranged_value(
|
||||
self.entity_description.speed_range(self.coordinator),
|
||||
percentage,
|
||||
)
|
||||
max(
|
||||
1,
|
||||
round(
|
||||
percentage_to_ranged_value(
|
||||
self.entity_description.speed_range(self.coordinator),
|
||||
percentage,
|
||||
)
|
||||
),
|
||||
)
|
||||
* PRANA_SPEED_MULTIPLIER,
|
||||
self._api_target_key,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""Integration-style tests for Prana fans."""
|
||||
|
||||
import math
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
@@ -153,7 +152,7 @@ async def test_fans_set_percentage(
|
||||
blocking=True,
|
||||
)
|
||||
expected_speed = (
|
||||
math.ceil(percentage_to_ranged_value((1, fan_mock_state.max_speed), 50))
|
||||
round(percentage_to_ranged_value((1, fan_mock_state.max_speed), 50))
|
||||
* PRANA_SPEED_MULTIPLIER
|
||||
)
|
||||
mock_prana_api.set_speed.assert_called_once_with(
|
||||
@@ -171,6 +170,58 @@ async def test_fans_set_percentage(
|
||||
mock_prana_api.set_speed_is_on.assert_called_with(False, expected_api_key)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("percentage", "expected_step"),
|
||||
[
|
||||
(1, 1), # any non-zero percentage turns the fan on at least at step 1
|
||||
(16, 1),
|
||||
(17, 1), # UI-displayed value for step 1 of 6 (16.67% rounded up)
|
||||
(33, 2),
|
||||
(50, 3),
|
||||
(66, 4),
|
||||
(67, 4), # UI-displayed value for step 4 of 6 (66.67% rounded up)
|
||||
(83, 5),
|
||||
(100, 6),
|
||||
],
|
||||
)
|
||||
async def test_fans_percentage_maps_to_nearest_step(
|
||||
hass: HomeAssistant,
|
||||
mock_prana_api: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
percentage: int,
|
||||
expected_step: int,
|
||||
) -> None:
|
||||
"""Test that displayed percentages map back to the same speed step.
|
||||
|
||||
A 6-step fan reports step 4 as 66.67%, which the UI displays as 67%.
|
||||
Sending that displayed value back must select step 4 again, not step 5.
|
||||
"""
|
||||
mock_prana_api.get_state.return_value.supply.max_speed = 6
|
||||
target, fan_mock_state = await _async_setup_fan_entity(
|
||||
hass,
|
||||
mock_prana_api,
|
||||
mock_config_entry,
|
||||
entity_registry,
|
||||
"supply",
|
||||
False,
|
||||
)
|
||||
|
||||
fan_mock_state.is_on = True
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(
|
||||
FAN_DOMAIN,
|
||||
SERVICE_SET_PERCENTAGE,
|
||||
{ATTR_ENTITY_ID: target, ATTR_PERCENTAGE: percentage},
|
||||
blocking=True,
|
||||
)
|
||||
mock_prana_api.set_speed.assert_called_once_with(
|
||||
expected_step * PRANA_SPEED_MULTIPLIER,
|
||||
"supply",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("type_key", "is_bound_mode", "expected_api_key"),
|
||||
FAN_TEST_CASES,
|
||||
|
||||
Reference in New Issue
Block a user