diff --git a/android/LedLamp.aia b/android/LedLamp.aia index 265e8e8..14ecc7c 100644 Binary files a/android/LedLamp.aia and b/android/LedLamp.aia differ diff --git a/android/LedLamp.apk b/android/LedLamp.apk index 5057391..5a64a7b 100644 Binary files a/android/LedLamp.apk and b/android/LedLamp.apk differ diff --git a/firmware/GyverLamp_v1.4/Constants.h b/firmware/GyverLamp_v1.4/Constants.h new file mode 100644 index 0000000..a16b49f --- /dev/null +++ b/firmware/GyverLamp_v1.4/Constants.h @@ -0,0 +1,94 @@ +#pragma once + + +// ============= НАСТРОЙКИ ============= +// --- ESP ----------------------------- +#define ESP_MODE (1U) // 0U - WiFi точка доступа, 1U - клиент WiFi (подключение к роутеру) +#define ESP_USE_BUTTON // если строка не закомментирована, должна быть подключена кнопка (иначе ESP может регистрировать "фантомные" нажатия и некорректно устанавливать яркость) +#define ESP_HTTP_PORT (80U) // номер порта, который будет использоваться во время первой утановки имени WiFi сети (и пароля), к которой потом будет подключаться лампа в режиме WiFi клиента (лучше не менять) +#define ESP_UDP_PORT (8888U) // номер порта, который будет "слушать" UDP сервер во время работы лампы как в режиме WiFi точки доступа, так и в режиме WiFi клиента (лучше не менять) +#define ESP_CONN_TIMEOUT (7U) // время в секундах (ДОЛЖНО БЫТЬ МЕНЬШЕ 8, иначе сработает WDT), которое ESP будет пытаться подключиться к WiFi сети, после его истечения автоматически развернёт WiFi точку доступа +#define ESP_CONF_TIMEOUT (300U) // время в секундах, которое ESP будет ждать ввода SSID и пароля WiFi сети роутера в конфигурационном режиме, после его истечения ESP перезагружается +#define GENERAL_DEBUG // если строка не закомментирована, будут выводиться отладочные сообщения +#define WIFIMAN_DEBUG (true) // вывод отладочных сообщений при подключении к WiFi сети: true - выводятся, false - не выводятся; настройка не зависит от GENERAL_DEBUG +#define OTA // если строка не закомментирована, модуль будет ждать два последдовательных запроса пользователя на прошивку по воздуху (см. документацию в "шапке") +#ifdef OTA +#define ESP_OTA_PORT (8266U) // номер порта, который будет "прослушиваться" в ожидании команды прошивки по воздуху +#endif +#define LED_PIN (2U) // пин ленты +#define BTN_PIN (4U) // пин кнопки + +// --- ESP (WiFi клиент) --------------- +const uint8_t STA_STATIC_IP[] = {}; // статический IP адрес: {} - IP адрес определяется роутером; {192, 168, 1, 66} - IP адрес задан явно (если DHCP на роутере не решит иначе); должен быть из того же диапазона адресов, что разадёт роутер + // SSID WiFi сети и пароль будут запрошены WiFi Manager'ом в режиме WiFi точки доступа, нет способа захардкодить их в прошивке + +// --- AP (WiFi точка доступа) --- +#define AP_NAME ("LedLamp") // имя WiFi точки доступа, используется как при запросе SSID и пароля WiFi сети роутера, так и при работе в режиме ESP_MODE = 0 +#define AP_PASS ("31415926") // пароль WiFi точки доступа +const uint8_t AP_STATIC_IP[] = {192, 168, 4, 1}; // статический IP точки доступа (лучше не менять) + +// --- ВРЕМЯ --------------------------- +#define USE_NTP // закомментировать или удалить эту строку, если нужно, чтобы устройство не лезло в интернет +#define GMT (3) // часовой пояс (москва 3) +#define NTP_ADDRESS ("ntp2.colocall.net") // сервер времени +#define NTP_INTERVAL (30UL * 60UL * 1000UL) // интервал синхронизации времени (30 минут) + +// --- РАССВЕТ ------------------------- +#define DAWN_BRIGHT (200U) // максимальная яркость рассвета (0-255) +#define DAWN_TIMEOUT (1U) // сколько рассвет светит после времени будильника, минут + +// --- МАТРИЦА ------------------------- +#define BRIGHTNESS (40U) // стандартная маскимальная яркость (0-255) +#define CURRENT_LIMIT (2000U) // лимит по току в миллиамперах, автоматически управляет яркостью (пожалей свой блок питания!) 0 - выключить лимит + +#define WIDTH (16U) // ширина матрицы +#define HEIGHT (16U) // высота матрицы + +#define COLOR_ORDER (GRB) // порядок цветов на ленте. Если цвет отображается некорректно - меняйте. Начать можно с RGB + +#define MATRIX_TYPE (0U) // тип матрицы: 0 - зигзаг, 1 - параллельная +#define CONNECTION_ANGLE (0U) // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний +#define STRIP_DIRECTION (0U) // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз + // при неправильной настройке матрицы вы получите предупреждение "Wrong matrix parameters! Set to default" + // шпаргалка по настройке матрицы здесь! https://alexgyver.ru/matrix_guide/ + + +// ============= ДЛЯ РАЗРАБОТЧИКОВ ===== + // список и номера эффектов ниже в списке согласованы с android приложением! +#define EFF_SPARKLES (0U) // Конфетти +#define EFF_FIRE (1U) // Огонь +#define EFF_RAINBOW_VER (2U) // Радуга вертикальная +#define EFF_RAINBOW_HOR (3U) // Радуга горизонтальная +#define EFF_RAINBOW_DIAG (4U) // Радуга диагональная +#define EFF_COLORS (5U) // Смена цвета +#define EFF_MADNESS (6U) // Безумие 3D +#define EFF_CLOUDS (7U) // Облака 3D +#define EFF_LAVA (8U) // Лава 3D +#define EFF_PLASMA (9U) // Плазма 3D +#define EFF_RAINBOW (10U) // Радуга 3D +#define EFF_RAINBOW_STRIPE (11U) // Павлин 3D +#define EFF_ZEBRA (12U) // Зебра 3D +#define EFF_FOREST (13U) // Лес 3D +#define EFF_OCEAN (14U) // Океан 3D +#define EFF_COLOR (15U) // Цвет +#define EFF_SNOW (16U) // Снегопад +#define EFF_SNOWSTORM (17U) // Метель +#define EFF_STARFALL (18U) // Звездопад +#define EFF_MATRIX (19U) // Матрица +#define EFF_LIGHTERS (20U) // Светлячки +#define EFF_LIGHTER_TRACES (21U) // Светлячки со шлейфом +#define EFF_PAINTBALL (22U) // Пейнтбол +#define EFF_CUBE (23U) // Блуждающий кубик +#define EFF_WHITE_COLOR (24U) // Белый свет +#define MODE_AMOUNT (25U) // количество режимов + +//#define MAX_UDP_BUFFER_SIZE (UDP_TX_PACKET_MAX_SIZE + 1) +#define MAX_UDP_BUFFER_SIZE (129U) // максимальный размер буффера UDP сервера + +// --- БИБЛИОТЕКИ ---------------------- +#define FASTLED_INTERRUPT_RETRY_COUNT (0U) +#define FASTLED_ALLOW_INTERRUPTS (0U) +#define FASTLED_ESP8266_RAW_PIN_ORDER + +#define NUM_LEDS (WIDTH * HEIGHT) +#define SEGMENTS (1U) // диодов в одном "пикселе" (для создания матрицы из кусков ленты) diff --git a/firmware/GyverLamp_v1.4/FavoritesManager.h b/firmware/GyverLamp_v1.4/FavoritesManager.h index 770b013..e8b7b5a 100644 --- a/firmware/GyverLamp_v1.4/FavoritesManager.h +++ b/firmware/GyverLamp_v1.4/FavoritesManager.h @@ -90,7 +90,7 @@ class FavoritesManager nextModeAt = getNexTime(); #ifdef GENERAL_DEBUG - Serial.printf("Переключение на следующий избранный режим: %d\n\n", (*currentMode)); + Serial.printf_P(PSTR("Переключение на следующий избранный режим: %d\n\n"), (*currentMode)); #endif return true; @@ -136,7 +136,7 @@ class FavoritesManager static bool isStatusTextCorrect(const char* statusText) // валидирует statusText (проверяет, правильное ли коичество компонентов он содержит) { - char buff[128]; + char buff[MAX_UDP_BUFFER_SIZE]; strcpy(buff, statusText); uint8_t lexCount = 0; @@ -208,7 +208,7 @@ class FavoritesManager return NULL; } - const uint8_t buffSize = 128; + const uint8_t buffSize = MAX_UDP_BUFFER_SIZE; char buff[buffSize]; memset(buff, 0, buffSize); strcpy(buff, statusText); diff --git a/firmware/GyverLamp_v1.4/GyverLamp_v1.4.ino b/firmware/GyverLamp_v1.4/GyverLamp_v1.4.ino index 5b141d4..1b3b42c 100644 --- a/firmware/GyverLamp_v1.4/GyverLamp_v1.4.ino +++ b/firmware/GyverLamp_v1.4/GyverLamp_v1.4.ino @@ -53,102 +53,19 @@ - Эффект "Светлячки со шлейфами" переименован в "Угасающие пиксели" - Добавлены 5 новых эффекта: "Радуга диагональная", "Метель", "Звездопад", "Светлячки со шлейфами" (новый) и "Блуждающий кубик" - Исправлены ошибки + --- 04.09.2019 + - Большая часть определений (констант) перенесена в файл Constants.h + - Большая оптимизация использования памяти + - Исправлена ошибка невключения эффекта "Белый свет" приложением и кнопкой + - Исправлена ошибка неправильного выбора интервала в режиме Избранное в android приложении */ // Ссылка для менеджера плат: // https://arduino.esp8266.com/stable/package_esp8266com_index.json -// ============= НАСТРОЙКИ ============= -// --- ВРЕМЯ --------------------------- -#define USE_NTP // закомментировать или удалить эту строку, если нужно, чтобы устройство не лезло в интернет -#define GMT (3) // часовой пояс (москва 3) -#define NTP_ADDRESS ("ntp2.colocall.net") // сервер времени -#define NTP_INTERVAL (30UL * 60UL * 1000UL) // интервал синхронизации времени (30 минут) - -// --- РАССВЕТ ------------------------- -#define DAWN_BRIGHT (200U) // максимальная яркость рассвета (0-255) -#define DAWN_TIMEOUT (1U) // сколько рассвет светит после времени будильника, минут - -// --- МАТРИЦА ------------------------- -#define BRIGHTNESS (40U) // стандартная маскимальная яркость (0-255) -#define CURRENT_LIMIT (2000U) // лимит по току в миллиамперах, автоматически управляет яркостью (пожалей свой блок питания!) 0 - выключить лимит - -#define WIDTH (16U) // ширина матрицы -#define HEIGHT (16U) // высота матрицы - -#define COLOR_ORDER (GRB) // порядок цветов на ленте. Если цвет отображается некорректно - меняйте. Начать можно с RGB - -#define MATRIX_TYPE (0U) // тип матрицы: 0 - зигзаг, 1 - параллельная -#define CONNECTION_ANGLE (0U) // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний -#define STRIP_DIRECTION (0U) // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз - // при неправильной настройке матрицы вы получите предупреждение "Wrong matrix parameters! Set to default" - // шпаргалка по настройке матрицы здесь! https://alexgyver.ru/matrix_guide/ - -// --- ESP ----------------------------- -#define ESP_MODE (1U) // 0U - WiFi точка доступа, 1U - клиент WiFi (подключение к роутеру) -#define ESP_USE_BUTTON // если строка не закомментирована, должна быть подключена кнопка (иначе ESP может регистрировать "фантомные" нажатия и некорректно устанавливать яркость) -#define ESP_HTTP_PORT (80U) // номер порта, который будет использоваться во время первой утановки имени WiFi сети (и пароля), к которой потом будет подключаться лампа в режиме WiFi клиента (лучше не менять) -#define ESP_UDP_PORT (8888U) // номер порта, который будет "слушать" UDP сервер во время работы лампы как в режиме WiFi точки доступа, так и в режиме WiFi клиента (лучше не менять) -#define ESP_CONN_TIMEOUT (7U) // время в секундах (ДОЛЖНО БЫТЬ МЕНЬШЕ 8, иначе сработает WDT), которое ESP будет пытаться подключиться к WiFi сети, после его истечения автоматически развернёт WiFi точку доступа -#define ESP_CONF_TIMEOUT (300U) // время в секундах, которое ESP будет ждать ввода SSID и пароля WiFi сети роутера в конфигурационном режиме, после его истечения ESP перезагружается -#define GENERAL_DEBUG // если строка не закомментирована, будут выводиться отладочные сообщения -#define WIFIMAN_DEBUG (true) // вывод отладочных сообщений при подключении к WiFi сети: true - выводятся, false - не выводятся; настройка не зависит от GENERAL_DEBUG -#define OTA // если строка не закомментирована, модуль будет ждать два последдовательных запроса пользователя на прошивку по воздуху (см. документацию в "шапке") -#ifdef OTA -#define ESP_OTA_PORT (8266U) // номер порта, который будет "прослушиваться" в ожидании команды прошивки по воздуху -#endif - -// --- ESP (WiFi клиент) --------------- -uint8_t STA_STATIC_IP[] = {}; // статический IP адрес: {} - IP адрес определяется роутером; {192, 168, 1, 66} - IP адрес задан явно (если DHCP на роутере не решит иначе); должен быть из того же диапазона адресов, что разадёт роутер - // SSID WiFi сети и пароль будут запрошены WiFi Manager'ом в режиме WiFi точки доступа, нет способа захардкодить их в прошивке - -// --- AP (WiFi точка доступа) --- -#define AP_NAME ("LedLamp") // имя WiFi точки доступа, используется как при запросе SSID и пароля WiFi сети роутера, так и при работе в режиме ESP_MODE = 0 -#define AP_PASS ("31415926") // пароль WiFi точки доступа -uint8_t AP_STATIC_IP[] = {192, 168, 4, 1}; // статический IP точки доступа (лучше не менять) - -// ============= ДЛЯ РАЗРАБОТЧИКОВ ===== -#define LED_PIN (2U) // пин ленты -#define BTN_PIN (4U) // пин кнопки - // список и номера эффектов ниже в списке согласованы с android приложением! -#define EFF_SPARKLES (0U) // Конфетти -#define EFF_FIRE (1U) // Огонь -#define EFF_RAINBOW_VER (2U) // Радуга вертикальная -#define EFF_RAINBOW_HOR (3U) // Радуга горизонтальная -#define EFF_RAINBOW_DIAG (4U) // Радуга диагональная -#define EFF_COLORS (5U) // Смена цвета -#define EFF_MADNESS (6U) // Безумие 3D -#define EFF_CLOUDS (7U) // Облака 3D -#define EFF_LAVA (8U) // Лава 3D -#define EFF_PLASMA (9U) // Плазма 3D -#define EFF_RAINBOW (10U) // Радуга 3D -#define EFF_RAINBOW_STRIPE (11U) // Павлин 3D -#define EFF_ZEBRA (12U) // Зебра 3D -#define EFF_FOREST (13U) // Лес 3D -#define EFF_OCEAN (14U) // Океан 3D -#define EFF_COLOR (15U) // Цвет -#define EFF_SNOW (16U) // Снегопад -#define EFF_SNOWSTORM (17U) // Метель -#define EFF_STARFALL (18U) // Звездопад -#define EFF_MATRIX (19U) // Матрица -#define EFF_LIGHTERS (20U) // Светлячки -#define EFF_LIGHTER_TRACES (21U) // Светлячки со шлейфом -#define EFF_PAINTBALL (22U) // Пейнтбол -#define EFF_CUBE (23U) // Блуждающий кубик -#define EFF_WHITE_COLOR (24U) // Белый свет -#define MODE_AMOUNT (25U) // количество режимов - -#define NUM_LEDS (WIDTH * HEIGHT) -#define SEGMENTS (1U) // диодов в одном "пикселе" (для создания матрицы из кусков ленты) - -// --- БИБЛИОТЕКИ ---------------------- -#define FASTLED_INTERRUPT_RETRY_COUNT (0U) -#define FASTLED_ALLOW_INTERRUPTS (0U) -#define FASTLED_ESP8266_RAW_PIN_ORDER - -#include "Types.h" -#include "timerMinim.h" +#include "pgmspace.h" +#include "Constants.h" #include #include #include @@ -156,6 +73,8 @@ uint8_t AP_STATIC_IP[] = {192, 168, 4, 1}; // статичес #include #include #include +#include "Types.h" +#include "timerMinim.h" #ifdef ESP_USE_BUTTON #include #endif @@ -169,6 +88,7 @@ uint8_t AP_STATIC_IP[] = {192, 168, 4, 1}; // статичес #include "FavoritesManager.h" #include "EepromManager.h" + // --- ИНИЦИАЛИЗАЦИЯ ОБЪЕКТОВ ---------- CRGB leds[NUM_LEDS]; WiFiManager wifiManager; @@ -192,14 +112,14 @@ OtaPhase OtaManager::OtaFlag = OtaPhase::None; // --- ИНИЦИАЛИЗАЦИЯ ПЕРЕМЕННЫХ ------- uint16_t localPort = ESP_UDP_PORT; -char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1]; // buffer to hold incoming packet -String inputBuffer; +char packetBuffer[MAX_UDP_BUFFER_SIZE]; // buffer to hold incoming packet +char inputBuffer[MAX_UDP_BUFFER_SIZE]; static const uint8_t maxDim = max(WIDTH, HEIGHT); ModeType modes[MODE_AMOUNT]; AlarmType alarms[7]; -uint8_t dawnOffsets[] = {5, 10, 15, 20, 25, 30, 40, 50, 60};// опции для выпадающего списка параметра "время перед 'рассветом'" (будильник) +uint8_t dawnOffsets[] = {5, 10, 15, 20, 25, 30, 40, 50, 60};// опции для выпадающего списка параметра "время перед 'рассветом'" (будильник); синхронизировано с android приложением uint8_t dawnMode; bool dawnFlag = false; long thisTime; @@ -242,7 +162,7 @@ void setup() wifiManager.resetSettings(); #ifdef GENERAL_DEBUG - Serial.println("Настройки WiFiManager сброшены"); + Serial.println(F("Настройки WiFiManager сброшены")); #endif } #endif @@ -267,23 +187,23 @@ void setup() WiFi.softAP(AP_NAME, AP_PASS); - Serial.println("Режим WiFi точки доступа"); - Serial.print("IP адрес: "); + Serial.println(F("Режим WiFi точки доступа")); + Serial.print(F("IP адрес: ")); Serial.println(WiFi.softAPIP()); wifiServer.begin(); } else // режим WiFi клиента (подключаемся к роутеру, если есть сохранённые SSID и пароль, иначе создаём WiFi точку доступа и запрашиваем их) { - Serial.println("Режим WiFi клиента"); + Serial.println(F("Режим WiFi клиента")); if (WiFi.SSID()) { - Serial.print("Подключение WiFi сети: "); + Serial.print(F("Подключение WiFi сети: ")); Serial.println(WiFi.SSID()); } else { - Serial.println("WiFi сеть не определена, запуск WiFi точки доступа для настройки параметров подключения к WiFi сети..."); + Serial.println(F("WiFi сеть не определена, запуск WiFi точки доступа для настройки параметров подключения к WiFi сети...")); } if (STA_STATIC_IP) @@ -300,7 +220,7 @@ void setup() if (WiFi.status() != WL_CONNECTED) { - Serial.printf("Время ожидания ввода SSID и пароля от WiFi сети или подключения к WiFi сети превышено\nПерезагрузка модуля"); + Serial.println(F("Время ожидания ввода SSID и пароля от WiFi сети или подключения к WiFi сети превышено\nПерезагрузка модуля")); #if defined(ESP8266) ESP.reset(); @@ -309,11 +229,11 @@ void setup() #endif } - Serial.print("IP адрес: "); + Serial.print(F("IP адрес: ")); Serial.println(WiFi.localIP()); } - Serial.printf("Порт UDP сервера: %u\n", localPort); + Serial.printf_P(PSTR("Порт UDP сервера: %u\n"), localPort); Udp.begin(localPort); EepromManager::InitEepromSettings( // инициализация EEPROM; запись начального состояния настроек, если их там ещё нет; инициализация настроек лампы значениями из EEPROM diff --git a/firmware/GyverLamp_v1.4/OtaManager.h b/firmware/GyverLamp_v1.4/OtaManager.h index 8e29f61..a1e52d8 100644 --- a/firmware/GyverLamp_v1.4/OtaManager.h +++ b/firmware/GyverLamp_v1.4/OtaManager.h @@ -38,7 +38,7 @@ class OtaManager if (ESP_MODE != 1) { #ifdef GENERAL_DEBUG - Serial.printf("Запрос обновления по воздуху поддерживается только в режиме ESP_MODE = 1\n"); + Serial.print(F("Запрос обновления по воздуху поддерживается только в режиме ESP_MODE = 1\n")); #endif return false; @@ -50,7 +50,7 @@ class OtaManager momentOfFirstConfirmation = millis(); #ifdef GENERAL_DEBUG - Serial.printf("Получено первое подтверждение обновления по воздуху\nОжидание второго подтверждения\n"); + Serial.print(F("Получено первое подтверждение обновления по воздуху\nОжидание второго подтверждения\n")); #endif return false; @@ -61,7 +61,7 @@ class OtaManager OtaFlag = OtaPhase::GotSecondConfirm; #ifdef GENERAL_DEBUG - Serial.printf("Получено второе подтверждение обновления по воздуху\nСтарт режима обновления\n"); + Serial.print(F("Получено второе подтверждение обновления по воздуху\nСтарт режима обновления\n")); #endif startOtaUpdate(); @@ -80,7 +80,7 @@ class OtaManager momentOfFirstConfirmation = 0; #ifdef GENERAL_DEBUG - Serial.printf("Таймаут ожидания второго подтверждения превышен\nСброс флага в исходное состояние\n"); + Serial.print(F("Таймаут ожидания второго подтверждения превышен\nСброс флага в исходное состояние\n")); #endif return; @@ -93,7 +93,7 @@ class OtaManager momentOfOtaStart = 0; #ifdef GENERAL_DEBUG - Serial.printf("Таймаут ожидания прошивки по воздуху превышен\nСброс флага в исходное состояние\nПерезагрузка\n"); + Serial.print(F("Таймаут ожидания прошивки по воздуху превышен\nСброс флага в исходное состояние\nПерезагрузка\n")); delay(500); #endif @@ -139,7 +139,7 @@ class OtaManager // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() #ifdef GENERAL_DEBUG - Serial.println("Start updating " + type); + Serial.printf_P(PSTR("Start updating %s\n"), type.c_str()); #endif }); @@ -148,7 +148,7 @@ class OtaManager OtaFlag = OtaPhase::Done; #ifdef GENERAL_DEBUG - Serial.printf("Обновление по воздуху выполнено\nПерезапуск"); + Serial.print(F("Обновление по воздуху выполнено\nПерезапуск")); delay(500); #endif }); @@ -156,7 +156,7 @@ class OtaManager ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { #ifdef GENERAL_DEBUG - Serial.printf("Ход выполнения: %u%%\r", (progress / (total / 100))); + Serial.printf_P(PSTR("Ход выполнения: %u%%\r"), (progress / (total / 100))); #endif }); @@ -165,42 +165,42 @@ class OtaManager OtaFlag = OtaPhase::None; #ifdef GENERAL_DEBUG - Serial.printf("Обновление по воздуху завершилось ошибкой [%u]: ", error); + Serial.printf_P(PSTR("Обновление по воздуху завершилось ошибкой [%u]: "), error); #endif if (error == OTA_AUTH_ERROR) { #ifdef GENERAL_DEBUG - Serial.println("Auth Failed"); + Serial.println(F("Auth Failed")); #endif } else if (error == OTA_BEGIN_ERROR) { #ifdef GENERAL_DEBUG - Serial.println("Begin Failed"); + Serial.println(F("Begin Failed")); #endif } else if (error == OTA_CONNECT_ERROR) { #ifdef GENERAL_DEBUG - Serial.println("Connect Failed"); + Serial.println(F("Connect Failed")); #endif } else if (error == OTA_RECEIVE_ERROR) { #ifdef GENERAL_DEBUG - Serial.println("Receive Failed"); + Serial.println(F("Receive Failed")); #endif } else if (error == OTA_END_ERROR) { #ifdef GENERAL_DEBUG - Serial.println("End Failed"); + Serial.println(F("End Failed")); #endif } #ifdef GENERAL_DEBUG - Serial.printf("Сброс флага в исходное состояние\nПереход в режим ожидания запроса прошивки по воздуху\n"); + Serial.print(F("Сброс флага в исходное состояние\nПереход в режим ожидания запроса прошивки по воздуху\n")); #endif }); @@ -211,11 +211,11 @@ class OtaManager momentOfOtaStart = 0; #ifdef GENERAL_DEBUG - Serial.printf("Для обновления в Arduino IDE выберите пункт меню Инструменты - Порт - '%s at ", espHostName); + Serial.printf_P(PSTR("Для обновления в Arduino IDE выберите пункт меню Инструменты - Порт - '%s at "), espHostName); Serial.print(WiFi.localIP()); - Serial.println("'"); - Serial.printf("Затем нажмите кнопку 'Загрузка' в течение %u секунд и по запросу введите пароль '%s'\n", ESP_CONF_TIMEOUT, AP_PASS); - Serial.println("Устройство с Arduino IDE должно быть в одной локальной сети с модулем ESP!"); + Serial.println(F("'")); + Serial.printf_P(PSTR("Затем нажмите кнопку 'Загрузка' в течение %u секунд и по запросу введите пароль '%s'\n"), ESP_CONF_TIMEOUT, AP_PASS); + Serial.println(F("Устройство с Arduino IDE должно быть в одной локальной сети с модулем ESP!")); #endif } }; diff --git a/firmware/GyverLamp_v1.4/TimerManager.h b/firmware/GyverLamp_v1.4/TimerManager.h index 7a54fbf..8bc4992 100644 --- a/firmware/GyverLamp_v1.4/TimerManager.h +++ b/firmware/GyverLamp_v1.4/TimerManager.h @@ -18,7 +18,7 @@ class TimerManager millis() >= TimerManager::TimeToFire) { #ifdef GENERAL_DEBUG - Serial.printf("Выключение по таймеру\n\n"); + Serial.print(F("Выключение по таймеру\n\n")); #endif TimerManager::TimerRunning = false; diff --git a/firmware/GyverLamp_v1.4/button.ino b/firmware/GyverLamp_v1.4/button.ino index da4d76e..32300ff 100644 --- a/firmware/GyverLamp_v1.4/button.ino +++ b/firmware/GyverLamp_v1.4/button.ino @@ -10,7 +10,6 @@ void buttonTick() { manualOff = true; dawnFlag = false; - loadingFlag = true; FastLED.setBrightness(modes[currentMode].Brightness); changePower(); } @@ -19,6 +18,7 @@ void buttonTick() ONflag = !ONflag; changePower(); } + loadingFlag = true; } if (ONflag && touch.isDouble()) @@ -79,7 +79,7 @@ void buttonTick() eepromTimeout = millis(); #ifdef GENERAL_DEBUG - Serial.printf("New brightness value: %d\n", modes[currentMode].Brightness); + Serial.printf_P(PSTR("New brightness value: %d\n"), modes[currentMode].Brightness); #endif } } diff --git a/firmware/GyverLamp_v1.4/effects.ino b/firmware/GyverLamp_v1.4/effects.ino index c9ef89f..c4497e9 100644 --- a/firmware/GyverLamp_v1.4/effects.ino +++ b/firmware/GyverLamp_v1.4/effects.ino @@ -47,11 +47,11 @@ void fadePixel(uint8_t i, uint8_t j, uint8_t step) // новый фей // ------------- огонь ----------------- #define SPARKLES (1U) // вылетающие угольки вкл выкл -unsigned char line[WIDTH]; -int32_t pcnt = 0; +uint8_t line[WIDTH]; +uint8_t pcnt = 0; //these values are substracetd from the generated values to give a shape to the animation -const unsigned char valueMask[8][16] PROGMEM = +const uint8_t valueMask[8][16] PROGMEM = { {32 , 0 , 0 , 0 , 0 , 0 , 0 , 32 , 32 , 0 , 0 , 0 , 0 , 0 , 0 , 32 }, {64 , 0 , 0 , 0 , 0 , 0 , 0 , 64 , 64 , 0 , 0 , 0 , 0 , 0 , 0 , 64 }, @@ -62,10 +62,10 @@ const unsigned char valueMask[8][16] PROGMEM = {255, 160, 128, 96 , 96 , 128, 160, 255, 255, 160, 128, 96 , 96 , 128, 160, 255}, {255, 192, 160, 128, 128, 160, 192, 255, 255, 192, 160, 128, 128, 160, 192, 255} }; + //these are the hues for the fire, //should be between 0 (red) to about 25 (yellow) - -const unsigned char hueMask[8][16] PROGMEM = +const uint8_t hueMask[8][16] PROGMEM = { {1 , 11, 19, 25, 25, 22, 11, 1 , 1 , 11, 19, 25, 25, 22, 11, 1 }, {1 , 8 , 13, 19, 25, 19, 8 , 1 , 1 , 8 , 13, 19, 25, 19, 8 , 1 }, @@ -129,14 +129,14 @@ void shiftUp() // draw a frame, interpolating between 2 "key frames" // @param pcnt percentage of interpolation -void drawFrame(int32_t pcnt) +void drawFrame(uint8_t pcnt) { int32_t nextv; //each row interpolates with the one before it - for (unsigned char y = HEIGHT - 1; y > 0; y--) + for (uint8_t y = HEIGHT - 1; y > 0; y--) { - for (unsigned char x = 0; x < WIDTH; x++) + for (uint8_t x = 0; x < WIDTH; x++) { uint8_t newX = x; if (x > 15) newX = x % 16; @@ -171,7 +171,7 @@ void drawFrame(int32_t pcnt) } //first row interpolates with the "next" line - for (unsigned char x = 0; x < WIDTH; x++) + for (uint8_t x = 0; x < WIDTH; x++) { uint8_t newX = x; if (x > 15) newX = x % 16; @@ -252,9 +252,15 @@ void colorsRoutine() // ------------- цвет ------------------ void colorRoutine() { - for (int32_t i = 0; i < NUM_LEDS; i++) + if (loadingFlag) { - leds[i] = CHSV(modes[EFF_COLOR].Scale * 2.5, 255, 255); + loadingFlag = false; + FastLED.clear(); + + for (int16_t i = 0; i < NUM_LEDS; i++) + { + leds[i] = CHSV(modes[EFF_COLOR].Scale * 2.5, 255, 255); + } } } @@ -486,7 +492,7 @@ void ballsRoutine() { loadingFlag = false; - for (byte j = 0; j < BALLS_AMOUNT; j++) + for (uint8_t j = 0; j < BALLS_AMOUNT; j++) { int8_t sign; // забиваем случайными данными @@ -537,7 +543,7 @@ void ballsRoutine() } } -// ------------- угасающие пиксели ------------- +// ------------- пейнтбол ------------- const uint8_t BorderWidth = 2; void lightBallsRoutine() { diff --git a/firmware/GyverLamp_v1.4/parsing.ino b/firmware/GyverLamp_v1.4/parsing.ino index df3cd4e..88a271d 100644 --- a/firmware/GyverLamp_v1.4/parsing.ino +++ b/firmware/GyverLamp_v1.4/parsing.ino @@ -1,37 +1,38 @@ void parseUDP() { int32_t packetSize = Udp.parsePacket(); + char buff[MAX_UDP_BUFFER_SIZE], *endToken = NULL; if (packetSize) { - int32_t n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE); - packetBuffer[n] = 0; - inputBuffer = packetBuffer; + int16_t n = Udp.read(packetBuffer, MAX_UDP_BUFFER_SIZE); + packetBuffer[n] = '\0'; + strcpy(inputBuffer, packetBuffer); #ifdef GENERAL_DEBUG - Serial.print("Inbound UDP packet: "); + Serial.print(F("Inbound UDP packet: ")); Serial.println(inputBuffer); #endif - if (inputBuffer.startsWith("DEB")) + if (!strncmp_P(inputBuffer, PSTR("DEB"), 3)) { - inputBuffer = #ifdef USE_NTP - "OK " + timeClient.getFormattedTime(); + sprintf_P(inputBuffer, PSTR("%s%s"), PSTR("OK "), timeClient.getFormattedTime().c_str()); #else - "OK --:--"; + strcpy_P(inputBuffer, PSTR("OK --:--")); #endif } - else if (inputBuffer.startsWith("GET")) + else if (!strncmp_P(inputBuffer, PSTR("GET"), 3)) { sendCurrent(); } - else if (inputBuffer.startsWith("EFF")) + else if (!strncmp_P(inputBuffer, PSTR("EFF"), 3)) { EepromManager::SaveModesSettings(¤tMode, modes); - currentMode = (byte)inputBuffer.substring(3).toInt(); + memcpy(buff, &inputBuffer[3], strlen(inputBuffer)); // взять подстроку, состоящую последних символов строки inputBuffer, начиная с символа 4 + currentMode = (uint8_t)atoi(buff); loadingFlag = true; FastLED.clear(); delay(1); @@ -39,128 +40,137 @@ void parseUDP() FastLED.setBrightness(modes[currentMode].Brightness); } - else if (inputBuffer.startsWith("BRI")) + else if (!strncmp_P(inputBuffer, PSTR("BRI"), 3)) { - modes[currentMode].Brightness = constrain(inputBuffer.substring(3).toInt(), 1, 255); + memcpy(buff, &inputBuffer[3], strlen(inputBuffer)); // взять подстроку, состоящую последних символов строки inputBuffer, начиная с символа 4 + modes[currentMode].Brightness = constrain(atoi(buff), 1, 255); FastLED.setBrightness(modes[currentMode].Brightness); settChanged = true; eepromTimeout = millis(); sendCurrent(); } - else if (inputBuffer.startsWith("SPD")) + else if (!strncmp_P(inputBuffer, PSTR("SPD"), 3)) { - modes[currentMode].Speed = inputBuffer.substring(3).toInt(); + memcpy(buff, &inputBuffer[3], strlen(inputBuffer)); // взять подстроку, состоящую последних символов строки inputBuffer, начиная с символа 4 + modes[currentMode].Speed = atoi(buff); loadingFlag = true; settChanged = true; eepromTimeout = millis(); sendCurrent(); } - else if (inputBuffer.startsWith("SCA")) + else if (!strncmp_P(inputBuffer, PSTR("SCA"), 3)) { - modes[currentMode].Scale = inputBuffer.substring(3).toInt(); + memcpy(buff, &inputBuffer[3], strlen(inputBuffer)); // взять подстроку, состоящую последних символов строки inputBuffer, начиная с символа 4 + modes[currentMode].Scale = atoi(buff); loadingFlag = true; settChanged = true; eepromTimeout = millis(); sendCurrent(); } - else if (inputBuffer.startsWith("P_ON")) + else if (!strncmp_P(inputBuffer, PSTR("P_ON"), 4)) { ONflag = true; + loadingFlag = true; changePower(); sendCurrent(); } - else if (inputBuffer.startsWith("P_OFF")) + else if (!strncmp_P(inputBuffer, PSTR("P_OFF"), 5)) { ONflag = false; changePower(); sendCurrent(); } - else if (inputBuffer.startsWith("ALM_SET")) + else if (!strncmp_P(inputBuffer, PSTR("ALM_SET"), 7)) { uint8_t alarmNum = (char)inputBuffer[7] - '0'; alarmNum -= 1; - if (inputBuffer.indexOf("ON") != -1) + if (strstr_P(inputBuffer, PSTR("ON")) - inputBuffer == 9) { alarms[alarmNum].State = true; sendAlarms(); } - else if (inputBuffer.indexOf("OFF") != -1) + else if (strstr_P(inputBuffer, PSTR("OFF")) - inputBuffer == 9) { alarms[alarmNum].State = false; sendAlarms(); } else { - int32_t alarmTime = inputBuffer.substring(8).toInt(); - alarms[alarmNum].Time = alarmTime; - uint8_t hour = floor(alarmTime / 60); - uint8_t minute = alarmTime - hour * 60; + memcpy(buff, &inputBuffer[8], strlen(inputBuffer)); // взять подстроку, состоящую последних символов строки inputBuffer, начиная с символа 9 + alarms[alarmNum].Time = atoi(buff); + uint8_t hour = floor(alarms[alarmNum].Time / 60); + uint8_t minute = alarms[alarmNum].Time - hour * 60; sendAlarms(); } EepromManager::SaveAlarmsSettings(&alarmNum, alarms); } - else if (inputBuffer.startsWith("ALM_GET")) + else if (!strncmp_P(inputBuffer, PSTR("ALM_GET"), 7)) { sendAlarms(); } - else if (inputBuffer.startsWith("DAWN")) + else if (!strncmp_P(inputBuffer, PSTR("DAWN"), 4)) { - dawnMode = inputBuffer.substring(4).toInt() - 1; + memcpy(buff, &inputBuffer[4], strlen(inputBuffer)); // взять подстроку, состоящую последних символов строки inputBuffer, начиная с символа 5 + dawnMode = atoi(buff) - 1; EepromManager::SaveDawnMode(&dawnMode); sendAlarms(); } - else if (inputBuffer.startsWith("DISCOVER")) // обнаружение приложением модуля esp в локальной сети + else if (!strncmp_P(inputBuffer, PSTR("DISCOVER"), 8)) // обнаружение приложением модуля esp в локальной сети { if (ESP_MODE == 1) // работает только в режиме WiFi клиента { - inputBuffer = "IP"; - inputBuffer += " "; - inputBuffer += String(WiFi.localIP()[0]) + "." + - String(WiFi.localIP()[1]) + "." + - String(WiFi.localIP()[2]) + "." + - String(WiFi.localIP()[3]); - inputBuffer += ":"; - inputBuffer += String(ESP_UDP_PORT); + sprintf_P(inputBuffer, PSTR("IP %u.%u.%u.%u:%u"), + WiFi.localIP()[0], + WiFi.localIP()[1], + WiFi.localIP()[2], + WiFi.localIP()[3], + ESP_UDP_PORT); } } - else if (inputBuffer.startsWith("TMR_GET")) + else if (!strncmp_P(inputBuffer, PSTR("TMR_GET"), 7)) { sendTimer(); } - else if (inputBuffer.startsWith("TMR_SET")) + else if (!strncmp_P(inputBuffer, PSTR("TMR_SET"), 7)) { - TimerManager::TimerRunning = inputBuffer.substring(8, 9).toInt(); - TimerManager::TimerOption = inputBuffer.substring(10, 11).toInt(); - TimerManager::TimeToFire = millis() + (uint64_t)(inputBuffer.substring(12).toInt() * 1000); + memcpy(buff, &inputBuffer[8], 2); // взять подстроку, состоящую из 9 и 10 символов, из строки inputBuffer + TimerManager::TimerRunning = (bool)atoi(buff); + + memcpy(buff, &inputBuffer[10], 2); // взять подстроку, состоящую из 11 и 12 символов, из строки inputBuffer + TimerManager::TimerOption = (uint8_t)atoi(buff); + + memcpy(buff, &inputBuffer[12], strlen(inputBuffer)); // взять подстроку, состоящую последних символов строки inputBuffer, начиная с символа 13 + TimerManager::TimeToFire = millis() + strtoull(buff, &endToken, 10) * 1000; + TimerManager::TimerHasFired = false; sendTimer(); } - else if (inputBuffer.startsWith("FAV_GET")) + else if (!strncmp_P(inputBuffer, PSTR("FAV_GET"), 7)) { sendFavorites(); } - else if (inputBuffer.startsWith("FAV_SET")) + else if (!strncmp_P(inputBuffer, PSTR("FAV_SET"), 7)) { - FavoritesManager::ConfigureFavorites(inputBuffer.c_str()); + FavoritesManager::ConfigureFavorites(inputBuffer); //FavoritesManager::SetStatus(inputBuffer); sendFavorites(); settChanged = true; eepromTimeout = millis(); } - else if (inputBuffer.startsWith("OTA")) + else if (!strncmp_P(inputBuffer, PSTR("OTA"), 3)) { #ifdef OTA otaManager.RequestOtaUpdate(); @@ -176,10 +186,10 @@ void parseUDP() else { - inputBuffer = ""; + inputBuffer[0] = '\0'; } - if (inputBuffer.length() <= 0) + if (strlen(inputBuffer) <= 0) { return; } @@ -189,15 +199,15 @@ void parseUDP() return; } - char reply[inputBuffer.length() + 1]; - inputBuffer.toCharArray(reply, inputBuffer.length() + 1); - inputBuffer.remove(0); // очистка буфера, читобы не он не интерпретировался, как следующий udp пакет + char reply[strlen(inputBuffer) + 1]; + strcpy(reply, inputBuffer); + inputBuffer[0] = '\0'; // очистка буфера, читобы не он не интерпретировался, как следующий udp пакет Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); Udp.write(reply); Udp.endPacket(); #ifdef GENERAL_DEBUG - Serial.print("Outbound UDP packet: "); + Serial.print(F("Outbound UDP packet: ")); Serial.println(reply); Serial.println(); #endif @@ -206,74 +216,63 @@ void parseUDP() void sendCurrent() { - inputBuffer = "CURR"; - inputBuffer += " "; - inputBuffer += String(currentMode); - inputBuffer += " "; - inputBuffer += String(modes[currentMode].Brightness); - inputBuffer += " "; - inputBuffer += String(modes[currentMode].Speed); - inputBuffer += " "; - inputBuffer += String(modes[currentMode].Scale); - inputBuffer += " "; - inputBuffer += String(ONflag); - inputBuffer += " "; - inputBuffer += String(ESP_MODE); - inputBuffer += " "; + sprintf_P(inputBuffer, PSTR("CURR %u %u %u %u %u %u"), + currentMode, + modes[currentMode].Brightness, + modes[currentMode].Speed, + modes[currentMode].Scale, + ONflag, + ESP_MODE); + #ifdef USE_NTP - inputBuffer += "1"; + strcat_P(inputBuffer, PSTR(" 1")); #else - inputBuffer += "0"; + strcat_P(inputBuffer, PSTR(" 0")); #endif - inputBuffer += " "; - inputBuffer += String((uint8_t)TimerManager::TimerRunning); - inputBuffer += " "; + + sprintf_P(inputBuffer, PSTR("%s %u"), inputBuffer, (uint8_t)TimerManager::TimerRunning); + #ifdef USE_NTP - inputBuffer += timeClient.getFormattedTime(); + sprintf_P(inputBuffer, PSTR("%s %s"), inputBuffer, timeClient.getFormattedTime().c_str()); #else - inputBuffer += String(millis()); + sprintf_P(inputBuffer, PSTR("%s %ull"), inputBuffer, millis()); #endif } void sendAlarms() { - inputBuffer = "ALMS "; + strcpy_P(inputBuffer, PSTR("ALMS")); + for (byte i = 0; i < 7; i++) { - inputBuffer += String(alarms[i].State); - inputBuffer += " "; + sprintf_P(inputBuffer, PSTR("%s %u"), inputBuffer, (uint8_t)alarms[i].State); } + for (byte i = 0; i < 7; i++) { - inputBuffer += String(alarms[i].Time); - inputBuffer += " "; + sprintf_P(inputBuffer, PSTR("%s %u"), inputBuffer, alarms[i].Time); } - inputBuffer += (dawnMode + 1); + + sprintf_P(inputBuffer, PSTR("%s %u"), inputBuffer, dawnMode + 1); } void sendTimer() { - inputBuffer = "TMR"; - inputBuffer += " "; - inputBuffer += String((uint8_t)TimerManager::TimerRunning); - inputBuffer += " "; - inputBuffer += String(TimerManager::TimerOption); - inputBuffer += " "; - inputBuffer += String(TimerManager::TimerRunning ? (uint16_t)floor((TimerManager::TimeToFire - millis()) / 1000) : 0); + sprintf_P(inputBuffer, PSTR("TMR %u %u %u"), + TimerManager::TimerRunning, + TimerManager::TimerOption, + (TimerManager::TimerRunning ? (uint16_t)floor((TimerManager::TimeToFire - millis()) / 1000) : 0)); } void sendFavorites() { - inputBuffer = "FAV"; - inputBuffer += " "; - inputBuffer += String((uint8_t)FavoritesManager::FavoritesRunning); - inputBuffer += " "; - inputBuffer += String((uint16_t)FavoritesManager::Interval); - inputBuffer += " "; - inputBuffer += String((uint16_t)FavoritesManager::Dispersion); + sprintf_P(inputBuffer, PSTR("FAV %u %u %u"), + FavoritesManager::FavoritesRunning, + FavoritesManager::Interval, + FavoritesManager::Dispersion); + for (uint8_t i = 0; i < MODE_AMOUNT; i++) { - inputBuffer += " "; - inputBuffer += String((uint8_t)FavoritesManager::FavoriteModes[i]); + sprintf_P(inputBuffer, PSTR("%s %u"), inputBuffer, FavoritesManager::FavoriteModes[i]); } } diff --git a/firmware/GyverLamp_v1.4/time.ino b/firmware/GyverLamp_v1.4/time.ino index 8e03d3b..1c22936 100644 --- a/firmware/GyverLamp_v1.4/time.ino +++ b/firmware/GyverLamp_v1.4/time.ino @@ -32,7 +32,7 @@ void timeTick() if (!ntpServerAddressResolved) { #ifdef GENERAL_DEBUG - Serial.println("Функции будильника отключены до восстановления подключения к интернету"); + Serial.println(F("Функции будильника отключены до восстановления подключения к интернету")); #endif } } @@ -101,7 +101,7 @@ void resolveNtpServerAddress(bool &ntpServerAddressResolved) // ф #ifdef GENERAL_DEBUG if (ntpServerAddressResolved) { - Serial.println("Подключение к интернету отсутствует"); + Serial.println(F("Подключение к интернету отсутствует")); } #endif @@ -112,7 +112,7 @@ void resolveNtpServerAddress(bool &ntpServerAddressResolved) // ф #ifdef GENERAL_DEBUG if (!ntpServerAddressResolved) { - Serial.println("Подключение к интернету установлено"); + Serial.println(F("Подключение к интернету установлено")); } #endif