Repository: XKNX/xknx
Pull request #612 (2021-02-22 06:24:47)

Bump pylint from 2.6.2 to 2.7.0
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.6.2 to 2.7.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/PyCQA/pylint/blob/master/ChangeLog">pylint's changelog</a>.</em></p>
<blockquote>
<h1>What's New in Pylint 2.7.0?</h1>
<p>Release date: 2021-02-21</p>
<ul>
<li>
<p>Introduce DeprecationMixin for reusable deprecation checks.</p>
<p>Closes <a href="https://github-redirect.dependabot.com/PyCQA/pylint/issues/4049">#4049</a></p>
</li>
<li>
<p>Fix false positive for <code>builtin-not-iterating</code> when <code>map</code> receives iterable</p>
<p>Closes <a href="https://github-redirect.dependabot.com/PyCQA/pylint/issues/4078">#4078</a></p>
</li>
<li>
<p>Python 3.6+ is now required.</p>
</li>
<li>
<p>Fix false positive for <code>builtin-not-iterating</code> when <code>zip</code> receives iterable</p>
</li>
<li>
<p>Add <code>nan-comparison</code> check for NaN comparisons</p>
</li>
<li>
<p>Bug fix for empty-comment message line number.</p>
<p>Closes <a href="https://github-redirect.dependabot.com/PyCQA/pylint/issues/4009">#4009</a></p>
</li>
<li>
<p>Only emit <code>bad-reversed-sequence</code> on dictionaries if below py3.8</p>
<p>Closes <a href="https://github-redirect.dependabot.com/PyCQA/pylint/issues/3940">#3940</a></p>
</li>
<li>
<p>Handle class decorators applied to function.</p>
<p>Closes <a href="https://github-redirect.dependabot.com/PyCQA/pylint/issues/3882">#3882</a></p>
</li>
<li>
<p>Add check for empty comments</p>
</li>
<li>
<p>Fix minor documentation issue in contribute.rst</p>
</li>
<li>
<p>Enums are now required to be named in UPPER_CASE by <code>invalid-name</code>.</p>
<p>Close <a href="https://github-redirect.dependabot.com/PyCQA/pylint/issues/3834">#3834</a></p>
</li>
<li>
<p>Add missing checks for deprecated functions.</p>
</li>
<li>
<p>Postponed evaluation of annotations are now recognized by default if python version is above 3.10</p>
<p>Closes <a href="https://github-redirect.dependabot.com/PyCQA/pylint/issues/3992">#3992</a></p>
</li>
<li>
<p>Fix column metadata for anomalous backslash lints</p>
</li>
<li>
<p>Drop support for Python 3.5</p>
</li>
<li>
<p>Add support for pep585 with postponed evaluation</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/PyCQA/pylint/commit/5e04ce74faa0142fe3ff99eec08479cfaeb9584c"><code>5e04ce7</code></a> Better documentation for the change in version during release</li>
<li><a href="https://github.com/PyCQA/pylint/commit/41d70221cdce96a209a479e349bdb70180bb5e8e"><code>41d7022</code></a> Upgrade the documentation about release</li>
<li><a href="https://github.com/PyCQA/pylint/commit/ac85223e5b8d0885d4717cec9499ab01bbd30fb6"><code>ac85223</code></a> Apply copyrite --contribution-threshold</li>
<li><a href="https://github.com/PyCQA/pylint/commit/6e2de8e3a2e2c5586e876ca305f0844bdd822db3"><code>6e2de8e</code></a> Upgrade version to 2.7.0 and fix astroid to 2.5.0</li>
<li><a href="https://github.com/PyCQA/pylint/commit/b9d9ca239c7f552abb3755cb04d73e3cd34e4530"><code>b9d9ca2</code></a> Edit highlights for 2.7.0 in whatsnew</li>
<li><a href="https://github.com/PyCQA/pylint/commit/ca110478acd0f0ad73b0ea20627d36402be401c8"><code>ca11047</code></a> Fix link to isort documentation in doc/faq.rst</li>
<li><a href="https://github.com/PyCQA/pylint/commit/ee910755b90af58d6aa9b908b5afe4310c5b26db"><code>ee91075</code></a> Migrate from % syntax or bad format() syntax to fstring</li>
<li><a href="https://github.com/PyCQA/pylint/commit/5bed07eba999130b6551acc7c43192d6a8eada43"><code>5bed07e</code></a> Move from % string formatting syntax to f-string or .format()</li>
<li><a href="https://github.com/PyCQA/pylint/commit/a1e553d3bb07c56ca99c31279f9af104bede0a32"><code>a1e553d</code></a> Add pyupgrade to the pre-commit configuration</li>
<li><a href="https://github.com/PyCQA/pylint/commit/154718cf610285be12cf72954ba7b88cda48eada"><code>154718c</code></a> Remove the # coding, since PEP3120 the default is UTF8</li>
<li>Additional commits viewable in <a href="https://github.com/PyCQA/pylint/compare/pylint-2.6.2...pylint-2.7.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=pylint&package-manager=pip&previous-version=2.6.2&new-version=2.7.0)](https://dependabot.com/compatibility-score/?dependency-name=pylint&package-manager=pip&previous-version=2.6.2&new-version=2.7.0)

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 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)
- `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language
- `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme

Additionally, you can set the following in your Dependabot [dashboard](https://app.dependabot.com):
- Update frequency (including time of day and day of week)
- Pull request limits (per update run and/or open at any time)
- Out-of-range updates (receive only lockfile updates, if desired)
- Security updates (receive only security updates, if desired)



</details>


Patch:
diff --git a/home-assistant-plugin/custom_components/xknx/__init__.py b/home-assistant-plugin/custom_components/xknx/__init__.py
index 38e848bf..7c592c63 100644
--- a/home-assistant-plugin/custom_components/xknx/__init__.py
+++ b/home-assistant-plugin/custom_components/xknx/__init__.py
@@ -106,31 +106,31 @@ CONFIG_SCHEMA = vol.Schema(
                     vol.Optional(CONF_XKNX_EXPOSE): vol.All(
                         cv.ensure_list, [ExposeSchema.SCHEMA]
                     ),
-                    vol.Optional(SupportedPlatforms.cover.value): vol.All(
+                    vol.Optional(SupportedPlatforms.COVER.value): vol.All(
                         cv.ensure_list, [CoverSchema.SCHEMA]
                     ),
-                    vol.Optional(SupportedPlatforms.binary_sensor.value): vol.All(
+                    vol.Optional(SupportedPlatforms.BINARY_sensor.value): vol.All(
                         cv.ensure_list, [BinarySensorSchema.SCHEMA]
                     ),
-                    vol.Optional(SupportedPlatforms.light.value): vol.All(
+                    vol.Optional(SupportedPlatforms.LIGHT.value): vol.All(
                         cv.ensure_list, [LightSchema.SCHEMA]
                     ),
-                    vol.Optional(SupportedPlatforms.climate.value): vol.All(
+                    vol.Optional(SupportedPlatforms.CLIMATE.value): vol.All(
                         cv.ensure_list, [ClimateSchema.SCHEMA]
                     ),
-                    vol.Optional(SupportedPlatforms.notify.value): vol.All(
+                    vol.Optional(SupportedPlatforms.NOTIFY.value): vol.All(
                         cv.ensure_list, [NotifySchema.SCHEMA]
                     ),
-                    vol.Optional(SupportedPlatforms.switch.value): vol.All(
+                    vol.Optional(SupportedPlatforms.SWITCH.value): vol.All(
                         cv.ensure_list, [SwitchSchema.SCHEMA]
                     ),
-                    vol.Optional(SupportedPlatforms.sensor.value): vol.All(
+                    vol.Optional(SupportedPlatforms.SENSOR.value): vol.All(
                         cv.ensure_list, [SensorSchema.SCHEMA]
                     ),
-                    vol.Optional(SupportedPlatforms.scene.value): vol.All(
+                    vol.Optional(SupportedPlatforms.SCENE.value): vol.All(
                         cv.ensure_list, [SceneSchema.SCHEMA]
                     ),
-                    vol.Optional(SupportedPlatforms.weather.value): vol.All(
+                    vol.Optional(SupportedPlatforms.WEATHER.value): vol.All(
                         cv.ensure_list, [WeatherSchema.SCHEMA]
                     ),
                     vol.Optional(SupportedPlatforms.fan.value): vol.All(
diff --git a/home-assistant-plugin/custom_components/xknx/const.py b/home-assistant-plugin/custom_components/xknx/const.py
index d9605ffc..a6926eeb 100644
--- a/home-assistant-plugin/custom_components/xknx/const.py
+++ b/home-assistant-plugin/custom_components/xknx/const.py
@@ -26,23 +26,23 @@ CONF_RESET_AFTER = "reset_after"
 class ColorTempModes(Enum):
     """Color temperature modes for config validation."""
 
-    absolute = "DPT-7.600"
-    relative = "DPT-5.001"
+    ABSOLUTE = "DPT-7.600"
+    RELATIVE = "DPT-5.001"
 
 
 class SupportedPlatforms(Enum):
     """Supported platforms."""
 
-    binary_sensor = "binary_sensor"
-    climate = "climate"
-    cover = "cover"
-    fan = "fan"
-    light = "light"
-    notify = "notify"
-    scene = "scene"
-    sensor = "sensor"
-    switch = "switch"
-    weather = "weather"
+    BINARY_SENSOR = "binary_sensor"
+    CLIMATE = "climate"
+    COVER = "cover"
+    FAN = "fan"
+    LIGHT = "light"
+    NOTIFY = "notify"
+    SCENE = "scene"
+    SENSOR = "sensor"
+    SWITCH = "switch"
+    WEATHER = "weather"
 
 
 # Map KNX controller modes to HA modes. This list might not be complete.
diff --git a/home-assistant-plugin/custom_components/xknx/factory.py b/home-assistant-plugin/custom_components/xknx/factory.py
index 4f50da4d..e8460946 100644
--- a/home-assistant-plugin/custom_components/xknx/factory.py
+++ b/home-assistant-plugin/custom_components/xknx/factory.py
@@ -40,34 +40,34 @@ def create_knx_device(
     config: ConfigType,
 ) -> XknxDevice:
     """Return the requested XKNX device."""
-    if platform is SupportedPlatforms.light:
+    if platform is SupportedPlatforms.LIGHT:
         return _create_light(knx_module, config)
 
-    if platform is SupportedPlatforms.cover:
+    if platform is SupportedPlatforms.COVER:
         return _create_cover(knx_module, config)
 
-    if platform is SupportedPlatforms.climate:
+    if platform is SupportedPlatforms.CLIMATE:
         return _create_climate(knx_module, config)
 
-    if platform is SupportedPlatforms.switch:
+    if platform is SupportedPlatforms.SWITCH:
         return _create_switch(knx_module, config)
 
-    if platform is SupportedPlatforms.sensor:
+    if platform is SupportedPlatforms.SENSOR:
         return _create_sensor(knx_module, config)
 
-    if platform is SupportedPlatforms.notify:
+    if platform is SupportedPlatforms.NOTIFY:
         return _create_notify(knx_module, config)
 
-    if platform is SupportedPlatforms.scene:
+    if platform is SupportedPlatforms.SCENE:
         return _create_scene(knx_module, config)
 
-    if platform is SupportedPlatforms.binary_sensor:
+    if platform is SupportedPlatforms.BINARY_sensor:
         return _create_binary_sensor(knx_module, config)
 
-    if platform is SupportedPlatforms.weather:
+    if platform is SupportedPlatforms.WEATHER:
         return _create_weather(knx_module, config)
 
-    if platform is SupportedPlatforms.fan:
+    if platform is SupportedPlatforms.FAN:
         return _create_fan(knx_module, config)
 
 
@@ -121,12 +121,12 @@ def _create_light(knx_module: XKNX, config: ConfigType) -> XknxLight:
     group_address_tunable_white_state = None
     group_address_color_temp = None
     group_address_color_temp_state = None
-    if config[LightSchema.CONF_COLOR_TEMP_MODE] == ColorTempModes.absolute:
+    if config[LightSchema.CONF_COLOR_TEMP_MODE] == ColorTempModes.ABSOLUTE:
         group_address_color_temp = config.get(LightSchema.CONF_COLOR_TEMP_ADDRESS)
         group_address_color_temp_state = config.get(
             LightSchema.CONF_COLOR_TEMP_STATE_ADDRESS
         )
-    elif config[LightSchema.CONF_COLOR_TEMP_MODE] == ColorTempModes.relative:
+    elif config[LightSchema.CONF_COLOR_TEMP_MODE] == ColorTempModes.RELATIVE:
         group_address_tunable_white = config.get(LightSchema.CONF_COLOR_TEMP_ADDRESS)
         group_address_tunable_white_state = config.get(
             LightSchema.CONF_COLOR_TEMP_STATE_ADDRESS
diff --git a/home-assistant-plugin/custom_components/xknx/fan.py b/home-assistant-plugin/custom_components/xknx/fan.py
index 6aa4f722..43d1cd7d 100644
--- a/home-assistant-plugin/custom_components/xknx/fan.py
+++ b/home-assistant-plugin/custom_components/xknx/fan.py
@@ -34,14 +34,14 @@ class KNXFan(KnxEntity, FanEntity):
         """Initialize of KNX fan."""
         super().__init__(device)
 
-        if self._device.mode == FanSpeedMode.Step:
+        if self._device.mode == FanSpeedMode.STEP:
             self._step_range = (1, device.max_step)
         else:
             self._step_range = None
 
     async def async_set_percentage(self, percentage: int) -> None:
         """Set the speed of the fan, as a percentage."""
-        if self._device.mode == FanSpeedMode.Step:
+        if self._device.mode == FanSpeedMode.STEP:
             step = math.ceil(percentage_to_ranged_value(self._step_range, percentage))
             await self._device.set_speed(step)
         else:
@@ -63,7 +63,7 @@ class KNXFan(KnxEntity, FanEntity):
         if self._device.current_speed is None:
             return None
 
-        if self._device.mode == FanSpeedMode.Step:
+        if self._device.mode == FanSpeedMode.STEP:
             return ranged_value_to_percentage(
                 self._step_range, self._device.current_speed
             )
diff --git a/xknx/devices/fan.py b/xknx/devices/fan.py
index da9b44d9..c30ab2da 100644
--- a/xknx/devices/fan.py
+++ b/xknx/devices/fan.py
@@ -30,8 +30,8 @@ logger = logging.getLogger("xknx.log")
 class FanSpeedMode(Enum):
     """Enum for setting the fan speed mode."""
 
-    Percent = 1
-    Step = 2
+    PERCENT = 1
+    STEP = 2
 
 
 class Fan(Device):
@@ -56,10 +56,10 @@ class Fan(Device):
         super().__init__(xknx, name, device_updated_cb)
 
         self.speed: Union[RemoteValueDptValue1Ucount, RemoteValueScaling]
-        self.mode = FanSpeedMode.Step if max_step is not None else FanSpeedMode.Percent
+        self.mode = FanSpeedMode.STEP if max_step is not None else FanSpeedMode.PERCENT
         self.max_step = max_step
 
-        if self.mode == FanSpeedMode.Step:
+        if self.mode == FanSpeedMode.STEP:
             self.speed = RemoteValueDptValue1Ucount(
                 xknx,
                 group_address_speed,
diff --git a/xknx/devices/light.py b/xknx/devices/light.py
index 4daeb1b3..172bc33c 100644
--- a/xknx/devices/light.py
+++ b/xknx/devices/light.py
@@ -47,8 +47,8 @@ logger = logging.getLogger("xknx.log")
 class ColorTempModes(Enum):
     """Color temperature modes for config validation."""
 
-    absolute = "DPT-7.600"
-    relative = "DPT-5.001"
+    ABSOLUTE = "DPT-7.600"
+    RELATIVE = "DPT-5.001"
 
 
 class _SwitchAndBrightness:
@@ -261,10 +261,14 @@ class Light(Device):
         yield self.rgbw
         yield self.tunable_white
         yield self.color_temperature
-        for color in (self.red, self.green, self.blue, self.white):
+        for color in self._iter_individual_colors():
             yield color.switch
             yield color.brightness
 
+    def _iter_individual_colors(self) -> Iterator[_SwitchAndBrightness]:
+        """Iterate the devices individual colors."""
+        yield from (self.red, self.green, self.blue, self.white)
+
     @property
     def supports_brightness(self) -> bool:
         """Return if light supports brightness."""
@@ -274,17 +278,14 @@ class Light(Device):
     def supports_color(self) -> bool:
         """Return if light supports color."""
         return self.color.initialized or all(
-            [c.brightness.initialized for c in (self.red, self.green, self.blue)]
+            c.brightness.initialized for c in (self.red, self.green, self.blue)
         )
 
     @property
     def supports_rgbw(self) -> bool:
         """Return if light supports RGBW."""
         return self.rgbw.initialized or all(
-            [
-                c.brightness.initialized
-                for c in (self.red, self.green, self.blue, self.white)
-            ]
+            c.brightness.initialized for c in self._iter_individual_colors()
         )
 
     @property
@@ -496,29 +497,22 @@ class Light(Device):
         """Return the current switch state of the device."""
         if self.switch.value is not None:
             return self.switch.value  # type: ignore
-        if any(
-            [
-                c.switch.value is not None
-                for c in (self.red, self.green, self.blue, self.white)
-            ]
-        ):
-            return any(
-                [c.switch.value for c in (self.red, self.green, self.blue, self.white)]
-            )
+        if any(c.switch.value is not None for c in self._iter_individual_colors()):
+            return any(c.switch.value for c in self._iter_individual_colors())
         return None
 
     async def set_on(self) -> None:
         """Switch light on."""
         if self.switch.initialized:
             await self.switch.on()
-        for color in (self.red, self.green, self.blue, self.white):
+        for color in self._iter_individual_colors():
             await color.set_on()
 
     async def set_off(self) -> None:
         """Switch light off."""
         if self.switch.initialized:
             await self.switch.off()
-        for color in (self.red, self.green, self.blue, self.white):
+        for color in self._iter_individual_colors():
             await color.set_off()
 
     @property
@@ -570,10 +564,7 @@ class Light(Device):
                     await self.rgbw.set(list(color) + [white])
                     return
                 if all(
-                    [
-                        c.brightness.initialized
-                        for c in (self.red, self.green, self.blue, self.white)
-                    ]
+                    c.brightness.initialized for c in self._iter_individual_colors()
                 ):
                     await self.red.brightness.set(color[0])
                     await self.green.brightness.set(color[1])
@@ -587,10 +578,7 @@ class Light(Device):
                     await self.color.set(color)
                     return
                 if all(
-                    [
-                        c.brightness.initialized
-                        for c in (self.red, self.green, self.blue)
-                    ]
+                    c.brightness.initialized for c in (self.red, self.green, self.blue)
                 ):
                     await self.red.brightness.set(color[0])
                     await self.green.brightness.set(color[1])
diff --git a/xknx/devices/weather.py b/xknx/devices/weather.py
index 3185f861..8da041b0 100644
--- a/xknx/devices/weather.py
+++ b/xknx/devices/weather.py
@@ -30,45 +30,45 @@ if TYPE_CHECKING:
 class WeatherCondition(Enum):
     """Home assistant weather conditions (partially)."""
 
-    clear_night = "clear-night"
-    cloudy = "cloudy"
-    lightning = "lightning"
-    lightning_rainy = "lightning-rainy"
-    partly_cloudy = "partly-cloudy"
-    pouring = "pouring"
-    rainy = "rainy"
-    snowy = "snowy"
-    snowy_rainy = "snowy-rainy"
-    sunny = "sunny"
-    windy = "windy"
-    windy_variant = "windy_variant"
-    exceptional = "exceptional"
+    CLEAR_NIGHT = "clear-night"
+    CLOUDY = "cloudy"
+    LIGHTNING = "lightning"
+    LIGHTNING_RAINY = "lightning-rainy"
+    PARTLY_CLOUDY = "partly-cloudy"
+    POURING = "pouring"
+    RAINY = "rainy"
+    SNOWY = "snowy"
+    SNOWY_RAINY = "snowy-rainy"
+    SUNNY = "sunny"
+    WINDY = "windy"
+    WINDY_VARIANT = "windy_variant"
+    EXCEPTIONAL = "exceptional"
 
 
 class Season(Enum):
     """Seasonal mapping for illuminance."""
 
-    winter = 0
-    summer = 1
+    WINTER = 0
+    SUMMER = 1
 
 
 YEAR = 2000  # dummy leap year to allow input X-02-29 (leap day)
 # Map year to winter and summer in order to be able to have seasonal illuminance checks
 # Sun during summer is stronger than in winter
 SEASONS = [
-    (Season.winter, (date(YEAR, 1, 1), date(YEAR, 4, 20))),
-    (Season.summer, (date(YEAR, 4, 21), date(YEAR, 10, 1))),
-    (Season.winter, (date(YEAR, 10, 2), date(YEAR, 12, 31))),
+    (Season.WINTER, (date(YEAR, 1, 1), date(YEAR, 4, 20))),
+    (Season.SUMMER, (date(YEAR, 4, 21), date(YEAR, 10, 1))),
+    (Season.WINTER, (date(YEAR, 10, 2), date(YEAR, 12, 31))),
 ]
 
 # Define current condition
 ILLUMINANCE_MAPPING: Tuple[
     Tuple[Season, Callable[[float], bool], WeatherCondition], ...
 ] = (
-    (Season.summer, lambda lx: 2000 <= lx <= 20000, WeatherCondition.cloudy),
-    (Season.summer, lambda lx: lx > 20000, WeatherCondition.sunny),
-    (Season.winter, lambda lx: 999 <= lx <= 4500, WeatherCondition.cloudy),
-    (Season.winter, lambda lx: lx > 4500, WeatherCondition.sunny),
+    (Season.SUMMER, lambda lx: 2000 <= lx <= 20000, WeatherCondition.CLOUDY),
+    (Season.SUMMER, lambda lx: lx > 20000, WeatherCondition.SUNNY),
+    (Season.WINTER, lambda lx: 999 <= lx <= 4500, WeatherCondition.CLOUDY),
+    (Season.WINTER, lambda lx: lx > 4500, WeatherCondition.SUNNY),
 )
 
 
@@ -419,16 +419,16 @@ class Weather(Device):
             )
 
         if self.wind_alarm and self.rain_alarm:
-            return WeatherCondition.lightning_rainy
+            return WeatherCondition.LIGHTNING_RAINY
 
         if self.frost_alarm and self.rain_alarm:
-            return WeatherCondition.snowy_rainy
+            return WeatherCondition.SNOWY_RAINY
 
         if self.rain_alarm:
-            return WeatherCondition.rainy
+            return WeatherCondition.RAINY
 
         if self.wind_alarm:
-            return WeatherCondition.windy
+            return WeatherCondition.WINDY
 
         current_season: Season = _get_season(current_date)
         _season: Season
@@ -439,9 +439,9 @@ class Weather(Device):
                 return result
 
         if self.day_night is False:
-            return WeatherCondition.clear_night
+            return WeatherCondition.CLEAR_NIGHT
 
-        return WeatherCondition.exceptional
+        return WeatherCondition.EXCEPTIONAL
 
     @classmethod
     def from_config(cls, xknx: "XKNX", name: str, config: Any) -> "Weather":
diff --git a/xknx/io/tunnelling.py b/xknx/io/tunnelling.py
index 8deb18c0..7d04f1ce 100644
--- a/xknx/io/tunnelling.py
+++ b/xknx/io/tunnelling.py
@@ -47,7 +47,7 @@ class Tunnelling(RequestResponse):
         cemi = CEMIFrame.init_from_telegram(
             self.xknx,
             telegram=self.telegram,
-            code=CEMIMessageCode.L_Data_REQ,
+            code=CEMIMessageCode.L_DATA_REQ,
             src_addr=self.src_address,
         )
         tunnelling_request = TunnellingRequest(
diff --git a/xknx/knxip/cemi_frame.py b/xknx/knxip/cemi_frame.py
index 068c41be..82aa19ea 100644
--- a/xknx/knxip/cemi_frame.py
+++ b/xknx/knxip/cemi_frame.py
@@ -121,7 +121,7 @@ class CEMIFrame:
 
         if self.code not in (
             CEMIMessageCode.L_DATA_IND,
-            CEMIMessageCode.L_Data_REQ,
+            CEMIMessageCode.L_DATA_REQ,
             CEMIMessageCode.L_DATA_CON,
         ):
             raise UnsupportedCEMIMessage(
@@ -133,7 +133,7 @@ class CEMIFrame:
         return self.from_knx_data_link_layer(raw)
 
     def from_knx_data_link_layer(self, cemi: bytes) -> int:
-        """Parse L_DATA_IND, CEMIMessageCode.L_Data_REQ, CEMIMessageCode.L_DATA_CON."""
+        """Parse L_DATA_IND, CEMIMessageCode.L_DATA_REQ, CEMIMessageCode.L_DATA_CON."""
         if len(cemi) < 11:
             # eg. ETS Line-Scan issues L_DATA_IND with length 10
             raise UnsupportedCEMIMessage(
diff --git a/xknx/knxip/knxip_enum.py b/xknx/knxip/knxip_enum.py
index d45fb5e6..a6dd98b3 100644
--- a/xknx/knxip/knxip_enum.py
+++ b/xknx/knxip/knxip_enum.py
@@ -57,7 +57,7 @@ class CEMIMessageCode(Enum):
 
     # FROM NETWORK LAYER TO DATA LINK LAYER
     L_RAW_REQ = 0x10
-    L_Data_REQ = 0x11  # Data Service.
+    L_DATA_REQ = 0x11  # Data Service.
     # Primitive used for transmitting a data frame
     L_POLL_DATA_REQ = 0x13  # Poll Data Service
 
diff --git a/xknx/knxip/tunnelling_request.py b/xknx/knxip/tunnelling_request.py
index 4c1755de..12848ce8 100644
--- a/xknx/knxip/tunnelling_request.py
+++ b/xknx/knxip/tunnelling_request.py
@@ -42,7 +42,7 @@ class TunnellingRequest(KNXIPBody):
         self.cemi: Optional[CEMIFrame] = (
             cemi
             if cemi is not None
-            else CEMIFrame(xknx, code=CEMIMessageCode.L_Data_REQ)
+            else CEMIFrame(xknx, code=CEMIMessageCode.L_DATA_REQ)
         )
 
     def calculated_length(self) -> int:


Test patch:
diff --git a/requirements/testing.txt b/requirements/testing.txt
index 2e605653..cf255e71 100644
--- a/requirements/testing.txt
+++ b/requirements/testing.txt
@@ -5,7 +5,7 @@ coveralls==3.0.0
 flake8==3.8.4
 flake8-isort==4.0.0
 pydocstyle==5.1.1
-pylint==2.6.2
+pylint==2.7.0
 pylint-strict-informational==0.1
 pytest==6.2.2
 pytest-cov==2.11.1
diff --git a/test/config_tests/resources/light/valid_1.yaml b/test/config_tests/resources/light/valid_1.yaml
index f9fd31e6..a885e76b 100644
--- a/test/config_tests/resources/light/valid_1.yaml
+++ b/test/config_tests/resources/light/valid_1.yaml
@@ -17,6 +17,6 @@ color_temperature:
   address: "2/5/7"
   state_address: "2/5/8"
   state_update: "expire 60"
-  mode: absolute
+  mode: ABSOLUTE
   min_kelvin: 2550
   max_kelvin: 6200
\ No newline at end of file
diff --git a/test/config_tests/resources/light/valid_4.yaml b/test/config_tests/resources/light/valid_4.yaml
index 910920f2..ca2b270f 100644
--- a/test/config_tests/resources/light/valid_4.yaml
+++ b/test/config_tests/resources/light/valid_4.yaml
@@ -7,4 +7,4 @@ color_temperature:
   address: "2/5/7"
   state_address: "2/5/8"
   state_update: "expire 60"
-  mode: relative
\ No newline at end of file
+  mode: RELATIVE
\ No newline at end of file
diff --git a/test/config_tests/resources/xknx/valid_1.yaml b/test/config_tests/resources/xknx/valid_1.yaml
index 36287d7e..6348d654 100644
--- a/test/config_tests/resources/xknx/valid_1.yaml
+++ b/test/config_tests/resources/xknx/valid_1.yaml
@@ -50,7 +50,7 @@ light:
       address: "2/5/7"
       state_address: "2/5/8"
       state_update: "expire 60"
-      mode: absolute
+      mode: ABSOLUTE
       min_kelvin: 2550
       max_kelvin: 6200
 fan:
diff --git a/test/config_tests/resources/xknx/valid_2.yaml b/test/config_tests/resources/xknx/valid_2.yaml
index 8ebc3351..8251c183 100644
--- a/test/config_tests/resources/xknx/valid_2.yaml
+++ b/test/config_tests/resources/xknx/valid_2.yaml
@@ -47,7 +47,7 @@ light:
       address: "2/5/7"
       state_address: "2/5/8"
       state_update: "expire 60"
-      mode: absolute
+      mode: ABSOLUTE
       min_kelvin: 2550
       max_kelvin: 6200
 fan:
diff --git a/test/config_tests/resources/xknx/valid_3.yaml b/test/config_tests/resources/xknx/valid_3.yaml
index 0d37e165..d100cf60 100644
--- a/test/config_tests/resources/xknx/valid_3.yaml
+++ b/test/config_tests/resources/xknx/valid_3.yaml
@@ -52,7 +52,7 @@ light:
       address: "2/5/7"
       state_address: "2/5/8"
       state_update: "expire 60"
-      mode: absolute
+      mode: ABSOLUTE
       min_kelvin: 2550
       max_kelvin: 6200
 fan:
diff --git a/test/devices_tests/weather_test.py b/test/devices_tests/weather_test.py
index 1c59eec3..6f79ca37 100644
--- a/test/devices_tests/weather_test.py
+++ b/test/devices_tests/weather_test.py
@@ -144,7 +144,7 @@ class TestWeather(unittest.TestCase):
         weather._rain_alarm.payload = DPTBinary(1)
         weather._wind_alarm.payload = DPTBinary(1)
 
-        self.assertEqual(weather.ha_current_state(), WeatherCondition.lightning_rainy)
+        self.assertEqual(weather.ha_current_state(), WeatherCondition.LIGHTNING_RAINY)
 
     def test_state_snowy_rainy(self):
         """Test snow rain if frost alarm and rain alarm are true."""
@@ -159,7 +159,7 @@ class TestWeather(unittest.TestCase):
         weather._rain_alarm.payload = DPTBinary(1)
         weather._frost_alarm.payload = DPTBinary(1)
 
-        self.assertEqual(weather.ha_current_state(), WeatherCondition.snowy_rainy)
+        self.assertEqual(weather.ha_current_state(), WeatherCondition.SNOWY_RAINY)
 
     def test_wind_alarm(self):
         """Test basic state mapping."""
@@ -174,7 +174,7 @@ class TestWeather(unittest.TestCase):
 
         weather._wind_alarm.payload = DPTBinary(1)
 
-        self.assertEqual(weather.ha_current_state(), WeatherCondition.windy)
+        self.assertEqual(weather.ha_current_state(), WeatherCondition.WINDY)
 
     def test_rain_alarm(self):
         """Test basic state mapping."""
@@ -189,7 +189,7 @@ class TestWeather(unittest.TestCase):
 
         weather._rain_alarm.payload = DPTBinary(1)
 
-        self.assertEqual(weather.ha_current_state(), WeatherCondition.rainy)
+        self.assertEqual(weather.ha_current_state(), WeatherCondition.RAINY)
 
     def test_cloudy_summer(self):
         """Test cloudy summer if illuminance matches defined interval."""
@@ -211,7 +211,7 @@ class TestWeather(unittest.TestCase):
         summer_date = datetime.datetime(2020, 10, 5, 18, 00)
 
         self.assertEqual(
-            weather.ha_current_state(current_date=summer_date), WeatherCondition.cloudy
+            weather.ha_current_state(current_date=summer_date), WeatherCondition.CLOUDY
         )
 
     def test_sunny_summer(self):
@@ -235,7 +235,7 @@ class TestWeather(unittest.TestCase):
         summer_date = datetime.datetime(2020, 10, 5, 18, 00)
 
         self.assertEqual(
-            weather.ha_current_state(current_date=summer_date), WeatherCondition.sunny
+            weather.ha_current_state(current_date=summer_date), WeatherCondition.SUNNY
         )
 
     def test_sunny_winter(self):
@@ -258,7 +258,7 @@ class TestWeather(unittest.TestCase):
         winter_date = datetime.datetime(2020, 12, 5, 18, 00)
 
         self.assertEqual(
-            weather.ha_current_state(current_date=winter_date), WeatherCondition.sunny
+            weather.ha_current_state(current_date=winter_date), WeatherCondition.SUNNY
         )
 
     def test_cloudy_winter(self):
@@ -282,7 +282,7 @@ class TestWeather(unittest.TestCase):
         winter_date = datetime.datetime(2020, 12, 31, 18, 00)
 
         self.assertEqual(
-            weather.ha_current_state(current_date=winter_date), WeatherCondition.cloudy
+            weather.ha_current_state(current_date=winter_date), WeatherCondition.CLOUDY
         )
 
     def test_day_night(self):
@@ -294,14 +294,14 @@ class TestWeather(unittest.TestCase):
 
         weather._day_night.payload = DPTBinary(0)
 
-        self.assertEqual(weather.ha_current_state(), WeatherCondition.clear_night)
+        self.assertEqual(weather.ha_current_state(), WeatherCondition.CLEAR_NIGHT)
 
     def test_weather_default(self):
         """Test default state mapping."""
         xknx = XKNX()
         weather: Weather = Weather(name="weather", xknx=xknx)
 
-        self.assertEqual(weather.ha_current_state(), WeatherCondition.exceptional)
+        self.assertEqual(weather.ha_current_state(), WeatherCondition.EXCEPTIONAL)
 
     #
     # Create sensor tests
diff --git a/test/knxip_tests/tunnelling_request_test.py b/test/knxip_tests/tunnelling_request_test.py
index 90bbf6d9..679d6bbc 100644
--- a/test/knxip_tests/tunnelling_request_test.py
+++ b/test/knxip_tests/tunnelling_request_test.py
@@ -66,7 +66,7 @@ class Test_KNXIP_TunnelingReq(unittest.TestCase):
             ),
         )
 
-        cemi = CEMIFrame(xknx, code=CEMIMessageCode.L_Data_REQ)
+        cemi = CEMIFrame(xknx, code=CEMIMessageCode.L_DATA_REQ)
         cemi.telegram = Telegram(
             destination_address=GroupAddress("9/0/8"),
             payload=GroupValueWrite(DPTBinary(1)),