Repository: XKNX/xknx
Pull request #1503 (2024-06-29 20:30:28)

Rename HVAC "Night" to "Economy", "Frost Protection" to "Building Protection", "Dry" to "Dehumidification" and add more modes
<!--
  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.
-->
- Rename `ClimateMode` argument `group_address_operation_mode_night` to `group_address_operation_mode_economy`
- rename HVACOperationMode "NIGHT" to "ECONOMY" and "FROST_PROTECTION" to "BUILDING_PROTECTION" according to KNX specifications
- rename HVACControllerMode "DRY" to "DEHUMIDIFICATION" and add some values according to KNX specifications

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
- [ ] 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/1503?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 [(`8a9312f`)](https://app.codecov.io/gh/XKNX/xknx/commit/8a9312f0e3d63acdc8a18cfbd725a8da5639b338?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX) to head [(`b4362df`)](https://app.codecov.io/gh/XKNX/xknx/commit/b4362df8b70ee18da6557848312e5e6d9d4d2118?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/1503/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/1503?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX)

```diff
@@           Coverage Diff           @@
##             main    #1503   +/-   ##
=======================================
  Coverage   96.62%   96.62%           
=======================================
  Files         156      156           
  Lines       10149    10154    +5     
=======================================
+ Hits         9806     9811    +5     
  Misses        343      343           
```

| [Files](https://app.codecov.io/gh/XKNX/xknx/pull/1503?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/climate\_mode.py](https://app.codecov.io/gh/XKNX/xknx/pull/1503?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==) | `99.06% <ø> (ø)` | |
| [xknx/dpt/dpt\_20.py](https://app.codecov.io/gh/XKNX/xknx/pull/1503?src=pr&el=tree&filepath=xknx%2Fdpt%2Fdpt_20.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX#diff-eGtueC9kcHQvZHB0XzIwLnB5) | `99.15% <100.00%> (+0.03%)` | :arrow_up: |
| [xknx/remote\_value/remote\_value\_climate\_mode.py](https://app.codecov.io/gh/XKNX/xknx/pull/1503?src=pr&el=tree&filepath=xknx%2Fremote_value%2Fremote_value_climate_mode.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=XKNX#diff-eGtueC9yZW1vdGVfdmFsdWUvcmVtb3RlX3ZhbHVlX2NsaW1hdGVfbW9kZS5weQ==) | `94.30% <ø> (ø)` | |

</details>

Patch:
diff --git a/docs/changelog.md b/docs/changelog.md
index 0693ffa5..b3f8f5a4 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -21,6 +21,10 @@ nav_order: 2
   - ValueReader: `.send_group_read`
 - Rename DPT transcoder modules for schema `xknx.dpt.dpt_<main-number>.py`
 
+### Bugfixes
+
+- Fix value scaling for sensor types: time_period_100msec, time_period_10msec, delta_time_10ms, delta_time_100ms, percentV16
+
 ### Features
 
 - 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.
@@ -30,6 +34,7 @@ nav_order: 2
 - A Device doesn't auto-add to `xknx.devices` anymore. It can be done via `xknx.devices.async_add()` now. `xknx.devices.async_remove` stops a device from processing telegrams, removes from StateUpdater and cancels its internal tasks. Removed devices can be added again.
 - `Device.shutdown` method is removed
 - Refactor `ClimateMode` device
+- Rename `ClimateMode` argument `group_address_operation_mode_night` to `group_address_operation_mode_economy`
 
 ### DPT
 
@@ -42,7 +47,9 @@ nav_order: 2
   - 20.60102 - DPTHVACStatus - HVACStatus (removed DPTControllerStatus in favour of this)
 - DPTEnum: Common interface for DPT transcoders with enumueration values. Transcoders accept Enum or string values for encoding.
   - 20.102 - DPTHVACMode - HVACOperationMode
+    - rename "NIGHT" to "ECONOMY" and "FROST_PROTECTION" to "BUILDING_PROTECTION" according to KNX specifications
   - 20.105 - DPTHVACContrMode - HVACControllerMode
+    - rename "DRY" to "DEHUMIDIFICATION" and add some values according to KNX specifications
 - Support dict values with "main" and "sub" keys for `DPTBase.parse_transcoder()`
 
 ### Address
diff --git a/docs/climate.md b/docs/climate.md
index 289f25f0..d43592ea 100644
--- a/docs/climate.md
+++ b/docs/climate.md
@@ -35,8 +35,8 @@ Climate are representations of KNX HVAC/Climate controls.
 - `mode` ClimateMode instance for this climate device
 - `group_address_operation_mode` KNX address for operation mode. *DPT 20.102*
 - `group_address_operation_mode_state` KNX address for operation mode status. *DPT 20.102*
-- `group_address_operation_mode_protection` KNX address for switching on/off frost/heat protection mode. *DPT 1*
-- `group_address_operation_mode_night` KNX address for switching on/off night nmode. *DPT 1*
+- `group_address_operation_mode_protection` KNX address for switching on/off building protection mode. *DPT 1*
+- `group_address_operation_mode_economy` KNX address for switching on/off economy mode. *DPT 1*
 - `group_address_operation_mode_comfort` KNX address for switching on/off comfort mode. *DPT 1*
 - `group_address_operation_mode_standby` KNX address for switching on/off standby mode. *DPT 1*
 - `group_address_controller_status` KNX address for controller status.
@@ -49,7 +49,7 @@ Climate are representations of KNX HVAC/Climate controls.
 - `controller_modes` Overrides the supported controller modes.
 - `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`.
+**Note:** `group_address_operation_mode_protection` / `group_address_operation_mode_economy` / `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`, `Building Protection` and `Economy` 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`.
 
 ```python
@@ -59,7 +59,7 @@ climate_mode = ClimateMode(
     group_address_operation_mode='',
     group_address_operation_mode_state='',
     group_address_operation_mode_protection=None,
-    group_address_operation_mode_night=None,
+    group_address_operation_mode_economy=None,
     group_address_operation_mode_comfort=None,
     group_address_controller_status=None,
     group_address_controller_status_state=None,
diff --git a/xknx/devices/climate_mode.py b/xknx/devices/climate_mode.py
index eb4dc393..b41181e0 100644
--- a/xknx/devices/climate_mode.py
+++ b/xknx/devices/climate_mode.py
@@ -39,7 +39,7 @@ class ClimateMode(Device):
         group_address_operation_mode: GroupAddressesType = None,
         group_address_operation_mode_state: GroupAddressesType = None,
         group_address_operation_mode_protection: GroupAddressesType = None,
-        group_address_operation_mode_night: GroupAddressesType = None,
+        group_address_operation_mode_economy: GroupAddressesType = None,
         group_address_operation_mode_comfort: GroupAddressesType = None,
         group_address_operation_mode_standby: GroupAddressesType = None,
         group_address_controller_status: GroupAddressesType = None,
@@ -104,14 +104,14 @@ class ClimateMode(Device):
             operation_mode=HVACOperationMode.STANDBY,
             after_update_cb=self._set_internal_operation_mode,
         )
-        self.remote_value_operation_mode_night = RemoteValueBinaryOperationMode(
+        self.remote_value_operation_mode_economy = RemoteValueBinaryOperationMode(
             xknx,
-            group_address=group_address_operation_mode_night,
-            group_address_state=group_address_operation_mode_night,
+            group_address=group_address_operation_mode_economy,
+            group_address_state=group_address_operation_mode_economy,
             sync_state=sync_state,
             device_name=name,
-            feature_name="Operation mode Night",
-            operation_mode=HVACOperationMode.NIGHT,
+            feature_name="Operation mode Economy",
+            operation_mode=HVACOperationMode.ECONOMY,
             after_update_cb=self._set_internal_operation_mode,
         )
         self.remote_value_operation_mode_protection = RemoteValueBinaryOperationMode(
@@ -121,7 +121,7 @@ class ClimateMode(Device):
             sync_state=sync_state,
             device_name=name,
             feature_name="Operation mode Protection",
-            operation_mode=HVACOperationMode.FROST_PROTECTION,
+            operation_mode=HVACOperationMode.BUILDING_PROTECTION,
             after_update_cb=self._set_internal_operation_mode,
         )
         self.remote_value_heat_cool = RemoteValueBinaryHeatCool(
@@ -170,7 +170,7 @@ class ClimateMode(Device):
         yield self.remote_value_controller_status
         yield self.remote_value_heat_cool
         yield self.remote_value_operation_mode_comfort
-        yield self.remote_value_operation_mode_night
+        yield self.remote_value_operation_mode_economy
         yield self.remote_value_operation_mode_protection
         yield self.remote_value_operation_mode_standby
 
diff --git a/xknx/dpt/dpt_20.py b/xknx/dpt/dpt_20.py
index a57e40fe..c8b3631d 100644
--- a/xknx/dpt/dpt_20.py
+++ b/xknx/dpt/dpt_20.py
@@ -18,8 +18,8 @@ class HVACOperationMode(Enum):
     AUTO = "Auto"
     COMFORT = "Comfort"
     STANDBY = "Standby"
-    NIGHT = "Night"
-    FROST_PROTECTION = "Frost Protection"
+    ECONOMY = "Economy"
+    BUILDING_PROTECTION = "Building Protection"
 
 
 class DPTHVACMode(DPTEnum[HVACOperationMode]):
@@ -41,8 +41,8 @@ class DPTHVACMode(DPTEnum[HVACOperationMode]):
             0: HVACOperationMode.AUTO,
             1: HVACOperationMode.COMFORT,
             2: HVACOperationMode.STANDBY,
-            3: HVACOperationMode.NIGHT,
-            4: HVACOperationMode.FROST_PROTECTION,
+            3: HVACOperationMode.ECONOMY,
+            4: HVACOperationMode.BUILDING_PROTECTION,
         }
 
 
@@ -61,7 +61,12 @@ class HVACControllerMode(Enum):
     FAN_ONLY = "Fan only"
     FREE_COOL = "Free Cool"
     ICE = "Ice"
-    DRY = "Dry"
+    MAXIMUM_HEATING_MODE = "Maximum Heating Mode"
+    ECONOMIC_HEAT_COOL_MODE = "Economic Heat/Cool Mode"
+    DEHUMIDIFICATION = "Dehumidification"
+    CALIBRATION_MODE = "Calibration Mode"
+    EMERGENCY_COOL_MODE = "Emergency Cool Mode"
+    EMERGENCY_STEAM_MODE = "Emergency Steam Mode"
     NODEM = "NoDem"
 
 
@@ -93,7 +98,12 @@ class DPTHVACContrMode(DPTEnum[HVACControllerMode]):
             9: HVACControllerMode.FAN_ONLY,
             10: HVACControllerMode.FREE_COOL,
             11: HVACControllerMode.ICE,
-            14: HVACControllerMode.DRY,
+            12: HVACControllerMode.MAXIMUM_HEATING_MODE,
+            13: HVACControllerMode.ECONOMIC_HEAT_COOL_MODE,
+            14: HVACControllerMode.DEHUMIDIFICATION,
+            15: HVACControllerMode.CALIBRATION_MODE,
+            16: HVACControllerMode.ECONOMIC_HEAT_COOL_MODE,
+            17: HVACControllerMode.EMERGENCY_STEAM_MODE,
             20: HVACControllerMode.NODEM,
         }
 
@@ -182,9 +192,9 @@ class DPTHVACStatus(DPTComplex[HVACStatus]):
         elif raw & 0b01000000:
             mode = HVACOperationMode.STANDBY
         elif raw & 0b00100000:
-            mode = HVACOperationMode.NIGHT
+            mode = HVACOperationMode.ECONOMY
         elif raw & 0b00010000:
-            mode = HVACOperationMode.FROST_PROTECTION
+            mode = HVACOperationMode.BUILDING_PROTECTION
         else:
             mode = HVACOperationMode.AUTO  # not sure if this is possible / valid
 
@@ -206,9 +216,9 @@ class DPTHVACStatus(DPTComplex[HVACStatus]):
             raw |= 0b10000000
         elif value.mode is HVACOperationMode.STANDBY:
             raw |= 0b01000000
-        elif value.mode is HVACOperationMode.NIGHT:
+        elif value.mode is HVACOperationMode.ECONOMY:
             raw |= 0b00100000
-        elif value.mode is HVACOperationMode.FROST_PROTECTION:
+        elif value.mode is HVACOperationMode.BUILDING_PROTECTION:
             raw |= 0b00010000
         if value.dew_point:
             raw |= 0b00001000
diff --git a/xknx/dpt/dpt_7.py b/xknx/dpt/dpt_7.py
index bb0a0de2..fd0f85e1 100644
--- a/xknx/dpt/dpt_7.py
+++ b/xknx/dpt/dpt_7.py
@@ -30,13 +30,13 @@ class DPT2ByteUnsigned(DPTNumeric):
     def from_knx(cls, payload: DPTArray | DPTBinary) -> int:
         """Parse/deserialize from KNX/IP raw data."""
         raw = cls.validate_payload(payload)
-        return (raw[0] * 256) + raw[1]
+        return ((raw[0] * 256) + raw[1]) * cls.resolution
 
     @classmethod
     def to_knx(cls, value: int | float) -> DPTArray:
         """Serialize to KNX/IP raw data."""
         try:
-            knx_value = int(value)
+            knx_value = int(value) // cls.resolution
             if not cls._test_boundaries(knx_value):
                 raise ValueError("Value out of range")
             return DPTArray((knx_value >> 8, knx_value & 0xFF))
@@ -75,6 +75,7 @@ class DPTTimePeriod10Msec(DPT2ByteUnsigned):
     dpt_main_number = 7
     dpt_sub_number = 3
     value_type = "time_period_10msec"
+    resolution = 10
     unit = "ms"
 
 
@@ -84,6 +85,7 @@ class DPTTimePeriod100Msec(DPT2ByteUnsigned):
     dpt_main_number = 7
     dpt_sub_number = 4
     value_type = "time_period_100msec"
+    resolution = 100
     unit = "ms"
 
 
diff --git a/xknx/dpt/dpt_8.py b/xknx/dpt/dpt_8.py
index ad552d80..e03df5d9 100644
--- a/xknx/dpt/dpt_8.py
+++ b/xknx/dpt/dpt_8.py
@@ -29,17 +29,17 @@ class DPT2ByteSigned(DPTNumeric):
 
     value_min = -32768
     value_max = 32767
-    resolution = 1
+    resolution: float = 1
 
     _struct_format = ">h"
 
     @classmethod
-    def from_knx(cls, payload: DPTArray | DPTBinary) -> int:
+    def from_knx(cls, payload: DPTArray | DPTBinary) -> int | float:
         """Parse/deserialize from KNX/IP raw data."""
         raw = cls.validate_payload(payload)
 
         try:
-            return struct.unpack(cls._struct_format, bytes(raw))[0]  # type: ignore[no-any-return]
+            return struct.unpack(cls._struct_format, bytes(raw))[0] * cls.resolution  # type: ignore[no-any-return]
         except struct.error as err:
             raise ConversionError(f"Could not parse {cls.__name__}", raw=raw) from err
 
@@ -47,7 +47,7 @@ class DPT2ByteSigned(DPTNumeric):
     def to_knx(cls, value: int | float) -> DPTArray:
         """Serialize to KNX/IP raw data."""
         try:
-            knx_value = int(value)
+            knx_value = int(float(value) / cls.resolution)
             if not cls._test_boundaries(knx_value):
                 raise ValueError("Value out of range")
             return DPTArray(struct.pack(cls._struct_format, knx_value))
@@ -86,6 +86,7 @@ class DPTDeltaTime10Msec(DPT2ByteSigned):
     dpt_main_number = 8
     dpt_sub_number = 3
     value_type = "delta_time_10ms"
+    resolution = 10
     unit = "ms"
 
 
@@ -95,6 +96,7 @@ class DPTDeltaTime100Msec(DPT2ByteSigned):
     dpt_main_number = 8
     dpt_sub_number = 4
     value_type = "delta_time_100ms"
+    resolution = 100
     unit = "ms"
 
 
@@ -131,6 +133,7 @@ class DPTPercentV16(DPT2ByteSigned):
     dpt_main_number = 8
     dpt_sub_number = 10
     value_type = "percentV16"
+    resolution = 0.01
     unit = "%"
 
 
diff --git a/xknx/remote_value/remote_value_climate_mode.py b/xknx/remote_value/remote_value_climate_mode.py
index 62a60a21..0bb60676 100644
--- a/xknx/remote_value/remote_value_climate_mode.py
+++ b/xknx/remote_value/remote_value_climate_mode.py
@@ -179,8 +179,8 @@ class RemoteValueHVACStatus(RemoteValueClimateModeBase[HVACStatus]):
         return [
             HVACOperationMode.COMFORT,
             HVACOperationMode.STANDBY,
-            HVACOperationMode.NIGHT,
-            HVACOperationMode.FROST_PROTECTION,
+            HVACOperationMode.ECONOMY,
+            HVACOperationMode.BUILDING_PROTECTION,
         ]
 
     def set_operation_mode(self, mode: HVACOperationMode) -> None:
@@ -270,8 +270,8 @@ class RemoteValueBinaryOperationMode(
         """Return a list of all supported operation modes."""
         return [
             HVACOperationMode.COMFORT,
-            HVACOperationMode.FROST_PROTECTION,
-            HVACOperationMode.NIGHT,
+            HVACOperationMode.BUILDING_PROTECTION,
+            HVACOperationMode.ECONOMY,
             HVACOperationMode.STANDBY,
         ]
 


Test patch:
diff --git a/test/devices_tests/climate_test.py b/test/devices_tests/climate_test.py
index 61434690..24077d37 100644
--- a/test/devices_tests/climate_test.py
+++ b/test/devices_tests/climate_test.py
@@ -26,8 +26,8 @@ DPT_20102_MODES = [
     HVACOperationMode.AUTO,
     HVACOperationMode.COMFORT,
     HVACOperationMode.STANDBY,
-    HVACOperationMode.NIGHT,
-    HVACOperationMode.FROST_PROTECTION,
+    HVACOperationMode.ECONOMY,
+    HVACOperationMode.BUILDING_PROTECTION,
 ]
 
 
@@ -105,7 +105,7 @@ class TestClimate:
             group_address_operation_mode="1/2/4",
             group_address_operation_mode_state="1/2/5",
             group_address_operation_mode_protection="1/2/6",
-            group_address_operation_mode_night="1/2/7",
+            group_address_operation_mode_economy="1/2/7",
             group_address_operation_mode_comfort="1/2/8",
             group_address_operation_mode_standby="1/2/9",
             group_address_controller_status="1/2/10",
@@ -181,7 +181,7 @@ class TestClimate:
         after_update_callback.assert_not_called()
         after_update_callback.reset_mock()
 
-        await climate_mode.set_operation_mode(HVACOperationMode.FROST_PROTECTION)
+        await climate_mode.set_operation_mode(HVACOperationMode.BUILDING_PROTECTION)
         after_update_callback.assert_called_with(climate_mode)
         after_update_callback.reset_mock()
 
@@ -337,7 +337,7 @@ class TestClimate:
             "TestClimate",
             group_address_operation_mode="1/2/4",
             group_address_operation_mode_protection="1/2/5",
-            group_address_operation_mode_night="1/2/6",
+            group_address_operation_mode_economy="1/2/6",
             group_address_operation_mode_comfort="1/2/7",
         )
 
@@ -402,7 +402,7 @@ class TestClimate:
             group_address_operation_mode="1/2/4",
             group_address_operation_mode_state="1/2/5",
             group_address_operation_mode_protection="1/2/6",
-            group_address_operation_mode_night="1/2/7",
+            group_address_operation_mode_economy="1/2/7",
             group_address_operation_mode_comfort="1/2/8",
             group_address_operation_mode_standby="1/2/9",
             group_address_controller_status="1/2/10",
@@ -444,10 +444,10 @@ class TestClimate:
         assert xknx.telegrams.qsize() == 3
         _process_all_telegrams()
 
-        await climate_mode.set_operation_mode(HVACOperationMode.NIGHT)
+        await climate_mode.set_operation_mode(HVACOperationMode.ECONOMY)
         assert xknx.telegrams.qsize() == 6
         _process_all_telegrams()
-        assert climate_mode.operation_mode == HVACOperationMode.NIGHT
+        assert climate_mode.operation_mode == HVACOperationMode.ECONOMY
         assert climate_mode.controller_mode == HVACControllerMode.COOL
 
     #
@@ -1268,8 +1268,8 @@ class TestClimate:
             HVACOperationMode.AUTO,
             HVACOperationMode.COMFORT,
             HVACOperationMode.STANDBY,
-            HVACOperationMode.NIGHT,
-            HVACOperationMode.FROST_PROTECTION,
+            HVACOperationMode.ECONOMY,
+            HVACOperationMode.BUILDING_PROTECTION,
         }
 
     def test_supported_modes_controller_status(self):
@@ -1281,8 +1281,8 @@ class TestClimate:
         assert set(climate_mode.operation_modes) == {
             HVACOperationMode.COMFORT,
             HVACOperationMode.STANDBY,
-            HVACOperationMode.NIGHT,
-            HVACOperationMode.FROST_PROTECTION,
+            HVACOperationMode.ECONOMY,
+            HVACOperationMode.BUILDING_PROTECTION,
         }
         assert set(climate_mode.controller_modes) == {
             HVACControllerMode.HEAT,
@@ -1302,29 +1302,29 @@ class TestClimate:
             xknx,
             "TestClimate",
             group_address_operation_mode_protection="1/2/5",
-            group_address_operation_mode_night="1/2/6",
+            group_address_operation_mode_economy="1/2/6",
             group_address_operation_mode_comfort="1/2/7",
         )
 
         assert set(climate_mode.operation_modes) == {
             HVACOperationMode.COMFORT,
             HVACOperationMode.STANDBY,
-            HVACOperationMode.NIGHT,
-            HVACOperationMode.FROST_PROTECTION,
+            HVACOperationMode.ECONOMY,
+            HVACOperationMode.BUILDING_PROTECTION,
         }
 
-    def test_supported_operation_modes_only_night(self):
-        """Test get_supported_operation_modes with only night mode supported."""
+    def test_supported_operation_modes_only_economy(self):
+        """Test get_supported_operation_modes with only economy mode supported."""
         xknx = XKNX()
         climate_mode = ClimateMode(
-            xknx, "TestClimate", group_address_operation_mode_night="1/2/7"
+            xknx, "TestClimate", group_address_operation_mode_economy="1/2/7"
         )
         # If one binary climate object is set, all 4 operation modes are supported.
         assert set(climate_mode.operation_modes) == {
             HVACOperationMode.STANDBY,
-            HVACOperationMode.NIGHT,
+            HVACOperationMode.ECONOMY,
             HVACOperationMode.COMFORT,
-            HVACOperationMode.FROST_PROTECTION,
+            HVACOperationMode.BUILDING_PROTECTION,
         }
 
     def test_supported_operation_modes_heat_cool(self):
@@ -1343,7 +1343,7 @@ class TestClimate:
 
     def test_custom_supported_operation_modes(self):
         """Test get_supported_operation_modes with custom mode."""
-        modes = [HVACOperationMode.STANDBY, HVACOperationMode.NIGHT]
+        modes = [HVACOperationMode.STANDBY, HVACOperationMode.ECONOMY]
         xknx = XKNX()
         climate_mode = ClimateMode(
             xknx,
@@ -1355,8 +1355,8 @@ class TestClimate:
 
     def test_custom_supported_operation_modes_as_str(self):
         """Test get_supported_operation_modes with custom mode as str list."""
-        str_modes = ["Standby", "Frost Protection"]
-        modes = [HVACOperationMode.STANDBY, HVACOperationMode.FROST_PROTECTION]
+        str_modes = ["Standby", "Building Protection"]
+        modes = [HVACOperationMode.STANDBY, HVACOperationMode.BUILDING_PROTECTION]
         xknx = XKNX()
         climate_mode = ClimateMode(
             xknx,
diff --git a/test/devices_tests/numeric_value_test.py b/test/devices_tests/numeric_value_test.py
index b180a064..45298174 100644
--- a/test/devices_tests/numeric_value_test.py
+++ b/test/devices_tests/numeric_value_test.py
@@ -66,7 +66,7 @@ class TestNumericValue:
             (
                 "percentV16",
                 DPTArray((0x8A, 0x2F)),
-                -30161,
+                -301.61,
             ),
             (
                 "pulse",
diff --git a/test/devices_tests/sensor_expose_loop_test.py b/test/devices_tests/sensor_expose_loop_test.py
index 4432d389..564acd47 100644
--- a/test/devices_tests/sensor_expose_loop_test.py
+++ b/test/devices_tests/sensor_expose_loop_test.py
@@ -95,7 +95,7 @@ class TestSensorExposeLoop:
         ("percent", DPTArray((0xE3,)), 89),
         ("percentU8", DPTArray((0x6B,)), 107),
         ("percentV8", DPTArray((0x20,)), 32),
-        ("percentV16", DPTArray((0x8A, 0x2F)), -30161),
+        ("percentV16", DPTArray((0x8A, 0x2F)), -301.61),
         ("phaseanglerad", DPTArray((0x45, 0x54, 0xAC, 0x2D)), 3402.761),
         ("phaseangledeg", DPTArray((0xC5, 0x25, 0x13, 0x37)), -2641.201),
         ("power", DPTArray((0x45, 0xCB, 0xE2, 0x5C)), 6524.295),
@@ -153,8 +153,8 @@ class TestSensorExposeLoop:
         ("thermoelectric_power", DPTArray((0x41, 0xCF, 0x9E, 0x4F)), 25.9523),
         ("time_1", DPTArray((0x5E, 0x1E)), 32071.68),
         ("time_2", DPTArray((0xFB, 0x29)), -405995.52),
-        ("time_period_100msec", DPTArray((0x6A, 0x35)), 27189),
-        ("time_period_10msec", DPTArray((0x32, 0x3)), 12803),
+        ("time_period_100msec", DPTArray((0x6A, 0x35)), 2718900),
+        ("time_period_10msec", DPTArray((0x32, 0x3)), 128030),
         ("time_period_hrs", DPTArray((0x29, 0xDE)), 10718),
         ("time_period_min", DPTArray((0x0, 0x54)), 84),
         ("time_period_msec", DPTArray((0x93, 0xC7)), 37831),
diff --git a/test/devices_tests/sensor_test.py b/test/devices_tests/sensor_test.py
index 7487b7e8..176fa376 100644
--- a/test/devices_tests/sensor_test.py
+++ b/test/devices_tests/sensor_test.py
@@ -416,7 +416,7 @@ class TestSensor:
             (
                 "percentV16",
                 DPTArray((0x8A, 0x2F)),
-                -30161,
+                -301.61,
             ),
             (
                 "phaseanglerad",
@@ -591,12 +591,12 @@ class TestSensor:
             (
                 "time_period_100msec",
                 DPTArray((0x6A, 0x35)),
-                27189,
+                2718900,
             ),
             (
                 "time_period_10msec",
                 DPTArray((0x32, 0x3)),
-                12803,
+                128030,
             ),
             (
                 "time_period_hrs",
diff --git a/test/dpt_tests/dpt_hvac_mode_test.py b/test/dpt_tests/dpt_hvac_mode_test.py
index 90f2c88e..98ceafd3 100644
--- a/test/dpt_tests/dpt_hvac_mode_test.py
+++ b/test/dpt_tests/dpt_hvac_mode_test.py
@@ -15,8 +15,8 @@ class TestDPTHVACMode:
         assert DPTHVACMode.to_knx(HVACOperationMode.AUTO) == DPTArray((0x00,))
         assert DPTHVACMode.to_knx(HVACOperationMode.COMFORT) == DPTArray((0x01,))
         assert DPTHVACMode.to_knx(HVACOperationMode.STANDBY) == DPTArray((0x02,))
-        assert DPTHVACMode.to_knx(HVACOperationMode.NIGHT) == DPTArray((0x03,))
-        assert DPTHVACMode.to_knx(HVACOperationMode.FROST_PROTECTION) == DPTArray(
+        assert DPTHVACMode.to_knx(HVACOperationMode.ECONOMY) == DPTArray((0x03,))
+        assert DPTHVACMode.to_knx(HVACOperationMode.BUILDING_PROTECTION) == DPTArray(
             (0x04,)
         )
 
@@ -25,9 +25,9 @@ class TestDPTHVACMode:
         assert DPTHVACMode.to_knx("auto") == DPTArray((0x00,))
         assert DPTHVACMode.to_knx("Comfort") == DPTArray((0x01,))
         assert DPTHVACMode.to_knx("standby") == DPTArray((0x02,))
-        assert DPTHVACMode.to_knx("NIGHT") == DPTArray((0x03,))
+        assert DPTHVACMode.to_knx("ECONOMY") == DPTArray((0x03,))
         assert DPTHVACMode.to_knx(
-            "Frost Protection"  # Enum value, not name
+            "Building Protection"  # Enum value, not name
         ) == DPTArray((0x04,))
 
     def test_mode_to_knx_wrong_value(self):
@@ -40,10 +40,10 @@ class TestDPTHVACMode:
         assert DPTHVACMode.from_knx(DPTArray((0x00,))) == HVACOperationMode.AUTO
         assert DPTHVACMode.from_knx(DPTArray((0x01,))) == HVACOperationMode.COMFORT
         assert DPTHVACMode.from_knx(DPTArray((0x02,))) == HVACOperationMode.STANDBY
-        assert DPTHVACMode.from_knx(DPTArray((0x03,))) == HVACOperationMode.NIGHT
+        assert DPTHVACMode.from_knx(DPTArray((0x03,))) == HVACOperationMode.ECONOMY
         assert (
             DPTHVACMode.from_knx(DPTArray((0x04,)))
-            == HVACOperationMode.FROST_PROTECTION
+            == HVACOperationMode.BUILDING_PROTECTION
         )
 
     def test_mode_from_knx_wrong_value(self):
@@ -167,7 +167,7 @@ class TestDPTHVACStatus:
             ),  # min values
             (
                 HVACStatus(
-                    mode=HVACOperationMode.NIGHT,
+                    mode=HVACOperationMode.ECONOMY,
                     dew_point=True,
                     heat_cool=HVACControllerMode.COOL,
                     inactive=False,
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 ee42fa12..03ceb91d 100644
--- a/test/remote_value_tests/remote_value_climate_mode_test.py
+++ b/test/remote_value_tests/remote_value_climate_mode_test.py
@@ -38,7 +38,7 @@ class TestRemoteValueOperationMode:
             xknx, operation_mode=HVACOperationMode.COMFORT
         )
         assert remote_value.to_knx(HVACOperationMode.COMFORT) == DPTBinary(True)
-        assert remote_value.to_knx(HVACOperationMode.NIGHT) == DPTBinary(False)
+        assert remote_value.to_knx(HVACOperationMode.ECONOMY) == DPTBinary(False)
 
     def test_from_knx_binary_error(self):
         """Test from_knx function with invalid payload."""
@@ -141,13 +141,13 @@ class TestRemoteValueOperationMode:
         with pytest.raises(ConversionError):
             remote_value.to_knx("256")
         with pytest.raises(ConversionError):
-            remote_value.to_knx(HVACOperationMode.NIGHT)
+            remote_value.to_knx(HVACOperationMode.ECONOMY)
 
     def test_to_knx_error_binary(self):
         """Test to_knx function with wrong parameter."""
         xknx = XKNX()
         remote_value = RemoteValueBinaryOperationMode(
-            xknx, operation_mode=HVACOperationMode.NIGHT
+            xknx, operation_mode=HVACOperationMode.ECONOMY
         )
         with pytest.raises(ConversionError):
             remote_value.to_knx(256)
@@ -162,14 +162,14 @@ class TestRemoteValueOperationMode:
         remote_value = RemoteValueOperationMode(
             xknx, group_address=GroupAddress("1/2/3")
         )
-        remote_value.set(HVACOperationMode.NIGHT)
+        remote_value.set(HVACOperationMode.ECONOMY)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTArray((0x03,))),
         )
-        remote_value.set(HVACOperationMode.FROST_PROTECTION)
+        remote_value.set(HVACOperationMode.BUILDING_PROTECTION)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -213,7 +213,7 @@ class TestRemoteValueOperationMode:
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(True)),
         )
-        remote_value.set(HVACOperationMode.FROST_PROTECTION)
+        remote_value.set(HVACOperationMode.BUILDING_PROTECTION)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
@@ -253,14 +253,14 @@ class TestRemoteValueOperationMode:
         remote_value = RemoteValueBinaryOperationMode(
             xknx,
             group_address=GroupAddress("1/2/3"),
-            operation_mode=HVACOperationMode.FROST_PROTECTION,
+            operation_mode=HVACOperationMode.BUILDING_PROTECTION,
         )
         telegram = Telegram(
             destination_address=GroupAddress("1/2/3"),
             payload=GroupValueWrite(DPTBinary(True)),
         )
         remote_value.process(telegram)
-        assert remote_value.value == HVACOperationMode.FROST_PROTECTION
+        assert remote_value.value == HVACOperationMode.BUILDING_PROTECTION
 
     def test_to_process_error_operation_mode(self):
         """Test process erroneous telegram."""
diff --git a/test/str_test.py b/test/str_test.py
index 93a17f40..72044397 100644
--- a/test/str_test.py
+++ b/test/str_test.py
@@ -151,7 +151,7 @@ class TestStringRepresentations:
             group_address_operation_mode="1/2/5",
             group_address_operation_mode_state="1/2/6",
             group_address_operation_mode_protection="1/2/7",
-            group_address_operation_mode_night="1/2/8",
+            group_address_operation_mode_economy="1/2/8",
             group_address_operation_mode_comfort="1/2/9",
             group_address_controller_status="1/2/10",
             group_address_controller_status_state="1/2/11",