Просмотр исходного кода

Fix the encoded length of masked datapoint values

Pusztai Tibor 2 лет назад
Родитель
Сommit
3ea0ab346a
2 измененных файлов с 59 добавлено и 1 удалено
  1. 2 1
      custom_components/tuya_local/helpers/device_config.py
  2. 57 0
      tests/test_device_config.py

+ 2 - 1
custom_components/tuya_local/helpers/device_config.py

@@ -866,8 +866,9 @@ class TuyaDpsConfig:
                 raise ValueError(f"{self.name} ({value}) must be between {mn} and {mx}")
 
         if mask and isinstance(result, Number):
+            # mask is in hex, 2 digits/characters per byte
+            length = int(len(mask) / 2)
             # Convert to int
-            length = len(mask)
             mask = int(mask, 16)
             mask_scale = mask & (1 + ~mask)
             current_value = int.from_bytes(self.decoded_value(device), "big")

+ 57 - 0
tests/test_device_config.py

@@ -414,6 +414,18 @@ class TestDeviceConfig(IsolatedAsyncioTestCase):
             bytes("Test", "utf-8"),
         )
 
+    def test_decoding_hex(self):
+        """Test that decoded_value works with hex encoding."""
+        mock_entity = MagicMock()
+        mock_config = {"id": "1", "name": "test", "type": "hex"}
+        mock_device = MagicMock()
+        mock_device.get_property.return_value = "babe"
+        cfg = TuyaDpsConfig(mock_entity, mock_config)
+        self.assertEqual(
+            cfg.decoded_value(mock_device),
+            b"\xba\xbe",
+        )
+
     def test_decoding_unencoded(self):
         """Test that decoded_value returns the raw value when not encoded."""
         mock_entity = MagicMock()
@@ -433,6 +445,13 @@ class TestDeviceConfig(IsolatedAsyncioTestCase):
         cfg = TuyaDpsConfig(mock_entity, mock_config)
         self.assertEqual(cfg.encode_value(bytes("Test", "utf-8")), "VGVzdA==")
 
+    def test_encoding_hex(self):
+        """Test that encode_value works with base64."""
+        mock_entity = MagicMock()
+        mock_config = {"id": "1", "name": "test", "type": "hex"}
+        cfg = TuyaDpsConfig(mock_entity, mock_config)
+        self.assertEqual(cfg.encode_value(b"\xca\xfe"), "cafe")
+
     def test_encoding_unencoded(self):
         """Test that encode_value works with base64."""
         mock_entity = MagicMock()
@@ -485,6 +504,44 @@ class TestDeviceConfig(IsolatedAsyncioTestCase):
         self.assertEqual("sub-id", get_device_id({"device_cid": "sub-id"}))
         self.assertEqual("s", get_device_id({"device_id": "d", "device_cid": "s"}))
 
+    def test_getting_masked_hex(self):
+        """Test that get_value works with masked hex encoding."""
+        mock_entity = MagicMock()
+        mock_config = {
+            "id": "1",
+            "name": "test",
+            "type": "hex",
+            "mapping": [
+                {"mask": "ff00"},
+            ],
+        }
+        mock_device = MagicMock()
+        mock_device.get_property.return_value = "babe"
+        cfg = TuyaDpsConfig(mock_entity, mock_config)
+        self.assertEqual(
+            cfg.get_value(mock_device),
+            0xBA,
+        )
+
+    def test_setting_masked_hex(self):
+        """Test that get_values_to_set works with masked hex encoding."""
+        mock_entity = MagicMock()
+        mock_config = {
+            "id": "1",
+            "name": "test",
+            "type": "hex",
+            "mapping": [
+                {"mask": "ff00"},
+            ],
+        }
+        mock_device = MagicMock()
+        mock_device.get_property.return_value = "babe"
+        cfg = TuyaDpsConfig(mock_entity, mock_config)
+        self.assertEqual(
+            cfg.get_values_to_set(mock_device, 0xCA),
+            {"1": "cabe"},
+        )
+
     def test_default_without_mapping(self):
         """Test that default returns None when there is no mapping"""
         mock_entity = MagicMock()