Daily MaverickWHO MADE 2026?: Heroes, villains and moegoes: nominate your People of the Year 2026CNN TürkÖZET | Hollanda'dan, Yunanistan'a farklı tarifeInquirerPCG lifts travel suspension for small vessels in 3 Palawan townsPunchMFM’s Olukoya celebrates wife’s PhD success at London collegeInquirer EntertainmentA tiny hand, baby Vans and a new chapter for Avril Lavigne — motherhoodGhaflaRuto Meets Kiambu Elected Leaders at State House Ahead of 2027 ElectionsZDF heuteAktuelle Pressemitteilungen des ZDFMintNoel Tata has no quarrel with where the Tata Group is headed. His problem is with how it is getting there.Capital FMGovernment seeks real-time blood tracking system to address hospital shortages20 MinutenBeine gebrochen: Emeric überlebt 30 Stunden in GletscherspalteWirtualna PolskaKomisja ds. pedofilii reaguje na weto Nawrockiego. "Z niepokojem"RapplerLIVE UPDATES: 49th ASEAN Summit in Manila
The Daily Newsstand · Free, Always
Saturday, November 14, 2026

Как я написал на Go демон для экрана кулера Ocypus в Linux

Translate

Моя основная система — Linux (Arch). Мне она очень нравится, но относительно недавно я обновил процессор и решил заодно поменять кулер. Выбор пал на Ocypus Delta A62 EX Digital. У него есть простая, но симпатичная фича: небольшой экранчик, на котором можно показывать температуру процессора или видеокарты.

У Ocypus есть официальное приложение для Windows, а для Linux — нет. Поэтому я решил написать своё. В то время я как раз изучал Go, и он почти идеально подходит под такую задачу, но, честно говоря, это было ещё и желанием потренироваться в языке. К слову, я думаю когда‑нибудь переписать всё на C или Rust, но из‑за большого объёма учёбы времени на это пока нет.

Так и начался проект ocyd.

Как устроен путь от идеи до рабочего демона

1. Что вообще такое этот экранчик

Первым делом нужно было понять, как кулер выглядит для системы. Выяснилось быстро: экран определяется как HID‑устройство с VID:PID = 1a2c:434d и названием «China Resource Semico Co., Ltd USB Gaming Keyboard».

Bus 001 Device 005: ID 1a2c:434d China Resource Semico Co., Ltd USB Gaming Keyboard

Видимо, чтобы не тратить деньги на собственные VID и PID, Ocypus просто взяли чужую платформу от какой‑то игровой клавиатуры.

2. Реверс‑инжиниринг протокола

Дальше нужно было понять, какие данные отправляет официальное приложение и как они меняются. Для этого я использовал Wireshark и драйвер USBPcap на Windows. Зная VID:PID, достаточно легко отфильтровать трафик именно этого устройства.

Проанализировав байты, я понял, что официальное приложение отправляет пакет из 64 байт:

Байт (с нуля)

Значение

0

Report ID = 0x07

1, 2

0xFF, 0xFF

3, 4, 5

цифры температуры: сотни, десятки, единицы

6—63

нули

То есть температура отправляется очень «в лоб»: не одним числом, а тремя отдельными цифрами. На этом весь реверс‑инжиниринг, больше ничего и не потребовалось:)

В коде отправка выглядит так:

// SendTemp раскладывает температуру на 3 цифры и пишет 64-байтный репорт.
func (d *Display) SendTemp(temp int) error {
	digits := decompose(temp)
	copy(d.buf[3:6], digits[:])

	n, err := d.dev.Write(d.buf[:])
	// ...
}

func decompose(temp int) [3]byte {
	if temp < 0 {
		temp = 0
	}
	if temp > 999 {
		temp = 999
	}
	return [3]byte{
		byte(temp / 100),
		byte((temp % 100) / 10),
		byte(temp % 10),
	}
}

Для работы с HID я взял библиотеку sstallion/go-hid. Демон открывает устройство по VID:PID и раз в секунду шлёт актуальную температуру.

3. Сам демон

Зная, что отправлять, осталось написать, собственно, демон. Как и в официальном приложении, я решил дать пользователю выбор:

  • температура CPU или GPU;

  • градусы Цельсия или Фаренгейта;

  • собственный VID:PID устройства.

Последний пункт важен. Я могу ручаться только за свою версию кулера: другие модели, возможно, работают, возможно, нет. А хардкодить VID:PID вообще плохая идея.

4. Где в Linux взять температуру

Температура процессора в Linux лежит в /sys/class/hwmon/hwmon*/temp*_input. Осталось понять, чем именно являются эти * в каждом конкретном случае. Для этого я описал базовые драйверы и метки их датчиков, по которым демон находит нужный файл:

Источник

Драйверы

Метки

CPU

k10temp, coretemp, zenpower, amd_energy

Tctl, Tdie, Package id 0, Package id 1

GPU

amdgpu, nouveau, nvidia, i915, xe

edge, junction, hotspot, GPU

Алгоритм простой: перебираем hwmon*/name, ищем драйвер из списка, внутри него ищем temp*_label с подходящей меткой и читаем соответствующий temp*_input. Если метки не нашлось, берём temp1_input. Ядро отдаёт значения в милли‑градусах Цельсия, поэтому результат делится на 1000.

cpuTarget = sensorTarget{
	Drivers: []string{"k10temp", "coretemp", "zenpower", "amd_energy"},
	Labels:  []string{"Tctl", "Tdie", "Package id 0", "Package id 1"},
}

Для видеокарт всё то же самое, кроме проприетарного драйвера NVIDIA: он не отдаёт датчик через hwmon. Для него демон использует библиотеку NVML (через go-nvml): сначала пробуется sysfs, и только если там ничего не нашлось, включается NVML.

Не буду углубляться в реализацию: весь код открыт, вы можете его посмотреть, разобраться и подсказать мне, если я что‑то делаю неправильно.

5. Доступ к устройству без root: udev

Чтобы демон мог писать в HID‑устройство, нужно правило udev. Без него hidraw‑узел принадлежит root, а запускать демон от root не хочется.

SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1a2c", ATTRS{idProduct}=="434d", MODE="0666"

Здесь 1a2c:434d — это VID:PID именно Ocypus Delta A62 EX Digital. У других моделей он может быть другим, поэтому его можно поменять и в правиле, и в конфиге. Стоит помнить и о компромиссе: MODE="0666" открывает узел этого устройства всем локальным пользователям. Для экрана, который просто показывает число, я счёл это приемлемым.

6. systemd, конфиг и ocydctl

Демон запускается как пользовательский systemd‑сервис, так что root для него не нужен:

systemctl --user enable --now ocyd.service
journalctl --user -u ocyd.service -f

Настройки лежат в ~/.config/ocyd/config.toml:

[display]
source = 'CPU'   # 'CPU' или 'GPU'
unit   = 'C'     # 'C' или 'F'

[device]
vendor_id  = '0x1a2c'
product_id = '0x434d'

Чтобы не править файл руками, я сделал небольшую утилиту ocydctl:

ocydctl -source GPU -unit F
ocydctl -vendor 0x1a2c -product 0x434d
systemctl --user restart ocyd.service

VID и PID принимаются и в hex, и в десятичном виде. Демон читает конфиг только при старте, поэтому после изменений его нужно перезапустить.

7. Установка и удаление одной командой

Чтобы человеку не приходилось руками раскладывать файлы, я написал install.sh и uninstall.sh.

install.sh:

  1. ищет готовые бинарники: сначала рядом со скриптом (если вы скачали архив релиза), затем в bin/ (если склонировали репозиторий). Если их нет, соберёт сам;

  2. спрашивает, оставить ли VID:PID по умолчанию (1a2c:434d, Delta A62 EX Digital) или ввести свои;

  3. копирует бинарники в /usr/bin, а udev‑правило в /etc/udev/rules.d;

  4. создаёт конфиг, если его ещё нет;

  5. спрашивает, нужен ли systemd. Если да, кладёт сервис в ~/.config/systemd/user/ и спрашивает, включить ли автозапуск и запустить ли сразу.

uninstall.sh делает обратное: останавливает и отключает сервис, удаляет юнит, бинарники и udev‑правило, а про конфиг спрашивает отдельно.

Установка

Из архива релиза (сборка не нужна):

tar -xzf ocyd_*_linux_amd64.tar.gz
cd ocyd_*_linux_amd64
./install.sh

Из исходников:

git clone https://github.com/Dilikel/ocyd.git
cd ocyd
./install.sh

Для сборки понадобятся Go, gcc и заголовки libudev (libudev-dev в Debian/Ubuntu, systemd-libs в Arch).

Итог

На данный момент я реализовал:

  • демон, который каждую секунду отправляет температуру CPU или GPU на экран кулера и при этом уже сейчас потребляет всего около 10 МБ оперативной памяти;

  • поддержку датчиков AMD, Intel и NVIDIA, включая проприетарный драйвер через NVML;

  • выбор источника и единиц измерения (°C / °F) и настраиваемые VID:PID;

  • утилиту ocydctl для изменения настроек из командной строки;

  • пользовательский systemd‑сервис, udev‑правило и скрипты установки и удаления;

  • готовые релизы через GoReleaser и двуязычный README (русский и английский).

Важная оговорка: проект на ранней альфа‑стадии. Проверено только на моём кулере, Ocypus Delta A62 EX Digital. Юнит‑тестов пока нет, а код ещё не оптимизирован и не отполирован.

Что планирую дальше:

  • добавить тесты (конфиг, поиск датчиков на поддельном дереве sysfs, HID‑драйвер на мок‑устройстве);

  • сделать код чище и лучше: рефакторинг, аккуратная обработка ошибок и структура;

  • выпустить пакеты в AUR: ocyd (сборка из исходников) и ocyd-bin (готовый релиз);

  • поддержать больше моделей кулеров.

Помогите проверить другие модели

Если у вас другой кулер Ocypus (или вы просто нашли у меня ошибку), буду рад любой обратной связи:

  1. узнайте VID:PID командой lsusb;

  2. поменяйте их в конфиге и в udev‑правиле (или просто запустите ./install.sh и введите свои значения);

  3. напишите в issue, даже если не заработало: укажите точную модель, дистрибутив, VID:PID и логи journalctl --user -u ocyd.service.

Также буду благодарен за code review: если вы видите, как сделать лучше, пишите в комментариях или в issue.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.