Repository: pwr-Solaar/Solaar

Issue:
Device equality test depends on wpid which may not be present
**Information**
- Solaar version (`solaar --version` or `git describe --tags` if cloned from this repository): 1.1.10
- Distribution: ArchLinux
- Kernel version (ex. `uname -srmo`): `Linux 6.5.7-arch1-1 x86_64 GNU/Linux`
- Output of `solaar show`: N/A

- Contents of `~/.config/solaar/config.yaml` (or `~/.config/solaar/config.json` if `~/.config/solaar/config.yaml` not present): 
<details>

```yaml
%YAML 1.3
---
- Device: 4F000000
- MouseClick: [left, 1]
...
```

</details>

- Errors or warrnings from Solaar: N/A


**Describe the bug**

Currently, the equality test of Device (`lib/logitech_receiver/diversion.py`) depends on its equality of `_kind` and `wpid`:

```python
def __eq__(self, other):
    return other is not None and self._kind == other._kind and self.wpid == other.wpid
```

However, for devices connected via Bluetooth, `wpid` is None. That means multiple devices of the same kind connected via Bluetooth would be considered equal. I don't know what other problem this might cause, but one problem this causes is with the Device condition in rules. For example, if 2 keyboards are connected simultaneously, and a rule is configured with a Device condition for one keyboard, then a notification from the other device would match that condition erroneously.

I'm hesitent to send a PR that replaces the above function with

```python
def __eq__(self, other):
    return other is not None and self.id == other.id
```

because I don't know if this will break for cases or devices I'm unaware of. And d4d4574 suggests that using fields that may require communication is undesired for some reason.

If the above change is good, I'll happily send a PR, otherwise please suggest on what field should be used instead of equality test.

**To Reproduce**
Steps to reproduce the behavior:
1. Connect 2 keyboards via Bluetooth, referred to as 4F000000 and 9CD7F863
2. Configure a rule with a Device condition set to 4F000000:
  ```yaml
  ---
  - Device: 4F000000
  - MouseClick: [left, 1]
  ```
3. Divert some key on both keyboards
4. Press a key on 9CD7F863.
5. See that the rule above has been trigerred:

```
2023-10-16 02:02:16,566,566    DEBUG [ReceiverListener:hidraw12] logitech_receiver.base: (16) => r[11 FF 0800 00000000000000000000000000000000]
2023-10-16 02:02:16,566,566    DEBUG [ReceiverListener:hidraw12] logitech_receiver.notifications: <Device(255,B365,Logi POP Keys,9CD7F863)>: notification for feature REPROG CONTROLS V4, report 0, data 00000000000000000000000000000000
2023-10-16 02:02:16,566,566    DEBUG [ReceiverListener:hidraw12] logitech_receiver.notifications: <Device(255,B365,Logi POP Keys,9CD7F863)>: diverted controls pressed: 0x0, 0x0, 0x0, 0x0
2023-10-16 02:02:16,566,566    DEBUG [MainThread] logitech_receiver.diversion: evaluating rules on Notification(11,255,08,00,00000000000000000000000000000000)
2023-10-16 02:02:16,567,567    DEBUG [MainThread] logitech_receiver.diversion: evaluate rule: Rule[Rule(/home/alex/.config/solaar/rules.yaml)[Rule(/home/alex/.config/solaar/rules.yaml)[Device: 4F000000, MouseClick: left (1)]], Rule[Rule[Rule[Key: Brightness Down (pressed), KeyPress: XF86_MonBrightnessDown click], Rule[Key: Brightness Up (pressed), KeyPress: XF86_MonBrightnessUp click]]]]
2023-10-16 02:02:16,567,567    DEBUG [MainThread] logitech_receiver.diversion: evaluate rule: Rule(/home/alex/.config/solaar/rules.yaml)[Rule(/home/alex/.config/solaar/rules.yaml)[Device: 4F000000, MouseClick: left (1)]]
2023-10-16 02:02:16,567,567    DEBUG [MainThread] logitech_receiver.diversion: evaluate rule: Rule(/home/alex/.config/solaar/rules.yaml)[Device: 4F000000, MouseClick: left (1)]
2023-10-16 02:02:16,567,567    DEBUG [MainThread] logitech_receiver.diversion: evaluate condition: Device: 4F000000
2023-10-16 02:02:16,567,567     INFO [MainThread] logitech_receiver.diversion: MouseClick action: 1 left
2023-10-16 02:02:16,568,568    DEBUG [MainThread] logitech_receiver.diversion: xtest simulated input <Xlib.display.Display object at 0x7fbceec29050> 4 1
2023-10-16 02:02:16,570,570    DEBUG [MainThread] logitech_receiver.diversion: xtest simulated input <Xlib.display.Display object at 0x7fbceec29050> 5 1
```


Discussion:
Yes, this looks like a bug.   The equality test doesn't even work right for any device as wpid is for a device model, not an individual device.  The solution, I think, is to not use device equality in the Device rule condition.

Resolving patch:
diff --git a/lib/logitech_receiver/diversion.py b/lib/logitech_receiver/diversion.py
--- a/lib/logitech_receiver/diversion.py
+++ b/lib/logitech_receiver/diversion.py
@@ -1051,8 +1051,7 @@ def __str__(self):
     def evaluate(self, feature, notification, device, status, last_result):
         if _log.isEnabledFor(_DEBUG):
             _log.debug('evaluate condition: %s', self)
-        dev = _Device.find(self.devID)
-        return device == dev
+        return device.unitId == self.devID or device.serial == self.devID
 
     def data(self):
         return {'Device': self.devID}


Test patch: