Repository: pwr-Solaar/Solaar

Issue:
config should be faster
solaar config is slow.

solaar config always determines all feature settings, which can be slow.

When using config to set a feature, don't bother to compute them all.


Discussion:

Resolving patch:
diff --git a/lib/logitech_receiver/settings_templates.py b/lib/logitech_receiver/settings_templates.py
--- a/lib/logitech_receiver/settings_templates.py
+++ b/lib/logitech_receiver/settings_templates.py
@@ -694,6 +694,23 @@ def _S(name, featureID=None, featureFn=None, registerFn=None, identifier=None):
 #
 
 
+def check_feature(device, name, featureId, featureFn):
+    """
+    :param name: name for the setting
+    :param featureId: the numeric Feature ID for this setting implementation
+    :param featureFn: the function for this setting implementation
+    """
+    if featureId not in device.features:
+        return
+    try:
+        detected = featureFn()(device)
+        if _log.isEnabledFor(_DEBUG):
+            _log.debug('check_feature[%s] detected %s', featureId, detected)
+        return detected
+    except Exception as reason:
+        _log.error('check_feature[%s] inconsistent feature %s', featureId, reason)
+
+
 # Returns True if device was queried to find features, False otherwise
 def check_feature_settings(device, already_known):
     """Try to auto-detect device settings by the HID++ 2.0 features they have."""
@@ -701,28 +718,16 @@ def check_feature_settings(device, already_known):
         return False
     if device.protocol and device.protocol < 2.0:
         return False
-
-    def check_feature(name, featureId, featureFn):
-        """
-        :param name: name for the setting
-        :param featureId: the numeric Feature ID for this setting implementation
-        :param featureFn: the function for this setting implementation
-        """
-        if featureId not in device.features:
-            return
-        if any(s.name == name for s in already_known):
-            return
-
-        try:
-            detected = featureFn()(device)
-            if _log.isEnabledFor(_DEBUG):
-                _log.debug('check_feature[%s] detected %s', featureId, detected)
-            if detected:
-                already_known.append(detected)
-        except Exception as reason:
-            _log.error('check_feature[%s] inconsistent feature %s', featureId, reason)
-
     for name, featureId, featureFn, __, __ in _SETTINGS_TABLE:
         if featureId and featureFn:
-            check_feature(name, featureId, featureFn)
+            if not any(s.name == name for s in already_known):
+                setting = check_feature(device, name, featureId, featureFn)
+                if setting:
+                    already_known.append(setting)
     return True
+
+
+def check_feature_setting(device, setting_name):
+    for name, featureId, featureFn, __, __ in _SETTINGS_TABLE:
+        if name == setting_name and featureId and featureFn:
+            return check_feature(device, name, featureId, featureFn)
diff --git a/lib/solaar/cli/config.py b/lib/solaar/cli/config.py
--- a/lib/solaar/cli/config.py
+++ b/lib/solaar/cli/config.py
@@ -20,6 +20,7 @@
 from __future__ import absolute_import, division, print_function, unicode_literals
 
 from logitech_receiver import settings as _settings
+from logitech_receiver import settings_templates as _settings_templates
 from solaar import configuration as _configuration
 
 
@@ -55,12 +56,12 @@ def run(receivers, args, find_receiver, find_device):
     if not dev.ping():
         raise Exception('%s is offline' % dev.name)
 
-    if not dev.settings:
-        raise Exception('no settings for %s' % dev.name)
-
-    _configuration.attach_to(dev)
-
-    if not args.setting:
+    if not args.setting:  # print all settings, so first set them all up
+        if not dev.settings:
+            raise Exception('no settings for %s' % dev.name)
+        _configuration.attach_to(dev)
+        for s in dev.settings:
+            s.apply()
         print(dev.name, '(%s) [%s:%s]' % (dev.codename, dev.wpid, dev.serial))
         for s in dev.settings:
             print('')
@@ -68,13 +69,11 @@ def run(receivers, args, find_receiver, find_device):
         return
 
     setting_name = args.setting.lower()
-    setting = None
-    for s in dev.settings:
-        if setting_name == s.name.lower():
-            setting = s
-            break
+    setting = _settings_templates.check_feature_setting(dev, setting_name)
     if setting is None:
         raise Exception("no setting '%s' for %s" % (args.setting, dev.name))
+    _configuration.attach_to(dev)
+    setting.apply()
 
     if args.value is None:
         _print_setting(setting)


Test patch: