One-shot Python CLI for Logitech PRO onboard profiles on Linux; experimental hardware support
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-31 14:14:25 +03:00
logimouse Use kernel-known receiver slots before register lookup or full scan; add timed debug logs 2026-10-31 14:14:25 +03:00
tests Use kernel-known receiver slots before register lookup or full scan; add timed debug logs 2026-10-31 14:14:25 +03:00
tools Implement one-shot Python Logitech onboard CLI 2026-10-28 00:47:35 +03:00
.gitignore Implement one-shot Python Logitech onboard CLI 2026-10-28 00:47:35 +03:00
LICENSE Implement one-shot Python Logitech onboard CLI 2026-10-28 00:47:35 +03:00
NOTICE Discover mouse slots from receiver pairing registers before probing 2026-10-31 12:11:50 +03:00
pyproject.toml Use kernel-known receiver slots before register lookup or full scan; add timed debug logs 2026-10-31 14:14:25 +03:00
README.md Use kernel-known receiver slots before register lookup or full scan; add timed debug logs 2026-10-31 14:14:25 +03:00
uv.lock Use kernel-known receiver slots before register lookup or full scan; add timed debug logs 2026-10-31 14:14:25 +03:00

logimouse

Одноразовые команды настройки onboard-памяти новых Logitech PRO под Linux. Python 3.10+, только стандартная библиотека, прямой доступ к /dev/hidraw*. Браузер, Solaar и постоянно работающий демон не нужны.

Статус: протокол перенесён из ClickSync; пользователь сообщил о работающих командах на SUPERLIGHT 2 SE, с периодическими сбоями обнаружения. Автоматические тесты используют имитацию устройства и sysfs. Сохранение настроек после сна и выключения мыши отдельно не подтверждено.

Запуск через uv

В pyproject.toml зарегистрирован entry point:

[project.scripts]
logimouse = "logimouse.cli:main"

Из checkout репозитория:

git clone https://git.wzray.com/friendiest/logimouse.git
cd logimouse
uv run logimouse --help
uv run logimouse dpi --stage 2 1600
uv run logimouse dpi --stage 1 800 --dry-run

uv сам создаёт .venv и устанавливает локальный пакет. uv.lock фиксирует проект. Для проверки из чистого checkout: uv run --locked logimouse --version. Отдельного Python launcher и PEP 723 metadata нет.

Запуск через Python

Можно использовать одиночный logimouse.pyz из релиза: python3 logimouse.pyz --help. После chmod +x logimouse.pyz его можно положить в ~/.local/bin/logimouse. Внутри Python-исходники и лицензия; внешних зависимостей нет.

Из каталога исходников:

python3 -m logimouse list
python3 -m logimouse show

Либо установка в venv:

python3 -m venv ~/.local/share/logimouse-venv
~/.local/share/logimouse-venv/bin/pip install .
mkdir -p ~/.local/bin
ln -s ~/.local/share/logimouse-venv/bin/logimouse ~/.local/bin/logimouse

Альтернатива: pipx install ..

Нужны права чтения/записи HID++-интерфейса. Если Solaar уже работал от обычного пользователя, подходящие udev-правила, вероятно, установлены. Дополнительные правила CLI автоматически не ставит. Закрой остальные конфигураторы перед записью. Разбуди мышь перед командой.

--device /dev/hidrawN выбирает интерфейс явно. --index 1..6 выбирает слот приёмника, --index ff означает прямой USB. Для USB-ресиверов Logitech C5xx автопоиск сначала берёт известные ядру слоты из sysfs: только непосредственные HID-потомки данного ресивера, с HID_PHYS вида <receiver phys>:<slot>. Дочерние hidraw-ноды используются только как метаданные; запросы идут через ресивер. При наличии таких слотов чтение pairing-регистров и полный перебор пропускаются. Тип дочернего устройства из имени не угадывается: каждый известный слот проверяется обычным read-only discovery. Если sysfs-слоты недоступны, читаются HID++ 1.0 receiver info, количество устройств и pairing-таблица. Номера слотов берутся из таблицы, включая пропуски; количество сверяется до и после чтения. Затем HID++ discovery выполняется только для слотов мышей и устройств с неизвестным типом. Клавиатуры пропускаются. Чтение таблицы не меняет привязки и не включает уведомления ресивера. Если таблица недоступна или противоречива, используется прежний перебор 1..6 и ff; причина fallback сохраняется в диагностике неудачного поиска. Другие USB/Bluetooth-устройства используют прежний поиск без чтения регистров ресивера. Явный --index полностью обходит чтение pairing-таблицы. Слоты опрашиваются параллельно через отдельные read-only hidraw handles. Ответы фильтруются по слоту и команде. Запись остаётся последовательной, с эксклюзивной блокировкой. Автопоиск исключает дочернюю HID-ноду мыши, созданную ядром под ресивером, если HID-нода предка тоже представлена доступным в sysfs HID++-кандидатом. Проверяется вложенность HID-путей, без привязки к номеру hidraw, PID или имени. Отдельные USB-интерфейсы сохраняются; дочерняя нода без подходящего предка тоже остаётся кандидатом. Явный --device обходит этот фильтр. Дубли HID++ одного физического USB-устройства в sysfs не сканируются повторно, если через первый интерфейс найдена мышь. list показывает альтернативные пути в interfaces; они могут быть ещё не проверены. Если выбранный интерфейс пропал перед подключением, CLI пробует альтернативы. После начала команды переключения на другой интерфейс нет. При нескольких отдельных мышах или неизвестной USB-топологии нужно указать --device и при необходимости --index. Одинаковые названия мышей не считаются доказательством, что это одно устройство. Глобальные параметры работают до и после подкоманды. Таймаут каждого HID++-запроса по умолчанию 5 секунд, включая discovery и основное соединение. --timeout N переопределяет его для текущего запуска. При получении подходящего ответа ожидание сразу заканчивается. При fallback на полный перебор пустые слоты могут занять все 5 секунд. --index 1 ограничивает поиск слотом 1. HID++ FAP-запросы, включая root ping, сразу отправляются длинными пакетами по 20 байт. Ожидания ответа на короткий ping перед ними нет. Команды записи при таймауте не повторяются.

--debug выводит в stderr источник списка слотов, выбранные индексы и TX/RX-пакеты с таймингами. Работает только в текущем процессе:

logimouse --debug dpi 2>logimouse.log

Лог содержит сырые HID++-данные; перед публикацией проверь его содержимое. Без --debug вывод команд сохраняет прежний формат.

DPI

Нумерация с 1. Ступень, выбранная или изменённая через dpi, становится одновременно текущей и default для восстановления после перезапуска мыши.

logimouse dpi                            # прочитать ступени
logimouse dpi 800                        # обе оси текущей ступени
logimouse dpi -x 800 -y 1200 --stage 2
logimouse dpi --stage 2 1600             # одинаково для X/Y
logimouse dpi --stage 2                  # активировать и сделать default
logimouse dpi --max-stages                # прочитать количество
logimouse dpi --max-stages 3              # оставить 3 включённые ступени
logimouse dpi --stage 2 --lod high
logimouse dpi --lod mid                   # LOD текущей ступени

Флаги только ASCII: --stage N, --max-stages [N]. --stage необязателен: без него DPI, -x, -y и --lod меняют текущую активную ступень, прочитанную с мыши. Она также становится default. При изменении только одной оси вторая сохраняется. Если --max-stages N одновременно отключает текущую редактируемую ступень, команда завершается до записи; укажи оставшуюся через --stage либо измени количество отдельно. LOD: low, mid, high.

От 1 до 5 ступеней. При расширении новые ступени копируют значения и LOD прежней default-ступени. При сокращении default сдвигается на последнюю оставшуюся ступень, если прежняя выключена. Редактирование выключенной ступени требует сначала увеличить число ступеней либо указать --max-stages N вместе с правкой.

Диапазон по формату ClickSync: 100..44000 DPI. Значения округляются по его сегментам: 100..200 шаг 1; 200..500 шаг 2; 500..1000 шаг 5; 1000..2000 шаг 10; 2000..5000 шаг 20; 5000..10000 шаг 50; 10000..20000 шаг 100; 20000..32000 шаг 125; 32000..44000 шаг 200. Результат выводится после операции. Это лимиты реализованного формата, не автоматическая проверка сенсора.

