From a4f098250bf31b2447945e5ebc2ef1b543ed7f7a Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 14 Feb 2021 20:14:33 +0300 Subject: [PATCH] v0.10b --- firmware/GyverLamp2/GyverLamp2.ino | 53 +++++-- firmware/GyverLamp2/analog.ino | 13 ++ firmware/GyverLamp2/data.h | 15 +- firmware/GyverLamp2/eeprom.ino | 1 + firmware/GyverLamp2/effects.ino | 16 +++ firmware/GyverLamp2/fire2D.ino | 4 +- firmware/GyverLamp2/parsing.ino | 216 +++++++++++++++-------------- firmware/GyverLamp2/startup.ino | 38 +++-- 8 files changed, 224 insertions(+), 132 deletions(-) diff --git a/firmware/GyverLamp2/GyverLamp2.ino b/firmware/GyverLamp2/GyverLamp2.ino index d5ec23d..88ec886 100644 --- a/firmware/GyverLamp2/GyverLamp2.ino +++ b/firmware/GyverLamp2/GyverLamp2.ino @@ -1,4 +1,20 @@ -// LOLIN(WEMOS) D1 R2 & mini +// 0.10 +// исправлена обработка ключа +// добавлена совместимость с nodemcu +// поворот матрицы +// обновление прошивок для разных схем +// исправлен цвет огня +// индикация обновления при запуске + +// мигает 8: +// красным - не смог подключиться к АР +// зелёным - смог подключиться к АР +// жёлтым - создал свою АП +// бирюзовым - успешно обновился на новую версию +// синим - обновился на ту же версию +// розовым - сброс всех настроек (первый запуск) + +// Generic ESP8266, 4MB (FS:2MB OTA) // ESP core 2.7.4+ http://arduino.esp8266.com/stable/package_esp8266com_index.json // FastLED 3.4.0+ https://github.com/FastLED/FastLED/releases @@ -6,12 +22,17 @@ #define GL_KEY "GL" // ключ сети // ------------ Кнопка ------------- -#define BTN_PIN 4 // пин кнопки GPIO4 (D2). Или 0 для схемы с ESP-01 !! +#define BTN_PIN 4 // пин кнопки GPIO4 (D2 на wemos/node), 0 для схемы с ESP-01 #define USE_BTN 1 // 1 использовать кнопку, 0 нет +// ------------- АЦП -------------- +#define USE_ADC 1 // можно выпилить АЦП +#define MIC_VCC 12 // питание микрофона GPIO12 (D6 на wemos/node) +#define PHOT_VCC 14 // питание фоторезистора GPIO14 (D5 на wemos/node) + // ------------ Лента ------------- -#define STRIP_PIN 2 // пин ленты GPIO2 (D4) -#define MAX_LEDS 512 // макс. светодиодов +#define STRIP_PIN 2 // пин ленты GPIO2 (D4 на wemos/node) +#define MAX_LEDS 600 // макс. светодиодов #define STRIP_CHIP WS2812 // чип ленты #define STRIP_COLOR GRB // порядок цветов в ленте #define STRIP_VOLT 5 // напряжение ленты, V @@ -28,13 +49,23 @@ const char AP_NameChar[] = "GyverLamp2"; const char WiFiPassword[] = "12345678"; // ------------ Прочее ------------- -#define MIC_VCC D6 // питание микрофона -#define PHOT_VCC D5 // питание фоторезистора +#define GL_VERSION 010 #define EE_TOUT 30000 // таймаут сохранения епром после изменения, мс -//#define DEBUG_SERIAL // закомментируй чтобы выключить отладку (скорость 115200) -#define EE_KEY 42 // ключ сброса WiFi (измени для сброса всех настроек) +#define DEBUG_SERIAL // закомментируй чтобы выключить отладку (скорость 115200) +#define EE_KEY 44 // ключ сброса WiFi (измени для сброса всех настроек) #define NTP_UPD_PRD 5 // период обновления времени с NTP сервера, минут +// ------------ БИЛДЕР ------------- +//#define MAX_LEDS 1200 + +// 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) + // ---------- БИБЛИОТЕКИ ----------- #include "data.h" // данные #include "Time.h" // часы @@ -71,18 +102,22 @@ FastFilter phot; byte btnClicks = 0, brTicks = 0; unsigned char matrixValue[11][16]; bool gotNTP = false; +void blink8(CRGB color); // ------------------- SETUP -------------------- void setup() { + delay(800); memset(matrixValue, 0, sizeof(matrixValue)); #ifdef DEBUG_SERIAL Serial.begin(115200); DEBUGLN(); #endif EEPROM.begin(512); // старт епром - startStrip(); // показываем РГБ + startStrip(); // старт ленты btn.setLevel(digitalRead(BTN_PIN)); // смотрим что за кнопка EE_startup(); // читаем епром + checkUpdate(); // индикация было ли обновление + showRGB(); // показываем ргб checkGroup(); // показываем или меняем адрес checkButton(); // проверяем кнопку на удержание startWiFi(); // старт вайфай diff --git a/firmware/GyverLamp2/analog.ino b/firmware/GyverLamp2/analog.ino index e0e2ed4..b7e7454 100644 --- a/firmware/GyverLamp2/analog.ino +++ b/firmware/GyverLamp2/analog.ino @@ -1,3 +1,4 @@ +#if (USE_ADC == 1) void setupADC() { low.setDt(0); low.setPeriod(0); @@ -104,3 +105,15 @@ void disableADC() { digitalWrite(MIC_VCC, 0); pinMode(MIC_VCC, INPUT); } +#else +void setupADC() {} +void checkAnalog() {} +void checkMusic() {} +void checkPhot() {} +byte getSoundVol() { + return 0; +} +void switchToMic() {} +void switchToPhot() {} +void disableADC() {} +#endif diff --git a/firmware/GyverLamp2/data.h b/firmware/GyverLamp2/data.h index d7db5e6..111492e 100644 --- a/firmware/GyverLamp2/data.h +++ b/firmware/GyverLamp2/data.h @@ -37,7 +37,16 @@ int mapFF(byte x, byte min, byte max) { return (((max - min) * x + (min << 8) + 1) >> 8); } -const char OTAhost[] = "http://ota.alexgyver.ru/GL2_latest.bin"; +const char OTAhost[] = "http://ota.alexgyver.ru/"; +const char *OTAfile[] = { + "GL2_latest.bin", + "com_600.bin", + "com_1200.bin", + "esp1_600.bin", + "esp1_1200.bin", + "module_600.bin", + "module_1200.bin", +}; const char *NTPservers[] = { "pool.ntp.org", @@ -62,9 +71,9 @@ struct Config { byte maxCur = 5; // макс ток (мА/100) byte workFrom = 0; // часы работы (0,1.. 23) byte workTo = 0; // часы работы (0,1.. 23) - int16_t length = 100; // длина ленты int16_t width = 1; // ширина матрицы + byte mTurn = 0; byte state = 1; // состояние 0 выкл, 1 вкл byte group = 1; // группа девайса (1-10) @@ -77,6 +86,8 @@ struct Config { int16_t maxLight = 1023; // макс освещённость char ssid[32]; // логин wifi char pass[32]; // пароль wifi + byte version = GL_VERSION; + byte update = 0; }; #define PRES_SIZE 13 diff --git a/firmware/GyverLamp2/eeprom.ino b/firmware/GyverLamp2/eeprom.ino index 4de02b4..3df66ca 100644 --- a/firmware/GyverLamp2/eeprom.ino +++ b/firmware/GyverLamp2/eeprom.ino @@ -10,6 +10,7 @@ void EE_startup() { EEPROM.put(sizeof(cfg), dawn); EEPROM.put(sizeof(cfg) + sizeof(dawn), preset); EEPROM.commit(); + blink8(CRGB::Pink); DEBUGLN("First start"); } EEPROM.get(0, cfg); diff --git a/firmware/GyverLamp2/effects.ino b/firmware/GyverLamp2/effects.ino index fec656d..ca3f965 100644 --- a/firmware/GyverLamp2/effects.ino +++ b/firmware/GyverLamp2/effects.ino @@ -203,8 +203,24 @@ void fillRow(int row, CRGB color) { FOR_i(cfg.width * row, cfg.width * (row + 1)) leds[i] = color; } +void blink8(CRGB color) { + FOR_i(0, 3) { + fill_solid(leds, 8, color); + FastLED.show(); + delay(300); + FastLED.clear(); + FastLED.show(); + delay(300); + } +} + // получить номер пикселя в ленте по координатам uint16_t getPix(int x, int y) { + if (cfg.mTurn) { + byte b = x; + x = y; + y = b; + } if ( !(y & 1) || (cfg.deviceType - 2) ) return (y * cfg.width + x); // если чётная строка else return (y * cfg.width + cfg.width - x - 1); // если нечётная строка } diff --git a/firmware/GyverLamp2/fire2D.ino b/firmware/GyverLamp2/fire2D.ino index 88df62c..d79a278 100644 --- a/firmware/GyverLamp2/fire2D.ino +++ b/firmware/GyverLamp2/fire2D.ino @@ -63,7 +63,7 @@ void drawFrame(int pcnt) { - pgm_read_byte(&(valueMask[y][newX])); leds[getPix(x, y)] = CHSV( - CUR_PRES.color * 2.5 + pgm_read_byte(&(hueMask[y][newX])), // H + CUR_PRES.color + pgm_read_byte(&(hueMask[y][newX])), // H 255, // S (uint8_t)max(0, nextv) // V ); @@ -75,7 +75,7 @@ void drawFrame(int pcnt) { int newX = x; if (x > 15) newX = x - 15; leds[getPix(newX, 0)] = CHSV( - CUR_PRES.color * 2.5 + pgm_read_byte(&(hueMask[0][newX])), // H + CUR_PRES.color + pgm_read_byte(&(hueMask[0][newX])), // H 255, // S (uint8_t)(((100.0 - pcnt) * matrixValue[0][newX] + pcnt * fireLine[newX]) / 100.0) // V ); diff --git a/firmware/GyverLamp2/parsing.ino b/firmware/GyverLamp2/parsing.ino index c8df298..c56432e 100644 --- a/firmware/GyverLamp2/parsing.ino +++ b/firmware/GyverLamp2/parsing.ino @@ -10,112 +10,120 @@ void parsing() { buf[n] = NULL; DEBUGLN(buf); // пакет вида <ключ>,<канал>,<тип>,<дата1>,<дата2>... - byte keyLen = strlen(GL_KEY); - if (!strncmp(buf, GL_KEY, keyLen)) { // парсим если это наша "сеть" - byte data[MAX_PRESETS * PRES_SIZE + keyLen]; - memset(data, 0, 30); - int count = 0; - char *str, *p = buf + keyLen; // сдвиг до даты - char *ssid, *pass; - while ((str = strtok_r(p, ",", &p)) != NULL) { - data[count++] = atoi(str); - if (count == 4) ssid = str; - if (count == 5) pass = str; - } + byte keyLen = strchr(buf, ',') - buf; // indexof + if (strncmp(buf, GL_KEY, keyLen)) return; // не наш ключ - // широковещательный запрос времени для local устройств в сети AP лампы - if (data[0] == 0 && cfg.WiFimode && !gotNTP) { - now.hour = data[1]; - now.min = data[2]; - now.setMs(0); - } - - if (data[0] != cfg.group) return; // не наш адрес, выходим - - switch (data[1]) { // тип 0 - control, 1 - config, 2 - effects, 3 - dawn - case 0: DEBUGLN("Control"); - switch (data[2]) { - case 0: setPower(0); break; // выкл - case 1: setPower(1); break; // вкл - case 2: cfg.minLight = phot.getRaw(); break; // мин яркость - case 3: cfg.maxLight = phot.getRaw(); break; // макс яркость - case 4: changePreset(-1); break; // пред пресет - case 5: changePreset(1); break; // след пресет - case 6: setPreset(data[3] - 1); break; // конкретный пресет data[3] - case 7: cfg.WiFimode = data[3]; EE_updCfgRst(); break; // смена режима WiFi - case 8: cfg.role = data[3]; break; // смена роли - case 9: cfg.group = data[3]; break; // смена группы - case 10: // установка настроек WiFi - strcpy(cfg.ssid, ssid); - strcpy(cfg.pass, pass); - break; - case 11: EE_updCfgRst(); break; // рестарт - case 12: if (gotNTP) { // OTA обновление, если есть интернет - delay(100); - FastLED.clear(); - FastLED.show(); - ESPhttpUpdate.update(OTAhost); - } break; - case 13: // выключить через - if (data[3] == 0) turnoffTmr.stop(); - else { - turnoffTmr.setInterval((uint32_t)data[3] * 60000ul); - turnoffTmr.restart(); - } - break; - } - EE_updCfg(); - break; - - case 1: DEBUGLN("Config"); - FOR_i(0, CFG_SIZE) { - *((byte*)&cfg + i) = data[i + 2]; // загоняем в структуру - } - cfg.length = data[17] | (data[16] << 8); // склеиваем - cfg.width = data[20] | (data[19] << 8); // склеиваем - if (cfg.length > MAX_LEDS) cfg.length = MAX_LEDS; - if (cfg.deviceType == GL_TYPE_STRIP) cfg.width = 1; - if (cfg.length * cfg.width > MAX_LEDS) cfg.width = MAX_LEDS / cfg.length; - ntp.setTimeOffset((cfg.GMT - 13) * 3600); - ntp.setPoolServerName(NTPservers[cfg.NTP - 1]); - FastLED.setMaxPowerInVoltsAndMilliamps(STRIP_VOLT, cfg.maxCur * 100); - if (cfg.adcMode == GL_ADC_BRI) switchToPhot(); - else if (cfg.adcMode == GL_ADC_MIC) switchToMic(); - else disableADC(); - EE_updCfg(); - break; - - case 2: DEBUGLN("Preset"); - cfg.presetAmount = data[2]; // кол-во режимов - FOR_j(0, cfg.presetAmount) { - FOR_i(0, PRES_SIZE) { - *((byte*)&preset + j * PRES_SIZE + i) = data[j * PRES_SIZE + i + 3]; // загоняем в структуру - } - } - EE_updatePreset(); - presetRotation(true); // форсировать смену режима - break; - - case 3: DEBUGLN("Dawn"); - FOR_i(0, (2 + 3 * 7)) { - *((byte*)&dawn + i) = data[i + 2]; // загоняем в структуру - } - EE_updateDawn(); - break; - - case 4: DEBUGLN("From master"); - if (cfg.role == GL_SLAVE) { - switch (data[2]) { - case 0: setPower(data[3]); break; // вкл выкл - case 1: setPreset(data[3]); break; // пресет - case 2: cfg.bright = data[3]; break; // яркость - } - EE_updateCfg(); - } - break; - } - FastLED.clear(); // на всякий случай + byte data[MAX_PRESETS * PRES_SIZE + keyLen]; + memset(data, 0, MAX_PRESETS * PRES_SIZE + keyLen); + int count = 0; + char *str, *p = buf + keyLen; // сдвиг до даты + char *ssid, *pass; + while ((str = strtok_r(p, ",", &p)) != NULL) { + data[count++] = atoi(str); + if (count == 4) ssid = str; + if (count == 5) pass = str; } + + // широковещательный запрос времени для local устройств в сети AP лампы + if (data[0] == 0 && cfg.WiFimode && !gotNTP) { + now.hour = data[1]; + now.min = data[2]; + now.setMs(0); + } + + if (data[0] != cfg.group) return; // не наш адрес, выходим + + switch (data[1]) { // тип 0 - control, 1 - config, 2 - effects, 3 - dawn + case 0: DEBUGLN("Control"); + switch (data[2]) { + case 0: setPower(0); break; // выкл + case 1: setPower(1); break; // вкл + case 2: cfg.minLight = phot.getRaw(); break; // мин яркость + case 3: cfg.maxLight = phot.getRaw(); break; // макс яркость + case 4: changePreset(-1); break; // пред пресет + case 5: changePreset(1); break; // след пресет + case 6: setPreset(data[3] - 1); break; // конкретный пресет data[3] + case 7: cfg.WiFimode = data[3]; EE_updCfgRst(); break; // смена режима WiFi + case 8: cfg.role = data[3]; break; // смена роли + case 9: cfg.group = data[3]; break; // смена группы + case 10: // установка настроек WiFi + strcpy(cfg.ssid, ssid); + strcpy(cfg.pass, pass); + break; + case 11: EE_updCfgRst(); break; // рестарт + case 12: if (gotNTP) { // OTA обновление, если есть интернет + cfg.update = 1; + EE_updCfg(); + delay(100); + FastLED.clear(); + FastLED.show(); + char OTA[60]; + strcpy(OTA, OTAhost); + strcpy(OTA + strlen(OTAhost), OTAfile[data[3]]); + ESPhttpUpdate.update(OTA); + } break; + case 13: // выключить через + if (data[3] == 0) turnoffTmr.stop(); + else { + turnoffTmr.setInterval((uint32_t)data[3] * 60000ul); + turnoffTmr.restart(); + } + break; + } + EE_updCfg(); + break; + + case 1: DEBUGLN("Config"); + FOR_i(0, CFG_SIZE) { + *((byte*)&cfg + i) = data[i + 2]; // загоняем в структуру + } + cfg.mTurn = data[21]; + cfg.length = data[17] | (data[16] << 8); // склеиваем + cfg.width = data[20] | (data[19] << 8); // склеиваем + + if (cfg.length > MAX_LEDS) cfg.length = MAX_LEDS; + if (cfg.deviceType == GL_TYPE_STRIP) cfg.width = 1; + if (cfg.length * cfg.width > MAX_LEDS) cfg.width = MAX_LEDS / cfg.length; + ntp.setTimeOffset((cfg.GMT - 13) * 3600); + ntp.setPoolServerName(NTPservers[cfg.NTP - 1]); + FastLED.setMaxPowerInVoltsAndMilliamps(STRIP_VOLT, cfg.maxCur * 100); + if (cfg.adcMode == GL_ADC_BRI) switchToPhot(); + else if (cfg.adcMode == GL_ADC_MIC) switchToMic(); + else disableADC(); + EE_updCfg(); + break; + + case 2: DEBUGLN("Preset"); + cfg.presetAmount = data[2]; // кол-во режимов + FOR_j(0, cfg.presetAmount) { + FOR_i(0, PRES_SIZE) { + *((byte*)&preset + j * PRES_SIZE + i) = data[j * PRES_SIZE + i + 3]; // загоняем в структуру + } + } + EE_updatePreset(); + presetRotation(true); // форсировать смену режима + break; + + case 3: DEBUGLN("Dawn"); + FOR_i(0, (2 + 3 * 7)) { + *((byte*)&dawn + i) = data[i + 2]; // загоняем в структуру + } + EE_updateDawn(); + break; + + case 4: DEBUGLN("From master"); + if (cfg.role == GL_SLAVE) { + switch (data[2]) { + case 0: setPower(data[3]); break; // вкл выкл + case 1: setPreset(data[3]); break; // пресет + case 2: cfg.bright = data[3]; break; // яркость + } + EE_updateCfg(); + } + break; + } + FastLED.clear(); // на всякий случай + } } diff --git a/firmware/GyverLamp2/startup.ino b/firmware/GyverLamp2/startup.ino index 28ffdc6..7a8a139 100644 --- a/firmware/GyverLamp2/startup.ino +++ b/firmware/GyverLamp2/startup.ino @@ -58,7 +58,7 @@ void checkGroup() { } if (flag) { EEPROM.put(0, cfg); - EEPROM.commit(); + EEPROM.commit(); } DEBUG("group: "); DEBUGLN(cfg.group); @@ -67,10 +67,13 @@ void checkGroup() { } void startStrip() { - delay(500); FastLED.addLeds(leds, MAX_LEDS).setCorrection(TypicalLEDStrip); FastLED.setMaxPowerInVoltsAndMilliamps(STRIP_VOLT, 500); FastLED.setBrightness(50); + FastLED.show(); +} + +void showRGB() { leds[0] = CRGB::Red; leds[1] = CRGB::Green; leds[2] = CRGB::Blue; @@ -91,9 +94,7 @@ void startWiFi() { } void setupAP() { - fill_solid(leds, 8, CRGB::Yellow); - FastLED.show(); - delay(500); + blink8(CRGB::Yellow); WiFi.disconnect(); WiFi.mode(WIFI_AP); delay(100); @@ -134,8 +135,7 @@ void setupLocal() { delay(50); } if (connect) { - fill_solid(leds, 8, CRGB::Green); - FastLED.show(); + blink8(CRGB::Green); server.begin(); DEBUG("Connected! Local IP: "); DEBUGLN(WiFi.localIP()); @@ -143,14 +143,7 @@ void setupLocal() { return; } else { DEBUGLN("Failed!"); - FOR_i(0, 3) { - fill_solid(leds, 8, CRGB::Red); - FastLED.show(); - delay(300); - FastLED.clear(); - FastLED.show(); - delay(300); - } + blink8(CRGB::Red); failCount++; tmr = millis(); if (failCount >= 3) { @@ -166,3 +159,18 @@ void setupLocal() { } } } + +void checkUpdate() { + if (cfg.update) { + if (cfg.version != GL_VERSION) { + cfg.version = GL_VERSION; + blink8(CRGB::Cyan); + DEBUG("Update to"); + DEBUGLN(GL_VERSION); + } else { + blink8(CRGB::Blue); + DEBUG("Update to current"); + } + cfg.update = 0; + } +}