Repository: XKNX/xknx
Pull request #1485 (2024-06-15 15:06:55)

Non-awaitable callbacks in Devices and RemoteValues
<!--
  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.
-->
- Change callback signatures from awaitable to callable in `XKNX.device_updated_cb`, Device, Devices and RemoteValue
- Change `RemoteValue.after_update_cb` from awaitable to callable. Remove `async` from `RemoteValue.set`, `.respond`, `.process` and `.update_value` (nothing has to be awaited there).

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)
- [ ] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Code quality improvements to existing code or addition of tests

## Checklist

- [x] The documentation has been adjusted accordingly
- [x] Tests have been added that prove the fix is effective or that the feature works
- [x] The changes are documented in the changelog (docs/changelog.md)

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/XKNX/xknx/pull/1485?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 96.62%. Comparing base [(`14d9ac4`)](https://app.codecov.io/gh/XKNX/xknx/commit/14d9ac47e3310b660b158ec986348651ad237bd2?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX) to head [(`585c39d`)](https://app.codecov.io/gh/XKNX/xknx/commit/585c39d986fb2f6d1a8177e9930650d7de541b88?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX).

<details><summary>Additional details and impacted files</summary>


[![Impacted file tree graph](https://app.codecov.io/gh/XKNX/xknx/pull/1485/graphs/tree.svg?width=650&height=150&src=pr&token=irWbIygS84&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX)](https://app.codecov.io/gh/XKNX/xknx/pull/1485?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX)

```diff
@@            Coverage Diff             @@
##             main    #1485      +/-   ##
==========================================
+ Coverage   96.61%   96.62%   +0.01%     
==========================================
  Files         153      154       +1     
  Lines        9990    10023      +33     
==========================================
+ Hits         9652     9685      +33     
  Misses        338      338              
```


| [Files](https://app.codecov.io/gh/XKNX/xknx/pull/1485?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX) | Coverage Δ | |
|---|---|---|
| [xknx/devices/binary\_sensor.py](https://app.codecov.io/gh/XKNX/xknx/pull/1485?src=pr&el=tree&filepath=xknx%2Fdevices%2Fbinary_sensor.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX#diff-eGtueC9kZXZpY2VzL2JpbmFyeV9zZW5zb3IucHk=) | `98.93% <100.00%> (ø)` | |
| [xknx/devices/climate.py](https://app.codecov.io/gh/XKNX/xknx/pull/1485?src=pr&el=tree&filepath=xknx%2Fdevices%2Fclimate.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX#diff-eGtueC9kZXZpY2VzL2NsaW1hdGUucHk=) | `100.00% <100.00%> (ø)` | |
| [xknx/devices/climate\_mode.py](https://app.codecov.io/gh/XKNX/xknx/pull/1485?src=pr&el=tree&filepath=xknx%2Fdevices%2Fclimate_mode.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX#diff-eGtueC9kZXZpY2VzL2NsaW1hdGVfbW9kZS5weQ==) | `100.00% <100.00%> (ø)` | |
| [xknx/devices/cover.py](https://app.codecov.io/gh/XKNX/xknx/pull/1485?src=pr&el=tree&filepath=xknx%2Fdevices%2Fcover.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX#diff-eGtueC9kZXZpY2VzL2NvdmVyLnB5) | `99.47% <100.00%> (+0.01%)` | :arrow_up: |
| [xknx/devices/datetime.py](https://app.codecov.io/gh/XKNX/xknx/pull/1485?src=pr&el=tree&filepath=xknx%2Fdevices%2Fdatetime.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX#diff-eGtueC9kZXZpY2VzL2RhdGV0aW1lLnB5) | `100.00% <100.00%> (ø)` | |
| [xknx/devices/device.py](https://app.codecov.io/gh/XKNX/xknx/pull/1485?src=pr&el=tree&filepath=xknx%2Fdevices%2Fdevice.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX#diff-eGtueC9kZXZpY2VzL2RldmljZS5weQ==) | `100.00% <100.00%> (ø)` | |
| [xknx/devices/devices.py](https://app.codecov.io/gh/XKNX/xknx/pull/1485?src=pr&el=tree&filepath=xknx%2Fdevices%2Fdevices.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX#diff-eGtueC9kZXZpY2VzL2RldmljZXMucHk=) | `100.00% <100.00%> (ø)` | |
| [xknx/devices/expose\_sensor.py](https://app.codecov.io/gh/XKNX/xknx/pull/1485?src=pr&el=tree&filepath=xknx%2Fdevices%2Fexpose_sensor.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX#diff-eGtueC9kZXZpY2VzL2V4cG9zZV9zZW5zb3IucHk=) | `100.00% <100.00%> (ø)` | |
| [xknx/devices/fan.py](https://app.codecov.io/gh/XKNX/xknx/pull/1485?src=pr&el=tree&filepath=xknx%2Fdevices%2Ffan.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX#diff-eGtueC9kZXZpY2VzL2Zhbi5weQ==) | `100.00% <100.00%> (ø)` | |
| [xknx/devices/light.py](https://app.codecov.io/gh/XKNX/xknx/pull/1485?src=pr&el=tree&filepath=xknx%2Fdevices%2Flight.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX#diff-eGtueC9kZXZpY2VzL2xpZ2h0LnB5) | `99.19% <100.00%> (+0.03%)` | :arrow_up: |
| ... and [21 more](https://app.codecov.io/gh/XKNX/xknx/pull/1485?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX) | |

</details>

Patch:
diff --git a/docs/binary_sensor.md b/docs/binary_sensor.md
index 7e932482..9df21ef4 100644
--- a/docs/binary_sensor.md
+++ b/docs/binary_sensor.md
@@ -23,7 +23,7 @@ The logic within switches can further handle if a button is pressed once or twic
 - `ignore_internal_state` allows callback call regardless of the current binary sensor state. Defaults to `False`
 - `context_timeout` time in seconds telegrams should be counted towards the current context to increment the counter. If set `ignore_internal_state` is set `True`. Defaults to `None`
 - `reset_after` may be used to reset the internal state to `OFF` again after given time in sec. Defaults to `None`
-- `device_updated_cb` awaitable callback for each update.
+- `device_updated_cb` Callback for each update.
 
 ## [](#header-2)Example
 
diff --git a/docs/changelog.md b/docs/changelog.md
index db5dddfa..c4a9f735 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -11,6 +11,7 @@ nav_order: 2
 ### General
 
 - Drop support for Python 3.9
+- Change callback signatures from awaitable to callable in `XKNX.device_updated_cb`, Device, Devices and RemoteValue.
 - Added eager telegram data decoding for GroupValueWrite / GroupValueResponse Telegrams. DPTs for group addresses can be set using `xknx.group_address_dpt.set()`. `Telegram` has a new attribute `decoded_data` which is set when a decoder was found.
 
 ### Devices
@@ -38,6 +39,7 @@ nav_order: 2
 - Convert Telegram and APCI to dataclasses. `Telegram` is not hashable anymore.
 - Use `asyncio.gather` where applicable (mostly device telegram process pipeline)
 - RemoteValue instances use pre-decoded data from Telegrams if available and `dpt_class` for is set - otherwise they decode the data themselves in `from_knx` like before.
+- Change `RemoteValue.after_update_cb` from awaitable to callable. Remove `async` from `RemoteValue.set`, `.respond`, `.process` and `.update_value` (nothing has to be awaited there).
 
 # 2.12.2 Fix thread leak 2024-03-05
 
diff --git a/docs/climate.md b/docs/climate.md
index 97522e9c..289f25f0 100644
--- a/docs/climate.md
+++ b/docs/climate.md
@@ -47,7 +47,7 @@ Climate are representations of KNX HVAC/Climate controls.
 - `group_address_heat_cool_state` KNX address for reading heating / cooling mode. *DPT 1*
 - `operation_modes` Overrides the supported operation modes.
 - `controller_modes` Overrides the supported controller modes.
-- `device_updated_cb` awaitable callback for each update.
+- `device_updated_cb` Callback for each update.
 
 **Note:** `group_address_operation_mode_protection` / `group_address_operation_mode_night` / `group_address_operation_mode_comfort` / `group_address_operation_mode_standby` are not necessary if `group_address_operation_mode` was specified. When one of these is set `True`, the others will be set `False`. When one of these is set `Standby`, `Comfort`, `Frost_Protection` and `Night` will be set as supported. If `group_address_operation_mode_standby` is omitted, `Standby` is set when the other 3 are set to `False`.
 If only a subset of operation modes shall be used a list of supported modes may be passed to `operation_modes`.
diff --git a/docs/cover.md b/docs/cover.md
index 0b19f8bd..fc9e0069 100644
--- a/docs/cover.md
+++ b/docs/cover.md
@@ -29,7 +29,7 @@ Shutters are simple representations of blind/roller cover actuators. With XKNX y
 - `invert_updown` invert up/down binary payload. Default: False
 - `invert_position` invert position percentage from / to KNX bus. Default: False
 - `invert_angle` invert angle from / to KNX bus. Default: False
-- `device_updated_cb` awaitable callback for each update.
+- `device_updated_cb` Callback for each update.
 
 ## [](#header-2)Example
 
diff --git a/docs/devices.md b/docs/devices.md
index 9b82b7a4..ca2deeeb 100644
--- a/docs/devices.md
+++ b/docs/devices.md
@@ -16,7 +16,7 @@ An instantiated device can be added to `xknx.devices` to receive telegrams and s
 
 * `xknx` is the XKNX object.
 * `name` is the name of the object.
-* `device_updated_cb` List of awaitable callbacks for each update.
+* `device_updated_cb` List of 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.
diff --git a/docs/fan.md b/docs/fan.md
index 7225480d..e7bdf8bc 100644
--- a/docs/fan.md
+++ b/docs/fan.md
@@ -22,7 +22,7 @@ Fans are simple representations of KNX controlled fans. They support switching o
 - `group_address_switch` is the KNX group address of the fan on/off state. If not used, on/off will implicitly be controlled via `group_address_speed` instead. Used for sending. *DPT 1.001*
 - `group_address_switch_state` is the KNX group address of the fan on/off state. Used for updating and reading state. *DPT 1.001*
 - `sync_state` defines if and how often the value should be actively read from the bus. If `False` no GroupValueRead telegrams will be sent to its group address. Defaults to `True`
-- `device_updated_cb` awaitable callback for each update.
+- `device_updated_cb` Callback for each update.
 - `max_step` Maximum step amount for fans which are controlled with steps and not percentage. If this attribute is set, the fan is controlled by sending the step value in the range `0` and `max_step`. In that case, the group address DPT changes from *DPT 5.001* to *DPT 5.010*. Default: None
 
 ## [](#header-2)Example
diff --git a/docs/light.md b/docs/light.md
index cd3f29f5..9fc491ef 100644
--- a/docs/light.md
+++ b/docs/light.md
@@ -54,7 +54,7 @@ The Light object is either a representation of a binary or dimm actor, LED-contr
 - `sync_state` defines if and how often the value should be actively read from the bus. If `False` no GroupValueRead telegrams will be sent to its group address. Defaults to `True`
 - `min_kelvin` lowest possible color temperature in Kelvin. Default: 2700
 - `max_kelvin` highest possible color temperature in Kelvin. Default: 6000
-- `device_updated_cb` awaitable callback for each update.
+- `device_updated_cb` Callback for each update.
 
 ## [](#header-2)Example
 
diff --git a/docs/numeric_value.md b/docs/numeric_value.md
index 5bda0db7..2a1eae83 100644
--- a/docs/numeric_value.md
+++ b/docs/numeric_value.md
@@ -21,7 +21,7 @@ NumericValue devices send values to the KNX bus. Received values update the devi
 - `sync_state` defines if and how often the value should be actively read from the bus. If `False` no GroupValueRead telegrams will be sent to its group address. Defaults to `True`
 - `value_type` controls how the value should be encoded / decoded. The attribute may have may have parseable value types representing numeric values.
 - `always_callback` defines if a callback shall be triggered for consecutive GroupValueWrite telegrams with same payload. Defaults to `False`
-- `device_updated_cb` awaitable callback for each update.
+- `device_updated_cb` Callback for each update.
 
 ## [](#header-2)Example
 
diff --git a/docs/raw_value.md b/docs/raw_value.md
index ec43b6ca..9a0eaed1 100644
--- a/docs/raw_value.md
+++ b/docs/raw_value.md
@@ -21,7 +21,7 @@ RawValue devices send uint values to the KNX bus. Received values update the dev
 - `respond_to_read` if `True` GroupValueRead requests to the `group_address` are answered. Defaults to `False`
 - `sync_state` defines if and how often the value should be actively read from the bus. If `False` no GroupValueRead telegrams will be sent to its group address. Defaults to `True`
 - `always_callback` defines if a callback shall be triggered for consecutive GroupValueWrite telegrams with same payload. Defaults to `False`
-- `device_updated_cb` awaitable callback for each update.
+- `device_updated_cb` Callback for each update.
 
 ## [](#header-2)Example
 
diff --git a/docs/sensor.md b/docs/sensor.md
index 485364d6..fbd788db 100644
--- a/docs/sensor.md
+++ b/docs/sensor.md
@@ -19,7 +19,7 @@ Sensors are monitoring temperature, air humidity, pressure etc. from KNX bus.
 - `sync_state` defines if the value should be actively read from the bus. If `False` no GroupValueRead telegrams will be sent to its group address. Defaults to `True`
 - `always_callback` defines if a callback shall be triggered for consecutive GroupValueWrite telegrams with same payload. Defaults to `False`
 - `value_type` controls how the value should be rendered in a human readable representation. The attribute may have may have the values `percent`, `temperature`, `illuminance`, `speed_ms` or `current`.
-- `device_updated_cb` awaitable callback for each update.
+- `device_updated_cb` Callback for each update.
 
 ## [](#header-2)Example
 
diff --git a/docs/switch.md b/docs/switch.md
index fe54156d..f24ac075 100644
--- a/docs/switch.md
+++ b/docs/switch.md
@@ -21,7 +21,7 @@ Switches are simple representations of binary actors. They mainly support switch
 - `sync_state` defines if and how often the value should be actively read from the bus. If `False` no GroupValueRead telegrams will be sent to its group address. Defaults to `True`
 - `invert` inverts the payload so state "on" is represented by 0 on bus and "off" by 1. Defaults to `False`
 - `reset_after` may be used to reset the switch to `OFF` again after given time in sec. Defaults to `None`
-- `device_updated_cb` awaitable callback for each update.
+- `device_updated_cb` Callback for each update.
 
 
 ## [](#header-2)Example
diff --git a/docs/time.md b/docs/time.md
index 7ae6f41d..4ba57599 100644
--- a/docs/time.md
+++ b/docs/time.md
@@ -31,7 +31,7 @@ await xknx.devices['TimeTest'].sync()
 * `group_address` is the KNX group address of the sensor device.
 * `broadcast_type` defines the value type that will be sent to the KNX bus. Valid attributes are: 'time', 'date' and 'datetime'. Default: `time`
 * `localtime` If set `True` sync() and GroupValueRead requests always return the current local time. On `False` the set value will be sent. Default: `True`
-* `device_updated_cb` awaitable callback for each update.
+* `device_updated_cb` Callback for each update.
 
 ## [](#header-2)Daemon mode
 
diff --git a/docs/weather.md b/docs/weather.md
index 800490e1..4dd30410 100644
--- a/docs/weather.md
+++ b/docs/weather.md
@@ -52,7 +52,7 @@ The weather device is basically a set of sensors that you can obtain from your w
 - **group_address_air_pressure** KNX address reading current air pressure. **DPT 9.006**
 - **group_address_humidity** KNX address for reading current humidity. **DPT 9.007**
 - **sync_state** Periodically sync the state.
-- **device_updated_cb** awaitable callback for each update.
+- **device_updated_cb** Callback for each update.
 
 ```python
 
diff --git a/docs/xknx.md b/docs/xknx.md
index 0a5a9052..0c54c531 100644
--- a/docs/xknx.md
+++ b/docs/xknx.md
@@ -42,7 +42,7 @@ The constructor of the XKNX object takes several parameters:
   - LONG: representation like '1/2/34' with middle groups
 - `connection_state_changed_cb` is a callback which is called every time the connection state to the gateway changes. See [callbacks](#callbacks) documentation for details.
 - `telegram_received_cb` is a callback which is called after every received KNX telegram. See [callbacks](#callbacks) documentation for details.
-- `device_updated_cb` is an async callback after a [XKNX device](#devices) was updated. See [callbacks](#callbacks) documentation for details.
+- `device_updated_cb` is a callback after a [XKNX device](#devices) was updated. See [callbacks](#callbacks) documentation for details.
 - `rate_limit` in telegrams per second - can be used to limit the outgoing traffic to the KNX/IP interface by the telegram queue. `0` disables rate limiter. Disabled by default.
 - `multicast_group` is the multicast group used for discovery - can be used to override the default multicast address (`224.0.23.12`)
 - `multicast_port` is the multicast port used for discovery - can be used to override the default multicast port (`3671`)
@@ -161,7 +161,7 @@ from xknx import XKNX
 from xknx.devices import Device, Switch
 
 
-async def device_updated_cb(device: Device):
+def device_updated_cb(device: Device):
     print("Callback received from {0}".format(device.name))
 
 
diff --git a/examples/example_callback.py b/examples/example_callback.py
index 0537127a..129fe537 100644
--- a/examples/example_callback.py
+++ b/examples/example_callback.py
@@ -7,7 +7,7 @@ from xknx.devices import Light
 from xknx.io import ConnectionConfig, ConnectionType
 
 
-async def light_callback(light: Light) -> None:
+def light_callback(light: Light) -> None:
     """Run callback when the light changed any of its state."""
     print(f"{light.name} - {light.state}")
 
diff --git a/examples/example_daemon.py b/examples/example_daemon.py
index de076e5a..df8935d3 100644
--- a/examples/example_daemon.py
+++ b/examples/example_daemon.py
@@ -6,7 +6,7 @@ from xknx import XKNX
 from xknx.devices import Device, Switch
 
 
-async def device_updated_cb(device: Device) -> None:
+def device_updated_cb(device: Device) -> None:
     """Do something with the updated device."""
     print(f"Callback received from {device.name}")
 
diff --git a/examples/example_light_rgbw.py b/examples/example_light_rgbw.py
index 5d888399..c934d3d1 100644
--- a/examples/example_light_rgbw.py
+++ b/examples/example_light_rgbw.py
@@ -19,29 +19,29 @@ async def main() -> None:
         device_name="RGBWLight",
     )
 
-    await rgbw.set(RGBWColor(255, 255, 255, 0))  # cold-white
+    rgbw.set(RGBWColor(255, 255, 255, 0))  # cold-white
     await asyncio.sleep(1)
-    await rgbw.set(RGBWColor(0, 0, 0, 255))  # warm-white
+    rgbw.set(RGBWColor(0, 0, 0, 255))  # warm-white
     await asyncio.sleep(1)
-    await rgbw.set(RGBWColor(0, 0, 0, 0))  # off
+    rgbw.set(RGBWColor(0, 0, 0, 0))  # off
     await asyncio.sleep(1)
 
-    await rgbw.set(RGBWColor(255, 0, 0, 0))  # red
+    rgbw.set(RGBWColor(255, 0, 0, 0))  # red
     await asyncio.sleep(1)
-    await rgbw.set(RGBWColor(0, 255, 0, 0))  # green
+    rgbw.set(RGBWColor(0, 255, 0, 0))  # green
     await asyncio.sleep(1)
-    await rgbw.set(RGBWColor(0, 0, 255, 0))  # blue
+    rgbw.set(RGBWColor(0, 0, 255, 0))  # blue
     await asyncio.sleep(1)
-    await rgbw.set(RGBWColor(0, 0, 0, 0))  # off
+    rgbw.set(RGBWColor(0, 0, 0, 0))  # off
     await asyncio.sleep(1)
 
-    await rgbw.set(RGBWColor(255, 255, 0, 0))
+    rgbw.set(RGBWColor(255, 255, 0, 0))
     await asyncio.sleep(1)
-    await rgbw.set(RGBWColor(0, 255, 255, 0))
+    rgbw.set(RGBWColor(0, 255, 255, 0))
     await asyncio.sleep(1)
-    await rgbw.set(RGBWColor(255, 0, 255, 0))
+    rgbw.set(RGBWColor(255, 0, 255, 0))
     await asyncio.sleep(1)
-    await rgbw.set(RGBWColor(0, 0, 0, 0))  # off
+    rgbw.set(RGBWColor(0, 0, 0, 0))  # off
     await asyncio.sleep(1)
 
     await xknx.stop()
diff --git a/examples/example_powermeter_mqtt.py b/examples/example_powermeter_mqtt.py
index 3472046e..4d0cb719 100644
--- a/examples/example_powermeter_mqtt.py
+++ b/examples/example_powermeter_mqtt.py
@@ -62,7 +62,7 @@ RE_CURRENT = re.compile("Current_")
 RE_FREQUENCY = re.compile("Frequency_")
 
 
-async def device_updated_cb(device):
+def device_updated_cb(device):
     """Do something with the updated device."""
     # print(device.name + ' ' + str(device.resolve_state()) + ' ' + device.unit_of_measurement())
     value = None
diff --git a/xknx/devices/binary_sensor.py b/xknx/devices/binary_sensor.py
index 76ad2085..446ea707 100644
--- a/xknx/devices/binary_sensor.py
+++ b/xknx/devices/binary_sensor.py
@@ -82,12 +82,12 @@ class BinarySensor(Device):
         """Return the last telegram received from the RemoteValue."""
         return self.remote_value.telegram
 
-    async def _state_from_remote_value(self) -> None:
+    def _state_from_remote_value(self) -> None:
         """Update the internal state from RemoteValue (Callback)."""
         if self.remote_value.value is not None:
-            await self._set_internal_state(self.remote_value.value)
+            self._set_internal_state(self.remote_value.value)
 
-    async def _set_internal_state(self, state: bool) -> None:
+    def _set_internal_state(self, state: bool) -> None:
         """Set the internal state of the device. If state was changed after_update hooks and connected Actions are executed."""
         if state != self.state or self.ignore_internal_state:
             self.state = state
@@ -99,16 +99,16 @@ class BinarySensor(Device):
                     async_func=partial(self._counter_task, self._context_timeout),
                 ).start()
             else:
-                await self.after_update()
+                self.after_update()
 
     async def _counter_task(self, wait_seconds: float) -> None:
         """Trigger after 1 second to prevent double triggers."""
         await asyncio.sleep(wait_seconds)
-        await self.after_update()
+        self.after_update()
 
         self._count_set_on = 0
         self._count_set_off = 0
-        await self.after_update()
+        self.after_update()
 
     @property
     def counter(self) -> int | None:
@@ -147,12 +147,12 @@ class BinarySensor(Device):
 
     async def process_group_write(self, telegram: Telegram) -> None:
         """Process incoming and outgoing GROUP WRITE telegram."""
-        if await self.remote_value.process(telegram, always_callback=True):
+        if self.remote_value.process(telegram, always_callback=True):
             self._process_reset_after()
 
     async def process_group_response(self, telegram: Telegram) -> None:
         """Process incoming GroupValueResponse telegrams."""
-        if await self.remote_value.process(telegram, always_callback=False):
+        if self.remote_value.process(telegram, always_callback=False):
             self._process_reset_after()
 
     def _process_reset_after(self) -> None:
@@ -166,7 +166,7 @@ class BinarySensor(Device):
 
     async def _reset_state(self, wait_seconds: float) -> None:
         await asyncio.sleep(wait_seconds)
-        await self._set_internal_state(False)
+        self._set_internal_state(False)
 
     def is_on(self) -> bool:
         """Return if binary sensor is 'on'."""
diff --git a/xknx/devices/climate.py b/xknx/devices/climate.py
index 9def8641..d0defb4f 100644
--- a/xknx/devices/climate.py
+++ b/xknx/devices/climate.py
@@ -7,7 +7,6 @@ Module for managing the climate within a room.
 
 from __future__ import annotations
 
-import asyncio
 from collections.abc import Iterator
 import logging
 from typing import TYPE_CHECKING, Any
@@ -170,11 +169,11 @@ class Climate(Device):
 
     async def turn_on(self) -> None:
         """Set power status to on."""
-        await self.on.on()
+        self.on.on()
 
     async def turn_off(self) -> None:
         """Set power status to off."""
-        await self.on.off()
+        self.on.off()
 
     @property
     def initialized_for_setpoint_shift_calculations(self) -> bool:
@@ -198,7 +197,7 @@ class Climate(Device):
             validated_temp = self.validate_value(
                 target_temperature, self.min_temp, self.max_temp
             )
-            await self.target_temperature.set(validated_temp)
+            self.target_temperature.set(validated_temp)
 
     @property
     def base_temperature(self) -> float | None:
@@ -240,10 +239,10 @@ class Climate(Device):
             offset, self.setpoint_shift_min, self.setpoint_shift_max
         )
         base_temperature = self.base_temperature
-        await self._setpoint_shift.set(validated_offset)
+        self._setpoint_shift.set(validated_offset)
         # broadcast new target temperature and set internally
         if self.target_temperature.writable and base_temperature is not None:
-            await self.target_temperature.set(base_temperature + validated_offset)
+            self.target_temperature.set(base_temperature + validated_offset)
 
     @property
     def target_temperature_max(self) -> float | None:
@@ -267,12 +266,9 @@ class Climate(Device):
 
     async def process_group_write(self, telegram: Telegram) -> None:
         """Process incoming and outgoing GROUP WRITE telegram."""
-        await asyncio.gather(
-            *[
-                remote_value.process(telegram)
-                for remote_value in self._iter_remote_values()
-            ]
-        )
+        for remote_value in self._iter_remote_values():
+            remote_value.process(telegram)
+
         if self.mode is not None:
             await self.mode.process_group_write(telegram)
 
diff --git a/xknx/devices/climate_mode.py b/xknx/devices/climate_mode.py
index f15b7ffe..b903ac6b 100644
--- a/xknx/devices/climate_mode.py
+++ b/xknx/devices/climate_mode.py
@@ -217,21 +217,19 @@ class ClimateMode(Device):
         yield self.remote_value_controller_mode
         yield self.remote_value_heat_cool
 
-    async def _set_internal_operation_mode(
-        self, operation_mode: HVACOperationMode
-    ) -> None:
+    def _set_internal_operation_mode(self, operation_mode: HVACOperationMode) -> None:
         """Set internal value of operation mode. Call hooks if operation mode was changed."""
         if operation_mode != self.operation_mode:
             self.operation_mode = operation_mode
-            await self.after_update()
+            self.after_update()
 
-    async def _set_internal_controller_mode(
+    def _set_internal_controller_mode(
         self, controller_mode: HVACControllerMode
     ) -> None:
         """Set internal value of controller mode. Call hooks if controller mode was changed."""
         if controller_mode != self.controller_mode:
             self.controller_mode = controller_mode
-            await self.after_update()
+            self.after_update()
 
     async def set_operation_mode(self, operation_mode: HVACOperationMode) -> None:
         """Set the operation mode of a thermostat. Send new operation_mode to BUS and update internal state."""
@@ -249,9 +247,9 @@ class ClimateMode(Device):
                 rv_operation.writable
                 and operation_mode in rv_operation.supported_operation_modes()
             ):
-                await rv_operation.set(operation_mode)
+                rv_operation.set(operation_mode)
 
-        await self._set_internal_operation_mode(operation_mode)
+        self._set_internal_operation_mode(operation_mode)
 
     async def set_controller_mode(self, controller_mode: HVACControllerMode) -> None:
         """Set the controller mode of a thermostat. Send new controller mode to the bus and update internal state."""
@@ -269,9 +267,9 @@ class ClimateMode(Device):
                 rv_controller.writable
                 and controller_mode in rv_controller.supported_operation_modes()
             ):
-                await rv_controller.set(controller_mode)
+                rv_controller.set(controller_mode)
 
-        await self._set_internal_controller_mode(controller_mode)
+        self._set_internal_controller_mode(controller_mode)
 
     @property
     def operation_modes(self) -> list[HVACOperationMode]:
@@ -309,17 +307,17 @@ class ClimateMode(Device):
         """Process incoming and outgoing GROUP WRITE telegram."""
         if self.supports_operation_mode:
             for rv_mode in self._iter_operation_remote_values():
-                if await rv_mode.process(telegram):
+                if rv_mode.process(telegram):
                     #  ignore inactive RemoteValueBinaryOperationMode
                     if rv_mode.value:
-                        await self._set_internal_operation_mode(rv_mode.value)
+                        self._set_internal_operation_mode(rv_mode.value)
                         return
 
         if self.supports_controller_mode:
             for rv_controller in self._iter_controller_remote_values():
-                if await rv_controller.process(telegram):
+                if rv_controller.process(telegram):
                     if rv_controller.value is not None:
-                        await self._set_internal_controller_mode(rv_controller.value)
+                        self._set_internal_controller_mode(rv_controller.value)
                     return
 
     def __str__(self) -> str:
diff --git a/xknx/devices/cover.py b/xknx/devices/cover.py
index 5795e76d..16877ea8 100644
--- a/xknx/devices/cover.py
+++ b/xknx/devices/cover.py
@@ -166,79 +166,79 @@ class Cover(Device):
     async def set_down(self) -> None:
         """Move cover down."""
         if self.updown.writable:
-            await self.updown.down()
+            self.updown.down()
             self._travel_direction_tilt = None
-            await self._start_position_update(
+            self._start_position_update(
                 target_position=self.travelcalculator.position_closed
             )
         elif self.position_target.writable:
-            await self.position_target.set(self.travelcalculator.position_closed)
+            self.position_target.set(self.travelcalculator.position_closed)
 
     async def set_up(self) -> None:
         """Move cover up."""
         if self.updown.writable:
-            await self.updown.up()
+            self.updown.up()
             self._travel_direction_tilt = None
-            await self._start_position_update(
+            self._start_position_update(
                 target_position=self.travelcalculator.position_open
             )
         elif self.position_target.writable:
-            await self.position_target.set(self.travelcalculator.position_open)
+            self.position_target.set(self.travelcalculator.position_open)
 
     async def set_short_down(self) -> None:
         """Move cover short down."""
-        await self.step.increase()
+        self.step.increase()
 
     async def set_short_up(self) -> None:
         """Move cover short up."""
-        await self.step.decrease()
+        self.step.decrease()
 
     async def stop(self) -> None:
         """Stop cover."""
         if self.stop_.writable:
-            await self.stop_.on()
+            self.stop_.on()
         elif self.step.writable:
             if TravelStatus.DIRECTION_UP in (
                 self.travelcalculator.travel_direction,
                 self._travel_direction_tilt,
             ):
-                await self.step.decrease()
+                self.step.decrease()
             elif TravelStatus.DIRECTION_DOWN in (
                 self.travelcalculator.travel_direction,
                 self._travel_direction_tilt,
             ):
-                await self.step.increase()
+                self.step.increase()
         else:
             logger.warning("Stop not supported for device %s", self.get_name())
             return
         self._travel_direction_tilt = None
-        await self._stop_position_update()
+        self._stop_position_update()
 
     async def set_position(self, position: int) -> None:
         """Move cover to a desginated position."""
         if self.position_target.writable:
-            await self.position_target.set(position)
+            self.position_target.set(position)
             return
         # No direct positioning group address defined
         # fully open or close is always possible even if current position is not known
         current_position = self.travelcalculator.current_position()
         if current_position is None:
             if position == self.travelcalculator.position_open:
-                await self.updown.up()
+                self.updown.up()
             elif position == self.travelcalculator.position_closed:
-                await self.updown.down()
+                self.updown.down()
             else:
                 logger.warning(
                     "Current position unknown. Initialize cover by moving to end position."
                 )
                 return
-            await self._start_position_update(target_position=position)
+            self._start_position_update(target_position=position)
             return
         if position < current_position:
-            await self.updown.up()
+            self.updown.up()
         elif position > current_position:
-            await self.updown.down()
-        await self._start_position_update(target_position=position)
+            self.updown.down()
+        self._start_position_update(target_position=position)
         # If device does not support auto_positioning,
         # we have to stop the device when position is reached,
         # unless device was traveling to fully open
@@ -263,10 +263,10 @@ class Cover(Device):
                 async_func=auto_stopper,
             ).start()
 
-    async def _start_position_update(self, target_position: int) -> None:
+    def _start_position_update(self, target_position: int) -> None:
         """Start the travel calculator and run device callbacks."""
         self.travelcalculator.start_travel(target_position)
-        await self.after_update()
+        self.after_update()
         if self.travelcalculator.is_traveling():
             self._start_auto_updater()
 
@@ -279,8 +279,8 @@ class Cover(Device):
                 await asyncio.sleep(TRAVELING_CALLBACK_INTERVAL)
                 if self.travelcalculator.is_traveling():
                     # else _stop_position_update will call after_update a second time
-                    await self.after_update()
-            asyncio.shield(self._stop_position_update())
+                    self.after_update()
+            self._stop_position_update()
 
         # restarts when already running
         self._periodic_update_task = self.xknx.task_registry.register(
@@ -288,7 +288,7 @@ class Cover(Device):
             async_func=periodic_updater,
         ).start()
 
-    async def _stop_position_update(self) -> None:
+    def _stop_position_update(self) -> None:
         """Stop the travel calculator and periodic device callbacks."""
         if not self.travelcalculator.position_reached():
             self.travelcalculator.stop()
@@ -298,16 +298,14 @@ class Cover(Device):
         if self._auto_stop_task:
             self._auto_stop_task.cancel()
             self._auto_stop_task = None
-        await self.after_update()
+        self.after_update()
 
-    async def _target_position_from_rv(self) -> None:
+    def _target_position_from_rv(self) -> None:
         """Update the target position from RemoteValue (Callback)."""
         if self.position_target.value is not None:
-            await self._start_position_update(
-                target_position=self.position_target.value
-            )
+            self._start_position_update(target_position=self.position_target.value)
 
-    async def _current_position_from_rv(self) -> None:
+    def _current_position_from_rv(self) -> None:
         """Update the current position from RemoteValue (Callback)."""
         position_before_update = self.travelcalculator.current_position()
         new_position = self.position_current.value
@@ -318,8 +316,9 @@ class Cover(Device):
         else:
             self.travelcalculator.set_position(new_position)
         if position_before_update != self.travelcalculator.current_position():
-            self._start_auto_updater()  # to restart the periodic updater
-            await self.after_update()
+            if position_before_update is not None:  # None on first move
+                self._start_auto_updater()  # to restart the periodic updater
+            self.after_update()
 
     async def set_angle(self, angle: int) -> None:
         """Move cover to designated angle."""
@@ -334,7 +333,7 @@ class Cover(Device):
             else TravelStatus.DIRECTION_UP
         )
 
-        await self.angle.set(angle)
+        self.angle.set(angle)
 
     async def sync(self, wait_for_result: bool = False) -> None:
         """Read states of device from KNX bus."""
@@ -344,32 +343,30 @@ class Cover(Device):
     async def process_group_write(self, telegram: Telegram) -> None:
         """Process incoming and outgoing GROUP WRITE telegram."""
         # call after_update to account for travelcalculator changes
-        if await self.updown.process(telegram):
+        if self.updown.process(telegram):
             if (
                 not self.is_opening()
                 and self.updown.value == RemoteValueUpDown.Direction.UP
             ):
-                await self._start_position_update(
+                self._start_position_update(
                     target_position=self.travelcalculator.position_open
                 )
             elif (
                 not self.is_closing()
                 and self.updown.value == RemoteValueUpDown.Direction.DOWN
             ):
-                await self._start_position_update(
+                self._start_position_update(
                     target_position=self.travelcalculator.position_closed
                 )
         # stop from bus
-        if await self.stop_.process(telegram) or await self.step.process(telegram):
+        if self.stop_.process(telegram) or self.step.process(telegram):
             if self.is_traveling():
-                await self._stop_position_update()
+                self._stop_position_update()
 
-        await asyncio.gather(
-            self.position_current.process(telegram, always_callback=True),
-            self.position_target.process(telegram, always_callback=True),
-            self.angle.process(telegram),
-            self.locked.process(telegram),
-        )
+        self.position_current.process(telegram, always_callback=True)
+        self.position_target.process(telegram, always_callback=True)
+        self.angle.process(telegram)
+        self.locked.process(telegram)
 
     def current_position(self) -> int | None:
         """Return current position of cover."""
diff --git a/xknx/devices/datetime.py b/xknx/devices/datetime.py
index c47718b5..be7bb76a 100644
--- a/xknx/devices/datetime.py
+++ b/xknx/devices/datetime.py
@@ -96,15 +96,15 @@ class DateTime(Device):
 
     async def broadcast_localtime(self, response: bool = False) -> None:
         """Broadcast the local time to KNX bus."""
-        await self.remote_value.set(time.localtime(), response=response)
+        self.remote_value.set(time.localtime(), response=response)
 
     async def set(self, struct_time: time.struct_time) -> None:
         """Set time and send to KNX bus."""
-        await self.remote_value.set(struct_time)
+        self.remote_value.set(struct_time)
 
     async def process_group_write(self, telegram: Telegram) -> None:
         """Process incoming and outgoing GROUP WRITE telegram."""
-        await self.remote_value.process(telegram)
+        self.remote_value.process(telegram)
 
     async def process_group_read(self, telegram: Telegram) -> None:
         """Process incoming GROUP READ telegram."""
@@ -114,7 +114,7 @@ class DateTime(Device):
             self.respond_to_read
             and telegram.destination_address == self.remote_value.group_address
         ):
-            await self.remote_value.respond()
+            self.remote_value.respond()
 
     async def sync(self, wait_for_result: bool = False) -> None:
         """Read state of device from KNX bus. Used here to broadcast time to KNX bus."""
diff --git a/xknx/devices/device.py b/xknx/devices/device.py
index 958667a0..8067efce 100644
--- a/xknx/devices/device.py
+++ b/xknx/devices/device.py
@@ -7,22 +7,19 @@ It provides basis functionality for reading the state from the KNX bus.
 from __future__ import annotations
 
 from abc import ABC, abstractmethod
-import asyncio
-from collections.abc import Callable, Coroutine, Iterator
+from collections.abc import Iterator
 import logging
-from typing import TYPE_CHECKING, Any, TypeVar
+from typing import TYPE_CHECKING, Any
 
 from xknx.remote_value import RemoteValue
 from xknx.telegram import Telegram
 from xknx.telegram.address import DeviceGroupAddress
 from xknx.telegram.apci import GroupValueRead, GroupValueResponse, GroupValueWrite
+from xknx.typing import DeviceCallbackType, DeviceT
 
 if TYPE_CHECKING:
     from xknx.xknx import XKNX
 
-T = TypeVar("T", bound="Device")
-DeviceCallbackType = Callable[[T], Coroutine[Any, Any, None]]
-
 logger = logging.getLogger("xknx.log")
 
 
@@ -30,15 +27,15 @@ class Device(ABC):
     """Base class for devices."""
 
     def __init__(
-        self: T,
+        self: DeviceT,
         xknx: XKNX,
         name: str,
-        device_updated_cb: DeviceCallbackType[T] | None = None,
+        device_updated_cb: DeviceCallbackType[DeviceT] | None = None,
     ):
         """Initialize Device class."""
         self.xknx = xknx
         self.name = name
-        self.device_updated_cbs: list[DeviceCallbackType[T]] = []
+        self.device_updated_cbs: list[DeviceCallbackType[DeviceT]] = []
         if device_updated_cb is not None:
             self.register_device_updated_cb(device_updated_cb)
 
@@ -68,27 +65,28 @@ class Device(ABC):
         yield from ()
 
     def register_device_updated_cb(
-        self: T, device_updated_cb: DeviceCallbackType[T]
+        self: DeviceT, device_updated_cb: DeviceCallbackType[DeviceT]
     ) -> None:
         """Register device updated callback."""
         self.device_updated_cbs.append(device_updated_cb)
 
     def unregister_device_updated_cb(
-        self: T, device_updated_cb: DeviceCallbackType[T]
+        self: DeviceT, device_updated_cb: DeviceCallbackType[DeviceT]
     ) -> None:
         """Unregister device updated callback."""
         if device_updated_cb in self.device_updated_cbs:
             self.device_updated_cbs.remove(device_updated_cb)
 
-    async def after_update(self: T) -> None:
+    def after_update(self: DeviceT) -> None:
         """Execute callbacks after internal state has been changed."""
-        try:
-            await asyncio.gather(*[cb(self) for cb in self.device_updated_cbs])
-        except Exception:  # pylint: disable=broad-except
-            logger.exception(
-                "Unexpected error while processing device_updated_cb for %s",
-                self,
-            )
+        for device_callback in self.device_updated_cbs:
+            try:
+                device_callback(self)
+            except Exception:  # pylint: disable=broad-except
+                logger.exception(
+                    "Unexpected error while processing device_updated_cb for %s",
+                    self,
+                )
 
     async def sync(self, wait_for_result: bool = False) -> None:
         """Read states of device from KNX bus."""
diff --git a/xknx/devices/devices.py b/xknx/devices/devices.py
index c66c8ec8..53cbf67a 100644
--- a/xknx/devices/devices.py
+++ b/xknx/devices/devices.py
@@ -7,15 +7,14 @@ More or less an array with devices. Adds some search functionality to find devic
 from __future__ import annotations
 
 import asyncio
-from collections.abc import Awaitable, Callable, Iterator
+from collections.abc import Iterator
 
 from xknx.telegram import Telegram
 from xknx.telegram.address import DeviceGroupAddress, GroupAddress, InternalGroupAddress
+from xknx.typing import DeviceCallbackType
 
 from .device import Device
 
-DeviceCallbackType = Callable[[Device], Awaitable[None]]
-
 
 class Devices:
     """Class for handling a vector/array of devices."""
@@ -24,7 +23,7 @@ class Devices:
         """Initialize Devices class."""
         self.started = started  # xknx.started
         self.__devices: list[Device] = []
-        self.device_updated_cbs: list[DeviceCallbackType] = []
+        self.device_updated_cbs: list[DeviceCallbackType[Device]] = []
 
     def async_start_device_tasks(self) -> None:
         """Start all devices tasks."""
@@ -36,12 +35,14 @@ class Devices:
         for device in self.__devices:
             device.async_remove_tasks()
 
-    def register_device_updated_cb(self, device_updated_cb: DeviceCallbackType) -> None:
+    def register_device_updated_cb(
+        self, device_updated_cb: DeviceCallbackType[Device]
+    ) -> None:
         """Register callback for devices being updated."""
         self.device_updated_cbs.append(device_updated_cb)
 
     def unregister_device_updated_cb(
-        self, device_updated_cb: DeviceCallbackType
+        self, device_updated_cb: DeviceCallbackType[Device]
     ) -> None:
         """Unregister callback for devices being updated."""
         self.device_updated_cbs.remove(device_updated_cb)
@@ -91,14 +92,10 @@ class Devices:
         device.unregister_device_updated_cb(self.device_updated)
         self.__devices.remove(device)
 
-    async def device_updated(self, device: Device) -> None:
+    def device_updated(self, device: Device) -> None:
         """Call all registered device updated callbacks of device."""
-        await asyncio.gather(
-            *[
-                device_updated_cb(device)
-                for device_updated_cb in self.device_updated_cbs
-            ]
-        )
+        for device_updated_cb in self.device_updated_cbs:
+            device_updated_cb(device)
 
     async def process(self, telegram: Telegram) -> None:
         """Process telegram."""
diff --git a/xknx/devices/expose_sensor.py b/xknx/devices/expose_sensor.py
index 31753e56..5f2166cb 100644
--- a/xknx/devices/expose_sensor.py
+++ b/xknx/devices/expose_sensor.py
@@ -71,10 +71,10 @@ class ExposeSensor(Device):
         self._cooldown_task: Task | None = None
         self._cooldown_task_name = f"expose_sensor.cooldown_{id(self)}"
 
-    async def after_update(self) -> None:
+    def after_update(self) -> None:
         """Call after state was updated."""
         self._cooldown_latest_value = self.sensor_value.value
-        await super().after_update()
+        super().after_update()
 
     def _iter_remote_values(self) -> Iterator[RemoteValue[Any]]:
         """Iterate the devices RemoteValue classes."""
@@ -88,16 +88,16 @@ class ExposeSensor(Device):
 
     async def process_group_write(self, telegram: Telegram) -> None:
         """Process incoming and outgoing GROUP WRITE telegram."""
-        await self.sensor_value.process(telegram)
+        self.sensor_value.process(telegram)
 
     async def process_group_read(self, telegram: Telegram) -> None:
         """Process incoming GROUP READ telegram."""
         if not self.respond_to_read:
             return
         if self._cooldown_latest_value is not None:
-            await self.sensor_value.set(self._cooldown_latest_value, response=True)
+            self.sensor_value.set(self._cooldown_latest_value, response=True)
             return
-        await self.sensor_value.respond()
+        self.sensor_value.respond()
 
     async def set(self, value: Any) -> None:
         """Set new value."""
@@ -109,7 +109,7 @@ class ExposeSensor(Device):
                 name=self._cooldown_task_name,
                 async_func=self._cooldown_wait,
             ).start()
-        await self.sensor_value.set(value)
+        self.sensor_value.set(value)
 
     async def _cooldown_wait(self) -> None:
         """Send value after cooldown if it differs from last processed value."""
@@ -117,7 +117,7 @@ class ExposeSensor(Device):
             await asyncio.sleep(self.cooldown)
             if self.sensor_value.value == self._cooldown_latest_value:
                 break
-            await self.sensor_value.set(self._cooldown_latest_value)  # type: ignore[arg-type]
+            self.sensor_value.set(self._cooldown_latest_value)  # type: ignore[arg-type]
 
     def unit_of_measurement(self) -> str | None:
         """Return the unit of measurement."""
diff --git a/xknx/devices/fan.py b/xknx/devices/fan.py
index 637a09c5..daef9fc2 100644
--- a/xknx/devices/fan.py
+++ b/xknx/devices/fan.py
@@ -9,7 +9,6 @@ It provides functionality for
 
 from __future__ import annotations
 
-import asyncio
 from collections.abc import Iterator
 from enum import Enum
 import logging
@@ -130,7 +129,7 @@ class Fan(Device):
     async def turn_on(self, speed: int | None = None) -> None:
         """Turn on fan."""
         if self.switch.initialized:
-            await self.switch.on()
+            self.switch.on()
             # For a switch GA fan, we only use an explicitly provided speed, but not
             # arbitrarily set a default speed here, compared to the speed GA based fans below.
             if speed is not None:
@@ -141,25 +140,23 @@ class Fan(Device):
     async def turn_off(self) -> None:
         """Turn off fan."""
         if self.switch.initialized:
-            await self.switch.off()
+            self.switch.off()
         else:
             await self.set_speed(0)
 
     async def set_speed(self, speed: int) -> None:
         """Set the fan to a designated speed."""
-        await self.speed.set(speed)
+        self.speed.set(speed)
 
     async def set_oscillation(self, oscillation: bool) -> None:
         """Set the fan oscillation mode on or off."""
-        await self.oscillation.set(oscillation)
+        self.oscillation.set(oscillation)
 
     async def process_group_write(self, telegram: Telegram) -> None:
         """Process incoming and outgoing GROUP WRITE telegram."""
-        await asyncio.gather(
-            self.switch.process(telegram),
-            self.speed.process(telegram),
-            self.oscillation.process(telegram),
-        )
+        self.switch.process(telegram)
+        self.speed.process(telegram)
+        self.oscillation.process(telegram)
 
     @property
     def current_speed(self) -> int | None:
diff --git a/xknx/devices/light.py b/xknx/devices/light.py
index a1d87e6b..dfc1d2f8 100644
--- a/xknx/devices/light.py
+++ b/xknx/devices/light.py
@@ -14,7 +14,7 @@ It provides functionality for
 from __future__ import annotations
 
 import asyncio
-from collections.abc import Awaitable, Callable, Iterator
+from collections.abc import Iterator
 from enum import Enum
 from itertools import chain
 import logging
@@ -31,6 +31,7 @@ from xknx.remote_value import (
     RemoteValueScaling,
     RemoteValueSwitch,
 )
+from xknx.typing import CallbackType
 
 from .device import Device, DeviceCallbackType
 
@@ -38,8 +39,6 @@ if TYPE_CHECKING:
     from xknx.telegram import Telegram
     from xknx.xknx import XKNX
 
-AsyncCallback = Callable[[], Awaitable[None]]
-
 logger = logging.getLogger("xknx.log")
 
 
@@ -61,7 +60,7 @@ class _SwitchAndBrightness:
         group_address_brightness: GroupAddressesType = None,
         group_address_brightness_state: GroupAddressesType = None,
         sync_state: bool | int | float | str = True,
-        after_update_cb: AsyncCallback | None = None,
+        after_update_cb: CallbackType | None = None,
     ):
         self.switch = RemoteValueSwitch(
             xknx,
@@ -93,21 +92,21 @@ class _SwitchAndBrightness:
             return bool(self.brightness.value)
         return None
 
-    async def set_on(self) -> None:
+    def set_on(self) -> None:
         """Switch light on."""
         if self.switch.writable:
-            await self.switch.on()
+            self.switch.on()
             return
         if self.brightness.writable:
-            await self.brightness.set(self.brightness.range_to)
+            self.brightness.set(self.brightness.range_to)
 
-    async def set_off(self) -> None:
+    def set_off(self) -> None:
         """Switch light off."""
         if self.switch.writable:
-            await self.switch.off()
+            self.switch.off()
             return
         if self.brightness.writable:
-            await self.brightness.set(0)
+            self.brightness.set(0)
 
     def __eq__(self, other: object) -> bool:
         """Compare for equality."""
@@ -362,13 +361,13 @@ class Light(Device):
             )
         )
 
-    async def _individual_color_callback_debounce(self) -> None:
+    def _individual_color_callback_debounce(self) -> None:
         """Run callback after all individual colors were updated or timeout passed."""
 
         async def debouncer() -> None:
             await asyncio.sleep(Light.DEBOUNCE_TIMEOUT)
             self._reset_individual_color_debounce_telegrams()
-            await asyncio.shield(self.after_update())
+            self.after_update()
 
         self._individual_color_debounce_telegram_counter -= 1
         if self._individual_color_debounce_telegram_counter > 0:
@@ -380,7 +379,7 @@ class Light(Device):
             return
         self.xknx.task_registry.unregister(self._individual_color_debounce_task_name)
         self._reset_individual_color_debounce_telegrams()
-        await self.after_update()
+        self.after_update()
 
     @property
     def supports_brightness(self) -> bool:
@@ -433,20 +432,18 @@ class Light(Device):
     async def set_on(self) -> None:
         """Switch light on."""
         if self.switch.writable:
-            await self.switch.on()
+            self.switch.on()
             return
-        await asyncio.gather(
-            *[color.set_on() for color in self._iter_individual_colors()]
-        )
+        for color in self._iter_individual_colors():
+            color.set_on()
 
     async def set_off(self) -> None:
         """Switch light off."""
         if self.switch.writable:
-            await self.switch.off()
+            self.switch.off()
             return
-        await asyncio.gather(
-            *[color.set_off() for color in self._iter_individual_colors()]
-        )
+        for color in self._iter_individual_colors():
+            color.set_off()
 
     @property
     def current_brightness(self) -> int | None:
@@ -458,7 +455,7 @@ class Light(Device):
         if not self.supports_brightness:
             logger.warning("Dimming not supported for device %s", self.get_name())
             return
-        await self.brightness.set(brightness)
+        self.brightness.set(brightness)
 
     @property
     def current_color(self) -> tuple[tuple[int, int, int] | None, int | None]:
@@ -510,32 +507,28 @@ class Light(Device):
         if white is not None:
             if self.supports_rgbw:
                 if self.rgbw.initialized:
-                    await self.rgbw.set(RGBWColor(*color, white))
+                    self.rgbw.set(RGBWColor(*color, white))
                     return
                 if all(
                     c.brightness.initialized for c in self._iter_individual_colors()
                 ):
-                    await asyncio.gather(
-                        self.red.brightness.set(color[0]),
-                        self.green.brightness.set(color[1]),
-                        self.blue.brightness.set(color[2]),
-                        self.white.brightness.set(white),
-                    )
+                    self.red.brightness.set(color[0])
+                    self.green.brightness.set(color[1])
+                    self.blue.brightness.set(color[2])
+                    self.white.brightness.set(white)
                     return
             logger.warning("RGBW not supported for device %s", self.get_name())
         else:
             if self.supports_color:
                 if self.color.initialized:
-                    await self.color.set(RGBColor(*color))
+                    self.color.set(RGBColor(*color))
                     return
                 if all(
                     c.brightness.initialized for c in (self.red, self.green, self.blue)
                 ):
-                    await asyncio.gather(
-                        self.red.brightness.set(color[0]),
-                        self.green.brightness.set(color[1]),
-                        self.blue.brightness.set(color[2]),
-                    )
+                    self.red.brightness.set(color[0])
+                    self.green.brightness.set(color[1])
+                    self.blue.brightness.set(color[2])
                     return
             logger.warning("Colors not supported for device %s", self.get_name())
 
@@ -560,26 +553,24 @@ class Light(Device):
             return
         value_sent = False
         if (hue := hs_color[0]) != self.hue.value:
-            await self.hue.set(hue)
+            self.hue.set(hue)
             value_sent = True
         if (saturation := hs_color[1]) != self.saturation.value:
-            await self.saturation.set(saturation)
+            self.saturation.set(saturation)
             value_sent = True
         if not value_sent:
             # at least one value shall be sent to enable turn-on by hs_color
-            await asyncio.gather(
-                self.hue.set(hue),
-                self.saturation.set(saturation),
-            )
+            self.hue.set(hue)
+            self.saturation.set(saturation)
 
-    async def _xyy_color_from_rv(self) -> None:
+    def _xyy_color_from_rv(self) -> None:
         """Update the current xyY-color from RemoteValue (Callback)."""
         new_xyy = self.xyy_color.value
         if self._xyy_color_valid is not None and new_xyy is not None:
             self._xyy_color_valid = self._xyy_color_valid | new_xyy
         else:
             self._xyy_color_valid = new_xyy
-        await self.after_update()
+        self.after_update()
 
     @property
     def current_xyy_color(self) -> XYYColor | None:
@@ -591,7 +582,7 @@ class Light(Device):
         if not self.supports_xyy_color:
             logger.warning("XYY-color not supported for device %s", self.get_name())
             return
-        await self.xyy_color.set(xyy)
+        self.xyy_color.set(xyy)
 
     @property
     def current_tunable_white(self) -> int | None:
@@ -603,7 +594,7 @@ class Light(Device):
         if not self.supports_tunable_white:
             logger.warning("Tunable white not supported for device %s", self.get_name())
             return
-        await self.tunable_white.set(tunable_white)
+        self.tunable_white.set(tunable_white)
 
     @property
     def current_color_temperature(self) -> int | float | None:
@@ -618,20 +609,14 @@ class Light(Device):
                 self.get_name(),
             )
             return
-        await self.color_temperature.set(color_temperature)
+        self.color_temperature.set(color_temperature)
 
     async def process_group_write(self, telegram: Telegram) -> None:
         """Process incoming and outgoing GROUP WRITE telegram."""
-        await asyncio.gather(
-            *[
-                remote_value.process(telegram)
-                for remote_value in self._iter_instant_remote_values()
-            ],
-            *[
-                remote_value.process(telegram, always_callback=True)
-                for remote_value in self._iter_debounce_remote_values()
-            ],
-        )
+        for remote_value in self._iter_instant_remote_values():
+            remote_value.process(telegram)
+        for remote_value in self._iter_debounce_remote_values():
+            remote_value.process(telegram, always_callback=True)
 
     def __str__(self) -> str:
         """Return object as readable string."""
diff --git a/xknx/devices/notification.py b/xknx/devices/notification.py
index d532dfb5..fb156414 100644
--- a/xknx/devices/notification.py
+++ b/xknx/devices/notification.py
@@ -55,11 +55,11 @@ class Notification(Device):
     async def set(self, message: str) -> None:
         """Set message."""
         cropped_message = message[:14]
-        await self.remote_value.set(cropped_message)
+        self.remote_value.set(cropped_message)
 
     async def process_group_write(self, telegram: Telegram) -> None:
         """Process incoming and outgoing GROUP WRITE telegram."""
-        await self.remote_value.process(telegram)
+        self.remote_value.process(telegram)
 
     async def process_group_read(self, telegram: Telegram) -> None:
         """Process incoming GroupValueResponse telegrams."""
@@ -67,7 +67,7 @@ class Notification(Device):
             self.respond_to_read
             and telegram.destination_address == self.remote_value.group_address
         ):
-            await self.remote_value.respond()
+            self.remote_value.respond()
 
     def __str__(self) -> str:
         """Return object as readable string."""
diff --git a/xknx/devices/numeric_value.py b/xknx/devices/numeric_value.py
index 0d307861..f9f4cb0e 100644
--- a/xknx/devices/numeric_value.py
+++ b/xknx/devices/numeric_value.py
@@ -62,7 +62,7 @@ class NumericValue(Device):
 
     async def process_group_write(self, telegram: Telegram) -> None:
         """Process incoming and outgoing GROUP WRITE telegram."""
-        await self.sensor_value.process(telegram, always_callback=self.always_callback)
+        self.sensor_value.process(telegram, always_callback=self.always_callback)
 
     async def process_group_read(self, telegram: Telegram) -> None:
         """Process incoming GroupValueResponse telegrams."""
@@ -70,11 +70,11 @@ class NumericValue(Device):
             self.respond_to_read
             and telegram.destination_address == self.sensor_value.group_address
         ):
-            await self.sensor_value.respond()
+            self.sensor_value.respond()
 
     async def set(self, value: float | int) -> None:
         """Set new value."""
-        await self.sensor_value.set(value)
+        self.sensor_value.set(value)
 
     def unit_of_measurement(self) -> str | None:
         """Return the unit of measurement."""
diff --git a/xknx/devices/raw_value.py b/xknx/devices/raw_value.py
index f5643552..554727f1 100644
--- a/xknx/devices/raw_value.py
+++ b/xknx/devices/raw_value.py
@@ -62,7 +62,7 @@ class RawValue(Device):
 
     async def process_group_write(self, telegram: Telegram) -> None:
         """Process incoming and outgoing GROUP WRITE telegram."""
-        await self.remote_value.process(telegram, always_callback=self.always_callback)
+        self.remote_value.process(telegram, always_callback=self.always_callback)
 
     async def process_group_read(self, telegram: Telegram) -> None:
         """Process incoming GroupValueResponse telegrams."""
@@ -70,11 +70,11 @@ class RawValue(Device):
             self.respond_to_read
             and telegram.destination_address == self.remote_value.group_address
         ):
-            await self.remote_value.respond()
+            self.remote_value.respond()
 
     async def set(self, value: int) -> None:
         """Set new value."""
-        await self.remote_value.set(value)
+        self.remote_value.set(value)
 
     def resolve_state(self) -> int | None:
         """Return the current state of the sensor as an unsigned integer."""
diff --git a/xknx/devices/scene.py b/xknx/devices/scene.py
index 3d5fef95..3e91f603 100644
--- a/xknx/devices/scene.py
+++ b/xknx/devices/scene.py
@@ -46,7 +46,7 @@ class Scene(Device):
 
     async def run(self) -> None:
         """Activate scene."""
-        await self.scene_value.set(self.scene_number)
+        self.scene_value.set(self.scene_number)
 
     def __str__(self) -> str:
         """Return object as readable string."""
diff --git a/xknx/devices/sensor.py b/xknx/devices/sensor.py
index 870ab740..65607630 100644
--- a/xknx/devices/sensor.py
+++ b/xknx/devices/sensor.py
@@ -79,11 +79,11 @@ class Sensor(Device):
 
     async def process_group_write(self, telegram: Telegram) -> None:
         """Process incoming and outgoing GROUP WRITE telegram."""
-        await self.sensor_value.process(telegram, always_callback=self.always_callback)
+        self.sensor_value.process(telegram, always_callback=self.always_callback)
 
     async def process_group_response(self, telegram: Telegram) -> None:
         """Process incoming GroupValueResponse telegrams."""
-        await self.sensor_value.process(telegram)
+        self.sensor_value.process(telegram)
 
     def unit_of_measurement(self) -> str | None:
         """Return the unit of measurement."""
diff --git a/xknx/devices/switch.py b/xknx/devices/switch.py
index 82bcb3bd..b5dd3772 100644
--- a/xknx/devices/switch.py
+++ b/xknx/devices/switch.py
@@ -75,15 +75,15 @@ class Switch(Device):
 
     async def set_on(self) -> None:
         """Switch on switch."""
-        await self.switch.on()
+        self.switch.on()
 
     async def set_off(self) -> None:
         """Switch off switch."""
-        await self.switch.off()
+        self.switch.off()
 
     async def process_group_write(self, telegram: Telegram) -> None:
         """Process incoming and outgoing GROUP WRITE telegram."""
-        if await self.switch.process(telegram):
+        if self.switch.process(telegram):
             if self.reset_after is not None and self.switch.value:
                 self._reset_task = self.xknx.task_registry.register(
                     name=f"switch.reset_{id(self)}",
@@ -97,7 +97,7 @@ class Switch(Device):
             self.respond_to_read
             and telegram.destination_address == self.switch.group_address
         ):
-            await self.switch.respond()
+            self.switch.respond()
 
     async def _reset_state(self, wait_seconds: float) -> None:
         await asyncio.sleep(wait_seconds)
diff --git a/xknx/devices/weather.py b/xknx/devices/weather.py
index 12c8f830..19969135 100644
--- a/xknx/devices/weather.py
+++ b/xknx/devices/weather.py
@@ -15,7 +15,6 @@ It provides functionality for
 
 from __future__ import annotations
 
-import asyncio
 from collections.abc import Callable, Iterator
 from datetime import date, datetime
 from enum import Enum
@@ -250,12 +249,8 @@ class Weather(Device):
 
     async def process_group_write(self, telegram: Telegram) -> None:
         """Process incoming and outgoing GROUP WRITE telegram."""
-        await asyncio.gather(
-            *[
-                remote_value.process(telegram)
-                for remote_value in self._iter_remote_values()
-            ]
-        )
+        for remote_value in self._iter_remote_values():
+            remote_value.process(telegram)
 
     @property
     def temperature(self) -> float | None:
diff --git a/xknx/remote_value/remote_value.py b/xknx/remote_value/remote_value.py
index 6ac307ad..16e30ff6 100644
--- a/xknx/remote_value/remote_value.py
+++ b/xknx/remote_value/remote_value.py
@@ -10,7 +10,7 @@ Remote value can be :
 from __future__ import annotations
 
 from abc import ABC
-from collections.abc import Awaitable, Callable, Iterator
+from collections.abc import Iterator
 import logging
 from typing import TYPE_CHECKING, Generic, TypeVar, Union
 
@@ -23,6 +23,7 @@ from xknx.telegram.address import (
     parse_device_group_address,
 )
 from xknx.telegram.apci import GroupValueResponse, GroupValueWrite
+from xknx.typing import CallbackType
 
 if TYPE_CHECKING:
     from xknx.telegram.address import DeviceAddressableType
@@ -30,7 +31,6 @@ if TYPE_CHECKING:
 
 logger = logging.getLogger("xknx.log")
 
-AsyncCallbackType = Callable[[], Awaitable[None]]
 GroupAddressesType = Union[
     "DeviceAddressableType", list[Union["DeviceAddressableType", None]], None
 ]
@@ -50,7 +50,7 @@ class RemoteValue(ABC, Generic[ValueT]):
         sync_state: None | bool | int | float | str = None,
         device_name: str | None = None,
         feature_name: str | None = None,
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
     ):
         """Initialize RemoteValue class."""
         self.xknx: XKNX = xknx
@@ -82,7 +82,7 @@ class RemoteValue(ABC, Generic[ValueT]):
         self.feature_name: str = "Unknown" if feature_name is None else feature_name
         self._value: ValueT | None = None
         self.telegram: Telegram | None = None
-        self.after_update_cb: AsyncCallbackType | None = after_update_cb
+        self.after_update_cb: CallbackType | None = after_update_cb
         self._sync_state = sync_state
 
     def register_state_updater(self) -> None:
@@ -118,11 +118,11 @@ class RemoteValue(ABC, Generic[ValueT]):
             self.to_knx(value)
         self._value = value
 
-    async def update_value(self, value: ValueT | None) -> None:
-        """Set new value without creating a Telegram. Awaits after_update_cb. Raises ConversionError on invalid value."""
+    def update_value(self, value: ValueT | None) -> None:
+        """Set new value without creating a Telegram. Calls after_update_cb. Raises ConversionError on invalid value."""
         self.value = value
         if self.after_update_cb is not None:
-            await self.after_update_cb()
+            self.after_update_cb()
 
     @property
     def initialized(self) -> bool:
@@ -170,7 +170,7 @@ class RemoteValue(ABC, Generic[ValueT]):
             )
         return self.dpt_class.to_knx(value)
 
-    async def process(self, telegram: Telegram, always_callback: bool = False) -> bool:
+    def process(self, telegram: Telegram, always_callback: bool = False) -> bool:
         """Process incoming or outgoing telegram."""
         if not isinstance(
             telegram.destination_address, GroupAddress | InternalGroupAddress
@@ -209,12 +209,10 @@ class RemoteValue(ABC, Generic[ValueT]):
             self._value = decoded_payload
             self.telegram = telegram
             if self.after_update_cb is not None:
-                await self.after_update_cb()
+                self.after_update_cb()
         return True
 
-    async def _send(
-        self, payload: DPTArray | DPTBinary, response: bool = False
-    ) -> None:
+    def _send(self, payload: DPTArray | DPTBinary, response: bool = False) -> None:
         """Send payload as telegram to KNX bus."""
         if self.group_address is None:
             return
@@ -225,9 +223,9 @@ class RemoteValue(ABC, Generic[ValueT]):
             ),
             source_address=self.xknx.current_address,
         )
-        await self.xknx.telegrams.put(telegram)
+        self.xknx.telegrams.put_nowait(telegram)
 
-    async def set(self, value: ValueT, response: bool = False) -> None:
+    def set(self, value: ValueT, response: bool = False) -> None:
         """Set new value."""
         if not self.initialized:
             logger.info(
@@ -246,15 +244,15 @@ class RemoteValue(ABC, Generic[ValueT]):
             )
             return
         payload = self.to_knx(value)
-        await self._send(payload, response)
+        self._send(payload, response)
         # self._value is set and after_update_cb() called when the outgoing telegram is processed.
 
-    async def respond(self) -> None:
+    def respond(self) -> None:
         """Send current payload as GroupValueResponse telegram to KNX bus."""
         if self._value is None:
             return
         payload = self.to_knx(self._value)
-        await self._send(payload, response=True)
+        self._send(payload, response=True)
 
     async def read_state(self, wait_for_result: bool = False) -> None:
         """Send GroupValueRead telegram for state address to KNX bus."""
diff --git a/xknx/remote_value/remote_value_climate_mode.py b/xknx/remote_value/remote_value_climate_mode.py
index a5bcdb45..665b18fb 100644
--- a/xknx/remote_value/remote_value_climate_mode.py
+++ b/xknx/remote_value/remote_value_climate_mode.py
@@ -19,8 +19,9 @@ from xknx.dpt import (
 )
 from xknx.dpt.dpt_hvac_mode import HVACControllerMode, HVACModeT, HVACOperationMode
 from xknx.exceptions import ConversionError, CouldNotParseTelegram
+from xknx.typing import CallbackType
 
-from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
+from .remote_value import GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
     from xknx.xknx import XKNX
@@ -54,7 +55,7 @@ class RemoteValueOperationMode(RemoteValueClimateModeBase[HVACOperationMode]):
         device_name: str | None = None,
         feature_name: str = "Climate mode",
         climate_mode_type: ClimateModeType | None = None,
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
     ):
         """Initialize remote value of KNX climate mode."""
         super().__init__(
@@ -101,7 +102,7 @@ class RemoteValueControllerMode(RemoteValueClimateModeBase[HVACControllerMode]):
         sync_state: bool | int | float | str = True,
         device_name: str | None = None,
         feature_name: str = "Controller Mode",
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
     ):
         """Initialize remote value of KNX climate mode."""
         super().__init__(
@@ -138,7 +139,7 @@ class RemoteValueBinaryOperationMode(RemoteValueClimateModeBase[HVACOperationMod
         sync_state: bool | int | float | str = True,
         device_name: str | None = None,
         feature_name: str = "Climate mode binary",
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
         operation_mode: HVACOperationMode | None = None,
     ):
         """Initialize remote value of KNX DPT 1 representing a climate operation mode."""
@@ -213,7 +214,7 @@ class RemoteValueBinaryHeatCool(RemoteValueClimateModeBase[HVACControllerMode]):
         sync_state: bool | int | float | str = True,
         device_name: str | None = None,
         feature_name: str = "Controller mode Heat/Cool",
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
         controller_mode: HVACControllerMode | None = None,
     ):
         """Initialize remote value of KNX DPT 1 representing a climate controller mode."""
diff --git a/xknx/remote_value/remote_value_color_rgbw.py b/xknx/remote_value/remote_value_color_rgbw.py
index a3c56ce5..700dd508 100644
--- a/xknx/remote_value/remote_value_color_rgbw.py
+++ b/xknx/remote_value/remote_value_color_rgbw.py
@@ -10,8 +10,9 @@ from typing import TYPE_CHECKING
 
 from xknx.dpt import DPTArray, DPTBinary
 from xknx.dpt.dpt_color import DPTColorRGBW, RGBWColor
+from xknx.typing import CallbackType
 
-from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
+from .remote_value import GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
     from xknx.xknx import XKNX
@@ -28,7 +29,7 @@ class RemoteValueColorRGBW(RemoteValue[RGBWColor]):
         sync_state: bool | int | float | str = True,
         device_name: str | None = None,
         feature_name: str = "Color RGBW",
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
     ):
         """Initialize remote value of KNX DPT 251.600 (DPT_Color_RGBW)."""
         super().__init__(
diff --git a/xknx/remote_value/remote_value_control.py b/xknx/remote_value/remote_value_control.py
index a5058a56..69e3043c 100644
--- a/xknx/remote_value/remote_value_control.py
+++ b/xknx/remote_value/remote_value_control.py
@@ -11,8 +11,9 @@ from typing import TYPE_CHECKING, Any
 
 from xknx.dpt import DPTControlStepCode
 from xknx.exceptions import ConversionError
+from xknx.typing import CallbackType
 
-from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
+from .remote_value import GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
     from xknx.xknx import XKNX
@@ -30,7 +31,7 @@ class RemoteValueControl(RemoteValue[Any]):
         value_type: str | None = None,
         device_name: str | None = None,
         feature_name: str = "Control",
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
     ):
         """Initialize control remote value."""
         if value_type is None:
diff --git a/xknx/remote_value/remote_value_datetime.py b/xknx/remote_value/remote_value_datetime.py
index 51d77ea3..1115cf76 100644
--- a/xknx/remote_value/remote_value_datetime.py
+++ b/xknx/remote_value/remote_value_datetime.py
@@ -12,8 +12,9 @@ from typing import TYPE_CHECKING
 
 from xknx.dpt import DPTDate, DPTDateTime, DPTTime
 from xknx.exceptions import ConversionError
+from xknx.typing import CallbackType
 
-from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
+from .remote_value import GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
     from xknx.xknx import XKNX
@@ -39,7 +40,7 @@ class RemoteValueDateTime(RemoteValue[time.struct_time]):
         value_type: str = "time",
         device_name: str | None = None,
         feature_name: str = "DateTime",
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
     ):
         """Initialize RemoteValueDateTime class."""
         try:
diff --git a/xknx/remote_value/remote_value_raw.py b/xknx/remote_value/remote_value_raw.py
index 1cc4201b..aea60cd8 100644
--- a/xknx/remote_value/remote_value_raw.py
+++ b/xknx/remote_value/remote_value_raw.py
@@ -11,8 +11,9 @@ from typing import TYPE_CHECKING
 
 from xknx.dpt.dpt import DPTArray, DPTBinary
 from xknx.exceptions import ConversionError, CouldNotParseTelegram
+from xknx.typing import CallbackType
 
-from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
+from .remote_value import GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
     from xknx.xknx import XKNX
@@ -30,7 +31,7 @@ class RemoteValueRaw(RemoteValue[int]):
         sync_state: bool | int | float | str = True,
         device_name: str | None = None,
         feature_name: str = "Raw",
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
     ):
         """Initialize RemoteValueRaw class."""
         self.payload_length = payload_length
diff --git a/xknx/remote_value/remote_value_scaling.py b/xknx/remote_value/remote_value_scaling.py
index 5cd8f35c..8e27d26b 100644
--- a/xknx/remote_value/remote_value_scaling.py
+++ b/xknx/remote_value/remote_value_scaling.py
@@ -10,8 +10,9 @@ from typing import TYPE_CHECKING
 
 from xknx.dpt import DPTArray, DPTBinary
 from xknx.exceptions import CouldNotParseTelegram
+from xknx.typing import CallbackType
 
-from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
+from .remote_value import GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
     from xknx.xknx import XKNX
@@ -28,7 +29,7 @@ class RemoteValueScaling(RemoteValue[int]):
         sync_state: bool | int | float | str = True,
         device_name: str | None = None,
         feature_name: str = "Value",
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
         range_from: int = 0,
         range_to: int = 100,
     ):
diff --git a/xknx/remote_value/remote_value_sensor.py b/xknx/remote_value/remote_value_sensor.py
index e1ad1931..3bc85ed6 100644
--- a/xknx/remote_value/remote_value_sensor.py
+++ b/xknx/remote_value/remote_value_sensor.py
@@ -11,8 +11,9 @@ from typing import TYPE_CHECKING, TypeVar
 
 from xknx.dpt import DPTBase, DPTNumeric, DPTString
 from xknx.exceptions import ConversionError
+from xknx.typing import CallbackType
 
-from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
+from .remote_value import GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
     from xknx.xknx import XKNX
@@ -36,7 +37,7 @@ class _RemoteValueGeneric(RemoteValue[ValueT]):
         value_type: int | str | None = None,
         device_name: str | None = None,
         feature_name: str = "Value",
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
     ):
         """Initialize RemoteValueSensor class."""
         _dpt_class = (
diff --git a/xknx/remote_value/remote_value_setpoint_shift.py b/xknx/remote_value/remote_value_setpoint_shift.py
index 02a1f9f7..4f8c1e6a 100644
--- a/xknx/remote_value/remote_value_setpoint_shift.py
+++ b/xknx/remote_value/remote_value_setpoint_shift.py
@@ -11,8 +11,9 @@ from typing import TYPE_CHECKING
 
 from xknx.dpt import DPTArray, DPTBinary, DPTTemperature, DPTValue1Count
 from xknx.exceptions import ConversionError, CouldNotParseTelegram
+from xknx.typing import CallbackType
 
-from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
+from .remote_value import GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
     from xknx.xknx import XKNX
@@ -35,7 +36,7 @@ class RemoteValueSetpointShift(RemoteValue[float]):
         group_address_state: GroupAddressesType = None,
         sync_state: bool | int | float | str = True,
         device_name: str | None = None,
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
         setpoint_shift_mode: SetpointShiftMode | None = None,
         setpoint_shift_step: float = 0.1,
     ):
diff --git a/xknx/remote_value/remote_value_step.py b/xknx/remote_value/remote_value_step.py
index ada4b964..1b0c37ad 100644
--- a/xknx/remote_value/remote_value_step.py
+++ b/xknx/remote_value/remote_value_step.py
@@ -11,8 +11,9 @@ from typing import TYPE_CHECKING
 
 from xknx.dpt import DPTArray, DPTBinary
 from xknx.exceptions import ConversionError, CouldNotParseTelegram
+from xknx.typing import CallbackType
 
-from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
+from .remote_value import GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
     from xknx.xknx import XKNX
@@ -34,7 +35,7 @@ class RemoteValueStep(RemoteValue["RemoteValueStep.Direction"]):
         group_address_state: GroupAddressesType = None,
         device_name: str | None = None,
         feature_name: str = "Step",
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
         invert: bool = False,
     ):
         """Initialize remote value of KNX DPT 1.007."""
@@ -78,10 +79,10 @@ class RemoteValueStep(RemoteValue["RemoteValueStep.Direction"]):
             feature_name=self.feature_name,
         )
 
-    async def increase(self) -> None:
+    def increase(self) -> None:
         """Increase value."""
-        await self.set(self.Direction.INCREASE)
+        self.set(self.Direction.INCREASE)
 
-    async def decrease(self) -> None:
+    def decrease(self) -> None:
         """Decrease the value."""
-        await self.set(self.Direction.DECREASE)
+        self.set(self.Direction.DECREASE)
diff --git a/xknx/remote_value/remote_value_switch.py b/xknx/remote_value/remote_value_switch.py
index 649627a4..ada762b9 100644
--- a/xknx/remote_value/remote_value_switch.py
+++ b/xknx/remote_value/remote_value_switch.py
@@ -10,8 +10,9 @@ from typing import TYPE_CHECKING
 
 from xknx.dpt import DPTArray, DPTBinary
 from xknx.exceptions import ConversionError, CouldNotParseTelegram
+from xknx.typing import CallbackType
 
-from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
+from .remote_value import GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
     from xknx.xknx import XKNX
@@ -28,7 +29,7 @@ class RemoteValueSwitch(RemoteValue[bool]):
         sync_state: bool | int | float | str = True,
         device_name: str | None = None,
         feature_name: str = "State",
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
         invert: bool = False,
     ):
         """Initialize remote value of KNX DPT 1.001."""
@@ -67,11 +68,11 @@ class RemoteValueSwitch(RemoteValue[bool]):
             feature_name=self.feature_name,
         )
 
-    async def off(self) -> None:
+    def off(self) -> None:
         """Set value to OFF."""
-        await self.set(False)
+        self.set(False)
 
-    async def on(self) -> None:
+    def on(self) -> None:
         """Set value to ON."""
         # pylint: disable=invalid-name
-        await self.set(True)
+        self.set(True)
diff --git a/xknx/remote_value/remote_value_updown.py b/xknx/remote_value/remote_value_updown.py
index 97f25aac..85e4c5b8 100644
--- a/xknx/remote_value/remote_value_updown.py
+++ b/xknx/remote_value/remote_value_updown.py
@@ -11,8 +11,9 @@ from typing import TYPE_CHECKING
 
 from xknx.dpt import DPTArray, DPTBinary
 from xknx.exceptions import ConversionError, CouldNotParseTelegram
+from xknx.typing import CallbackType
 
-from .remote_value import AsyncCallbackType, GroupAddressesType, RemoteValue
+from .remote_value import GroupAddressesType, RemoteValue
 
 if TYPE_CHECKING:
     from xknx.xknx import XKNX
@@ -34,7 +35,7 @@ class RemoteValueUpDown(RemoteValue["RemoteValueUpDown.Direction"]):
         group_address_state: GroupAddressesType = None,
         device_name: str | None = None,
         feature_name: str = "Up/Down",
-        after_update_cb: AsyncCallbackType | None = None,
+        after_update_cb: CallbackType | None = None,
         invert: bool = False,
     ):
         """Initialize remote value of KNX DPT 1.008."""
@@ -74,11 +75,11 @@ class RemoteValueUpDown(RemoteValue["RemoteValueUpDown.Direction"]):
             feature_name=self.feature_name,
         )
 
-    async def down(self) -> None:
+    def down(self) -> None:
         """Set value to down."""
-        await self.set(self.Direction.DOWN)
+        self.set(self.Direction.DOWN)
 
-    async def up(self) -> None:
+    def up(self) -> None:
         """Set value to UP."""
         # pylint: disable=invalid-name
-        await self.set(self.Direction.UP)
+        self.set(self.Direction.UP)
diff --git a/xknx/typing/__init__.py b/xknx/typing/__init__.py
new file mode 100644
index 00000000..3f716291
--- /dev/null
+++ b/xknx/typing/__init__.py
@@ -0,0 +1,12 @@
+"""Types used by XKNX."""
+
+from collections.abc import Callable
+from typing import TYPE_CHECKING, TypeVar
+
+if TYPE_CHECKING:
+    from xknx.devices import Device
+
+CallbackType = Callable[[], None]
+
+DeviceT = TypeVar("DeviceT", bound="Device")
+DeviceCallbackType = Callable[[DeviceT], None]
diff --git a/xknx/xknx.py b/xknx/xknx.py
index 3993a9e7..ab75c244 100644
--- a/xknx/xknx.py
+++ b/xknx/xknx.py
@@ -29,6 +29,7 @@ from xknx.io import (
 )
 from xknx.management import Management
 from xknx.telegram import GroupAddress, GroupAddressType, IndividualAddress, Telegram
+from xknx.typing import DeviceCallbackType
 
 from .__version__ import __version__ as VERSION
 
@@ -42,7 +43,7 @@ class XKNX:
         self,
         address_format: GroupAddressType = GroupAddressType.LONG,
         telegram_received_cb: Callable[[Telegram], Awaitable[None]] | None = None,
-        device_updated_cb: Callable[[Device], Awaitable[None]] | None = None,
+        device_updated_cb: DeviceCallbackType[Device] | None = None,
         connection_state_changed_cb: Callable[[XknxConnectionState], Awaitable[None]]
         | None = None,
         rate_limit: int = 0,


Test patch:
diff --git a/test/devices_tests/binary_sensor_test.py b/test/devices_tests/binary_sensor_test.py
index 7e767991..4152c783 100644
--- a/test/devices_tests/binary_sensor_test.py
+++ b/test/devices_tests/binary_sensor_test.py
@@ -1,6 +1,6 @@
 """Unit test for BinarySensor objects."""
 
-from unittest.mock import AsyncMock, patch
+from unittest.mock import Mock, patch
 
 from xknx import XKNX
 from xknx.devices import BinarySensor
@@ -73,13 +73,13 @@ class TestBinarySensor:
         """Test process / reading telegrams from telegram queue."""
         xknx = XKNX()
         reset_after_sec = 1
-        async_after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         binaryinput = BinarySensor(
             xknx,
             "TestInput",
             "1/2/3",
             reset_after=reset_after_sec,
-            device_updated_cb=async_after_update_callback,
+            device_updated_cb=after_update_callback,
         )
         telegram_on = Telegram(
             destination_address=GroupAddress("1/2/3"),
@@ -92,22 +92,22 @@ class TestBinarySensor:
         await time_travel(reset_after_sec)
         assert not binaryinput.state
         # once for 'on' and once for 'off'
-        assert async_after_update_callback.call_count == 2
+        assert after_update_callback.call_count == 2
 
-        async_after_update_callback.reset_mock()
+        after_update_callback.reset_mock()
         # multiple telegrams during reset_after time period shall reset timer
         await binaryinput.process(telegram_on)
-        async_after_update_callback.assert_called_once()
+        after_update_callback.assert_called_once()
         await binaryinput.process(telegram_on)
         await binaryinput.process(telegram_on)
         # second and third telegram resets timer but doesn't run callback
-        async_after_update_callback.assert_called_once()
+        after_update_callback.assert_called_once()
         assert binaryinput.state
 
         await time_travel(reset_after_sec)
         assert not binaryinput.state
         # once for 'on' and once for 'off'
-        assert async_after_update_callback.call_count == 2
+        assert after_update_callback.call_count == 2
 
     async def test_process_wrong_payload(self):
         """Test process wrong telegram (wrong payload type)."""
@@ -125,13 +125,13 @@ class TestBinarySensor:
     #
     # TEST SWITCHED ON
     #
-    async def test_is_on(self):
+    def test_is_on(self):
         """Test is_on() and is_off() of a BinarySensor with state 'on'."""
         xknx = XKNX()
         binaryinput = BinarySensor(xknx, "TestInput", "1/2/3")
         assert not binaryinput.is_on()
         assert binaryinput.is_off()
-        await binaryinput._set_internal_state(True)
+        binaryinput._set_internal_state(True)
 
         assert binaryinput.is_on()
         assert not binaryinput.is_off()
@@ -139,11 +139,11 @@ class TestBinarySensor:
     #
     # TEST SWITCHED OFF
     #
-    async def test_is_off(self):
+    def test_is_off(self):
         """Test is_on() and is_off() of a BinarySensor with state 'off'."""
         xknx = XKNX()
         binaryinput = BinarySensor(xknx, "TestInput", "1/2/3")
-        await binaryinput._set_internal_state(False)
+        binaryinput._set_internal_state(False)
 
         assert not binaryinput.is_on()
         assert binaryinput.is_off()
@@ -157,9 +157,9 @@ class TestBinarySensor:
         switch = BinarySensor(
             xknx, "TestInput", group_address_state="1/2/3", ignore_internal_state=False
         )
-        async_after_update_callback = AsyncMock()
+        after_update_callback = Mock()
 
-        switch.register_device_updated_cb(async_after_update_callback)
+        switch.register_device_updated_cb(after_update_callback)
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
@@ -168,12 +168,12 @@ class TestBinarySensor:
         await switch.process(telegram)
         # no _context_task started because ignore_internal_state is False
         assert switch._context_task is None
-        async_after_update_callback.assert_called_once_with(switch)
+        after_update_callback.assert_called_once_with(switch)
 
-        async_after_update_callback.reset_mock()
+        after_update_callback.reset_mock()
         # send same telegram again
         await switch.process(telegram)
-        async_after_update_callback.assert_not_called()
+        after_update_callback.assert_not_called()
 
     async def test_process_callback_ignore_internal_state(self):
         """Test after_update_callback after state of switch was changed."""
@@ -185,9 +185,9 @@ class TestBinarySensor:
             ignore_internal_state=True,
             context_timeout=0.001,
         )
-        async_after_update_callback = AsyncMock()
+        after_update_callback = Mock()
 
-        switch.register_device_updated_cb(async_after_update_callback)
+        switch.register_device_updated_cb(after_update_callback)
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
@@ -196,25 +196,25 @@ class TestBinarySensor:
         assert switch.counter == 0
 
         await switch.process(telegram)
-        async_after_update_callback.assert_not_called()
+        after_update_callback.assert_not_called()
         assert switch.counter == 1
         await switch._context_task
-        async_after_update_callback.assert_called_with(switch)
+        after_update_callback.assert_called_with(switch)
         # once with counter 1 and once with counter 0
-        assert async_after_update_callback.call_count == 2
+        assert after_update_callback.call_count == 2
 
-        async_after_update_callback.reset_mock()
+        after_update_callback.reset_mock()
         # send same telegram again
         await switch.process(telegram)
         assert switch.counter == 1
         await switch.process(telegram)
         assert switch.counter == 2
-        async_after_update_callback.assert_not_called()
+        after_update_callback.assert_not_called()
 
         await switch._context_task
-        async_after_update_callback.assert_called_with(switch)
+        after_update_callback.assert_called_with(switch)
         # once with counter 2 and once with counter 0
-        assert async_after_update_callback.call_count == 2
+        assert after_update_callback.call_count == 2
         assert switch.counter == 0
 
     async def test_process_callback_ignore_internal_state_no_counter(self):
@@ -227,9 +227,9 @@ class TestBinarySensor:
             ignore_internal_state=True,
             context_timeout=0,
         )
-        async_after_update_callback = AsyncMock()
+        after_update_callback = Mock()
 
-        switch.register_device_updated_cb(async_after_update_callback)
+        switch.register_device_updated_cb(after_update_callback)
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
@@ -238,12 +238,12 @@ class TestBinarySensor:
         await switch.process(telegram)
         # no _context_task started because context_timeout is False
         assert switch._context_task is None
-        async_after_update_callback.assert_called_once_with(switch)
+        after_update_callback.assert_called_once_with(switch)
 
-        async_after_update_callback.reset_mock()
+        after_update_callback.reset_mock()
         # send same telegram again
         await switch.process(telegram)
-        async_after_update_callback.assert_called_once_with(switch)
+        after_update_callback.assert_called_once_with(switch)
 
     async def test_process_group_value_response(self):
         """Test process of GroupValueResponse telegrams."""
@@ -254,9 +254,9 @@ class TestBinarySensor:
             group_address_state="1/2/3",
             ignore_internal_state=True,
         )
-        async_after_update_callback = AsyncMock()
+        after_update_callback = Mock()
 
-        switch.register_device_updated_cb(async_after_update_callback)
+        switch.register_device_updated_cb(after_update_callback)
 
         write_telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
@@ -272,16 +272,16 @@ class TestBinarySensor:
         # initial GroupValueResponse changes state and runs callback
         await switch.process(response_telegram)
         assert switch.state
-        async_after_update_callback.assert_called_once_with(switch)
+        after_update_callback.assert_called_once_with(switch)
         # GroupValueWrite with same payload runs callback because of `ignore_internal_state`
-        async_after_update_callback.reset_mock()
+        after_update_callback.reset_mock()
         await switch.process(write_telegram)
         assert switch.state
-        async_after_update_callback.assert_called_once_with(switch)
+        after_update_callback.assert_called_once_with(switch)
         # GroupValueResponse should not run callback when state has not changed
-        async_after_update_callback.reset_mock()
+        after_update_callback.reset_mock()
         await switch.process(response_telegram)
-        async_after_update_callback.assert_not_called()
+        after_update_callback.assert_not_called()
 
     #
     # TEST COUNTER
diff --git a/test/devices_tests/climate_test.py b/test/devices_tests/climate_test.py
index 47743dab..d6059369 100644
--- a/test/devices_tests/climate_test.py
+++ b/test/devices_tests/climate_test.py
@@ -1,6 +1,6 @@
 """Unit test for Climate objects."""
 
-from unittest.mock import AsyncMock, patch
+from unittest.mock import Mock, patch
 
 import pytest
 
@@ -147,11 +147,11 @@ class TestClimate:
             group_address_setpoint_shift_state="1/2/4",
             setpoint_shift_mode=SetpointShiftMode.DPT6010,
         )
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         climate.register_device_updated_cb(after_update_callback)
         xknx.devices.async_add(climate)
 
-        await climate.target_temperature.set(23.00)
+        climate.target_temperature.set(23.00)
         await xknx.devices.process(xknx.telegrams.get_nowait())
         after_update_callback.assert_called_with(climate)
         after_update_callback.reset_mock()
@@ -165,7 +165,7 @@ class TestClimate:
         """Test if after_update_callback is called after update of Climate object was changed."""
 
         xknx = XKNX()
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         climate_mode = ClimateMode(
             xknx,
             "TestClimate",
@@ -196,7 +196,7 @@ class TestClimate:
             group_address_target_temperature="1/2/2",
             group_address_setpoint_shift="1/2/3",
         )
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         climate.register_device_updated_cb(after_update_callback)
 
         telegram = Telegram(
@@ -230,7 +230,7 @@ class TestClimate:
         climate_mode = ClimateMode(
             xknx, "TestClimateMode", group_address_operation_mode="1/2/4"
         )
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
 
         climate = Climate(xknx, "TestClimate", mode=climate_mode)
         climate_mode.register_device_updated_cb(after_update_callback)
@@ -409,7 +409,7 @@ class TestClimate:
         await xknx.devices.process(xknx.telegrams.get_nowait())
         assert not climate3.initialized_for_setpoint_shift_calculations
 
-        await climate3.target_temperature.set(23.00)
+        climate3.target_temperature.set(23.00)
         await xknx.devices.process(xknx.telegrams.get_nowait())
         assert climate3.initialized_for_setpoint_shift_calculations
 
@@ -514,7 +514,7 @@ class TestClimate:
         await xknx.devices.process(xknx.telegrams.get_nowait())
         assert not climate.initialized_for_setpoint_shift_calculations
 
-        await climate.target_temperature.set(23.00)
+        climate.target_temperature.set(23.00)
         await xknx.devices.process(xknx.telegrams.get_nowait())
         assert climate.initialized_for_setpoint_shift_calculations
         assert climate.target_temperature_min == "3"
@@ -546,7 +546,7 @@ class TestClimate:
         )
         await xknx.devices.process(_telegram)
 
-        await climate.target_temperature.set(23.00)
+        climate.target_temperature.set(23.00)
         assert xknx.telegrams.qsize() == 1
         _telegram = xknx.telegrams.get_nowait()
         assert _telegram == Telegram(
@@ -625,7 +625,7 @@ class TestClimate:
         )
         await xknx.devices.process(_telegram)
 
-        await climate.target_temperature.set(23.00)
+        climate.target_temperature.set(23.00)
         assert xknx.telegrams.qsize() == 1
         _telegram = xknx.telegrams.get_nowait()
         assert _telegram == Telegram(
@@ -707,7 +707,7 @@ class TestClimate:
             payload=GroupValueWrite(DPTArray(6)),
         )
 
-        await climate.target_temperature.set(23.00)
+        climate.target_temperature.set(23.00)
         assert xknx.telegrams.qsize() == 1
         _telegram = xknx.telegrams.get_nowait()
         await xknx.devices.process(_telegram)
@@ -811,7 +811,7 @@ class TestClimate:
         xknx.devices.async_add(climate)
 
         # base temperature is 20 °C
-        await climate.target_temperature.process(
+        climate.target_temperature.process(
             Telegram(
                 destination_address=GroupAddress("1/2/2"),
                 payload=GroupValueWrite(DPT2ByteFloat().to_knx(20.00)),
@@ -837,7 +837,7 @@ class TestClimate:
             payload=GroupValueWrite(DPTArray((0x87, 0xC4))),
         )  # -0.6
         # simulate incoming new target temperature for next calculation
-        await climate.target_temperature.process(
+        climate.target_temperature.process(
             Telegram(
                 destination_address=GroupAddress("1/2/2"),
                 payload=GroupValueWrite(DPT2ByteFloat().to_knx(19.40)),
@@ -1053,7 +1053,7 @@ class TestClimate:
     async def test_process_controller_status_wrong_payload(self):
         """Test process wrong telegram for controller status (wrong payload type)."""
         xknx = XKNX()
-        updated_cb = AsyncMock()
+        updated_cb = Mock()
         climate_mode = ClimateMode(
             xknx,
             "TestClimate",
@@ -1073,7 +1073,7 @@ class TestClimate:
     async def test_process_controller_status_payload_invalid_length(self):
         """Test process wrong telegram for controller status (wrong payload length)."""
         xknx = XKNX()
-        updated_cb = AsyncMock()
+        updated_cb = Mock()
         climate_mode = ClimateMode(
             xknx,
             "TestClimate",
@@ -1093,7 +1093,7 @@ class TestClimate:
     async def test_process_operation_mode_wrong_payload(self):
         """Test process wrong telegram for operation mode (wrong payload type)."""
         xknx = XKNX()
-        updated_cb = AsyncMock()
+        updated_cb = Mock()
         climate_mode = ClimateMode(
             xknx,
             "TestClimate",
@@ -1113,7 +1113,7 @@ class TestClimate:
     async def test_process_operation_mode_payload_invalid_length(self):
         """Test process wrong telegram for operation mode (wrong payload length)."""
         xknx = XKNX()
-        updated_cb = AsyncMock()
+        updated_cb = Mock()
         climate_mode = ClimateMode(
             xknx,
             "TestClimate",
@@ -1135,7 +1135,7 @@ class TestClimate:
 
         xknx = XKNX()
         climate = Climate(xknx, "TestClimate", group_address_temperature="1/2/3")
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         climate.register_device_updated_cb(after_update_callback)
 
         telegram = Telegram(
diff --git a/test/devices_tests/cover_test.py b/test/devices_tests/cover_test.py
index fdb639ba..0c1b755e 100644
--- a/test/devices_tests/cover_test.py
+++ b/test/devices_tests/cover_test.py
@@ -1,6 +1,6 @@
 """Unit test for Cover objects."""
 
-from unittest.mock import AsyncMock, patch
+from unittest.mock import AsyncMock, Mock, patch
 
 from xknx import XKNX
 from xknx.devices import Cover
@@ -419,7 +419,7 @@ class TestCover:
         # Set cover tilt to a dummy start value, since otherwise we cannot
         # determine later on a tilt direction and without it, stopping the
         # til process has no effect.
-        await cover_short_stop.angle.process(
+        cover_short_stop.angle.process(
             Telegram(
                 destination_address=GroupAddress("1/2/5"),
                 payload=GroupValueWrite(DPTArray(0xAA)),
@@ -824,7 +824,7 @@ class TestCover:
             group_address_angle_state="1/2/7",
         )
 
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
 
         cover.register_device_updated_cb(after_update_callback)
         for address, payload, _feature in [
@@ -973,7 +973,7 @@ class TestCover:
     async def test_periodic_update(self, time_travel):
         """Test periodic update functionality."""
         xknx = XKNX()
-        callback_mock = AsyncMock()
+        callback_mock = Mock()
         cover = Cover(
             xknx,
             "TestCoverPeriodicUpdate",
@@ -992,9 +992,8 @@ class TestCover:
                 GroupAddress("1/2/4"), payload=GroupValueWrite(DPTArray(0))
             )
             await cover.process(telegram)
-            assert (
-                callback_mock.call_count == 2
-            )  # 1 additional form _stop_position_update because previous state was None
+            await time_travel(0)
+            assert callback_mock.call_count == 1
             callback_mock.reset_mock()
             # move to 50%
             telegram = Telegram(
diff --git a/test/devices_tests/device_test.py b/test/devices_tests/device_test.py
index 413477af..1a88b233 100644
--- a/test/devices_tests/device_test.py
+++ b/test/devices_tests/device_test.py
@@ -1,6 +1,6 @@
 """Unit test for Switch objects."""
 
-from unittest.mock import AsyncMock, patch
+from unittest.mock import AsyncMock, Mock, patch
 
 from xknx import XKNX
 from xknx.devices import Device, Sensor
@@ -13,33 +13,33 @@ from xknx.telegram.apci import GroupValueRead, GroupValueResponse, GroupValueWri
 class TestDevice:
     """Test class for Switch object."""
 
-    async def test_device_updated_cb(self):
+    def test_device_updated_cb(self):
         """Test device updated cb is added to the device."""
         xknx = XKNX()
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         device = Device(xknx, "TestDevice", device_updated_cb=after_update_callback)
 
-        await device.after_update()
+        device.after_update()
         after_update_callback.assert_called_with(device)
 
-    async def test_process_callback(self):
+    def test_process_callback(self):
         """Test process / reading telegrams from telegram queue. Test if callback was called."""
         xknx = XKNX()
         device = Device(xknx, "TestDevice")
-        after_update_callback1 = AsyncMock()
-        after_update_callback2 = AsyncMock()
+        after_update_callback1 = Mock()
+        after_update_callback2 = Mock()
         device.register_device_updated_cb(after_update_callback1)
         device.register_device_updated_cb(after_update_callback2)
 
         # Triggering first time. Both have to be called
-        await device.after_update()
+        device.after_update()
         after_update_callback1.assert_called_with(device)
         after_update_callback2.assert_called_with(device)
         after_update_callback1.reset_mock()
         after_update_callback2.reset_mock()
 
         # Triggering 2nd time. Both have to be called
-        await device.after_update()
+        device.after_update()
         after_update_callback1.assert_called_with(device)
         after_update_callback2.assert_called_with(device)
         after_update_callback1.reset_mock()
@@ -47,7 +47,7 @@ class TestDevice:
 
         # Unregistering first callback
         device.unregister_device_updated_cb(after_update_callback1)
-        await device.after_update()
+        device.after_update()
         after_update_callback1.assert_not_called()
         after_update_callback2.assert_called_with(device)
         after_update_callback1.reset_mock()
@@ -55,24 +55,24 @@ class TestDevice:
 
         # Unregistering second callback
         device.unregister_device_updated_cb(after_update_callback2)
-        await device.after_update()
+        device.after_update()
         after_update_callback1.assert_not_called()
         after_update_callback2.assert_not_called()
 
     @patch("logging.Logger.exception")
-    async def test_bad_callback(self, logging_exception_mock):
+    def test_bad_callback(self, logging_exception_mock):
         """Test handling callback raising an exception."""
         xknx = XKNX()
         device = Device(xknx, "TestDevice")
-        good_callback_1 = AsyncMock()
-        bad_callback = AsyncMock(side_effect=Exception("Boom"))
-        good_callback_2 = AsyncMock()
+        good_callback_1 = Mock()
+        bad_callback = Mock(side_effect=Exception("Boom"))
+        good_callback_2 = Mock()
 
         device.register_device_updated_cb(good_callback_1)
         device.register_device_updated_cb(bad_callback)
         device.register_device_updated_cb(good_callback_2)
 
-        await device.after_update()
+        device.after_update()
         good_callback_1.assert_called_with(device)
         bad_callback.assert_called_with(device)
         good_callback_2.assert_called_with(device)
diff --git a/test/devices_tests/devices_test.py b/test/devices_tests/devices_test.py
index f98b6c55..25d233dd 100644
--- a/test/devices_tests/devices_test.py
+++ b/test/devices_tests/devices_test.py
@@ -1,6 +1,6 @@
 """Unit test for devices container within XKNX."""
 
-from unittest.mock import AsyncMock, patch
+from unittest.mock import AsyncMock, Mock, patch
 
 import pytest
 
@@ -169,7 +169,7 @@ class TestDevices:
     # TEST CALLBACK
     #
     @patch.multiple(Device, __abstractmethods__=set())
-    async def test_device_updated_callback(self):
+    def test_device_updated_callback(self):
         """Test if device updated callback is called correctly if device was updated."""
         xknx = XKNX()
         device1 = Device(xknx, "TestDevice1")
@@ -177,43 +177,43 @@ class TestDevices:
         xknx.devices.async_add(device1)
         xknx.devices.async_add(device2)
 
-        async_after_update_callback1 = AsyncMock()
-        async_after_update_callback2 = AsyncMock()
+        after_update_callback1 = Mock()
+        after_update_callback2 = Mock()
 
         # Registering both callbacks
-        xknx.devices.register_device_updated_cb(async_after_update_callback1)
-        xknx.devices.register_device_updated_cb(async_after_update_callback2)
+        xknx.devices.register_device_updated_cb(after_update_callback1)
+        xknx.devices.register_device_updated_cb(after_update_callback2)
 
         # Triggering first device. Both callbacks to be called
-        await device1.after_update()
-        async_after_update_callback1.assert_called_with(device1)
-        async_after_update_callback2.assert_called_with(device1)
-        async_after_update_callback1.reset_mock()
-        async_after_update_callback2.reset_mock()
+        device1.after_update()
+        after_update_callback1.assert_called_with(device1)
+        after_update_callback2.assert_called_with(device1)
+        after_update_callback1.reset_mock()
+        after_update_callback2.reset_mock()
 
         # Triggering 2nd device. Both callbacks have to be called
-        await device2.after_update()
-        async_after_update_callback1.assert_called_with(device2)
-        async_after_update_callback2.assert_called_with(device2)
-        async_after_update_callback1.reset_mock()
-        async_after_update_callback2.reset_mock()
+        device2.after_update()
+        after_update_callback1.assert_called_with(device2)
+        after_update_callback2.assert_called_with(device2)
+        after_update_callback1.reset_mock()
+        after_update_callback2.reset_mock()
 
         # Unregistering first callback
-        xknx.devices.unregister_device_updated_cb(async_after_update_callback1)
+        xknx.devices.unregister_device_updated_cb(after_update_callback1)
 
         # Triggering first device. Only second callback has to be called
-        await device1.after_update()
-        async_after_update_callback1.assert_not_called()
-        async_after_update_callback2.assert_called_with(device1)
-        async_after_update_callback1.reset_mock()
-        async_after_update_callback2.reset_mock()
+        device1.after_update()
+        after_update_callback1.assert_not_called()
+        after_update_callback2.assert_called_with(device1)
+        after_update_callback1.reset_mock()
+        after_update_callback2.reset_mock()
 
         # Unregistering second callback
-        xknx.devices.unregister_device_updated_cb(async_after_update_callback2)
+        xknx.devices.unregister_device_updated_cb(after_update_callback2)
 
         # Triggering second device. No callback should be called
-        await device2.after_update()
-        async_after_update_callback1.assert_not_called()
-        async_after_update_callback2.assert_not_called()
-        async_after_update_callback1.reset_mock()
-        async_after_update_callback2.reset_mock()
+        device2.after_update()
+        after_update_callback1.assert_not_called()
+        after_update_callback2.assert_not_called()
+        after_update_callback1.reset_mock()
+        after_update_callback2.reset_mock()
diff --git a/test/devices_tests/expose_sensor_test.py b/test/devices_tests/expose_sensor_test.py
index ee145e66..33289a22 100644
--- a/test/devices_tests/expose_sensor_test.py
+++ b/test/devices_tests/expose_sensor_test.py
@@ -1,6 +1,6 @@
 """Unit test for Sensor objects."""
 
-from unittest.mock import AsyncMock, call
+from unittest.mock import AsyncMock, Mock, call
 
 from xknx import XKNX
 from xknx.devices import ExposeSensor
@@ -206,7 +206,7 @@ class TestExposeSensor:
         """Test setting value. Test if callback is called."""
 
         xknx = XKNX()
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         expose_sensor = ExposeSensor(
             xknx, "TestSensor", group_address="1/2/3", value_type="temperature"
         )
diff --git a/test/devices_tests/fan_test.py b/test/devices_tests/fan_test.py
index 27216099..03e7f34f 100644
--- a/test/devices_tests/fan_test.py
+++ b/test/devices_tests/fan_test.py
@@ -1,6 +1,6 @@
 """Unit test for Fan objects."""
 
-from unittest.mock import AsyncMock, patch
+from unittest.mock import Mock, patch
 
 from xknx import XKNX
 from xknx.devices import Fan
@@ -272,7 +272,7 @@ class TestFan:
     async def test_process_speed_wrong_payload(self):
         """Test process wrong telegrams. (wrong payload type)."""
         xknx = XKNX()
-        cb_mock = AsyncMock()
+        cb_mock = Mock()
         fan = Fan(
             xknx, name="TestFan", group_address_speed="1/2/3", device_updated_cb=cb_mock
         )
@@ -372,7 +372,7 @@ class TestFan:
     async def test_process_fan_payload_invalid_length(self):
         """Test process wrong telegrams. (wrong payload length)."""
         xknx = XKNX()
-        cb_mock = AsyncMock()
+        cb_mock = Mock()
         fan = Fan(
             xknx, name="TestFan", group_address_speed="1/2/3", device_updated_cb=cb_mock
         )
diff --git a/test/devices_tests/light_test.py b/test/devices_tests/light_test.py
index 9b09c557..5964057b 100644
--- a/test/devices_tests/light_test.py
+++ b/test/devices_tests/light_test.py
@@ -1,6 +1,6 @@
 """Unit test for Light objects."""
 
-from unittest.mock import AsyncMock, patch
+from unittest.mock import Mock, patch
 
 from xknx import XKNX
 from xknx.devices import Light
@@ -1310,7 +1310,7 @@ class TestLight:
         )
         xknx.devices.async_add(light)
 
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         light.register_device_updated_cb(after_update_callback)
 
         telegram = Telegram(
@@ -1343,7 +1343,7 @@ class TestLight:
     async def test_process_dimm_wrong_payload(self):
         """Test process wrong telegrams. (wrong payload type)."""
         xknx = XKNX()
-        cb_mock = AsyncMock()
+        cb_mock = Mock()
         light = Light(
             xknx,
             name="TestLight",
@@ -1365,7 +1365,7 @@ class TestLight:
     async def test_process_dimm_payload_invalid_length(self):
         """Test process wrong telegrams. (wrong payload length)."""
         xknx = XKNX()
-        cb_mock = AsyncMock()
+        cb_mock = Mock()
         light = Light(
             xknx,
             name="TestLight",
@@ -1501,8 +1501,8 @@ class TestLight:
     async def test_process_individual_color_debouncer(self, time_travel):
         """Test the debouncer for individual color lights."""
         xknx = XKNX()
-        rgb_callback = AsyncMock()
-        rgbw_callback = AsyncMock()
+        rgb_callback = Mock()
+        rgbw_callback = Mock()
 
         rgb_light = Light(
             xknx,
@@ -1694,7 +1694,7 @@ class TestLight:
     async def test_process_tunable_white_wrong_payload(self):
         """Test process wrong telegrams. (wrong payload type)."""
         xknx = XKNX()
-        cb_mock = AsyncMock()
+        cb_mock = Mock()
         light = Light(
             xknx,
             name="TestLight",
@@ -1714,7 +1714,7 @@ class TestLight:
     async def test_process_tunable_white_payload_invalid_length(self):
         """Test process wrong telegrams. (wrong payload length)."""
         xknx = XKNX()
-        cb_mock = AsyncMock()
+        cb_mock = Mock()
         light = Light(
             xknx,
             name="TestLight",
@@ -1759,7 +1759,7 @@ class TestLight:
     async def test_process_color_temperature_wrong_payload(self):
         """Test process wrong telegrams. (wrong payload type)."""
         xknx = XKNX()
-        cb_mock = AsyncMock()
+        cb_mock = Mock()
         light = Light(
             xknx,
             name="TestLight",
@@ -1779,7 +1779,7 @@ class TestLight:
     async def test_process_color_temperature_payload_invalid_length(self):
         """Test process wrong telegrams. (wrong payload length)."""
         xknx = XKNX()
-        cb_mock = AsyncMock()
+        cb_mock = Mock()
         light = Light(
             xknx,
             name="TestLight",
diff --git a/test/devices_tests/notification_test.py b/test/devices_tests/notification_test.py
index 38d661b6..2b53a139 100644
--- a/test/devices_tests/notification_test.py
+++ b/test/devices_tests/notification_test.py
@@ -1,6 +1,6 @@
 """Unit test for Notification objects."""
 
-from unittest.mock import AsyncMock, patch
+from unittest.mock import Mock, patch
 
 from xknx import XKNX
 from xknx.devices import Notification
@@ -54,7 +54,7 @@ class TestNotification:
 
         xknx = XKNX()
         notification = Notification(xknx, "Warning", group_address="1/2/3")
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         notification.register_device_updated_cb(after_update_callback)
 
         telegram_set = Telegram(
@@ -67,9 +67,12 @@ class TestNotification:
     async def test_process_payload_invalid_length(self):
         """Test process wrong telegram (wrong payload length)."""
         xknx = XKNX()
-        cb_mock = AsyncMock()
+        after_update_callback = Mock()
         notification = Notification(
-            xknx, "Warning", group_address="1/2/3", device_updated_cb=cb_mock
+            xknx,
+            "Warning",
+            group_address="1/2/3",
+            device_updated_cb=after_update_callback,
         )
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
@@ -78,14 +81,17 @@ class TestNotification:
         with patch("logging.Logger.warning") as log_mock:
             await notification.process(telegram)
             log_mock.assert_called_once()
-            cb_mock.assert_not_called()
+            after_update_callback.assert_not_called()
 
     async def test_process_wrong_payload(self):
         """Test process wrong telegram (wrong payload type)."""
         xknx = XKNX()
-        cb_mock = AsyncMock()
+        after_update_callback = Mock()
         notification = Notification(
-            xknx, "Warning", group_address="1/2/3", device_updated_cb=cb_mock
+            xknx,
+            "Warning",
+            group_address="1/2/3",
+            device_updated_cb=after_update_callback,
         )
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
@@ -94,7 +100,7 @@ class TestNotification:
         with patch("logging.Logger.warning") as log_mock:
             await notification.process(telegram)
             log_mock.assert_called_once()
-            cb_mock.assert_not_called()
+            after_update_callback.assert_not_called()
 
     #
     # TEST RESPOND
diff --git a/test/devices_tests/numeric_value_test.py b/test/devices_tests/numeric_value_test.py
index 83cbf5cc..a74c988a 100644
--- a/test/devices_tests/numeric_value_test.py
+++ b/test/devices_tests/numeric_value_test.py
@@ -1,6 +1,6 @@
 """Unit test for NumericValue objects."""
 
-from unittest.mock import AsyncMock
+from unittest.mock import Mock
 
 import pytest
 
@@ -247,7 +247,7 @@ class TestNumericValue:
         sensor = NumericValue(
             xknx, "TestSensor", group_address="1/2/3", value_type="temperature"
         )
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         sensor.register_device_updated_cb(after_update_callback)
 
         telegram = Telegram(
@@ -273,7 +273,7 @@ class TestNumericValue:
             value_type="temperature",
             always_callback=True,
         )
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         sensor.register_device_updated_cb(after_update_callback)
 
         telegram = Telegram(
@@ -292,7 +292,7 @@ class TestNumericValue:
         """Test setting value. Test if callback is called."""
 
         xknx = XKNX()
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         num_value = NumericValue(
             xknx, "TestSensor", group_address="1/2/3", value_type="temperature"
         )
diff --git a/test/devices_tests/raw_value_test.py b/test/devices_tests/raw_value_test.py
index 06f748d6..bf6053a6 100644
--- a/test/devices_tests/raw_value_test.py
+++ b/test/devices_tests/raw_value_test.py
@@ -1,6 +1,6 @@
 """Unit test for RawValue objects."""
 
-from unittest.mock import AsyncMock
+from unittest.mock import Mock
 
 import pytest
 
@@ -154,7 +154,7 @@ class TestRawValue:
             2,
             group_address="1/2/3",
         )
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         sensor.register_device_updated_cb(after_update_callback)
 
         telegram = Telegram(
@@ -180,7 +180,7 @@ class TestRawValue:
             group_address="1/2/3",
             always_callback=True,
         )
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         sensor.register_device_updated_cb(after_update_callback)
 
         telegram = Telegram(
diff --git a/test/devices_tests/sensor_test.py b/test/devices_tests/sensor_test.py
index 08e37e13..518eec40 100644
--- a/test/devices_tests/sensor_test.py
+++ b/test/devices_tests/sensor_test.py
@@ -1,6 +1,6 @@
 """Unit test for Sensor objects."""
 
-from unittest.mock import AsyncMock
+from unittest.mock import Mock
 
 import pytest
 
@@ -703,7 +703,7 @@ class TestSensor:
             always_callback=False,
             value_type="volume_liquid_litre",
         )
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         sensor.register_device_updated_cb(after_update_callback)
         payload = DPTArray((0x00, 0x00, 0x01, 0x00))
         #  set initial payload of sensor
@@ -786,7 +786,7 @@ class TestSensor:
         sensor = Sensor(
             xknx, "TestSensor", group_address_state="1/2/3", value_type="temperature"
         )
-        after_update_callback = AsyncMock()
+        after_update_callback = Mock()
         sensor.register_device_updated_cb(after_update_callback)
 
         telegram = Telegram(
diff --git a/test/devices_tests/switch_test.py b/test/devices_tests/switch_test.py
index 622884be..82cd6185 100644
--- a/test/devices_tests/switch_test.py
+++ b/test/devices_tests/switch_test.py
@@ -1,6 +1,6 @@
 """Unit test for Switch objects."""
 
-from unittest.mock import AsyncMock, Mock
+from unittest.mock import Mock
 
 from xknx import XKNX
 from xknx.devices import Switch
@@ -47,7 +47,7 @@ class TestSwitch:
     async def test_process(self):
         """Test process / reading telegrams from telegram queue. Test if device was updated."""
         xknx = XKNX()
-        callback_mock = AsyncMock()
+        callback_mock = Mock()
 
         switch1 = Switch(
             xknx, "TestOutlet", group_address="1/2/3", device_updated_cb=callback_mock
@@ -89,7 +89,7 @@ class TestSwitch:
     async def test_process_state(self):
         """Test process / reading telegrams from telegram queue. Test if device was updated."""
         xknx = XKNX()
-        callback_mock = AsyncMock()
+        callback_mock = Mock()
 
         switch1 = Switch(
             xknx,
@@ -222,12 +222,7 @@ class TestSwitch:
         switch = Switch(xknx, "TestOutlet", group_address="1/2/3")
 
         after_update_callback = Mock()
-
-        async def async_after_update_callback(device):
-            """Async callback."""
-            after_update_callback(device)
-
-        switch.register_device_updated_cb(async_after_update_callback)
+        switch.register_device_updated_cb(after_update_callback)
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
@@ -380,7 +375,7 @@ class TestSwitch:
     async def test_process_passive(self):
         """Test process / reading telegrams from telegram queue. Test if device was updated."""
         xknx = XKNX()
-        callback_mock = AsyncMock()
+        callback_mock = Mock()
 
         switch1 = Switch(
             xknx,
diff --git a/test/remote_value_tests/remote_value_1count_test.py b/test/remote_value_tests/remote_value_1count_test.py
index d9da2604..22b181a1 100644
--- a/test/remote_value_tests/remote_value_1count_test.py
+++ b/test/remote_value_tests/remote_value_1count_test.py
@@ -26,14 +26,14 @@ class TestRemoteValue1Count:
         """Test setting value."""
         xknx = XKNX()
         remote_value = RemoteValue1Count(xknx, group_address=GroupAddress("1/2/3"))
-        await remote_value.set(100)
+        remote_value.set(100)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64,))),
         )
-        await remote_value.set(101)
+        remote_value.set(101)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -41,7 +41,7 @@ class TestRemoteValue1Count:
             payload=GroupValueWrite(DPTArray((0x65,))),
         )
 
-    async def test_process(self):
+    def test_process(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValue1Count(xknx, group_address=GroupAddress("1/2/3"))
@@ -49,10 +49,10 @@ class TestRemoteValue1Count:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64,))),
         )
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == 100
 
-    async def test_to_process_error(self):
+    def test_to_process_error(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValue1Count(xknx, group_address=GroupAddress("1/2/3"))
@@ -61,12 +61,12 @@ class TestRemoteValue1Count:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65))),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
diff --git a/test/remote_value_tests/remote_value_climate_mode_test.py b/test/remote_value_tests/remote_value_climate_mode_test.py
index f1b58a6c..1177b13f 100644
--- a/test/remote_value_tests/remote_value_climate_mode_test.py
+++ b/test/remote_value_tests/remote_value_climate_mode_test.py
@@ -176,14 +176,14 @@ class TestRemoteValueOperationMode:
             group_address=GroupAddress("1/2/3"),
             climate_mode_type=RemoteValueOperationMode.ClimateModeType.HVAC_MODE,
         )
-        await remote_value.set(HVACOperationMode.NIGHT)
+        remote_value.set(HVACOperationMode.NIGHT)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x03,))),
         )
-        await remote_value.set(HVACOperationMode.FROST_PROTECTION)
+        remote_value.set(HVACOperationMode.FROST_PROTECTION)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -197,14 +197,14 @@ class TestRemoteValueOperationMode:
         remote_value = RemoteValueControllerMode(
             xknx, group_address=GroupAddress("1/2/3")
         )
-        await remote_value.set(HVACControllerMode.COOL)
+        remote_value.set(HVACControllerMode.COOL)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x03,))),
         )
-        await remote_value.set(HVACControllerMode.NIGHT_PURGE)
+        remote_value.set(HVACControllerMode.NIGHT_PURGE)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -220,14 +220,14 @@ class TestRemoteValueOperationMode:
             group_address=GroupAddress("1/2/3"),
             operation_mode=HVACOperationMode.STANDBY,
         )
-        await remote_value.set(HVACOperationMode.STANDBY)
+        remote_value.set(HVACOperationMode.STANDBY)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(True)),
         )
-        await remote_value.set(HVACOperationMode.FROST_PROTECTION)
+        remote_value.set(HVACOperationMode.FROST_PROTECTION)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -235,7 +235,7 @@ class TestRemoteValueOperationMode:
             payload=GroupValueWrite(DPTBinary(False)),
         )
 
-    async def test_process_operation_mode(self):
+    def test_process_operation_mode(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueOperationMode(
@@ -247,10 +247,10 @@ class TestRemoteValueOperationMode:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x00,))),
         )
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == HVACOperationMode.AUTO
 
-    async def test_process_controller_mode(self):
+    def test_process_controller_mode(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueControllerMode(
@@ -260,10 +260,10 @@ class TestRemoteValueOperationMode:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x00,))),
         )
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == HVACControllerMode.AUTO
 
-    async def test_process_binary(self):
+    def test_process_binary(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueBinaryOperationMode(
@@ -275,10 +275,10 @@ class TestRemoteValueOperationMode:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(True)),
         )
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == HVACOperationMode.FROST_PROTECTION
 
-    async def test_to_process_error_operation_mode(self):
+    def test_to_process_error_operation_mode(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueOperationMode(
@@ -291,17 +291,17 @@ class TestRemoteValueOperationMode:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65))),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
 
-    async def test_to_process_error_binary_operation_mode(self):
+    def test_to_process_error_binary_operation_mode(self):
         """Test processing invalid payload."""
         xknx = XKNX()
         remote_value = RemoteValueBinaryOperationMode(
@@ -315,9 +315,9 @@ class TestRemoteValueOperationMode:
                 DPTArray((1,)),
             ),
         )
-        assert await remote_value.process(telegram=invalid_telegram) is False
+        assert remote_value.process(telegram=invalid_telegram) is False
 
-    async def test_to_process_error_controller_mode(self):
+    def test_to_process_error_controller_mode(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueControllerMode(
@@ -328,17 +328,17 @@ class TestRemoteValueOperationMode:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65))),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
 
-    async def test_to_process_error_heat_cool(self):
+    def test_to_process_error_heat_cool(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueBinaryHeatCool(
@@ -351,12 +351,12 @@ class TestRemoteValueOperationMode:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x01,))),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65))),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
diff --git a/test/remote_value_tests/remote_value_color_rgb_test.py b/test/remote_value_tests/remote_value_color_rgb_test.py
index 48509fc2..580e6e84 100644
--- a/test/remote_value_tests/remote_value_color_rgb_test.py
+++ b/test/remote_value_tests/remote_value_color_rgb_test.py
@@ -48,14 +48,14 @@ class TestRemoteValueColorRGB:
         """Test setting value."""
         xknx = XKNX()
         remote_value = RemoteValueColorRGB(xknx, group_address=GroupAddress("1/2/3"))
-        await remote_value.set(RGBColor(100, 101, 102))
+        remote_value.set(RGBColor(100, 101, 102))
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x66))),
         )
-        await remote_value.set(RGBColor(100, 101, 104))
+        remote_value.set(RGBColor(100, 101, 104))
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -63,7 +63,7 @@ class TestRemoteValueColorRGB:
             payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x68))),
         )
 
-    async def test_process(self):
+    def test_process(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueColorRGB(xknx, group_address=GroupAddress("1/2/3"))
@@ -71,10 +71,10 @@ class TestRemoteValueColorRGB:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x66))),
         )
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == RGBColor(100, 101, 102)
 
-    async def test_to_process_error(self):
+    def test_to_process_error(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueColorRGB(xknx, group_address=GroupAddress("1/2/3"))
@@ -83,12 +83,12 @@ class TestRemoteValueColorRGB:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x66, 0x67))),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
diff --git a/test/remote_value_tests/remote_value_color_rgbw_test.py b/test/remote_value_tests/remote_value_color_rgbw_test.py
index 70e04970..a149f43c 100644
--- a/test/remote_value_tests/remote_value_color_rgbw_test.py
+++ b/test/remote_value_tests/remote_value_color_rgbw_test.py
@@ -53,14 +53,14 @@ class TestRemoteValueColorRGBW:
         """Test setting value."""
         xknx = XKNX()
         remote_value = RemoteValueColorRGBW(xknx, group_address=GroupAddress("1/2/3"))
-        await remote_value.set(RGBWColor(100, 101, 102, 103))
+        remote_value.set(RGBWColor(100, 101, 102, 103))
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x66, 0x67, 0x00, 0x0F))),
         )
-        await remote_value.set(RGBWColor(100, 101, 104, 105))
+        remote_value.set(RGBWColor(100, 101, 104, 105))
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -68,7 +68,7 @@ class TestRemoteValueColorRGBW:
             payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x68, 0x69, 0x00, 0x0F))),
         )
 
-    async def test_process(self):
+    def test_process(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueColorRGBW(xknx, group_address=GroupAddress("1/2/3"))
@@ -76,10 +76,10 @@ class TestRemoteValueColorRGBW:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x66, 0x67, 0x00, 0x0F))),
         )
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == RGBWColor(100, 101, 102, 103)
 
-    async def test_to_process_error(self):
+    def test_to_process_error(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueColorRGBW(xknx, group_address=GroupAddress("1/2/3"))
@@ -88,13 +88,13 @@ class TestRemoteValueColorRGBW:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x66))),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
@@ -102,6 +102,6 @@ class TestRemoteValueColorRGBW:
                 DPTArray((0x00, 0x00, 0x0F, 0x64, 0x65, 0x66, 0x67))
             ),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
diff --git a/test/remote_value_tests/remote_value_color_xyy_test.py b/test/remote_value_tests/remote_value_color_xyy_test.py
index cbd09ba7..3c5a4189 100644
--- a/test/remote_value_tests/remote_value_color_xyy_test.py
+++ b/test/remote_value_tests/remote_value_color_xyy_test.py
@@ -54,14 +54,14 @@ class TestRemoteValueColorXYY:
         """Test setting value."""
         xknx = XKNX()
         remote_value = RemoteValueColorXYY(xknx, group_address=GroupAddress("1/2/3"))
-        await remote_value.set(XYYColor((1, 0.9), 102))
+        remote_value.set(XYYColor((1, 0.9), 102))
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0xFF, 0xFF, 0xE6, 0x66, 0x66, 0x03))),
         )
-        await remote_value.set(XYYColor((1, 0.9), 255))
+        remote_value.set(XYYColor((1, 0.9), 255))
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -69,7 +69,7 @@ class TestRemoteValueColorXYY:
             payload=GroupValueWrite(DPTArray((0xFF, 0xFF, 0xE6, 0x66, 0xFF, 0x03))),
         )
 
-    async def test_process(self):
+    def test_process(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueColorXYY(xknx, group_address=GroupAddress("1/2/3"))
@@ -77,10 +77,10 @@ class TestRemoteValueColorXYY:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0xFF, 0xFF, 0x66, 0x66, 0xFA, 0x03))),
         )
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == XYYColor((1, 0.4), 250)
 
-    async def test_to_process_error(self):
+    def test_to_process_error(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueColorXYY(xknx, group_address=GroupAddress("1/2/3"))
@@ -89,12 +89,12 @@ class TestRemoteValueColorXYY:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65, 0x66, 0x67))),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
diff --git a/test/remote_value_tests/remote_value_control_test.py b/test/remote_value_tests/remote_value_control_test.py
index ba09f6ca..06719d05 100644
--- a/test/remote_value_tests/remote_value_control_test.py
+++ b/test/remote_value_tests/remote_value_control_test.py
@@ -25,7 +25,7 @@ class TestRemoteValueControl:
         remote_value = RemoteValueControl(
             xknx, group_address=GroupAddress("1/2/3"), value_type="stepwise"
         )
-        await remote_value.set(25)
+        remote_value.set(25)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -33,7 +33,7 @@ class TestRemoteValueControl:
             payload=GroupValueWrite(DPTBinary(0xB)),
         )
 
-    async def test_process(self):
+    def test_process(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueControl(
@@ -44,10 +44,10 @@ class TestRemoteValueControl:
             payload=GroupValueWrite(DPTBinary(0xB)),
         )
         assert remote_value.value is None
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == 25
 
-    async def test_to_process_error(self):
+    def test_to_process_error(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueControl(
@@ -58,12 +58,12 @@ class TestRemoteValueControl:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray(0x01)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(0x10)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
diff --git a/test/remote_value_tests/remote_value_dpt_value_1_ucount_test.py b/test/remote_value_tests/remote_value_dpt_value_1_ucount_test.py
index 085b6da7..2c1754f5 100644
--- a/test/remote_value_tests/remote_value_dpt_value_1_ucount_test.py
+++ b/test/remote_value_tests/remote_value_dpt_value_1_ucount_test.py
@@ -40,14 +40,14 @@ class TestRemoteValueDptValue1Ucount:
         remote_value = RemoteValueDptValue1Ucount(
             xknx, group_address=GroupAddress("1/2/3")
         )
-        await remote_value.set(10)
+        remote_value.set(10)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x0A,))),
         )
-        await remote_value.set(11)
+        remote_value.set(11)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -55,7 +55,7 @@ class TestRemoteValueDptValue1Ucount:
             payload=GroupValueWrite(DPTArray((0x0B,))),
         )
 
-    async def test_process(self):
+    def test_process(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueDptValue1Ucount(
@@ -65,10 +65,10 @@ class TestRemoteValueDptValue1Ucount:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x0A,))),
         )
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == 10
 
-    async def test_to_process_error(self):
+    def test_to_process_error(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueDptValue1Ucount(
@@ -79,12 +79,12 @@ class TestRemoteValueDptValue1Ucount:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65))),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
diff --git a/test/remote_value_tests/remote_value_raw_test.py b/test/remote_value_tests/remote_value_raw_test.py
index 6e4e1ff5..b45f6c6a 100644
--- a/test/remote_value_tests/remote_value_raw_test.py
+++ b/test/remote_value_tests/remote_value_raw_test.py
@@ -47,14 +47,14 @@ class TestRemoteValueRaw:
         rv_1 = RemoteValueRaw(xknx, payload_length=1, group_address="1/2/3")
         rv_2 = RemoteValueRaw(xknx, payload_length=2, group_address="1/2/3")
 
-        await rv_0.set(0)
+        rv_0.set(0)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(False)),
         )
-        await rv_0.set(63)
+        rv_0.set(63)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -62,14 +62,14 @@ class TestRemoteValueRaw:
             payload=GroupValueWrite(DPTBinary(0x3F)),
         )
 
-        await rv_1.set(0)
+        rv_1.set(0)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x00,))),
         )
-        await rv_1.set(63)
+        rv_1.set(63)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -77,14 +77,14 @@ class TestRemoteValueRaw:
             payload=GroupValueWrite(DPTArray((0x3F,))),
         )
 
-        await rv_2.set(0)
+        rv_2.set(0)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x00, 0x00))),
         )
-        await rv_2.set(63)
+        rv_2.set(63)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -92,7 +92,7 @@ class TestRemoteValueRaw:
             payload=GroupValueWrite(DPTArray((0x00, 0x3F))),
         )
 
-    async def test_process(self):
+    def test_process(self):
         """Test process telegram."""
         xknx = XKNX()
         rv_0 = RemoteValueRaw(xknx, payload_length=0, group_address="1/0/0")
@@ -103,24 +103,24 @@ class TestRemoteValueRaw:
             destination_address=GroupAddress("1/0/0"),
             payload=GroupValueWrite(DPTBinary(0)),
         )
-        await rv_0.process(telegram)
+        rv_0.process(telegram)
         assert rv_0.value == 0
 
         telegram = Telegram(
             destination_address=GroupAddress("1/1/1"),
             payload=GroupValueWrite(DPTArray((0x64,))),
         )
-        await rv_1.process(telegram)
+        rv_1.process(telegram)
         assert rv_1.value == 100
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/2"),
             payload=GroupValueWrite(DPTArray((0x12, 0x34))),
         )
-        await rv_2.process(telegram)
+        rv_2.process(telegram)
         assert rv_2.value == 4660
 
-    async def test_to_process_error(self):
+    def test_to_process_error(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         rv_0 = RemoteValueRaw(xknx, payload_length=0, group_address="1/0/0")
@@ -131,39 +131,39 @@ class TestRemoteValueRaw:
             destination_address=GroupAddress("1/0/0"),
             payload=GroupValueWrite(DPTArray((0x01,))),
         )
-        assert await rv_0.process(telegram) is False
+        assert rv_0.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/0/0"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65))),
         )
-        assert await rv_0.process(telegram) is False
+        assert rv_0.process(telegram) is False
         assert rv_0.value is None
 
         telegram = Telegram(
             destination_address=GroupAddress("1/1/1"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        assert await rv_1.process(telegram) is False
+        assert rv_1.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/1/1"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65))),
         )
-        assert await rv_1.process(telegram) is False
+        assert rv_1.process(telegram) is False
         assert rv_1.value is None
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/2"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        assert await rv_2.process(telegram) is False
+        assert rv_2.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/2"),
             payload=GroupValueWrite(DPTArray((0x64,))),
         )
-        assert await rv_2.process(telegram) is False
+        assert rv_2.process(telegram) is False
         assert rv_2.value is None
 
     def test_to_knx_error(self):
diff --git a/test/remote_value_tests/remote_value_scene_number_test.py b/test/remote_value_tests/remote_value_scene_number_test.py
index a27be646..d62fc301 100644
--- a/test/remote_value_tests/remote_value_scene_number_test.py
+++ b/test/remote_value_tests/remote_value_scene_number_test.py
@@ -38,14 +38,14 @@ class TestRemoteValueSceneNumber:
         """Test setting value."""
         xknx = XKNX()
         remote_value = RemoteValueSceneNumber(xknx, group_address=GroupAddress("1/2/3"))
-        await remote_value.set(11)
+        remote_value.set(11)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x0A,))),
         )
-        await remote_value.set(12)
+        remote_value.set(12)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -53,7 +53,7 @@ class TestRemoteValueSceneNumber:
             payload=GroupValueWrite(DPTArray((0x0B,))),
         )
 
-    async def test_process(self):
+    def test_process(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueSceneNumber(xknx, group_address=GroupAddress("1/2/3"))
@@ -61,10 +61,10 @@ class TestRemoteValueSceneNumber:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x0A,))),
         )
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == 11
 
-    async def test_to_process_error(self):
+    def test_to_process_error(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueSceneNumber(xknx, group_address=GroupAddress("1/2/3"))
@@ -73,12 +73,12 @@ class TestRemoteValueSceneNumber:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65))),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
diff --git a/test/remote_value_tests/remote_value_step_test.py b/test/remote_value_tests/remote_value_step_test.py
index 59685a88..ea2fa700 100644
--- a/test/remote_value_tests/remote_value_step_test.py
+++ b/test/remote_value_tests/remote_value_step_test.py
@@ -52,14 +52,14 @@ class TestRemoteValueStep:
         """Test setting value."""
         xknx = XKNX()
         remote_value = RemoteValueStep(xknx, group_address=GroupAddress("1/2/3"))
-        await remote_value.decrease()
+        remote_value.decrease()
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(0)),
         )
-        await remote_value.increase()
+        remote_value.increase()
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -67,7 +67,7 @@ class TestRemoteValueStep:
             payload=GroupValueWrite(DPTBinary(1)),
         )
 
-    async def test_process(self):
+    def test_process(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueStep(xknx, group_address=GroupAddress("1/2/3"))
@@ -76,10 +76,10 @@ class TestRemoteValueStep:
             payload=GroupValueWrite(DPTBinary(0)),
         )
         assert remote_value.value is None
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == RemoteValueStep.Direction.DECREASE
 
-    async def test_to_process_error(self):
+    def test_to_process_error(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueStep(xknx, group_address=GroupAddress("1/2/3"))
@@ -88,12 +88,12 @@ class TestRemoteValueStep:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray(0x01)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(3)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
diff --git a/test/remote_value_tests/remote_value_string_test.py b/test/remote_value_tests/remote_value_string_test.py
index 30bb1e3a..b0852c53 100644
--- a/test/remote_value_tests/remote_value_string_test.py
+++ b/test/remote_value_tests/remote_value_string_test.py
@@ -85,7 +85,7 @@ class TestRemoteValueString:
         """Test setting value."""
         xknx = XKNX()
         remote_value = RemoteValueString(xknx, group_address=GroupAddress("1/2/3"))
-        await remote_value.set("asdf")
+        remote_value.set("asdf")
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -94,7 +94,7 @@ class TestRemoteValueString:
                 DPTArray((97, 115, 100, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
             ),
         )
-        await remote_value.set("ASDF")
+        remote_value.set("ASDF")
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -104,7 +104,7 @@ class TestRemoteValueString:
             ),
         )
 
-    async def test_process(self):
+    def test_process(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueString(xknx, group_address=GroupAddress("1/2/3"))
@@ -131,10 +131,10 @@ class TestRemoteValueString:
                 )
             ),
         )
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == "AAAAABBBBBCCCC"
 
-    async def test_to_process_error(self):
+    def test_to_process_error(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueString(xknx, group_address=GroupAddress("1/2/3"))
@@ -143,12 +143,12 @@ class TestRemoteValueString:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64, 0x65))),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
diff --git a/test/remote_value_tests/remote_value_switch_test.py b/test/remote_value_tests/remote_value_switch_test.py
index 9ef95ed5..7cd6fbaf 100644
--- a/test/remote_value_tests/remote_value_switch_test.py
+++ b/test/remote_value_tests/remote_value_switch_test.py
@@ -52,14 +52,14 @@ class TestRemoteValueSwitch:
         """Test setting value."""
         xknx = XKNX()
         remote_value = RemoteValueSwitch(xknx, group_address=GroupAddress("1/2/3"))
-        await remote_value.on()
+        remote_value.on()
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        await remote_value.off()
+        remote_value.off()
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -67,7 +67,7 @@ class TestRemoteValueSwitch:
             payload=GroupValueWrite(DPTBinary(0)),
         )
 
-    async def test_process(self):
+    def test_process(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueSwitch(xknx, group_address=GroupAddress("1/2/3"))
@@ -76,11 +76,11 @@ class TestRemoteValueSwitch:
             payload=GroupValueWrite(DPTBinary(1)),
         )
         assert remote_value.value is None
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.telegram is not None
         assert remote_value.value is True
 
-    async def test_process_off(self):
+    def test_process_off(self):
         """Test process OFF telegram."""
         xknx = XKNX()
         remote_value = RemoteValueSwitch(xknx, group_address=GroupAddress("1/2/3"))
@@ -89,11 +89,11 @@ class TestRemoteValueSwitch:
             payload=GroupValueWrite(DPTBinary(0)),
         )
         assert remote_value.value is None
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.telegram is not None
         assert remote_value.value is False
 
-    async def test_to_process_error(self):
+    def test_to_process_error(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueSwitch(xknx, group_address=GroupAddress("1/2/3"))
@@ -102,12 +102,12 @@ class TestRemoteValueSwitch:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray(0x01)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(3)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
diff --git a/test/remote_value_tests/remote_value_temp_test.py b/test/remote_value_tests/remote_value_temp_test.py
index 3278366e..8f4f0581 100644
--- a/test/remote_value_tests/remote_value_temp_test.py
+++ b/test/remote_value_tests/remote_value_temp_test.py
@@ -34,7 +34,7 @@ class TestRemoteValueTemp:
         with pytest.raises(ConversionError):
             remote_value.to_knx("abc")
 
-    async def test_process(self):
+    def test_process(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueTemp(xknx, group_address=GroupAddress("1/2/3"))
@@ -42,10 +42,10 @@ class TestRemoteValueTemp:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x04, 0x4C))),
         )
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == 11
 
-    async def test_to_process_error(self):
+    def test_to_process_error(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueTemp(xknx, group_address=GroupAddress("1/2/3"))
@@ -54,12 +54,12 @@ class TestRemoteValueTemp:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x64,))),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None
diff --git a/test/remote_value_tests/remote_value_test.py b/test/remote_value_tests/remote_value_test.py
index 04713966..99401732 100644
--- a/test/remote_value_tests/remote_value_test.py
+++ b/test/remote_value_tests/remote_value_test.py
@@ -1,6 +1,6 @@
 """Unit test for RemoveValue objects."""
 
-from unittest.mock import AsyncMock, patch
+from unittest.mock import AsyncMock, Mock, patch
 
 import pytest
 
@@ -21,7 +21,7 @@ class TestRemoteValue:
         xknx = XKNX()
         remote_value = RemoteValue(xknx)
         remote_value.to_knx = lambda value: DPT2ByteFloat.to_knx(value)
-        remote_value.after_update_cb = AsyncMock()
+        remote_value.after_update_cb = Mock()
 
         assert remote_value.value is None
         remote_value.value = 2.2
@@ -31,28 +31,28 @@ class TestRemoteValue:
             remote_value.value = "a"
         # new value is used in response Telegram
         test_payload = remote_value.to_knx(2.2)
-        remote_value._send = AsyncMock()
-        await remote_value.respond()
+        remote_value._send = Mock()
+        remote_value.respond()
         remote_value._send.assert_called_with(test_payload, response=True)
         # callback is not called when setting value programmatically
         remote_value.after_update_cb.assert_not_called()
         # no Telegram was sent to the queue
         assert xknx.telegrams.qsize() == 0
 
-    async def test_set_value(self):
+    def test_set_value(self):
         """Test set_value awaitable."""
         xknx = XKNX()
         remote_value = RemoteValue(xknx)
         remote_value.to_knx = lambda value: DPT2ByteFloat.to_knx(value)
-        remote_value.after_update_cb = AsyncMock()
+        remote_value.after_update_cb = Mock()
 
-        await remote_value.update_value(3.3)
+        remote_value.update_value(3.3)
         assert remote_value.value == 3.3
         remote_value.after_update_cb.assert_called_once()
         assert xknx.telegrams.qsize() == 0
         # invalid value raises ConversionError
         with pytest.raises(ConversionError):
-            await remote_value.update_value("a")
+            remote_value.update_value("a")
         assert remote_value.value == 3.3
 
     async def test_info_set_uninitialized(self):
@@ -60,7 +60,7 @@ class TestRemoteValue:
         xknx = XKNX()
         remote_value = RemoteValue(xknx)
         with patch("logging.Logger.info") as mock_info:
-            await remote_value.set(23)
+            remote_value.set(23)
             mock_info.assert_called_with(
                 "Setting value of uninitialized device: %s - %s (value: %s)",
                 "Unknown",
@@ -73,7 +73,7 @@ class TestRemoteValue:
         xknx = XKNX()
         remote_value = RemoteValue(xknx, group_address_state=GroupAddress("1/2/3"))
         with patch("logging.Logger.warning") as mock_warning:
-            await remote_value.set(23)
+            remote_value.set(23)
             mock_warning.assert_called_with(
                 "Attempted to set value for non-writable device: %s - %s (value: %s)",
                 "Unknown",
@@ -103,9 +103,9 @@ class TestRemoteValue:
                 CouldNotParseTelegram,
                 match=r".*payload not a GroupValueWrite or GroupValueResponse.*",
             ):
-                await remote_value.process(telegram)
+                remote_value.process(telegram)
 
-    async def test_process_unsupported_payload(self):
+    def test_process_unsupported_payload(self):
         """Test warning is logged when processing telegram with unsupported payload."""
         xknx = XKNX()
         remote_value = RemoteValue(xknx)
@@ -123,7 +123,7 @@ class TestRemoteValue:
             patch_has_group_address.return_value = True
             patch_from.side_effect = ConversionError("TestError")
 
-            assert await remote_value.process(telegram) is False
+            assert remote_value.process(telegram) is False
             mock_warning.assert_called_once_with(
                 "Can not process %s for %s - %s: %s",
                 telegram,
@@ -235,7 +235,7 @@ class TestRemoteValue:
             GroupAddress("2/2/20"),
         ]
 
-    async def test_process_passive_address(self):
+    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"])
@@ -251,10 +251,10 @@ class TestRemoteValue:
             destination_address=GroupAddress("1/1/1"),
             payload=GroupValueWrite(test_payload),
         )
-        assert await remote_value.process(telegram)
+        assert remote_value.process(telegram)
         assert remote_value.telegram.payload.value == test_payload
 
-    async def test_to_from_knx(self):
+    def test_to_from_knx(self):
         """Test to_knx and from_knx raises when not set properly."""
         xknx = XKNX()
         remote_value = RemoteValue(xknx, group_address="1/1/1")
@@ -267,14 +267,14 @@ class TestRemoteValue:
             payload=GroupValueWrite(test_payload),
         )
         with pytest.raises(NotImplementedError):
-            await remote_value.process(telegram)
+            remote_value.process(telegram)
 
         # doesn't raise with `dpt_class` set
         remote_value.dpt_class = DPT2ByteFloat
         remote_value.value = 3.3
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
 
-    async def test_pre_decoded_telegram(self):
+    def test_pre_decoded_telegram(self):
         """Test if pre-decoded Telegram is processed."""
         xknx = XKNX()
         remote_value = RemoteValue(xknx, group_address="1/1/1")
@@ -286,7 +286,7 @@ class TestRemoteValue:
             payload=GroupValueWrite(test_payload),
             decoded_data=TelegramDecodedData(transcoder=DPT2ByteFloat, value=3.3),
         )
-        assert await remote_value.process(telegram)
+        assert remote_value.process(telegram)
         assert remote_value.value == 3.3
 
     def test_eq(self):
diff --git a/test/remote_value_tests/remote_value_updown_test.py b/test/remote_value_tests/remote_value_updown_test.py
index 5f9c1602..d37914cf 100644
--- a/test/remote_value_tests/remote_value_updown_test.py
+++ b/test/remote_value_tests/remote_value_updown_test.py
@@ -52,14 +52,14 @@ class TestRemoteValueUpDown:
         """Test setting value."""
         xknx = XKNX()
         remote_value = RemoteValueUpDown(xknx, group_address=GroupAddress("1/2/3"))
-        await remote_value.down()
+        remote_value.down()
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(1)),
         )
-        await remote_value.up()
+        remote_value.up()
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -67,7 +67,7 @@ class TestRemoteValueUpDown:
             payload=GroupValueWrite(DPTBinary(0)),
         )
 
-    async def test_process(self):
+    def test_process(self):
         """Test process telegram."""
         xknx = XKNX()
         remote_value = RemoteValueUpDown(xknx, group_address=GroupAddress("1/2/3"))
@@ -76,10 +76,10 @@ class TestRemoteValueUpDown:
             payload=GroupValueWrite(DPTBinary(1)),
         )
         assert remote_value.value is None
-        await remote_value.process(telegram)
+        remote_value.process(telegram)
         assert remote_value.value == RemoteValueUpDown.Direction.DOWN
 
-    async def test_to_process_error(self):
+    def test_to_process_error(self):
         """Test process erroneous telegram."""
         xknx = XKNX()
         remote_value = RemoteValueUpDown(xknx, group_address=GroupAddress("1/2/3"))
@@ -88,12 +88,12 @@ class TestRemoteValueUpDown:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray(0x01)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(3)),
         )
-        assert await remote_value.process(telegram) is False
+        assert remote_value.process(telegram) is False
 
         assert remote_value.value is None