Commit Graph

115 Commits

Author SHA1 Message Date
Ken Sanislo ac7add6297 G522 LIGHTSPEED headphones support
End-to-end support for the G522 LIGHTSPEED gaming headset (and the
infrastructure that comes with it for related Centurion-bridged headsets).

Hardware/protocol layer:

- centurion.py — CenturionReceiver: lightweight receiver-like wrapper
  for Centurion-bridged dongles (PRO X 2 LIGHTSPEED already, G522 added
  here). Handles deferred init for 0x50 devices that don't respond to
  the initial probe, sub-device feature discovery via bridge, online
  detection via ping.

- base.py — Centurion handle state, device_addr probe (256-candidate
  scan), 0x50/0x51 frame routing, bridge TX/RX framing.

- hidpp20.py — Centurion sub-device feature query and bridge request
  routing. CENTURION_DEVICE_INFO / CENTURION_BATTERY_SOC / CENTURION_*
  query helpers in centurion.py for parent + sub paths.

- device.py — Centurion device creation path, USB product-string
  fallback for naming, bridge sub-device error handling.

- notifications.py — HEADSET_ADVANCED_PARA_EQ band-change events,
  HEADSET_MIC_MUTE state-change events; both route to the relevant
  setting via setting_callback.

Headset settings:

- HeadsetEcoMode, HeadsetDoNotDisturb, HeadsetMicMute, HeadsetMicSNR,
  HeadsetAINR / HeadsetAINRLevel, HeadsetSidetone, HeadsetMicGain,
  HeadsetMixBalance, HeadsetAutoSleep — bool / range / choice settings
  for the headset-specific feature pages.

- HeadsetOnboardEQ + HeadsetActiveEQPreset — onboard EQ slot picker
  with active-preset tracking via the EQ change event subscription.

- HeadsetAdvancedEQ — multi-band parametric EQ (advanced_para_eq.py
  module handles getEQInfos / getCustomEQ / band-change subscription;
  setting builds the per-band sliders).

- HeadsetLEDControl + HeadsetLedsPrimary + HeadsetPerZoneLighting —
  RGB feature set (0x0620 HEADSET_RGB_HOSTMODE) with shared zone-write
  helper (headset_rgb.py) and the G522 layout for the per-key painter
  (perkey/layouts/headset_g522.py).

- LogiVoice family (12 settings: NR / NG / Compressor / De-esser /
  Depopper / Limiter / HPF, each with state + parameters) — voice
  processing pipeline. logivoice.py module handles probe + parsing.

Probes:

- rgb_effects_probe.py — runtime probe for headset RGB feature
  variants (0x0621 onboard-effects, 0x0622 signature-effects, 0x0623).

Tests:

- test_base.py / test_device.py / test_hidpp20_complex.py — Centurion
  framing, device-creation path, sub-device feature parsing.

- test_setting_templates.py — fixtures for the new headset settings.

Closes pwr-Solaar/Solaar#3181.
2026-05-21 10:13:00 -04:00
Ken Sanislo 3df2a30f30 Add RGB lighting persistence and software LED power management for G515
Software-managed LED persistence and power management for devices that
expose RGBEffects (0x8071) — primarily G515 LIGHTSPEED TKL, but the same
infrastructure works on any 0x8071 device that supports SW takeover.

Core mechanism: RGBControl toggle drives a Set SWControl(mode=3, flags)
handshake. While SW control is held, the host owns the LED pipeline: zone
effects, per-key paint, idle/sleep transitions, and the NvConfig boot/exit
animations. On release, the firmware resumes its onboard profile.

Major pieces:

- rgb_power.py — new module hosting the software RGB power manager:
  ACTIVE / DIMMING / IDLE / SLEEPING state machine driven by firmware
  onUserActivity events, smooth 5-second dim ramp (zone or per-key), idle
  Static color snap, software sleep timer, wake handler that re-pushes
  saved state. Includes the cleanup hook that runs on device close (and,
  optionally, fires the cap 0x0040 shutdown trigger).

