Repository: XKNX/xknx
Pull request #1576 (2024-09-23 10:21:28)

Bump pylint from 3.2.7 to 3.3.0
Bumps [pylint](https://github.com/pylint-dev/pylint) from 3.2.7 to 3.3.0.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/pylint-dev/pylint/commit/6350dfa900b11de442bc562564884037ca8bc4f6"><code>6350dfa</code></a> Bump pylint to 3.3.0, update changelog</li>
<li><a href="https://github.com/pylint-dev/pylint/commit/78f3dfa0c40bdb1e0f145e75c309f28f4e8cc31e"><code>78f3dfa</code></a> Bump astroid to 3.3.3 (<a href="https://redirect.github.com/pylint-dev/pylint/issues/9939">#9939</a>)</li>
<li><a href="https://github.com/pylint-dev/pylint/commit/b28c1f69334191ade62357d01c248742afac24b3"><code>b28c1f6</code></a> Add check for <code>unnecessary-default-type-args</code> (<a href="https://redirect.github.com/pylint-dev/pylint/issues/9938">#9938</a>)</li>
<li><a href="https://github.com/pylint-dev/pylint/commit/bd97b93db80298570bce6a0197c62d78a4d5134f"><code>bd97b93</code></a> [doc framework] Assert that the good and bad example exists in the doc (<a href="https://redirect.github.com/pylint-dev/pylint/issues/9936">#9936</a>)</li>
<li><a href="https://github.com/pylint-dev/pylint/commit/7aa44364a6c202dce8384eafad7f4d5fb6492dad"><code>7aa4436</code></a> Fix duplicate workflow step ids (<a href="https://redirect.github.com/pylint-dev/pylint/issues/9934">#9934</a>)</li>
<li><a href="https://github.com/pylint-dev/pylint/commit/09509163baaba140fca2633930a6632f05830246"><code>0950916</code></a> [pre-commit] Add codespell, and fix some existing typos (<a href="https://redirect.github.com/pylint-dev/pylint/issues/9912">#9912</a>)</li>
<li><a href="https://github.com/pylint-dev/pylint/commit/3b4a7f9ba6ed01298324d73e2e625324ee4a39e7"><code>3b4a7f9</code></a> Add details.rst for c-extension-no-member (<a href="https://redirect.github.com/pylint-dev/pylint/issues/9933">#9933</a>)</li>
<li><a href="https://github.com/pylint-dev/pylint/commit/7d60c27efc799dabd2aa217744636c81036c78c6"><code>7d60c27</code></a> Explicitly save cache in primer jobs</li>
<li><a href="https://github.com/pylint-dev/pylint/commit/67acc9669fdaca388fcf2078413827941993b777"><code>67acc96</code></a> Add additional stdlib deprecations (mostly 3.13) (<a href="https://redirect.github.com/pylint-dev/pylint/issues/9853">#9853</a>)</li>
<li><a href="https://github.com/pylint-dev/pylint/commit/0adf671a98b6171099b19e8d5d0d363421c8b451"><code>0adf671</code></a> Remove old-style classes code, remove check for new-style class (<a href="https://redirect.github.com/pylint-dev/pylint/issues/9925">#9925</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/pylint-dev/pylint/compare/v3.2.7...v3.3.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=pylint&package-manager=pip&previous-version=3.2.7&new-version=3.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/docs/climate.md b/docs/climate.md
index 97cbd7d8..5fd0111d 100644
--- a/docs/climate.md
+++ b/docs/climate.md
@@ -34,7 +34,7 @@ Climate are representations of KNX HVAC/Climate controls.
 - `sync_state` defines if and how often the value should be actively read from the bus. If `False` no GroupValueRead telegrams will be sent to its group address. Defaults to `True`
 - `max_temp` Maximum value for target temperature.
 - `min_temp` Minimum value for target temperature.
-- `fan_max_step` Maximum step amount for fans which are controlled with steps and not percentage. If this attribute is set, the fan is controlled by sending the step value in the range `0` and `max_step`. In that case, the group address DPT changes from *DPT 5.001* to *DPT 5.010*. Default: None.
+- `fan_speed_mode` Defines the mode of fan speed control. Can be either `FanSpeedMode.STEP` for step-wise control or `FanSpeedMode.PERCENT` for percentage control. For `STEP` mode, the fan speed is controlled by sending integer values, and the group address uses *DPT 5.010*. For `PERCENT` mode, the fan speed is controlled by sending percentage values (0-100%), and the group address uses *DPT 5.001*. Default: `FanSpeedMode.PERCENT`.
 - `mode` ClimateMode instance for this climate device
 - `group_address_operation_mode` KNX address for operation mode. *DPT 20.102*
 - `group_address_operation_mode_state` KNX address for operation mode status. *DPT 20.102*
@@ -93,7 +93,7 @@ climate = Climate(
     max_temp=26,
     mode=climate_mode,
     device_updated_cb=None,
-    fan_max_step=None,
+    fan_speed_mode=FanSpeedMode.STEP,
 )
 xknx.devices.async_add(climate)
 xknx.devices.async_add(climate_mode)
diff --git a/pyproject.toml b/pyproject.toml
index df01523d..73f8a269 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -99,6 +99,7 @@ disable = [
   "too-many-instance-attributes",
   "too-many-lines",
   "too-many-locals",
+  "too-many-positional-arguments",
   "too-many-public-methods",
   "too-many-return-statements",
   "too-many-statements",
diff --git a/xknx/devices/climate.py b/xknx/devices/climate.py
index 48ec3350..dc54c75b 100644
--- a/xknx/devices/climate.py
+++ b/xknx/devices/climate.py
@@ -67,7 +67,7 @@ class Climate(Device):
         device_updated_cb: DeviceCallbackType[Climate] | None = None,
         group_address_fan_speed: GroupAddressesType = None,
         group_address_fan_speed_state: GroupAddressesType = None,
-        fan_max_step: int | None = None,
+        fan_speed_mode: FanSpeedMode = FanSpeedMode.PERCENT,
     ):
         """Initialize Climate class."""
         super().__init__(xknx, name, device_updated_cb)
@@ -141,10 +141,9 @@ class Climate(Device):
         )
 
         self.fan_speed: RemoteValueDptValue1Ucount | RemoteValueScaling
-        self.fan_mode = FanSpeedMode.STEP if fan_max_step else FanSpeedMode.PERCENT
-        self.fan_max_step = fan_max_step
+        self.fan_speed_mode = fan_speed_mode
 
-        if self.fan_mode == FanSpeedMode.STEP:
+        if self.fan_speed_mode == FanSpeedMode.STEP:
             self.fan_speed = RemoteValueDptValue1Ucount(
                 xknx,
                 group_address_fan_speed,


Test patch:
diff --git a/requirements/testing.txt b/requirements/testing.txt
index 503063b8..02c2f858 100644
--- a/requirements/testing.txt
+++ b/requirements/testing.txt
@@ -2,12 +2,12 @@
 freezegun==1.5.1
 mypy==1.11.2
 pre-commit==3.8.0
-pylint==3.2.7
+pylint==3.3.0
 pytest==8.3.3
 pytest-asyncio==0.24.0
 pytest-cov==5.0.0
 pytest-icdiff==0.9
-ruff==0.6.5
-setuptools==75.0.0
-tox==4.18.1
+ruff==0.6.7
+setuptools==75.1.0
+tox==4.20.0
 tox-gh-actions==3.2.0
diff --git a/test/devices_tests/climate_test.py b/test/devices_tests/climate_test.py
index d6f5d8ca..63fef737 100644
--- a/test/devices_tests/climate_test.py
+++ b/test/devices_tests/climate_test.py
@@ -6,7 +6,7 @@ import pytest
 
 from xknx import XKNX
 from xknx.devices import Climate, ClimateMode
-from xknx.devices.climate import SetpointShiftMode
+from xknx.devices.climate import FanSpeedMode, SetpointShiftMode
 from xknx.dpt import (
     DPT2ByteFloat,
     DPTArray,
@@ -1571,7 +1571,7 @@ class TestClimate:
             name="TestClimate",
             group_address_fan_speed="1/2/3",
             group_address_fan_speed_state="1/2/4",
-            fan_max_step=3,
+            fan_speed_mode=FanSpeedMode.STEP,
         )
         xknx.devices.async_add(climate_step)
         climate_percent = Climate(
@@ -1580,6 +1580,7 @@ class TestClimate:
             group_address_fan_speed="1/2/5",
             group_address_fan_speed_state="1/2/6",
         )
+        assert climate_percent.fan_speed_mode == FanSpeedMode.PERCENT
         xknx.devices.async_add(climate_percent)
 
         # Test initial state