diff --git a/Android/GyverLamp2.aia b/Android/GyverLamp2.aia index fa3c60c..4d835c6 100644 Binary files a/Android/GyverLamp2.aia and b/Android/GyverLamp2.aia differ diff --git a/Android/GyverLamp2.apk b/Android/GyverLamp2.apk index a93b807..06dc7be 100644 Binary files a/Android/GyverLamp2.apk and b/Android/GyverLamp2.apk differ diff --git a/firmware/GyverLamp2/0_func.ino b/firmware/GyverLamp2/0_func.ino index e52fe1e..5838755 100644 --- a/firmware/GyverLamp2/0_func.ino +++ b/firmware/GyverLamp2/0_func.ino @@ -1,22 +1,30 @@ void sendUDP(char *data) { - Udp.beginPacket(deviceIP, portNum + cfg.group); + Udp.beginPacket(broadIP, portNum + cfg.group); Udp.write(data); Udp.endPacket(); } void sendUDP(byte cmd, int data1 = 0, int data2 = 0, int data3 = 0) { char reply[20] = ""; - mString packet(reply, sizeof(reply)); + mString packet(reply); packet = packet + "GL," + cmd + ',' + data1 + ',' + data2 + ',' + data3; sendUDP(reply); //DEBUG("Sending: "); //DEBUGLN(cmd); } +void iAmOnline() { + if (onlineTmr.isReady()) { + char reply[10] = "GL_ONL"; + mString packet(reply); + packet += cfg.curPreset; + sendUDP(reply); + } +} void restartUDP() { Udp.stop(); Udp.begin(portNum + cfg.group); - deviceIP = WiFi.localIP(); - deviceIP[3] = 255; + broadIP = WiFi.localIP(); + broadIP[3] = 255; DEBUG("UDP port: "); DEBUGLN(portNum + cfg.group); } @@ -60,7 +68,7 @@ void drawDots(int X, int Y, CRGB color) { } void drawClock(byte Y, byte speed, CRGB color) { - if (cfg.deviceType == 1 || cfg.width < 16) return; // лента или мелкая матрица - на выход + if (cfg.deviceType == 1) return; // лента - на выход byte h1, h2, m1, m2; if (gotNTP || gotTime) { h1 = now.hour / 10; @@ -70,8 +78,10 @@ void drawClock(byte Y, byte speed, CRGB color) { m2 = now.min % 10; } else { h1 = h2 = m1 = m2 = 10; - } - int pos = cfg.width - (now.weekMs / (speed * 2)) % (cfg.width + 26); + } + int pos; + if (speed == 0) pos = cfg.width / 2 - 13; + else pos = cfg.width - (now.weekMs / (speed * 2)) % (cfg.width + 26); drawDigit(h1, pos, Y, color); drawDigit(h2, pos + 6, Y, color); if (now.getMs() < 500) drawDots(pos + 12, Y, color); diff --git a/firmware/GyverLamp2/GyverLamp2.ino b/firmware/GyverLamp2/GyverLamp2.ino index a358f0a..b6664a8 100644 --- a/firmware/GyverLamp2/GyverLamp2.ino +++ b/firmware/GyverLamp2/GyverLamp2.ino @@ -1,73 +1,27 @@ /* - Версия 0.19b - Минимальная версия приложения 1.17!!! - Почищен мусор, оптимизация, повышена стабильность и производительность - Мигает теперь 16 светиков - Снова переделана сетевая политика, упрощён и сильно ускорен парсинг - Изменены пределы по светодиодам, что сильно увеличило производительность - Выключенная (программно) лампа не принимает сервисные команды кроме команды включиться - Добавлены часы, в том числе в рассвет - Slave работает со светомузыкой сам, если не получает данные с мастера - - Версия 0.18b - Уменьшена чувствительность хлопков - Увеличена плавность светомузыки - Переделана сетевая политика - Микрофон и датчик света опрашивает только мастер и отсылает данные слейвам своей группы - 4 клика - включить первый режим - Отправка точного времени на лампу в режиме АР для работы рассвета и синхронизации эффектов - - Версия 0.17b - Автосмена отключается 30 сек во время настройки режимов - Убрана кнопка upload в режимах - Лампа чуть мигает при получении данных - Кастом палитра работает на огне 2020 - Вкл выкл двумя хлопками - Плавное выключение - Починил рассвет - - Версия 0.16b - Исправлен масштаб огня 2020 - Фикс невыключения рассвета - - Версия 0.14b - Мелкие баги - Вернул искры огню - Добавлены палитры - Добавлен огонь 2020 - - Версия 0.13b - Улучшена стабильность - - Версия 0.12b - Мелкие исправления - - Версия 0.11b - Добавлен редактор палитр - Исправлены мелкие баги в эффектах - Переподключение к роутеру после сброса сети - Настройка ориентации матрицы из приложения - Переработан эффект "Частицы" - Добавлена скорость огня - Переключение на новый/выбранный режим при редактировании - Отправка времени из сервиса (для АР) - Выключение по таймеру теперь плавное - Добавлен рассвет - - TODO: - плавная смена режимов - Mqtt? - Базовый пак - Эффект погода https://it4it.club/topic/40-esp8266-i-parsing-pogodyi-s-openweathermap/ + ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! + ДЛЯ КОМПИЛЯЦИИ ПРОШИВКИ ПОД NODEMCU/WEMOS/ESP01/ESP12 ВЫБИРАТЬ + Инструменты / Плата Generic ESP8266 + Инструменты / Flash Size 4MB (FS:2MB OTA) + CPU Frequency / 160 MHz (рекомендуется для стабильности светомузыки!!!) + При прошивке с других прошивок лампы поставить: Инструменты/Erase Flash/All Flash Contents + ESP core 2.7.4+ http://arduino.esp8266.com/stable/package_esp8266com_index.json + FastLED 3.4.0+ https://github.com/FastLED/FastLED/releases */ -// ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! -// ДЛЯ КОМПИЛЯЦИИ ПРОШИВКИ ПОД NODEMCU/WEMOS/ESP01/ESP12 ВЫБИРАТЬ -// Инструменты/Плата Generic ESP8266 -// Инструменты/Flash Size 4MB (FS:2MB OTA) -// При прошивке с других прошивок лампы поставить: Инструменты/Erase Flash/All Flash Contents -// ESP core 2.7.4+ http://arduino.esp8266.com/stable/package_esp8266com_index.json -// FastLED 3.4.0+ https://github.com/FastLED/FastLED/releases +/* + Версия 0.23b + Поправлена яркость рассвета + + TODO: + Upload -> Применить + Длина огня в светомуз? + Плавная смена режимов + Mqtt + Базовый пак + Поддержка куба + Погода https://it4it.club/topic/40-esp8266-i-parsing-pogodyi-s-openweathermap/ +*/ // ---------- Настройки ----------- #define GL_KEY "GL" // ключ сети @@ -83,7 +37,7 @@ #define PHOT_VCC 14 // питание фоторезистора GPIO14 (D5 на wemos/node) // ------------ Лента ------------- -#define STRIP_PIN 2 // пин ленты GPIO2 (D4 на wemos/node) +#define STRIP_PIN 2 // пин ленты GPIO2 (D4 на wemos/node), GPIO5 (D1) для module #define MAX_LEDS 300 // макс. светодиодов #define STRIP_CHIP WS2812 // чип ленты #define STRIP_COLOR GRB // порядок цветов в ленте @@ -101,30 +55,43 @@ const char AP_NameChar[] = "GyverLamp2"; const char WiFiPassword[] = "12345678"; // ------------ Прочее ------------- -#define GL_VERSION 19 // код версии прошивки +#define GL_VERSION 23 // код версии прошивки #define EE_TOUT 30000 // таймаут сохранения епром после изменения, мс #define DEBUG_SERIAL_LAMP // закомментируй чтобы выключить отладку (скорость 115200) -#define EE_KEY 55 // ключ сброса WiFi (измени для сброса всех настроек) +#define EE_KEY 56 // ключ сброса eeprom #define NTP_UPD_PRD 5 // период обновления времени с NTP сервера, минут //#define SKIP_WIFI // пропустить подключение к вафле (для отладки) // ------------ БИЛДЕР ------------- -//#define MAX_LEDS 900 +#define GL_BUILD 0 // 0: com 300, 1: com 900, 2: esp1 300, 3: esp1 900, 4: module 300, 5: module 900 -// esp01 -//#define BTN_PIN 0 -//#define STRIP_PIN 2 -//#define USE_ADC 0 - -// GL2 module -//#define STRIP_PIN 5 // GPIO5 на gl module (D1 на wemos/node) +#if (GL_BUILD == 0) +#elif (GL_BUILD == 1) +#define MAX_LEDS 900 +#elif (GL_BUILD == 2) +#define MAX_LEDS 300 +#define BTN_PIN 0 +#define STRIP_PIN 2 +#define USE_ADC 0 +#elif (GL_BUILD == 3) +#define MAX_LEDS 900 +#define BTN_PIN 0 +#define STRIP_PIN 2 +#define USE_ADC 0 +#elif (GL_BUILD == 4) +#define MAX_LEDS 300 +#define STRIP_PIN 5 +#elif (GL_BUILD == 5) +#define MAX_LEDS 900 +#define STRIP_PIN 5 +#endif // ---------- БИБЛИОТЕКИ ----------- -#define FASTLED_ALLOW_INTERRUPTS 0 +//#define FASTLED_ALLOW_INTERRUPTS 0 #include "data.h" // данные #include "Time.h" // часы #include "TimeRandom.h" // случайные числа по времени -#include "FastRandom.h" // быстрый рандом +//#include "FastRandom.h" // быстрый рандом #include "Button.h" // библа кнопки #include "palettes.h" // палитры #include "NTPClient-Gyver.h" // сервер времени (модиф) @@ -147,13 +114,13 @@ Palette pal; WiFiServer server(80); WiFiUDP Udp; WiFiUDP ntpUDP; -IPAddress deviceIP; +IPAddress broadIP; NTPClient ntp(ntpUDP); CRGB leds[MAX_LEDS]; Time now; Button btn(BTN_PIN); timerMillis EEtmr(EE_TOUT), turnoffTmr, connTmr(120000ul), dawnTmr, holdPresTmr(30000ul), blinkTmr(300); -timerMillis effTmr(30, true); +timerMillis effTmr(30, true), onlineTmr(500, true), postDawn(10 * 60000ul); TimeRandom trnd; VolAnalyzer vol(A0), low, high; FastFilter phot; @@ -207,4 +174,5 @@ void loop() { button(); // проверяем кнопку checkAnalog(); // чтение звука и датчика yield(); + iAmOnline(); } diff --git a/firmware/GyverLamp2/analog.ino b/firmware/GyverLamp2/analog.ino index f693119..e63b4e7 100644 --- a/firmware/GyverLamp2/analog.ino +++ b/firmware/GyverLamp2/analog.ino @@ -5,7 +5,7 @@ void setupADC() { vol.setDt(700); vol.setPeriod(5); - vol.setWindow(map(MAX_LEDS, 300, 1200, 20, 1)); + vol.setWindow(map(MAX_LEDS, 300, 900, 20, 1)); low.setDt(0); low.setPeriod(0); @@ -63,11 +63,11 @@ void checkAnalog() { void checkMusic() { vol.tick(); + yield(); #if (USE_CLAP == 1) clap.tick(vol.getRawMax()); if (clap.hasClaps(2)) controlHandler(!cfg.state); #endif - yield(); if (CUR_PRES.advMode == GL_ADV_LOW || CUR_PRES.advMode == GL_ADV_HIGH) { // частоты int raw[FFT_SIZE], spectr[FFT_SIZE]; for (int i = 0; i < FFT_SIZE; i++) raw[i] = analogRead(A0); diff --git a/firmware/GyverLamp2/data.h b/firmware/GyverLamp2/data.h index 5c0feec..07ad82d 100644 --- a/firmware/GyverLamp2/data.h +++ b/firmware/GyverLamp2/data.h @@ -29,6 +29,7 @@ #define FOR_i(x,y) for (int i = (x); i < (y); i++) #define FOR_j(x,y) for (int j = (x); j < (y); j++) +#define FOR_k(x,y) for (int k = (x); k < (y); k++) #define CUR_PRES preset[cfg.curPreset] byte scaleFF(byte x, byte b) { @@ -80,7 +81,7 @@ struct Config { int16_t length = 16; // длина ленты int16_t width = 16; // ширина матрицы - byte GMT = 3; // часовой пояс +13 + byte GMT = 16; // часовой пояс +13 uint32_t cityID = 1; // city ID bool mqtt = 0; // mqtt char mqttID[32]; // @@ -118,20 +119,22 @@ struct Preset { byte scale = 100; // масштаб (0.. 255) byte fromCenter = 0; // эффект из центра (0/1) byte color = 0; // цвет (0.. 255) - byte rnd = 0; // случайный (0/1) + byte fromPal = 0; // из палитры (0/1) }; -#define DAWN_SIZE 23 +#define DAWN_SIZE 24 struct Dawn { byte state[7] = {0, 0, 0, 0, 0, 0, 0}; // (1/0) byte hour[7] = {0, 0, 0, 0, 0, 0, 0}; // (0.. 59) byte minute[7] = {0, 0, 0, 0, 0, 0, 0}; // (0.. 59) byte bright = 100; // (0.. 255) byte time = 1; // (5,10,15,20..) + byte post = 1; // (5,10,15,20..) }; /* - Каждые 5 минут лампа AP отправляет время (день час минута) на Local лампы всех ролей в сети с ней (GL,6,день,час,мин) - Если включен АЦП, Мастер отправляет своей группе данные с него на каждой итерации отрисовки эффектов (GL,1,длина,масштаб,яркость) - Установка времени с мобилы - получают все роли АР и Local (не получившие ntp) + - Каждую секунду устройства шлют посылку GL_ONL */ diff --git a/firmware/GyverLamp2/eeprom.ino b/firmware/GyverLamp2/eeprom.ino index 11b0cd7..658ccbc 100644 --- a/firmware/GyverLamp2/eeprom.ino +++ b/firmware/GyverLamp2/eeprom.ino @@ -26,6 +26,11 @@ void EE_startup() { DEBUGLN(sizeof(cfg) + sizeof(dawn) + sizeof(pal) + sizeof(preset) + 1); // запускаем всё + if (cfg.deviceType == GL_TYPE_STRIP) { + if (cfg.length > MAX_LEDS) cfg.length = MAX_LEDS; + cfg.width = 1; + } + if (cfg.length * cfg.width > MAX_LEDS) cfg.width = MAX_LEDS / cfg.length; FastLED.setMaxPowerInVoltsAndMilliamps(STRIP_VOLT, cfg.maxCur * 100); updPal(); } diff --git a/firmware/GyverLamp2/effects.ino b/firmware/GyverLamp2/effects.ino index 85e6cce..4dcefc7 100644 --- a/firmware/GyverLamp2/effects.ino +++ b/firmware/GyverLamp2/effects.ino @@ -2,12 +2,20 @@ void effectsRoutine() { static byte prevEff = 255; if (!effTmr.isReady()) return; - if (dawnTmr.running()) { - fill_solid(leds, MAX_LEDS, ColorFromPalette(HeatColors_p, dawnTmr.getLength8(), scaleFF(dawnTmr.getLength8(), dawn.bright), LINEARBLEND)); - drawClock(cfg.length / 2 - 4, 150, 0); + if (dawnTmr.running() || postDawn.running()) { + FastLED.setBrightness(255); + byte thisColor = dawnTmr.getLength8(); + if (postDawn.running()) thisColor = 255; + fill_solid(leds, MAX_LEDS, ColorFromPalette(HeatColors_p, thisColor, scaleFF(thisColor, dawn.bright), LINEARBLEND)); + drawClock(cfg.length / 2 - 4, 100, 0); FastLED.show(); if (dawnTmr.isReady()) { dawnTmr.stop(); + postDawn.setInterval(dawn.post * 60000ul); + postDawn.restart(); + } + if (postDawn.isReady()) { + postDawn.stop(); FastLED.clear(); FastLED.show(); } @@ -19,12 +27,15 @@ void effectsRoutine() { byte thisScale = getScale(); byte thisBright = getBright(); - if (cfg.adcMode > 1) { // музыка или яркость + if (musicMode() || briMode()) { // музыка или яркость if (cfg.role) { // мастер отправляет - static timerMillis adcSend(120, true); - if (adcSend.isReady() && millis() - udpTmr >= 1000) sendUDP(7, thisLength, thisScale, thisBright); + static uint32_t tmr = 0; + if ((millis() - tmr >= musicMode() ? 60 : 1000) && millis() - udpTmr >= 1000) { + sendUDP(7, thisLength, thisScale, thisBright); + tmr = millis(); + } } else { // слейв получает - if (millis() - gotADCtmr < 2000) { // есть сигнал с мастера + if (millis() - gotADCtmr < 4000) { // есть сигнал с мастера thisLength = udpLength; thisScale = udpScale; thisBright = udpBright; @@ -46,6 +57,7 @@ void effectsRoutine() { prevEff = CUR_PRES.effect; loading = true; } + yield(); // =================================================== ЭФФЕКТЫ =================================================== switch (CUR_PRES.effect) { @@ -132,7 +144,8 @@ void effectsRoutine() { FOR_i(0, cfg.length * cfg.width) leds[i].fadeToBlackBy(70); { uint16_t rndVal = 0; - FOR_i(0, thisScale / 8 + 1) { + byte amount = (thisScale >> 3) + 1; + FOR_i(0, amount) { rndVal = rndVal * 2053 + 13849; // random2053 алгоритм int homeX = inoise16(i * 100000000ul + (now.weekMs << 3) * CUR_PRES.speed / 255); homeX = map(homeX, 15000, 50000, 0, cfg.length); @@ -146,9 +159,15 @@ void effectsRoutine() { int offsY = inoise8(i * 2500 + 30000 + (now.weekMs >> 1) * CUR_PRES.speed / 255) - 128; offsY = cfg.length / 2 * offsY / 128; int thisY = homeY + offsY; - setPix(thisX, thisY, CHSV(CUR_PRES.rnd ? rndVal : CUR_PRES.color, 255, 255)); + setPix(thisX, thisY, CUR_PRES.fromPal ? + ColorFromPalette(paletteArr[CUR_PRES.palette - 1], scalePal(i * 255 / amount), 255, LINEARBLEND) : + CHSV(CUR_PRES.color, 255, 255) + ); } else { - setLED(thisX, CHSV(CUR_PRES.rnd ? rndVal : CUR_PRES.color, 255, 255)); + setLED(thisX, CUR_PRES.fromPal ? + ColorFromPalette(paletteArr[CUR_PRES.palette - 1], scalePal(i * 255 / amount), 255, LINEARBLEND) : + CHSV(CUR_PRES.color, 255, 255) + ); } } } @@ -204,27 +223,53 @@ void effectsRoutine() { break; case 8: // ================================== КОНФЕТТИ ================================== - FOR_i(0, (thisScale >> 3) + 1) { - int x = random(0, cfg.length * cfg.width); - if (leds[x] == CRGB(0, 0, 0)) leds[x] = CHSV(CUR_PRES.rnd ? random(0, 255) : CUR_PRES.color, 255, 255); - } - FOR_i(0, cfg.length * cfg.width) { - if (leds[i].r >= 10 || leds[i].g >= 10 || leds[i].b >= 10) leds[i].fadeToBlackBy(CUR_PRES.speed / 2 + 1); - else leds[i] = 0; + { + byte amount = (thisScale >> 3) + 1; + FOR_i(0, amount) { + int x = random(0, cfg.length * cfg.width); + if (leds[x] == CRGB(0, 0, 0)) leds[x] = CUR_PRES.fromPal ? + ColorFromPalette(paletteArr[CUR_PRES.palette - 1], scalePal(i * 255 / amount), 255, LINEARBLEND) : + CHSV(CUR_PRES.color, 255, 255); + } + FOR_i(0, cfg.length * cfg.width) { + if (leds[i].r >= 10 || leds[i].g >= 10 || leds[i].b >= 10) leds[i].fadeToBlackBy(CUR_PRES.speed / 2 + 1); + else leds[i] = 0; + } } break; - - case 9: // =================================== ЧАСЫ =================================== + case 9: // =================================== СМЕРЧ =================================== FastLED.clear(); - drawClock(mapFF(CUR_PRES.scale, 0, cfg.length - 7), (255 - CUR_PRES.speed), CHSV(CUR_PRES.color, 255, 255)); - break; + FOR_k(0, (thisScale >> 5) + 1) { + FOR_i(0, cfg.length) { + //byte thisPos = inoise8(i * 10 - (now.weekMs >> 1) * CUR_PRES.speed / 255, k * 10000); + byte thisPos = inoise8(i * 10 + (now.weekMs >> 3) * CUR_PRES.speed / 255 + k * 10000, (now.weekMs >> 1) * CUR_PRES.speed / 255); + thisPos = map(thisPos, 50, 200, 0, cfg.width); + byte scale = 4; + FOR_j(0, scale) { + CRGB color = ColorFromPalette(paletteArr[CUR_PRES.palette - 1], scalePal(j * 255 / scale), (255 - j * 255 / (scale - 1)), LINEARBLEND); + if (j == 0) { + setPixOverlap(thisPos, i, color); + } else { + setPixOverlap(thisPos - j, i, color); + setPixOverlap(thisPos + j, i, color); + } + } + } + } + break; - case 10: // ================================= ПОГОДА ================================== + case 10: // =================================== ЧАСЫ =================================== + FastLED.clear(); + drawClock(mapFF(CUR_PRES.scale, 0, cfg.length - 7), (CUR_PRES.speed < 10) ? 0 : (255 - CUR_PRES.speed), CHSV(CUR_PRES.color, 255, 255)); + break; + + case 11: // ================================= ПОГОДА ================================== break; + } - if (CUR_PRES.advMode == GL_ADV_CLOCK && CUR_PRES.effect != 9) drawClock(mapFF(CUR_PRES.scale, 0, cfg.length - 7), 150, 0); + if (CUR_PRES.advMode == GL_ADV_CLOCK && CUR_PRES.effect != 9) drawClock(mapFF(CUR_PRES.scale, 0, cfg.length - 7), 100, 0); // выводим нажатия кнопки if (btnClicks > 0) fill_solid(leds, btnClicks, CRGB::White); if (brTicks > 0) fill_solid(leds, brTicks, CRGB::Cyan); @@ -236,13 +281,16 @@ void effectsRoutine() { bool musicMode() { return ((cfg.adcMode == GL_ADC_MIC || cfg.adcMode == GL_ADC_BOTH) && (CUR_PRES.advMode > 1 && CUR_PRES.advMode <= 4)); } +bool briMode() { + return (cfg.adcMode == GL_ADC_BRI || cfg.adcMode == GL_ADC_BOTH); +} byte getBright() { int maxBr = cfg.bright; // макс яркость из конфига byte fadeBr = 255; if (CUR_PRES.fadeBright) fadeBr = CUR_PRES.bright; // ограничен вручную - if (cfg.adcMode == GL_ADC_BRI || cfg.adcMode == GL_ADC_BOTH) { // ----> датчик света или оба + if (briMode()) { // ----> датчик света или оба maxBr = constrain(phot.getFil(), cfg.minLight, cfg.maxLight); if (cfg.minLight != cfg.maxLight) maxBr = map(maxBr, cfg.minLight, cfg.maxLight, cfg.minBright, cfg.maxBright); @@ -298,6 +346,13 @@ byte scalePal(byte val) { void setPix(int x, int y, CRGB color) { if (y >= 0 && y < cfg.length && x >= 0 && x < cfg.width) leds[getPix(x, y)] = color; } +void setPixOverlap(int x, int y, CRGB color) { + if (y < 0) y += cfg.length; + if (x < 0) x += cfg.width; + if (y >= cfg.length) y -= cfg.length; + if (x >= cfg.width) x -= cfg.width; + setPix(x, y, color); +} void setLED(int x, CRGB color) { if (x >= 0 && x < cfg.length) leds[x] = color; } diff --git a/firmware/GyverLamp2/mString.h b/firmware/GyverLamp2/mString.h index 6fe778d..72f1f12 100644 --- a/firmware/GyverLamp2/mString.h +++ b/firmware/GyverLamp2/mString.h @@ -1,5 +1,7 @@ -// TODO -// защита от переполнения +#ifndef mString_h +#define mString_h + +#include char* mUtoa(uint32_t value, char *buffer, bool clear = 1); char* mLtoa(int32_t value, char *buffer, bool clear = 1); @@ -53,7 +55,7 @@ class mString { } // constructor - mString(char* buffer, int newSize) { + mString(char* buffer, int newSize = -1) { buf = buffer; size = newSize; } @@ -101,7 +103,7 @@ class mString { // add mString& add(const char c) { byte len = length(); - if (len + 1 >= size) return *this; + if (size != -1 && len + 1 >= size) return *this; buf[len++] = c; buf[len++] = NULL; return *this; @@ -111,13 +113,13 @@ class mString { do { buf[len] = *(data++); } while (buf[len++] != 0);*/ - if (length() + strlen(data) >= size) return *this; + if (size != -1 && length() + strlen(data) >= size) return *this; strcpy(buf + length(), data); return *this; } mString& add(const __FlashStringHelper *data) { PGM_P p = reinterpret_cast(data); - if (length() + strlen_P(p) >= size) return *this; + if (size != -1 && length() + strlen_P(p) >= size) return *this; strcpy_P(buf + length(), p); return *this; /*do { @@ -297,7 +299,7 @@ class mString { // convert & parse char operator [] (uint16_t index) const { - return (index < size ? buf[index] : 0); + return buf[index];//(index < size ? buf[index] : 0); } char& operator [] (uint16_t index) { return buf[index]; @@ -356,5 +358,5 @@ class mString { } } private: - }; +#endif \ No newline at end of file diff --git a/firmware/GyverLamp2/parsing.ino b/firmware/GyverLamp2/parsing.ino index c6759e9..829f82c 100644 --- a/firmware/GyverLamp2/parsing.ino +++ b/firmware/GyverLamp2/parsing.ino @@ -1,6 +1,6 @@ +char buf[UDP_TX_PACKET_MAX_SIZE + 1]; void parsing() { if (Udp.parsePacket()) { - static char buf[UDP_TX_PACKET_MAX_SIZE + 1]; int n = Udp.read(buf, UDP_TX_PACKET_MAX_SIZE); buf[n] = NULL; @@ -9,7 +9,7 @@ void parsing() { if (buf[3] == '7') { // АЦП GL,7, if (!cfg.role) { // принимаем данные ацп если слейв int data[3]; - mString ints(buf + 5, 20); + mString ints(buf + 5); ints.parseInts(data, 3); udpLength = data[0]; udpScale = data[1]; @@ -27,7 +27,7 @@ void parsing() { // ПАРСИНГ byte data[MAX_PRESETS * PRES_SIZE + 10]; - memset(data, 0, sizeof(data)); + memset(data, 0, MAX_PRESETS * PRES_SIZE + 10); int count = 0; char *str, *p = buf; char *ssid, *pass; @@ -53,7 +53,6 @@ void parsing() { if (count == 24) strcpy(cfg.mqttPass, str); } } - yield(); // тип 0 - control, 1 - config, 2 - effects, 3 - dawn, 4 - from master, 5 - palette, 6 - time switch (data[1]) { @@ -81,7 +80,7 @@ void parsing() { FastLED.clear(); FastLED.show(); char OTA[60]; - mString ota(OTA, 60); + mString ota(OTA); ota.clear(); ota += OTAhost; ota += OTAfile[data[3]]; @@ -93,6 +92,7 @@ void parsing() { case 13: // выключить через if (data[3] == 0) turnoffTmr.stop(); else { + DEBUGLN("Fade"); fadeDown((uint32_t)data[3] * 60000ul); } break; @@ -185,16 +185,16 @@ void parsing() { void sendToSlaves(byte data1, byte data2) { if (cfg.role == GL_MASTER) { char reply[15]; - mString packet(reply, sizeof(reply)); + mString packet(reply); packet.clear(); packet = packet + "GL,4," + data1 + ',' + data2; DEBUG("Sending to Slaves: "); DEBUGLN(reply); - FOR_i(0, 3) { + FOR_i(0, 4) { sendUDP(reply); - delay(10); + delay(8); } } } diff --git a/firmware/GyverLamp2/presetManager.ino b/firmware/GyverLamp2/presetManager.ino index 4955f24..bdceaff 100644 --- a/firmware/GyverLamp2/presetManager.ino +++ b/firmware/GyverLamp2/presetManager.ino @@ -42,8 +42,9 @@ void controlHandler(bool state) { DEBUGLN("stop off timer"); return; } - if (dawnTmr.running()) { + if (dawnTmr.running() || postDawn.running()) { dawnTmr.stop(); + postDawn.stop(); delay(50); FastLED.clear(); FastLED.show(); @@ -68,7 +69,7 @@ void setPower(bool state) { FastLED.clear(); FastLED.show(); } - if (millis() - udpTmr >= 1000) sendToSlaves(0, cfg.state); // пиздец костыль + if (millis() - udpTmr >= 1000) sendToSlaves(0, cfg.state); // пиздец костыль (не отправлять слейвам если команда получена по воздуху) DEBUGLN(state ? "Power on" : "Power off"); } diff --git a/firmware/GyverLamp2/startup.ino b/firmware/GyverLamp2/startup.ino index 52bf313..acb3d98 100644 --- a/firmware/GyverLamp2/startup.ino +++ b/firmware/GyverLamp2/startup.ino @@ -156,7 +156,7 @@ void setupLocal() { } void checkUpdate() { - if (cfg.update) { + if (cfg.update) { // было ОТА обновление if (cfg.version != GL_VERSION) { cfg.version = GL_VERSION; blink16(CRGB::Cyan); @@ -164,10 +164,17 @@ void checkUpdate() { DEBUGLN(GL_VERSION); } else { blink16(CRGB::Blue); - DEBUG("Update to current"); + DEBUGLN("Update to current"); } cfg.update = 0; EE_updCfg(); + } else { + if (cfg.version != GL_VERSION) { + cfg.version = GL_VERSION; + blink16(CRGB::Cyan); + DEBUG("Update to"); + DEBUGLN(GL_VERSION); + } } } diff --git a/firmware/GyverLamp2/time.ino b/firmware/GyverLamp2/time.ino index e6dff8e..a1d6d09 100644 --- a/firmware/GyverLamp2/time.ino +++ b/firmware/GyverLamp2/time.ino @@ -1,6 +1,6 @@ void setupTime() { - ntp.setUpdateInterval(NTP_UPD_PRD * 60000ul); - ntp.setTimeOffset((cfg.GMT - 13) * 3600); + ntp.setUpdateInterval(NTP_UPD_PRD * 60000ul / 2); // ставим меньше, так как апдейт вручную + ntp.setTimeOffset((cfg.GMT - 13) * 3600l); ntp.setPoolServerName(NTPserver); if (cfg.WiFimode && !connTmr.running()) { // если успешно подключились к WiFi ntp.begin(); @@ -12,14 +12,14 @@ void setupTime() { void timeTicker() { static timerMillis tmr(30, true); if (tmr.isReady()) { - if (cfg.WiFimode && WiFi.status() == WL_CONNECTED) { // если вайфай подключен + if (cfg.WiFimode && WiFi.status() == WL_CONNECTED && !connTmr.running()) { // если вайфай подключен и это не попытка переподключиться now.sec = ntp.getSeconds(); now.min = ntp.getMinutes(); now.hour = ntp.getHours(); now.day = ntp.getDay(); // вс 0, сб 6 now.weekMs = now.getWeekS() * 1000ul + ntp.getMillis(); - now.setMs(ntp.getMillis()); - if (ntp.update()) gotNTP = true; + now.setMs(ntp.getMillis()); + if (now.sec == 0 && now.min % NTP_UPD_PRD == 0 && ntp.update()) gotNTP = true; } else { // если вайфай не подключен now.tick(); // тикаем своим счётчиком } @@ -64,8 +64,7 @@ void checkDawn() { DEBUG("dawn start "); DEBUGLN(dawn.time * 60000ul); dawnTmr.setInterval(dawn.time * 60000ul); - dawnTmr.restart(); - FastLED.setBrightness(255); + dawnTmr.restart(); } } } @@ -75,6 +74,7 @@ void checkWorkTime() { byte curState = isWorkTime(now.hour, cfg.workFrom, cfg.workTo); if (prevState != curState) { // переключение расписания prevState = curState; + // todo: проверить пересечение с рассветом if (curState && !cfg.state && !cfg.manualOff) fade(1); // нужно включить, а лампа выключена и не выключалась вручную if (!curState && cfg.state) fade(0); // нужно выключить, а лампа включена } diff --git a/firmware/GyverLamp2/timerMillis.h b/firmware/GyverLamp2/timerMillis.h index 0fbb0e5..2b8486c 100644 --- a/firmware/GyverLamp2/timerMillis.h +++ b/firmware/GyverLamp2/timerMillis.h @@ -38,7 +38,7 @@ class timerMillis { return _active; } byte getLength8() { - return (_active) ? ((millis() - _tmr) * 255ul / _interval) : 0; + return (_active) ? ((min(uint32_t(millis() - _tmr), _interval)) * 255ul / _interval) : 0; } private: