/* Скетч к проекту "Многофункциональный RGB светильник" Страница проекта (схемы, описания): https://alexgyver.ru/GyverLamp/ Исходники на GitHub: https://github.com/AlexGyver/GyverLamp/ Нравится, как написан код? Поддержи автора! https://alexgyver.ru/support_alex/ Автор: AlexGyver, AlexGyver Technologies, 2019 https://AlexGyver.ru/ */ /* Версия 1.5.1 - Оптимизировано обращение к серверу времени (нет подвисаний при отсутствии интернета) - Оптимизация под пины NodeMCU Версия 1.5.2 - Исправлен незначительный баг с таймером - Исправлено падение по WDT при выводе IP - Исправлен баг с переназначением времени будильника - Исправлено переключение с первого на последний режимы - Приложение автоматически получает настройки с кнопки - Бегущая строка с текущим временем во время рассвета Версия 1.5.3 - Увеличена плавность рассвета - Поправлен баг с отображением времени рассвета Версия 1.5.4 - Поправлены глюки во время рассвета */ // Ссылка для менеджера плат: // http://arduino.esp8266.com/stable/package_esp8266com_index.json // Для WEMOS выбираем плату LOLIN(WEMOS) D1 R2 & mini // Для NodeMCU выбираем NodeMCU 1.0 (ESP-12E Module) // ============= НАСТРОЙКИ ============= // -------- КНОПКА ------- #define USE_BUTTON 1 // 1 - использовать кнопку, 0 - нет // -------- ВРЕМЯ ------- #define GMT 3 // смещение (москва 3) #define NTP_ADDRESS "europe.pool.ntp.org" // сервер времени // -------- РАССВЕТ ------- #define DAWN_BRIGHT 200 // макс. яркость рассвета #define DAWN_TIMEOUT 1 // сколько рассвет светит после времени будильника, минут // ---------- МАТРИЦА --------- #define BRIGHTNESS 40 // стандартная маскимальная яркость (0-255) #define CURRENT_LIMIT 2000 // лимит по току в миллиамперах, автоматически управляет яркостью (пожалей свой блок питания!) 0 - выключить лимит #define WIDTH 16 // ширина матрицы #define HEIGHT 16 // высота матрицы #define COLOR_ORDER GRB // порядок цветов на ленте. Если цвет отображается некорректно - меняйте. Начать можно с RGB #define MATRIX_TYPE 0 // тип матрицы: 0 - зигзаг, 1 - параллельная #define CONNECTION_ANGLE 0 // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний #define STRIP_DIRECTION 0 // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз // при неправильной настройке матрицы вы получите предупреждение "Wrong matrix parameters! Set to default" // шпаргалка по настройке матрицы здесь! https://alexgyver.ru/matrix_guide/ // --------- ESP -------- #define ESP_MODE 1 // 0 - точка доступа // 1 - локальный byte IP_AP[] = {192, 168, 4, 66}; // статический IP точки доступа (менять только последнюю цифру) // ----- AP (точка доступа) ------- #define AP_SSID "GyverLamp" #define AP_PASS "12345678" #define AP_PORT 8888 // -------- Менеджер WiFi --------- #define AC_SSID "AutoConnectAP" #define AC_PASS "12345678" // ============= ДЛЯ РАЗРАБОТЧИКОВ ============= #define LED_PIN D4 // пин ленты #define BTN_PIN D2 #define MODE_AMOUNT 18 #define NUM_LEDS WIDTH * HEIGHT #define SEGMENTS 1 // диодов в одном "пикселе" (для создания матрицы из кусков ленты) // ---------------- БИБЛИОТЕКИ ----------------- #define FASTLED_INTERRUPT_RETRY_COUNT 0 #define FASTLED_ALLOW_INTERRUPTS 0 #define FASTLED_ESP8266_RAW_PIN_ORDER #define NTP_INTERVAL 60 * 1000 // обновление (1 минута) #include "timer2Minim.h" #include #include #include #include #include #include #include #include #include #include "fonts.h" // ------------------- ТИПЫ -------------------- CRGB leds[NUM_LEDS]; WiFiServer server(80); WiFiUDP Udp; WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, NTP_ADDRESS, GMT * 3600, NTP_INTERVAL); timerMinim timeTimer(1000); timerMinim timeStrTimer(120); GButton touch(BTN_PIN, LOW_PULL, NORM_OPEN); // ----------------- ПЕРЕМЕННЫЕ ------------------ const char* autoConnectSSID = AC_SSID; const char* autoConnectPass = AC_PASS; const char AP_NameChar[] = AP_SSID; const char WiFiPassword[] = AP_PASS; unsigned int localPort = AP_PORT; char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1]; //buffer to hold incoming packet String inputBuffer; static const byte maxDim = max(WIDTH, HEIGHT); struct { byte brightness = 50; byte speed = 30; byte scale = 40; } modes[MODE_AMOUNT]; struct { boolean state = false; int time = 0; } alarm[7]; const byte dawnOffsets[] = {5, 10, 15, 20, 25, 30, 40, 50, 60}; byte dawnMode; boolean dawnFlag = false; float thisTime; boolean manualOff = false; boolean sendSettings_flag = false; int8_t currentMode = 0; boolean loadingFlag = true; boolean ONflag = true; uint32_t eepromTimer; boolean settChanged = false; // Конфетти, Огонь, Радуга верт., Радуга гориз., Смена цвета, // Безумие 3D, Облака 3D, Лава 3D, Плазма 3D, Радуга 3D, // Павлин 3D, Зебра 3D, Лес 3D, Океан 3D, unsigned char matrixValue[8][16]; String lampIP = ""; byte hrs, mins, secs; byte days; String timeStr = "00:00"; void setup() { ESP.wdtDisable(); //ESP.wdtEnable(WDTO_8S); // ЛЕНТА FastLED.addLeds(leds, NUM_LEDS)/*.setCorrection( TypicalLEDStrip )*/; FastLED.setBrightness(BRIGHTNESS); if (CURRENT_LIMIT > 0) FastLED.setMaxPowerInVoltsAndMilliamps(5, CURRENT_LIMIT); FastLED.show(); touch.setStepTimeout(100); touch.setClickTimeout(500); Serial.begin(115200); Serial.println(); delay(1000); // WI-FI if (ESP_MODE == 0) { // режим точки доступа WiFi.softAPConfig(IPAddress(IP_AP[0], IP_AP[1], IP_AP[2], IP_AP[3]), IPAddress(192, 168, 4, 1), IPAddress(255, 255, 255, 0)); WiFi.softAP(AP_NameChar, WiFiPassword); IPAddress myIP = WiFi.softAPIP(); Serial.print("Access point Mode"); Serial.print("AP IP address: "); Serial.println(myIP); server.begin(); } else { // подключаемся к роутеру Serial.print("WiFi manager"); WiFiManager wifiManager; wifiManager.setDebugOutput(false); #if (USE_BUTTON == 1) if (digitalRead(BTN_PIN)) wifiManager.resetSettings(); #endif wifiManager.autoConnect(autoConnectSSID, autoConnectPass); /*WiFi.config(IPAddress(IP_STA[0], IP_STA[1], IP_STA[2], IP_STA[3]), IPAddress(192, 168, 1, 1), IPAddress(255, 255, 255, 0));*/ Serial.print("Connected! IP address: "); Serial.println(WiFi.localIP()); lampIP = WiFi.localIP().toString(); } Serial.printf("UDP server on port %d\n", localPort); Udp.begin(localPort); // EEPROM EEPROM.begin(202); delay(50); if (EEPROM.read(198) != 20) { // первый запуск EEPROM.write(198, 20); EEPROM.commit(); for (byte i = 0; i < MODE_AMOUNT; i++) { EEPROM.put(3 * i + 40, modes[i]); EEPROM.commit(); } for (byte i = 0; i < 7; i++) { EEPROM.write(5 * i, alarm[i].state); // рассвет eeWriteInt(5 * i + 1, alarm[i].time); EEPROM.commit(); } EEPROM.write(199, 0); // рассвет EEPROM.write(200, 0); // режим EEPROM.commit(); } for (byte i = 0; i < MODE_AMOUNT; i++) { EEPROM.get(3 * i + 40, modes[i]); } for (byte i = 0; i < 7; i++) { alarm[i].state = EEPROM.read(5 * i); alarm[i].time = eeGetInt(5 * i + 1); } dawnMode = EEPROM.read(199); currentMode = (int8_t)EEPROM.read(200); // отправляем настройки sendSettings(); timeClient.begin(); memset(matrixValue, 0, sizeof(matrixValue)); randomSeed(micros()); // получаем время byte count = 0; while (count < 5) { if (timeClient.update()) { hrs = timeClient.getHours(); mins = timeClient.getMinutes(); secs = timeClient.getSeconds(); days = timeClient.getDay(); break; } count++; delay(500); } updTime(); } void loop() { parseUDP(); effectsTick(); eepromTick(); timeTick(); #if (USE_BUTTON == 1) buttonTick(); #endif ESP.wdtFeed(); // пнуть собаку yield(); // ещё раз пнуть собаку } void eeWriteInt(int pos, int val) { byte* p = (byte*) &val; EEPROM.write(pos, *p); EEPROM.write(pos + 1, *(p + 1)); EEPROM.write(pos + 2, *(p + 2)); EEPROM.write(pos + 3, *(p + 3)); EEPROM.commit(); } int eeGetInt(int pos) { int val; byte* p = (byte*) &val; *p = EEPROM.read(pos); *(p + 1) = EEPROM.read(pos + 1); *(p + 2) = EEPROM.read(pos + 2); *(p + 3) = EEPROM.read(pos + 3); return val; }