Repository: XKNX/xknx
Pull request #596 (2021-02-06 20:23:53)

DPT update
<!--
  You are awesome! Thanks for contributing to our project!
  Please, DO NOT DELETE ANY TEXT from this template!.
-->
This PR updates DPT definition as follows:
- Resolution of DPT9 had been changed from 1 to 0.01 according to the KNX specification. This should not break anything, as the parameter is not used for the time being.
- Some additional `HA_device_class`es had been added: `power_factor` for DPT14 and `energy` for DPT13.

<!--
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.
-->

## 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.
-->

- [x] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update

## Checklist:

- [x] I have performed a self-review of my own code
- [ ] The documentation has been adjusted accordingly
- [x] The changes generate no new warnings
- [ ] Tests have been added that prove the fix is effective or that the feature works
- [ ] The changes are documented in the changelog
- [ ] The Homeassistant plugin has been adjusted in case of new config options


coveralls: 
[![Coverage Status](https://coveralls.io/builds/36922472/badge)](https://coveralls.io/builds/36922472)

Coverage increased (+0.01%) to 94.883% when pulling **c8932dcfd3212d97fa0f5a92ea6d2e22a5bb1105 on KNXBroker:DPT-update** into **bc76b93d810c3a577f0dadcdac67b33b47b6ab6c on XKNX:master**.

KNXBroker: Your are fully right, it's corrected.

Patch:
diff --git a/xknx/dpt/dpt_2byte_float.py b/xknx/dpt/dpt_2byte_float.py
index 1783523c..e64be7a0 100644
--- a/xknx/dpt/dpt_2byte_float.py
+++ b/xknx/dpt/dpt_2byte_float.py
@@ -22,7 +22,7 @@ class DPT2ByteFloat(DPTBase):
     dpt_sub_number = None
     value_type = "2byte_float"
     unit = ""
-    resolution = 1
+    resolution = 0.01
     payload_length = 2
 
     @classmethod
@@ -93,7 +93,6 @@ class DPTTemperature(DPT2ByteFloat):
     value_type = "temperature"
     unit = "°C"
     ha_device_class = "temperature"
-    resolution = 1
 
 
 class DPTTemperatureDifference2Byte(DPT2ByteFloat):
@@ -106,7 +105,6 @@ class DPTTemperatureDifference2Byte(DPT2ByteFloat):
     value_type = "temperature_difference_2byte"
     unit = "K"
     ha_device_class = "temperature"
-    resolution = 1
 
 
 class DPTTemperatureA(DPT2ByteFloat):
@@ -118,7 +116,6 @@ class DPTTemperatureA(DPT2ByteFloat):
     dpt_sub_number = 3
     value_type = "temperature_a"
     unit = "K/h"
-    resolution = 1
 
 
 class DPTLux(DPT2ByteFloat):
@@ -131,7 +128,6 @@ class DPTLux(DPT2ByteFloat):
     value_type = "illuminance"
     unit = "lx"
     ha_device_class = "illuminance"
-    resolution = 1
 
 
 class DPTWsp(DPT2ByteFloat):
@@ -143,7 +139,6 @@ class DPTWsp(DPT2ByteFloat):
     dpt_sub_number = 5
     value_type = "wind_speed_ms"
     unit = "m/s"
-    resolution = 1
 
 
 class DPTPressure2Byte(DPT2ByteFloat):
@@ -156,7 +151,6 @@ class DPTPressure2Byte(DPT2ByteFloat):
     value_type = "pressure_2byte"
     unit = "Pa"
     ha_device_class = "pressure"
-    resolution = 1
 
 
 class DPTHumidity(DPT2ByteFloat):
@@ -169,7 +163,6 @@ class DPTHumidity(DPT2ByteFloat):
     value_type = "humidity"
     unit = "%"
     ha_device_class = "humidity"
-    resolution = 1
 
 
 class DPTPartsPerMillion(DPT2ByteFloat):
@@ -190,7 +183,6 @@ class DPTTime1(DPT2ByteFloat):
     dpt_sub_number = 10
     value_type = "time_1"
     unit = "s"
-    resolution = 1
 
 
 class DPTTime2(DPT2ByteFloat):
@@ -202,7 +194,6 @@ class DPTTime2(DPT2ByteFloat):
     dpt_sub_number = 11
     value_type = "time_2"
     unit = "ms"
-    resolution = 1
 
 
 class DPTVoltage(DPT2ByteFloat):
@@ -281,7 +272,6 @@ class DPTTemperatureF(DPT2ByteFloat):
     value_type = "temperature_f"
     unit = "°F"
     ha_device_class = "temperature"
-    resolution = 1
 
 
 class DPTWspKmh(DPT2ByteFloat):
@@ -293,7 +283,6 @@ class DPTWspKmh(DPT2ByteFloat):
     dpt_sub_number = 28
     value_type = "wind_speed_kmh"
     unit = "km/h"
-    resolution = 1
 
 
 class DPTEnthalpy(DPT2ByteFloat):
diff --git a/xknx/dpt/dpt_4byte_float.py b/xknx/dpt/dpt_4byte_float.py
index 278f752b..d9cef01d 100644
--- a/xknx/dpt/dpt_4byte_float.py
+++ b/xknx/dpt/dpt_4byte_float.py
@@ -572,6 +572,7 @@ class DPTPowerFactor(DPT4ByteFloat):
     dpt_sub_number = 57
     value_type = "powerfactor"
     unit = "cosΦ"
+    ha_device_class = "power_factor"
 
 
 class DPTPressure(DPT4ByteFloat):
diff --git a/xknx/dpt/dpt_4byte_int.py b/xknx/dpt/dpt_4byte_int.py
index ba1d2a38..f5d41cc8 100644
--- a/xknx/dpt/dpt_4byte_int.py
+++ b/xknx/dpt/dpt_4byte_int.py
@@ -120,6 +120,7 @@ class DPTActiveEnergy(DPT4ByteSigned):
     dpt_sub_number = 10
     value_type = "active_energy"
     unit = "Wh"
+    ha_device_class = "energy"
 
 
 class DPTApparantEnergy(DPT4ByteSigned):
@@ -129,6 +130,7 @@ class DPTApparantEnergy(DPT4ByteSigned):
     dpt_sub_number = 11
     value_type = "apparant_energy"
     unit = "VAh"
+    ha_device_class = "energy"
 
 
 class DPTReactiveEnergy(DPT4ByteSigned):
@@ -138,6 +140,7 @@ class DPTReactiveEnergy(DPT4ByteSigned):
     dpt_sub_number = 12
     value_type = "reactive_energy"
     unit = "VARh"
+    ha_device_class = "energy"
 
 
 class DPTActiveEnergykWh(DPT4ByteSigned):
@@ -147,6 +150,7 @@ class DPTActiveEnergykWh(DPT4ByteSigned):
     dpt_sub_number = 13
     value_type = "active_energy_kwh"
     unit = "kWh"
+    ha_device_class = "energy"
 
 
 class DPTApparantEnergykVAh(DPT4ByteSigned):
@@ -156,6 +160,7 @@ class DPTApparantEnergykVAh(DPT4ByteSigned):
     dpt_sub_number = 14
     value_type = "apparant_energy_kvah"
     unit = "kVAh"
+    ha_device_class = "energy"
 
 
 class DPTReactiveEnergykVARh(DPT4ByteSigned):
@@ -165,6 +170,7 @@ class DPTReactiveEnergykVARh(DPT4ByteSigned):
     dpt_sub_number = 15
     value_type = "reactive_energy_kvarh"
     unit = "kVARh"
+    ha_device_class = "energy"
 
 
 class DPTLongDeltaTimeSec(DPT4ByteSigned):


Test patch:
diff --git a/test/devices_tests/sensor_test.py b/test/devices_tests/sensor_test.py
index ad928f3c..26dc7079 100644
--- a/test/devices_tests/sensor_test.py
+++ b/test/devices_tests/sensor_test.py
@@ -224,7 +224,7 @@ class TestSensor(unittest.TestCase):
 
         self.assertEqual(sensor.resolve_state(), 641157503)
         self.assertEqual(sensor.unit_of_measurement(), "Wh")
-        self.assertEqual(sensor.ha_device_class(), None)
+        self.assertEqual(sensor.ha_device_class(), "energy")
 
     def test_str_active_energy_kwh(self):
         """Test resolve state with active_energy_kwh sensor."""
@@ -246,7 +246,7 @@ class TestSensor(unittest.TestCase):
 
         self.assertEqual(sensor.resolve_state(), 923076074)
         self.assertEqual(sensor.unit_of_measurement(), "kWh")
-        self.assertEqual(sensor.ha_device_class(), None)
+        self.assertEqual(sensor.ha_device_class(), "energy")
 
     def test_str_activity(self):
         """Test resolve state with activity sensor."""
@@ -422,7 +422,7 @@ class TestSensor(unittest.TestCase):
 
         self.assertEqual(sensor.resolve_state(), -742580571)
         self.assertEqual(sensor.unit_of_measurement(), "VAh")
-        self.assertEqual(sensor.ha_device_class(), None)
+        self.assertEqual(sensor.ha_device_class(), "energy")
 
     def test_str_apparant_energy_kvah(self):
         """Test resolve state with apparant_energy_kvah sensor."""
@@ -444,7 +444,7 @@ class TestSensor(unittest.TestCase):
 
         self.assertEqual(sensor.resolve_state(), 1228982537)
         self.assertEqual(sensor.unit_of_measurement(), "kVAh")
-        self.assertEqual(sensor.ha_device_class(), None)
+        self.assertEqual(sensor.ha_device_class(), "energy")
 
     def test_str_area(self):
         """Test resolve state with area sensor."""
@@ -1794,7 +1794,7 @@ class TestSensor(unittest.TestCase):
 
         self.assertEqual(sensor.resolve_state(), -2898.508056640625)
         self.assertEqual(sensor.unit_of_measurement(), "cosΦ")
-        self.assertEqual(sensor.ha_device_class(), None)
+        self.assertEqual(sensor.ha_device_class(), "power_factor")
 
     def test_str_ppm(self):
         """Test resolve state with ppm sensor."""
@@ -1917,7 +1917,7 @@ class TestSensor(unittest.TestCase):
 
         self.assertEqual(sensor.resolve_state(), 441019815)
         self.assertEqual(sensor.unit_of_measurement(), "VARh")
-        self.assertEqual(sensor.ha_device_class(), None)
+        self.assertEqual(sensor.ha_device_class(), "energy")
 
     def test_str_reactive_energy_kvarh(self):
         """Test resolve state with reactive_energy_kvarh sensor."""
@@ -1939,7 +1939,7 @@ class TestSensor(unittest.TestCase):
 
         self.assertEqual(sensor.resolve_state(), -865991375)
         self.assertEqual(sensor.unit_of_measurement(), "kVARh")
-        self.assertEqual(sensor.ha_device_class(), None)
+        self.assertEqual(sensor.ha_device_class(), "energy")
 
     def test_str_resistance(self):
         """Test resolve state with resistance sensor."""
diff --git a/test/dpt_tests/dpt_float_test.py b/test/dpt_tests/dpt_float_test.py
index 65743367..a583fe4f 100644
--- a/test/dpt_tests/dpt_float_test.py
+++ b/test/dpt_tests/dpt_float_test.py
@@ -131,7 +131,7 @@ class TestDPTFloat(unittest.TestCase):
         self.assertEqual(DPTTemperature().value_min, -273)
         self.assertEqual(DPTTemperature().value_max, 670760)
         self.assertEqual(DPTTemperature().unit, "°C")
-        self.assertEqual(DPTTemperature().resolution, 1)
+        self.assertEqual(DPTTemperature().resolution, 0.01)
 
     def test_temperature_assert_min_exceeded(self):
         """Testing parsing of DPTTemperature with wrong value."""
@@ -151,7 +151,7 @@ class TestDPTFloat(unittest.TestCase):
         self.assertEqual(DPTLux().value_min, 0)
         self.assertEqual(DPTLux().value_max, 670760)
         self.assertEqual(DPTLux().unit, "lx")
-        self.assertEqual(DPTLux().resolution, 1)
+        self.assertEqual(DPTLux().resolution, 0.01)
 
     def test_lux_assert_min_exceeded(self):
         """Test parsing of DPTLux with wrong value."""
@@ -166,7 +166,7 @@ class TestDPTFloat(unittest.TestCase):
         self.assertEqual(DPTHumidity().value_min, 0)
         self.assertEqual(DPTHumidity().value_max, 670760)
         self.assertEqual(DPTHumidity().unit, "%")
-        self.assertEqual(DPTHumidity().resolution, 1)
+        self.assertEqual(DPTHumidity().resolution, 0.01)
 
     def test_humidity_assert_min_exceeded(self):
         """Test parsing of DPTHumidity with wrong value."""