ソースを参照

Prefer non-legacy types.

Instead of searching through all config files for legacy types, first try
loading the config of that name directly. Only if that fails revert to using
legacy types.

This should speed up loading of non-legacy devices.  Later changes will save
the non-legacy type in the config, and migrate existing config entries.
Jason Rumney 4 年 前
コミット
c57c7bde70

+ 2 - 2
custom_components/tuya_local/climate.py

@@ -10,7 +10,7 @@ from .const import (
     CONF_TYPE,
 )
 from .generic.climate import TuyaLocalClimate
-from .helpers.device_config import config_for_legacy_use
+from .helpers.device_config import get_config
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -20,7 +20,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
     data = hass.data[DOMAIN][discovery_info[CONF_DEVICE_ID]]
     device = data["device"]
 
-    cfg = config_for_legacy_use(discovery_info[CONF_TYPE])
+    cfg = get_config(discovery_info[CONF_TYPE])
     if cfg is None:
         raise ValueError(f"No device config found for {discovery_info}")
     ecfg = cfg.primary_entity

+ 3 - 3
custom_components/tuya_local/config_flow.py

@@ -8,7 +8,7 @@ from homeassistant.core import HomeAssistant, callback
 from . import DOMAIN
 from .device import TuyaLocalDevice
 from .const import CONF_DEVICE_ID, CONF_LOCAL_KEY, CONF_TYPE
-from .helpers.device_config import config_for_legacy_use
+from .helpers.device_config import get_config
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -94,7 +94,7 @@ class ConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
             return self.async_create_entry(
                 title=title, data={**self.data, **user_input}
             )
-        config = config_for_legacy_use(self.data[CONF_TYPE])
+        config = get_config(self.data[CONF_TYPE])
         schema = {vol.Required(CONF_NAME, default=config.name): str}
         e = config.primary_entity
         schema[vol.Optional(e.entity, default=True)] = bool
@@ -137,7 +137,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
             vol.Required(CONF_LOCAL_KEY, default=config.get(CONF_LOCAL_KEY, "")): str,
             vol.Required(CONF_HOST, default=config.get(CONF_HOST, "")): str,
         }
-        cfg = config_for_legacy_use(config[CONF_TYPE])
+        cfg = get_config(config[CONF_TYPE])
         if cfg is None:
             return self.async_abort(reason="not_supported")
         e = cfg.primary_entity

+ 2 - 2
custom_components/tuya_local/fan.py

@@ -10,7 +10,7 @@ from .const import (
     CONF_TYPE,
 )
 from .generic.fan import TuyaLocalFan
-from .helpers.device_config import config_for_legacy_use
+from .helpers.device_config import get_config
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -20,7 +20,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
     data = hass.data[DOMAIN][discovery_info[CONF_DEVICE_ID]]
     device = data["device"]
 
-    cfg = config_for_legacy_use(discovery_info[CONF_TYPE])
+    cfg = get_config(discovery_info[CONF_TYPE])
     if cfg is None:
         raise ValueError(f"No device config found for {discovery_info}")
     ecfg = cfg.primary_entity

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

@@ -4,7 +4,7 @@ Config parser for Tuya Local devices.
 from fnmatch import fnmatch
 import logging
 from os import walk
-from os.path import join, dirname, splitext
+from os.path import join, dirname, splitext, exists
 from pydoc import locate
 
 from homeassistant.util.yaml import load_yaml
@@ -536,6 +536,19 @@ def possible_matches(dps):
             yield parsed
 
 
+def get_config(conf_type):
+    """
+    Return a config to use with config_type.
+    """
+    _CONFIG_DIR = dirname(config_dir.__file__)
+    fname = conf_type + ".yaml"
+    fpath = join(_CONFIG_DIR, fname)
+    if exists(fpath):
+        return TuyaDeviceConfig(fname)
+    else:
+        return config_for_legacy_use(conf_type)
+
+
 def config_for_legacy_use(conf_type):
     """
     Return a config to use with config_type for legacy transition.

+ 2 - 2
custom_components/tuya_local/humidifier.py

@@ -10,7 +10,7 @@ from .const import (
     CONF_TYPE,
 )
 from .generic.humidifier import TuyaLocalHumidifier
-from .helpers.device_config import config_for_legacy_use
+from .helpers.device_config import get_config
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -20,7 +20,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
     data = hass.data[DOMAIN][discovery_info[CONF_DEVICE_ID]]
     device = data["device"]
 
-    cfg = config_for_legacy_use(discovery_info[CONF_TYPE])
+    cfg = get_config(discovery_info[CONF_TYPE])
     if cfg is None:
         raise ValueError(f"No device config found for {discovery_info}")
     ecfg = cfg.primary_entity

+ 2 - 2
custom_components/tuya_local/light.py

@@ -10,7 +10,7 @@ from .const import (
     CONF_TYPE,
 )
 from .generic.light import TuyaLocalLight
-from .helpers.device_config import config_for_legacy_use
+from .helpers.device_config import get_config
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -20,7 +20,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
     data = hass.data[DOMAIN][discovery_info[CONF_DEVICE_ID]]
     device = data["device"]
 
-    cfg = config_for_legacy_use(discovery_info[CONF_TYPE])
+    cfg = get_config(discovery_info[CONF_TYPE])
     if cfg is None:
         raise ValueError(f"No device config found for {discovery_info}")
     ecfg = cfg.primary_entity

+ 2 - 2
custom_components/tuya_local/lock.py

@@ -10,7 +10,7 @@ from .const import (
     CONF_TYPE,
 )
 from .generic.lock import TuyaLocalLock
-from .helpers.device_config import config_for_legacy_use
+from .helpers.device_config import get_config
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -21,7 +21,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
     data = hass.data[DOMAIN][discovery_info[CONF_DEVICE_ID]]
     device = data["device"]
 
-    cfg = config_for_legacy_use(discovery_info[CONF_TYPE])
+    cfg = get_config(discovery_info[CONF_TYPE])
     if cfg is None:
         raise ValueError(f"No device config found for {discovery_info}")
     ecfg = cfg.primary_entity

+ 2 - 2
custom_components/tuya_local/switch.py

@@ -10,7 +10,7 @@ from .const import (
     CONF_TYPE,
 )
 from .generic.switch import TuyaLocalSwitch
-from .helpers.device_config import config_for_legacy_use
+from .helpers.device_config import get_config
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -20,7 +20,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
     data = hass.data[DOMAIN][discovery_info[CONF_DEVICE_ID]]
     device = data["device"]
 
-    cfg = config_for_legacy_use(discovery_info[CONF_TYPE])
+    cfg = get_config(discovery_info[CONF_TYPE])
     if cfg is None:
         raise ValueError(f"No device config found for {discovery_info}")
     ecfg = cfg.primary_entity

+ 9 - 9
tests/test_device_config.py

@@ -6,7 +6,7 @@ from warnings import warn
 
 from custom_components.tuya_local.helpers.device_config import (
     available_configs,
-    config_for_legacy_use,
+    get_config,
     possible_matches,
     TuyaDeviceConfig,
 )
@@ -51,7 +51,7 @@ class TestDeviceConfig(IsolatedAsyncioTestCase):
 
     def test_match_quality(self):
         """Test the match_quality function."""
-        cfg = config_for_legacy_use("deta_fan")
+        cfg = get_config("deta_fan")
         q = cfg.match_quality({**KOGAN_HEATER_PAYLOAD, "updated_at": 0})
         self.assertEqual(q, 0)
         q = cfg.match_quality({**GPPH_HEATER_PAYLOAD})
@@ -59,14 +59,14 @@ class TestDeviceConfig(IsolatedAsyncioTestCase):
 
     def test_entity_find_unknown_dps_fails(self):
         """Test that finding a dps that doesn't exist fails."""
-        cfg = config_for_legacy_use("kogan_switch")
+        cfg = get_config("kogan_switch")
         non_existing = cfg.primary_entity.find_dps("missing")
         self.assertIsNone(non_existing)
 
     async def test_dps_async_set_readonly_value_fails(self):
         """Test that setting a readonly dps fails."""
         mock_device = MagicMock()
-        cfg = config_for_legacy_use("kogan_switch")
+        cfg = get_config("kogan_switch")
         voltage = cfg.primary_entity.find_dps("voltage_v")
         with self.assertRaises(TypeError):
             await voltage.async_set_value(mock_device, 230)
@@ -74,20 +74,20 @@ class TestDeviceConfig(IsolatedAsyncioTestCase):
     def test_dps_values_returns_none_with_no_mapping(self):
         """Test that a dps with no mapping returns None as its possible values"""
         mock_device = MagicMock()
-        cfg = config_for_legacy_use("kogan_switch")
+        cfg = get_config("kogan_switch")
         voltage = cfg.primary_entity.find_dps("voltage_v")
         self.assertIsNone(voltage.values(mock_device))
 
     # Test detection of all devices.
 
-    def _test_detect(self, payload, legacy_type, legacy_class):
+    def _test_detect(self, payload, dev_type, legacy_class):
         """Test that payload is detected as the correct type and class."""
         matched = False
         false_matches = []
         quality = 0
         for cfg in possible_matches(payload):
             self.assertTrue(cfg.matches(payload))
-            if cfg.legacy_type == legacy_type:
+            if cfg.legacy_type == dev_type:
                 self.assertFalse(matched)
                 matched = True
                 quality = cfg.match_quality(payload)
@@ -108,7 +108,7 @@ class TestDeviceConfig(IsolatedAsyncioTestCase):
 
         self.assertTrue(matched)
         if quality < 100:
-            warn(f"{legacy_type} detected with imperfect quality {quality}%")
+            warn(f"{dev_type} detected with imperfect quality {quality}%")
 
         best_q = 0
         for cfg in false_matches:
@@ -119,7 +119,7 @@ class TestDeviceConfig(IsolatedAsyncioTestCase):
         self.assertGreater(quality, best_q)
 
         # Ensure the same correct config is returned when looked up by type
-        cfg = config_for_legacy_use(legacy_type)
+        cfg = get_config(dev_type)
         if legacy_class is not None:
             cfg_class = cfg.primary_entity.legacy_class
             if cfg_class is None: