Если ты, читатель, тоже страдаешь понятием "Не баг, а фича" и желанием покапаться в железках, то этот пост для твоих "кривых ручек", как у меня.
1. Обзор и сборка проекта
На днях, я искал интересный корпус для Raspberry Pi 4, мне очень уж понравился набор
Mini Tower Kit от https://github.com/geeekpi/minitowercase, но вот незадачка, проект, изначально, предназначен для RPi 5, а у меня RPi 4, но хотелка меня переосилила и я решился купить его за 2300 денег.
Корпус Mini Tower Kit это интересный и прикольный проект, напечатанный на 3Д принтере, состоящий из 3х частей корпуса, кулера (Ice Tower), OLED-экрана и RGB-подсветки, на кулере (не управляемая) и на обратной стороне экрана, выглядит это чудо как уменьшенная копия геймерского ПК. Так же в комплекте блок расширения GPIO контактов.



Все бы хорошо, но вот незадачка, кулер подключается через fan-интерфейс на RPi 5, а на RPi 4 такого нет.

- Чож делать, Чож делать?
- Кустарить!
Мое приключение началось с разбора распиновки, в прочем ничего особенного, вот она:


Ну, в целом, разницы особо никакой, поэтому проблем с OLED и I2C не будет, значит надо разбираться с кулером.
Распиновка кулера представляет из себя JST-PH 2.0 мм (4 pin), у которого:
Цвет провода | Назначение | Что с ним делать |
|---|---|---|
🔴 Красный | +5V питание | 5V (Pin 2 или Pin 4) |
⚫ Чёрный | GND | GND (Pin 6 / 9 / 14 и т.д.) |
🟡 Жёлтый | TACH / Sense (датчик оборотов) | Опционально, можно не подключать |
🔵 Синий | PWM control (управление скоростью) | GPIO (GPIO 13 / Pin 33) |

Ну, красный и черный - понятно и валенку, а желтый и синий - нужно разбираться.
ЖЁЛТЫЙ (RPM) - тахометр (мы его НЕ используем) - это это выход вентилятора
Что он делает:
вентилятор шлёт импульсы
обычно 2 импульса на один оборот
это open-collector выход (нужна подтяжка к 3.3V)
Используется для:
подсчёта RPM (оборотов)
мониторинга: «крутится / заклинил»
В нашей переделке нам не нужен RPM, потому что мы его регулируем по температуре CPU, которая прекрасно вычисляется самим RPi 4. Таким образом в этом корпусе малинки нет смысла использовать его, потому что придется проводить рассчеты напряжения, ставить сопротивление, потому что GPIO не любит получать чистый 3.3v на вход - ну его нафиг.
А вот СИНИЙ (PWM) - это провод на вход к кулеру, т.е. он управляет самим кулером.
Как это работает:
Вентилятор питается постоянно от 5V
Синий провод принимает логический сигнал
Частота обычно ~25 кГц (PC стандарт) (по крайней мере так пишут про подобные на просторах тырнета)
Но 5V вентиляторы терпят и 100–1000 Гц
Получается такие вертушки работают по принципу:
Duty Cycle | Что происходит с сигналом | Как крутится вентилятор |
|---|---|---|
0% | всегда LOW | не крутится |
10% | 1 короткий «пшик» | еле живой |
25% | четверть времени ON | медленно |
50% | половина ON / половина OFF | средне |
75% | почти всегда ON | быстро |
100% | всегда HIGH | максимум |
Таким образом, мы подаём PWM с GPIO, и вентилятор сам регулирует обороты.
Теперь, когда мы разобрались во всех причинно-следственных связях, переделаем контактики на виртушке, под нашу архитектуру.
Я особо не запаривался, отрезал покороче JST, взял коннекторы типа "мама" с ардуиновских проводов и просто перепаял провода и насадил коннекторы

Синий, в общем-то, я не захотел изолировать или удалять, поэтому просто тоже насадил на него коннектор, а вось когда-нибудь и пригодится :D
Затем приступил к сборке, согласно распиновки из комплекта, но столкнулся с небольшой накладкой, т.к. пины OLED дисплея и кулера пересекались. Эта задачка была решена достаточно тривиально - использованием блока расширения для GPIO и простой сменой ШИМ-порта с GPIO 18 на GPIO 13 - код все поправит


Прекрасно, железо запустилось, кулер крутится, диоды на нем горят, но дисплей не воркает, потому что I2C еще не инициализирована в системе.
Так, с железом разобрались, переходим к программной части.
У меня RPi 4 с Ubuntu Server на борту, а родное ПО предполагает RPi 5 с RPi OS.
Выкачиваем репозиторий, смотрим какие библиотеки использует код. Для работы с OLED и I2C используется rpi_ws281x - не проблема, питон переварит. Для кулера же, все гораздо проще, на уровне драйверов ОС (kernel / firmware).
Ну, с дисплеем все понятно, а по поводу вентилятора придется вернуться к истокам ардуино, в принципе, тоже ничего сложного, в тырнете полно информации. Питон спасет мир, поэтому вот, я реализовал это у себя:
GPIO.setup(FAN_PIN, GPIO.OUT) pwm = GPIO.PWM(FAN_PIN, 250) # частота pwm.start(0) while True: temp = get_cpu_temp() if temp < 45: pwm.ChangeDutyCycle(20) elif temp < 60: pwm.ChangeDutyCycle(50) else: pwm.ChangeDutyCycle(100)
На этом моменте основной функционал отработан, тесты положительные, все воркает.
Теперь можно экспериментировать.
2. Архитектура ПО
Оригинальный софт представлял собой один бесконечный цикл на Python, который пытался делать всё сразу. Я пошел по пути Unix-way: одна задача - один процесс.
Вся экосистема проекта была разбита на независимые демоны (Systemd Services), которые общаются друг с другом через файлы состояний и конфигурационный JSON-файл.
Структура проекта
Файловая система организована так, чтобы отделить исполняемый код от конфигурации, доступной пользователю.
/ ├── etc/ │ └── minitower/ │ └── config.json # Глобальный конфиг (пользовательские настройки) ├── usr/ │ └── local/ │ ├── minitower/ │ │ ├── fan_control.py # Логика охлаждения │ │ ├── led_service.py # Драйвер подсветки (запущен от root) │ │ ├── sysinfo.py # Драйвер OLED дисплея │ │ └── led_control.py # CLI-утилита для пользователя │ └── bin/ │ ├── led # Симлинк для удобного вызова │ └── minitower_wrapper # Перехватчик команд reboot/shutdown └── tmp/ └── led_status # IPC-канал для приоритетных сигналов
Такая структура позволяет обновлять скрипты, не затирая настройки пользователя, и дает возможность управлять подсветкой без прав суперпользователя.
Логика работы сервисов
1. Сервис охлаждения (Fan Control)
Максимально простой и надежный скрипт. Он читает /sys/class/thermal/thermal_zone0/temp и управляет скважностью ШИМ на GPIO 13.
Тихий режим: До 45°C вентилятор полностью остановлен.
Линейный рост: С 45°C до 65°C обороты плавно растут.
Турбо: Выше 65°C вентилятор включается на 100%.
2. Сервис подсветки (Moodlight Service)
Это не просто «гирлянда», а конечный автомат (State Machine). Сервис работает с библиотекой rpi_ws281x и имеет систему приоритетов.
Приоритет 1 (Высокий): Системные события.
Скрипт мониторит наличие файла-флага в /tmp/led_status.
Если файл содержит
BLINK_RED- пропал интернет, мигаем красным.Если
BLINK_ALARM- обнаружена попытка взлома, агрессивный стробоскоп (в моем случае реализовано при неправильном вводе пароля по SSH.Если
REBOOT- плавное угасание.
Приоритет 2 (Низкий): Пользовательские настройки.
Если системных событий нет, сервис читает /etc/minitower/config.json. Пользователь может выбрать статический цвет, режим «радуги», «матрицы», «дыхания» и т.п.
Хак с правами доступа: Чтобы менять цвет мог обычный пользователь командой
led greenбезsudo, файл конфигурации и папка/etc/minitowerимеют права 666/777. Демон подсветки (работающий от root) просто перечитывает файл при изменении его времени модификации.
3. Сервис OLED-дисплея (Sysinfo)
Экран 128x64 используется на 100%. Вместо стандартных логотипов, я сделал полноценный дашборд.
Верхняя панель: Hostname и часы.
Метрики: CPU Temp, RAM Usage, Disk Usage. Если значение превышает критический порог (например, RAM > 80%), строка инвертируется (черный текст на белом фоне), привлекая внимание.

Сетевой монитор:
Скрипт пингует
8.8.8.8. Если пинга нет - на экран выводится крупное предупреждение CONNECTION LOST, и отправляется сигнал подсветке стать красной.Если сеть есть, отображается локальный IP.
Детектор SSH: Через библиотеку
psutilсканируются активные TCP-соединения на 22 порту. Если вы подключились к серверу, на дисплее появится надписьssh connectedи IP-адрес вашего клиента.
4. Intruder Alert (Система безопасности)
В отдельном потоке дисплейного сервиса запущен мониторинг логов journalctl.
Если скрипт видит строки Failed password или Invalid user от sshd:
Создается файл-флаг тревоги для подсветки.
OLED-экран начинает быстро мигать белым фоном.
На дисплее крупно выводится надпись INTRUDER ALERT и IP-адрес атакующего.
Это превращает сервер в наглядный индикатор того, что вас пытаются брутфорсить.

Магия выключения (Shutdown Wrappers)
Самая интересная техническая задача - сделать красивое выключение. Если просто написать systemd-юнит с Before=shutdown.target, система может убить процессы экрана и подсветки раньше, чем они успеют отрисовать анимацию прощания.
Я пошел радикальным путем: Shell Wrappers.
Системные команды /usr/sbin/reboot, shutdown, poweroff и halt подменяются симлинками на мой скрипт-обертку.
Алгоритм работы обертки:
Пользователь вводит
sudo reboot.Запускается мой скрипт.
Он вызывает скрипт дисплея с аргументом
reboot.Рисуется Progress Bar остановки сервисов, подсветка плавно гаснет.
Только после завершения анимации скрипт вызывает системный бинарник перезагрузки.


CLI-интерфей��
Чтобы не править JSON вручную, написана утилита led. Она написана на Python, но скомпилирована в исполняемый файл (или вызвана через shebang) и доступна в $PATH.
Примеры команд:
root@AnDyPi:~$ led Minitower LED Control v2.6 Использование: led on / off - Включить (белый статический) или выключить led [название_цвета] - Статичный цвет (red, orange, yellow, green, blue, indigo, violet...) led mode [название] - Эффект (rainbow, pulse, breath, knight, strobe, sparkle, fire, matrix, party, ycle) led auto [on/off] - Автоматическая смена режимов (гирлянда) led brightness [0-255] - Установка яркости led speed [1-100] - Скорость анимации (чем меньше, тем быстрее) led set [r] [g] [b] - Установка своего RGB цвета
Установка и деплой
Весь проект упакован в Git-репозиторий - https://github.com/Reider0/PC_Pi_pack.git
install.sh делает всю грязную работу по установке:
Проверяет root-права.
Ставит зависимости (
python3-pip,i2c-tools,rpi.gpio).Разносит файлы по папкам
/usr/local/minitower/и/etc/minitower/.Создает Systemd юниты и активирует их.
Создает симлинки для перехвата команд выключения.
Итог
Вместо китайской игрушки для Raspberry Pi 5 получился полноценный, информативный домашний кампуктер на Raspberry Pi 4 с Ubuntu Server на борту.
Этот проект - отличный пример того, как с помощью Python и понимания устройства Linux можно значительно прокачать опыт даже на таком простом наборе для для Raspberry Pi, а самое главное его преимущество, что возможности ограничиваются только фантазией и количеством токенов в ChatGPT :D