Rate

logimouse rate
logimouse rate 1000                       # провод и радио
logimouse rate --wired 500 --wireless 1000
logimouse rate --wireless 2000

Провод: 125/250/500/1000 Гц. Радио: 125/250/500/1000/2000/4000/8000 Гц. Изменение радио дополнительно проверяет заявленную текущим устройством маску поддерживаемых частот через feature 8061. Это может ограничить редактирование радиочастоты при подключении по проводу: используй приёмник. Сохранение байта частоты не является измерением фактического polling rate.

Extra

logimouse extra
logimouse extra --lightforce optical      # optical / hybrid
logimouse extra --surface on              # auto / on / off
logimouse extra --bhop off
logimouse extra --bhop 100                 # мс, 0..2550, кратно 10

Только Superstrike:

logimouse extra --side left --trigger 5 --rapid-trigger 2 --feedback 3
logimouse extra --side both --rapid-trigger off

--side: both/left/right, по умолчанию both. Trigger 1..10, rapid distance 0..5 либо off, feedback 0..5. LIGHTFORCE на Superstrike отсутствует. LIGHTFORCE/surface и BHOP/Superstrike меняют разные области устройства, поэтому их нужно записывать отдельными командами. Смешанный вызов отклоняется до подключения к мыши.

Профили

logimouse profile
logimouse profile --mode onboard
logimouse profile 2
logimouse profile --mode host

Выбираются только существующие включённые слоты. Создания, удаления, переименования, включения слотов и редактирования кнопок нет. После выбора профиля CLI активирует его сохранённую default DPI stage. Для редактирования и чтения настроек нужен onboard mode; CLI не включает его скрыто. Команды mode/profile выполняются отдельно. Если в host mode текущий профиль равен 0x0000, profile --mode onboard выбирает первый включённый профиль из каталога, читает его и проверяет CRC до переключения. Затем включает onboard, выбирает проверенный профиль и активирует его default DPI stage с проверкой результата. Flash-память эта операция не переписывает. При ошибке после переключения CLI сообщает о непроверенном конечном состоянии; повторов и автоматического отката нет.

Защита записи

  • Положительное обнаружение UUID features, без запасных захардкоженных индексов
  • Проверка модели, memory model 1, profile format 6/7 и размера сектора 255 байт
  • Полное чтение исходного сектора и проверка CRC16/CCITT-FALSE
  • Изменение известных полей с сохранением остальных байтов, включая кнопки
  • Повторное чтение перед записью: профиль не должен измениться другим процессом
  • Запись с ACK без автоматического повтора при ошибке
  • Обязательное повторное чтение, CRC и сравнение всех байтов после commit
  • Проверка индекса текущей DPI-ступени после активации, даже при одинаковых DPI

Бэкапы и автоматический откат отсутствуют по текущему требованию. Сбой USB или питания во время flash-записи остаётся риском. CRC и readback не заменяют аппаратную проверку layout. Если прошивка не поддерживает чтение индекса текущей ступени через 8100/B0, изменение профиля отклоняется до flash-записи.

--dry-run выполняет чтение и валидацию плана без изменения памяти, режима или активной ступени. Перед первой записью на SE:

logimouse list
logimouse show
logimouse dpi --stage 1 800 --dry-run

После первой реальной записи проверь сохранение после выключения/включения мыши и сна хоста. На VM разработки физического устройства нет.

Каждый запуск открывает новое соединение и закрывает его по завершении. CLI не переживает sleep между командами как долгоживущий процесс. Спящая или недоступная мышь выдаёт ограниченный таймаут; незавершённые записи не повторяются. flock координирует процессы logimouse, но не блокирует Solaar/G HUB.

Разработка

python3 -m unittest discover -s tests -v
python3 tools/build_zipapp.py              # dist/logimouse.pyz

Протокольная основа: Nuitfanee/ClickSync, commit 3a945428b25bf6b2db0e8750f819666caff9cda5. Лицензия GPL-2.0-only, см. LICENSE и NOTICE.