Repository: pwr-Solaar/Solaar

Issue:
Solaar stoped detect my K480 keyboard after update
**Information**
<!-- Make sure that your issue is not one of the known issues in the Solaar documentation at https://pwr-solaar.github.io/Solaar/ -->
<!-- Do not bother opening an issue for a version older than 1.0.6.  Please update to the latest version and see if your issue persists. -->
- Solaar version: 1.0.6+git1388-3f33d06~ubuntu20.04.1
- Distribution: Linux Lite 5.4 (Ubuntu 20.04.1 LTS based)
- Kernel version (ex. `uname -srmo`): Linux 5.8.5-050805-generic x86_64 GNU/Linux
- Output of `solaar show`: 

```
  Wired Devices
  1: ?? (B33D)
     Device path  : /dev/hidraw2
     USB id       : 046d:B33D
     Codename     : ?? (B33D)
solaar: error: Traceback (most recent call last):
  File "/usr/share/solaar/lib/solaar/cli/__init__.py", line 207, in run
    m.run(c, args, _find_receiver, _find_device)
  File "/usr/share/solaar/lib/solaar/cli/show.py", line 292, in run
    _print_device(d, num=dev_num)
  File "/usr/share/solaar/lib/solaar/cli/show.py", line 101, in _print_device
    print('     Kind         :', dev.kind)
  File "/usr/share/solaar/lib/logitech_receiver/device.py", line 260, in kind
    self._kind = KIND_MAP[_hidpp20.get_kind(self)]
KeyError: None
```

- 

<details>

```
OUTPUT HERE
```
</details>

**Describe the bug**
After a few updates from apt, Solaar won't detect my K480 Keyboard anymore. I turned off, and turned on again, and won't works...

I also have a M535 mouse, Solaar is working with it like a charm.

Thanks in advance,
Samuel. (samuckadf)

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Additional context**
Add any other context about the problem here.



Discussion:
I think I know what might be going on.  Please provide output from `solaar -dd show` so that I can see the interaction with the device.

Resolving patch:
diff --git a/lib/logitech_receiver/base.py b/lib/logitech_receiver/base.py
--- a/lib/logitech_receiver/base.py
+++ b/lib/logitech_receiver/base.py
@@ -381,7 +381,7 @@ def acquire_timeout(lock, handle, timeout):
 
 
 # a very few requests (e.g., host switching) do not expect a reply, but use no_reply=True with extreme caution
-def request(handle, devnumber, request_id, *params, no_reply=False, return_error=False, long_message=False):
+def request(handle, devnumber, request_id, *params, no_reply=False, return_error=False, long_message=False, protocol=1.0):
     """Makes a feature call to a device and waits for a matching reply.
     :param handle: an open UR handle.
     :param devnumber: attached device number.
@@ -395,7 +395,7 @@ def request(handle, devnumber, request_id, *params, no_reply=False, return_error
 
     with acquire_timeout(handle_lock(handle), handle, 10.):
         assert isinstance(request_id, int)
-        if devnumber != 0xFF and request_id < 0x8000:
+        if (devnumber != 0xFF or protocol >= 2.0) and request_id < 0x8000:
             # For HID++ 2.0 feature requests, randomize the SoftwareId to make it
             # easier to recognize the reply for this request. also, always set the
             # most significant bit (8) in SoftwareId, to make notifications easier
diff --git a/lib/logitech_receiver/device.py b/lib/logitech_receiver/device.py
--- a/lib/logitech_receiver/device.py
+++ b/lib/logitech_receiver/device.py
@@ -198,6 +198,8 @@ def codename(self):
         if not self._codename:
             if self.online and self.protocol >= 2.0:
                 self._codename = _hidpp20.get_friendly_name(self)
+                if not self._codename:
+                    self._codename = self.name.split(' ', 1)[0] if self.name else None
             elif self.receiver:
                 codename = self.receiver.read_register(_R.receiver_info, _IR.device_name + self.number - 1)
                 if codename:
@@ -213,7 +215,7 @@ def name(self):
         if not self._name:
             if self.online and self.protocol >= 2.0:
                 self._name = _hidpp20.get_name(self)
-        return self._name or self.codename or ('Unknown device %s' % (self.wpid or self.product_id))
+        return self._name or self._codename or ('Unknown device %s' % (self.wpid or self.product_id))
 
     @property
     def unitId(self):
@@ -257,7 +259,8 @@ def kind(self):
                 kind = ord(pair_info[7:8]) & 0x0F
                 self._kind = _hidpp10.DEVICE_KIND[kind]
             elif self.online and self.protocol >= 2.0:
-                self._kind = KIND_MAP[_hidpp20.get_kind(self)]
+                kind = _hidpp20.get_kind(self)
+                self._kind = KIND_MAP[kind] if kind else None
         return self._kind or '?'
 
     @property
@@ -432,7 +435,6 @@ def handle_notification(self, n) -> Optional[bool]:
         return None
 
     def request(self, request_id, *params, no_reply=False):
-
         if self:
             return _base.request(
                 self.handle or self.receiver.handle,
@@ -440,7 +442,8 @@ def request(self, request_id, *params, no_reply=False):
                 request_id,
                 *params,
                 no_reply=no_reply,
-                long_message=self.bluetooth or self.protocol >= 2.0
+                long_message=self.bluetooth or self.protocol >= 2.0,
+                protocol=self.protocol
             )
 
     def feature_request(self, feature, function=0x00, *params, no_reply=False):
diff --git a/lib/solaar/cli/show.py b/lib/solaar/cli/show.py
--- a/lib/solaar/cli/show.py
+++ b/lib/solaar/cli/show.py
@@ -196,9 +196,11 @@ def _print_device(dev, num=None):
                 if wheel_status:
                     print('            Wheel Reports: %s' % wheel_status)
             elif feature == _hidpp20.FEATURE.NEW_FN_INVERSION:
-                inverted, default_inverted = _hidpp20.get_new_fn_inversion(dev)
-                print('            Fn-swap:', 'enabled' if inverted else 'disabled')
-                print('            Fn-swap default:', 'enabled' if default_inverted else 'disabled')
+                inversion = _hidpp20.get_new_fn_inversion(dev)
+                if inversion:
+                    inverted, default_inverted = inversion
+                    print('            Fn-swap:', 'enabled' if inverted else 'disabled')
+                    print('            Fn-swap default:', 'enabled' if default_inverted else 'disabled')
             elif feature == _hidpp20.FEATURE.HOSTS_INFO:
                 host_names = _hidpp20.get_host_names(dev)
                 for host, (paired, name) in host_names.items():
@@ -206,6 +208,8 @@ def _print_device(dev, num=None):
             elif feature == _hidpp20.FEATURE.DEVICE_NAME:
                 print('            Name: %s' % _hidpp20.get_name(dev))
                 print('            Kind: %s' % _hidpp20.get_kind(dev))
+            elif feature == _hidpp20.FEATURE.DEVICE_FRIENDLY_NAME:
+                print('            Friendly Name: %s' % _hidpp20.get_friendly_name(dev))
             elif feature == _hidpp20.FEATURE.DEVICE_FW_VERSION:
                 for fw in _hidpp20.get_firmware(dev):
                     extras = _strhex(fw.extras) if fw.extras else ''


Test patch: