Centurion transport reuses HID++ 2.0 feature IDs 0x0000, 0x0001,
0x0003, 0x0005, 0x0007 with different meanings. Since SupportedFeature
(IntEnum) requires unique values, create a separate CenturionCoreFeature
enum and resolve_feature() helper for transport-aware lookup.
Also replace the +0x100 offset hack in FeaturesArray.inverse with a
dedicated sub_inverse dict for sub-device feature indexing.
The HID++ ping math (major + minor/10.0) produced a bogus "2.6" for
Centurion devices whose ProtocolCapabilities returns major=1, minor=0x10.
Store the raw (major, minor) bytes from the ping response and display
them correctly as "Centurion 1.16" in both CLI and GUI.
Replace ad-hoc heuristics with proper bridge event function dispatch:
- Function 0 (ConnectionStateChangedEvent): parse sub-device list length
to determine connect (len>0) vs disconnect (len=0)
- Function 1 (MessageEvent): fallback online detection if headset sends
a message while marked offline (handles cold-start power-on)
Remove CPL sub_id>=0x80 fallback in listener that misidentified HID++
error replies as disconnect events. Skip HID++ 1.0
set_configuration_pending_flags for CenturionReceiver (not supported).
Also adds OnboardEQ (0x0636) support, bridge multi-fragment sends,
bridge-based headset ping probe, and CLI offline display.
- Add CenturionReceiver class that provides the Receiver UI interface so
the dongle appears as a parent with the headset indented underneath,
matching how Lightspeed/Unifying receivers display
- Independently probe dongle features via feature_request() on the
CenturionReceiver, separate from headset features via bridge
- Fix bridge notification dispatch: remove incorrect sub_cpl=0xFF filter
that was silently dropping all battery and other notifications
- Fix battery status decoding: charging status is at byte 2 (not byte 1)
of the CENTURION_BATTERY_SOC response
- Detect wired vs wireless by checking for CentPPBridge in discovered
features; wired headsets fall back to standalone Device
- Name the dongle "Centurion Receiver" to distinguish from the headset
- Filter unprintable dongle serial (control characters 0x14-0x1F)
- Update CLI show output with proper receiver/child hierarchy and spacing
Replace the hardcoded descriptor entry with dynamic discovery of all device
properties via the Centurion protocol. The headset name, kind, serial,
firmware, and battery are now probed at runtime — matching how the device
actually presents itself rather than relying on static data.
Key changes:
- Discover sub-device features via CentPPBridge and route requests through
the bridge automatically
- Infer device kind from feature IDs (0x06xx = headset) for both wireless
and direct USB connections
- Read device name from USB product string with protocol probe fallback
- Parse bridge error responses (sub_feat_idx=0xFF) instead of timing out
- Handle unknown HID++ error codes gracefully in base.py
- Fix firmware deduplication for Centurion parent devices
- Prefer sub-device serial/firmware over parent (non-printable) values
- Add Centurion-aware display in solaar show with parent/sub-device sections
- Support both wireless (0AF7 dongle) and direct USB (0AF8) connections
Fixes "solaar show" for hidpp10 device (or at least for 27MHz FastRF
hidpp10 peripherals).
Fixes: 72c9dfc5 Remove NamedInts: Convert NotificationFlag to flag
Logger enabled checks clutter the code unnecessarily. The checks are
now handled in a custom logger class. Eventually they can be completely
removed in the future.
Related #2664
* refactoring(logitech_receiver/notifications): change to enums PairingError and BoltPairingError
* refactoring(logitech_receiver/notifications): change to enums PairingError and BoltPairingError (Fix pre-commit checks)
* refactor(logitech_receiver/base.py): create unit tests for ping function before replacing ERRORNamedInts by IntEnum
* refactor(logitech_receiver/base.py): create unit tests for request function before replacing ERROR NamedInts by IntEnum
* refactor(logitech_receiver/base.py): create unit tests for ping function before replacing ERRORNamedInts by IntEnum (add exclusion for macOS)
* refactor(logitech_receiver/base.py): create unit tests for ping function before replacing ERRORNamedInts by IntEnum (fix for python < 3.10)
* refactor(solaar/cli./probe.py): create unit tests for run function before replacing ERROR NamedInts by IntEnum (focusing on the call order when receiving errors)
* refactor(solaar/cli./probe.py): refactor register processing to handle short and long registers in a single loop structure for improved readability and reduced code duplication.
* refactor(logitech_receiver/hidpp10_constants.py): replace ERROR NamedInt by IntEnum.
* refactor(logitech_receiver/hidpp10_constants.py): distinguish hidpp10 and hidpp20 errors in the code for readibility.
* refactor(logitech_receiver/hidpp20_constants.py): replace ERROR NamedInt by IntEnum.
* refactor(logitech_receiver/hidpp20_constants.py): replace ERROR NamedInt by IntEnum. (fix problem with | operator when typing with python 3.8)
* feature(hide on startup option): Visual test (not binded yet) DRAFT
* refactor(solaar/cli./probe.py): create unit tests for run function before replacing ERROR NamedInts by IntEnum (focusing on the call order when receiving errors)
* refactor(solaar/cli./probe.py): refactor register processing to handle short and long registers in a single loop structure for improved readability and reduced code duplication.
* refactor(logitech_receiver/hidpp10_constants.py): replace ERROR NamedInt by IntEnum.
* refactor(logitech_receiver/hidpp20_constants.py): replace ERROR NamedInt by IntEnum.
* refactor(logitech_receiver/hidpp20_constants.py): replace ERROR NamedInt by IntEnum. (fix problem with | operator when typing with python 3.8)
* feature(hide on startup option): Visual test (not binded yet) DRAFT
* Merge: Refactor: hidpp20 to use enum
* Merge: Refactor: hidpp20 to use enum (fix test)
---------
Co-authored-by: some_developer <some.developper.44@gmail.com>
* Remove duplicated Param definition
Use constants from hidpp20 constants
Related #2273
* hidpp20/Param: Refactor to use IntEnum
Related #2273
* hidpp20_constants: Refactor to use IntEnum
Related #2273
* Refactor: test_named_ints_flag_names
Shorten test and clarify behavior using binary numbers.
* Introduce plain flag_names function
This replicates the NamedInts functionality as plain function.
* Refactor FeatureFlag to use IntFlag
Replace NamedInts implementation with IntFlag enum and plain flag_names
function.
Related #2273
* Refactor FirmwareKind to use IntEnum
- Move general FirmwareKind to common module.
- Replace NamedInts implementation with IntEnum.
- Harden related HIDPP 1.0 get_firmware test.
Related #2273
* Refactor CID_GROUP, CID_GROUP_BIT to use IntEnum
Related #2273
Warnings found by automatic code inspection and partially tackled
- Drop distuitls inf favour of setuptools
- Replace deprecated pyudev.Device.from_device_number
- Remove unnecessary brackets
- Avoid access to private variables etc.
- Shadows built-in name
- Line length >120 characters
- Not a module level variable
- Simplify clause
and more
Avoid direct access to hidapi and use the base module as low-level API
instead. This change replaces the remaining calls to find_paired_node
and find_paired_node_wpid by exposing them via base module.
* Remove import as _ in solaar startup
Related #2273
* Remove import as _ in listener
Related #2273
* Remove import as _ in cli init
Related #2273
* Remove import as _ in gtk
Related #2273
* Remove import as _ in show
Related #2273
* Remove import as _ in tray
Related #2273
* Remove import as _ in profiles
Related #2273
* Remove import as _ in config
Related #2273
* Remove import as _ in config panel
Related #2273
* Remove import as _ in window
Related #2273
* Remove import as _ in pair
Related #2273
* Remove import as _ in pair window
Related #2273
* Remove import as _ in cli package
Related #2273
* Remove import as _ in ui package
Related #2273
* Remove commented out code
Related #2273
* Use constant for Logitech ID
* Refactor HID Register definitions
Use enums for distinct type hints, easy discovery of registers.
Make constants uppercase and benefit from enum auto-completion.
Related #2273
* Improve type hints: Registers