// Определения программных констант и переменных (параметры эффектов и т.п.) // При запуске микроконтроллера выполняется инициализация всех параметров значениями, сохраненными в EEPROM (функция loadSettings() в eeprom.ino) // При этом если флаг EEPROM_OK в строке 7 этого файла был изменен и не совпадает со считанными яз ячейки #0 значением - // выполняется инициализация параметров значениями по умолчанию (функция loadSettings() в eeprom.ino, ветвь if (isInitialized) -> false ) #define EEPROM_OK 0x5D // Флаг, показывающий, что EEPROM инициализирована корректными данными // ******************* ОПРЕДЕЛЕНИЯ ПАРАМЕТРОВ подключения к сети ********************* // Внимание!!! Если вы меняете эти значения ПОСЛЕ того, как прошивка уже хотя бы раз была загружена в плату и выполнялась, // чтобы изменения вступили в силу нужно также изменить значение константы EEPROM_OK в строке 7 этого файла (см.выше) // или в Arduino IDE в меню "Инструменты" -> "Erase Flash" выбрать значение "All Flash Contents" // ------------------------ Локальная сеть --------------------- #ifndef NETWORK_SSID #define NETWORK_SSID "" // Имя WiFi сети #endif #ifndef NETWORK_PASS #define NETWORK_PASS "" // Пароль для подключения к WiFi сети #endif #ifndef DEFAULT_IP #define DEFAULT_IP {192, 168, 0, 100} // Сетевой адрес устройства по умолчанию #endif #ifndef GTW #define GTW 1 // Последняя цифра в IP адресе роутера. Обычно IP роутера 192.168.0.*1*, но некоторые роутеры имеют адрес 192.168.0.100 или 192.168.0.254 #endif // Тогда здесь вместо *1* должно быть 100 или 254 соответственно // ------------------------ Сервер времени --------------------- #define DEFAULT_NTP_SERVER "ru.pool.ntp.org" // NTP сервер по умолчанию "time.nist.gov" #define DEFAULT_AP_NAME "PanelAP" // Имя точки доступа по умолчанию #define DEFAULT_AP_PASS "12341234" // Пароль точки доступа по умолчанию // ------------------------ MQTT parameters -------------------- #if (USE_MQTT == 1) #ifndef DEFAULT_MQTT_SERVER #define DEFAULT_MQTT_SERVER "mqtt.by" // MQTT сервер #endif #ifndef DEFAULT_MQTT_USER #define DEFAULT_MQTT_USER "" // Имя mqtt-пользователя (!!! укажите имя пользователя для вашего соединения - зарегистрируйтесь на mqtt.by -> смотрите в личном кабинете !!!) #endif #ifndef DEFAULT_MQTT_PASS #define DEFAULT_MQTT_PASS "" // Пароль mqtt-пользователя (!!! укажите пароль вашего соединения - зарегистрируйтесь на mqtt.by -> смотрите в личном кабинете !!!) #endif #ifndef DEFAULT_MQTT_PORT #define DEFAULT_MQTT_PORT 1883 // Порт mqtt-соединения #endif #ifndef DEFAULT_MQTT_PREFIX #define DEFAULT_MQTT_PREFIX "af7cd12a" // Префикс топика сообщения уникальный для вашего устройства #endif #endif // --------------------------------------------------------------- #define EEPROM_MAX 4096 // Максимальный размер EEPROM доступный для использования #define EFFECT_EEPROM 400 // Начальная ячейка eeprom с параметрами эффектов, 5 байт на эффект #define TEXT_EEPROM 1000 // Начальная ячейка eeprom с текстом бегущих строк #define COLOR_ORDER GRB // Порядок цветов на ленте. Если цвет отображается некорректно - меняйте. Начать можно с RGB #ifndef BRIGHTNESS #define BRIGHTNESS 32 // Яркость матрицы по-умолчанию 0..255 #endif // ------------ Настройки региона погоды и часового пояса #ifndef TIME_ZONE #define TIME_ZONE 7 // Смещение часового пояса от UTC #endif #ifndef WEATHER_REGION_YDX #define WEATHER_REGION_YDX 62 // Код региона погоды по Yandex #endif #ifndef WEATHER_REGION_OWTH #define WEATHER_REGION_OWTH 1502026 // Код региона погоды по OpenWeatherMap #endif // Список и порядок эффектов, передаваемый в приложение на смартфоне. Данный список попадает в комбобокс выбора, // чей индекс передается из приложения в контроллер матрицы для выбора, поэтому порядок должен соответствовать // списку эффектов, определенному ниже // Часы в фоторамке - размер 17x11 - для них нет картинки анимации - эффект анимация удален из прошивки #ifdef NO_ANIMATION #if (USE_SD == 1) #define EFFECT_LIST F("Часы,Лампа,Снегопад,Кубик,Радуга,Пейнтбол,Огонь,The Matrix,Шарики,Звездопад,Конфетти," \ "Цветной шум,Облака,Лава,Плазма,Радужные переливы,Павлин,Зебра,Шумящий лес,Морской прибой,Смена цвета," \ "Светлячки,Водоворот,Циклон,Мерцание,Северное сияние,Тени,Лабиринт,Змейка,Тетрис,Арканоид," \ "Палитра,Спектрум,Синусы,Вышиванка,Дождь,Камин,Стрелки,Погода,Жизнь,Узоры,Рубик,Звёзды,Штора,Рассвет,SD-Карта") #else #define EFFECT_LIST F("Часы,Лампа,Снегопад,Кубик,Радуга,Пейнтбол,Огонь,The Matrix,Шарики,Звездопад,Конфетти," \ "Цветной шум,Облака,Лава,Плазма,Радужные переливы,Павлин,Зебра,Шумящий лес,Морской прибой,Смена цвета," \ "Светлячки,Водоворот,Циклон,Мерцание,Северное сияние,Тени,Лабиринт,Змейка,Тетрис,Арканоид," \ "Палитра,Спектрум,Синусы,Вышиванка,Дождь,Камин,Стрелки,Погода,Жизнь,Узоры,Рубик,Звёзды,Штора,Рассвет") #endif #else #if (USE_SD == 1) #define EFFECT_LIST F("Часы,Лампа,Снегопад,Кубик,Радуга,Пейнтбол,Огонь,The Matrix,Шарики,Звездопад,Конфетти," \ "Цветной шум,Облака,Лава,Плазма,Радужные переливы,Павлин,Зебра,Шумящий лес,Морской прибой,Смена цвета," \ "Светлячки,Водоворот,Циклон,Мерцание,Северное сияние,Тени,Лабиринт,Змейка,Тетрис,Арканоид," \ "Палитра,Спектрум,Синусы,Вышиванка,Дождь,Камин,Стрелки,Анимация,Погода,Жизнь,Узоры,Рубик,Звёзды,Штора,Рассвет,SD-Карта") #else #define EFFECT_LIST F("Часы,Лампа,Снегопад,Кубик,Радуга,Пейнтбол,Огонь,The Matrix,Шарики,Звездопад,Конфетти," \ "Цветной шум,Облака,Лава,Плазма,Радужные переливы,Павлин,Зебра,Шумящий лес,Морской прибой,Смена цвета," \ "Светлячки,Водоворот,Циклон,Мерцание,Северное сияние,Тени,Лабиринт,Змейка,Тетрис,Арканоид," \ "Палитра,Спектрум,Синусы,Вышиванка,Дождь,Камин,Стрелки,Анимация,Погода,Жизнь,Узоры,Рубик,Звёзды,Штора,Рассвет") #endif #endif // Список картинок, доступных для отрисовки в эффекте "Анимация". // Нумерация - с 1 до MAX_IMAGE_NUM, список разделяется запятыми, позиция в списке соответствует индексу картинки для отрисовки #define IMAGE_LIST F("Марио,Погода") // "Марио,Погода,Jinx" // Jinx закомментирован в animation.ino, в строке 45, также исправить значение MAX_IMAGE_NUM ниже в стр. 222 // Ниже представлен список эффектов, поддерживаемых прошивкой. Нумерация - сплошная от ID = 0 до ID = MAX_EFFECT // Если какие-то эффекты вам не нужны - перенесите их в конец списка, исправьте нумерацию и поправьте MAX_EFFECT так, // чтобы ненужные эффекты имели номера бОльшие MAX_EFFECT. // Так как перебор эффектов идет от 0 до MAX_EFFECT-1, эффекты с номерами за этим диапазоном не будут отображаться. // Также требуется исправить список эффектов EFFECT_LIST (см.выше) так, чтобы названия и порядок эффектов // соответствовал списку, определенному ниже. Отключенные эффекты не должны присутствовать в EFFECT_LIST // ID эффектов #define MC_CLOCK 0 // Режим отображения часов (когда "Ночные часы" или просто "Часы" на черном фоне, а не как оверлей поверх других эффектов #define MC_FILL_COLOR 1 #define MC_SNOW 2 #define MC_BALL 3 #define MC_RAINBOW 4 #define MC_PAINTBALL 5 #define MC_FIRE 6 #define MC_MATRIX 7 #define MC_BALLS 8 #define MC_STARFALL 9 #define MC_SPARKLES 10 #define MC_NOISE_MADNESS 11 #define MC_NOISE_CLOUD 12 #define MC_NOISE_LAVA 13 #define MC_NOISE_PLASMA 14 #define MC_NOISE_RAINBOW 15 #define MC_NOISE_RAINBOW_STRIP 16 #define MC_NOISE_ZEBRA 17 #define MC_NOISE_FOREST 18 #define MC_NOISE_OCEAN 19 #define MC_COLORS 20 #define MC_LIGHTERS 21 #define MC_SWIRL 22 #define MC_CYCLON 23 #define MC_FLICKER 24 #define MC_PACIFICA 25 #define MC_SHADOWS 26 #define MC_MAZE 27 #define MC_SNAKE 28 #define MC_TETRIS 29 #define MC_ARKANOID 30 #define MC_PALETTE 31 #define MC_ANALYZER 32 #define MC_PRIZMATA 33 #define MC_MUNCH 34 #define MC_RAIN 35 #define MC_FIRE2 36 #define MC_ARROWS 37 // Часы в фоторамке - размер 17x11 - для них нет картинки анимации - эффект анимация удален из прошивки #ifdef NO_ANIMATION #define MC_WEATHER 38 #define MC_LIFE 39 #define MC_PATTERNS 40 #define MC_RUBIK 41 #define MC_STARS 42 #define MC_STARS2 43 #define MC_DAWN_ALARM 44 #define MC_SDCARD 45 #if (USE_SD == 1) #define MAX_EFFECT 46 // количество эффектов, определенных в прошивке #else #define MAX_EFFECT 45 // количество эффектов, определенных в прошивке #endif #else #define MC_IMAGE 38 #define MC_WEATHER 39 #define MC_LIFE 40 #define MC_PATTERNS 41 #define MC_RUBIK 42 #define MC_STARS 43 #define MC_STARS2 44 #define MC_DAWN_ALARM 45 #define MC_SDCARD 46 #if (USE_SD == 1) #define MAX_EFFECT 47 // количество эффектов, определенных в прошивке #else #define MAX_EFFECT 46 // количество эффектов, определенных в прошивке #endif #endif #define MAX_SPEC_EFFECT 11 // количество эффектов быстрого доступа определенных в прошивке -> 0..10 #define MAX_IMAGE_NUM 2 // Количество картинок для эффекта "Анимация", определенных в программе (файлы bitmap1.h, .. ,bitmapN.h) // --------------------------------- #define SPECIAL_EFFECTS_START 120 // Некоторые специальные "служебные" эффекты имеют код >= SPECIAL_EFFECTS_START // Внимание !!! - для идентификатора режима используется тип int8_t (-128..127, нужно значение -1), поэтому код режима не может быть больше 127 !!! #define MC_DRAW 123 // Режим рисования картинки на телефоне #define MC_LOADIMAGE 124 // Режим загрузки изображения с телефона #define MC_TEXT 125 // Режим бегущей строки (для отображения IP адреса) - бегущая строка на черном фоне #define MC_DAWN_ALARM_SPIRAL 126 // Специальный режим, вызывается из DEMO_DAWN_ALARM для ламп на круговой матрице - огонек по спирали #define MC_DAWN_ALARM_SQUARE 127 // Специальный режим, вызывается из DEMO_DAWN_ALARM для плоских матриц - огонек по спирали на плоскости матрицы // --------------------------------- // ************************************************************************* enum eModes {NORMAL, COLOR, TEXT} parseMode; // Текущий режим парсера enum eSources {NONE, BOTH, UDP, MQTT} cmdSource; // Источник команды; NONE - нет значения; BOTH - любой, UDP-клиент, MQTT-клиент // ****************** ОПРЕДЕЛЕНИЯ ПАРАМЕТРОВ БУДИЛЬНИКА ******************** #if (USE_MP3 == 1) // SD карточка в MP3 плеере (DFPlayer) содержит в корне три папки - "1","2" и "3" // Папка "1" содержит MP3 файлы звуков, проигрываемых при наступлении события будильника // Папка "2" содержит MP3 файлы звуков, проигрываемых при наступлении события рассвета // Папка "3" содержит MP3 файлы звуков, проигрываемых в макросе {A} бегущей строки // DFPlayer не имеет возможности считывать имена файлов, только возможность получить количество файлов в папке. // Команда на воспроизведение звука означает - играть файл с индексом (номером) N из папки M // Номера файлов определяются таблицей размещения файлов SD-карты (FAT) и формируются в порядке очереди записи файлов на чистую флэшку // Так, файл записанный в папку первым получает номер 1, второй - 2 и так далее и никак не зависит от имен файлов // Данные массивы содержат отображаемые в приложении имена звуков в порядке, соответствующем нумерации записанных в папки файлов. // Список звуков для комбобокса "Звук будильника" в приложении на смартфоне #define ALARM_SOUND_LIST F("One Step Over,In the Death Car,Труба зовет,Маяк,Mister Sandman,Шкатулка,Banana Phone,Carol of the Bells") // Список звуков для комбобокса "Звук рассвета" в приложении на смартфоне #define DAWN_SOUND_LIST F("Птицы,Гроза,Прибой,Дождь,Ручей,Мантра,La Petite Fille De La Mer") // Список звуков для макроса {A} бегущей строки #define NOTIFY_SOUND_LIST F("Piece Of Сake,Swiftly,Pristine,Goes Without Saying,Inflicted,Eventually,Point Blank,Spring Board," \ "To The Point,Serious Strike,Jingle Bells,Happy New Year,Christmas Bells,Door Knock,Alarm Signal," \ "Viber Message,Viber Call,Text Message,Old Clock 1,Old Clock 2,Old Clock 3") #endif // ********************* ОПРЕДЕЛЕНИЯ ПАРАМЕТРОВ ЧАСОВ ********************** #define D_CLOCK_SPEED 254 // скорость перемещения эффекта часов по умолчанию (мс) - если больше 240 - часы стоят, не прокручиваются #define D_CLOCK_SPEED_MIN 2 #define D_CLOCK_SPEED_MAX 254 uint8_t CLOCK_SIZE = 0; // Размер горизонтальных часов: 0 - авто; 1 - цифры 3x5; 2 - цифры 5х7 uint8_t CLOCK_ORIENT = 0; // Ориентация отображения часов: 0 горизонтальные, 1 вертикальные (только для режима часов с цифрами 3х5; Часы шрифтом 5x7 всегда горизонтальные uint8_t CLOCK_MOVE_DIVIDER = 3; // Делитель такта таймера эффектов для движения часов оверлея (режим прокручивания часов по горизонтали) uint8_t CLOCK_MOVE_CNT = CLOCK_MOVE_DIVIDER;// Текущее значения счетчика сдвига uint8_t clockScrollSpeed = D_CLOCK_SPEED; // Скорость прокрутки часов uint8_t c_size = 0; // тип часов: 0 - авто; 1 - шрифт 3x5; 2 - шрифт 5х7; вычисляется в зависимости от настроек и параметров матрицы bool allow_two_row = false; // высота матрицы позволяет размещать календарь и часы с температурой в две строки // Позиции отображения часов, календаря, погоды; // Вычисляется в зависимости от выбранного шрифта часов 3x5 или 5x7, вертикальные/горизонтальные uint8_t CALENDAR_X; // Позиция вывода календаря по X uint8_t CALENDAR_Y; // Позиция вывода календаря по Y uint8_t CLOCK_X; // Позиция вывода часов по X uint8_t CLOCK_Y; // Позиция вывода часов по Y int8_t CLOCK_WX; // Позиция вывода погоды по X в малых часах / Реальная ширина отрисованных часов в больших часах int8_t CLOCK_WY; // Позиция вывода погоды по Y uint8_t CALENDAR_W; // Ширина вывода календаря uint8_t CALENDAR_H; // Высота вывода календаря по Y uint8_t CLOCK_W; // Ширина вывода часов по X uint8_t CLOCK_H; // Высота вывода часов по Y uint8_t CLOCK_WW; // Ширина вывода погоды по X uint8_t CLOCK_WH; // Высота вывода погоды по Y int8_t CLOCK_XC = 0; // Текущая позиция часов оверлея по оси Х с учетом скроллинга int8_t CALENDAR_XC = 0; // Текущая позиция календаря оверлея по оси Х int8_t CLOCK_FX = 0; // Реальная X позиция отрисовки первой цифры блока часов и температуры int8_t CLOCK_LX = 0; // Реальная X позиция отрисовки последней цифры часов - температура будет выводиться от этой позиции влево, чтобы выровнять температуру по правому краю часов uint8_t COLOR_MODE = 0; // Режим цвета часов // 0 - монохром // 1 - радужная смена (каждая цифра) // 2 - радужная смена (часы, точки, минуты) // 3 - заданные цвета (часы, точки, минуты) - HOUR_COLOR, DOT_COLOR, MIN_COLOR в clock.ino #define MIN_NIGHT_CLOCK_BRIGHTNESS 16 // Минимальная яркость ночных часов при которой диоды еще светятся uint8_t nightClockBrightness = 16; // Яркость отображения ночных часов uint8_t nightClockColor = 0; // Цвет ночных часов: 0 - R; 1 - G; 2 - B; 3 - C; 4 - M; 5 - Y; 6 - W; bool needTurnOffClock = false; // Выключать индикатор часов TM1637 при выключении устройства (true); если False - при отключении панели индикатор TM1637 продолжает показывать текущее время bool showWeatherInClock = true; // Показывать текущую температуру при отображении малых (неподвижных) часов bool showDateInClock = true; // Показывать дату при отображении часов uint8_t showDateDuration = 2; // на 2 секунды uint8_t showDateInterval = 240; // через каждые 240 секунд bool showDateState = false; // false - отображаются часы; true - отображается дата bool showWeatherState = false; // false - отображаются часы; true - отображается температура в больших часах uint32_t showDateStateLastChange = 0; // Время, когда отображение часов сменилось на отображение календаря и наоборот int8_t hrs = 0, mins = 0; // Для получения текущего времени. Инициализировано как 01.01.1970 00:00 int8_t secs = 0, aday = 1, amnth = 1; int16_t ayear = 1970; bool dotFlag; // флаг: в часах рисуется точки // ************************ НАСТРОЙКИ БЕГУЩЕЙ СТРОКИ *********************** #define D_TEXT_SPEED 100 // скорость перемещения эффекта часов по умолчанию (мс) #define D_TEXT_SPEED_MIN 2 #define D_TEXT_SPEED_MAX 254 #define MIRR_V 0 // отразить текст по вертикали (0 / 1) #define MIRR_H 0 // отразить текст по горизонтали (0 / 1) #if (BIG_FONT == 0) #define LET_WIDTH 5 // ширина буквы шрифта #define LET_HEIGHT 8 // высота буквы шрифта #define SPACE 1 // пробел между буквами #elif (BIG_FONT == 1) #define LET_WIDTH 10 // ширина буквы шрифта #define LET_HEIGHT 16 // высота буквы шрифта #define SPACE 2 // пробел между буквами #else #define LET_WIDTH 8 // ширина буквы шрифта #define LET_HEIGHT 13 // высота буквы шрифта #define SPACE 1 // пробел между буквами #endif uint8_t textScrollSpeed = D_TEXT_SPEED; // Скорость прокрутки оверлея бегущей строки uint16_t TEXT_INTERVAL = 90; // Интервал (время в секундах) между отображением строк // следующая бегущая строка будет отображена через указанное кол-во секунд // 0 - отключено, следующая строка отображается после завершения текущей uint8_t COLOR_TEXT_MODE = 0; // Режим цвета текста бегущей строки и самой бегущей строки // 0 - монохром // 1 - радужная смена (каждая цифра) // 2 - каждая цифра свой цвет // --- Параметры отображения текущей бегущей строки int16_t textShowTime = -1; // Если больше нуля - сколько времени отображать бегущую строку в секундах; Если 0 - используется textShowCount; В самой строке спец-макросом может быть указано кол-во секунд uint8_t textShowCount = 1; // Сколько раз прокручивать текст бегущей строки поверх эффектов; По умолчанию - 1; В самой строке спец-макросом может быть указано число uint8_t textCurrentCount = 0; // Сколько раз текст очередной бегущей строки поверх эффектов уже показан bool useSpecialTextColor = false; // В текущей бегущей строке был задан цвет, которым она должна отображаться uint32_t specialTextColor = 0xffffff; // Цвет отображения бегущей строки, может быть указан макросом в строке. Если не указан - используются глобальные настройки цвета бегущей строки bool useSpecialBackColor = false; // В текущей бегущей строке был задан цвет фона, на котором она должна отображаться uint32_t specialBackColor = 0x000000; // Цвет фона отображения бегущей строки, может быть указан макросом в строке. Если не указан - наложение на текущий эффект int8_t specialTextEffect = -1; // Эффект, который нужно включить при начале отображения строки текста, может быть указан макросом в строке. int8_t specialTextEffectParam = -1; // Параметр для эффекта (см. выше). Например эффект MC_SDCARD имеет более 40 подэффектов. Номер подэффекта хранится в этой переменной, извлекается из макроса {E} int8_t saveEffectBeforeText = -1; // Если указан эффект на котором отображать строку, сохранить текущий эффект тут, чтобы по завершению строки восстановить его int8_t currentTextLineIdx = -1; // Какая строка из массива строк показывается в текущий момент int8_t nextTextLineIdx = -1; // Какую следующую строку показывать, может быть указан макросом в строке. Если указан - интервал отображения игнорируется, строка показывается сразу bool textHasDateTime = false; // Строка содержит макрос отображения текущего времени - ее нужно пересчитывать каждый раз при отрисовке; Если макроса времени нет - рассчитать текст строки один раз на этапе инициализации bool textHasMultiColor = false; // Строка содержит несколько (до 6) макросов, задающих цвет строки String currentText = ""; // Текст текущей отображаемой строки String syncText = ""; // Текст текущей отображаемой строки не очищенный от макросов bool ignoreTextOverlaySettingforEffect = false; // Показывать бегущую строку для эффекта, даже если настройки эффекта это запрещают; В строке может быть указано, какую строку показывать следующей - ее надо показывать даже если настройки текущего эффекта это запрещают int8_t sequenceIdx = -1; // Если нулевая строка массива содержит последовательность отображения строк (начинается с # или имеет значение ##) - указывает на позицию какой будет следующая отображаемая строка int8_t editIdx = -1; // Индекс строки, передаваемой в телефон на запрос строки по индексу uint16_t crc = 0; // Контрольная сумма загруженного массива строк. Рассчитывается при загрузке, проверяется перед сохранением int16_t memoryAvail = 0; // Сколько памяти осталось под хранение строк; Устанавливается при загрузке / сохранении массива строк #define MAX_COLORS 12 // сколько макросов цвета может содержать строка int16_t textColorPos[MAX_COLORS+1]; // Позиции начала цвета в строке uint32_t textColor[MAX_COLORS+1]; // Цвета в строке // --- uint32_t textStartTime = 0; // Время начала отображения текущей бегущей строки uint32_t textLastTime = 0; // Время завершения отображения последней показанной бегущей строки uint32_t textLastSend = 0; // Время последней отправки очередной строки списка строк в телефон uint32_t textAllowBegin = 0; // Для строк с макросом {S} - время начала допустимого интервала отображения unixTime uint32_t textAllowEnd = 4294967295; // Для строк с макросом {S} - время конца допустимого интервала отображения unixTime bool loadingTextFlag = false; // Флаг инициализации показа строки в режиме MC_TEXT (показ IP адреса); для новой строки оверлейного текста используется специальный вызов prepareNextText() в custom.ino bool showTextNow = false; // флаг: что в настоящий момент нужно отображать оверлеем: true - оверлей бегущей строки; false - оверлей часов; bool fullTextFlag = false; // флаг: текст бегущей строки показан полностью (строка убежала) bool gameOverFlag = false; // флаг: демо-игра завершена String textLines[36]; // Массив строк для отображения 0..9A..Z; // --- typedef struct { // Структура описателя событий постоянного контроля time_t moment; // unixtime - ближайший момент времени наступления события uint32_t before; // за сколько секунд до события начинать отображать строку uint32_t after; // сколько секунд после наступления события отображать строку-заместитель uint8_t index_b; // индекс в массиве строк textLines отображаемой строки ДО события, привязанной к этому событию int8_t index_a; // индекс в массиве строк textLines отображаемой строки ПОСЛЕ события, привязанной к этому событию (-1 если строки замены не указано) } Moment; #define MOMENTS_NUM 6 // максимальное количество отслеживаемых событий для строк, содержащих макрос {P} Moment moments[MOMENTS_NUM]; // массив с моментами времени событий для бегущих строк с макросом {P} bool moment_active = false; // В текущий момент происходит отображение строки, привязанной к отслеживаемому событию. int8_t momentIdx = -1; // Индекс строки в массиве moments для активного текущего непрерывно отслеживаемого события int8_t momentTextIdx = -1; // Индекс строки в массиве textLines для активного текущего непрерывно отслеживаемого события uint32_t textCheckTime = 0; // Время контроля списка событий непрерывного отслеживания // *************************** ПОДКЛЮЧЕНИЕ К СЕТИ ************************** WiFiUDP udp; // Объект транспорта сетевых пакетов // к длине +1 байт на \0 - терминальный символ. Это буферы для загрузки имен/пароля из EEPROM. Значения задаются в define выше char apName[11] = DEFAULT_AP_NAME; // Имя сети в режиме точки доступа char apPass[17] = DEFAULT_AP_PASS; // Пароль подключения к точке доступа uint8_t IP_STA[] = DEFAULT_IP; // Статический адрес в локальной сети WiFi по умолчанию при первом запуске. Потом - загружается из настроек, сохраненных в EEPROM String ssid = NETWORK_SSID; // SSID (имя) вашего роутера (конфигурируется подключением через точку доступа и сохранением в файловой системе микроконтроллера) String pass = NETWORK_PASS; // пароль роутера uint16_t localPort = 2390; // локальный порт на котором слушаются входящие команды управления от приложения на смартфоне, передаваемые через локальную сеть // ------------------------ MQTT parameters -------------------- #if (USE_MQTT == 1) WiFiClient m_client; // Объект для работы с удалёнными хостами - соединение с MQTT-сервером PubSubClient mqtt(m_client); // Объект соединения с MQTT сервером String mqtt_client_name = ""; // Имя для регистрации клиента на сервере MQTT // Код работы с MQTT-каналом ориентирован на использование MQTT-брокера mqtt.by #define TOPIC_CMD "cmd" // Топик - получение команды управления от клиента #define TOPIC_DTA "dta" // Топик - отправка запрошенных данных клиенту #define TOPIC_ERR "err" // Топик - отправка уведомлений об ошибке клиенту #define TOPIC_STA "sta" // Топик - отправка уведомления о (ре)старте микроконтроллера #define TOPIC_ALM "alm" // Топик - отправка клиенту сообщений о событиях будильника #define TOPIC_AMD "amd" // Топик - отправка клиенту сообщений о событиях авторежимов по времени #define TOPIC_WTR "wtr" // Топик - отправка клиенту сообщений о событиях погоды #define TOPIC_TME "tme" // Топик - отправка клиенту сообщений о событиях времени #define TOPIC_PWR "pwr" // Топик - отправка клиенту сообщений о включении/выключении устройства #define TOPIC_SDC "sdc" // Топик - отправка клиенту сообщений о событиях SD-карты #define TOPIC_TXT "txt" // Топик - отправка клиенту сообщений о событиях бегущей строки #define TOPIC_STT "stt" // Топик - отправка клиенту сообщений о текущем статусе параметров устройства - основной набор параметров (пакет) #define TOPIC_E131 "e131" // Топик - отправка клиенту сообщений о событиях передачи данных по протоколу E131 #define MQTT_CONNECT_TIMEOUT 1000 // Таймаут попытки установить соединение с MQTT сервером #define MQTT_RECONNECT_PERIOD 300000 // Интервал между попытками соединения с MQTT сервером, если соединение не установилось из-за неответа сервера по таймауту bool useMQTT = true; // Использовать канал управления через MQTT - флаг намерения // При отключении из приложения set_useMQTT(false) устанавливается соответствующее состояние (параметр QA), состояние 'намерение отключить MQTT' bool stopMQTT = false; // Использовать канал управления через MQTT - флаг результата // которое должно быть отправлено на MQTT-сервер, значит реально состояние 'MQTT остановлен' - только после отправки флага QA на сервер char mqtt_server[25] = ""; // Имя сервера MQTT char mqtt_user[15] = ""; // Логин от сервера char mqtt_pass[15] = ""; // Пароль от сервера char mqtt_prefix[31] = ""; // Префикс топика сообщения uint16_t mqtt_port = DEFAULT_MQTT_PORT; // Порт для подключения к серверу MQTT // Выделение места под массив команд, поступающих от MQTT-сервера // Callback на поступление команды от MQTT сервера происходит асинхронно, и если предыдущая // команда еще не обработалась - происходит новый вызов обработчика команд, который не реентерабелен - // это приводит к краху приложения. Чтобы избежать этого поступающие команды будем складывать в очередь // и выполнять их в основном цикле программы #define QSIZE_IN 8 // размер очереди команд от MQTT #define QSIZE_OUT 96 // размер очереди исходящих сообщений MQTT String cmdQueue[QSIZE_IN]; // Кольцевой буфер очереди полученных команд от MQTT String tpcQueue[QSIZE_OUT]; // Кольцевой буфер очереди отправки команд в MQTT (topic) String outQueue[QSIZE_OUT]; // Кольцевой буфер очереди отправки команд в MQTT (message) bool rtnQueue[QSIZE_OUT]; // Кольцевой буфер очереди отправки команд в MQTT (retain) uint8_t queueWriteIdx = 0; // позиция записи в очередь обработки полученных команд uint8_t queueReadIdx = 0; // позиция чтения из очереди обработки полученных команд uint8_t queueLength = 0; // количество команд в очереди обработки полученных команд uint8_t outQueueWriteIdx = 0; // позиция записи в очередь отправки MQTT сообщений uint8_t outQueueReadIdx = 0; // позиция чтения из очереди отправки MQTT сообщений uint8_t outQueueLength = 0; // количество команд в очереди отправки MQTT сообщений String last_mqtt_server = ""; uint16_t last_mqtt_port = 0; String changed_keys = ""; // Строка, содержащая список измененных параметров, чье состояние требуется отправить серверу bool mqtt_connecting = false; // Выполняется подключение к MQTT (еще не установлено) bool mqtt_topic_subscribed = false; // Подписка на топик команд выполнена uint8_t mqtt_conn_cnt = 0; // Счетчик попыток подключения для форматирования вывода uint32_t mqtt_conn_last; // Время последней попытки подключения к MQTT-серверу uint32_t uptime_send_last; // Время последней отправки uptime к MQTT-серверу по инициативе устройства uint32_t nextMqttConnectTime; // При недоступности MQTT сервера определяет время следующей попытки соединения #endif // --------------------------------------------------------------- bool useSoftAP = false; // использовать режим точки доступа bool wifi_connected = false; // true - подключение к wifi сети выполнена bool ap_connected = false; // true - работаем в режиме точки доступа; bool wifi_print_ip = false; // Включен режим отображения текущего IP на индикаторе TM1637 bool wifi_print_ip_text = false; // Включен режим отображения текущего IP на матрице uint8_t wifi_print_idx = 0; // Индекс отображаемой на индикаторе TM1637 тетрады IP адреса String wifi_current_ip = ""; // Отображаемый в бегущей строке IP адрес лампы // **************** СИНХРОНИЗАЦИЯ ЧАСОВ ЧЕРЕЗ ИНТЕРНЕТ ******************* IPAddress timeServerIP; #define NTP_PACKET_SIZE 48 // NTP время - в первых 48 байтах сообщения uint16_t SYNC_TIME_PERIOD = 60; // Период синхронизации в минутах по умолчанию uint8_t packetBuffer[NTP_PACKET_SIZE]; // буфер для хранения входящих и исходящих пакетов NTP int8_t timeZoneOffset = TIME_ZONE; // смещение часового пояса от UTC uint32_t ntp_t = 0; // Время, прошедшее с запроса данных с NTP-сервера (таймаут) uint8_t ntp_cnt = 0; // Счетчик попыток получить данные от сервера bool init_time = false; // Флаг false - время не инициализировано; true - время инициализировано bool refresh_time = true; // Флаг true - пришло время выполнить синхронизацию часов с сервером NTP bool useNtp = true; // Использовать синхронизацию времени с NTP-сервером bool getNtpInProgress = false; // Запрос времени с NTP сервера в процессе выполнения char ntpServerName[31] = ""; // Используемый сервер NTP // *************************** Yandex.Погода ***************************** WiFiClient w_client; // Объект для работы с удалёнными хостами - соединение с сервером погоды bool init_weather = false; // Флаг: true - погода получена; false - погода не получена / не актуальна #if (USE_WEATHER == 1) uint8_t useWeather = 1; // Использовать получение текущей погоды с погодного сервера 0 - не использовать; 1 - Yandex; 2 - OpenWeatherMap uint32_t regionID = WEATHER_REGION_YDX; // Код региона по Yandex uint32_t regionID2 = WEATHER_REGION_OWTH; // Код региона по OpenWeatherMap String skyColor; // Рекомендованный цвет фона погоды String weather; // Состояние - "Ясно", "Облачно", "Дождь" и т.д. String dayTime; // "Темное время суток" / "Светлое время суток" bool isNight; // день / ночь int8_t temperature; // Текущая температура int16_t weather_code; // код погодных условий для OpenWeatherMap String icon; // код иконки, содержит зашифрованный статус погодных условий uint32_t weather_t = 0; // Время, прошедшее с запроса данных с сервера погоды (таймаут) uint8_t weather_cnt = 0; // Счетчик попыток получить данные от сервера uint32_t weather_time; // Время последнего получения погоды; uint8_t weatherActualityDuration = 3; // Какой период времени в часах после получения погоды считать ее актуальной (на случай, если сервер перестал отвечать) uint16_t SYNC_WEATHER_PERIOD = 15; // Период обновления информации о текущей погоде в минутах по умолчанию uint8_t refresh_weather = true; // Флаг: пришло время очередного получения погоды с сервера bool getWeatherInProgress = false; // Запрос погоды сервера в процессе выполнения bool weather_ok = true; // Погода получена // API-идентификатор сервиса получения погоды - смотрите раздел Wiki - Настройка получения информации о погоде // https://github.com/vvip-68/GyverPanelWiFi/wiki/Настройка-получения-информации-о-погоде #ifndef WEATHER_API_KEY #define WEATHER_API_KEY "6a4ba421859c9f4166697758b68d889b" #endif #endif bool useTemperatureColor = true; // Для дневных часов: true - выводить температуру специальным цветом, в зависимости от значения температуры; 0 - не использовать градации цвета bool useTemperatureColorNight = false; // Для ночных часов: true - выводить температуру специальным цветом, в зависимости от значения температуры; 0 - не использовать градации цвета #define cold_less_30 "#3300FF" // -39..-30 #define cold_29_20 "#0000FF" // -29..-20 #define cold_19_10 "#0077FF" // -19..-10 #define cold_9_4 "#00FFFF" // -9..-4 #define zero_3_3 "#808080" // -3..+3 #define hot_4_9 "#AA5511" // +4..+9 #define hot_10_19 "#773300" // +10..+19 #define hot_20_29 "#A01F03" // +20..+29 #define hot_30_great "#FF0000" // +30..+39 // *********************** ДЛЯ БУДИЛЬНИКА-РАССВЕТ ************************ bool isAlarming = false; // Сработал будильник "рассвет" bool isPlayAlarmSound = false; // Сработал настоящий будильник - играется звук будильника bool isAlarmStopped = false; // Сработавший будильник "рассвет" остановлен пользователем uint8_t alarmWeekDay = 0; // Битовая маска дней недели будильника uint8_t alarmDuration = 1; // Проигрывать звук будильнике N минут после срабатывания (по окончанию рассвета) uint8_t alarmHour[7] = {0,0,0,0,0,0,0}; // Часы времени срабатывания будильника по дням недели uint8_t alarmMinute[7] = {0,0,0,0,0,0,0}; // Минуты времени срабатывания будильника по дням недели int8_t dawnHour = 0; // Часы времени начала рассвета int8_t dawnMinute = 0; // Минуты времени начала рассвета uint8_t dawnWeekDay = 0; // День недели времени начала рассвета (0 - выключено, 1..7 - пн..вс) uint8_t dawnDuration = 10; // Продолжительность "рассвета" по настройкам в минутах uint8_t realDawnDuration = 0; // Продолжительность "рассвета" по вычисленному времени срабатывания будильника uint8_t alarmEffect = MC_DAWN_ALARM; // Какой эффект используется для будильника "рассвет". Могут быть обычные эффекты - их яркость просто будет постепенно увеличиваться // **************************** MP3 ПЛЕЕР ***************************** bool isDfPlayerOk = false; // MP3-Player корректно инициализирован и готов к использованию #if (USE_MP3 == 1) class Mp3Notify; #if defined(ESP32) #if (DFPLAYER_TYPE == 0) typedef DFMiniMp3 DfMp3; #endif #if (DFPLAYER_TYPE == 1) typedef DFMiniMp3 DfMp3; #endif #define mp3Serial Serial2 #else #if (DFPLAYER_TYPE == 0) typedef DFMiniMp3 DfMp3; #endif #if (DFPLAYER_TYPE == 1) typedef DFMiniMp3 DfMp3; #endif SoftwareSerial mp3Serial; #endif DfMp3 dfPlayer(mp3Serial); int16_t alarmSoundsCount = 0; // Кол-во файлов звуков в папке '01' на SD-карте int16_t dawnSoundsCount = 0; // Кол-во файлов звуков в папке '02' на SD-карте int16_t noteSoundsCount = 0; // Кол-во файлов звуков в папке '03' на SD-карте uint8_t soundFolder = 0; // Текущая используемая папка со звуками uint8_t soundFile = 0; // Текущий используемый файл звука в папке int8_t fadeSoundDirection = 1; // направление изменения громкости звука: 1 - увеличение; -1 - уменьшение uint8_t fadeSoundStepCounter = 0; // счетчик шагов изменения громкости, которое осталось сделать bool useAlarmSound = false; // Использовать звуки в будильнике int8_t alarmSound = 0; // Звук будильника - номер файла в папке SD:/01 [-1 не использовать; 0 - случайный; 1..N] номер файла int8_t dawnSound = 0; // Звук рассвета - номер файла в папке SD:/02 [-1 не использовать; 0 - случайный; 1..N] номер файла int8_t runTextSound = -1; // Номер звука в папке SD://03 на sd-карте, который воспроизводится вместе с отображением бегущей строки bool runTextSoundRepeat = false; // Флаг - повторять в цикле: false - играть один раз; true - зацикливать uint8_t maxAlarmVolume = 30; // Максимальная громкость будильника (1..30) #endif // ************************* КНОПКА УПРАВЛЕНИЯ ************************* #if (BUTTON_TYPE == 0) GButton butt(PIN_BTN, LOW_PULL, NORM_OPEN); // Для сенсорной кнопки #else GButton butt(PIN_BTN, HIGH_PULL, NORM_OPEN); // Для обычной кнопки #endif bool isButtonHold = false; // Кнопка нажата и удерживается uint8_t bCounter = 0; // Счетчик нажатия на кнопку // ************************** Дисплей TM1637 ************************** #if (USE_TM1637 == 1) TM1637Display display(CLK, DIO); bool aDirection = true; // Направление счетчика изменения яркости, отображаемом на индикаторе при регулировке uint8_t aCounter = 0; // Текущая яркость индикатора при плавном изменении яркости uint32_t fade_time; // Для плавного изменения яркости индикатора при сработавшем будильнике #endif // ******************** ВКЛЮЧЕНИЕ РЕЖИМОВ ПО ВРЕМЕНИ ********************* bool AM1_running = false; // Режим 1 по времени - работает uint8_t AM1_hour = 0; // Режим 1 по времени - часы uint8_t AM1_minute = 0; // Режим 1 по времени - минуты int8_t AM1_effect_id = -3; // Режим 1 по времени - ID эффекта или -3 - выключено (не используется); -2 - выключить матрицу (черный экран); -1 - ночные часы, 0 - случайный, 1 и далее - эффект EFFECT_LIST bool AM2_running = false; // Режим 2 по времени - работает uint8_t AM2_hour = 0; // Режим 2 по времени - часы uint8_t AM2_minute = 0; // Режим 2 по времени - минуты int8_t AM2_effect_id = -3; // Режим 2 по времени - ID эффекта или -3 - выключено (не используется); -2 - выключить матрицу (черный экран); -1 - ночные часы, 0 - случайный, 1 и далее - эффект EFFECT_LIST bool AM3_running = false; // Режим 3 по времени - работает uint8_t AM3_hour = 0; // Режим 3 по времени - часы uint8_t AM3_minute = 0; // Режим 3 по времени - минуты int8_t AM3_effect_id = -3; // Режим 3 по времени - ID эффекта или -3 - выключено (не используется); -2 - выключить матрицу (черный экран); -1 - ночные часы, 0 - случайный, 1 и далее - эффект EFFECT_LIST bool AM4_running = false; // Режим 4 по времени - работает uint8_t AM4_hour = 0; // Режим 4 по времени - часы uint8_t AM4_minute = 0; // Режим 4 по времени - минуты int8_t AM4_effect_id = -3; // Режим 4 по времени - ID эффекта или -3 - выключено (не используется); -2 - выключить матрицу (черный экран); -1 - ночные часы, 0 - случайный, 1 и далее - эффект EFFECT_LIST bool dawn_running = false; // Режим по времени "Рассвет" - работает uint8_t dawn_hour = 0; // Режим по времени "Рассвет" - часы uint8_t dawn_minute = 0; // Режим по времени "Рассвет" - минуты int8_t dawn_effect_id = -3; // Режим по времени "Рассвет" - ID эффекта или -3 - выключено (не используется); -2 - выключить матрицу (черный экран); -1 - ночные часы, 0 - случайный, 1 и далее - эффект EFFECT_LIST bool dusk_running = false; // Режим по времени "Закат" - работает uint8_t dusk_hour = 0; // Режим по времени "Закат" - часы uint8_t dusk_minute = 0; // Режим по времени "Закат" - минуты int8_t dusk_effect_id = -3; // Режим по времени "Закат" - ID эффекта или -3 - выключено (не используется); -2 - выключить матрицу (черный экран); -1 - ночные часы, 0 - случайный, 1 и далее - эффект EFFECT_LIST // ************************* РАБОТА С SD КАРТОЙ ************************* #if (USE_SD == 1) #define MAX_FILES 126 // больше нельзя - переполнение индекса массива для типа int8_t -128..127; Значение 127 и < 0 - специальные значения для перехода по циклу эффектов String nameFiles[MAX_FILES]; // Список имен файлов, найденных в папке на SD-карте bool isSdCardReady = false; // Флаг - SD карта инициализирована корректно bool play_file_finished = false; // Флаг - воспроизведение эффекта завершено bool wait_play_finished = (WAIT_PLAY_FINISHED == 1); // Флаг - true - переключаться на следующий эффект только когда весь файл показан; false - прерывать показ по истечении времени эффекта uint8_t countFiles = 0; // Количество найденных файлов эффектов, найденных на SD-карте int8_t sf_file_idx = -1; // Эффект, проигрываемый с SD-карты - индекс в массиве nameFiles #endif // ************************* ПРОЧИЕ ПЕРЕМЕННЫЕ ************************* bool repeat_play = (REPEAT_PLAY == 1); // Флаг - true - повторное проигрывание текущего эффекта, если время не вышло; false - перейти к следующему эффекту после однократного проигрывания текущего (игры, SD-карта) uint8_t fadeMode = 4; // Фаза режима плавной смены эффекта bool modeDir; // Направление перехода к следующему / предыдущему режиму // --------------------------------------------------------------- #define D_GAME_SPEED 150 // скорость игр по умолчанию (мс) #define D_EFFECT_SPEED 80 // скорость эффектов по умолчанию (мс) #define D_EFFECT_SPEED_MIN 0 // пределы регулировки скорости #define D_EFFECT_SPEED_MAX 255 // --------------------------------------------------------------- #define AUTOPLAY_PERIOD 60 // время между авто сменой режимов (секунды) #define IDLE_TIME 30 // время бездействия (в минутах, по умолчанию) после которого запускается автосмена режимов, если разрешена в настройках #define SMOOTH_CHANGE 0 // плавная смена режимов через чёрный // --------------------------------------------------------------- bool eepromModified = false; // флаг: EEPROM изменен, требует сохранения // --------------------------------------------------------------- uint32_t globalColor = 0xffffff; // цвет панели в режиме "Лампа" по умолчанию uint32_t globalClockColor = 0xffffff; // цвет часов в режиме MC_COLOR - режим цвета "Монохром" по умолчанию uint32_t globalTextColor = 0xffffff; // цвет бегущей строки MC_TEXT в режиме цвета "Монохром" по умолчанию uint32_t drawColor = 0xffffff; // цвет рисования bool sendImageFlag = false; // флаг: режим отправки изображения с матрицы в приложение на телефоне uint8_t sendImageRow = 0; // Индекс отправляемого изображения (по строкам) uint8_t sendImageCol = 0; // Индекс отправляемого изображения (по колонкам) eSources sendImageSrc = NONE; // Источник запроса изображения // --------------------------------------------------------------- bool specialMode = false; // Спец.режим, включенный вручную со смартфона или с кнопок быстрого включения режима bool specialClock = false; // Отображение часов в спец.режиме - как отдельный эффект "Часы" на черном фоне, а не как оверлей поверх других эффектов uint8_t specialBrightness = 1; // Яркость в спец.режиме bool isTurnedOff = false; // Включен черный экран (т.е. всё выключено) bool isNightClock = false; // Включен режим ночных часов int8_t specialModeId = -1; // Номер текущего спецрежима int8_t manualModeId = -1; // Номер текущего режима bool useRandomSequence = true; // Флаг: случайный выбор режима bool clockOverlayEnabled = true; // Доступность оверлея часов поверх эффектов bool textOverlayEnabled = true; // Доступность оверлея бегущей строки поверх эффектов bool overlayDelayed = false; // используется для указания был ли оверлей на предыдущем цикле отрисовки int8_t y_overlay_low = 0; // Вычисленная позиция оверлея матрицы - во всю ширину, область отображения текста бегущей строки / часов / календаря int8_t y_overlay_high = 0; int8_t debug_hours = -1; // Для отладки позиционирования часов int8_t debug_mins = -1; // Для отладки позиционирования часов int8_t debug_temperature; // Для отладки позиционирования часов // --------------------------------------------------------------- // Сервер не может инициировать отправку сообщения клиенту - только в ответ на запрос клиента // Следующие две переменные хранят сообщения, формируемые по инициативе сервера и отправляются в ответ на ближайший запрос от клиента, // например в ответ на периодический ping - в команде sendAcknowledge(); String cmd95 = ""; // Строка, формируемая sendPageParams(95) для отправки по инициативе сервера String cmd96 = ""; // Строка, формируемая sendPageParams(96) для отправки по инициативе сервера // --------------------------------------------------------------- uint8_t globalBrightness = BRIGHTNESS; // текущая яркость бегущей строки и часов (общая) uint8_t contrast = 255; // контрастность эффектов по отношению к яркости часов / бегущей строки (общей яркости) => 0.255 -> 10..100% bool brightDirection = false; // true - увеличение яркости; false - уменьшение яркости при регулировке кнопкой // --------------------------------------------------------------- uint8_t effectScaleParam[MAX_EFFECT]; // Динамический параметр эффекта, параметр #1 uint8_t effectScaleParam2[MAX_EFFECT]; // Динамический параметр эффекта, параметр #2 uint8_t effectContrast[MAX_EFFECT]; // Динамический параметр эффекта - контрастность (яркость эффекта относительно яркости часов или текста бегущей строки) uint8_t effectSpeed[MAX_EFFECT]; // Динамический параметр эффекта - скорость bool manualMode = false; // флаг: true - ручное управление эффектами; false - в режиме Autoplay bool loadingFlag = true; // флаг: инициализация параметров эффекта // --------------------------------------------------------------- uint32_t idleTime = ((uint32_t)IDLE_TIME * 60 * 1000UL); // минуты -> миллисекунды uint32_t autoplayTime = ((uint32_t)AUTOPLAY_PERIOD * 1000UL); // секунды -> миллисекунды bool idleState = true; // флаг холостого режима работы uint32_t autoplayTimer; // время до автоматического перехода в демо-режим uint32_t upTime = 0; // время работы системы с последней перезагрузки // --------------------------------------------------------------- int8_t thisMode = 0; // текущий режим - id String effect_name = ""; // текущий режим - название // --------------------------------------------------------------- #define GLOBAL_COLOR_1 CRGB::Green // основной цвет №1 для игр #define GLOBAL_COLOR_2 CRGB::Orange // основной цвет №2 для игр #define SCORE_SIZE 1 // размер символов счёта в игре. 0 - маленький для 8х8 (шрифт 3х5), 1 - большой (шрифт 5х7) bool gameDemo = true; // Игры Тетрис, Лабиринт, Змейка работают в демо-режиме bool gamePaused = false; // Игра на паузе (при ручном управлении игрой) uint8_t buttons; // Эмуляция кнопок управления играми в демо-режиме // --------------------------------------------------------------- timerMinim gameTimer(D_GAME_SPEED); // Таймер скорости игр timerMinim effectTimer(D_EFFECT_SPEED); // Таймер скорости эффекта (шага выполнения эффекта) timerMinim clockTimer(D_CLOCK_SPEED); // Таймер смещения оверлея часов timerMinim textTimer(D_TEXT_SPEED); // Таймер смещения оверлея часов timerMinim changeTimer(70); // Таймер шага плавной смены режима - Fade timerMinim halfsecTimer(500); // Полусекундный таймер точек часов timerMinim idleTimer(idleTime); // Таймер бездействия ручного управления для автоперехода в демо-режим timerMinim dawnTimer(1000); // Таймер шага рассвета для будильника "рассвет" timerMinim alarmSoundTimer(4294967295); // Таймер выключения звука будильника timerMinim fadeSoundTimer(4294967295); // Таймер плавного включения / выключения звука timerMinim saveSettingsTimer(15000); // Таймер отложенного сохранения настроек timerMinim ntpSyncTimer(1000 * 60 * SYNC_TIME_PERIOD); // Сверяем время с NTP-сервером через SYNC_TIME_PERIOD минут #if (USE_WEATHER == 1) timerMinim weatherTimer(1000 * 60 * SYNC_WEATHER_PERIOD); // Получаем текущую погоду каждые SYNC_WEATHER_PERIOD минут #endif // ********************* ДЛЯ ПАРСЕРА КОМАНДНЫХ ПАКЕТОВ ************************* #define BUF_MAX_SIZE 4096 // максимальный размер выделяемого буфера для коммуникации по UDP каналу #define PARSE_AMOUNT 16 // максимальное количество значений в массиве, который хотим получить #define header '$' // стартовый символ управляющей посылки #define divider ' ' // разделительный символ #define ending ';' // завершающий символ int32_t intData[PARSE_AMOUNT]; // массив численных значений после парсинга - для WiFi часы время синхронизации может быть отрицательным + // период синхронизации может быть больше 255 мин - нужен тип int32_t char incomeBuffer[BUF_MAX_SIZE]; // Буфер для приема строки команды из wifi udp сокета; также используется для загрузки строк из EEPROM char replyBuffer[8]; // ответ клиенту - подтверждения получения команды: "ack;/r/n/0" uint8_t ackCounter = 0; // счетчик отправляемых ответов для создания уникальности номера ответа #if (USE_MQTT == 1) #define BUF_MQTT_SIZE 384 // максимальный размер выделяемого буфера для входящих сообщений по MQTT каналу char incomeMqttBuffer[BUF_MQTT_SIZE]; // Буфер для приема строки команды из MQTT #endif // **************** ДЛЯ СИНХРОННОЙ РАБОТЫ УСТРОЙСТВ И ПРИЕМА ПОТОКА E1.31 ****************** #if (USE_E131 == 1) ESPAsyncE131 *e131; // Объект приемника данных по протоколу E1.31 в UDP пакетах по WiFi e131_packet_t e131_packet; // Пакет данных формата E1.31 // Режимы работы панели - Самостоятельный без поддержки синхронизации, Мастер (ведущий), Слушатель (подчиненный) enum eWorkModes { STANDALONE, MASTER, SLAVE } workMode, prevWorkMode; // Режим синхронизации enum eSyncModes { // Данные в E1.31 пакете PHYSIC, // соответствуют физическому порядку следования диодов в цепочке соединения матрицы (самый быстрый) LOGIC, // соответствуют логическому порядку, начиная с левого верхнего угла X,Y=0,0, далее вправо по X? затем вниз по Y (медленный, но позволяет правильно работать устройствам с разным типом подключения и размером матриц) COMMAND // пакет не содержит данных RGB светодиодов. Мастер отправляет ведомым команды на включение того или иного режима, которые ведомые устройства обрабатывают самостоятельно. } syncMode, prevSyncMode; uint16_t START_UNIVERSE = 1; // Номер начальной вселенной для прослушивания E1.31 (DMX) пакетов uint8_t UNIVERSE_COUNT = 2; // Общее количество прослушиваемых вселенных; Одна вселенная - 170 диодов. Для матрицы 16x16 достаточно двух вселенных uint16_t END_UNIVERSE = 2; // Номер конечной вселенной uint8_t syncGroup = 0, prevSyncGroup; // Номер группы синхронизации (одна группа может содержать до 7 вселенных (по протоколу управления E1.31 DMX MULTICAST), т.е для Группы 0 - 1..7 вселенные, для Группы 1 - 8..14 вселенные и т.д. uint32_t e131_last_packet; // Время поступления последнего E1.31 пакета. uint8_t e131_send_delay = 0; // Задержка миллисекунд после отправки данных мастером в канал E1.31 и до отображения сформированных данных на стороне мастера на матрицу - для визуальной синхронизации панелей MASTER-SLAVE uint8_t e131_cid[16]; // Идентификатор устройства для отправки пакета мастером по протоколу E1.31 uint16_t frameCnt = 0; // Количество принятых фреймов по потоку E1.31 за интервал времени uint32_t last_fps_time = 0; // Последнее время отображения / расчета FPS потока // В режиме синхронизации SLAVE / COMMAND uint8_t syncEffectSpeed; // Скорость эффекта uint8_t syncEffectContrast; // Контраст эффекта uint8_t syncEffectParam1; // Параметр эффекта 1 uint8_t syncEffectParam2; // Параметр эффекта 2 uint8_t masterWidth; // ширина матрицы MASTER устройства при получении пакета синхронизации uint8_t masterHeight; // высота матрицы MASTER устройства при получении пакета синхронизации #define E131_FPS_INTERVAL 10000 // Отображать FPS получаемого потока каждые 10000 мс (10 сек); Установите 0 если отображать не нужно; #define E131_TIMEOUT 2000 // Таймаут в миллисекундах получения потока E1.31. Если данных нет - переключаемся на самостоятельную работу #endif bool e131_streaming = false; // Устройство работает в режиме отправки E1.31 пакетов (MASTER) или происходит прием E1.31 пакетов (SLAVE) bool e131_wait_command = false; // Устройство работает в режиме прием E1.31 пакетов команд (SLAVE, COMMAND) // --------------- ВРЕМЕННЫЕ ПЕРЕМЕННЫЕ ПАРСЕРА ------------------ uint32_t prevColor; bool recievedFlag; // буфер содержит принятые данные bool parseStarted; uint8_t parse_index; String string_convert = ""; String receiveText = ""; bool haveIncomeData = false; char incomingByte; int16_t bufIdx = 0; // Могут приниматься пакеты > 255 байт - тип int16_t int16_t packetSize = 0; // ************************* УПРАВЛЕНИЕ МАТРИЦЕЙ ******************************* String host_name = ""; // Имя для регистрации в сети uint16_t CURRENT_LIMIT = 10000; // лимит по току в миллиамперах, автоматически управляет яркостью (пожалей свой блок питания!) 0 - выключить лимит uint8_t mapWIDTH = WIDTH; // полная ширина ширина матрицы 1..127 при использовании карты индексов uint8_t mapHEIGHT = HEIGHT; // полная высота матрицы 1..127 при использовании карты индексов uint8_t sWIDTH = WIDTH; // ширина одного сегмента матрицы 1..127 uint8_t sHEIGHT = HEIGHT; // высота одного сегмента матрицы 1..127 uint8_t sMATRIX_TYPE = MATRIX_TYPE; // тип соединения диодов в сегменте матрицы: 0 - зигзаг, 1 - параллельная, 2 - карта индексов uint8_t sCONNECTION_ANGLE = CONNECTION_ANGLE; // угол подключения диодов в сегменте: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний uint8_t sSTRIP_DIRECTION = STRIP_DIRECTION; // направление ленты из угла сегмента: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз uint8_t mWIDTH = META_MATRIX_WIDTH; // количество сегментов в ширину 1..9 uint8_t mHEIGHT = META_MATRIX_HEIGHT; // количество сегментов в высоту 1..9 uint8_t mTYPE = META_MATRIX_TYPE; // соединение сегментов мета-матрицы: 0 - зигзаг, 1 - параллельная uint8_t mANGLE = META_MATRIX_ANGLE; // угол 1-го сегмента мета-матрицы: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний uint8_t mDIRECTION = META_MATRIX_DIRECTION; // направление следующих сегментов мета-матрицы из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз uint8_t pWIDTH = sWIDTH * mWIDTH; uint8_t pHEIGHT = sHEIGHT * mHEIGHT; uint32_t NUM_LEDS = pWIDTH * pHEIGHT; uint8_t maxDim = max(pWIDTH, pHEIGHT); uint8_t minDim = min(pWIDTH, pHEIGHT); #define MAX_MAP_FILES 10 // Один файл карты индексов - одно разрешение WxH матрицы String mapFiles[MAX_MAP_FILES]; // Список имен файлов карт индексов, найденных в корне файловой системы uint8_t mapListLen = 0; #if (BIG_FONT == 0) // Шрифт размером 5x8 uint32_t OVERLAY_SIZE = pHEIGHT < 17 ? pWIDTH * pHEIGHT : pWIDTH * 17; #elif (BIG_FONT == 1) // Шрифт размером 10x16 uint32_t OVERLAY_SIZE = pWIDTH * 21; // высотв шрифта 16 + 3 строки диакритич символов над знакоместом и две - под знакоместом #else // Шрифт размером 8x13 uint32_t OVERLAY_SIZE = pWIDTH * 18; // высотв шрифта 13 + 3 строки диакритич символов над знакоместом и две - под знакоместом #endif // Часы могут отображаться: // - вертикальные при высоте матрицы >= 11 и ширине >= 7; // - горизонтальные при ширене матрицы >= 15 и высоте >= 5 // минимальная ширина горизонтальных часов - 15 символов, т.к если большие часы не помещаются по ширине - автоматически используются маленькие часы // Вычисление - в checkClockOrigin() bool allowVertical, allowHorizontal; CRGB *leds; // обращение к светодиодам матрицы через этот массив CRGB *overlayLEDs; // буфер оверлея; по максимуму - для бегущей строки во всю ширину матрицы или отображение календаря / вертикальных часов - 11 высота #define POWER_ON HIGH // Для включения питания матрицы (через MOSFET) подавать на пин POWER_PIN высокий уровень #define POWER_OFF LOW // Для вЫключения питания матрицы (через MOSFET) подавать на пин POWER_PIN низкий уровень #define TRUE_RANDOM #define DEBUG_MEM 0 // Вкл/выкл вывод отладочных сообщений об объеме свободной памяти при смене эффектов // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** // ------------------- ФАЙЛОВАЯ СИСТЕМА SPIFFS ---------------------- bool spiffs_ok = false; // Флаг - файловая система SPIFFS доступна для использования size_t spiffs_total_bytes; // Доступно байт в SPIFFS size_t spiffs_used_bytes; // Использовано байт в SPIFFS int8_t eeprom_backup = 0; // Флаг - backup настроек 0 - нeт; 1 - FS; 2 - SD; 3 - FS и SD // ------------------- ВРЕМЕННЫЕ ПЕРЕМЕННЫЕ ---------------------- bool saveSpecialMode = specialMode; int8_t saveSpecialModeId = specialModeId; uint8_t saveMode; uint8_t tmpSaveMode = 0; uint8_t resourcesMode = 0; bool mandatoryStopText = false; // --------------------------------------------------------------- #define FOR_i(from, to) for(int i = (from); i < (to); i++) #define FOR_j(from, to) for(int j = (from); j < (to); j++) #define FOR_x(from, to) for(int x = (from); x < (to); x++) #define FOR_y(from, to) for(int y = (from); y < (to); y++) // ---------------------------------------------------------------