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


#include <FastLED.h>

// --- НАСТРОЙКИ ---
#define LED_PIN     25       // Пин управления светодиодами (GPIO 25)
#define BUTTON_PIN  4        // Пин кнопки (вы можете изменить на любой свободный, например, 13 или 21)
#define NUM_LEDS    60       // Укажите количество светодиодов в вашей ленте/кольце
#define BRIGHTNESS  120      // Яркость (от 0 до 255), чтобы не слепило

CRGB leds[NUM_LEDS];

// --- ПАЛИТРА ИЗ 12 ПРИЯТНЫХ СТАТИЧНЫХ ЦВЕТОВ ---
const CRGB pleasantColors[12] = {
  CRGB(255, 120, 50),   // 0. Теплый янтарный (мягкий закатный)
  CRGB(255, 150, 100),  // 1. Пастельный персиковый
  CRGB(255, 100, 150),  // 2. Нежно-розовый
  CRGB(180, 100, 255),  // 3. Мягкий лавандовый
  CRGB(100, 130, 255),  // 4. Спокойный васильковый
  CRGB(50, 180, 255),   // 5. Небесно-голубой
  CRGB(50, 220, 180),   // 6. Бирюзово-мятный
  CRGB(80, 240, 120),   // 7. Светло-салатовый (пастельный)
  CRGB(220, 220, 100),  // 8. Теплый золотистый/песочный
  CRGB(255, 180, 50),   // 9. Медовый
  CRGB(200, 150, 220),  // 10. Сиреневая дымка
  CRGB(220, 220, 220)   // 11. Теплый белый (уютный)
};

// --- СОСТОЯНИЯ ---
int currentHueIndex = 0;   // Индекс текущего цвета (0-11)
int currentMode = 0;       // Текущий режим анимации (0-5)
const int totalModes = 6;  // Всего модов анимации

// Переменные для обработки кнопки с антидребезгом и определением длинного нажатия
unsigned long buttonPressStartTime = 0;
bool buttonIsPressed = false;
bool longPressHandled = false;
const unsigned long longPressTime = 500; // Время длинного нажатия в миллисекундах (0.5 сек)

void setup() {
  Serial.begin(115200);
  
  // Инициализация ленты FastLED (используем WS2812B, порядок цветов GRB)
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(BRIGHTNESS);

  // Настройка пина кнопки (используем внутреннюю подтяжку к питанию, 
  // так как вы говорили, что хотите замыкать в минус / GND)
  pinMode(BUTTON_PIN, INPUT_PULLUP);
}

void loop() {
  handleButton();
  runCurrentMode();
  FastLED.delay(15); // Небольшая задержка для стабильности анимаций (~60 FPS)
}

// --- ЛОГИКА КНОПКИ (КОРОТКОЕ / ДОЛГОЕ НАЖАТИЕ) ---
void handleButton() {
  // Кнопка подключена к GND, поэтому при нажатии читается LOW
  bool reading = (digitalRead(BUTTON_PIN) == LOW);

  if (reading && !buttonIsPressed) {
    // Кнопка только что нажата
    buttonIsPressed = true;
    buttonPressStartTime = millis();
    longPressHandled = false;
  } 
  else if (reading && buttonIsPressed) {
    // Кнопка удерживается, проверяем на длинное нажатие
    if (!longPressHandled && (millis() - buttonPressStartTime >= longPressTime)) {
      // Сработало ДОЛГОЕ нажатие -> меняем МОД анимации
      currentMode = (currentMode + 1) % totalModes;
      longPressHandled = true;
      Serial.print("Смена мода анимации на: ");
      Serial.println(currentMode);
    }
  } 
  else if (!reading && buttonIsPressed) {
    // Кнопка отпущена
    buttonIsPressed = false;
    // Если долгое нажатие НЕ срабатывало, значит это было КОРОТКОЕ нажатие
    if (!longPressHandled) {
      // Сработало КОРОТКОЕ нажатие -> меняем ЦВЕТ
      currentHueIndex = (currentHueIndex + 1) % 12;
      Serial.print("Смена цвета на индекс: ");
      Serial.println(currentHueIndex);
    }
  }
}

// --- ВЫПОЛНЕНИЕ ТЕКУЩЕГО МОДА АНИМАЦИИ ---
void runCurrentMode() {
  CRGB baseColor = pleasantColors[currentHueIndex];

  switch (currentMode) {
    case 0:
      // Мод 0: Статичное свечение выбранным цветом
      fill_solid(leds, NUM_LEDS, baseColor);
      break;

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

    case 2:
      // Мод 2: Бегающая волна (плавный перелив яркости вдоль ленты)
      for (int i = 0; i < NUM_LEDS; i++) {
        float wave = (sin(millis() / 200.0 + i * 0.2) + 1.0) / 2.0;
        CRGB waveColor = baseColor;
        waveColor.nscale8(wave * 255);
        leds[i] = waveColor;
      }
      break;

    case 3:
      // Мод 3: Бегающая точка-искра на фоне выбранного приглушенного цвета
      {
        fadeToBlackBy(leds, NUM_LEDS, 40);
        int pos = (millis() / 50) % NUM_LEDS;
        leds[pos] = CRGB::White; // Белая искра бегает по выбранному цвету
        // Заполняем фон приглушенным цветом
        for(int i=0; i<NUM_LEDS; i++) {
          if(i != pos) {
            CRGB dimColor = baseColor;
            dimColor.nscale8(100);
            leds[i] = dimColor;
          }
        }
      }
      break;

    case 4:
      // Мод 4: Переливающийся градиент (плавный переход оттенков вокруг выбранного цвета)
      fill_gradient_rainbow(leds, NUM_LEDS, currentHueIndex * 21); // Сдвигаем палитру по кругу
      break;

    case 5:
      // Мод 5: Плавное мерцание (эффект тлеющих угольков / мягких переливов)
      {
        fadeToBlackBy(leds, NUM_LEDS, 20);
        if (random8() < 40) {
          int idx = random16(NUM_LEDS);
          leds[idx] = baseColor;
        }
      }
      break;
  }
}

// Вспомогательная функция для плавности дыхания
uint8_t triangularScale(float val) {
  return (uint8_t)(val * 255);
}