Загрузка данных


#include <FastLED.h>

#define LED_PIN     25       // Пин управления светодиодами (GPIO 25)
#define BUTTON_PIN  4        // Пин кнопки (на GND)
#define NUM_LEDS    10       // Всего 10 светодиодов
#define BRIGHTNESS  130      // Комфортная яркость

CRGB leds[NUM_LEDS];
CRGB realLeds[NUM_LEDS];

// --- НАСЫЩЕННАЯ И СБАЛАНСИРОВАННАЯ ПАЛИТРА (для статики и цветовых модов) ---
const CRGB balancedColors[] = {
  CRGB(255, 30, 30),    // 0. Насыщенный красный
  CRGB(0, 220, 50),     // 1. Сочный зеленый
  CRGB(0, 100, 255),    // 2. Глубокий синий
  CRGB(255, 255, 255),  // 3. Чистый белый
  CRGB(255, 180, 0),    // 4. Теплый янтарно-желтый
  CRGB(0, 220, 220),    // 5. Бирюзовый
  CRGB(255, 50, 150),   // 6. Малиново-розовый
  CRGB(255, 100, 0),    // 7. Насыщенный оранжевый
  CRGB(140, 50, 255)    // 8. Благородный фиолетовый
};
const int totalColors = 9;

int currentColorIndex = 0;
int currentMode = 0;       
const int totalModes = 7;  // Всего 7 крутых плавных модов анимации!

// --- ПЕРЕМЕННЫЕ ДЛЯ АНТИДРЕБЕЗГА КНОПКИ ---
bool lastButtonState = HIGH;      
bool buttonState = HIGH;          
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50; 

unsigned long pressStartTime = 0;
bool waitingForRelease = false;
bool longPressTriggered = false;
const unsigned long longPressTime = 600; // 0.6 сек для долгого удержания

void setup() {
  Serial.begin(115200);
  Serial.println("System initialized with smooth animations & gradient.");
  
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(realLeds, NUM_LEDS);
  FastLED.setBrightness(BRIGHTNESS);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
}

void loop() {
  handleButtonWithDebounce();

  // Выполнение текущего анимационного режима
  runCurrentAnimation();

  // Перенос в физический порядок под вашу плату
  for (int i = 0; i < NUM_LEDS; i++) {
    realLeds[getPhysicalIndex(i)] = leds[i];
  }
  
  FastLED.show();
  FastLED.delay(15); // Плавный фреймрейт (~66 FPS)
}

int getPhysicalIndex(int logicalIndex) {
  const int mapTable[10] = {3, 2, 1, 0, 4, 5, 6, 7, 8, 9}; 
  return mapTable[logicalIndex];
}

// --- УПРАВЛЕНИЕ КНОПКОЙ ---
void handleButtonWithDebounce() {
  int reading = digitalRead(BUTTON_PIN);

  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;

      if (buttonState == LOW) {
        pressStartTime = millis();
        longPressTriggered = false;
        waitingForRelease = true;
      } 
      else if (buttonState == HIGH && waitingForRelease) {
        waitingForRelease = false;
        if (!longPressTriggered) {
          // Короткое нажатие -> меняет цвет (для модов, зависящих от цвета)
          currentColorIndex = (currentColorIndex + 1) % totalColors;
          Serial.print("Цвет изменен на индекс: ");
          Serial.println(currentColorIndex);
        }
      }
    }
  }

  // Долгое нажатие -> переключает режим анимации
  if (waitingForRelease && !longPressTriggered) {
    if (millis() - pressStartTime >= longPressTime) {
      currentMode = (currentMode + 1) % totalModes;
      longPressTriggered = true; 
      Serial.print("Режим анимации изменен на: ");
      Serial.println(currentMode);
    }
  }

  lastButtonState = reading;
}

// --- 7 ПЛАВНЫХ И КРАСИВЫХ АНИМАЦИОННЫХ МОДОВ ---
void runCurrentAnimation() {
  CRGB baseColor = balancedColors[currentColorIndex];

  switch (currentMode) {
    case 0:
      // МОД 0: Плавный переливающийся РАДУЖНЫЙ ГРАДИЕНТ (меняется сам, цвет кнопки не нужен)
      {
        uint8_t startIndex = millis() / 20;
        fill_rainbow(leds, NUM_LEDS, startIndex, 15); // Плавная бегущая радуга по всей плате
      }
      break;

    case 1:
      // МОД 1: Статичное свечение выбранным цветом
      fill_solid(leds, NUM_LEDS, baseColor);
      break;

    case 2:
      // МОД 2: Мягкое «дыхание» выбранным цветом (плавное затухание и розжиг)
      {
        float breath = (sin(millis() / 400.0) + 1.0) / 2.0; // от 0.0 до 1.0
        CRGB breathColor = baseColor;
        breathColor.nscale8(breath * 255);
        fill_solid(leds, NUM_LEDS, breathColor);
      }
      break;

    case 3:
      // МОД 3: Плавная бегущая волна выбранного цвета слева направо
      {
        for (int i = 0; i < NUM_LEDS; i++) {
          float wave = (sin(millis() / 200.0 - i * 0.5) + 1.0) / 2.0;
          CRGB waveColor = baseColor;
          waveColor.nscale8(wave * 255);
          leds[i] = waveColor;
        }
      }
      break;

    case 4:
      // МОД 4: Двухсторонняя волна (перелив от центра к краям)
      {
        float t = millis() / 250.0;
        for (int i = 0; i < NUM_LEDS; i++) {
          float dist = abs(i - 4.5); // центр платы
          float wave = (sin(t - dist * 0.6) + 1.0) / 2.0;
          CRGB waveColor = baseColor;
          waveColor.nscale8(wave * 255);
          leds[i] = waveColor;
        }
      }
      break;

    case 5:
      // МОД 5: Плавный перелив цвета в цвет (индивидуальный цветовой градиент для выбранного тона)
      {
        for (int i = 0; i < NUM_LEDS; i++) {
          // Смешиваем базовый цвет с соседним оттенком по кругу палитры
          CRGB nextColor = balancedColors[(currentColorIndex + 1) % totalColors];
          float mix = (sin(millis() / 300.0 + i * 0.4) + 1.0) / 2.0;
          leds[i] = blend(baseColor, nextColor, mix * 255);
        }
      }
      break;

    case 6:
      // МОД 6: Мягкое мерцание / перелив «живые искорки» на выбранном цвете
      {
        fadeToBlackBy(leds, NUM_LEDS, 15); // Очень плавное угасание
        if (random8() < 30) {
          int idx = random8(NUM_LEDS);
          leds[idx] = baseColor;
          leds[idx].maximizeBrightness(); // Делаем искорку чуть ярче и сочнее
        }
      }
      break;
  }
}