Repository: XKNX/xknx
Pull request #634 (2021-03-15 07:44:35)

Passive / Listening group addresses from Lists of group_addresses
<!--
  You are awesome! Thanks for contributing to our project!
  Please, DO NOT DELETE ANY TEXT from this template!.
-->
## Description
<!--
Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context.
List any dependencies that are required for this change.
-->
Passive / Listening group addresses from Lists of group_addresses. This can be used for all functions without breaking changes.

Group address configuration behaves like in ETS where the first is the "sending" address and others are just for updating the communication object. 

```python
light = Light(
    xknx, 
    name="light with passive address",
    group_address_switch=["1/2/3", "1/2/10", "1/2/20"]
    group_address_switch_state=["1/3/3", "1/3/10", "1/3/20"]
    )
assert light.switch.group_address == GroupAddress("1/2/3")
assert light.switch.group_address_state == GroupAddress("1/3/3")
assert light.switch.passive_group_addresses == [
    GroupAddress("1/2/10"),
    GroupAddress("1/2/20"),
    GroupAddress("1/3/10"),
    GroupAddress("1/3/20"),
    ]
```

Removed currently unused `RemoteValue.passive_group_addresses` attribute in favor of unpacking from `RemoteValue.group_address` and `RemoteValue.group_address_state`. 

It is not (yet) possible to define a RemoteValue with only passive addresses - not sure if this is useful. It would be equal to configure state_address and set sync_state to False. 

Fixes # (issue)

## Type of change
<!--
Please tick the applicable options.
NOTE: Ticking multiple options most likely indicates
that your change is to big and it is suggested to split it into several smaller PRs.
-->

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [x] This change requires a documentation update

## Checklist:

- [x] I have performed a self-review of my own code
- [x] The documentation has been adjusted accordingly
- [x] The changes generate no new warnings
- [x] Tests have been added that prove the fix is effective or that the feature works
- [x] The changes are documented in the changelog
- [x] The Homeassistant plugin has been adjusted in case of new config options



Patch:
diff --git a/changelog.md b/changelog.md
index b68ab4c0..7a5058f5 100644
--- a/changelog.md
+++ b/changelog.md
@@ -2,9 +2,10 @@
 
 ## Unreleased changes
 
-### Internals
+### Devices
 
-- Don't allow floats in DPTBase value_type parser
+- Accept lists of group addresses using the heads for group_address / group_address_state and the tails for passive_group_addresses in every Device (and RemoteValue)
+- Sensor: Don't allow floats in DPTBase value_type parser
 
 ## 0.17.2 Value templates 2021-03-10
 
diff --git a/docs/devices.md b/docs/devices.md
index 156e82d8..edacc4ae 100644
--- a/docs/devices.md
+++ b/docs/devices.md
@@ -17,6 +17,7 @@ An instantiated device is automatically added to `xknx.devices`.
 * `xknx` is the XKNX object.
 * `name` is the name of the object.
 * `device_updated_cb` List of awaitable callbacks for each update.
+* `group_address*` Group address for a specific function. If a list is passed the first element is used for sending / reading,  the rest are passively updating state (listening group address).
 
 * `has_group_address(group_address)` Test if device has given group address.
 * `sync(wait_for_result)` Read states of device from KNX bus via GroupValueRead requests.
@@ -24,6 +25,36 @@ An instantiated device is automatically added to `xknx.devices`.
 * `unregister_device_updated_cb(device_updated_cb)` Unregister device updated callback.
 * `shutdown()` Remove callbacks and device form Devices vector.
 
+## [](#header-2)Example
+
+```python
+>>> light_s = Light(
+...     xknx,
+...     name="light with state address",
+...     group_address_switch="0/2/2",
+...     group_address_switch_state="0/3/3",
+...     )
+>>> light_s.switch.group_address # this is used to send payloads to the bus
+GroupAddress("0/2/2")
+>>> light_s.switch.group_address_state # group_address_*_state is used to send GroupValueRead requests to (from `sync()` or StateUpdater)
+GroupAddress("0/3/3")
+>>> light_s.switch.passive_group_addresses # none configured
+[]
+>>>
+>>> light_p = Light(
+...     xknx,
+...     name="light with state and passive addresses",
+...     group_address_switch=["1/2/2", "4/2/10", "4/2/20"],
+...     group_address_switch_state=["1/3/3", "4/3/10", "4/3/20"],
+...     )
+>>> light_p.switch.group_address # this is used to send payloads to the bus
+GroupAddress("1/2/2")
+>>> light_p.switch.group_address_state # group_address_*_state is used for reading state from the bus
+GroupAddress("1/3/3")
+>>> light_p.switch.passive_group_addresses # these are only listening
+[GroupAddress("4/2/10"), GroupAddress("4/2/20"), GroupAddress("4/3/10"), GroupAddress("4/3/20")]
+```
+
 ## [](#header-2)Device classes
 
-The following pages will give you an overview over the available devices within XKNX.
\ No newline at end of file
+The following pages will give you an overview over the available devices within XKNX.
diff --git a/home-assistant-plugin/custom_components/xknx/__init__.py b/home-assistant-plugin/custom_components/xknx/__init__.py
index 0d05401b..6029c232 100644
--- a/home-assistant-plugin/custom_components/xknx/__init__.py
+++ b/home-assistant-plugin/custom_components/xknx/__init__.py
@@ -77,7 +77,7 @@ SERVICE_XKNX_READ = "read"
 CONFIG_SCHEMA = vol.Schema(
     {
         DOMAIN: vol.All(
-            # deprecated since 2021.3
+            # deprecated since 2021.4
             cv.deprecated(CONF_XKNX_CONFIG),
             # deprecated since 2021.2
             cv.deprecated(CONF_XKNX_FIRE_EVENT),
diff --git a/home-assistant-plugin/custom_components/xknx/schema.py b/home-assistant-plugin/custom_components/xknx/schema.py
index 31f6684e..5bbe49b2 100644
--- a/home-assistant-plugin/custom_components/xknx/schema.py
+++ b/home-assistant-plugin/custom_components/xknx/schema.py
@@ -35,6 +35,7 @@ ga_validator = vol.Any(
     vol.All(vol.Coerce(int), vol.Range(min=1, max=65535)),
     msg="value does not match pattern for KNX group address '<main>/<middle>/<sub>', '<main>/<sub>' or '<free>' (eg.'1/2/3', '9/234', '123')",
 )
+ga_or_list_validator = vol.Any(ga_validator, [ga_validator])
 
 ia_validator = vol.Any(
     cv.matches_regex(IndividualAddress.ADDRESS_RE),
@@ -97,7 +98,7 @@ class BinarySensorSchema:
                 vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
                 vol.Optional(CONF_SYNC_STATE, default=True): sync_state_validator,
                 vol.Optional(CONF_IGNORE_INTERNAL_STATE, default=False): cv.boolean,
-                vol.Required(CONF_STATE_ADDRESS): ga_validator,
+                vol.Required(CONF_STATE_ADDRESS): ga_or_list_validator,
                 vol.Optional(CONF_CONTEXT_TIMEOUT): vol.All(
                     vol.Coerce(float), vol.Range(min=0, max=10)
                 ),
@@ -168,27 +169,31 @@ class ClimateSchema:
                 vol.Optional(
                     CONF_TEMPERATURE_STEP, default=DEFAULT_TEMPERATURE_STEP
                 ): vol.All(float, vol.Range(min=0, max=2)),
-                vol.Required(CONF_TEMPERATURE_ADDRESS): ga_validator,
-                vol.Required(CONF_TARGET_TEMPERATURE_STATE_ADDRESS): ga_validator,
-                vol.Optional(CONF_TARGET_TEMPERATURE_ADDRESS): ga_validator,
-                vol.Optional(CONF_SETPOINT_SHIFT_ADDRESS): ga_validator,
-                vol.Optional(CONF_SETPOINT_SHIFT_STATE_ADDRESS): ga_validator,
-                vol.Optional(CONF_OPERATION_MODE_ADDRESS): ga_validator,
-                vol.Optional(CONF_OPERATION_MODE_STATE_ADDRESS): ga_validator,
-                vol.Optional(CONF_CONTROLLER_STATUS_ADDRESS): ga_validator,
-                vol.Optional(CONF_CONTROLLER_STATUS_STATE_ADDRESS): ga_validator,
-                vol.Optional(CONF_CONTROLLER_MODE_ADDRESS): ga_validator,
-                vol.Optional(CONF_CONTROLLER_MODE_STATE_ADDRESS): ga_validator,
-                vol.Optional(CONF_HEAT_COOL_ADDRESS): ga_validator,
-                vol.Optional(CONF_HEAT_COOL_STATE_ADDRESS): ga_validator,
+                vol.Required(CONF_TEMPERATURE_ADDRESS): ga_or_list_validator,
+                vol.Required(
+                    CONF_TARGET_TEMPERATURE_STATE_ADDRESS
+                ): ga_or_list_validator,
+                vol.Optional(CONF_TARGET_TEMPERATURE_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_SETPOINT_SHIFT_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_SETPOINT_SHIFT_STATE_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_OPERATION_MODE_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_OPERATION_MODE_STATE_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_CONTROLLER_STATUS_ADDRESS): ga_or_list_validator,
+                vol.Optional(
+                    CONF_CONTROLLER_STATUS_STATE_ADDRESS
+                ): ga_or_list_validator,
+                vol.Optional(CONF_CONTROLLER_MODE_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_CONTROLLER_MODE_STATE_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_HEAT_COOL_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_HEAT_COOL_STATE_ADDRESS): ga_or_list_validator,
                 vol.Optional(
                     CONF_OPERATION_MODE_FROST_PROTECTION_ADDRESS
-                ): ga_validator,
-                vol.Optional(CONF_OPERATION_MODE_NIGHT_ADDRESS): ga_validator,
-                vol.Optional(CONF_OPERATION_MODE_COMFORT_ADDRESS): ga_validator,
-                vol.Optional(CONF_OPERATION_MODE_STANDBY_ADDRESS): ga_validator,
-                vol.Optional(CONF_ON_OFF_ADDRESS): ga_validator,
-                vol.Optional(CONF_ON_OFF_STATE_ADDRESS): ga_validator,
+                ): ga_or_list_validator,
+                vol.Optional(CONF_OPERATION_MODE_NIGHT_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_OPERATION_MODE_COMFORT_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_OPERATION_MODE_STANDBY_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_ON_OFF_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_ON_OFF_STATE_ADDRESS): ga_or_list_validator,
                 vol.Optional(
                     CONF_ON_OFF_INVERT, default=DEFAULT_ON_OFF_INVERT
                 ): cv.boolean,
@@ -229,13 +234,13 @@ class CoverSchema:
     SCHEMA = vol.Schema(
         {
             vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
-            vol.Optional(CONF_MOVE_LONG_ADDRESS): ga_validator,
-            vol.Optional(CONF_MOVE_SHORT_ADDRESS): ga_validator,
-            vol.Optional(CONF_STOP_ADDRESS): ga_validator,
-            vol.Optional(CONF_POSITION_ADDRESS): ga_validator,
-            vol.Optional(CONF_POSITION_STATE_ADDRESS): ga_validator,
-            vol.Optional(CONF_ANGLE_ADDRESS): ga_validator,
-            vol.Optional(CONF_ANGLE_STATE_ADDRESS): ga_validator,
+            vol.Optional(CONF_MOVE_LONG_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_MOVE_SHORT_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_STOP_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_POSITION_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_POSITION_STATE_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_ANGLE_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_ANGLE_STATE_ADDRESS): ga_or_list_validator,
             vol.Optional(
                 CONF_TRAVELLING_TIME_DOWN, default=DEFAULT_TRAVEL_TIME
             ): cv.positive_float,
@@ -280,10 +285,10 @@ class FanSchema:
     SCHEMA = vol.Schema(
         {
             vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
-            vol.Required(KNX_ADDRESS): ga_validator,
-            vol.Optional(CONF_STATE_ADDRESS): ga_validator,
-            vol.Optional(CONF_OSCILLATION_ADDRESS): ga_validator,
-            vol.Optional(CONF_OSCILLATION_STATE_ADDRESS): ga_validator,
+            vol.Required(KNX_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_STATE_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_OSCILLATION_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_OSCILLATION_STATE_ADDRESS): ga_or_list_validator,
             vol.Optional(CONF_MAX_STEP): cv.byte,
         }
     )
@@ -318,10 +323,10 @@ class LightSchema:
 
     COLOR_SCHEMA = vol.Schema(
         {
-            vol.Optional(KNX_ADDRESS): ga_validator,
-            vol.Optional(CONF_STATE_ADDRESS): ga_validator,
-            vol.Required(CONF_BRIGHTNESS_ADDRESS): ga_validator,
-            vol.Optional(CONF_BRIGHTNESS_STATE_ADDRESS): ga_validator,
+            vol.Optional(KNX_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_STATE_ADDRESS): ga_or_list_validator,
+            vol.Required(CONF_BRIGHTNESS_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_BRIGHTNESS_STATE_ADDRESS): ga_or_list_validator,
         }
     )
 
@@ -329,25 +334,25 @@ class LightSchema:
         vol.Schema(
             {
                 vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
-                vol.Optional(KNX_ADDRESS): ga_validator,
-                vol.Optional(CONF_STATE_ADDRESS): ga_validator,
-                vol.Optional(CONF_BRIGHTNESS_ADDRESS): ga_validator,
-                vol.Optional(CONF_BRIGHTNESS_STATE_ADDRESS): ga_validator,
+                vol.Optional(KNX_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_STATE_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_BRIGHTNESS_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_BRIGHTNESS_STATE_ADDRESS): ga_or_list_validator,
                 vol.Exclusive(CONF_INDIVIDUAL_COLORS, "color"): {
                     vol.Inclusive(CONF_RED, "colors"): COLOR_SCHEMA,
                     vol.Inclusive(CONF_GREEN, "colors"): COLOR_SCHEMA,
                     vol.Inclusive(CONF_BLUE, "colors"): COLOR_SCHEMA,
                     vol.Optional(CONF_WHITE): COLOR_SCHEMA,
                 },
-                vol.Exclusive(CONF_COLOR_ADDRESS, "color"): ga_validator,
-                vol.Optional(CONF_COLOR_STATE_ADDRESS): ga_validator,
-                vol.Optional(CONF_COLOR_TEMP_ADDRESS): ga_validator,
-                vol.Optional(CONF_COLOR_TEMP_STATE_ADDRESS): ga_validator,
+                vol.Exclusive(CONF_COLOR_ADDRESS, "color"): ga_or_list_validator,
+                vol.Optional(CONF_COLOR_STATE_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_COLOR_TEMP_ADDRESS): ga_or_list_validator,
+                vol.Optional(CONF_COLOR_TEMP_STATE_ADDRESS): ga_or_list_validator,
                 vol.Optional(
                     CONF_COLOR_TEMP_MODE, default=DEFAULT_COLOR_TEMP_MODE
                 ): vol.All(vol.Upper, cv.enum(ColorTempModes)),
-                vol.Exclusive(CONF_RGBW_ADDRESS, "color"): ga_validator,
-                vol.Optional(CONF_RGBW_STATE_ADDRESS): ga_validator,
+                vol.Exclusive(CONF_RGBW_ADDRESS, "color"): ga_or_list_validator,
+                vol.Optional(CONF_RGBW_STATE_ADDRESS): ga_or_list_validator,
                 vol.Optional(CONF_MIN_KELVIN, default=DEFAULT_MIN_KELVIN): vol.All(
                     vol.Coerce(int), vol.Range(min=1)
                 ),
@@ -400,7 +405,7 @@ class SceneSchema:
     SCHEMA = vol.Schema(
         {
             vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
-            vol.Required(KNX_ADDRESS): ga_validator,
+            vol.Required(KNX_ADDRESS): ga_or_list_validator,
             vol.Required(CONF_SCENE_NUMBER): cv.positive_int,
         }
     )
@@ -420,7 +425,7 @@ class SensorSchema:
             vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
             vol.Optional(CONF_SYNC_STATE, default=True): sync_state_validator,
             vol.Optional(CONF_ALWAYS_CALLBACK, default=False): cv.boolean,
-            vol.Required(CONF_STATE_ADDRESS): ga_validator,
+            vol.Required(CONF_STATE_ADDRESS): ga_or_list_validator,
             vol.Required(CONF_TYPE): vol.Any(int, float, str),
             vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
         }
@@ -437,8 +442,8 @@ class SwitchSchema:
     SCHEMA = vol.Schema(
         {
             vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
-            vol.Required(KNX_ADDRESS): ga_validator,
-            vol.Optional(CONF_STATE_ADDRESS): ga_validator,
+            vol.Required(KNX_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_STATE_ADDRESS): ga_or_list_validator,
             vol.Optional(CONF_INVERT): cv.boolean,
         }
     )
@@ -470,18 +475,18 @@ class WeatherSchema:
             vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
             vol.Optional(CONF_SYNC_STATE, default=True): sync_state_validator,
             vol.Optional(CONF_XKNX_CREATE_SENSORS, default=False): cv.boolean,
-            vol.Required(CONF_XKNX_TEMPERATURE_ADDRESS): ga_validator,
-            vol.Optional(CONF_XKNX_BRIGHTNESS_SOUTH_ADDRESS): ga_validator,
-            vol.Optional(CONF_XKNX_BRIGHTNESS_EAST_ADDRESS): ga_validator,
-            vol.Optional(CONF_XKNX_BRIGHTNESS_WEST_ADDRESS): ga_validator,
-            vol.Optional(CONF_XKNX_BRIGHTNESS_NORTH_ADDRESS): ga_validator,
-            vol.Optional(CONF_XKNX_WIND_SPEED_ADDRESS): ga_validator,
-            vol.Optional(CONF_XKNX_WIND_BEARING_ADDRESS): ga_validator,
-            vol.Optional(CONF_XKNX_RAIN_ALARM_ADDRESS): ga_validator,
-            vol.Optional(CONF_XKNX_FROST_ALARM_ADDRESS): ga_validator,
-            vol.Optional(CONF_XKNX_WIND_ALARM_ADDRESS): ga_validator,
-            vol.Optional(CONF_XKNX_DAY_NIGHT_ADDRESS): ga_validator,
-            vol.Optional(CONF_XKNX_AIR_PRESSURE_ADDRESS): ga_validator,
-            vol.Optional(CONF_XKNX_HUMIDITY_ADDRESS): ga_validator,
+            vol.Required(CONF_XKNX_TEMPERATURE_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_XKNX_BRIGHTNESS_SOUTH_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_XKNX_BRIGHTNESS_EAST_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_XKNX_BRIGHTNESS_WEST_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_XKNX_BRIGHTNESS_NORTH_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_XKNX_WIND_SPEED_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_XKNX_WIND_BEARING_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_XKNX_RAIN_ALARM_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_XKNX_FROST_ALARM_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_XKNX_WIND_ALARM_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_XKNX_DAY_NIGHT_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_XKNX_AIR_PRESSURE_ADDRESS): ga_or_list_validator,
+            vol.Optional(CONF_XKNX_HUMIDITY_ADDRESS): ga_or_list_validator,
         }
     )
diff --git a/xknx/devices/binary_sensor.py b/xknx/devices/binary_sensor.py
index 30aa4764..579fda54 100644
--- a/xknx/devices/binary_sensor.py
+++ b/xknx/devices/binary_sensor.py
@@ -12,14 +12,13 @@ import asyncio
 import time
 from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, cast
 
-from xknx.remote_value import RemoteValueSwitch
+from xknx.remote_value import GroupAddressesType, RemoteValueSwitch
 
 from .action import Action
 from .device import Device, DeviceCallbackType
 
 if TYPE_CHECKING:
     from xknx.telegram import Telegram
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -31,7 +30,7 @@ class BinarySensor(Device):
         self,
         xknx: "XKNX",
         name: str,
-        group_address_state: "GroupAddressableType" = None,
+        group_address_state: GroupAddressesType = None,
         invert: bool = False,
         sync_state: bool = True,
         ignore_internal_state: bool = False,
diff --git a/xknx/devices/climate.py b/xknx/devices/climate.py
index e6941fb2..bc1c6740 100644
--- a/xknx/devices/climate.py
+++ b/xknx/devices/climate.py
@@ -9,6 +9,8 @@ import logging
 from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Union, cast
 
 from xknx.remote_value import (
+    GroupAddressesType,
+    RemoteValue,
     RemoteValueSetpointShift,
     RemoteValueSwitch,
     RemoteValueTemp,
@@ -19,9 +21,8 @@ from .device import Device, DeviceCallbackType
 from .sensor import Sensor
 
 if TYPE_CHECKING:
-    from xknx.remote_value import RemoteValue
     from xknx.telegram import Telegram
-    from xknx.telegram.address import GroupAddress, GroupAddressableType
+    from xknx.telegram.address import GroupAddress
     from xknx.xknx import XKNX
 
 logger = logging.getLogger("xknx.log")
@@ -48,17 +49,17 @@ class Climate(Device):
         self,
         xknx: "XKNX",
         name: str,
-        group_address_temperature: Optional["GroupAddressableType"] = None,
-        group_address_target_temperature: Optional["GroupAddressableType"] = None,
-        group_address_target_temperature_state: Optional["GroupAddressableType"] = None,
-        group_address_setpoint_shift: Optional["GroupAddressableType"] = None,
-        group_address_setpoint_shift_state: Optional["GroupAddressableType"] = None,
+        group_address_temperature: Optional[GroupAddressesType] = None,
+        group_address_target_temperature: Optional[GroupAddressesType] = None,
+        group_address_target_temperature_state: Optional[GroupAddressesType] = None,
+        group_address_setpoint_shift: Optional[GroupAddressesType] = None,
+        group_address_setpoint_shift_state: Optional[GroupAddressesType] = None,
         setpoint_shift_mode: SetpointShiftMode = DEFAULT_SETPOINT_SHIFT_MODE,
         setpoint_shift_max: float = DEFAULT_SETPOINT_SHIFT_MAX,
         setpoint_shift_min: float = DEFAULT_SETPOINT_SHIFT_MIN,
         temperature_step: float = DEFAULT_TEMPERATURE_STEP,
-        group_address_on_off: Optional["GroupAddressableType"] = None,
-        group_address_on_off_state: Optional["GroupAddressableType"] = None,
+        group_address_on_off: Optional[GroupAddressesType] = None,
+        group_address_on_off_state: Optional[GroupAddressesType] = None,
         on_off_invert: bool = False,
         min_temp: Optional[float] = None,
         max_temp: Optional[float] = None,
@@ -130,7 +131,7 @@ class Climate(Device):
         if create_temperature_sensors:
             self.create_temperature_sensors()
 
-    def _iter_remote_values(self) -> Iterator["RemoteValue[Any]"]:
+    def _iter_remote_values(self) -> Iterator[RemoteValue[Any]]:
         """Iterate the devices RemoteValue classes."""
         yield from (
             self.temperature,
diff --git a/xknx/devices/climate_mode.py b/xknx/devices/climate_mode.py
index a1d0161c..859f9e57 100644
--- a/xknx/devices/climate_mode.py
+++ b/xknx/devices/climate_mode.py
@@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Union
 
 from xknx.dpt.dpt_hvac_mode import HVACControllerMode, HVACOperationMode
 from xknx.exceptions import DeviceIllegalValue
+from xknx.remote_value import GroupAddressesType, RemoteValue
 from xknx.remote_value.remote_value_climate_mode import (
     RemoteValueBinaryHeatCool,
     RemoteValueBinaryOperationMode,
@@ -20,9 +21,7 @@ from xknx.remote_value.remote_value_climate_mode import (
 from .device import Device, DeviceCallbackType
 
 if TYPE_CHECKING:
-    from xknx.remote_value import RemoteValue
     from xknx.telegram import Telegram
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -35,20 +34,18 @@ class ClimateMode(Device):
         self,
         xknx: "XKNX",
         name: str,
-        group_address_operation_mode: Optional["GroupAddressableType"] = None,
-        group_address_operation_mode_state: Optional["GroupAddressableType"] = None,
-        group_address_operation_mode_protection: Optional[
-            "GroupAddressableType"
-        ] = None,
-        group_address_operation_mode_night: Optional["GroupAddressableType"] = None,
-        group_address_operation_mode_comfort: Optional["GroupAddressableType"] = None,
-        group_address_operation_mode_standby: Optional["GroupAddressableType"] = None,
-        group_address_controller_status: Optional["GroupAddressableType"] = None,
-        group_address_controller_status_state: Optional["GroupAddressableType"] = None,
-        group_address_controller_mode: Optional["GroupAddressableType"] = None,
-        group_address_controller_mode_state: Optional["GroupAddressableType"] = None,
-        group_address_heat_cool: Optional["GroupAddressableType"] = None,
-        group_address_heat_cool_state: Optional["GroupAddressableType"] = None,
+        group_address_operation_mode: Optional[GroupAddressesType] = None,
+        group_address_operation_mode_state: Optional[GroupAddressesType] = None,
+        group_address_operation_mode_protection: Optional[GroupAddressesType] = None,
+        group_address_operation_mode_night: Optional[GroupAddressesType] = None,
+        group_address_operation_mode_comfort: Optional[GroupAddressesType] = None,
+        group_address_operation_mode_standby: Optional[GroupAddressesType] = None,
+        group_address_controller_status: Optional[GroupAddressesType] = None,
+        group_address_controller_status_state: Optional[GroupAddressesType] = None,
+        group_address_controller_mode: Optional[GroupAddressesType] = None,
+        group_address_controller_mode_state: Optional[GroupAddressesType] = None,
+        group_address_heat_cool: Optional[GroupAddressesType] = None,
+        group_address_heat_cool_state: Optional[GroupAddressesType] = None,
         operation_modes: Optional[List[Union[str, HVACOperationMode]]] = None,
         controller_modes: Optional[List[Union[str, HVACControllerMode]]] = None,
         device_updated_cb: Optional[DeviceCallbackType] = None,
@@ -230,7 +227,7 @@ class ClimateMode(Device):
 
     def _iter_remote_values(
         self,
-    ) -> Iterator["RemoteValue[Any]"]:
+    ) -> Iterator[RemoteValue[Any]]:
         """Iterate climate mode RemoteValue classes."""
         return chain(
             self._iter_byte_operation_modes(),
diff --git a/xknx/devices/cover.py b/xknx/devices/cover.py
index 9bffa9c8..b6bd607e 100644
--- a/xknx/devices/cover.py
+++ b/xknx/devices/cover.py
@@ -11,6 +11,8 @@ import logging
 from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional
 
 from xknx.remote_value import (
+    GroupAddressesType,
+    RemoteValue,
     RemoteValueScaling,
     RemoteValueStep,
     RemoteValueSwitch,
@@ -21,9 +23,7 @@ from .device import Device, DeviceCallbackType
 from .travelcalculator import TravelCalculator, TravelStatus
 
 if TYPE_CHECKING:
-    from xknx.remote_value import RemoteValue
     from xknx.telegram import Telegram
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 logger = logging.getLogger("xknx.log")
@@ -44,13 +44,13 @@ class Cover(Device):
         self,
         xknx: "XKNX",
         name: str,
-        group_address_long: Optional["GroupAddressableType"] = None,
-        group_address_short: Optional["GroupAddressableType"] = None,
-        group_address_stop: Optional["GroupAddressableType"] = None,
-        group_address_position: Optional["GroupAddressableType"] = None,
-        group_address_position_state: Optional["GroupAddressableType"] = None,
-        group_address_angle: Optional["GroupAddressableType"] = None,
-        group_address_angle_state: Optional["GroupAddressableType"] = None,
+        group_address_long: Optional[GroupAddressesType] = None,
+        group_address_short: Optional[GroupAddressesType] = None,
+        group_address_stop: Optional[GroupAddressesType] = None,
+        group_address_position: Optional[GroupAddressesType] = None,
+        group_address_position_state: Optional[GroupAddressesType] = None,
+        group_address_angle: Optional[GroupAddressesType] = None,
+        group_address_angle_state: Optional[GroupAddressesType] = None,
         travel_time_down: float = DEFAULT_TRAVEL_TIME_DOWN,
         travel_time_up: float = DEFAULT_TRAVEL_TIME_UP,
         invert_position: bool = False,
@@ -129,7 +129,7 @@ class Cover(Device):
 
         self.device_class = device_class
 
-    def _iter_remote_values(self) -> Iterator["RemoteValue[Any]"]:
+    def _iter_remote_values(self) -> Iterator[RemoteValue[Any]]:
         """Iterate the devices RemoteValue classes."""
         yield self.updown
         yield self.step
diff --git a/xknx/devices/datetime.py b/xknx/devices/datetime.py
index d57072b6..23c1d412 100644
--- a/xknx/devices/datetime.py
+++ b/xknx/devices/datetime.py
@@ -9,13 +9,12 @@ import asyncio
 import time
 from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional
 
-from xknx.remote_value import RemoteValueDateTime
+from xknx.remote_value import GroupAddressesType, RemoteValueDateTime
 
 from .device import Device, DeviceCallbackType
 
 if TYPE_CHECKING:
     from xknx.telegram import Telegram
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -29,7 +28,7 @@ class DateTime(Device):
         name: str,
         broadcast_type: str = "TIME",
         localtime: bool = True,
-        group_address: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
         device_updated_cb: Optional[DeviceCallbackType] = None,
     ):
         """Initialize DateTime class."""
diff --git a/xknx/devices/expose_sensor.py b/xknx/devices/expose_sensor.py
index 125990bf..701efd0c 100644
--- a/xknx/devices/expose_sensor.py
+++ b/xknx/devices/expose_sensor.py
@@ -13,14 +13,17 @@ LCD display.
 """
 from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Union
 
-from xknx.remote_value import RemoteValueSensor, RemoteValueSwitch
+from xknx.remote_value import (
+    GroupAddressesType,
+    RemoteValue,
+    RemoteValueSensor,
+    RemoteValueSwitch,
+)
 
 from .device import Device, DeviceCallbackType
 
 if TYPE_CHECKING:
-    from xknx.remote_value import RemoteValue
     from xknx.telegram import Telegram
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -31,7 +34,7 @@ class ExposeSensor(Device):
         self,
         xknx: "XKNX",
         name: str,
-        group_address: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
         value_type: Optional[Union[int, str]] = None,
         device_updated_cb: Optional[DeviceCallbackType] = None,
     ):
@@ -58,7 +61,7 @@ class ExposeSensor(Device):
                 value_type=value_type,
             )
 
-    def _iter_remote_values(self) -> Iterator["RemoteValue[Any]"]:
+    def _iter_remote_values(self) -> Iterator[RemoteValue[Any]]:
         """Iterate the devices RemoteValue classes."""
         yield self.sensor_value
 
diff --git a/xknx/devices/fan.py b/xknx/devices/fan.py
index c7a36ce6..0b39d083 100644
--- a/xknx/devices/fan.py
+++ b/xknx/devices/fan.py
@@ -11,6 +11,8 @@ import logging
 from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Union
 
 from xknx.remote_value import (
+    GroupAddressesType,
+    RemoteValue,
     RemoteValueDptValue1Ucount,
     RemoteValueScaling,
     RemoteValueSwitch,
@@ -19,9 +21,7 @@ from xknx.remote_value import (
 from .device import Device, DeviceCallbackType
 
 if TYPE_CHECKING:
-    from xknx.remote_value import RemoteValue
     from xknx.telegram import Telegram
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 logger = logging.getLogger("xknx.log")
@@ -44,10 +44,10 @@ class Fan(Device):
         self,
         xknx: "XKNX",
         name: str,
-        group_address_speed: Optional["GroupAddressableType"] = None,
-        group_address_speed_state: Optional["GroupAddressableType"] = None,
-        group_address_oscillation: Optional["GroupAddressableType"] = None,
-        group_address_oscillation_state: Optional["GroupAddressableType"] = None,
+        group_address_speed: Optional[GroupAddressesType] = None,
+        group_address_speed_state: Optional[GroupAddressesType] = None,
+        group_address_oscillation: Optional[GroupAddressesType] = None,
+        group_address_oscillation_state: Optional[GroupAddressesType] = None,
         device_updated_cb: Optional[DeviceCallbackType] = None,
         max_step: Optional[int] = None,
     ):
@@ -89,7 +89,7 @@ class Fan(Device):
             after_update_cb=self.after_update,
         )
 
-    def _iter_remote_values(self) -> Iterator["RemoteValue[Any]"]:
+    def _iter_remote_values(self) -> Iterator[RemoteValue[Any]]:
         """Iterate the devices RemoteValue classes."""
         yield from (self.speed, self.oscillation)
 
diff --git a/xknx/devices/light.py b/xknx/devices/light.py
index 8f5c8f65..d5e9c010 100644
--- a/xknx/devices/light.py
+++ b/xknx/devices/light.py
@@ -24,6 +24,8 @@ from typing import (
 )
 
 from xknx.remote_value import (
+    GroupAddressesType,
+    RemoteValue,
     RemoteValueColorRGB,
     RemoteValueColorRGBW,
     RemoteValueDpt2ByteUnsigned,
@@ -34,9 +36,7 @@ from xknx.remote_value import (
 from .device import Device, DeviceCallbackType
 
 if TYPE_CHECKING:
-    from xknx.remote_value import RemoteValue
     from xknx.telegram import Telegram
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 AsyncCallback = Callable[[], Awaitable[None]]
@@ -57,10 +57,10 @@ class _SwitchAndBrightness:
         xknx: "XKNX",
         name: str,
         feature_name: str,
-        group_address_switch: Optional["GroupAddressableType"] = None,
-        group_address_switch_state: Optional["GroupAddressableType"] = None,
-        group_address_brightness: Optional["GroupAddressableType"] = None,
-        group_address_brightness_state: Optional["GroupAddressableType"] = None,
+        group_address_switch: Optional[GroupAddressesType] = None,
+        group_address_switch_state: Optional[GroupAddressesType] = None,
+        group_address_brightness: Optional[GroupAddressesType] = None,
+        group_address_brightness_state: Optional[GroupAddressesType] = None,
         after_update_cb: Optional[AsyncCallback] = None,
     ):
         self.switch = RemoteValueSwitch(
@@ -114,34 +114,34 @@ class Light(Device):
         self,
         xknx: "XKNX",
         name: str,
-        group_address_switch: Optional["GroupAddressableType"] = None,
-        group_address_switch_state: Optional["GroupAddressableType"] = None,
-        group_address_brightness: Optional["GroupAddressableType"] = None,
-        group_address_brightness_state: Optional["GroupAddressableType"] = None,
-        group_address_color: Optional["GroupAddressableType"] = None,
-        group_address_color_state: Optional["GroupAddressableType"] = None,
-        group_address_rgbw: Optional["GroupAddressableType"] = None,
-        group_address_rgbw_state: Optional["GroupAddressableType"] = None,
-        group_address_tunable_white: Optional["GroupAddressableType"] = None,
-        group_address_tunable_white_state: Optional["GroupAddressableType"] = None,
-        group_address_color_temperature: Optional["GroupAddressableType"] = None,
-        group_address_color_temperature_state: Optional["GroupAddressableType"] = None,
-        group_address_switch_red: Optional["GroupAddressableType"] = None,
-        group_address_switch_red_state: Optional["GroupAddressableType"] = None,
-        group_address_brightness_red: Optional["GroupAddressableType"] = None,
-        group_address_brightness_red_state: Optional["GroupAddressableType"] = None,
-        group_address_switch_green: Optional["GroupAddressableType"] = None,
-        group_address_switch_green_state: Optional["GroupAddressableType"] = None,
-        group_address_brightness_green: Optional["GroupAddressableType"] = None,
-        group_address_brightness_green_state: Optional["GroupAddressableType"] = None,
-        group_address_switch_blue: Optional["GroupAddressableType"] = None,
-        group_address_switch_blue_state: Optional["GroupAddressableType"] = None,
-        group_address_brightness_blue: Optional["GroupAddressableType"] = None,
-        group_address_brightness_blue_state: Optional["GroupAddressableType"] = None,
-        group_address_switch_white: Optional["GroupAddressableType"] = None,
-        group_address_switch_white_state: Optional["GroupAddressableType"] = None,
-        group_address_brightness_white: Optional["GroupAddressableType"] = None,
-        group_address_brightness_white_state: Optional["GroupAddressableType"] = None,
+        group_address_switch: Optional[GroupAddressesType] = None,
+        group_address_switch_state: Optional[GroupAddressesType] = None,
+        group_address_brightness: Optional[GroupAddressesType] = None,
+        group_address_brightness_state: Optional[GroupAddressesType] = None,
+        group_address_color: Optional[GroupAddressesType] = None,
+        group_address_color_state: Optional[GroupAddressesType] = None,
+        group_address_rgbw: Optional[GroupAddressesType] = None,
+        group_address_rgbw_state: Optional[GroupAddressesType] = None,
+        group_address_tunable_white: Optional[GroupAddressesType] = None,
+        group_address_tunable_white_state: Optional[GroupAddressesType] = None,
+        group_address_color_temperature: Optional[GroupAddressesType] = None,
+        group_address_color_temperature_state: Optional[GroupAddressesType] = None,
+        group_address_switch_red: Optional[GroupAddressesType] = None,
+        group_address_switch_red_state: Optional[GroupAddressesType] = None,
+        group_address_brightness_red: Optional[GroupAddressesType] = None,
+        group_address_brightness_red_state: Optional[GroupAddressesType] = None,
+        group_address_switch_green: Optional[GroupAddressesType] = None,
+        group_address_switch_green_state: Optional[GroupAddressesType] = None,
+        group_address_brightness_green: Optional[GroupAddressesType] = None,
+        group_address_brightness_green_state: Optional[GroupAddressesType] = None,
+        group_address_switch_blue: Optional[GroupAddressesType] = None,
+        group_address_switch_blue_state: Optional[GroupAddressesType] = None,
+        group_address_brightness_blue: Optional[GroupAddressesType] = None,
+        group_address_brightness_blue_state: Optional[GroupAddressesType] = None,
+        group_address_switch_white: Optional[GroupAddressesType] = None,
+        group_address_switch_white_state: Optional[GroupAddressesType] = None,
+        group_address_brightness_white: Optional[GroupAddressesType] = None,
+        group_address_brightness_white_state: Optional[GroupAddressesType] = None,
         min_kelvin: Optional[int] = None,
         max_kelvin: Optional[int] = None,
         device_updated_cb: Optional[DeviceCallbackType] = None,
@@ -253,7 +253,7 @@ class Light(Device):
         self.min_kelvin = min_kelvin
         self.max_kelvin = max_kelvin
 
-    def _iter_remote_values(self) -> Iterator["RemoteValue[Any]"]:
+    def _iter_remote_values(self) -> Iterator[RemoteValue[Any]]:
         """Iterate the devices RemoteValue classes."""
         yield self.switch
         yield self.brightness
@@ -302,10 +302,10 @@ class Light(Device):
     def read_color_from_config(
         cls, color: str, config: Any
     ) -> Tuple[
-        Optional["GroupAddressableType"],
-        Optional["GroupAddressableType"],
-        Optional["GroupAddressableType"],
-        Optional["GroupAddressableType"],
+        Optional[GroupAddressesType],
+        Optional[GroupAddressesType],
+        Optional[GroupAddressesType],
+        Optional[GroupAddressesType],
     ]:
         """Load color configuration from configuration structure."""
         if "individual_colors" in config and color in config["individual_colors"]:
diff --git a/xknx/devices/notification.py b/xknx/devices/notification.py
index 840073f8..9dfbfa70 100644
--- a/xknx/devices/notification.py
+++ b/xknx/devices/notification.py
@@ -2,13 +2,12 @@
 import logging
 from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional
 
-from xknx.remote_value import RemoteValueString
+from xknx.remote_value import GroupAddressesType, RemoteValueString
 
 from .device import Device, DeviceCallbackType
 
 if TYPE_CHECKING:
     from xknx.telegram import Telegram
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 logger = logging.getLogger("xknx.log")
@@ -21,8 +20,8 @@ class Notification(Device):
         self,
         xknx: "XKNX",
         name: str,
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         device_updated_cb: Optional[DeviceCallbackType] = None,
     ):
         """Initialize notification class."""
diff --git a/xknx/devices/scene.py b/xknx/devices/scene.py
index bd2c90db..5f8b1cb2 100644
--- a/xknx/devices/scene.py
+++ b/xknx/devices/scene.py
@@ -2,12 +2,11 @@
 import logging
 from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional
 
-from xknx.remote_value import RemoteValueSceneNumber
+from xknx.remote_value import GroupAddressesType, RemoteValueSceneNumber
 
 from .device import Device, DeviceCallbackType
 
 if TYPE_CHECKING:
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 logger = logging.getLogger("xknx.log")
@@ -20,7 +19,7 @@ class Scene(Device):
         self,
         xknx: "XKNX",
         name: str,
-        group_address: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
         scene_number: int = 1,
         device_updated_cb: Optional[DeviceCallbackType] = None,
     ):
diff --git a/xknx/devices/sensor.py b/xknx/devices/sensor.py
index 7fbcadf9..a7ade455 100644
--- a/xknx/devices/sensor.py
+++ b/xknx/devices/sensor.py
@@ -8,14 +8,17 @@ It provides functionality for
 """
 from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Union
 
-from xknx.remote_value import RemoteValueControl, RemoteValueSensor
+from xknx.remote_value import (
+    GroupAddressesType,
+    RemoteValue,
+    RemoteValueControl,
+    RemoteValueSensor,
+)
 
 from .device import Device, DeviceCallbackType
 
 if TYPE_CHECKING:
-    from xknx.remote_value import RemoteValue
     from xknx.telegram import Telegram
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -26,7 +29,7 @@ class Sensor(Device):
         self,
         xknx: "XKNX",
         name: str,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         sync_state: bool = True,
         always_callback: bool = False,
         value_type: Optional[Union[int, str]] = None,
@@ -64,7 +67,7 @@ class Sensor(Device):
         self.always_callback = always_callback
         self.ha_value_template = ha_value_template
 
-    def _iter_remote_values(self) -> Iterator["RemoteValue[Any]"]:
+    def _iter_remote_values(self) -> Iterator[RemoteValue[Any]]:
         """Iterate the devices RemoteValue classes."""
         yield self.sensor_value
 
diff --git a/xknx/devices/switch.py b/xknx/devices/switch.py
index 16914abb..cf2a983c 100644
--- a/xknx/devices/switch.py
+++ b/xknx/devices/switch.py
@@ -10,13 +10,12 @@ import asyncio
 import logging
 from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional
 
-from xknx.remote_value import RemoteValueSwitch
+from xknx.remote_value import GroupAddressesType, RemoteValueSwitch
 
 from .device import Device, DeviceCallbackType
 
 if TYPE_CHECKING:
     from xknx.telegram import Telegram
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 logger = logging.getLogger("xknx.log")
@@ -29,8 +28,8 @@ class Switch(Device):
         self,
         xknx: "XKNX",
         name: str,
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         invert: bool = False,
         reset_after: Optional[float] = None,
         device_updated_cb: Optional[DeviceCallbackType] = None,
diff --git a/xknx/devices/weather.py b/xknx/devices/weather.py
index dd8fa2b5..385a0a85 100644
--- a/xknx/devices/weather.py
+++ b/xknx/devices/weather.py
@@ -16,14 +16,18 @@ from datetime import date, datetime
 from enum import Enum
 from typing import TYPE_CHECKING, Any, Callable, Dict, Iterator, Optional, Tuple
 
-from xknx.remote_value import RemoteValue, RemoteValueSensor, RemoteValueSwitch
+from xknx.remote_value import (
+    GroupAddressesType,
+    RemoteValue,
+    RemoteValueSensor,
+    RemoteValueSwitch,
+)
 
 from . import BinarySensor, Sensor
 from .device import Device, DeviceCallbackType
 
 if TYPE_CHECKING:
     from xknx.telegram import Telegram
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -81,19 +85,19 @@ class Weather(Device):
         self,
         xknx: "XKNX",
         name: str,
-        group_address_temperature: Optional["GroupAddressableType"] = None,
-        group_address_brightness_south: Optional["GroupAddressableType"] = None,
-        group_address_brightness_north: Optional["GroupAddressableType"] = None,
-        group_address_brightness_west: Optional["GroupAddressableType"] = None,
-        group_address_brightness_east: Optional["GroupAddressableType"] = None,
-        group_address_wind_speed: Optional["GroupAddressableType"] = None,
-        group_address_wind_bearing: Optional["GroupAddressableType"] = None,
-        group_address_rain_alarm: Optional["GroupAddressableType"] = None,
-        group_address_frost_alarm: Optional["GroupAddressableType"] = None,
-        group_address_wind_alarm: Optional["GroupAddressableType"] = None,
-        group_address_day_night: Optional["GroupAddressableType"] = None,
-        group_address_air_pressure: Optional["GroupAddressableType"] = None,
-        group_address_humidity: Optional["GroupAddressableType"] = None,
+        group_address_temperature: Optional[GroupAddressesType] = None,
+        group_address_brightness_south: Optional[GroupAddressesType] = None,
+        group_address_brightness_north: Optional[GroupAddressesType] = None,
+        group_address_brightness_west: Optional[GroupAddressesType] = None,
+        group_address_brightness_east: Optional[GroupAddressesType] = None,
+        group_address_wind_speed: Optional[GroupAddressesType] = None,
+        group_address_wind_bearing: Optional[GroupAddressesType] = None,
+        group_address_rain_alarm: Optional[GroupAddressesType] = None,
+        group_address_frost_alarm: Optional[GroupAddressesType] = None,
+        group_address_wind_alarm: Optional[GroupAddressesType] = None,
+        group_address_day_night: Optional[GroupAddressesType] = None,
+        group_address_air_pressure: Optional[GroupAddressesType] = None,
+        group_address_humidity: Optional[GroupAddressesType] = None,
         create_sensors: bool = False,
         sync_state: bool = True,
         device_updated_cb: Optional[DeviceCallbackType] = None,
diff --git a/xknx/remote_value/__init__.py b/xknx/remote_value/__init__.py
index e94c38e3..5c2df5cd 100644
--- a/xknx/remote_value/__init__.py
+++ b/xknx/remote_value/__init__.py
@@ -1,6 +1,6 @@
 """Module for handling values on the KNX bus."""
 # flake8: noqa
-from .remote_value import RemoteValue
+from .remote_value import GroupAddressesType, RemoteValue
 from .remote_value_1count import RemoteValue1Count
 from .remote_value_climate_mode import (
     RemoteValueBinaryHeatCool,
@@ -25,6 +25,7 @@ from .remote_value_temp import RemoteValueTemp
 from .remote_value_updown import RemoteValueUpDown
 
 __all__ = [
+    "GroupAddressesType",
     "RemoteValue",
     "RemoteValue1Count",
     "RemoteValueBinaryHeatCool",
diff --git a/xknx/remote_value/remote_value.py b/xknx/remote_value/remote_value.py
index e6d1ba87..d2081aa3 100644
--- a/xknx/remote_value/remote_value.py
+++ b/xknx/remote_value/remote_value.py
@@ -32,6 +32,7 @@ if TYPE_CHECKING:
 logger = logging.getLogger("xknx.log")
 
 AsyncCallbackType = Callable[[], Awaitable[None]]
+GroupAddressesType = Union["GroupAddressableType", List["GroupAddressableType"]]
 
 
 class RemoteValue(ABC, Generic[DPTPayloadType]):
@@ -41,28 +42,32 @@ class RemoteValue(ABC, Generic[DPTPayloadType]):
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         sync_state: bool = True,
         device_name: Optional[str] = None,
         feature_name: Optional[str] = None,
         after_update_cb: Optional[AsyncCallbackType] = None,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize RemoteValue class."""
         # pylint: disable=too-many-arguments
         self.xknx: "XKNX" = xknx
-
-        if group_address is not None:
-            group_address = GroupAddress(group_address)
-        if group_address_state is not None:
-            group_address_state = GroupAddress(group_address_state)
-        self.group_address: Optional[GroupAddress] = group_address
-        self.group_address_state: Optional[GroupAddress] = group_address_state
-
-        self.passive_group_addresses: List[
-            GroupAddress
-        ] = RemoteValue.get_passive_group_addresses(passive_group_addresses)
+        self.passive_group_addresses: List[GroupAddress] = []
+
+        def unpack_group_addresses(
+            addresses: Optional[GroupAddressesType],
+        ) -> Optional[GroupAddress]:
+            """Parse group addresses and assign passive addresses when given."""
+            if addresses is None:
+                return None
+            if not isinstance(addresses, list):
+                return GroupAddress(addresses)
+            active, *passive = map(GroupAddress, addresses)
+            self.passive_group_addresses.extend(passive)  # type: ignore
+            return active
+
+        self.group_address = unpack_group_addresses(group_address)
+        self.group_address_state = unpack_group_addresses(group_address_state)
 
         self.device_name: str = "Unknown" if device_name is None else device_name
         self.feature_name: str = "Unknown" if feature_name is None else feature_name
@@ -275,12 +280,3 @@ class RemoteValue(ABC, Generic[DPTPayloadType]):
             if key not in self.__dict__:
                 return False
         return True
-
-    @staticmethod
-    def get_passive_group_addresses(
-        passive_group_addresses: Optional[List["GroupAddressableType"]],
-    ) -> List[GroupAddress]:
-        """Obtain passive state group addresses."""
-        if passive_group_addresses is None:
-            return []
-        return [GroupAddress(ga) for ga in passive_group_addresses]
diff --git a/xknx/remote_value/remote_value_climate_mode.py b/xknx/remote_value/remote_value_climate_mode.py
index 6756e972..2b982d1c 100644
--- a/xknx/remote_value/remote_value_climate_mode.py
+++ b/xknx/remote_value/remote_value_climate_mode.py
@@ -18,10 +18,9 @@ from xknx.dpt.dpt import DPTPayloadType
 from xknx.dpt.dpt_hvac_mode import HVACControllerMode, HVACModeType, HVACOperationMode
 from xknx.exceptions import ConversionError, CouldNotParseTelegram
 
-from .remote_value import AsyncCallbackType, RemoteValue
+from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -49,14 +48,13 @@ class RemoteValueOperationMode(RemoteValueClimateModeBase[DPTArray, HVACOperatio
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         sync_state: bool = True,
         device_name: Optional[str] = None,
         feature_name: str = "Climate mode",
         climate_mode_type: Optional[ClimateModeType] = None,
         after_update_cb: Optional[AsyncCallbackType] = None,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize remote value of KNX climate mode."""
         # pylint: disable=too-many-arguments
@@ -68,7 +66,6 @@ class RemoteValueOperationMode(RemoteValueClimateModeBase[DPTArray, HVACOperatio
             device_name=device_name,
             feature_name=feature_name,
             after_update_cb=after_update_cb,
-            passive_group_addresses=passive_group_addresses,
         )
         if not isinstance(climate_mode_type, self.ClimateModeType):
             raise ConversionError(
@@ -115,13 +112,12 @@ class RemoteValueControllerMode(
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         sync_state: bool = True,
         device_name: Optional[str] = None,
         feature_name: str = "Controller Mode",
         after_update_cb: Optional[AsyncCallbackType] = None,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize remote value of KNX climate mode."""
         # pylint: disable=too-many-arguments
@@ -133,7 +129,6 @@ class RemoteValueControllerMode(
             device_name=device_name,
             feature_name=feature_name,
             after_update_cb=after_update_cb,
-            passive_group_addresses=passive_group_addresses,
         )
 
     @staticmethod
@@ -170,8 +165,8 @@ class RemoteValueBinaryOperationMode(
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         sync_state: bool = True,
         device_name: Optional[str] = None,
         feature_name: str = "Climate mode binary",
@@ -256,8 +251,8 @@ class RemoteValueBinaryHeatCool(
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         sync_state: bool = True,
         device_name: Optional[str] = None,
         feature_name: str = "Controller mode Heat/Cool",
diff --git a/xknx/remote_value/remote_value_color_rgb.py b/xknx/remote_value/remote_value_color_rgb.py
index c0d44adb..16a62638 100644
--- a/xknx/remote_value/remote_value_color_rgb.py
+++ b/xknx/remote_value/remote_value_color_rgb.py
@@ -3,15 +3,14 @@ Module for managing an RGB remote value.
 
 DPT 232.600.
 """
-from typing import TYPE_CHECKING, List, Optional, Sequence, Tuple, Union
+from typing import TYPE_CHECKING, Optional, Sequence, Tuple, Union
 
 from xknx.dpt import DPTArray, DPTBinary
 from xknx.exceptions import ConversionError
 
-from .remote_value import AsyncCallbackType, RemoteValue
+from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -23,12 +22,11 @@ class RemoteValueColorRGB(RemoteValue[DPTArray]):
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         device_name: Optional[str] = None,
         feature_name: str = "Color RGB",
         after_update_cb: Optional[AsyncCallbackType] = None,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize remote value of KNX DPT 232.600 (DPT_Color_RGB)."""
         # pylint: disable=too-many-arguments
@@ -39,7 +37,6 @@ class RemoteValueColorRGB(RemoteValue[DPTArray]):
             device_name=device_name,
             feature_name=feature_name,
             after_update_cb=after_update_cb,
-            passive_group_addresses=passive_group_addresses,
         )
 
     def payload_valid(
diff --git a/xknx/remote_value/remote_value_color_rgbw.py b/xknx/remote_value/remote_value_color_rgbw.py
index 5f6bec17..b42fe687 100644
--- a/xknx/remote_value/remote_value_color_rgbw.py
+++ b/xknx/remote_value/remote_value_color_rgbw.py
@@ -3,15 +3,14 @@ Module for managing an RGBW remote value.
 
 DPT 251.600.
 """
-from typing import TYPE_CHECKING, List, Optional, Sequence, Tuple, Union
+from typing import TYPE_CHECKING, Optional, Sequence, Tuple, Union
 
 from xknx.dpt import DPTArray, DPTBinary
 from xknx.exceptions import ConversionError
 
-from .remote_value import AsyncCallbackType, RemoteValue
+from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -21,12 +20,11 @@ class RemoteValueColorRGBW(RemoteValue[DPTArray]):
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         device_name: Optional[str] = None,
         feature_name: str = "Color RGBW",
         after_update_cb: Optional[AsyncCallbackType] = None,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize remote value of KNX DPT 251.600 (DPT_Color_RGBW)."""
         # pylint: disable=too-many-arguments
@@ -37,7 +35,6 @@ class RemoteValueColorRGBW(RemoteValue[DPTArray]):
             device_name=device_name,
             feature_name=feature_name,
             after_update_cb=after_update_cb,
-            passive_group_addresses=passive_group_addresses,
         )
         self.previous_value: Tuple[int, ...] = (0, 0, 0, 0)
 
diff --git a/xknx/remote_value/remote_value_control.py b/xknx/remote_value/remote_value_control.py
index f27e5dcd..590605a0 100644
--- a/xknx/remote_value/remote_value_control.py
+++ b/xknx/remote_value/remote_value_control.py
@@ -4,15 +4,14 @@ Module for managing a control remote value.
 Examples are switching commands with priority control, relative dimming or blinds control commands.
 DPT 2.yyy and DPT 3.yyy
 """
-from typing import TYPE_CHECKING, Any, List, Optional, Type, Union
+from typing import TYPE_CHECKING, Any, Optional, Type, Union
 
 from xknx.dpt import DPTArray, DPTBase, DPTBinary, DPTControlStepCode
 from xknx.exceptions import ConversionError
 
-from .remote_value import AsyncCallbackType, RemoteValue
+from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -22,14 +21,13 @@ class RemoteValueControl(RemoteValue[DPTBinary]):
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         sync_state: bool = True,
         value_type: Optional[str] = None,
         device_name: Optional[str] = None,
         feature_name: str = "Control",
         after_update_cb: Optional[AsyncCallbackType] = None,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize control remote value."""
         # pylint: disable=too-many-arguments
@@ -50,7 +48,6 @@ class RemoteValueControl(RemoteValue[DPTBinary]):
             device_name=device_name,
             feature_name=feature_name,
             after_update_cb=after_update_cb,
-            passive_group_addresses=passive_group_addresses,
         )
 
     def payload_valid(
diff --git a/xknx/remote_value/remote_value_datetime.py b/xknx/remote_value/remote_value_datetime.py
index f776f106..2aba9a79 100644
--- a/xknx/remote_value/remote_value_datetime.py
+++ b/xknx/remote_value/remote_value_datetime.py
@@ -5,15 +5,14 @@ DPT 10.001, 11.001 and 19.001
 """
 from enum import Enum
 import time
-from typing import TYPE_CHECKING, List, Optional, Type, Union
+from typing import TYPE_CHECKING, Optional, Type, Union
 
 from xknx.dpt import DPTArray, DPTBinary, DPTDate, DPTDateTime, DPTTime
 from xknx.exceptions import ConversionError
 
-from .remote_value import AsyncCallbackType, RemoteValue
+from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -31,14 +30,13 @@ class RemoteValueDateTime(RemoteValue[DPTArray]):
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         sync_state: bool = True,
         value_type: str = "time",
         device_name: Optional[str] = None,
         feature_name: str = "DateTime",
         after_update_cb: Optional[AsyncCallbackType] = None,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize RemoteValueSensor class."""
         # pylint: disable=too-many-arguments
@@ -61,7 +59,6 @@ class RemoteValueDateTime(RemoteValue[DPTArray]):
             device_name=device_name,
             feature_name=feature_name,
             after_update_cb=after_update_cb,
-            passive_group_addresses=passive_group_addresses,
         )
 
     def payload_valid(
diff --git a/xknx/remote_value/remote_value_dpt_2_byte_unsigned.py b/xknx/remote_value/remote_value_dpt_2_byte_unsigned.py
index 448d51fd..8033a4cc 100644
--- a/xknx/remote_value/remote_value_dpt_2_byte_unsigned.py
+++ b/xknx/remote_value/remote_value_dpt_2_byte_unsigned.py
@@ -3,14 +3,13 @@ Module for managing a DTP 7001 remote value.
 
 DPT 7.001.
 """
-from typing import TYPE_CHECKING, List, Optional, Union
+from typing import TYPE_CHECKING, Optional, Union
 
 from xknx.dpt import DPT2ByteUnsigned, DPTArray, DPTBinary
 
-from .remote_value import AsyncCallbackType, RemoteValue
+from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -22,12 +21,11 @@ class RemoteValueDpt2ByteUnsigned(RemoteValue[DPTArray]):
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         device_name: Optional[str] = None,
         feature_name: str = "Value",
         after_update_cb: Optional[AsyncCallbackType] = None,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize remote value of KNX DPT 7.001."""
         # pylint: disable=too-many-arguments
@@ -38,7 +36,6 @@ class RemoteValueDpt2ByteUnsigned(RemoteValue[DPTArray]):
             device_name=device_name,
             feature_name=feature_name,
             after_update_cb=after_update_cb,
-            passive_group_addresses=passive_group_addresses,
         )
 
     def payload_valid(
diff --git a/xknx/remote_value/remote_value_scaling.py b/xknx/remote_value/remote_value_scaling.py
index d76ef92e..38917fe9 100644
--- a/xknx/remote_value/remote_value_scaling.py
+++ b/xknx/remote_value/remote_value_scaling.py
@@ -3,14 +3,13 @@ Module for managing a Scaling remote value.
 
 DPT 5.001.
 """
-from typing import TYPE_CHECKING, List, Optional, Union
+from typing import TYPE_CHECKING, Optional, Union
 
 from xknx.dpt import DPTArray, DPTBinary
 
-from .remote_value import AsyncCallbackType, RemoteValue
+from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -20,14 +19,13 @@ class RemoteValueScaling(RemoteValue[DPTArray]):
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         device_name: Optional[str] = None,
         feature_name: str = "Value",
         after_update_cb: Optional[AsyncCallbackType] = None,
         range_from: int = 0,
         range_to: int = 100,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize remote value of KNX DPT 5.001 (DPT_Scaling)."""
         # pylint: disable=too-many-arguments
@@ -38,7 +36,6 @@ class RemoteValueScaling(RemoteValue[DPTArray]):
             device_name=device_name,
             feature_name=feature_name,
             after_update_cb=after_update_cb,
-            passive_group_addresses=passive_group_addresses,
         )
         self.range_from = range_from
         self.range_to = range_to
diff --git a/xknx/remote_value/remote_value_sensor.py b/xknx/remote_value/remote_value_sensor.py
index 9c525a78..b79a7b84 100644
--- a/xknx/remote_value/remote_value_sensor.py
+++ b/xknx/remote_value/remote_value_sensor.py
@@ -4,15 +4,14 @@ Module for managing a remote value typically used within a sensor.
 The module maps a given value_type to a DPT class and uses this class
 for serialization and deserialization of the KNX value.
 """
-from typing import TYPE_CHECKING, List, Optional, Union
+from typing import TYPE_CHECKING, Optional, Union
 
 from xknx.dpt import DPTArray, DPTBase, DPTBinary
 from xknx.exceptions import ConversionError
 
-from .remote_value import AsyncCallbackType, RemoteValue
+from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -22,14 +21,13 @@ class RemoteValueSensor(RemoteValue[DPTArray]):
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         sync_state: bool = True,
         value_type: Optional[Union[int, str]] = None,
         device_name: Optional[str] = None,
         feature_name: str = "Value",
         after_update_cb: Optional[AsyncCallbackType] = None,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize RemoteValueSensor class."""
         # pylint: disable=too-many-arguments
@@ -49,7 +47,6 @@ class RemoteValueSensor(RemoteValue[DPTArray]):
             device_name=device_name,
             feature_name=feature_name,
             after_update_cb=after_update_cb,
-            passive_group_addresses=passive_group_addresses,
         )
 
     def payload_valid(
diff --git a/xknx/remote_value/remote_value_setpoint_shift.py b/xknx/remote_value/remote_value_setpoint_shift.py
index d53f11e0..9aeb028a 100644
--- a/xknx/remote_value/remote_value_setpoint_shift.py
+++ b/xknx/remote_value/remote_value_setpoint_shift.py
@@ -3,14 +3,13 @@ Module for managing setpoint shifting.
 
 DPT 6.010.
 """
-from typing import TYPE_CHECKING, List, Optional, Union
+from typing import TYPE_CHECKING, Optional, Union
 
 from xknx.dpt import DPTArray, DPTBinary, DPTValue1Count
 
-from .remote_value import AsyncCallbackType, RemoteValue
+from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -20,12 +19,11 @@ class RemoteValueSetpointShift(RemoteValue[DPTArray]):
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         device_name: Optional[str] = None,
         after_update_cb: Optional[AsyncCallbackType] = None,
         setpoint_shift_step: float = 0.1,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize RemoteValueSetpointShift class."""
         # pylint: disable=too-many-arguments
@@ -36,7 +34,6 @@ class RemoteValueSetpointShift(RemoteValue[DPTArray]):
             device_name=device_name,
             feature_name="Setpoint shift value",
             after_update_cb=after_update_cb,
-            passive_group_addresses=passive_group_addresses,
         )
 
         self.setpoint_shift_step = setpoint_shift_step
diff --git a/xknx/remote_value/remote_value_step.py b/xknx/remote_value/remote_value_step.py
index 4acdfc31..73752608 100644
--- a/xknx/remote_value/remote_value_step.py
+++ b/xknx/remote_value/remote_value_step.py
@@ -4,15 +4,14 @@ Module for managing an DPT Step remote value.
 DPT 1.007.
 """
 from enum import Enum
-from typing import TYPE_CHECKING, List, Optional, Union
+from typing import TYPE_CHECKING, Optional, Union
 
 from xknx.dpt import DPTArray, DPTBinary
 from xknx.exceptions import ConversionError, CouldNotParseTelegram
 
-from .remote_value import AsyncCallbackType, RemoteValue
+from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -28,13 +27,12 @@ class RemoteValueStep(RemoteValue[DPTBinary]):
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         device_name: Optional[str] = None,
         feature_name: str = "Step",
         after_update_cb: Optional[AsyncCallbackType] = None,
         invert: bool = False,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize remote value of KNX DPT 1.007."""
         # pylint: disable=too-many-arguments
@@ -45,7 +43,6 @@ class RemoteValueStep(RemoteValue[DPTBinary]):
             device_name=device_name,
             feature_name=feature_name,
             after_update_cb=after_update_cb,
-            passive_group_addresses=passive_group_addresses,
         )
         self.invert = invert
 
diff --git a/xknx/remote_value/remote_value_switch.py b/xknx/remote_value/remote_value_switch.py
index b2b7a6e9..f3c0af95 100644
--- a/xknx/remote_value/remote_value_switch.py
+++ b/xknx/remote_value/remote_value_switch.py
@@ -3,15 +3,14 @@ Module for managing an DPT Switch remote value.
 
 DPT 1.001.
 """
-from typing import TYPE_CHECKING, List, Optional, Union
+from typing import TYPE_CHECKING, Optional, Union
 
 from xknx.dpt import DPTArray, DPTBinary
 from xknx.exceptions import ConversionError, CouldNotParseTelegram
 
-from .remote_value import AsyncCallbackType, RemoteValue
+from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -21,14 +20,13 @@ class RemoteValueSwitch(RemoteValue[DPTBinary]):
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         sync_state: bool = True,
         device_name: Optional[str] = None,
         feature_name: str = "State",
         after_update_cb: Optional[AsyncCallbackType] = None,
         invert: bool = False,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize remote value of KNX DPT 1.001."""
         # pylint: disable=too-many-arguments
@@ -40,7 +38,6 @@ class RemoteValueSwitch(RemoteValue[DPTBinary]):
             device_name=device_name,
             feature_name=feature_name,
             after_update_cb=after_update_cb,
-            passive_group_addresses=passive_group_addresses,
         )
         self.invert = bool(invert)
 
diff --git a/xknx/remote_value/remote_value_updown.py b/xknx/remote_value/remote_value_updown.py
index 8d5a9614..c34c000e 100644
--- a/xknx/remote_value/remote_value_updown.py
+++ b/xknx/remote_value/remote_value_updown.py
@@ -4,15 +4,14 @@ Module for managing an DPT Up/Down remote value.
 DPT 1.008.
 """
 from enum import Enum
-from typing import TYPE_CHECKING, List, Optional, Union
+from typing import TYPE_CHECKING, Optional, Union
 
 from xknx.dpt import DPTArray, DPTBinary
 from xknx.exceptions import ConversionError, CouldNotParseTelegram
 
-from .remote_value import AsyncCallbackType, RemoteValue
+from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
-    from xknx.telegram.address import GroupAddressableType
     from xknx.xknx import XKNX
 
 
@@ -29,13 +28,12 @@ class RemoteValueUpDown(RemoteValue[DPTBinary]):
     def __init__(
         self,
         xknx: "XKNX",
-        group_address: Optional["GroupAddressableType"] = None,
-        group_address_state: Optional["GroupAddressableType"] = None,
+        group_address: Optional[GroupAddressesType] = None,
+        group_address_state: Optional[GroupAddressesType] = None,
         device_name: Optional[str] = None,
         feature_name: str = "Up/Down",
         after_update_cb: Optional[AsyncCallbackType] = None,
         invert: bool = False,
-        passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
     ):
         """Initialize remote value of KNX DPT 1.008."""
         # pylint: disable=too-many-arguments
@@ -46,7 +44,6 @@ class RemoteValueUpDown(RemoteValue[DPTBinary]):
             device_name=device_name,
             feature_name=feature_name,
             after_update_cb=after_update_cb,
-            passive_group_addresses=passive_group_addresses,
         )
         self.invert = invert
 


Test patch:
diff --git a/requirements/testing.txt b/requirements/testing.txt
index 4ead4e51..57a9dade 100644
--- a/requirements/testing.txt
+++ b/requirements/testing.txt
@@ -2,7 +2,7 @@
 pre-commit==2.11.1
 isort==5.7.0
 coveralls==3.0.1
-flake8==3.9.0
+flake8==3.8.4
 flake8-isort==4.0.0
 pydocstyle==5.1.1
 pylint==2.7.2
@@ -10,6 +10,6 @@ pylint-strict-informational==0.1
 pytest==6.2.2
 pytest-cov==2.11.1
 pytest-timeout==1.4.2
-setuptools==54.1.2
+setuptools==54.1.1
 tox==3.23.0
 mypy==0.812
diff --git a/test/devices_tests/switch_test.py b/test/devices_tests/switch_test.py
index a26e0c23..9f9aacff 100644
--- a/test/devices_tests/switch_test.py
+++ b/test/devices_tests/switch_test.py
@@ -348,3 +348,47 @@ class TestSwitch(unittest.TestCase):
         switch = Switch(xknx, "TestOutlet", group_address="1/2/3")
         self.assertTrue(switch.has_group_address(GroupAddress("1/2/3")))
         self.assertFalse(switch.has_group_address(GroupAddress("2/2/2")))
+
+    #
+    # TEST passive group addresses
+    #
+    def test_has_group_address_passive(self):
+        """Test has_group_address with passive group address."""
+        xknx = XKNX()
+        switch = Switch(xknx, "TestOutlet", group_address=["1/2/3", "4/4/4"])
+        self.assertTrue(switch.has_group_address(GroupAddress("1/2/3")))
+        self.assertTrue(switch.has_group_address(GroupAddress("4/4/4")))
+        self.assertFalse(switch.has_group_address(GroupAddress("2/2/2")))
+
+    def test_process_passive(self):
+        """Test process / reading telegrams from telegram queue. Test if device was updated."""
+        xknx = XKNX()
+        callback_mock = AsyncMock()
+
+        switch1 = Switch(
+            xknx,
+            "TestOutlet",
+            group_address=["1/2/3", "4/4/4"],
+            group_address_state=["1/2/30", "5/5/5"],
+            device_updated_cb=callback_mock,
+        )
+        self.assertEqual(switch1.state, None)
+        callback_mock.assert_not_called()
+
+        telegram_on_passive = Telegram(
+            destination_address=GroupAddress("4/4/4"),
+            payload=GroupValueWrite(DPTBinary(1)),
+        )
+        telegram_off_passive = Telegram(
+            destination_address=GroupAddress("5/5/5"),
+            payload=GroupValueWrite(DPTBinary(0)),
+        )
+
+        self.loop.run_until_complete(switch1.process(telegram_on_passive))
+        self.assertEqual(switch1.state, True)
+        callback_mock.assert_called_once()
+        callback_mock.reset_mock()
+        self.loop.run_until_complete(switch1.process(telegram_off_passive))
+        self.assertEqual(switch1.state, False)
+        callback_mock.assert_called_once()
+        callback_mock.reset_mock()
diff --git a/test/remote_value_tests/remote_value_test.py b/test/remote_value_tests/remote_value_test.py
index d0301f03..eebd56e1 100644
--- a/test/remote_value_tests/remote_value_test.py
+++ b/test/remote_value_tests/remote_value_test.py
@@ -137,12 +137,56 @@ class TestRemoteValue(unittest.TestCase):
                 "State",
             )
 
-    def test_process_listening_address(self):
-        """Test if listening group addresses are processed."""
+    def test_unpacking_passive_address(self):
+        """Test if passive group addresses are properly unpacked."""
         xknx = XKNX()
-        remote_value = RemoteValue(
-            xknx, group_address="1/2/3", passive_group_addresses=["1/1/1"]
+
+        remote_value_1 = RemoteValue(xknx, group_address=["1/2/3", "1/1/1"])
+        self.assertEqual(remote_value_1.group_address, GroupAddress("1/2/3"))
+        self.assertIsNone(remote_value_1.group_address_state)
+        self.assertEqual(
+            remote_value_1.passive_group_addresses, [GroupAddress("1/1/1")]
+        )
+        self.assertTrue(remote_value_1.has_group_address(GroupAddress("1/2/3")))
+        self.assertTrue(remote_value_1.has_group_address(GroupAddress("1/1/1")))
+
+        remote_value_2 = RemoteValue(xknx, group_address_state=["1/2/3", "1/1/1"])
+        self.assertIsNone(remote_value_2.group_address)
+        self.assertEqual(remote_value_2.group_address_state, GroupAddress("1/2/3"))
+        self.assertEqual(
+            remote_value_2.passive_group_addresses, [GroupAddress("1/1/1")]
+        )
+        self.assertTrue(remote_value_2.has_group_address(GroupAddress("1/2/3")))
+        self.assertTrue(remote_value_2.has_group_address(GroupAddress("1/1/1")))
+
+        remote_value_3 = RemoteValue(
+            xknx,
+            group_address=["1/2/3", "1/1/1", "1/1/10"],
+            group_address_state=["2/3/4", "2/2/2", "2/2/20"],
+        )
+        self.assertEqual(remote_value_3.group_address, GroupAddress("1/2/3"))
+        self.assertEqual(remote_value_3.group_address_state, GroupAddress("2/3/4"))
+        self.assertEqual(
+            remote_value_3.passive_group_addresses,
+            [
+                GroupAddress("1/1/1"),
+                GroupAddress("1/1/10"),
+                GroupAddress("2/2/2"),
+                GroupAddress("2/2/20"),
+            ],
         )
+        self.assertTrue(remote_value_3.has_group_address(GroupAddress("1/2/3")))
+        self.assertTrue(remote_value_3.has_group_address(GroupAddress("1/1/1")))
+        self.assertTrue(remote_value_3.has_group_address(GroupAddress("1/1/10")))
+        self.assertTrue(remote_value_3.has_group_address(GroupAddress("2/3/4")))
+        self.assertTrue(remote_value_3.has_group_address(GroupAddress("2/2/2")))
+        self.assertTrue(remote_value_3.has_group_address(GroupAddress("2/2/20")))
+        self.assertFalse(remote_value_3.has_group_address(GroupAddress("0/0/0")))
+
+    def test_process_passive_address(self):
+        """Test if passive group addresses are processed."""
+        xknx = XKNX()
+        remote_value = RemoteValue(xknx, group_address=["1/2/3", "1/1/1"])
         self.assertTrue(remote_value.writable)
         self.assertFalse(remote_value.readable)
         # RemoteValue is initialized with only passive group address