Skip to content

Ambilight — подсветка экрана на ESP32 + SK6812

Захват цвета с краёв экрана в реальном времени → передача по UART → отображение на адресной RGBW-ленте SK6812 через ESP32. В отличие от датчиков остального курса, здесь поток данных идёт в обратную сторону — компьютер становится источником сигнала, а ESP32 с лентой — актуатором. Исходный код, platformio.ini и pyproject.toml — в firmware/Projects/Ambilight_project.

Ambilight на ESP32 + SK6812

Захват цвета с краёв экрана (Linux) → передача по UART → отображение на адресной RGBW-ленте SK6812 через ESP32 DevKit V1. Подробная теория (физика/математика/протоколы) — в THEORY.md, схема подключения — в WIRING.md.

Основные возможности

  • Универсальный захват периметра: одна функция sample_edge() обслуживает все четыре стороны экрана — расширение с двух сторон (left/top) до полного периметра не требует нового кода, только раскомментирования готовых блоков.
  • Протокол с защитой целостности: кадр 'A','d','a' + N×4 байта (G,R,B,W) + XOR-чексумма; битый кадр отбрасывается целиком, а не отображается как “мусор” на ленте.
  • Watchdog обрыва связи: если Python-скрипт не прислал валидный кадр дольше 2 секунд (упал, отключили USB), контроллер сам гасит ленту — не оставляет “замёрзшую” картинку.
  • Программный лимит яркости/тока: ограничение через setBrightness(), чтобы не просаживать слабый источник питания при работе всех светодиодов на максимум.
  • Два слоя кода: продвинутый класс Sk6812AmbilightStrip (Adafruit_NeoPixel, нативный RGBW) и педагогический фасад simple_api.h/.cpp — только простые функции для скетча.

Состав проекта

ambilight.py                       - Python-скрипт захвата экрана и отправки по UART
include/Sk6812AmbilightStrip.h     - продвинутый слой (класс, Adafruit_NeoPixel)
include/simple_api.h               - педагогический слой-фасад (простые функции)
src/Sk6812AmbilightStrip.cpp
src/simple_api.cpp
src/main.cpp                       - главный скетч ESP32 (использует только фасад)
platformio.ini                     - конфигурация сборки (PlatformIO)
pyproject.toml / uv.lock           - зависимости Python-скрипта (управляются `uv`)

Аппаратные требования

  • ESP32 DevKit V1 (или совместимый — см. окружения esp32s3/esp32c6 в platformio.ini)
  • Лента SK6812, 60 светодиодов (сейчас физически: 16 левая сторона + 34 верхняя)
  • Конденсатор ~440 мкФ на входе V+/GND ленты
  • Рекомендуется добавить: level-shifter 3.3V→5V (74AHCT125/74HCT245) на линии данных и керамический 100nF конденсатор у первого светодиода (см. THEORY.md, раздел 5, и Troubleshooting ниже)
  • Источник 5V с запасом по току (≥1.5A на 60 RGBW-светодиодов в максимуме)

Полная схема подключения — в WIRING.md.

Установка ПО

Прошивка ESP32 (PlatformIO)

cd firmware/Projects/Ambilight_project
pio run -e esp32dev -t upload

Библиотека Adafruit NeoPixel подтягивается автоматически через lib_deps в platformio.ini — устанавливать вручную не нужно. Перед прошивкой проверьте DATA_PIN/NUM_LEDS в src/main.cpp.

Python-скрипт (Linux, venv через uv)

cd firmware/Projects/Ambilight_project
uv sync
uv run ambilight.py

Если порт не /dev/ttyUSB0 — посмотреть реальный через ls /dev/ttyUSB* /dev/ttyACM* и поправить константу PORT в начале ambilight.py.

Настройка под другой экран / другую раскладку ленты

Все параметры — константы в начале ambilight.py:

  • MONITOR_INDEX — какой монитор захватывать (для мультимониторных систем).
  • LEDS_LEFT / LEDS_TOP / LEDS_RIGHT / LEDS_BOTTOM — сколько светодиодов на какой стороне. RIGHT/BOTTOM сейчас закомментированы в основном цикле — когда физически расширите ленту на полный периметр, достаточно раскомментировать соответствующий вызов append_edge_to_packet(...), никакой новый код писать не нужно (используется одна универсальная функция sample_edge).
  • ZONE_DEPTH_PERCENT — глубина зоны сэмплирования в % от экрана (а не в пикселях) — поэтому смена разрешения монитора не требует ручной подстройки этого параметра.
  • GAMMA — включить гамма-коррекцию, если в тёмных сценах лента выглядит “пустой”.

Troubleshooting

Случайные яркие вспышки на однотонном свете: Раз кадр данных по UART защищён чексуммой, проблема почти наверняка на участке ESP32 → лента (этот участок чексуммой не защищён, протокол однонаправленный). По убыванию вероятности:

  1. Нет согласования логических уровней 3.3V (ESP32) → 5V (SK6812) — поставить level-shifter.
  2. Нет общего провода GND между питанием ESP32 и питанием ленты (особенно если лента от пауэрбанка, а ESP32 от USB ПК) — соединить GND отдельным проводом. Самая частая и самая быстро проверяемая причина — начинайте отладку с неё.
  3. Источник питания не держит резкие скачки тока / шумит по питанию — добавить керамику 100nF у первого светодиода в дополнение к электролиту 440 мкФ; на тест попробовать обычный 5V/2A блок питания вместо пауэрбанка.

Подробное физическое объяснение каждого пункта — в THEORY.md, раздел 5.

Лента “замерла” на последней картинке: проверить isAmbilightConnectionLost() — если Python-скрипт не присылал валидный кадр >2 сек, контроллер сам гасит ленту. Если лента всё равно горит старым цветом — проверить, что прошивка с этой логикой действительно залита (не старая версия без watchdog).

Roadmap / идеи на будущее

Готовое приложение для Linux. Технически реализуемо несколькими путями:

  • Системный трей-иконка (pystray) с переключателем вкл/выкл и слайдером яркости — лучший вариант для демонстрации, не требует знаний терминала от зрителя.
  • systemd-юзер-сервис — для “фонового” запуска без какого-либо UI.
  • Локальная веб-панель (Flask/FastAPI + простая HTML-страница) — даёт управление с телефона/планшета в той же сети и попутно учит концепции клиент-сервер/REST.
  • pyinstaller — сборка в один исполняемый файл, чтобы не требовать от пользователя настройки Python/venv вручную.

“Эмоциональный” режим от микрофона. Архитектурно — да, без изменений на стороне ESP32 (см. THEORY.md, раздел 1 и 6): меняется только источник данных в Python. Честная реализация — “audio-reactive” режим (громкость→яркость, тон через FFT→оттенок), а не заявка на настоящее распознавание эмоций, у которого даже в лаборатории точность далека от 100% (см. THEORY.md, раздел 6 — хороший повод для разговора с учениками о реалистичных границах ИИ).