Guard KNX climate fan_mode against out-of-range step values (#182007)

This commit is contained in:
Abdellatif Anaflous
2026-09-12 12:09:01 +02:00
committed by GitHub
parent d45ba845ae
commit 775b532bdb
2 changed files with 44 additions and 1 deletions
+5 -1
View File
@@ -554,7 +554,7 @@ class _KnxClimate(ClimateEntity, _KnxEntityBase):
@property
@override
def fan_mode(self) -> str:
def fan_mode(self) -> str | None:
"""Return the fan setting."""
fan_speed = self._device.current_fan_speed
@@ -563,6 +563,10 @@ class _KnxClimate(ClimateEntity, _KnxEntityBase):
return self.fan_zero_mode
if self._device.fan_speed_mode is FanSpeedMode.STEP:
# DPT 5.010 fits any 1-byte value (0-255), so a gateway may report
# a step beyond the configured fan_max_step
if fan_speed >= len(self._attr_fan_modes):
return None
return self._attr_fan_modes[fan_speed]
# Find the closest fan mode percentage
+39
View File
@@ -502,6 +502,45 @@ async def test_fan_speed_3_steps(hass: HomeAssistant, knx: KNXTestKit) -> None:
knx.assert_state("climate.test", HVACMode.HEAT, fan_mode="off")
@pytest.mark.parametrize("raw_value", [0x04, 0xFF])
async def test_fan_speed_step_out_of_range(
hass: HomeAssistant, knx: KNXTestKit, raw_value: int
) -> None:
"""Test that fan step values beyond fan_max_step don't crash the entity."""
await knx.setup_integration(
{
ClimateSchema.PLATFORM: {
CONF_NAME: "test",
ClimateSchema.CONF_TEMPERATURE_ADDRESS: "1/2/3",
ClimateSchema.CONF_TARGET_TEMPERATURE_ADDRESS: "1/2/4",
ClimateSchema.CONF_TARGET_TEMPERATURE_STATE_ADDRESS: "1/2/5",
ClimateSchema.CONF_FAN_SPEED_ADDRESS: "1/2/6",
ClimateSchema.CONF_FAN_SPEED_STATE_ADDRESS: "1/2/7",
ClimateConf.FAN_SPEED_MODE: "step",
ClimateConf.FAN_MAX_STEP: 3,
}
}
)
# read states state updater
await knx.assert_read("1/2/3")
await knx.assert_read("1/2/5")
# StateUpdater initialize state
await knx.receive_response("1/2/5", RAW_FLOAT_22_0)
await knx.receive_response("1/2/3", RAW_FLOAT_21_0)
# Query status
await knx.assert_read("1/2/7")
# a gateway may report a step value beyond the configured fan_max_step
await knx.receive_write("1/2/7", (raw_value,))
await hass.async_block_till_done()
# the invalid telegram is published without breaking the state write
knx.assert_state("climate.test", HVACMode.HEAT, fan_mode=None)
async def test_fan_speed_2_steps(hass: HomeAssistant, knx: KNXTestKit) -> None:
"""Test KNX climate fan speed 2 steps."""
await knx.setup_integration(