- RGBControl (settings_templates) — switch-style render via BooleanValidator
  (true_value=3 / false_value=0) plus a full _claim_sw_control /
  _release_sw_control pair: profile-management mode, SetSWControl, per-key
  flag reset, manager start, cleanup registration, and a post-claim
  repaint pass so the device immediately reflects Solaar's saved zone +
  per-key state.

- RGBEffectSetting — zone-effect Setting subclass for 0x8071. Handles
  per-key/zone coexistence: per-key paint dominates only when zone is
  Static and the user has explicitly opted in via the lock icon; under
  animations or before opt-in, the zone wire push is the visible layer.

- RGBIdleEffect / RGBIdleTimeout / RGBSleepTimeout — Solaar-managed idle
  behavior. Choice list: "No change" → Dim → Static (snap to color) →
  device-specific animations. Static idle substitutes the idle color for
  unset per-key cells via effective_zone_base_color's state-aware lookup.

- RgbStartupAnimation / RgbShutdownAnimation — toggle-and-color rows for
  RGBEffects NvConfig caps 0x0001 and 0x0040, exposed only on devices
  that answer the probe. Shutdown trigger fires SetRgbPowerMode(0) at
  cleanup time so the firmware plays the configured animation on exit.

- PerKeyLighting — per-key painter improvements: explicit-opt-in
  dominance over zone effects, BUSY retry, FrameEnd suppression on
  per-cell failure, single-shot prep sequence (SetEffectByIndex into the
  out-of-range slot) on mice with firmware effect cards.

- device_quirks.py — small per-model quirks table keyed by device.modelId
  (stable across USB/BLE/wireless). Currently used to mark RGBEffects
  NvConfig color slots as inert on devices where the firmware accepts
  but ignores the bytes (G502 X PLUS startup colors).

- config_panel.py — HeteroKeyControl gains a TOGGLE field kind that
  renders as a Gtk.Switch (used by the boot-effect rows). Visual gate
  greys out RGB settings whose prerequisites aren't met: rgb_zone_* /
  rgb_idle_* / rgb_sleep_timeout require LED Control = Solaar; per-key
  additionally requires every zone effect to be Static. Visual-only —
  doesn't touch the persister's user lock-icon state.

- tests/test_rgb_power.py — coverage for the power manager state
  machine, dim ramp, idle effects, wake path, and per-key/zone
  coexistence.

Closes pwr-Solaar/Solaar#3149.
2026-05-13 19:03:44 -04:00
Ken Sanislo d159081893
device: Fix operator precedence bug and end-of-configuration timing in device.changed() (#3173)
* Fix WIRELESS_DEVICE_STATUS reconfiguration: push settings and ack with proper cookie

When a device sends WIRELESS_DEVICE_STATUS with config_needed=1, the host
should re-push settings and acknowledge via ConfigChange SetComplete. The
existing code relied on the push flag in changed(), but operator precedence
caused push=True to be ignored for devices that have the WIRELESS_DEVICE_STATUS
feature — the exact devices that send this notification.

Handle the reconfiguration entirely in the notification handler: explicitly
push settings and ack, rather than trying to overload the changed() condition.

Also replace hardcoded cookie 0x11 with proper GetCookie/SetComplete protocol:
read the device's current configuration cookie and echo it back, per the
ConfigChange (0x0020) specification.

* WIRELESS_DEVICE_STATUS reconfig: gate apply on ConfigChange cookie

Add a cookie-comparison gate so devices that emit multiple reconfig
notifications (PRO X 2 sends two on power-on) don't get their settings
re-applied for every one. The gate also benefits any path that calls
apply_settings_if_needed — devices that retain config through
power-save now skip the redundant apply.

New flow:

- Device.apply_settings_if_needed() reads ConfigChange (0x0020) cookie
  via GetCookie. If the live value matches the cookie we stored after
  the last successful sync (persister key `_config_cookie`), the
  device hasn't drifted and we skip apply_all_settings entirely. On a
  real apply, SetComplete echoes the cookie back and we persist it.
  Devices without CONFIG_CHANGE bypass the gate (always apply).

- device.changed(active=True) calls apply_settings_if_needed in place
  of the old apply_all_settings + signal_configuration_complete pair.

- WIRELESS_DEVICE_STATUS reconfig handler drops the redundant explicit
  apply + ack (changed() already handles it on transition to active)
  and instead calls apply_settings_if_needed to cover the case of
  follow-up reconfig notifications on an already-active device — the
  cookie gate makes the second/third call essentially free.

Protocol cleanup:

- set_configuration_complete no longer auto-increments the cookie
  before echoing. The device owns the cookie and bumps it when its
  config drifts; the host's job is to confirm which value it synced
  with, not to advance the value. Host-side increment introduced a
  needless race with device-side bumps.

- signal_configuration_complete gains an optional cookie= arg so the
  caller can pass a value it already read (saves a redundant GetCookie
  round-trip from inside the gated apply path).

Tests:

- get_configuration_cookie returns the two-byte cookie from fn 0.
- set_configuration_complete echoes a provided cookie unchanged.
- set_configuration_complete with cookie=None reads the live cookie
  and echoes it (no increment).
2026-05-13 11:30:26 -04:00
Ken Sanislo 12aabf029b
centurion: support PRO X 2 LIGHTSPEED headphones Centurion features (#3150)
* Add Centurion transport and PRO X 2 LIGHTSPEED headset support

Adds support for the Logitech PRO X 2 LIGHTSPEED Gaming Headset (PID 0x0AF7)
which uses the Centurion transport protocol (report ID 0x51 on USB usage page
0xFFA0) instead of standard HID++ report IDs.

Changes:
- HID enumeration: detect Centurion devices via report descriptor parsing
  (usage page 0xFFA0, report ID 0x51, 63-byte frames)
- Centurion transport: wrap/unwrap HID++ 2.0 frames in Centurion framing
  for write, read, and ping operations
- Feature discovery: enumerate features individually on Centurion devices
  (different response format: [remaining_count, feat_hi, feat_lo])
- Device descriptor for PRO X 2 LIGHTSPEED Gaming Headset
- New feature enum entries for Centurion-era headset features (0x06xx)
- CenturionRawRW class for write-only headset settings controlled via
  raw Centurion commands reverse-engineered from HeadsetControl
- HeadsetSidetone setting (0-100 range, persisted locally)

Known limitations:
- Only sidetone control is implemented; other features need RE work
- Settings are write-only (no read-back from device)
- Headset features (0x06xx) not discoverable via IRoot; registered manually

* Remove static PRO X 2 descriptor; fully probe Centurion devices at runtime

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

* Display Centurion dongle as receiver with headset as child device

- 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

* Fix headset setting validators and code formatting

- Add signed int8 support to RangeValidator for HeadsetMicGain (0x0611)
- Make HeadsetSidetone version-aware: v1 uses 2-byte skip, v2+ uses
  3-byte skip with 0xFF separator per protocol spec
- Fix ruff formatting in device.py, listener.py, udev_impl.py
- Update CenturionReceiver test for renamed receiver

* Use ConnectionStateChangedEvent for headset online/offline detection

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.

* Update PRO X 2 LIGHTSPEED device doc with current solaar show output

* Fix Centurion protocol version display (1.16 not 2.6)

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.

* Add OnboardEQ (0x0636) support for Centurion headsets

Implement host-computed biquad EQ coefficient generation and multi-fragment
bridge writes for the PRO X 2 LIGHTSPEED headset's 5-band parametric EQ.

The coefficient algorithm uses standard Audio EQ Cookbook peaking EQ formulas
with a simplified rescale normalization (max_b0 × 1.19 headroom). This is our
own implementation — not an exact replica of LGHUB's ~350-line per-band cascade
normalization — but it produces functionally correct results. The DSP
compensates via the rescale factor, and the EQ changes are audible and working
on real hardware.

Wire format verified against 38 LGHUB pcap writes:
- 4-byte LE section headers, LE uint16 coefficient words
- Mixed Q1.31/Q2.30 fixed-point with 24-bit precision
- Only b-coefficients divided by rescale; a-coefficients unchanged
- Two sections: 48kHz playback + 16kHz mic
- No trailing padding, no extra words between sections

Changes:
- base.py: Add flags parameter to write_centurion_cpl() for multi-fragment CPL
- device.py: Rewrite multi-fragment bridge send — proper CPL fragmentation with
  fragment 0 carrying bridge prefix/hdr and continuations carrying raw sub_msg,
  all fragments sent back-to-back without intermediate ACKs
- hidpp20.py: Replace placeholder coefficient code with full biquad math,
  mixed Q-format quantization, rescale normalization, and dual-section output
- settings_templates.py: Persist EQ to slot 0x80 after writing to slot 0x00
  so settings survive power cycle
- tests: Update expected SetEQParameters payloads for new coefficient format

* Extract Centurion protocol into separate modules

Move CenturionReceiver class, factory function, and Centurion protocol
queries (firmware, serial, hardware info, battery, name) from device.py
and hidpp20.py into new centurion.py module. Move OnboardEQ biquad math
and payload builders from hidpp20.py into new onboard_eq.py module.
Move _read_usb_product_string() to common.py to avoid circular imports.

Re-exports preserve backward compatibility for all existing callers.

* Add vertical graphic EQ slider widget for headset equalizer

Replace horizontal slider rows with a traditional graphic EQ layout
using vertical sliders side-by-side, with dB value display and
frequency labels per band.

* Fix device online state clobbered by debug ping in _status_changed

The INFO-level logging guard in _status_changed() called device.ping()
before logging, purely to show accurate online status. But ping() has
side effects — it sets device.online based on the result. When a
ConnectionStateChangedEvent correctly marked a device online, the
subsequent _status_changed() callback would re-ping. If the device
wasn't ready yet (e.g. Centurion headset still booting), the ping
timed out and set online back to False, requiring 2-3 power cycles
to sync state.

Remove the unnecessary ping — the log message already reads
device.online which reflects the state set by the event handler.

* Sort feature constants by ID and add PROFILE_MANAGEMENT

Move RPM_INDICATOR/RPM_LED_PATTERN (0x807A-B) before PER_KEY_LIGHTING
(0x8080-81), sort five Centurion-era headset entries into their correct
positions by feature ID, and add missing PROFILE_MANAGEMENT = 0x8101.

* Add CenturionCoreFeature enum for colliding feature IDs

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.

* Fix ruff I001 import sorting in centurion.py and hidpp20.py

* Add 9 missing centurion/headset feature names

Add feature constants split out from the HID++ 2.0 names PR (#3153):
CENTURION_LED_BRIGHTNESS (0x0110), CENTURION_EU_POWER_MODE (0x0115),
CENTURION_DEVICE_BOOL_STATE (0x0116), HEADSET_ADVANCED_PARA_EQ (0x020D),
HEADSET_MIC_TEST (0x020E), HEADSET_EQ_STYLES (0x0213),
BT_HOST_INFO (0x0305), LIGHTSPEED_PAIRING (0x0309),
BT_GAMING_MODE (0x030A).

* Extract _record_ping_protocol helper so all ping paths capture Centurion version

The raw Centurion (major, minor) pickup was only in the Centurion-child
dongle branch of Device.ping(). Wired Centurion variants (e.g. PRO X 2
LIGHTSPEED 046d:0AF8) go through the generic fallback branch and never
recorded the raw version, so they displayed "Centurion 2.6" instead of
"Centurion 1.16".

Extract the protocol + centurion version recording into a helper and
call it from both branches.

---------

Co-authored-by: Peter F. Patel-Schneider <pfpschneider@gmail.com>
2026-04-14 11:43:23 -04:00
Peter F. Patel-Schneider 4c63bdb6ee
show better pairing errors (#3063)
* Fix: Show pairing error str

Fixes #2827

* device: also show bolt pairing errors

---------

Co-authored-by: MattHag <16444067+MattHag@users.noreply.github.com>
2025-12-10 11:18:50 -05:00
Peter F. Patel-Schneider 44a647499c ui: don't pop up window in response to ADC changes 2025-10-25 10:41:35 -04:00
Peter F. Patel-Schneider 694513832d
device: report symbolic names for pairing errors (#2886)
* device: report symbolic names for pairing errors

* testing: fix testing of notifications
2025-05-31 08:12:42 -04:00
Peter F. Patel-Schneider abea1c4341 device: add present flag, unset when internal error occurs, set when notification appears 2025-04-22 08:45:55 -04:00
Peter F. Patel-Schneider 217b9360e6 device: pause setting up features when error occurs; use ADC message to signal connection and disconnection 2025-04-22 08:45:55 -04:00
MattHag d42524dec9 notification: Remove alias for SupportedFeature
Related #2273
2025-01-02 08:05:02 -05:00
MattHag 8894463f64 notification: Refactor process_device_notification
Simplify code and unify interfaces and type hints.

Related #2273
2025-01-02 08:05:02 -05:00
MattHag 15aaba2802 notification: Refactor process_receiver_notification
Remove repeated code pattern with generalized implementation. Aim
towards easy extension and code readability.

Related #2273
2025-01-02 08:05:02 -05:00
MattHag fa3a9bc5b3 notification: Refactor receiver event handling
Split processing of receiver notification into smaller functions.
Extract handler functions for every receiver notification for simple
maintenence and testability.

Related #2273
2025-01-02 08:05:02 -05:00
MattHag 810cda917a Refactor notifications
Add type hints and reasonable variable names.

Related #2711
2025-01-01 13:48:14 -05:00
MattHag 64ac437b7f Rename variable to full name notification
Related #2711
2025-01-01 13:48:14 -05:00
Romain Loutrel 79ffbda903
change pairing error values to intenums
* 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)
2024-10-23 16:22:22 -04:00
rloutrel 0d12c6f229 notifications: Introduce unit tests 2024-10-20 12:57:00 -04:00
MattHag 0cd9c0c9b5 Refactor: Introduce Feature enum
Convert Feature NamedInts to SupportedFeature integer enum.

Related #2273
2024-10-14 07:28:09 -04:00
rloutrel 15659a1ee4 Fix copy-paste error while refactoring notifications.py 2024-10-11 13:23:55 -04:00
MattHag d67466298b Introduce Enum for notification types 2024-06-03 08:37:02 -04:00
MattHag be83dac209
hid: Convert definition of HID registers to enum
* 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
2024-06-02 10:34:00 -04:00
MattHag 815dce07be Unify imports in logitech package
Related #2273
2024-05-23 16:42:18 -04:00
Matthias Hagmann c9dc232951 Refactor: Use dataclasses and enums
Replace unnecessary NamedInts in favour of default data types.
Simplify interfaces by reducing possible input from strings to members
of an enum.
2024-05-22 21:14:41 -04:00
Matthias Hagmann 469c04faaf Introduce Device protocol and type hints 2024-05-22 21:14:41 -04:00
Matthias Hagmann 193dbfda21 hidpp10: Move independent functions to module level 2024-05-22 21:14:41 -04:00
MistificaT0r 4225fce8d7
po: update Russion translation and have all strings translated
* update Russian translation

* Fixed translation display in GUI

* fix checks / Fixed translation display in GUI
2024-04-21 11:36:39 -04:00
Peter F. Patel-Schneider 490493d7a3 device: handle BRIGHTNESS CONTROL notifications 2024-03-24 15:44:15 -04:00
Matthias Hagmann 5b09ace1f5 ruff: Apply single line import format
# Usage
pre-commit run --all-files

Related #2295
2024-03-13 15:41:21 -04:00
Peter F. Patel-Schneider b957217ea8 receiver: delay device sending first messages 2024-03-13 08:34:28 -04:00
Peter F. Patel-Schneider 9c5ba6445e device: remove status from Device and Receiver 2024-03-11 08:23:27 -04:00
Peter F. Patel-Schneider a1418cd834 device: move changed method from status to Device and Receiver 2024-03-11 08:23:27 -04:00
Peter F. Patel-Schneider 1fe2eab1a4 device: move link_encrypted from status to Device 2024-03-11 08:23:27 -04:00
Peter F. Patel-Schneider 15d425c365 device: move battery information from status to Device 2024-03-11 08:23:27 -04:00
Peter F. Patel-Schneider 0805ecb511 device: move status string function to Device and Receiver 2024-03-11 08:23:27 -04:00
Peter F. Patel-Schneider 87285faf7f receiver: move pairing status to new dataclass attached to receiver 2024-03-11 08:23:27 -04:00
Peter F. Patel-Schneider 135c8b8cb9 device: use status attribute for error 2024-03-09 10:36:40 -05:00
Peter F. Patel-Schneider 6b3f09aa5d device: use status attribute for link_encrypted 2024-03-09 10:36:40 -05:00
Peter F. Patel-Schneider 64d8cad81a device: change status battery fields to Battery objects 2024-03-09 10:36:40 -05:00
Matthias Hagmann 9c76a6c5ba refactor: Introduce Hidpp20 class
Related #1097
2024-03-02 10:56:41 -05:00
Matthias Hagmann 85149a809e refactor: Introduce Hidpp10 class
Related #1097
2024-03-02 10:56:41 -05:00
Matthias Hagmann c3b01bffae fix: Replace invalid hidpp10 usage
Related #1097
2024-02-28 17:41:46 -05:00
Peter F. Patel-Schneider b7afc410ba device: clean up listener and notifications code 2024-02-23 11:37:23 -05:00
Peter F. Patel-Schneider 646ef2f596 device: move battery constants common to HID++ 1.0 and 2.0 to common 2024-02-22 09:57:02 -05:00
Matthias Hagmann 7774569971 Apply ruff format
Run ruff auto formatting using:
ruff format .

Related #2295
2024-02-20 15:41:10 -05:00
Peter F. Patel-Schneider ed248c62b9 device: add callback to call when changing a setting 2024-02-20 06:19:23 -05:00
Matthias Hagmann 5f487dd3b2 logitech_receiver: Move hidpp20 constants into new module
Related #1097
2024-02-20 05:58:33 -05:00
Peter F. Patel-Schneider 12de240949 device: improve imports in logitech_receiver
device: move imports of ui modules to beginning of files

logitech_receiver: remove imports from __init__.py
2024-02-18 06:21:35 -05:00
Peter F. Patel-Schneider 31d795fcb8 device: improve imports in logitech_receiver
device: move some imports to top of modules

device: break up imports loop with device descriptors

device: break up imports loop by moving a function from notifications.py to setting_templates.py

device: break import loop between device.py and diversion.py by using device to access method
2024-02-18 06:21:35 -05:00
Peter F. Patel-Schneider 468fad1358 ui: refactor code to record change to setting 2024-02-10 14:45:00 -05:00
MattHag 87658fb189
logging: Simplify logger instantiation
* logging: Simplify logger instantiation

Relates #2254

* logging: Remove aliases

Relates #2254

* logging: Replace deprecated warn with warning

Related #2254

* logging: Fix mistake

Related #2257
2024-02-10 13:55:27 -05:00