# Ambilight на ESP32 + SK6812

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

## Установка ПО

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

```bash
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`)

```bash
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 — хороший повод для разговора с учениками
о реалистичных границах ИИ).
