/*
   Гирлянда на ESP8266 v2.01
*/
#if defined(ESP8266)
#include <ESP8266WiFi.h>        //Содержится в пакете
#include <ESP8266WebServer.h>   //Содержится в пакете
#endif
#if defined(ESP32)
#include <WebServer.h>
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#endif

/* для Led */
#include "FastLED.h"
FASTLED_USING_NAMESPACE

#if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000)
#warning "Requires FastLED 3.1 or later; check github for latest code."
#endif
/* Переменные */
// можно менять //
#ifdef ESP8266
#define DATA_PIN    6     // пин для вывода на гирлянду
byte button_rejim = D2;  // пин подключения кнопки
#else
#define DATA_PIN    19   // пин для вывода на гирлянду
byte button_rejim = 21;  // пин подключения кнопки
#endif

#define LED_TYPE WS2812B        // What kind of strip are you using (APA102, WS2801 or WS2812B)?
#define COLOR_ORDER GRB         // It's GRB for WS2812B
#define NUM_LEDS    30          // кол-во светодиодов в гирлянде 33 
#define NUM_LEDS_STAR    5      // + 5 звезда
CRGB leds[NUM_LEDS + NUM_LEDS_STAR];

#define TIMER_MS 60      // время длительности одного эффекта 
                          //в сек. для авто режима

/* настройка wi-fi */
IPAddress apIP(192, 168, 4, 1);
// Web интерфейс для устройства
#ifdef ESP8266
// Web интерфейс для устройства
ESP8266WebServer HTTP(80);
#else
// Web интерфейс для устройства
WebServer HTTP(80);
#endif
// Определяем переменные wifi
String _ssid     = "Wi-Fi"; // Для хранения SSID
String _password = "12345678"; // Для хранения пароля сети
String _ssidAP = "ATGarland";   // SSID AP точки доступа
String _passwordAP = "012345678"; // пароль точки доступа

String Effect(int n)  // Название эффектов выводиться в приложении
{
  char* effects[] = {
    "конфетти 2","Радуга с блестками","жонглирование 2","синелон 2",
    "конфетти","синелон", "радуга","жонглирование","синелон 3","bpm",
    "полное заполнение", "жонглирование 3", "мерцание","три цвета","матрица"  };

  return effects[n];
}
// массив функций эффектов
typedef void (*SimplePatternList[])();
SimplePatternList gPatterns = { confetti2, rainbowWithGlitter, juggle2, sinelon2, 
confetti, sinelon, rainbow, juggle, sinelon3, bpm, 
cylonfill,juggle3,twinkle,three_sin,matrix };


// Не менять //
uint8_t gCurrentPatternNumber = 0; // порядковый номер эффекта
uint8_t gHue = 0; // "базовый цвет" используется многими эффектами
uint8_t i = 0; // счётчик индекса в массиве эффектов
uint8_t j = 0; // Счечик яркости
boolean auto_rejim = false; // авто режим выкл.
unsigned long last_change = 0; // предыдущее значениее времени
unsigned long now = 0; //текущее значениее времени
boolean lastButten = LOW;     // предыдущее состояние кнопки
boolean currentButten = LOW;  // текущее состояние кнопки
long prestroMillis = 0;        // время для кнопки, до
int interval = 4000;// Время изменения яркости после выход
byte flag = 0;      // состояние кнопки

void setup() {

  pinMode(button_rejim, INPUT); // настроить пин кнопки

  Serial.begin(115200);
  Serial.println("");

  Serial.println("Start WIFI");
  //Запускаем WIFI
  WIFIinit();
  //Настраиваем и запускаем HTTP интерфейс
  Serial.println("Start WebServer");
  HTTP_init();
  
  //Инициализируем работу со светодиодами. 
  FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS + NUM_LEDS_STAR).setCorrection(TypicalLEDStrip);
  
  // Источник питания 1A 5v 
   FastLED.setMaxPowerInVoltsAndMilliamps(5,2000); 
   
  // set master brightness control
  FastLED.setBrightness(160);
  
  for (int i = NUM_LEDS; i < (NUM_LEDS + NUM_LEDS_STAR); i++) {
    // Set the i'th led to red
    leds[i] = CRGB::Red;
    // Show the leds
    FastLED.show();
  }
}


void loop() {
  HTTP.handleClient();
  delay(2);
  // Call the current pattern function once, updating the 'leds' array
  gPatterns[gCurrentPatternNumber]();

  // send the 'leds' array out to the actual LED strip
  FastLED.show();

  // do some periodic updates
  EVERY_N_MILLISECONDS( 20 ) {
    gHue++;  // slowly cycle the "base color" through the rainbow
  }

  if (auto_rejim)
  {
    EVERY_N_SECONDS( TIMER_MS ) {
      nextPattern();
    }
  }
  #if defined(ESP8266)
      Led();
  #endif
  
}

/*
   Гирлянда на ESP8266 v2.01
 */

void HTTP_init(void) {
  HTTP.onNotFound(handleNotFound); // Сообщение если нет страницы. Попробуйте ввести http://192.168.0.101/restar?device=ok&test=1&led=on
  HTTP.on("/led", handle_Led); // Упровляем Led http://192.168.0.101/ 
  HTTP.on("/light", handle_Light);  /// Яркасть
  HTTP.on("/effect", handle_Effect); /// вывод текущего эффекта
  HTTP.on("/color", handle_Color);  // выбор цвета
  // Запускаем HTTP сервер
  HTTP.begin();

}

// Ответ если страница не найдена
void handleNotFound() {
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += HTTP.uri();
  message += "\nMethod: ";
  message += (HTTP.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += HTTP.args();
  message += "\n";
  for (uint8_t i = 0; i < HTTP.args(); i++) {
    message += " " + HTTP.argName(i) + ": " + HTTP.arg(i) + "\n";
  }
  HTTP.send(404, "text/plain", message);
}

// Переключение режимов http://192.168.0.101/led?status={переменная}
void handle_Led() {
  String status = HTTP.arg("status");
  if (status == "next")
  {
    nextPattern();  // change patterns periodically
    //Serial.println(modes[i]);
    auto_rejim = false;
    //HTTP.send(200, "text/plain", Effect(gCurrentPatternNumber));
  }

  if (status == "prev")
  {
    prevPattern();  // change patterns periodically
    auto_rejim = false;
    HTTP.send(200, "text/plain", Effect(gCurrentPatternNumber));
  }

  if (status == "auto")
  {
    auto_rejim = true;
    Serial.println("auto");
    HTTP.send(200, "text/plain", Effect(gCurrentPatternNumber));
  }
}

void handle_Light()
{
  String num = HTTP.arg("num");
  Serial.println(num);
  if (num)
  {
    int intNum = num.toInt();
    if (intNum > 0)
    {
      j = map(intNum, 1, 100, 0, 255);
      FastLED.setBrightness(j);
      HTTP.send(200, "text/plain",  Effect(gCurrentPatternNumber));

    }
    else
      HTTP.send(200, "text/plain", "0");

  }
}

void handle_Color()
{
  String num = HTTP.arg("num");
  Serial.println(num);
  if (num)
  {
    int intNum = num.toInt();
    if (intNum > 0)
    {
      if (intNum == 4)
      {
        for (int i = NUM_LEDS; i < (NUM_LEDS + NUM_LEDS_STAR); i++) {
          // Set the i'th led to red
          leds[i] = CRGB::Red;
          // Show the leds
          FastLED.show();
        }
      }
      if (intNum == 5)
      {
        for (int i = NUM_LEDS; i < (NUM_LEDS + NUM_LEDS_STAR); i++) {
          // Set the i'th led to red
          leds[i] = CRGB::Blue;
          // Show the leds
          FastLED.show();
        }
      }
      if (intNum == 6)
      {
        for (int i = NUM_LEDS; i < (NUM_LEDS + NUM_LEDS_STAR); i++) {
          // Set the i'th led to red
          leds[i] = CRGB::Green;
          // Show the leds
          FastLED.show();
        }
      }
      if (intNum == 7)
      {
        for (int i = NUM_LEDS; i < (NUM_LEDS + NUM_LEDS_STAR); i++) {
          // Set the i'th led to red
          leds[i] = CRGB::Orange;
          // Show the leds
          FastLED.show();
        }
      }
      if (intNum == 8)
      {
        for (int i = NUM_LEDS; i < (NUM_LEDS + NUM_LEDS_STAR); i++) {
          // Set the i'th led to red
          leds[i] = CRGB::Yellow;
          // Show the leds
          FastLED.show();
        }
      }
      if (intNum == 9)
      {
        for (int i = NUM_LEDS; i < (NUM_LEDS + NUM_LEDS_STAR); i++) {
          // Set the i'th led to red
          leds[i] = CRGB::Purple;
          // Show the leds
          FastLED.show();
        }
      }

      HTTP.send(200, "text/plain", Effect(gCurrentPatternNumber));
    }
    else
      HTTP.send(200, "text/plain", "0");
  }
}

void handle_Effect()
{
  String ef = HTTP.arg("ef");
  if (ef)
  {
    int intEf = ef.toInt();
    if (intEf > 0)
    {
      String str = "[" + String(intEf - 1) + "] " ;
      HTTP.send(200, "text/plain", Effect(gCurrentPatternNumber));
    }
  }
}

/*
   Гирлянда на ESP8266 v2.01
*/
/*
    Набо эффектов 
*/ 
int x = 1;
// Initialize global variables for sequences
int thisdelay = 150;                                           // A delay value for the sequence(s)
int thishue = 50;
int thissat = 255;
int thisdir = 20;
bool huerot = 70; 

// Does the hue rotate? 1 = yes
// Routine specific variables
uint8_t numdots = 8;                                          // Number of dots in use.
uint8_t faderate = 1;                                         // How long should the trails be. Very low value = longer trails.
uint8_t hueinc = 6;                                          // Incremental change in hue between each dot.
//uint8_t thishue = 20;                                          // Starting hue.
uint8_t curhue = 10;                                           // The current hue
//uint8_t thissat = 255;                                        // Saturation of the colour.
uint8_t thisbright = 255;                                     // How bright should the LED/display be.
uint8_t basebeat = 1;   // Higher = faster movement.

int wave1=5;                                            // Current phase is calculated.
int wave2=0;
int wave3=0;

uint8_t inc1 = 2;                                       // Phase shift. Keep it low, as this is the speed at which the waves move.
uint8_t inc2 = -11;
uint8_t inc3 = -2;

uint8_t lvl1 = 180;                                      // Any result below this value is displayed as 0.
uint8_t lvl2 = 80;
uint8_t lvl3 = 80;

uint8_t mul1 = 2;                                      // Frequency, thus the distance between waves
uint8_t mul2 = 5;
uint8_t mul3 = 22;

// 1 //
void confetti2() 
{
  // random colored speckles that blink in and fade smoothly
  fadeToBlackBy( leds, NUM_LEDS, 10);
  int pos = random16(NUM_LEDS);
  leds[pos] += CHSV( gHue + random8(64), 200, 255);
}

// 2 //
void rainbowWithGlitter() 
{
  // built-in FastLED rainbow, plus some random sparkly glitter
  rainbow2();
  addGlitter(80);
  //addGlitter(10);
}
void rainbow2() 
{
  // FastLED's built-in rainbow generator
  fill_rainbow( leds, NUM_LEDS, gHue, 2);
}
void addGlitter( fract8 chanceOfGlitter) 
{
  if( random8() < chanceOfGlitter) {
    leds[ random16(NUM_LEDS) ] += CRGB::White;
    //leds[ random16(NUM_LEDS) ] += 0xFFFFFF;
  }
}
// end 2 //

// 3 //
void cyclon() { 
  static uint8_t hue = 0;
  // First slide the led in one direction
  for(int i = 0; i < NUM_LEDS; i++) {
    // Set the i'th led to red 
    //leds[i] = CHSV(hue++, 255, 255);
    leds[i] = 0xAAAAAA;
    // Show the leds
    FastLED.show(); 
    //leds[i] = CHSV(hue++, 255, 255); FastLED.show();
    // now that we've shown the leds, reset the i'th led to black
    leds[i] = CRGB::Black;
    leds[i] = CHSV(hue++, 255, 255); FastLED.show();
    fadeall();
    // Wait a little bit before we loop around and do it again
    delay(10);
  }

  // Now go in the other direction.  
  for(int i = (NUM_LEDS)-1; i >= 0; i--) {
    // Set the i'th led to red 
    //leds[i] = 0xAAAAAA;
    leds[i] = CHSV(hue++, 255, 255);
    // Show the leds
    FastLED.show();
    // now that we've shown the leds, reset the i'th led to black
    // leds[i] = CRGB::Black;
    fadeall();
    // Wait a little bit before we loop around and do it again
    delay(30);
  }
}
void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } }
// end 3 //

// 4 //
void juggle2() { 
  // eight colored dots, weaving in and out of sync with each other
  fadeToBlackBy( leds, NUM_LEDS, 20);
  //fadeToBlackBy( leds, NUM_LEDS, 5);
  byte dothue = 0;
  for( int i = 0; i < 8; i++) {
    leds[beatsin16( i+7, 0, NUM_LEDS-1 )] |= CHSV(dothue, 200, 255);
    dothue += 32;
  }
}

// 5 //
void sinelon2() 
{
  // a colored dot sweeping back and forth, with fading trails
  //fadeToBlackBy( leds, NUM_LEDS, 20);
  fadeToBlackBy( leds, NUM_LEDS, 2);
  int pos = beatsin16( 13, 0, NUM_LEDS-1 );
  leds[pos] += CHSV( gHue, 255, 192);
}

// 6 //
void confetti()  
{
  // random colored speckles that blink in and fade smoothly
  fadeToBlackBy( leds, NUM_LEDS, 5);
  int pos = random16(NUM_LEDS);
  leds[pos] += CHSV( gHue + random8(64), 200, 255);
  delay(30);
}

// 7 //
void sinelon() 
{
  // a colored dot sweeping back and forth, with fading trails
  //fadeToBlackBy( leds, NUM_LEDS, 20);
  fadeToBlackBy( leds, NUM_LEDS, 20);
  int pos = beatsin16( 13, 0, NUM_LEDS-1 );
  leds[pos] += CHSV( gHue, 255, 192);
}

// 8 //
void rainbow() 
{
  // FastLED's built-in rainbow generator
  fill_rainbow( leds, NUM_LEDS, gHue, 7);
}

// 9 //
void juggle() { 
  // eight colored dots, weaving in and out of sync with each other
  fadeToBlackBy( leds, NUM_LEDS, 3);
  //fadeToBlackBy( leds, NUM_LEDS, 5);
  byte dothue = 0;
  for( int i = 0; i < 8; i++) {
    leds[beatsin16( i+7, 0, NUM_LEDS-1 )] |= CHSV(dothue, 200, 255);
    dothue += 50;
  }
}

// 10 //
void sinelon3() 
{
  // a colored dot sweeping back and forth, with fading trails
  //fadeToBlackBy( leds, NUM_LEDS, 20);
  fadeToBlackBy( leds, NUM_LEDS, 5);
  int pos = beatsin16( 3, 0, NUM_LEDS-1 );
  leds[pos] += CHSV( gHue, 255, 192);
}

// 11 //
void bpm() 
{
  // colored stripes pulsing at a defined Beats-Per-Minute (BPM)
  uint8_t BeatsPerMinute = 62;
  CRGBPalette16 palette = PartyColors_p;
  uint8_t beat = beatsin8( BeatsPerMinute, 64, 255);
  for( int i = 0; i < NUM_LEDS; i++) { //9948
    leds[i] = ColorFromPalette(palette, gHue+(i*2), beat-gHue+(i*10));
  }
}
//12 //
void cylonfill(){
  // First slide the led in one direction
  for(int i = 0; i < NUM_LEDS-x; i++) {
    // Set the i'th led to red 
    leds[i] = CRGB::Blue;
    // Show the leds
    FastLED.show();
    // now that we've shown the leds, reset the i'th led to black
    leds[i] = CRGB::Green;
    // Wait a little bit before we loop around and do it again
    delay(16);
   }
        
        leds[NUM_LEDS -x] = CRGB::Orange;
        FastLED.show();
        x++;
        if (x ==NUM_LEDS){
          x =1;
        }
        Serial.println(x);
  // Now go in the other direction.  
  for(int i = NUM_LEDS-x; i >= 2; i--) {
    // Set the i'th led to red 
    leds[i] = CRGB::Purple;
    // Show the leds
    FastLED.show();
    // now that we've shown the leds, reset the i'th led to black
    leds[i] = CRGB::Black;
    // Wait a little bit before we loop around and do it again
  //  delay(1);
  }
}

//13//
void juggle3() {                                               // Several colored dots, weaving in and out of sync with each other
  curhue = thishue;                                          // Reset the hue values.
  fadeToBlackBy(leds, NUM_LEDS, faderate);
  for( int i = 0; i < numdots; i++) {
    leds[beatsin16(basebeat+i+numdots,0,NUM_LEDS)] += CHSV(curhue, thissat, thisbright);   //beat16 is a FastLED 3.1 function
    curhue += hueinc;
  }
} // juggle()

//14//
void twinkle() {
  int i = random(NUM_LEDS);                                           // A random number. Higher number => fewer twinkles. Use random16() for values >255.
  if (i < NUM_LEDS) leds[i] = CHSV(random(255), random(255), random(255));              // Only the lowest probability twinkles will do. You could even randomize the hue/saturation. .
  for (int j = 0; j < NUM_LEDS; j++) leds[j].fadeToBlackBy(8);
  
  LEDS.show();                                                // Standard FastLED display
  //show_at_max_brightness_for_power();                          // Power managed FastLED display

  //delay(10);                                            // Standard delay
  LEDS.delay(50);                                     // FastLED delay 
  //delay_at_max_brightness_for_power(thisdelay);              // Power managed FastLED delay
} // twinkle()

//15//
void three_sin() {
  wave1 += inc1;
  wave2 += inc2;
  wave3 += inc3;
  for (int k=0; k<NUM_LEDS; k++) {
    leds[k].r = qsub8(sin8(mul1*k + wave1/128), lvl1);         // Another fixed frequency, variable phase sine wave with lowered level
    leds[k].g = qsub8(sin8(mul2*k + wave2/128), lvl2);         // A fixed frequency, variable phase sine wave with lowered level
    leds[k].b = qsub8(sin8(mul3*k + wave3/128), lvl3);         // A fixed frequency, variable phase sine wave with lowered level
  }
} // three_sin()

//16//
void matrix() {                                               // One line matrix

  if (huerot) thishue=thishue+5;

  if (random16(90) > 80) {
    if (thisdir == 0) leds[0] = CHSV(thishue, thissat, 255); else leds[NUM_LEDS-1] = CHSV(thishue, thissat, 255);
  }
  else {leds[0] = CHSV(thishue, thissat, 0);}

  if (thisdir == 0) {
    for (int i = NUM_LEDS-1; i >0 ; i-- ) leds[i] = leds[i-1];
  } else {
    for (int i = 0; i < NUM_LEDS ; i++ ) leds[i] = leds[i+1];
  }
} // matrix()

/*
   Код упровления светодиодами 
*/ 
void Led() {  // Авто режим и переключение кнопкой

  currentButten = debvance (lastButten); // Передаем функции дребезга значение по умолчанию LOW
  if (lastButten == LOW && currentButten == HIGH ) // Проверяем отпускали мы кнопку или нет
  {
    prestroMillis = millis();
    interval = 1000;
  }
  if (currentButten == HIGH) // Проверяем отпускали мы кнопку или нет
  {
    unsigned long curstroMillis = millis();  // устанавливаем время в сейчас
    if ((curstroMillis - prestroMillis) > interval) // проверяем интервал
    {
      if ( flag == 1)
      {
        j=j+5;
        if (j > 250)
          j = 1;
        FastLED.setBrightness(j);
        prestroMillis = curstroMillis;
      }
      else
      {
        flag = 1;
        interval = 100;
      }
    }
  }

  if (lastButten == HIGH && currentButten == LOW) // Проверяем отпускали мы кнопку или нет
  {
    if (flag == 1)
      flag = 0;
    else
    {
      nextPattern();  // change patterns periodically
      //Serial.println(modes[i]);
      auto_rejim = false;
    }
  }
  lastButten =  currentButten;  // Переприсваеваем прошлое состояние кнопки

}


boolean debvance (boolean last) //убираем дребизг
{
  boolean current = digitalRead (button_rejim); // считываем данные с кнопки
  if (last != current) // Если текущее состояни еотличететься от предыдущего
  {
    delay (5);   // Ждем 5 милисек.
    current = digitalRead (button_rejim); // Присваеваем текущее состояние кнопки
    return current;
  }
}

#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) // подчет эффектов

void nextPattern() // переключение на следующий эффект
{
  if (gCurrentPatternNumber  == (ARRAY_SIZE( gPatterns)-1))
    gCurrentPatternNumber = 0;
  else
    gCurrentPatternNumber = (gCurrentPatternNumber + 1);
  Serial.println(gCurrentPatternNumber);
  HTTP.send(200, "text/plain", Effect(gCurrentPatternNumber));
}

void prevPattern() // переключение на предыдущий эффект
{
  if (gCurrentPatternNumber  == 0)
    gCurrentPatternNumber = ARRAY_SIZE( gPatterns)-1;
  else
    gCurrentPatternNumber = (gCurrentPatternNumber - 1);
  Serial.println(gCurrentPatternNumber);
  HTTP.send(200, "text/plain", Effect(gCurrentPatternNumber));
}

/*
   Гирлянда на ESP8266 v2.01
   Страница проекта: https://arduino-tex.ru/news/29/elochnaya-girlyanda-na-esp8266-esp32-upravlenie-s-prilozheniya.html
   Сайт разработчика https://portal-pk.ru/
   Проекты на Arduino https://portal-pk.ru/page-17/proekty-na-arduino.html
   Проекты на ESP https://portal-pk.ru/page-18/proekty-na-nodemcu-esp8266-esp-01.html
*/

void WIFIinit() {
  // Попытка подключения к точке доступа
  WiFi.mode(WIFI_STA);
  byte tries = 10;
  WiFi.begin(_ssid.c_str(), _password.c_str());
  // Делаем проверку подключения до тех пор пока счетчик tries
  // не станет равен нулю или не получим подключение
  while (--tries && WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(500);
  }
  if (WiFi.status() != WL_CONNECTED)
  {
    // Если не удалось подключиться запускаем в режиме AP
    Serial.println("");
    Serial.println("WiFi up AP");
    StartAPMode();
  }
  else {
    // Иначе удалось подключиться отправляем сообщение
    // о подключении и выводим адрес IP
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
  }
}

bool StartAPMode()
{ // Отключаем WIFI
  WiFi.disconnect();
  // Меняем режим на режим точки доступа
  WiFi.mode(WIFI_AP);
  // Задаем настройки сети
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  // Включаем WIFI в режиме точки доступа с именем и паролем
  // хронящихся в переменных _ssidAP _passwordAP
  WiFi.softAP(_ssidAP.c_str(), _passwordAP.c_str());
  return true;
}
FPS: 0
Power: 0.00W