Добавлена возможность смены ESP_MODE без перепрошивки; доработан будильник; добавлена визуальная сигнализация красными и жёлтыми вспышками для некоторых действий/состояний; оптимизирован код, исправлены ошибки

This commit is contained in:
gunner47
2019-10-12 19:52:04 +03:00
parent baa82236ee
commit 33c811ab59
13 changed files with 469 additions and 363 deletions

View File

@@ -6,11 +6,12 @@
// ============= НАСТРОЙКИ ============= // ============= НАСТРОЙКИ =============
// --- ESP ----------------------------- // --- ESP -----------------------------
#define ESP_MODE (1U) // 0U - WiFi точка доступа, 1U - клиент WiFi (подключение к роутеру) #define ESP_MODE (1U) // 0U - WiFi точка доступа, 1U - клиент WiFi (подключение к роутеру)
uint8_t espMode = ESP_MODE; // ESP_MODE может быть сохранён в энергонезависимую память и изменён в процессе работы лампы без необходимости её перепрошивки
#define ESP_USE_BUTTON // если строка не закомментирована, должна быть подключена кнопка (иначе ESP может регистрировать "фантомные" нажатия и некорректно устанавливать яркость) #define ESP_USE_BUTTON // если строка не закомментирована, должна быть подключена кнопка (иначе ESP может регистрировать "фантомные" нажатия и некорректно устанавливать яркость)
#define ESP_RESET_ON_START (false) // true - если при старте нажата кнопка (или кнопки нет!), сохранённые настройки будут сброшены; false - не будут #define ESP_RESET_ON_START (false) // true - если при старте нажата кнопка (или кнопки нет!), сохранённые настройки будут сброшены; false - не будут
#define ESP_HTTP_PORT (80U) // номер порта, который будет использоваться во время первой утановки имени WiFi сети (и пароля), к которой потом будет подключаться лампа в режиме WiFi клиента (лучше не менять) #define ESP_HTTP_PORT (80U) // номер порта, который будет использоваться во время первой утановки имени WiFi сети (и пароля), к которой потом будет подключаться лампа в режиме WiFi клиента (лучше не менять)
#define ESP_UDP_PORT (8888U) // номер порта, который будет "слушать" UDP сервер во время работы лампы как в режиме WiFi точки доступа, так и в режиме WiFi клиента (лучше не менять) #define ESP_UDP_PORT (8888U) // номер порта, который будет "слушать" UDP сервер во время работы лампы как в режиме WiFi точки доступа, так и в режиме WiFi клиента (лучше не менять)
#define ESP_CONN_TIMEOUT (7U) // время в секундах (ДОЛЖНО БЫТЬ МЕНЬШЕ 8, иначе сработает WDT), которое ESP будет пытаться подключиться к WiFi сети, после его истечения автоматически развернёт WiFi точку доступа #define ESP_CONN_TIMEOUT (6U) // время в секундах (ДОЛЖНО БЫТЬ МЕНЬШЕ 8, иначе сработает WDT), которое ESP будет пытаться подключиться к WiFi сети, после его истечения автоматически развернёт WiFi точку доступа
#define ESP_CONF_TIMEOUT (300U) // время в секундах, которое ESP будет ждать ввода SSID и пароля WiFi сети роутера в конфигурационном режиме, после его истечения ESP перезагружается #define ESP_CONF_TIMEOUT (300U) // время в секундах, которое ESP будет ждать ввода SSID и пароля WiFi сети роутера в конфигурационном режиме, после его истечения ESP перезагружается
#define GENERAL_DEBUG // если строка не закомментирована, будут выводиться отладочные сообщения #define GENERAL_DEBUG // если строка не закомментирована, будут выводиться отладочные сообщения
#define WIFIMAN_DEBUG (true) // вывод отладочных сообщений при подключении к WiFi сети: true - выводятся, false - не выводятся; настройка не зависит от GENERAL_DEBUG #define WIFIMAN_DEBUG (true) // вывод отладочных сообщений при подключении к WiFi сети: true - выводятся, false - не выводятся; настройка не зависит от GENERAL_DEBUG
@@ -111,5 +112,5 @@ bool telnetGreetingShown = false; // признак "
#define FASTLED_ALLOW_INTERRUPTS (0U) #define FASTLED_ALLOW_INTERRUPTS (0U)
#define FASTLED_ESP8266_RAW_PIN_ORDER #define FASTLED_ESP8266_RAW_PIN_ORDER
#define NUM_LEDS (WIDTH * HEIGHT) #define NUM_LEDS (uint16_t)(WIDTH * HEIGHT)
#define SEGMENTS (1U) // диодов в одном "пикселе" (для создания матрицы из кусков ленты) #define SEGMENTS (1U) // диодов в одном "пикселе" (для создания матрицы из кусков ленты)

View File

@@ -55,7 +55,7 @@
* *
* Не используются адреса: * Не используются адреса:
* 96-110 15 резерв, можно добавить ещё 5 эффектов * 96-110 15 резерв, можно добавить ещё 5 эффектов
* 142-196 55 если добавить ещё 5 эффектов, начальный адрес неиспользуемой памяти сдвинется с 142 на 147 * 142-195 54 если добавить ещё 5 эффектов, начальный адрес неиспользуемой памяти сдвинется с 142 на 147
*/ */
#include <EEPROM.h> #include <EEPROM.h>
@@ -64,6 +64,7 @@
#define EEPROM_ALARM_START_ADDRESS (0U) // начальный адрес в EEPROM памяти для записи настроек будильников #define EEPROM_ALARM_START_ADDRESS (0U) // начальный адрес в EEPROM памяти для записи настроек будильников
#define EEPROM_MODES_START_ADDRESS (21U) // начальный адрес в EEPROM памяти для записи настроек эффектов (яркость, скорость, масштаб) #define EEPROM_MODES_START_ADDRESS (21U) // начальный адрес в EEPROM памяти для записи настроек эффектов (яркость, скорость, масштаб)
#define EEPROM_FAVORITES_START_ADDRESS (111U) // начальный адрес в EEPROM памяти для записи настроек режима избранных эффектов #define EEPROM_FAVORITES_START_ADDRESS (111U) // начальный адрес в EEPROM памяти для записи настроек режима избранных эффектов
#define EEPROM_ESP_MODE (196U) // адрес в EEPROM памяти для записи режима работы модуля ESP (точка доступа/WiFi клиент)
#define EEPROM_LAMP_ON_ADDRESS (197U) // адрес в EEPROM памяти для записи состояния лампы (вкл/выкл) #define EEPROM_LAMP_ON_ADDRESS (197U) // адрес в EEPROM памяти для записи состояния лампы (вкл/выкл)
#define EEPROM_FIRST_RUN_ADDRESS (198U) // адрес в EEPROM памяти для записи признака первого запуска (определяет необходимость первоначальной записи всех хранимых настроек) #define EEPROM_FIRST_RUN_ADDRESS (198U) // адрес в EEPROM памяти для записи признака первого запуска (определяет необходимость первоначальной записи всех хранимых настроек)
#define EEPROM_DAWN_MODE_ADDRESS (199U) // адрес в EEPROM памяти для записи времени до "рассвета" #define EEPROM_DAWN_MODE_ADDRESS (199U) // адрес в EEPROM памяти для записи времени до "рассвета"
@@ -79,7 +80,7 @@
class EepromManager class EepromManager
{ {
public: public:
static void InitEepromSettings(ModeType modes[], AlarmType alarms[], bool* onFlag, uint8_t* dawnMode, int8_t* currentMode, static void InitEepromSettings(ModeType modes[], AlarmType alarms[], uint8_t* espMode, bool* onFlag, uint8_t* dawnMode, int8_t* currentMode,
void (*readFavoritesSettings)(), void (*saveFavoritesSettings)()) void (*readFavoritesSettings)(), void (*saveFavoritesSettings)())
{ {
// записываем в EEPROM начальное состояние настроек, если их там ещё нет // записываем в EEPROM начальное состояние настроек, если их там ещё нет
@@ -104,6 +105,7 @@ class EepromManager
EEPROM.commit(); EEPROM.commit();
} }
EEPROM.write(EEPROM_ESP_MODE, ESP_MODE);
EEPROM.write(EEPROM_LAMP_ON_ADDRESS, 0); EEPROM.write(EEPROM_LAMP_ON_ADDRESS, 0);
EEPROM.write(EEPROM_DAWN_MODE_ADDRESS, 0); EEPROM.write(EEPROM_DAWN_MODE_ADDRESS, 0);
EEPROM.write(EEPROM_CURRENT_MODE_ADDRESS, 0); EEPROM.write(EEPROM_CURRENT_MODE_ADDRESS, 0);
@@ -127,6 +129,7 @@ class EepromManager
readFavoritesSettings(); readFavoritesSettings();
*espMode = (uint8_t)EEPROM.read(EEPROM_ESP_MODE);
*onFlag = (bool)EEPROM.read(EEPROM_LAMP_ON_ADDRESS); *onFlag = (bool)EEPROM.read(EEPROM_LAMP_ON_ADDRESS);
*dawnMode = EEPROM.read(EEPROM_DAWN_MODE_ADDRESS); *dawnMode = EEPROM.read(EEPROM_DAWN_MODE_ADDRESS);
*currentMode = EEPROM.read(EEPROM_CURRENT_MODE_ADDRESS); *currentMode = EEPROM.read(EEPROM_CURRENT_MODE_ADDRESS);
@@ -162,6 +165,12 @@ class EepromManager
EEPROM.commit(); EEPROM.commit();
} }
static void SaveEspMode(uint8_t* espMode)
{
EEPROM.write(EEPROM_ESP_MODE, *espMode);
EEPROM.commit();
}
static void SaveOnFlag(bool* onFlag) static void SaveOnFlag(bool* onFlag)
{ {
EEPROM.write(EEPROM_LAMP_ON_ADDRESS, *onFlag); EEPROM.write(EEPROM_LAMP_ON_ADDRESS, *onFlag);

View File

@@ -74,6 +74,19 @@
- Добавлено управление по протоколу MQTT - Добавлено управление по протоколу MQTT
- Исправлена ошибка выключения будильника кнопкой - Исправлена ошибка выключения будильника кнопкой
- Добавлена задержка в 1 секунду сразу после старта, в течение которой нужно нажать кнопку, чтобы очистить сохранённые параметры WiFi (если ESP_RESET_ON_START == true) - Добавлена задержка в 1 секунду сразу после старта, в течение которой нужно нажать кнопку, чтобы очистить сохранённые параметры WiFi (если ESP_RESET_ON_START == true)
--- 12.10.2019
- Добавлена возможность сменить рабочий режим лампы (ESP_MODE) без необходимости перепрошивки; вызывается по семикратному клику по кнопке при включенной матрице; сохраняется в EEPROM
- Изменён алгоритм работы будильника:
- * обновление его оттенка/яркости происходит 1 раз в 3 секунды вместо 1 раза в минуту
- * диоды разбиты на 6 групп, первой из которых назначается новый оттенок/яркость 1 раз в 3 секунды, вторая "отстаёт" на 1 шаг, третья - на 2 шага и т.д. (для большей плавности)
- Добавлена визуальная сигнализация о некоторых важных действиях/состояниях лампы:
- * при запуске в режиме WiFi клиента и ещё не настроенных параметрах WiFi сети (когда их нужно ввести) - 1 короткая (0,25 сек) вспышка жёлтым
- * если лампа стартовала в режиме WiFi клиента с ненастроенными параметрами WiFi сети, и они не были введены за отведённый таймаут (перед перезагрузкой) - 1 короткая вспышка красным
- * при переходе лампы в режим обновления по воздуху (OTA) по двум четырёхкратным кликам по кнопке или по кнопке OTA из android приложения - 2 стандартных (0,5 сек) вспышки жёлтым
- * если лампа была переведена в режим OTA, но не дождалась прошивки за отведённый таймаут (перед перезагрузкой) - 2 стандартных вспышки красным
- * при переключении рабочего режима лампы WiFi точка доступа/WiFi клиент семикратным кликом по кнопке (перед перезагрузкой) - 3 стандартных вспышки красным
- Уменьшен таймаут подключения к WiFi сети до 6 секунд; вызвано увеличившейся продолжительностью работы функции setup(), она в сумме должна быть меньше 8 секунд
- Оптимизирован код
*/ */
// Ссылка для менеджера плат: // Ссылка для менеджера плат:
@@ -126,7 +139,7 @@ GButton touch(BTN_PIN, LOW_PULL, NORM_OPEN);
#endif #endif
#ifdef OTA #ifdef OTA
OtaManager otaManager; OtaManager otaManager(&showWarning);
OtaPhase OtaManager::OtaFlag = OtaPhase::None; OtaPhase OtaManager::OtaFlag = OtaPhase::None;
#endif #endif
@@ -159,7 +172,7 @@ AlarmType alarms[7];
static const uint8_t dawnOffsets[] PROGMEM = {5, 10, 15, 20, 25, 30, 40, 50, 60}; // опции для выпадающего списка параметра "время перед 'рассветом'" (будильник); синхронизировано с android приложением static const uint8_t dawnOffsets[] PROGMEM = {5, 10, 15, 20, 25, 30, 40, 50, 60}; // опции для выпадающего списка параметра "время перед 'рассветом'" (будильник); синхронизировано с android приложением
uint8_t dawnMode; uint8_t dawnMode;
bool dawnFlag = false; bool dawnFlag = false;
long thisTime; uint32_t thisTime;
bool manualOff = false; bool manualOff = false;
int8_t currentMode = 0; int8_t currentMode = 0;
@@ -212,10 +225,7 @@ void setup()
if (digitalRead(BTN_PIN)) if (digitalRead(BTN_PIN))
{ {
wifiManager.resetSettings(); // сброс сохранённых SSID и пароля при старте с зажатой кнопкой, если разрешено wifiManager.resetSettings(); // сброс сохранённых SSID и пароля при старте с зажатой кнопкой, если разрешено
#ifdef GENERAL_DEBUG
LOG.println(F("Настройки WiFiManager сброшены")); LOG.println(F("Настройки WiFiManager сброшены"));
#endif
} }
#endif #endif
#endif #endif
@@ -224,25 +234,41 @@ void setup()
// ЛЕНТА/МАТРИЦА // ЛЕНТА/МАТРИЦА
FastLED.addLeds<WS2812B, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS)/*.setCorrection(TypicalLEDStrip)*/; FastLED.addLeds<WS2812B, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS)/*.setCorrection(TypicalLEDStrip)*/;
FastLED.setBrightness(BRIGHTNESS); FastLED.setBrightness(BRIGHTNESS);
if (CURRENT_LIMIT > 0) FastLED.setMaxPowerInVoltsAndMilliamps(5, CURRENT_LIMIT); if (CURRENT_LIMIT > 0)
{
FastLED.setMaxPowerInVoltsAndMilliamps(5, CURRENT_LIMIT);
}
FastLED.clear(); FastLED.clear();
FastLED.show(); FastLED.show();
// EEPROM
EepromManager::InitEepromSettings( // инициализация EEPROM; запись начального состояния настроек, если их там ещё нет; инициализация настроек лампы значениями из EEPROM
modes, alarms, &espMode, &ONflag, &dawnMode, &currentMode,
&(FavoritesManager::ReadFavoritesFromEeprom),
&(FavoritesManager::SaveFavoritesToEeprom));
LOG.printf_P(PSTR("Рабочий режим лампы: ESP_MODE = %d\n"), espMode);
// WI-FI // WI-FI
wifiManager.setDebugOutput(WIFIMAN_DEBUG); // вывод отладочных сообщений wifiManager.setDebugOutput(WIFIMAN_DEBUG); // вывод отладочных сообщений
//wifiManager.setMinimumSignalQuality(); // установка минимально приемлемого уровня сигнала WiFi сетей (8% по умолчанию) // wifiManager.setMinimumSignalQuality(); // установка минимально приемлемого уровня сигнала WiFi сетей (8% по умолчанию)
if (ESP_MODE == 0) // режим WiFi точки доступа if (espMode == 0U) // режим WiFi точки доступа
{ {
// wifiManager.setConfigPortalBlocking(false); // wifiManager.setConfigPortalBlocking(false);
WiFi.softAPConfig( // wifiManager.startConfigPortal использовать нельзя, т.к. он блокирует вычислительный процесс внутри себя, а затем перезагружает ESP, т.е. предназначен только для ввода SSID и пароля
if (sizeof(AP_STATIC_IP))
{
LOG.println(F("Используется статический IP адрес WiFi точки доступа"));
wifiManager.setAPStaticIPConfig( // wifiManager.startConfigPortal использовать нельзя, т.к. он блокирует вычислительный процесс внутри себя, а затем перезагружает ESP, т.е. предназначен только для ввода SSID и пароля
IPAddress(AP_STATIC_IP[0], AP_STATIC_IP[1], AP_STATIC_IP[2], AP_STATIC_IP[3]), // IP адрес WiFi точки доступа IPAddress(AP_STATIC_IP[0], AP_STATIC_IP[1], AP_STATIC_IP[2], AP_STATIC_IP[3]), // IP адрес WiFi точки доступа
IPAddress(AP_STATIC_IP[0], AP_STATIC_IP[1], AP_STATIC_IP[2], 1), // первый доступный IP адрес сети IPAddress(AP_STATIC_IP[0], AP_STATIC_IP[1], AP_STATIC_IP[2], 1), // первый доступный IP адрес сети
IPAddress(255, 255, 255, 0)); // маска подсети IPAddress(255, 255, 255, 0)); // маска подсети
}
WiFi.softAP(AP_NAME, AP_PASS); WiFi.softAP(AP_NAME, AP_PASS);
LOG.println(F("Режим WiFi точки доступа")); LOG.println(F("Старт в режиме WiFi точки доступа"));
LOG.print(F("IP адрес: ")); LOG.print(F("IP адрес: "));
LOG.println(WiFi.softAPIP()); LOG.println(WiFi.softAPIP());
@@ -250,19 +276,22 @@ void setup()
} }
else // режим WiFi клиента (подключаемся к роутеру, если есть сохранённые SSID и пароль, иначе создаём WiFi точку доступа и запрашиваем их) else // режим WiFi клиента (подключаемся к роутеру, если есть сохранённые SSID и пароль, иначе создаём WiFi точку доступа и запрашиваем их)
{ {
LOG.println(F("Режим WiFi клиента")); LOG.println(F("Старт в режиме WiFi клиента (подключение к роутеру)"));
if (WiFi.SSID())
if (WiFi.SSID().length())
{ {
LOG.print(F("Подключение WiFi сети: ")); LOG.printf_P(PSTR("Подключение к WiFi сети: %s\n"), WiFi.SSID().c_str());
LOG.println(WiFi.SSID());
} }
else else
{ {
LOG.println(F("WiFi сеть не определена, запуск WiFi точки доступа для настройки параметров подключения к WiFi сети...")); LOG.println(F("WiFi сеть не определена, запуск WiFi точки доступа для настройки параметров подключения к WiFi сети..."));
showWarning(CRGB::Yellow, 250U, 250U); // мигание жёлтым цветом 0,25 секунды (1 раз) - нужно ввести параметры WiFi сети для подключения
} }
if (STA_STATIC_IP) if (sizeof(STA_STATIC_IP))
{ {
LOG.print(F("Сконфигурирован статический IP адрес: "));
LOG.printf_P(PSTR("%u.%u.%u.%u\n"), STA_STATIC_IP[0], STA_STATIC_IP[1], STA_STATIC_IP[2], STA_STATIC_IP[3]);
wifiManager.setSTAStaticIPConfig( wifiManager.setSTAStaticIPConfig(
IPAddress(STA_STATIC_IP[0], STA_STATIC_IP[1], STA_STATIC_IP[2], STA_STATIC_IP[3]), // статический IP адрес ESP в режиме WiFi клиента IPAddress(STA_STATIC_IP[0], STA_STATIC_IP[1], STA_STATIC_IP[2], STA_STATIC_IP[3]), // статический IP адрес ESP в режиме WiFi клиента
IPAddress(STA_STATIC_IP[0], STA_STATIC_IP[1], STA_STATIC_IP[2], 1), // первый доступный IP адрес сети (справедливо для 99,99% случаев; для сетей меньше чем на 255 адресов нужно вынести в константы) IPAddress(STA_STATIC_IP[0], STA_STATIC_IP[1], STA_STATIC_IP[2], 1), // первый доступный IP адрес сети (справедливо для 99,99% случаев; для сетей меньше чем на 255 адресов нужно вынести в константы)
@@ -276,12 +305,8 @@ void setup()
if (WiFi.status() != WL_CONNECTED) if (WiFi.status() != WL_CONNECTED)
{ {
LOG.println(F("Время ожидания ввода SSID и пароля от WiFi сети или подключения к WiFi сети превышено\nПерезагрузка модуля")); LOG.println(F("Время ожидания ввода SSID и пароля от WiFi сети или подключения к WiFi сети превышено\nПерезагрузка модуля"));
showWarning(CRGB::Red, 250U, 250U); // мигание красным цветом 0,25 секунды (1 раз) - ожидание ввода SSID'а и пароля WiFi сети прекращено, перезагрузка
#if defined(ESP8266)
ESP.reset();
#else
ESP.restart(); ESP.restart();
#endif
} }
LOG.print(F("IP адрес: ")); LOG.print(F("IP адрес: "));
@@ -292,13 +317,6 @@ void setup()
Udp.begin(localPort); Udp.begin(localPort);
// EEPROM
EepromManager::InitEepromSettings( // инициализация EEPROM; запись начального состояния настроек, если их там ещё нет; инициализация настроек лампы значениями из EEPROM
modes, alarms, &ONflag, &dawnMode, &currentMode,
&(FavoritesManager::ReadFavoritesFromEeprom),
&(FavoritesManager::SaveFavoritesToEeprom));
// NTP // NTP
#ifdef USE_NTP #ifdef USE_NTP
timeClient.begin(); timeClient.begin();
@@ -306,9 +324,12 @@ void setup()
// MQTT // MQTT
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
mqttClient = new AsyncMqttClient(); mqttClient = new AsyncMqttClient();
MqttManager::setupMqtt(mqttClient, inputBuffer, &sendCurrent); // создание экземпляров объектов для работы с MQTT, их инициализация и подключение к MQTT брокеру MqttManager::setupMqtt(mqttClient, inputBuffer, &sendCurrent); // создание экземпляров объектов для работы с MQTT, их инициализация и подключение к MQTT брокеру
}
#endif #endif
@@ -358,7 +379,7 @@ void loop()
} }
#if USE_MQTT #if USE_MQTT
if (ESP_MODE == 1 && mqttClient && WiFi.isConnected() && !mqttClient->connected()) if (espMode == 1U && mqttClient && WiFi.isConnected() && !mqttClient->connected())
{ {
MqttManager::mqttConnect(); // библиотека не умеет восстанавливать соединение в случае потери подключения к MQTT брокеру, нужно управлять этим явно MqttManager::mqttConnect(); // библиотека не умеет восстанавливать соединение в случае потери подключения к MQTT брокеру, нужно управлять этим явно
MqttManager::needToPublish = true; MqttManager::needToPublish = true;

View File

@@ -33,9 +33,14 @@ class OtaManager
public: public:
static OtaPhase OtaFlag; static OtaPhase OtaFlag;
OtaManager(ShowWarningDelegate showWarningDelegate)
{
this->showWarningDelegate = showWarningDelegate;
}
bool RequestOtaUpdate() // пользователь однократно запросил обновление по воздуху; возвращает true, когда переходит в режим обновления - startOtaUpdate() bool RequestOtaUpdate() // пользователь однократно запросил обновление по воздуху; возвращает true, когда переходит в режим обновления - startOtaUpdate()
{ {
if (ESP_MODE != 1) if (espMode != 1U)
{ {
#ifdef GENERAL_DEBUG #ifdef GENERAL_DEBUG
LOG.print(F("Запрос обновления по воздуху поддерживается только в режиме ESP_MODE = 1\n")); LOG.print(F("Запрос обновления по воздуху поддерживается только в режиме ESP_MODE = 1\n"));
@@ -59,11 +64,13 @@ class OtaManager
if (OtaFlag == OtaPhase::GotFirstConfirm) if (OtaFlag == OtaPhase::GotFirstConfirm)
{ {
OtaFlag = OtaPhase::GotSecondConfirm; OtaFlag = OtaPhase::GotSecondConfirm;
momentOfOtaStart = millis();
#ifdef GENERAL_DEBUG #ifdef GENERAL_DEBUG
LOG.print(F("Получено второе подтверждение обновления по воздуху\nСтарт режима обновления\n")); LOG.print(F("Получено второе подтверждение обновления по воздуху\nСтарт режима обновления\n"));
#endif #endif
showWarningDelegate(CRGB::Yellow, 2000U, 500U); // мигание жёлтым цветом 2 секунды (2 раза) - готовность к прошивке
startOtaUpdate(); startOtaUpdate();
return true; return true;
} }
@@ -86,7 +93,7 @@ class OtaManager
return; return;
} }
if (OtaFlag == OtaPhase::GotSecondConfirm && if ((OtaFlag == OtaPhase::GotSecondConfirm || OtaFlag == OtaPhase::InProgress) &&
millis() - momentOfOtaStart >= ESP_CONF_TIMEOUT * 1000) millis() - momentOfOtaStart >= ESP_CONF_TIMEOUT * 1000)
{ {
OtaFlag = OtaPhase::None; OtaFlag = OtaPhase::None;
@@ -97,12 +104,9 @@ class OtaManager
delay(500); delay(500);
#endif #endif
#if defined(ESP8266) showWarningDelegate(CRGB::Red, 2000U, 500U); // мигание красным цветом 2 секунды (2 раза) - ожидание прошивки по воздуху прекращено, перезагрузка
ESP.reset();
#else
ESP.restart();
#endif
ESP.restart();
return; return;
} }
@@ -115,37 +119,41 @@ class OtaManager
private: private:
uint64_t momentOfFirstConfirmation = 0; // момент времени, когда получено первое подтверждение и с которого начинается отсчёт ожидания второго подтверждения uint64_t momentOfFirstConfirmation = 0; // момент времени, когда получено первое подтверждение и с которого начинается отсчёт ожидания второго подтверждения
uint64_t momentOfOtaStart = 0; // момент времени, когда развёрнута WiFi точка доступа для обновления по воздуху uint64_t momentOfOtaStart = 0; // момент времени, когда развёрнута WiFi точка доступа для обновления по воздуху
ShowWarningDelegate showWarningDelegate;
void startOtaUpdate() void startOtaUpdate()
{ {
char espHostName[65]; char espHostName[65];
sprintf(espHostName, "%s-%u", AP_NAME, ESP.getChipId()); sprintf_P(espHostName, PSTR("%s-%u"), AP_NAME, ESP.getChipId());
ArduinoOTA.setPort(ESP_OTA_PORT); ArduinoOTA.setPort(ESP_OTA_PORT);
ArduinoOTA.setHostname(espHostName); ArduinoOTA.setHostname(espHostName);
ArduinoOTA.setPassword(AP_PASS); ArduinoOTA.setPassword(AP_PASS);
ArduinoOTA.onStart([this]() ArduinoOTA.onStart([this]()
{ {
String type; OtaFlag = OtaPhase::InProgress;
char type[16];
if (ArduinoOTA.getCommand() == U_FLASH) if (ArduinoOTA.getCommand() == U_FLASH)
{ {
type = "sketch"; strcpy_P(type, PSTR("sketch"));
} }
else // U_SPIFFS else // U_SPIFFS
{ {
type = "filesystem"; strcpy_P(type, PSTR("filesystem"));
} }
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
#ifdef GENERAL_DEBUG #ifdef GENERAL_DEBUG
LOG.printf_P(PSTR("Start updating %s\n"), type.c_str()); LOG.printf_P(PSTR("Start updating %s\n"), type);
#endif #endif
}); });
ArduinoOTA.onEnd([this]() ArduinoOTA.onEnd([this]()
{ {
OtaFlag = OtaPhase::Done; OtaFlag = OtaPhase::Done;
momentOfFirstConfirmation = 0;
momentOfOtaStart = 0;
#ifdef GENERAL_DEBUG #ifdef GENERAL_DEBUG
LOG.print(F("Обновление по воздуху выполнено\nПерезапуск")); LOG.print(F("Обновление по воздуху выполнено\nПерезапуск"));
@@ -163,6 +171,8 @@ class OtaManager
ArduinoOTA.onError([this](ota_error_t error) ArduinoOTA.onError([this](ota_error_t error)
{ {
OtaFlag = OtaPhase::None; OtaFlag = OtaPhase::None;
momentOfFirstConfirmation = 0;
momentOfOtaStart = 0;
#ifdef GENERAL_DEBUG #ifdef GENERAL_DEBUG
LOG.printf_P(PSTR("Обновление по воздуху завершилось ошибкой [%u]: "), error); LOG.printf_P(PSTR("Обновление по воздуху завершилось ошибкой [%u]: "), error);
@@ -207,8 +217,6 @@ class OtaManager
ArduinoOTA.setRebootOnSuccess(true); ArduinoOTA.setRebootOnSuccess(true);
ArduinoOTA.begin(); ArduinoOTA.begin();
OtaFlag = OtaPhase::InProgress; OtaFlag = OtaPhase::InProgress;
momentOfFirstConfirmation = 0;
momentOfOtaStart = 0;
#ifdef GENERAL_DEBUG #ifdef GENERAL_DEBUG
LOG.printf_P(PSTR("Для обновления в Arduino IDE выберите пункт меню Инструменты - Порт - '%s at "), espHostName); LOG.printf_P(PSTR("Для обновления в Arduino IDE выберите пункт меню Инструменты - Порт - '%s at "), espHostName);

View File

@@ -4,14 +4,15 @@
struct AlarmType struct AlarmType
{ {
bool State = false; bool State = false;
uint16_t Time = 0; uint16_t Time = 0U;
}; };
struct ModeType struct ModeType
{ {
uint8_t Brightness = 50; uint8_t Brightness = 50U;
uint8_t Speed = 30; uint8_t Speed = 30U;
uint8_t Scale = 40; uint8_t Scale = 40U;
}; };
typedef void (*SendCurrentDelegate)(char *outputBuffer); typedef void (*SendCurrentDelegate)(char *outputBuffer);
typedef void (*ShowWarningDelegate)(CRGB color, uint32_t duration, uint16_t blinkHalfPeriod);

View File

@@ -6,9 +6,9 @@ static bool startButtonHolding = false; // флаг: кно
void buttonTick() void buttonTick()
{ {
touch.tick(); touch.tick();
uint8_t clickCount = touch.hasClicks() ? touch.getClicks() : 0; uint8_t clickCount = touch.hasClicks() ? touch.getClicks() : 0U;
if (clickCount == 1) if (clickCount == 1U)
{ {
if (dawnFlag) if (dawnFlag)
{ {
@@ -26,14 +26,17 @@ void buttonTick()
eepromTimeout = millis(); eepromTimeout = millis();
loadingFlag = true; loadingFlag = true;
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }
if (ONflag && clickCount == 2) if (ONflag && clickCount == 2U)
{ {
if (++currentMode >= MODE_AMOUNT) currentMode = 0; if (++currentMode >= (int8_t)MODE_AMOUNT) currentMode = 0;
FastLED.setBrightness(modes[currentMode].Brightness); FastLED.setBrightness(modes[currentMode].Brightness);
loadingFlag = true; loadingFlag = true;
settChanged = true; settChanged = true;
@@ -41,12 +44,15 @@ void buttonTick()
FastLED.clear(); FastLED.clear();
delay(1); delay(1);
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }
if (ONflag && clickCount == 3) if (ONflag && clickCount == 3U)
{ {
if (--currentMode < 0) currentMode = MODE_AMOUNT - 1; if (--currentMode < 0) currentMode = MODE_AMOUNT - 1;
FastLED.setBrightness(modes[currentMode].Brightness); FastLED.setBrightness(modes[currentMode].Brightness);
@@ -56,26 +62,31 @@ void buttonTick()
FastLED.clear(); FastLED.clear();
delay(1); delay(1);
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }
if (clickCount == 4) if (clickCount == 4U)
{ {
#ifdef OTA #ifdef OTA
if (otaManager.RequestOtaUpdate()) if (otaManager.RequestOtaUpdate())
{ {
ONflag = true;
currentMode = EFF_MATRIX; // принудительное включение режима "Матрица" для индикации перехода в режим обновления по воздуху currentMode = EFF_MATRIX; // принудительное включение режима "Матрица" для индикации перехода в режим обновления по воздуху
FastLED.clear(); FastLED.clear();
delay(1); delay(1);
changePower();
} }
#endif #endif
} }
if (ONflag && clickCount == 5) // вывод IP на лампу if (ONflag && clickCount == 5U) // вывод IP на лампу
{ {
if (ESP_MODE == 1U) if (espMode == 1U)
{ {
loadingFlag = true; loadingFlag = true;
while(!fillString(WiFi.localIP().toString().c_str())) delay(1); while(!fillString(WiFi.localIP().toString().c_str())) delay(1);
@@ -83,6 +94,22 @@ void buttonTick()
} }
} }
if (ONflag && clickCount == 7U) // смена рабочего режима лампы: с WiFi точки доступа на WiFi клиент или наоборот
{
espMode = (espMode == 0U) ? 1U : 0U;
EepromManager::SaveEspMode(&espMode);
#ifdef GENERAL_DEBUG
LOG.printf_P(PSTR("Рабочий режим лампы изменён и сохранён в энергонезависимую память\nНовый рабочий режим: ESP_MODE = %d, %s\nРестарт...\n"),
espMode, espMode == 0U ? F("WiFi точка доступа") : F("WiFi клиент (подключение к роутеру)"));
delay(1000);
#endif
showWarning(CRGB::Red, 3000U, 500U); // мигание красным цветом 3 секунды - смена рабочего режима лампы, перезагрузка
ESP.restart();
}
if (ONflag && touch.isHolded()) if (ONflag && touch.isHolded())
{ {
brightDirection = !brightDirection; brightDirection = !brightDirection;
@@ -91,9 +118,9 @@ void buttonTick()
if (ONflag && touch.isStep()) if (ONflag && touch.isStep())
{ {
uint8_t delta = modes[currentMode].Brightness < 10 // определение шага изменения яркости: при яркости [1..10] шаг = 1, при [11..16] шаг = 3, при [17..255] шаг = 15 uint8_t delta = modes[currentMode].Brightness < 10U // определение шага изменения яркости: при яркости [1..10] шаг = 1, при [11..16] шаг = 3, при [17..255] шаг = 15
? 1 ? 1U
: 5; : 5U;
modes[currentMode].Brightness = modes[currentMode].Brightness =
constrain(brightDirection constrain(brightDirection
? modes[currentMode].Brightness + delta ? modes[currentMode].Brightness + delta
@@ -108,8 +135,8 @@ void buttonTick()
#endif #endif
} }
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (ONflag && !touch.isHold() && startButtonHolding) // кнопка отпущена после удерживания, нужно отправить MQTT сообщение об изменении яркости лампы if (espMode == 1U && ONflag && !touch.isHold() && startButtonHolding) // кнопка отпущена после удерживания, нужно отправить MQTT сообщение об изменении яркости лампы
{ {
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
startButtonHolding = false; startButtonHolding = false;

View File

@@ -46,7 +46,7 @@ void changePower()
if (ONflag) if (ONflag)
{ {
effectsTick(); effectsTick();
for (uint8_t i = 0; i < modes[currentMode].Brightness; i = constrain(i + 8, 0, modes[currentMode].Brightness)) for (uint8_t i = 0U; i < modes[currentMode].Brightness; i = constrain(i + 8, 0, modes[currentMode].Brightness))
{ {
FastLED.setBrightness(i); FastLED.setBrightness(i);
delay(1); delay(1);
@@ -74,12 +74,15 @@ void changePower()
TimerManager::TimerHasFired = false; TimerManager::TimerHasFired = false;
TimerManager::TimeToFire = 0ULL; TimerManager::TimeToFire = 0ULL;
if (FavoritesManager::UseSavedFavoritesRunning == 0) // если выбрана опция Сохранять состояние (вкл/выкл) "избранного", то ни выключение модуля, ни выключение матрицы не сбрасывают текущее состояние (вкл/выкл) "избранного" if (FavoritesManager::UseSavedFavoritesRunning == 0U) // если выбрана опция Сохранять состояние (вкл/выкл) "избранного", то ни выключение модуля, ни выключение матрицы не сбрасывают текущее состояние (вкл/выкл) "избранного"
{ {
FavoritesManager::TurnFavoritesOff(); FavoritesManager::TurnFavoritesOff();
} }
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }

View File

@@ -6,11 +6,11 @@ void sparklesRoutine()
{ {
for (uint8_t i = 0; i < modes[EFF_SPARKLES].Scale; i++) for (uint8_t i = 0; i < modes[EFF_SPARKLES].Scale; i++)
{ {
uint8_t x = random(0, WIDTH); uint8_t x = random(0U, WIDTH);
uint8_t y = random(0, HEIGHT); uint8_t y = random(0U, HEIGHT);
if (getPixColorXY(x, y) == 0) if (getPixColorXY(x, y) == 0U)
{ {
leds[getPixelNumber(x, y)] = CHSV(random(0, 255), 255, 255); leds[getPixelNumber(x, y)] = CHSV(random(0U, 255U), 255U, 255U);
} }
} }
fader(FADE_OUT_SPEED); fader(FADE_OUT_SPEED);
@@ -19,9 +19,9 @@ void sparklesRoutine()
// функция плавного угасания цвета для всех пикселей // функция плавного угасания цвета для всех пикселей
void fader(uint8_t step) void fader(uint8_t step)
{ {
for (uint8_t i = 0; i < WIDTH; i++) for (uint8_t i = 0U; i < WIDTH; i++)
{ {
for (uint8_t j = 0; j < HEIGHT; j++) for (uint8_t j = 0U; j < HEIGHT; j++)
{ {
fadePixel(i, j, step); fadePixel(i, j, step);
} }
@@ -31,24 +31,24 @@ void fader(uint8_t step)
void fadePixel(uint8_t i, uint8_t j, uint8_t step) // новый фейдер void fadePixel(uint8_t i, uint8_t j, uint8_t step) // новый фейдер
{ {
int32_t pixelNum = getPixelNumber(i, j); int32_t pixelNum = getPixelNumber(i, j);
if (getPixColor(pixelNum) == 0) return; if (getPixColor(pixelNum) == 0U) return;
if (leds[pixelNum].r >= 30 || if (leds[pixelNum].r >= 30U ||
leds[pixelNum].g >= 30 || leds[pixelNum].g >= 30U ||
leds[pixelNum].b >= 30) leds[pixelNum].b >= 30U)
{ {
leds[pixelNum].fadeToBlackBy(step); leds[pixelNum].fadeToBlackBy(step);
} }
else else
{ {
leds[pixelNum] = 0; leds[pixelNum] = 0U;
} }
} }
// ------------- огонь ----------------- // ------------- огонь -----------------
#define SPARKLES (1U) // вылетающие угольки вкл выкл #define SPARKLES (1U) // вылетающие угольки вкл выкл
uint8_t line[WIDTH]; uint8_t line[WIDTH];
uint8_t pcnt = 0; uint8_t pcnt = 0U;
//these values are substracetd from the generated values to give a shape to the animation //these values are substracetd from the generated values to give a shape to the animation
static const uint8_t valueMask[8][16] PROGMEM = static const uint8_t valueMask[8][16] PROGMEM =
@@ -99,7 +99,7 @@ void fireRoutine()
// Randomly generate the next line (matrix row) // Randomly generate the next line (matrix row)
void generateLine() void generateLine()
{ {
for (uint8_t x = 0; x < WIDTH; x++) for (uint8_t x = 0U; x < WIDTH; x++)
{ {
line[x] = random(64, 255); line[x] = random(64, 255);
} }
@@ -107,22 +107,22 @@ void generateLine()
void shiftUp() void shiftUp()
{ {
for (uint8_t y = HEIGHT - 1; y > 0; y--) for (uint8_t y = HEIGHT - 1U; y > 0U; y--)
{ {
for (uint8_t x = 0; x < WIDTH; x++) for (uint8_t x = 0U; x < WIDTH; x++)
{ {
uint8_t newX = x; uint8_t newX = x;
if (x > 15) newX = x % 16; if (x > 15U) newX = x % 16U;
if (y > 7) continue; if (y > 7U) continue;
matrixValue[y][newX] = matrixValue[y - 1][newX]; matrixValue[y][newX] = matrixValue[y - 1U][newX];
} }
} }
for (uint8_t x = 0; x < WIDTH; x++) for (uint8_t x = 0U; x < WIDTH; x++)
{ {
uint8_t newX = x; uint8_t newX = x;
if (x > 15) newX = x % 16; if (x > 15U) newX = x % 16U;
matrixValue[0][newX] = line[newX]; matrixValue[0U][newX] = line[newX];
} }
} }
@@ -134,13 +134,13 @@ void drawFrame(uint8_t pcnt)
int32_t nextv; int32_t nextv;
//each row interpolates with the one before it //each row interpolates with the one before it
for (uint8_t y = HEIGHT - 1; y > 0; y--) for (uint8_t y = HEIGHT - 1U; y > 0U; y--)
{ {
for (uint8_t x = 0; x < WIDTH; x++) for (uint8_t x = 0U; x < WIDTH; x++)
{ {
uint8_t newX = x; uint8_t newX = x;
if (x > 15) newX = x % 16; if (x > 15U) newX = x % 16U;
if (y < 8) if (y < 8U)
{ {
nextv = nextv =
(((100.0 - pcnt) * matrixValue[y][newX] (((100.0 - pcnt) * matrixValue[y][newX]
@@ -149,32 +149,32 @@ void drawFrame(uint8_t pcnt)
CRGB color = CHSV( CRGB color = CHSV(
modes[EFF_FIRE].Scale * 2.5 + pgm_read_byte(&hueMask[y][newX]), // H modes[EFF_FIRE].Scale * 2.5 + pgm_read_byte(&hueMask[y][newX]), // H
255, // S 255U, // S
(uint8_t)max(0, nextv) // V (uint8_t)max(0, nextv) // V
); );
leds[getPixelNumber(x, y)] = color; leds[getPixelNumber(x, y)] = color;
} }
else if (y == 8 && SPARKLES) else if (y == 8U && SPARKLES)
{ {
if (random(0, 20) == 0 && getPixColorXY(x, y - 1) != 0) drawPixelXY(x, y, getPixColorXY(x, y - 1)); if (random(0, 20) == 0 && getPixColorXY(x, y - 1U) != 0U) drawPixelXY(x, y, getPixColorXY(x, y - 1U));
else drawPixelXY(x, y, 0); else drawPixelXY(x, y, 0U);
} }
else if (SPARKLES) else if (SPARKLES)
{ {
// старая версия для яркости // старая версия для яркости
if (getPixColorXY(x, y - 1) > 0) if (getPixColorXY(x, y - 1U) > 0U)
drawPixelXY(x, y, getPixColorXY(x, y - 1)); drawPixelXY(x, y, getPixColorXY(x, y - 1U));
else drawPixelXY(x, y, 0); else drawPixelXY(x, y, 0U);
} }
} }
} }
//first row interpolates with the "next" line //first row interpolates with the "next" line
for (uint8_t x = 0; x < WIDTH; x++) for (uint8_t x = 0U; x < WIDTH; x++)
{ {
uint8_t newX = x; uint8_t newX = x;
if (x > 15) newX = x % 16; if (x > 15U) newX = x % 16U;
CRGB color = CHSV( CRGB color = CHSV(
modes[EFF_FIRE].Scale * 2.5 + pgm_read_byte(&(hueMask[0][newX])), // H modes[EFF_FIRE].Scale * 2.5 + pgm_read_byte(&(hueMask[0][newX])), // H
255, // S 255, // S
@@ -193,7 +193,7 @@ void rainbowVerticalRoutine()
for (uint8_t j = 0; j < HEIGHT; j++) for (uint8_t j = 0; j < HEIGHT; j++)
{ {
CHSV thisColor = CHSV((uint8_t)(hue + j * modes[EFF_RAINBOW_VER].Scale), 255, 255); CHSV thisColor = CHSV((uint8_t)(hue + j * modes[EFF_RAINBOW_VER].Scale), 255, 255);
for (uint8_t i = 0; i < WIDTH; i++) for (uint8_t i = 0U; i < WIDTH; i++)
{ {
drawPixelXY(i, j, thisColor); drawPixelXY(i, j, thisColor);
} }
@@ -204,10 +204,10 @@ void rainbowVerticalRoutine()
void rainbowHorizontalRoutine() void rainbowHorizontalRoutine()
{ {
hue += 4; hue += 4;
for (uint8_t i = 0; i < WIDTH; i++) for (uint8_t i = 0U; i < WIDTH; i++)
{ {
CHSV thisColor = CHSV((uint8_t)(hue + i * modes[EFF_RAINBOW_HOR].Scale), 255, 255); CHSV thisColor = CHSV((uint8_t)(hue + i * modes[EFF_RAINBOW_HOR].Scale), 255, 255);
for (uint8_t j = 0; j < HEIGHT; j++) for (uint8_t j = 0U; j < HEIGHT; j++)
{ {
drawPixelXY(i, j, thisColor); drawPixelXY(i, j, thisColor);
} }
@@ -224,12 +224,12 @@ void rainbowDiagonalRoutine()
} }
hue += 8; hue += 8;
for (uint8_t i = 0; i < WIDTH; i++) for (uint8_t i = 0U; i < WIDTH; i++)
{ {
for (uint8_t j = 0; j < HEIGHT; j++) for (uint8_t j = 0U; j < HEIGHT; j++)
{ {
float twirlFactor = 3.0F * (modes[EFF_RAINBOW_DIAG].Scale / 100.0F); // на сколько оборотов будет закручена матрица, [0..3] float twirlFactor = 3.0F * (modes[EFF_RAINBOW_DIAG].Scale / 100.0F); // на сколько оборотов будет закручена матрица, [0..3]
CRGB thisColor = CHSV(constrain((uint8_t)(hue + (float)(WIDTH / HEIGHT * i + j * twirlFactor) * (float)(255 / maxDim)), 0, 255), 255, 255); CRGB thisColor = CHSV(constrain(hue + (float)(WIDTH / HEIGHT * i + j * twirlFactor) * (float)(255 / maxDim), 0, 255), 255, 255);
drawPixelXY(i, j, thisColor); drawPixelXY(i, j, thisColor);
} }
} }
@@ -242,9 +242,9 @@ void colorsRoutine()
{ {
hue += modes[EFF_COLORS].Scale; hue += modes[EFF_COLORS].Scale;
for (int16_t i = 0; i < NUM_LEDS; i++) for (uint16_t i = 0U; i < NUM_LEDS; i++)
{ {
leds[i] = CHSV(hue, 255, 255); leds[i] = CHSV(hue, 255U, 255U);
} }
} }
} }
@@ -257,9 +257,9 @@ void colorRoutine()
loadingFlag = false; loadingFlag = false;
FastLED.clear(); FastLED.clear();
for (int16_t i = 0; i < NUM_LEDS; i++) for (int16_t i = 0U; i < NUM_LEDS; i++)
{ {
leds[i] = CHSV(modes[EFF_COLOR].Scale * 2.5, 255, 255); leds[i] = CHSV(modes[EFF_COLOR].Scale * 2.5, 255U, 255U);
} }
} }
} }
@@ -268,22 +268,22 @@ void colorRoutine()
void snowRoutine() void snowRoutine()
{ {
// сдвигаем всё вниз // сдвигаем всё вниз
for (uint8_t x = 0; x < WIDTH; x++) for (uint8_t x = 0U; x < WIDTH; x++)
{ {
for (uint8_t y = 0; y < HEIGHT - 1; y++) for (uint8_t y = 0U; y < HEIGHT - 1; y++)
{ {
drawPixelXY(x, y, getPixColorXY(x, y + 1)); drawPixelXY(x, y, getPixColorXY(x, y + 1U));
} }
} }
for (uint8_t x = 0; x < WIDTH; x++) for (uint8_t x = 0U; x < WIDTH; x++)
{ {
// заполняем случайно верхнюю строку // заполняем случайно верхнюю строку
// а также не даём двум блокам по вертикали вместе быть // а также не даём двум блокам по вертикали вместе быть
if (getPixColorXY(x, HEIGHT - 2) == 0 && (random(0, 100 - modes[EFF_SNOW].Scale) == 0)) if (getPixColorXY(x, HEIGHT - 2U) == 0U && (random(0, 100 - modes[EFF_SNOW].Scale) == 0U))
drawPixelXY(x, HEIGHT - 1, 0xE0FFFF - 0x101010 * random(0, 4)); drawPixelXY(x, HEIGHT - 1U, 0xE0FFFF - 0x101010 * random(0, 4));
else else
drawPixelXY(x, HEIGHT - 1, 0x000000); drawPixelXY(x, HEIGHT - 1U, 0x000000);
} }
} }
@@ -300,45 +300,45 @@ void snowStormRoutine()
} }
// заполняем головами комет левую и верхнюю линию // заполняем головами комет левую и верхнюю линию
for (uint8_t i = HEIGHT / 2; i < HEIGHT; i++) for (uint8_t i = HEIGHT / 2U; i < HEIGHT; i++)
{ {
if (getPixColorXY(0, i) == 0 && if (getPixColorXY(0U, i) == 0U &&
(random(0, SNOW_DENSE) == 0) && (random(0, SNOW_DENSE) == 0) &&
getPixColorXY(0, i + 1) == 0 && getPixColorXY(0U, i + 1U) == 0U &&
getPixColorXY(0, i - 1) == 0) getPixColorXY(0U, i - 1U) == 0U)
{ {
leds[getPixelNumber(0, i)] = CHSV(random(0, 200), SNOW_SATURATION, 255); leds[getPixelNumber(0U, i)] = CHSV(random(0, 200), SNOW_SATURATION, 255U);
} }
} }
for (uint8_t i = 0; i < WIDTH / 2; i++) for (uint8_t i = 0U; i < WIDTH / 2U; i++)
{ {
if (getPixColorXY(i, HEIGHT - 1) == 0 && if (getPixColorXY(i, HEIGHT - 1U) == 0U &&
(random(0, map(modes[EFF_SNOWSTORM].Scale, 0, 255, 10, 120)) == 0) && (random(0, map(modes[EFF_SNOWSTORM].Scale, 0U, 255U, 10U, 120U)) == 0U) &&
getPixColorXY(i + 1, HEIGHT - 1) == 0 && getPixColorXY(i + 1U, HEIGHT - 1U) == 0U &&
getPixColorXY(i - 1, HEIGHT - 1) == 0) getPixColorXY(i - 1U, HEIGHT - 1U) == 0U)
{ {
leds[getPixelNumber(i, HEIGHT - 1)] = CHSV(random(0, 200), SNOW_SATURATION, 255); leds[getPixelNumber(i, HEIGHT - 1U)] = CHSV(random(0, 200), SNOW_SATURATION, 255U);
} }
} }
// сдвигаем по диагонали // сдвигаем по диагонали
for (uint8_t y = 0; y < HEIGHT - 1; y++) for (uint8_t y = 0U; y < HEIGHT - 1U; y++)
{ {
for (uint8_t x = WIDTH - 1; x > 0; x--) for (uint8_t x = WIDTH - 1U; x > 0U; x--)
{ {
drawPixelXY(x, y, getPixColorXY(x - 1, y + 1)); drawPixelXY(x, y, getPixColorXY(x - 1U, y + 1U));
} }
} }
// уменьшаем яркость левой и верхней линии, формируем "хвосты" // уменьшаем яркость левой и верхней линии, формируем "хвосты"
for (uint8_t i = HEIGHT / 2; i < HEIGHT; i++) for (uint8_t i = HEIGHT / 2U; i < HEIGHT; i++)
{ {
fadePixel(0, i, SNOW_TAIL_STEP); fadePixel(0U, i, SNOW_TAIL_STEP);
} }
for (uint8_t i = 0; i < WIDTH / 2; i++) for (uint8_t i = 0U; i < WIDTH / 2U; i++)
{ {
fadePixel(i, HEIGHT - 1, SNOW_TAIL_STEP); fadePixel(i, HEIGHT - 1U, SNOW_TAIL_STEP);
} }
} }
@@ -355,77 +355,77 @@ void starfallRoutine()
} }
// заполняем головами комет левую и верхнюю линию // заполняем головами комет левую и верхнюю линию
for (uint8_t i = HEIGHT / 2; i < HEIGHT; i++) for (uint8_t i = HEIGHT / 2U; i < HEIGHT; i++)
{ {
if (getPixColorXY(0, i) == 0 && if (getPixColorXY(0U, i) == 0U &&
(random(0, STAR_DENSE) == 0) && (random(0, STAR_DENSE) == 0) &&
getPixColorXY(0, i + 1) == 0 && getPixColorXY(0U, i + 1U) == 0U &&
getPixColorXY(0, i - 1) == 0) getPixColorXY(0U, i - 1U) == 0U)
{ {
leds[getPixelNumber(0, i)] = CHSV(random(0, 200), STAR_SATURATION, 255); leds[getPixelNumber(0U, i)] = CHSV(random(0, 200), STAR_SATURATION, 255U);
} }
} }
for (uint8_t i = 0; i < WIDTH / 2; i++) for (uint8_t i = 0U; i < WIDTH / 2U; i++)
{ {
if (getPixColorXY(i, HEIGHT - 1) == 0 && if (getPixColorXY(i, HEIGHT - 1U) == 0U &&
(random(0, map(modes[EFF_STARFALL].Scale, 0, 255, 10, 120)) == 0) && (random(0, map(modes[EFF_STARFALL].Scale, 0U, 255U, 10U, 120U)) == 0U) &&
getPixColorXY(i + 1, HEIGHT - 1) == 0 && getPixColorXY(i + 1U, HEIGHT - 1U) == 0U &&
getPixColorXY(i - 1, HEIGHT - 1) == 0) getPixColorXY(i - 1U, HEIGHT - 1U) == 0U)
{ {
leds[getPixelNumber(i, HEIGHT - 1)] = CHSV(random(0, 200), STAR_SATURATION, 255); leds[getPixelNumber(i, HEIGHT - 1U)] = CHSV(random(0, 200), STAR_SATURATION, 255U);
} }
} }
// сдвигаем по диагонали // сдвигаем по диагонали
for (uint8_t y = 0; y < HEIGHT - 1; y++) for (uint8_t y = 0U; y < HEIGHT - 1U; y++)
{ {
for (uint8_t x = WIDTH - 1; x > 0; x--) for (uint8_t x = WIDTH - 1U; x > 0U; x--)
{ {
drawPixelXY(x, y, getPixColorXY(x - 1, y + 1)); drawPixelXY(x, y, getPixColorXY(x - 1U, y + 1U));
} }
} }
// уменьшаем яркость левой и верхней линии, формируем "хвосты" // уменьшаем яркость левой и верхней линии, формируем "хвосты"
for (uint8_t i = HEIGHT / 2; i < HEIGHT; i++) for (uint8_t i = HEIGHT / 2U; i < HEIGHT; i++)
{ {
fadePixel(0, i, STAR_TAIL_STEP); fadePixel(0U, i, STAR_TAIL_STEP);
} }
for (uint8_t i = 0; i < WIDTH / 2; i++) for (uint8_t i = 0U; i < WIDTH / 2U; i++)
{ {
fadePixel(i, HEIGHT - 1, STAR_TAIL_STEP); fadePixel(i, HEIGHT - 1U, STAR_TAIL_STEP);
} }
} }
// ------------- матрица --------------- // ------------- матрица ---------------
void matrixRoutine() void matrixRoutine()
{ {
for (uint8_t x = 0; x < WIDTH; x++) for (uint8_t x = 0U; x < WIDTH; x++)
{ {
// заполняем случайно верхнюю строку // заполняем случайно верхнюю строку
uint32_t thisColor = getPixColorXY(x, HEIGHT - 1); uint32_t thisColor = getPixColorXY(x, HEIGHT - 1U);
if (thisColor == 0) if (thisColor == 0U)
drawPixelXY(x, HEIGHT - 1, 0x00FF00 * (random(0, 100 - modes[EFF_MATRIX].Scale) == 0)); drawPixelXY(x, HEIGHT - 1U, 0x00FF00 * (random(0, 100 - modes[EFF_MATRIX].Scale) == 0U));
else if (thisColor < 0x002000) else if (thisColor < 0x002000)
drawPixelXY(x, HEIGHT - 1, 0); drawPixelXY(x, HEIGHT - 1U, 0U);
else else
drawPixelXY(x, HEIGHT - 1, thisColor - 0x002000); drawPixelXY(x, HEIGHT - 1U, thisColor - 0x002000);
} }
// сдвигаем всё вниз // сдвигаем всё вниз
for (uint8_t x = 0; x < WIDTH; x++) for (uint8_t x = 0U; x < WIDTH; x++)
{ {
for (uint8_t y = 0; y < HEIGHT - 1; y++) for (uint8_t y = 0U; y < HEIGHT - 1U; y++)
{ {
drawPixelXY(x, y, getPixColorXY(x, y + 1)); drawPixelXY(x, y, getPixColorXY(x, y + 1U));
} }
} }
} }
// ------------- светлячки -------------- // ------------- светлячки --------------
#define LIGHTERS_AM (100) #define LIGHTERS_AM (100U)
int32_t lightersPos[2][LIGHTERS_AM]; int32_t lightersPos[2U][LIGHTERS_AM];
int8_t lightersSpeed[2][LIGHTERS_AM]; int8_t lightersSpeed[2U][LIGHTERS_AM];
CHSV lightersColor[LIGHTERS_AM]; CHSV lightersColor[LIGHTERS_AM];
uint8_t loopCounter; uint8_t loopCounter;
int32_t angle[LIGHTERS_AM]; int32_t angle[LIGHTERS_AM];
@@ -437,44 +437,44 @@ void lightersRoutine()
{ {
loadingFlag = false; loadingFlag = false;
randomSeed(millis()); randomSeed(millis());
for (uint8_t i = 0; i < LIGHTERS_AM; i++) for (uint8_t i = 0U; i < LIGHTERS_AM; i++)
{ {
lightersPos[0][i] = random(0, WIDTH * 10); lightersPos[0U][i] = random(0, WIDTH * 10);
lightersPos[1][i] = random(0, HEIGHT * 10); lightersPos[1U][i] = random(0, HEIGHT * 10);
lightersSpeed[0][i] = random(-10, 10); lightersSpeed[0U][i] = random(-10, 10);
lightersSpeed[1][i] = random(-10, 10); lightersSpeed[1U][i] = random(-10, 10);
lightersColor[i] = CHSV(random(0, 255), 255, 255); lightersColor[i] = CHSV(random(0U, 255U), 255U, 255U);
} }
} }
FastLED.clear(); FastLED.clear();
if (++loopCounter > 20) loopCounter = 0; if (++loopCounter > 20U) loopCounter = 0U;
for (uint8_t i = 0; i < modes[EFF_LIGHTERS].Scale; i++) for (uint8_t i = 0U; i < modes[EFF_LIGHTERS].Scale; i++)
{ {
if (loopCounter == 0) // меняем скорость каждые 255 отрисовок if (loopCounter == 0U) // меняем скорость каждые 255 отрисовок
{ {
lightersSpeed[0][i] += random(-3, 4); lightersSpeed[0U][i] += random(-3, 4);
lightersSpeed[1][i] += random(-3, 4); lightersSpeed[1U][i] += random(-3, 4);
lightersSpeed[0][i] = constrain(lightersSpeed[0][i], -20, 20); lightersSpeed[0U][i] = constrain(lightersSpeed[0U][i], -20, 20);
lightersSpeed[1][i] = constrain(lightersSpeed[1][i], -20, 20); lightersSpeed[1U][i] = constrain(lightersSpeed[1U][i], -20, 20);
} }
lightersPos[0][i] += lightersSpeed[0][i]; lightersPos[0U][i] += lightersSpeed[0U][i];
lightersPos[1][i] += lightersSpeed[1][i]; lightersPos[1U][i] += lightersSpeed[1U][i];
if (lightersPos[0][i] < 0) lightersPos[0][i] = (WIDTH - 1) * 10; if (lightersPos[0U][i] < 0) lightersPos[0U][i] = (WIDTH - 1) * 10;
if (lightersPos[0][i] >= WIDTH * 10) lightersPos[0][i] = 0; if (lightersPos[0U][i] >= (int32_t)(WIDTH * 10)) lightersPos[0U][i] = 0;
if (lightersPos[1][i] < 0) if (lightersPos[1U][i] < 0)
{ {
lightersPos[1][i] = 0; lightersPos[1U][i] = 0;
lightersSpeed[1][i] = -lightersSpeed[1][i]; lightersSpeed[1U][i] = -lightersSpeed[1U][i];
} }
if (lightersPos[1][i] >= (HEIGHT - 1) * 10) if (lightersPos[1U][i] >= (int32_t)(HEIGHT - 1) * 10)
{ {
lightersPos[1][i] = (HEIGHT - 1) * 10; lightersPos[1U][i] = (HEIGHT - 1U) * 10;
lightersSpeed[1][i] = -lightersSpeed[1][i]; lightersSpeed[1U][i] = -lightersSpeed[1U][i];
} }
drawPixelXY(lightersPos[0][i] / 10, lightersPos[1][i] / 10, lightersColor[i]); drawPixelXY(lightersPos[0U][i] / 10, lightersPos[1U][i] / 10, lightersColor[i]);
} }
} }
@@ -483,8 +483,8 @@ void lightersRoutine()
#define CLEAR_PATH (1U) // очищать путь #define CLEAR_PATH (1U) // очищать путь
#define BALL_TRACK (1U) // (0 / 1) - вкл/выкл следы шариков #define BALL_TRACK (1U) // (0 / 1) - вкл/выкл следы шариков
#define TRACK_STEP (70U) // длина хвоста шарика (чем больше цифра, тем хвост короче) #define TRACK_STEP (70U) // длина хвоста шарика (чем больше цифра, тем хвост короче)
int16_t coord[BALLS_AMOUNT][2]; int16_t coord[BALLS_AMOUNT][2U];
int8_t vector[BALLS_AMOUNT][2]; int8_t vector[BALLS_AMOUNT][2U];
CRGB ballColors[BALLS_AMOUNT]; CRGB ballColors[BALLS_AMOUNT];
void ballsRoutine() void ballsRoutine()
{ {
@@ -492,17 +492,17 @@ void ballsRoutine()
{ {
loadingFlag = false; loadingFlag = false;
for (uint8_t j = 0; j < BALLS_AMOUNT; j++) for (uint8_t j = 0U; j < BALLS_AMOUNT; j++)
{ {
int8_t sign; int8_t sign;
// забиваем случайными данными // забиваем случайными данными
coord[j][0] = WIDTH / 2 * 10; coord[j][0U] = WIDTH / 2 * 10;
random(0, 2) ? sign = 1 : sign = -1; random(0, 2) ? sign = 1 : sign = -1;
vector[j][0] = random(4, 15) * sign; vector[j][0U] = random(4, 15) * sign;
coord[j][1] = HEIGHT / 2 * 10; coord[j][1U] = HEIGHT / 2 * 10;
random(0, 2) ? sign = 1 : sign = -1; random(0, 2) ? sign = 1 : sign = -1;
vector[j][1] = random(4, 15) * sign; vector[j][1U] = random(4, 15) * sign;
ballColors[j] = CHSV(random(0, 9) * 28, 255, 255); ballColors[j] = CHSV(random(0, 9) * 28, 255U, 255U);
} }
} }
@@ -516,10 +516,10 @@ void ballsRoutine()
} }
// движение шариков // движение шариков
for (uint8_t j = 0; j < BALLS_AMOUNT; j++) for (uint8_t j = 0U; j < BALLS_AMOUNT; j++)
{ {
// движение шариков // движение шариков
for (uint8_t i = 0; i < 2; i++) for (uint8_t i = 0U; i < 2U; i++)
{ {
coord[j][i] += vector[j][i]; coord[j][i] += vector[j][i];
if (coord[j][i] < 0) if (coord[j][i] < 0)
@@ -529,22 +529,22 @@ void ballsRoutine()
} }
} }
if (coord[j][0] > (WIDTH - 1) * 10) if (coord[j][0U] > (int16_t)((WIDTH - 1) * 10))
{ {
coord[j][0] = (WIDTH - 1) * 10; coord[j][0U] = (WIDTH - 1) * 10;
vector[j][0] = -vector[j][0]; vector[j][0U] = -vector[j][0U];
} }
if (coord[j][1] > (HEIGHT - 1) * 10) if (coord[j][1U] > (int16_t)((HEIGHT - 1) * 10))
{ {
coord[j][1] = (HEIGHT - 1) * 10; coord[j][1U] = (HEIGHT - 1) * 10;
vector[j][1] = -vector[j][1]; vector[j][1U] = -vector[j][1U];
} }
leds[getPixelNumber(coord[j][0] / 10, coord[j][1] / 10)] = ballColors[j]; leds[getPixelNumber(coord[j][0U] / 10, coord[j][1U] / 10)] = ballColors[j];
} }
} }
// ------------- пейнтбол ------------- // ------------- пейнтбол -------------
const uint8_t BorderWidth = 2; const uint8_t BorderWidth = 2U;
void lightBallsRoutine() void lightBallsRoutine()
{ {
// Apply some blurring to whatever's already on the matrix // Apply some blurring to whatever's already on the matrix
@@ -562,10 +562,10 @@ void lightBallsRoutine()
// The color of each point shifts over time, each at a different speed. // The color of each point shifts over time, each at a different speed.
uint16_t ms = millis(); uint16_t ms = millis();
leds[XY( i, j)] += CHSV( ms / 29, 200, 255); leds[XY( i, j)] += CHSV( ms / 29, 200U, 255U);
leds[XY( j, k)] += CHSV( ms / 41, 200, 255); leds[XY( j, k)] += CHSV( ms / 41, 200U, 255U);
leds[XY( k, m)] += CHSV( ms / 73, 200, 255); leds[XY( k, m)] += CHSV( ms / 73, 200U, 255U);
leds[XY( m, i)] += CHSV( ms / 97, 200, 255); leds[XY( m, i)] += CHSV( ms / 97, 200U, 255U);
} }
// Trivial XY function for the SmartMatrix; use a different XY // Trivial XY function for the SmartMatrix; use a different XY
@@ -589,8 +589,8 @@ uint16_t XY(uint8_t x, uint8_t y)
// ------------- блуждающий кубик ------------- // ------------- блуждающий кубик -------------
#define RANDOM_COLOR (1U) // случайный цвет при отскоке #define RANDOM_COLOR (1U) // случайный цвет при отскоке
int16_t coordB[2]; int16_t coordB[2U];
int8_t vectorB[2]; int8_t vectorB[2U];
CRGB ballColor; CRGB ballColor;
int8_t ballSize; int8_t ballSize;
void ballRoutine() void ballRoutine()
@@ -600,49 +600,49 @@ void ballRoutine()
loadingFlag = false; loadingFlag = false;
//FastLED.clear(); //FastLED.clear();
for (uint8_t i = 0; i < 2; i++) for (uint8_t i = 0U; i < 2U; i++)
{ {
coordB[i] = WIDTH / 2 * 10; coordB[i] = WIDTH / 2 * 10;
vectorB[i] = random(8, 20); vectorB[i] = random(8, 20);
ballColor = CHSV(random(0, 9) * 28, 255, 255); ballColor = CHSV(random(0, 9) * 28, 255U, 255U);
} }
} }
ballSize = map(modes[EFF_CUBE].Scale, 0, 255, 2, max((int16_t)min(WIDTH,HEIGHT) / 3, 2)); ballSize = map(modes[EFF_CUBE].Scale, 0U, 255U, 2U, max((uint8_t)min(WIDTH,HEIGHT) / 3, 2));
for (uint8_t i = 0; i < 2; i++) for (uint8_t i = 0U; i < 2U; i++)
{ {
coordB[i] += vectorB[i]; coordB[i] += vectorB[i];
if (coordB[i] < 0) if (coordB[i] < 0)
{ {
coordB[i] = 0; coordB[i] = 0;
vectorB[i] = -vectorB[i]; vectorB[i] = -vectorB[i];
if (RANDOM_COLOR) ballColor = CHSV(random(0, 9) * 28, 255, 255); if (RANDOM_COLOR) ballColor = CHSV(random(0, 9) * 28, 255U, 255U);
//vectorB[i] += random(0, 6) - 3; //vectorB[i] += random(0, 6) - 3;
} }
} }
if (coordB[0] > (WIDTH - ballSize) * 10) if (coordB[0U] > (int16_t)((WIDTH - ballSize) * 10))
{ {
coordB[0] = (WIDTH - ballSize) * 10; coordB[0U] = (WIDTH - ballSize) * 10;
vectorB[0] = -vectorB[0]; vectorB[0U] = -vectorB[0U];
if (RANDOM_COLOR) ballColor = CHSV(random(0, 9) * 28, 255, 255); if (RANDOM_COLOR) ballColor = CHSV(random(0, 9) * 28, 255U, 255U);
//vectorB[0] += random(0, 6) - 3; //vectorB[0] += random(0, 6) - 3;
} }
if (coordB[1] > (HEIGHT - ballSize) * 10) if (coordB[1U] > (int16_t)((HEIGHT - ballSize) * 10))
{ {
coordB[1] = (HEIGHT - ballSize) * 10; coordB[1U] = (HEIGHT - ballSize) * 10;
vectorB[1] = -vectorB[1]; vectorB[1U] = -vectorB[1U];
if (RANDOM_COLOR) if (RANDOM_COLOR)
{ {
ballColor = CHSV(random(0, 9) * 28, 255, 255); ballColor = CHSV(random(0, 9) * 28, 255U, 255U);
} }
//vectorB[1] += random(0, 6) - 3; //vectorB[1] += random(0, 6) - 3;
} }
FastLED.clear(); FastLED.clear();
for (uint8_t i = 0; i < ballSize; i++) for (uint8_t i = 0U; i < ballSize; i++)
{ {
for (uint8_t j = 0; j < ballSize; j++) for (uint8_t j = 0U; j < ballSize; j++)
{ {
leds[getPixelNumber(coordB[0] / 10 + i, coordB[1] / 10 + j)] = ballColor; leds[getPixelNumber(coordB[0U] / 10 + i, coordB[1U] / 10 + j)] = ballColor;
} }
} }
} }
@@ -655,9 +655,9 @@ void whiteColorRoutine()
loadingFlag = false; loadingFlag = false;
FastLED.clear(); FastLED.clear();
for (int16_t i = 0; i < NUM_LEDS; i++) for (uint16_t i = 0U; i < NUM_LEDS; i++)
{ {
leds[i] = CHSV(0, 0, 255); leds[i] = CHSV(0U, 0U, 255U);
} }
} }
} }
@@ -676,82 +676,57 @@ void whiteColorStripeRoutine()
for (int16_t y = centerY; y >= 0; y--) for (int16_t y = centerY; y >= 0; y--)
{ {
CRGB color = CHSV( CRGB color = CHSV(
45, // определяем тон 45U, // определяем тон
map(modes[EFF_WHITE_COLOR].Speed, 0, 255, 0, 170), // определяем насыщенность map(modes[EFF_WHITE_COLOR].Speed, 0U, 255U, 0U, 170U), // определяем насыщенность
y == centerY // определяем яркость y == centerY // определяем яркость
? 255 // для центральной горизонтальной полосы (или двух) яркость всегда равна 255 ? 255U // для центральной горизонтальной полосы (или двух) яркость всегда равна 255
: (modes[EFF_WHITE_COLOR].Scale / 100.0F) > ((centerY + 1.0F) - (y + 1.0F)) / (centerY + 1.0F) ? 255 : 0); // для остальных горизонтальных полос яркость равна либо 255, либо 0 в зависимости от масштаба : (modes[EFF_WHITE_COLOR].Scale / 100.0F) > ((centerY + 1.0F) - (y + 1.0F)) / (centerY + 1.0F) ? 255U : 0U); // для остальных горизонтальных полос яркость равна либо 255, либо 0 в зависимости от масштаба
for (uint8_t x = 0; x < WIDTH; x++) for (uint8_t x = 0U; x < WIDTH; x++)
{ {
drawPixelXY(x, y, color); // при чётной высоте матрицы максимально яркими отрисуются 2 центральных горизонтальных полосы drawPixelXY(x, y, color); // при чётной высоте матрицы максимально яркими отрисуются 2 центральных горизонтальных полосы
drawPixelXY(x, max((uint8_t)(HEIGHT - 1) - (y + 1) + bottomOffset, 0), color); // при нечётной - одна, но дважды drawPixelXY(x, max((uint8_t)(HEIGHT - 1U) - (y + 1U) + bottomOffset, 0U), color); // при нечётной - одна, но дважды
} }
} }
} }
} }
/* // ------------- мигающий цвет (не эффект! используется для отображения краткосрочного предупреждения; блокирующий код!) -------------
* устарело #define WARNING_BRIGHTNESS (10U) // яркость вспышки
void lightersRoutine() void showWarning(
CRGB color, // цвет вспышки
uint32_t duration, // продолжительность отображения предупреждения (общее время)
uint16_t blinkHalfPeriod) // продолжительность одной вспышки в миллисекундах (полупериод)
{ {
if (loadingFlag) uint32_t blinkTimer = millis();
{ enum BlinkState { OFF = 0, ON = 1 } blinkState = BlinkState::OFF;
loadingFlag = false; FastLED.setBrightness(WARNING_BRIGHTNESS); // установка яркости для предупреждения
randomSeed(millis());
for (uint8_t i = 0; i < LIGHTERS_AM; i++)
{
lightersPos[0][i] = random(0, WIDTH * 10);
lightersPos[1][i] = random(0, HEIGHT * 10);
lightersColor[i] = CHSV(random(0, 255), 255, 255);
speedV[i] = random(5, 10);
angle[i] = random(0, 360);
angleSpeed[i] = random(-10, 10);
}
}
FastLED.clear(); FastLED.clear();
if (++loopCounter > 20) loopCounter = 0; delay(2);
FastLED.show();
for (uint8_t i = 0; i < modes[EFF_LIGHTER_TRACES].scale; i++) for (uint16_t i = 0U; i < NUM_LEDS; i++) // установка цвета всех диодов в WARNING_COLOR
{ {
if (loopCounter == 0) // меняем скорость каждые 255 отрисовок leds[i] = color;
{
angleSpeed[i] += random(-3, 4);
angleSpeed[i] = constrain(angleSpeed[i], -15, 15);
} }
lightersPos[0][i] += speedV[i] * cos(radians(angle[i])); uint32_t startTime = millis();
lightersPos[1][i] += speedV[i] * sin(radians(angle[i])); while (millis() - startTime <= (duration + 5)) // блокировка дальнейшего выполнения циклом на время отображения предупреждения
if (lightersPos[0][i] < 0) lightersPos[0][i] = (WIDTH - 1) * 10;
if (lightersPos[0][i] >= WIDTH * 10) lightersPos[0][i] = 0;
if (lightersPos[1][i] < 0)
{ {
lightersPos[1][i] = 0; if (millis() - blinkTimer >= blinkHalfPeriod) // переключение вспышка/темнота
angle[i] = 360 - angle[i];
}
else
{ {
angle[i] += angleSpeed[i]; blinkTimer = millis();
blinkState = (BlinkState)!blinkState;
FastLED.setBrightness(blinkState == BlinkState::OFF ? 0 : WARNING_BRIGHTNESS);
delay(1);
FastLED.show();
}
delay(50);
} }
if (lightersPos[1][i] >= (HEIGHT - 1) * 10) FastLED.clear();
{ FastLED.setBrightness(ONflag ? modes[currentMode].Brightness : 0); // установка яркости, которая была выставлена до вызова предупреждения
lightersPos[1][i] = (HEIGHT - 1) * 10; delay(1);
angle[i] = 360 - angle[i]; FastLED.show();
} loadingFlag = true; // принудительное отображение текущего эффекта (того, что был активен перед предупреждением)
else
{
angle[i] += angleSpeed[i];
}
if (angle[i] > 360) angle[i] = 360 - angle[i];
if (angle[i] < 0) angle[i] = 360 + angle[i];
drawPixelXY(lightersPos[0][i] / 10, lightersPos[1][i] / 10, lightersColor[i]);
}
} }
*/

View File

@@ -86,7 +86,7 @@ void zebraNoiseRoutine()
{ {
loadingFlag = false; loadingFlag = false;
// 'black out' all 16 palette entries... // 'black out' all 16 palette entries...
fill_solid( currentPalette, 16, CRGB::Black); fill_solid(currentPalette, 16, CRGB::Black);
// and set every fourth one to white. // and set every fourth one to white.
currentPalette[0] = CRGB::White; currentPalette[0] = CRGB::White;
currentPalette[4] = CRGB::White; currentPalette[4] = CRGB::White;

View File

@@ -21,8 +21,11 @@ void parseUDP()
char reply[MAX_UDP_BUFFER_SIZE]; char reply[MAX_UDP_BUFFER_SIZE];
processInputBuffer(inputBuffer, reply, true); processInputBuffer(inputBuffer, reply, true);
#if (USE_MQTT && ESP_MODE == 1) // отправка ответа выполнения команд по MQTT, если разрешено #if (USE_MQTT) // отправка ответа выполнения команд по MQTT, если разрешено
if (espMode == 1U)
{
strcpy(MqttManager::mqttBuffer, reply); // разрешение определяется при выполнении каждой команды отдельно, команды GET, DEB, DISCOVER и OTA, пришедшие по UDP, игнорируются (приходят раз в 2 секунды от приложения) strcpy(MqttManager::mqttBuffer, reply); // разрешение определяется при выполнении каждой команды отдельно, команды GET, DEB, DISCOVER и OTA, пришедшие по UDP, игнорируются (приходят раз в 2 секунды от приложения)
}
#endif #endif
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
@@ -62,13 +65,18 @@ void processInputBuffer(char *inputBuffer, char *outputBuffer, bool generateOutp
memcpy(buff, &inputBuffer[3], strlen(inputBuffer)); // взять подстроку, состоящую последних символов строки inputBuffer, начиная с символа 4 memcpy(buff, &inputBuffer[3], strlen(inputBuffer)); // взять подстроку, состоящую последних символов строки inputBuffer, начиная с символа 4
currentMode = (uint8_t)atoi(buff); currentMode = (uint8_t)atoi(buff);
loadingFlag = true; loadingFlag = true;
settChanged = true;
eepromTimeout = millis();
FastLED.clear(); FastLED.clear();
delay(1); delay(1);
sendCurrent(inputBuffer); sendCurrent(inputBuffer);
FastLED.setBrightness(modes[currentMode].Brightness); FastLED.setBrightness(modes[currentMode].Brightness);
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }
@@ -82,8 +90,11 @@ void processInputBuffer(char *inputBuffer, char *outputBuffer, bool generateOutp
eepromTimeout = millis(); eepromTimeout = millis();
sendCurrent(inputBuffer); sendCurrent(inputBuffer);
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }
@@ -96,8 +107,11 @@ void processInputBuffer(char *inputBuffer, char *outputBuffer, bool generateOutp
eepromTimeout = millis(); eepromTimeout = millis();
sendCurrent(inputBuffer); sendCurrent(inputBuffer);
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }
@@ -110,8 +124,11 @@ void processInputBuffer(char *inputBuffer, char *outputBuffer, bool generateOutp
eepromTimeout = millis(); eepromTimeout = millis();
sendCurrent(inputBuffer); sendCurrent(inputBuffer);
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }
@@ -124,8 +141,11 @@ void processInputBuffer(char *inputBuffer, char *outputBuffer, bool generateOutp
changePower(); changePower();
sendCurrent(inputBuffer); sendCurrent(inputBuffer);
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }
@@ -137,8 +157,11 @@ void processInputBuffer(char *inputBuffer, char *outputBuffer, bool generateOutp
changePower(); changePower();
sendCurrent(inputBuffer); sendCurrent(inputBuffer);
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }
@@ -160,15 +183,16 @@ void processInputBuffer(char *inputBuffer, char *outputBuffer, bool generateOutp
{ {
memcpy(buff, &inputBuffer[8], strlen(inputBuffer)); // взять подстроку, состоящую последних символов строки inputBuffer, начиная с символа 9 memcpy(buff, &inputBuffer[8], strlen(inputBuffer)); // взять подстроку, состоящую последних символов строки inputBuffer, начиная с символа 9
alarms[alarmNum].Time = atoi(buff); alarms[alarmNum].Time = atoi(buff);
uint8_t hour = floor(alarms[alarmNum].Time / 60);
uint8_t minute = alarms[alarmNum].Time - hour * 60;
sendAlarms(inputBuffer); sendAlarms(inputBuffer);
} }
EepromManager::SaveAlarmsSettings(&alarmNum, alarms); EepromManager::SaveAlarmsSettings(&alarmNum, alarms);
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
strcpy(MqttManager::mqttBuffer, inputBuffer); strcpy(MqttManager::mqttBuffer, inputBuffer);
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }
@@ -184,14 +208,17 @@ void processInputBuffer(char *inputBuffer, char *outputBuffer, bool generateOutp
EepromManager::SaveDawnMode(&dawnMode); EepromManager::SaveDawnMode(&dawnMode);
sendAlarms(inputBuffer); sendAlarms(inputBuffer);
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }
else if (!strncmp_P(inputBuffer, PSTR("DISCOVER"), 8)) // обнаружение приложением модуля esp в локальной сети else if (!strncmp_P(inputBuffer, PSTR("DISCOVER"), 8)) // обнаружение приложением модуля esp в локальной сети
{ {
if (ESP_MODE == 1) // работает только в режиме WiFi клиента if (espMode == 1U) // работает только в режиме WiFi клиента
{ {
sprintf_P(inputBuffer, PSTR("IP %u.%u.%u.%u:%u"), sprintf_P(inputBuffer, PSTR("IP %u.%u.%u.%u:%u"),
WiFi.localIP()[0], WiFi.localIP()[0],
@@ -221,8 +248,11 @@ void processInputBuffer(char *inputBuffer, char *outputBuffer, bool generateOutp
TimerManager::TimerHasFired = false; TimerManager::TimerHasFired = false;
sendTimer(inputBuffer); sendTimer(inputBuffer);
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }
@@ -238,8 +268,11 @@ void processInputBuffer(char *inputBuffer, char *outputBuffer, bool generateOutp
settChanged = true; settChanged = true;
eepromTimeout = millis(); eepromTimeout = millis();
#if (USE_MQTT && ESP_MODE == 1) #if (USE_MQTT)
if (espMode == 1U)
{
MqttManager::needToPublish = true; MqttManager::needToPublish = true;
}
#endif #endif
} }
@@ -282,7 +315,7 @@ void sendCurrent(char *outputBuffer)
modes[currentMode].Speed, modes[currentMode].Speed,
modes[currentMode].Scale, modes[currentMode].Scale,
ONflag, ONflag,
ESP_MODE); espMode);
#ifdef USE_NTP #ifdef USE_NTP
strcat_P(outputBuffer, PSTR(" 1")); strcat_P(outputBuffer, PSTR(" 1"));

View File

@@ -42,7 +42,7 @@ bool fillString(const char* text)
} }
else else
{ {
drawLetter(j, text[i], offset + j * (LET_WIDTH + SPACE)); drawLetter(text[i], offset + j * (LET_WIDTH + SPACE));
i++; i++;
j++; j++;
} }
@@ -60,7 +60,7 @@ bool fillString(const char* text)
return false; return false;
} }
void drawLetter(uint8_t index, uint8_t letter, int8_t offset) void drawLetter(uint8_t letter, int8_t offset)
{ {
uint8_t start_pos = 0, finish_pos = LET_WIDTH; uint8_t start_pos = 0, finish_pos = LET_WIDTH;

View File

@@ -15,11 +15,18 @@ uint64_t lastResolveTryMoment = 0UL;
bool timeSynched = false; bool timeSynched = false;
bool ntpServerAddressResolved = false; bool ntpServerAddressResolved = false;
IPAddress ntpServerIp = {0, 0, 0, 0}; IPAddress ntpServerIp = {0, 0, 0, 0};
static CHSV dawnColor = CHSV(0, 0, 0); // цвет "рассвета"
static CHSV dawnColorMinus1 = CHSV(0, 0, 0); // для большей плавности назначаем каждый новый цвет только 1/10 всех диодов; каждая следующая 1/10 часть будет "оставать" на 1 шаг
static CHSV dawnColorMinus2 = CHSV(0, 0, 0);
static CHSV dawnColorMinus3 = CHSV(0, 0, 0);
static CHSV dawnColorMinus4 = CHSV(0, 0, 0);
static CHSV dawnColorMinus5 = CHSV(0, 0, 0);
static uint8_t dawnCounter = 0; // счётчик первых 10 шагов будильника
void timeTick() void timeTick()
{ {
if (ESP_MODE == 1) if (espMode == 1U)
{ {
if (timeTimer.isReady()) if (timeTimer.isReady())
{ {
@@ -48,26 +55,41 @@ void timeTick()
return; return;
} }
byte thisDay = timeClient.getDay(); uint8_t thisDay = timeClient.getDay();
if (thisDay == 0) thisDay = 7; // воскресенье это 0 if (thisDay == 0) thisDay = 7; // воскресенье это 0
thisDay--; thisDay--;
thisTime = timeClient.getHours() * 60 + timeClient.getMinutes(); thisTime = timeClient.getHours() * 60 + timeClient.getMinutes();
uint32_t thisFullTime = timeClient.getHours() * 3600 + timeClient.getMinutes() * 60 + timeClient.getSeconds();
// проверка рассвета // проверка рассвета
if (alarms[thisDay].State && // день будильника if (alarms[thisDay].State && // день будильника
thisTime >= (alarms[thisDay].Time - pgm_read_byte(&dawnOffsets[dawnMode])) && // позже начала thisTime >= (uint16_t)constrain(alarms[thisDay].Time - pgm_read_byte(&dawnOffsets[dawnMode]), 0, (24 * 60)) && // позже начала
thisTime < (alarms[thisDay].Time + DAWN_TIMEOUT)) // раньше конца + минута thisTime < (alarms[thisDay].Time + DAWN_TIMEOUT)) // раньше конца + минута
{ {
if (!manualOff) // будильник не был выключен вручную (из приложения или кнопкой) if (!manualOff) // будильник не был выключен вручную (из приложения или кнопкой)
{ {
LOG.println("Будильник включен");
// величина рассвета 0-255 // величина рассвета 0-255
int32_t dawnPosition = 255 * ((float)(thisTime - (alarms[thisDay].Time - pgm_read_byte(&dawnOffsets[dawnMode]))) / pgm_read_byte(&dawnOffsets[dawnMode])); int32_t dawnPosition = 255 * ((float)(thisFullTime - (alarms[thisDay].Time - pgm_read_byte(&dawnOffsets[dawnMode])) * 60) / (pgm_read_byte(&dawnOffsets[dawnMode]) * 60));
dawnPosition = constrain(dawnPosition, 0, 255); dawnPosition = constrain(dawnPosition, 0, 255);
CHSV dawnColor = CHSV(map(dawnPosition, 0, 255, 10, 35), dawnColorMinus5 = dawnCounter > 4 ? dawnColorMinus4 : dawnColorMinus5;
dawnColorMinus4 = dawnCounter > 3 ? dawnColorMinus3 : dawnColorMinus4;
dawnColorMinus3 = dawnCounter > 2 ? dawnColorMinus2 : dawnColorMinus3;
dawnColorMinus2 = dawnCounter > 1 ? dawnColorMinus1 : dawnColorMinus2;
dawnColorMinus1 = dawnCounter > 0 ? dawnColor : dawnColorMinus1;
dawnColor = CHSV(map(dawnPosition, 0, 255, 10, 35),
map(dawnPosition, 0, 255, 255, 170), map(dawnPosition, 0, 255, 255, 170),
map(dawnPosition, 0, 255, 10, DAWN_BRIGHT)); map(dawnPosition, 0, 255, 10, DAWN_BRIGHT));
fill_solid(leds, NUM_LEDS, dawnColor); dawnCounter++;
// fill_solid(leds, NUM_LEDS, dawnColor);
for (uint16_t i = 0U; i < NUM_LEDS; i++)
{
if (i % 6 == 0) leds[i] = dawnColor; // 1я 1/10 диодов: цвет текущего шага
if (i % 6 == 1) leds[i] = dawnColorMinus1; // 2я 1/10 диодов: -1 шаг
if (i % 6 == 2) leds[i] = dawnColorMinus2; // 3я 1/10 диодов: -2 шага
if (i % 6 == 3) leds[i] = dawnColorMinus3; // 3я 1/10 диодов: -3 шага
if (i % 6 == 4) leds[i] = dawnColorMinus4; // 3я 1/10 диодов: -4 шага
if (i % 6 == 5) leds[i] = dawnColorMinus5; // 3я 1/10 диодов: -5 шагов
}
FastLED.setBrightness(255); FastLED.setBrightness(255);
delay(1); delay(1);
FastLED.show(); FastLED.show();
@@ -86,6 +108,12 @@ void timeTick()
changePower(); // выключение матрицы или установка яркости текущего эффекта в засисимости от того, была ли включена лампа до срабатывания будильника changePower(); // выключение матрицы или установка яркости текущего эффекта в засисимости от того, была ли включена лампа до срабатывания будильника
} }
manualOff = false; manualOff = false;
dawnColorMinus1 = CHSV(0, 0, 0);
dawnColorMinus2 = CHSV(0, 0, 0);
dawnColorMinus3 = CHSV(0, 0, 0);
dawnColorMinus4 = CHSV(0, 0, 0);
dawnColorMinus5 = CHSV(0, 0, 0);
dawnCounter = 0;
} }
} }
} }

View File

@@ -10,10 +10,10 @@ void fillAll(CRGB color)
} }
// функция отрисовки точки по координатам X Y // функция отрисовки точки по координатам X Y
void drawPixelXY(uint8_t x, uint8_t y, CRGB color) void drawPixelXY(int16_t x, int16_t y, CRGB color)
{ {
if (x < 0 || x > WIDTH - 1 || y < 0 || y > HEIGHT - 1) return; if (x < 0 || x > (int16_t)(WIDTH - 1) || y < 0 || y > (int16_t)(HEIGHT - 1)) return;
uint32_t thisPixel = getPixelNumber(x, y) * SEGMENTS; uint32_t thisPixel = getPixelNumber((uint8_t)x, (uint8_t)y) * SEGMENTS;
for (uint8_t i = 0; i < SEGMENTS; i++) for (uint8_t i = 0; i < SEGMENTS; i++)
{ {
leds[thisPixel + i] = color; leds[thisPixel + i] = color;
@@ -24,7 +24,7 @@ void drawPixelXY(uint8_t x, uint8_t y, CRGB color)
uint32_t getPixColor(uint32_t thisSegm) uint32_t getPixColor(uint32_t thisSegm)
{ {
uint32_t thisPixel = thisSegm * SEGMENTS; uint32_t thisPixel = thisSegm * SEGMENTS;
if (thisPixel < 0 || thisPixel > NUM_LEDS - 1) return 0; if (thisPixel > NUM_LEDS - 1) return 0;
return (((uint32_t)leds[thisPixel].r << 16) | ((uint32_t)leds[thisPixel].g << 8 ) | (uint32_t)leds[thisPixel].b); return (((uint32_t)leds[thisPixel].r << 16) | ((uint32_t)leds[thisPixel].g << 8 ) | (uint32_t)leds[thisPixel].b);
} }