Добавлен режим автоматического переключения избранных эффектов; Реорганизован код, исправлены ошибки

This commit is contained in:
gunner47
2019-08-26 14:35:37 +03:00
parent b2d0110a63
commit 5012ee3141
17 changed files with 704 additions and 236 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -28,6 +28,11 @@ ScreenManager
ShowScreen метод: принимает номер "экрана", устанавливает свойство видимости в true для этого экрана и в false для остальных экранов; вызывает перерисовку "экранов"
RebuildAllScreens метод: перерисовывает "экраны", делает их блоки видимыми или видимыми в зависимости от выставленных свойств видимости
CloseApplication метод: закрывает приложение
Color_DarkGrey свойство (константа): код цвета "тёмно-серый"
Color_LightGrey свойство (константа): код цвета "светло-серый"
Color_LightLightGrey свойство (константа): код цвета "светло-светло-серый"
Color_LightGreyBackground свойство (константа): код цвета "светло-серый" для фона
Color_Red свойство (константа): код цвета "красный"
MainScreen
Visible свойство: "Видимость главного экрана"
@@ -60,7 +65,7 @@ ConnectivityScreen
RemoveConnectionButtonClick метод (событие): действия при нажатии на кнопку "Удалить"
SaveAllConnectionButtonClick метод (событие): действия при нажатии на кнопку "Сканировать и добавить"
DeviceSocketListViewAfterPicking метод (событие): действия при выборе устройства из списка сохранённых и его подключение
BaсkButtonClick метод (событие): действия при UI кнопки "Назад" на "экране" устройств
BaсkButtonClick метод (событие): действия при нажатии кнопки "Назад" на "экране" устройств
UpdateConnectivityStatus метод: обновить статус устройства "Подключен"/"Отключен" на "экране" устройств
UpdateCurrentDeviceSocket метод: отобразить текущее устройство (DeviceManager.CurrentDeviceSocket) в полях ввода IP адреса и порта на "экране" устройств
UpdateCurrentDevicesSockets метод: отобразить текущий список сохранённых устройств (DeviceManager.Devices) на "экране" устройств
@@ -70,17 +75,31 @@ ConnectivityScreen
ModesScreen
Visible свойство: "Видимость экрана эффектов"
ModesListViewAfterPicking метод (событие): действия при выборе эффекта из списка эффектов
BaсkButtonClick метод (событие): действия при UI кнопки "Назад" на "экране" эффектов
BaсkButtonClick метод (событие): действия при нажатии кнопки "Назад" на "экране" эффектов
FavoritesScreen
Visible свойство: "Видимость экрана устройств"
BaсkButtonClick метод (событие): действия при UI кнопки "Назад" на "экране" избранных эффектов
Initialized свойство: "Экран автоматического переключения избранных эффектов инициализирован"
BlockControlEventsEmitting свойство: "Не генерировать события от элементов управления" (переключателей, лист пикеров и т.д.)
BaсkButtonClick метод (событие): действия при нажатии кнопки "Назад" на "экране" избранных эффектов
OnOffSwitchChanged метод (событие): действия при установке/снятии переключателя включения режима избранных эффектов
IntervalListPickerAfterPicking метод (событие): действия при выборе интервала времени (статической состявляющей) между автоматическими переключениями избранных эффектов
DispersionListPickerAfterPicking метод (событие): действия при выборе разброса времени (случайной состявляющей) между автоматическими переключениями избранных эффектов
ListViewIconClick метод (событие): действия при добавлении/удалении эффекта в/из список избранных
ListViewelementTouchUp метод (событие): служебный метод, необходимый для корректной отрисовки фона элемента в списке избранных эффектов
Initialize метод: настраивает и заполняющий специфический (кастомный) компонент ListViewer
MarkListItemAsFavorite метод: устанавливает признак включения/исключения эффекта в избранные в свойстве "состояние режима избранных эффектов"
UpdateScreen метод: обновить все элементы управления на "экране" избранных эффектов согласно модели данных
UpdateControls метод: обновить отображение элементов управления (статусы enabled/disabled) в зависимости от сохранённых свойств (модели данных)
SetFavoriteSettings метод: меняет состояние "экрана" избранных эффектов (устанавливает недоступность элементов управления и отображает анимацию) и вызывает DeviceManager.SetFavoriteSettings
SetIntervalListPicker метод: иниицализирует значение поля выбора интервала времени автоматической смены избранных эффектов согласно модели данных
SetDispersionListPicker метод: иниицализирует значение поля выбора разброса времени автоматической смены избранных эффектов согласно модели данных
AlarmScreen
Visible свойство: "Видимость экрана устройств"
Initialized свойство: "Экран управления будильниками инициализирован"
BlockControlEventsEmitting свойство: "Не генерировать события от элементов управления" (переключателей, тайм пикеров и т.д.); нужно, например, чтобы предотвратить switch.changed при его enable/disable
BaсkButtonClick метод (событие): действия при UI кнопки "Назад" на "экране" будильника
BaсkButtonClick метод (событие): действия при нажатии кнопки "Назад" на "экране" будильника
MonSwitchChanged метод (событие): действия при установке/снятии переключателя включения будильника
TueSwitchChanged метод (событие): действия при установке/снятии переключателя включения будильника
WedSwitchChanged метод (событие): действия при установке/снятии переключателя включения будильника
@@ -106,6 +125,7 @@ TimerScreen
AnimationTimerOn свойство: "таймер, управляющий анимацией функции таймера лампы, включен"
RemainingSeconds свойство: "время до срабатывания таймера лампы" и одновремнно "время до окончания работы таймера, управляющего анимацией функции таймера лампы"
TimerTickMs свойство: "шаг таймера, управляющего анимацией функции таймера лампы"
BaсkButtonClick метод (событие): действия при нажатии кнопки "Назад" на "экране" таймера
TimeListPickerAfterPicking метод (событие): действия при выборе пользователем времени до срабатывания таймера лампы (отправка команды модулю)
UpdateControls метод: обновить отображение элементов управления (статусы enabled/disabled) в зависимости от сохранённых свойств (модели данных)
UpdateScreen метод: обновить все элементы управления на "экране" управления таймером согласно модели данных
@@ -114,13 +134,13 @@ TimerScreen
HandleAnimation метод: обработать таймер, управляющий анимацией функции таймера лампы (запуск, если не запущен, принудительная остановка, если нужно)
AnimationTimerTimerNow метод: действия при срабатывании события таймера, управляющий анимацией функции таймера лампы (показать/скрыть иконку, обновить текст оставшегося времени)
StopAnimationTimer метод: остановить таймер, управляющий анимацией функции таймера лампы, сбросить его сохранённое состояние в исходное (модель данных)
BaсkButtonClick метод (событие): действия при UI кнопки "Назад" на "экране" таймера
DeviceManager
Connected свойство: подключено ли устройство (лампа)? точнее, был ли получен ответ на последнюю высланную ему команду
State свойство: полученное командой GET состояние устройства (CURR...), список (не строка)
Devices свойство: список устройств (хранимое свойство)
CurrentDeviceSocket свойство: текущее устройство (хранимое свойство)
FavoritesState свойство: текущее состояние избранных эффектов (вкл/выкл, интервал, разброс, список эффектов)
AlarmState свойство: текущее состояние будильников по дням (вкл/выкл, время каждого, время срабатывания перед "рассветом")
TimerState свойство: текущее состояние таймера (ответ команды TMR_GET)
Modes свойство: список доступных режимов, захардкожен одновременно в лампе и в приложении, должен совпадать
@@ -158,6 +178,14 @@ DeviceManager
GetTimerTimeOption метод: получить выбранное пользователем значение предуст ановки времени таймера (из свойства TimerState)
GetTimerRemainingSeconds метод: получить оставшееся до срабатывания таймера время (из свойства TimerState)
SetTimerSettings метод: отправить команду установки таймера TMR_SET
GetFavoriteSettings метод: отправить команду запроса состояния избранных эффектов FAV_GET на устройство
SetFavoriteSettings метод: отправить команду установки состояния избранных эффектов FAV_SET
GeFavoritesModeOnOff метод: получить состояние (включен/исключён в избранные) для заданного эффекта (из свойства FavoritesState)
SeFavoritesModeOnOff метод: установить состояние (включен/исключён в избранные) для заданного эффекта (из свойства FavoritesState)
GeFavoritesOnOff метод: получить состояние вкл/выкл режима избранных эффектов (из свойства FavoritesState)
GeFavoritesInterval метод: получить интервал времени смены избранных эффектов (из свойства FavoritesState)
GeFavoritesDispersion метод: получить разброс времени смены избранных эффектов (из свойства FavoritesState)
GeFavoritesModesList метод: получить список эффектов с указанным состояние (включен/исключён в избранные) для каждого из них
DiscoverManager
TimeoutMs свойство: время ожидания ответа от устройств на multicast команду DISCOVER

View File

@@ -0,0 +1,239 @@
#pragma once
/*
* Схема использования EEPROM памяти:
* Используются адреса:
* Начало Длина Описание
* массив alarm
* 0 1 будильник пн вкл/выкл
* 1-2 2 будильник пн время в минутах от начала суток (0 - 1440), должно быть 2 байта
* 3 1 будильник вт вкл/выкл
* 4-5 2 будильник вт время в минутах от начала суток (0 - 1440), должно быть 2 байта
* 6 1 будильник ср вкл/выкл
* 7-8 2 будильник ср время в минутах от начала суток (0 - 1440), должно быть 2 байта
* 9 1 будильник чт вкл/выкл
* 10-11 2 будильник чт время в минутах от начала суток (0 - 1440), должно быть 2 байта
* 12 1 будильник пт вкл/выкл
* 13-14 2 будильник пт время в минутах от начала суток (0 - 1440), должно быть 2 байта
* 15 1 будильник сб вкл/выкл
* 16-17 2 будильник сб время в минутах от начала суток (0 - 1440), должно быть 2 байта
* 18 1 будильник вс вкл/выкл
* 19-20 2 будильник вс время в минутах от начала суток (0 - 1440), должно быть 2 байта
* массив modes
* 21-23 3 режим №1: яркость, скорость, масштаб (по одному байту)
* 24-26 3 режим №2: яркость, скорость, масштаб (по одному байту)
* 27-29 3 режим №3: яркость, скорость, масштаб (по одному байту)
* 30-32 3 режим №4: яркость, скорость, масштаб (по одному байту)
* 33-35 3 режим №5: яркость, скорость, масштаб (по одному байту)
* 36-38 3 режим №6: яркость, скорость, масштаб (по одному байту)
* 39-41 3 режим №7: яркость, скорость, масштаб (по одному байту)
* 42-44 3 режим №8: яркость, скорость, масштаб (по одному байту)
* 45-47 3 режим №9: яркость, скорость, масштаб (по одному байту)
* 48-50 3 режим №10: яркость, скорость, масштаб (по одному байту)
* 51-53 3 режим №11: яркость, скорость, масштаб (по одному байту)
* 54-56 3 режим №12: яркость, скорость, масштаб (по одному байту)
* 57-59 3 режим №13: яркость, скорость, масштаб (по одному байту)
* 60-62 3 режим №14: яркость, скорость, масштаб (по одному байту)
* 63-65 3 режим №15: яркость, скорость, масштаб (по одному байту)
* 66-68 3 режим №16: яркость, скорость, масштаб (по одному байту)
* 69-71 3 режим №17: яркость, скорость, масштаб (по одному байту)
* 72-74 3 режим №18: яркость, скорость, масштаб (по одному байту)
* 75-77 3 режим №19: яркость, скорость, масштаб (по одному байту)
* 78-80 3 режим №20: яркость, скорость, масштаб (по одному байту)
*
* 111-134 24 настройки режима избранных эффектов (интервал - 2 байта; разброс - 2 байта; вкл/выкл каждого эффекта - 20 (MODE_AMOUNT) байт; вкл/выкл не хранится в EEPROM)
*
* 198 1 признак первого запуска (определяет необходимость первоначальной записи всех хранимых настроек)
* 199 1 время до "рассвета" (dawnMode)
* 200 1 текущий режим (currentMode)
*
* Не используются адреса:
* 81-110 30 резерв, можно добавить ещё 10 эффектов
* 135-197 63 если добавить ещё 10 эффектов, начальный адрес неиспользуемой памяти сдвинется с 135 на 145
*/
#include <EEPROM.h>
#include "Types.h"
#define EEPROM_TOTAL_BYTES_USED (201U) // общий размер используемой EEPROM памяти (сумма всех хранимых настроек + 1 байт)
#define EEPROM_ALARM_START_ADDRESS (0U) // начальный адрес в EEPROM памяти для записи настроек будильников
#define EEPROM_MODES_START_ADDRESS (21U) // начальный адрес в EEPROM памяти для записи настроек эффектов (яркость, скорость, масштаб)
#define EEPROM_FAVORITES_START_ADDRESS (111U) // начальный адрес в EEPROM памяти для записи настроек режима избранных эффектов
#define EEPROM_FIRST_RUN_ADDRESS (198U) // адрес в EEPROM памяти для записи признака первого запуска (определяет необходимость первоначальной записи всех хранимых настроек)
#define EEPROM_DAWN_MODE_ADDRESS (199U) // адрес в EEPROM памяти для записи времени до "рассвета"
#define EEPROM_CURRENT_MODE_ADDRESS (200U) // адрес в EEPROM памяти для записи номера текущего эффекта лампы
#define EEPROM_ALARM_STRUCT_SIZE (3U) // 1 байт - вкл/выкл; 2 байта - время от начала суток в минутах (0 - 1440)
#define EEPROM_MODE_STRUCT_SIZE (3U) // 1 байт - яркость; 1 байт - скорость; 1 байт - масштаб
#define EEPROM_FIRST_RUN_MARK (22U) // счисло-метка, если ещё не записно в EEPROM_FIRST_RUN_ADDRESS, значит нужно проинициализировать EEPROM и записать все первоначальные настройки
#define EEPROM_WRITE_DELAY (30000UL) // отсрочка записи в EEPROM после последнего изменения хранимых настроек, позволяет уменьшить количество операций записи в EEPROM
class EepromManager
{
public:
static void InitEepromSettings(ModeType modes[], AlarmType alarms[], uint8_t* dawnMode, int8_t* currentMode,
void (*readFavoritesSettings)(), void (*saveFavoritesSettings)())
{
// записываем в EEPROM начальное состояние настроек, если их там ещё нет
EEPROM.begin(EEPROM_TOTAL_BYTES_USED);
delay(50);
if (EEPROM.read(EEPROM_FIRST_RUN_ADDRESS) != EEPROM_FIRST_RUN_MARK)
{
EEPROM.write(EEPROM_FIRST_RUN_ADDRESS, EEPROM_FIRST_RUN_MARK);
EEPROM.commit();
for (uint8_t i = 0; i < MODE_AMOUNT; i++)
{
EEPROM.put(EEPROM_MODES_START_ADDRESS + EEPROM_ALARM_STRUCT_SIZE * i, modes[i]);
EEPROM.commit();
}
for (uint8_t i = 0; i < 7; i++)
{
EEPROM.write(EEPROM_ALARM_START_ADDRESS + EEPROM_ALARM_STRUCT_SIZE * i, alarms[i].State);
WriteUint16(EEPROM_ALARM_START_ADDRESS + EEPROM_ALARM_STRUCT_SIZE * i + 1, alarms[i].Time);
EEPROM.commit();
}
EEPROM.write(EEPROM_DAWN_MODE_ADDRESS, 0);
EEPROM.write(EEPROM_CURRENT_MODE_ADDRESS, 0);
saveFavoritesSettings();
EEPROM.commit();
}
// инициализируем настройки лампы значениями из EEPROM
for (uint8_t i = 0; i < MODE_AMOUNT; i++)
{
EEPROM.get(EEPROM_MODES_START_ADDRESS + EEPROM_MODE_STRUCT_SIZE * i, modes[i]);
}
for (uint8_t i = 0; i < 7; i++)
{
alarms[i].State = EEPROM.read(EEPROM_ALARM_START_ADDRESS + EEPROM_ALARM_STRUCT_SIZE * i);
alarms[i].Time = ReadInt16(EEPROM_ALARM_START_ADDRESS + EEPROM_ALARM_STRUCT_SIZE * i + 1);
}
readFavoritesSettings();
*dawnMode = EEPROM.read(EEPROM_DAWN_MODE_ADDRESS);
*currentMode = EEPROM.read(EEPROM_CURRENT_MODE_ADDRESS);
}
static void SaveModesSettings(int8_t* currentMode, ModeType modes[])
{
EEPROM.put(3 * (*currentMode) + EEPROM_MODES_START_ADDRESS, modes[*currentMode]);
EEPROM.commit();
}
static void HandleEepromTick(bool* settChanged, uint32_t* eepromTimer, int8_t* currentMode, ModeType modes[], void (*saveFavoritesSettings)())
{
if (*settChanged && millis() - *eepromTimer > EEPROM_WRITE_DELAY)
{
*settChanged = false;
*eepromTimer = millis();
SaveModesSettings(currentMode, modes);
if (EEPROM.read(EEPROM_CURRENT_MODE_ADDRESS) != *currentMode)
{
EEPROM.write(EEPROM_CURRENT_MODE_ADDRESS, *currentMode);
}
saveFavoritesSettings();
EEPROM.commit();
}
}
static void SaveAlarmsSettings(uint8_t* alarmNumber, AlarmType alarms[])
{
EEPROM.write(5 * (*alarmNumber), alarms[*alarmNumber].State);
WriteUint16((uint16_t)(5 * (*alarmNumber) + 1), alarms[*alarmNumber].Time);
EEPROM.commit();
}
static void SaveDawnMode(uint8_t* dawnMode)
{
EEPROM.write(EEPROM_DAWN_MODE_ADDRESS, *dawnMode);
EEPROM.commit();
}
static uint16_t ReadUint16(uint16_t address)
{
uint16_t val;
uint8_t* p = (uint8_t*)&val;
*p = EEPROM.read(address);
*(p + 1) = EEPROM.read(address + 1);
return val;
}
static void WriteUint16(uint16_t address, uint16_t val)
{
uint8_t* p = (uint8_t*)&val;
EEPROM.write(address, *p);
EEPROM.write(address + 1, *(p + 1));
EEPROM.commit();
}
static int16_t ReadInt16(uint16_t address)
{
int16_t val;
uint8_t* p = (uint8_t*)&val;
*p = EEPROM.read(address);
*(p + 1) = EEPROM.read(address + 1);
return val;
}
static void WriteInt16(uint16_t address, int16_t val)
{
uint8_t* p = (uint8_t*)&val;
EEPROM.write(address, *p);
EEPROM.write(address + 1, *(p + 1));
EEPROM.commit();
}
static uint32_t ReadUint32(uint16_t address)
{
uint32_t val;
uint8_t* p = (uint8_t*)&val;
*p = EEPROM.read(address);
*(p + 1) = EEPROM.read(address + 1);
*(p + 2) = EEPROM.read(address + 2);
*(p + 3) = EEPROM.read(address + 3);
return val;
}
static void WriteUint32(uint16_t address, uint32_t val)
{
uint8_t* p = (uint8_t*)&val;
EEPROM.write(address, *p);
EEPROM.write(address + 1, *(p + 1));
EEPROM.write(address + 2, *(p + 2));
EEPROM.write(address + 3, *(p + 3));
EEPROM.commit();
}
static int32_t ReadInt32(uint16_t address)
{
int32_t val;
uint8_t* p = (uint8_t*)&val;
*p = EEPROM.read(address);
*(p + 1) = EEPROM.read(address + 1);
*(p + 2) = EEPROM.read(address + 2);
*(p + 3) = EEPROM.read(address + 3);
return val;
}
static void WriteInt32(uint16_t address, int32_t val)
{
uint8_t* p = (uint8_t*)&val;
EEPROM.write(address, *p);
EEPROM.write(address + 1, *(p + 1));
EEPROM.write(address + 2, *(p + 2));
EEPROM.write(address + 3, *(p + 3));
EEPROM.commit();
}
private:
};

View File

@@ -0,0 +1,245 @@
#pragma once
#include <EEPROM.h>
#include "EepromManager.h"
#define DEFAULT_FAVORITES_INTERVAL (300U) // значение по умолчанию для интервала переключения избпранных эффектов в секундах
#define DEFAULT_FAVORITES_DISPERSION (0U) // значение по умолчанию для разброса интервала переключения избпранных эффектов в секундах
class FavoritesManager
{
public:
static bool FavoritesRunning; // флаг "работает режим автоматической смены избранных эффектов"
static uint16_t Interval; // статический интервал (время между сменами эффектов)
static uint16_t Dispersion; // дополнительный динамический (случайный) интервал (время между сменами эффектов)
static uint8_t FavoriteModes[MODE_AMOUNT]; // массив, каждый элемент которого соответствует флагу "эффект №... добавлен в избранные"
static void SetStatus(char* statusText) // помещает в statusText состояние режима работы избранных эффектов
{
char buff[6];
statusText = "FAV ";
statusText = strcat(statusText, FavoritesRunning ? "1" : "0");
statusText = strcat(statusText, " ");
itoa(Interval, buff, 10);
statusText = strcat(statusText, buff);
statusText = strcat(statusText, " ");
buff[0] = '\0';
itoa(Dispersion, buff, 10);
statusText = strcat(statusText, buff);
statusText = strcat(statusText, " ");
buff[0] = '\0';
for (uint8_t i = 0; i < MODE_AMOUNT; i++)
{
itoa((uint8_t)FavoriteModes[i], buff, 10);
statusText = strcat(statusText, buff);
if (i < MODE_AMOUNT - 1) statusText = strcat(statusText, " ");
buff[0] = '\0';
}
statusText = strcat(statusText, "\0");
}
static void ConfigureFavorites(const char* statusText) // принимает statusText, парсит его и инициализирует свойства класса значениями из statusText'а
{
FavoritesRunning = getFavoritesRunning(statusText);
Interval = getInterval(statusText);
Dispersion = getDispersion(statusText);
for (uint8_t i = 0; i < MODE_AMOUNT; i++)
{
FavoriteModes[i] = getModeOnOff(statusText, i);
}
}
static bool HandleFavorites( // функция, обрабатывающая циклическое переключение избранных эффектов; возвращает true, если эффект был переключен
bool* ONflag,
int8_t* currentMode,
bool* loadingFlag
#ifdef USE_NTP
, bool* dawnFlag
#endif
)
{
if (!FavoritesRunning ||
!*ONflag // лампа не переключается на следующий эффект при выключенной матрице
#ifdef USE_NTP
|| *dawnFlag // лампа не переключается на следующий эффект при включенном будильнике
#endif
)
{
return false;
}
if (nextModeAt == 0) // лампа не переключается на следующий эффект сразу после включения режима избранных эффектов
{
nextModeAt = getNexTime();
return false;
}
if (millis() >= nextModeAt)
{
*currentMode = getNextFavoriteMode(currentMode);
*loadingFlag = true;
nextModeAt = getNexTime();
#ifdef GENERAL_DEBUG
Serial.printf("Переключение на следующий избранный режим: %d\n\n", (*currentMode));
#endif
return true;
}
return false;
}
static void ReadFavoritesFromEeprom()
{
Interval = EepromManager::ReadUint16(EEPROM_FAVORITES_START_ADDRESS);
Dispersion = EepromManager::ReadUint16(EEPROM_FAVORITES_START_ADDRESS + 2);
for (uint8_t i = 0; i < MODE_AMOUNT; i++)
{
FavoriteModes[i] = EEPROM.read(EEPROM_FAVORITES_START_ADDRESS + i + 4);
FavoriteModes[i] = FavoriteModes[i] > 0 ? 1 : 0;
}
}
static void SaveFavoritesToEeprom()
{
// FavoritesRunning в EEPROM не сохраняем для экономии ресурса памяти
EepromManager::WriteUint16(EEPROM_FAVORITES_START_ADDRESS, Interval);
EepromManager::WriteUint16(EEPROM_FAVORITES_START_ADDRESS + 2, Dispersion);
for (uint8_t i = 0; i < MODE_AMOUNT; i++)
{
EEPROM.put(EEPROM_FAVORITES_START_ADDRESS + i + 4, FavoriteModes[i] > 0 ? 1 : 0);
}
EEPROM.commit();
}
private:
static uint32_t nextModeAt; // ближайшее время переключения на следующий избранный эффект (millis())
static bool isStatusTextCorrect(const char* statusText) // валидирует statusText (проверяет, правильное ли коичество компонентов он содержит)
{
char buff[64];
strcpy(buff, statusText);
uint8_t lexCount = 0;
char* p = strtok(buff, " ");
while (p != NULL) // пока есть лексемы...
{
lexCount++;
p = strtok(NULL, " ");
}
return lexCount == getStatusTextNormalComponentsCount();
}
static uint8_t getStatusTextNormalComponentsCount() // возвращает правильное ли коичество компонентов для statusText в зависимости от определённого формата команды и количества эффектов
{
// "FAV 0/1 <цифра> <цифра> <массив цифр 0/1 для каждого режима>" (вкл/выкл, интервал в секундах, разброс в секундах, вкл/выкл каждого эффекта в избранные)
return
1 + // "FAV"
1 + // On/Off
1 + // интервал
1 + // разброс
MODE_AMOUNT; // 0/1 для каждого эффекта
}
static bool getFavoritesRunning(const char* statusText) // возвращает признак вкл/выкл режима избранных эффектов из statusText
{
char lexem[2];
memset(lexem, 0, 2);
strcpy(lexem, getLexNo(statusText, 1));
return lexem != NULL
? !strcmp(lexem, "1")
: false;
}
static uint16_t getInterval(const char* statusText) // возвращает интервал (постоянную составляющую) переключения избранных эффектов из statusText
{
char lexem[6];
memset(lexem, 0, 6);
strcpy(lexem, getLexNo(statusText, 2));
return lexem != NULL
? atoi((const char*)lexem)
: DEFAULT_FAVORITES_INTERVAL;
}
static uint16_t getDispersion(const char* statusText) // возвращает разброс (случайную составляющую) интервала переключения избранных эффектов из statusText
{
char lexem[6];
memset(lexem, 0, 6);
strcpy(lexem, getLexNo(statusText, 3));
return lexem != NULL
? atoi((const char*)lexem)
: DEFAULT_FAVORITES_DISPERSION;
}
static bool getModeOnOff(const char* statusText, uint8_t modeId) // возвращает признак включения указанного эффекта в избранные эффекты
{
char lexem[2];
memset(lexem, 0, 2);
strcpy(lexem, getLexNo(statusText, modeId + 4));
return lexem != NULL
? !strcmp(lexem, "1")
: false;
}
static char* getLexNo(const char* statusText, uint8_t pos) // служебная функция, разбивает команду statusText на лексемы ("слова", разделённые пробелами) и возвращает указанную по счёту лексему
{
if (!isStatusTextCorrect(statusText))
{
return NULL;
}
const uint8_t buffSize = 64;
char buff[buffSize];
memset(buff, 0, buffSize);
strcpy(buff, statusText);
uint8_t lexPos = 0;
char* p = strtok(buff, " ");
while (p != NULL) // пока есть лексемы...
{
if (lexPos == pos)
{
return p;
}
p = strtok(NULL, " ");
lexPos++;
}
return NULL;
}
static int8_t getNextFavoriteMode(int8_t* currentMode) // возвращает следующий (случайный) включенный в избранные эффект
{
int8_t result = *currentMode;
for (int8_t tryNo = 0; tryNo <= random(0, MODE_AMOUNT); tryNo++)// случайное количество попыток определения следующего эффекта; без этого будет выбран следующий (избранный) по порядку после текущего
{
for (uint8_t i = (result + 1); i <= (result + MODE_AMOUNT); i++)
{
if (FavoriteModes[i < MODE_AMOUNT ? i : i - MODE_AMOUNT] > 0)
{
result = i < MODE_AMOUNT ? i : i - MODE_AMOUNT;
break;
}
}
}
return result;
}
static uint32_t getNexTime() // определяет время следующего переключения на следующий избранный эффект
{
return millis() + Interval * 1000 + random(0, Dispersion + 1) * 1000;
}
};

View File

@@ -44,6 +44,9 @@
- Добавлено взаимодействие с android приложением по управлению будильниками
--- 14.08.2019
- Добавлена функция таймера отключения
--- 26.08.2019
- Добавлен режим автоматического переключения избранных эффектов
- Реорганизован код, исправлены ошибки
*/
// Ссылка для менеджера плат:
@@ -112,6 +115,7 @@ uint8_t AP_STATIC_IP[] = {192, 168, 4, 1}; // статичес
#define FASTLED_ALLOW_INTERRUPTS (0U)
#define FASTLED_ESP8266_RAW_PIN_ORDER
#include "Types.h"
#include "timerMinim.h"
#include <FastLED.h>
#include <ESP8266WiFi.h>
@@ -130,6 +134,8 @@ uint8_t AP_STATIC_IP[] = {192, 168, 4, 1}; // статичес
#include "OtaManager.h"
#endif
#include "TimerManager.h"
#include "FavoritesManager.h"
#include "EepromManager.h"
// --- ИНИЦИАЛИЗАЦИЯ ОБЪЕКТОВ ----------
CRGB leds[NUM_LEDS];
@@ -158,34 +164,25 @@ char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1]; // buffer to hold in
String inputBuffer;
static const uint8_t maxDim = max(WIDTH, HEIGHT);
struct
{
uint8_t brightness = 50;
uint8_t speed = 30;
uint8_t scale = 40;
} modes[MODE_AMOUNT];
struct
{
boolean state = false;
int16_t time = 0;
} alarm[7];
ModeType modes[MODE_AMOUNT];
AlarmType alarms[7];
uint8_t dawnOffsets[] = {5, 10, 15, 20, 25, 30, 40, 50, 60};// опции для выпадающего списка параметра "время перед 'рассветом'" (будильник)
uint8_t dawnMode;
boolean dawnFlag = false;
bool dawnFlag = false;
long thisTime;
boolean manualOff = false;
bool manualOff = false;
int8_t currentMode = 0;
boolean loadingFlag = true;
boolean ONflag = true;
bool loadingFlag = true;
bool ONflag = true;
uint32_t eepromTimer;
boolean settChanged = false;
bool settChanged = false;
// Конфетти, Огонь, Радуга верт., Радуга гориз., Смена цвета,
// Конфетти, Огонь, Радуга вертикальная, Радуга горизонтальная, Смена цвета,
// Безумие 3D, Облака 3D, Лава 3D, Плазма 3D, Радуга 3D,
// Павлин 3D, Зебра 3D, Лес 3D, Океан 3D,
// Цвет, Снег, Матрица, Светлячки, Светлячки со шлейфом, Белый свет
unsigned char matrixValue[8][16];
@@ -194,6 +191,12 @@ bool TimerManager::TimerHasFired = false;
uint8_t TimerManager::TimerOption = 1U;
uint64_t TimerManager::TimeToFire = 0ULL;
bool FavoritesManager::FavoritesRunning = false;
uint16_t FavoritesManager::Interval = DEFAULT_FAVORITES_INTERVAL;
uint16_t FavoritesManager::Dispersion = DEFAULT_FAVORITES_DISPERSION;
uint8_t FavoritesManager::FavoriteModes[MODE_AMOUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint32_t FavoritesManager::nextModeAt = 0UL;
void setup()
{
@@ -286,47 +289,12 @@ void setup()
Serial.printf("Порт UDP сервера: %u\n", localPort);
Udp.begin(localPort);
// EEPROM
EEPROM.begin(202);
delay(50);
if (EEPROM.read(198) != 20) // первый запуск
{
EEPROM.write(198, 20);
EEPROM.commit();
EepromManager::InitEepromSettings( // инициализация EEPROM; запись начального состояния настроек, если их там ещё нет; инициализация настроек лампы значениями из EEPROM
modes, alarms, &dawnMode, &currentMode,
&(FavoritesManager::ReadFavoritesFromEeprom),
&(FavoritesManager::SaveFavoritesToEeprom));
for (uint8_t i = 0; i < MODE_AMOUNT; i++)
{
EEPROM.put(3 * i + 40, modes[i]);
EEPROM.commit();
}
for (uint8_t i = 0; i < 7; i++)
{
EEPROM.write(5 * i, alarm[i].state); // рассвет
eeWriteInt(5 * i + 1, alarm[i].time);
EEPROM.commit();
}
EEPROM.write(199, 0); // рассвет
EEPROM.write(200, 0); // режим
EEPROM.commit();
}
for (uint8_t i = 0; i < MODE_AMOUNT; i++)
{
EEPROM.get(3 * i + 40, modes[i]);
}
for (uint8_t i = 0; i < 7; i++)
{
alarm[i].state = EEPROM.read(5 * i);
alarm[i].time = eeGetInt(5 * i + 1);
}
dawnMode = EEPROM.read(199);
currentMode = (int8_t)EEPROM.read(200);
sendCurrent(); // отправляем настройки
sendCurrent(); // отправляем настройки (куда?)
char reply[inputBuffer.length() + 1];
inputBuffer.toCharArray(reply, inputBuffer.length() + 1);
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
@@ -347,7 +315,7 @@ void loop()
{
parseUDP();
effectsTick();
eepromTick();
EepromManager::HandleEepromTick(&settChanged, &eepromTimer, &currentMode, modes, &(FavoritesManager::SaveFavoritesToEeprom));
#ifdef USE_NTP
timeTick();
#endif
@@ -358,29 +326,19 @@ void loop()
otaManager.HandleOtaUpdate(); // ожидание и обработка команды на обновление прошивки по воздуху
#endif
TimerManager::HandleTimer(&ONflag, &changePower); // обработка событий таймера отключения лампы
if (FavoritesManager::HandleFavorites( // обработка режима избранных эффектов
&ONflag,
&currentMode,
&loadingFlag
#ifdef USE_NTP
, &dawnFlag
#endif
))
{
FastLED.setBrightness(modes[currentMode].Brightness);
FastLED.clear();
delay(1);
}
ESP.wdtFeed(); // пнуть собаку
yield(); // обработать все "служебные" задачи: WiFi подключение и т.д.
}
void eeWriteInt(int16_t pos, int16_t val)
{
uint8_t* p = (uint8_t*) &val;
EEPROM.write(pos, *p);
EEPROM.write(pos + 1, *(p + 1));
EEPROM.write(pos + 2, *(p + 2));
EEPROM.write(pos + 3, *(p + 3));
EEPROM.commit();
}
int16_t eeGetInt(int16_t pos)
{
int16_t val;
uint8_t* p = (uint8_t*) &val;
*p = EEPROM.read(pos);
*(p + 1) = EEPROM.read(pos + 1);
*(p + 2) = EEPROM.read(pos + 2);
*(p + 3) = EEPROM.read(pos + 3);
return val;
yield(); // обработать все "служебные" задачи: wdt, WiFi подключение и т.д. (?)
}

View File

@@ -1,3 +1,4 @@
#pragma once
/*
* 11.07.2019
* Класс, который отслеживает действия пользователя по запросу обновления прошивки по воздуху и выполняет эту прошивку.

View File

@@ -1,3 +1,6 @@
#pragma once
class TimerManager
{
public:
@@ -7,7 +10,7 @@ class TimerManager
static uint64_t TimeToFire; // время, в которое должен сработать таймер (millis)
static void HandleTimer( // функция, обрабатывающая срабатывание таймера, гасит матрицу
bool *ONflag,
bool* ONflag,
void (*changePower)())
{
if (!TimerManager::TimerHasFired &&

View File

@@ -0,0 +1,15 @@
#pragma once
struct AlarmType
{
bool State = false;
uint16_t Time = 0;
};
struct ModeType
{
uint8_t Brightness = 50;
uint8_t Speed = 30;
uint8_t Scale = 40;
};

View File

@@ -1,5 +1,5 @@
#ifdef ESP_USE_BUTTON
boolean brightDirection;
bool brightDirection;
void buttonTick()
{
@@ -11,7 +11,7 @@ void buttonTick()
manualOff = true;
dawnFlag = false;
loadingFlag = true;
FastLED.setBrightness(modes[currentMode].brightness);
FastLED.setBrightness(modes[currentMode].Brightness);
changePower();
}
else
@@ -24,7 +24,7 @@ void buttonTick()
if (ONflag && touch.isDouble())
{
if (++currentMode >= MODE_AMOUNT) currentMode = 0;
FastLED.setBrightness(modes[currentMode].brightness);
FastLED.setBrightness(modes[currentMode].Brightness);
loadingFlag = true;
settChanged = true;
eepromTimer = millis();
@@ -35,7 +35,7 @@ void buttonTick()
if (ONflag && touch.isTriple())
{
if (--currentMode < 0) currentMode = MODE_AMOUNT - 1;
FastLED.setBrightness(modes[currentMode].brightness);
FastLED.setBrightness(modes[currentMode].Brightness);
loadingFlag = true;
settChanged = true;
eepromTimer = millis();
@@ -64,22 +64,22 @@ void buttonTick()
{
if (brightDirection)
{
if (modes[currentMode].brightness < 10) modes[currentMode].brightness += 1;
else if (modes[currentMode].brightness < 250) modes[currentMode].brightness += 5;
else modes[currentMode].brightness = 255;
if (modes[currentMode].Brightness < 10) modes[currentMode].Brightness += 1;
else if (modes[currentMode].Brightness < 250) modes[currentMode].Brightness += 5;
else modes[currentMode].Brightness = 255;
}
else
{
if (modes[currentMode].brightness > 15) modes[currentMode].brightness -= 5;
else if (modes[currentMode].brightness > 1) modes[currentMode].brightness -= 1;
else modes[currentMode].brightness = 0;
if (modes[currentMode].Brightness > 15) modes[currentMode].Brightness -= 5;
else if (modes[currentMode].Brightness > 1) modes[currentMode].Brightness -= 1;
else modes[currentMode].Brightness = 0;
}
FastLED.setBrightness(modes[currentMode].brightness);
FastLED.setBrightness(modes[currentMode].Brightness);
settChanged = true;
eepromTimer = millis();
#ifdef GENERAL_DEBUG
Serial.printf("New brightness value: %d\n", modes[currentMode].brightness);
Serial.printf("New brightness value: %d\n", modes[currentMode].Brightness);
#endif
}
}

View File

@@ -1,30 +0,0 @@
void saveEEPROM()
{
EEPROM.put(3 * currentMode + 40, modes[currentMode]);
EEPROM.commit();
}
void eepromTick()
{
if (settChanged && millis() - eepromTimer > 30000)
{
settChanged = false;
eepromTimer = millis();
saveEEPROM();
if (EEPROM.read(200) != currentMode) EEPROM.write(200, currentMode);
EEPROM.commit();
}
}
void saveAlarm(byte almNumber)
{
EEPROM.write(5 * almNumber, alarm[almNumber].state); // рассвет
eeWriteInt(5 * almNumber + 1, alarm[almNumber].time);
EEPROM.commit();
}
void saveDawnMmode()
{
EEPROM.write(199, dawnMode); // рассвет
EEPROM.commit();
}

View File

@@ -4,51 +4,32 @@ void effectsTick()
{
if (!dawnFlag)
{
if (ONflag && (millis() - effTimer >= ((currentMode < 5 || currentMode > 13) ? modes[currentMode].speed : 50)))
if (ONflag && (millis() - effTimer >= ((currentMode < 5 || currentMode > 13) ? modes[currentMode].Speed : 50)))
{
effTimer = millis();
switch (currentMode)
{
case 0: sparklesRoutine();
break;
case 1: fireRoutine();
break;
case 2: rainbowVertical();
break;
case 3: rainbowHorizontal();
break;
case 4: colorsRoutine();
break;
case 5: madnessNoise();
break;
case 6: cloudNoise();
break;
case 7: lavaNoise();
break;
case 8: plasmaNoise();
break;
case 9: rainbowNoise();
break;
case 10: rainbowStripeNoise();
break;
case 11: zebraNoise();
break;
case 12: forestNoise();
break;
case 13: oceanNoise();
break;
case 14: colorRoutine();
break;
case 15: snowRoutine();
break;
case 16: matrixRoutine();
break;
case 17: lightersRoutine();
break;
case 18: lightBalls();
break;
case 19: whiteColor();
break;
case 0: sparklesRoutine(); break;
case 1: fireRoutine(); break;
case 2: rainbowVertical(); break;
case 3: rainbowHorizontal(); break;
case 4: colorsRoutine(); break;
case 5: madnessNoise(); break;
case 6: cloudNoise(); break;
case 7: lavaNoise(); break;
case 8: plasmaNoise(); break;
case 9: rainbowNoise(); break;
case 10: rainbowStripeNoise(); break;
case 11: zebraNoise(); break;
case 12: forestNoise(); break;
case 13: oceanNoise(); break;
case 14: colorRoutine(); break;
case 15: snowRoutine(); break;
case 16: matrixRoutine(); break;
case 17: lightersRoutine(); break;
case 18: lightBalls(); break;
case 19: whiteColor(); break;
default: break;
}
FastLED.show();
}
@@ -60,20 +41,20 @@ void changePower()
if (ONflag)
{
effectsTick();
for (uint8_t i = 0; i < modes[currentMode].brightness; i = constrain(i + 8, 0, modes[currentMode].brightness))
for (uint8_t i = 0; i < modes[currentMode].Brightness; i = constrain(i + 8, 0, modes[currentMode].Brightness))
{
FastLED.setBrightness(i);
delay(1);
FastLED.show();
}
FastLED.setBrightness(modes[currentMode].brightness);
FastLED.setBrightness(modes[currentMode].Brightness);
delay(2);
FastLED.show();
}
else
{
effectsTick();
for (uint8_t i = modes[currentMode].brightness; i > 0; i = constrain(i - 8, 0, modes[currentMode].brightness))
for (uint8_t i = modes[currentMode].Brightness; i > 0; i = constrain(i - 8, 0, modes[currentMode].Brightness))
{
FastLED.setBrightness(i);
delay(1);

View File

@@ -3,7 +3,7 @@
// ------------- конфетти --------------
void sparklesRoutine()
{
for (uint8_t i = 0; i < modes[0].scale; i++)
for (uint8_t i = 0; i < modes[0].Scale; i++)
{
uint8_t x = random(0, WIDTH);
uint8_t y = random(0, HEIGHT);
@@ -144,7 +144,7 @@ void drawFrame(int32_t pcnt)
- pgm_read_byte(&(valueMask[y][newX]));
CRGB color = CHSV(
modes[1].scale * 2.5 + pgm_read_byte(&(hueMask[y][newX])), // H
modes[1].Scale * 2.5 + pgm_read_byte(&(hueMask[y][newX])), // H
255, // S
(uint8_t)max(0, nextv) // V
);
@@ -172,7 +172,7 @@ void drawFrame(int32_t pcnt)
uint8_t newX = x;
if (x > 15) newX = x - 15;
CRGB color = CHSV(
modes[1].scale * 2.5 + pgm_read_byte(&(hueMask[0][newX])), // H
modes[1].Scale * 2.5 + pgm_read_byte(&(hueMask[0][newX])), // H
255, // S
(uint8_t)(((100.0 - pcnt) * matrixValue[0][newX] + pcnt * line[newX]) / 100.0) // V
);
@@ -187,7 +187,7 @@ void rainbowVertical()
hue += 2;
for (uint8_t j = 0; j < HEIGHT; j++)
{
CHSV thisColor = CHSV((uint8_t)(hue + j * modes[2].scale), 255, 255);
CHSV thisColor = CHSV((uint8_t)(hue + j * modes[2].Scale), 255, 255);
for (uint8_t i = 0; i < WIDTH; i++)
drawPixelXY(i, j, thisColor);
}
@@ -198,7 +198,7 @@ void rainbowHorizontal()
hue += 2;
for (uint8_t i = 0; i < WIDTH; i++)
{
CHSV thisColor = CHSV((uint8_t)(hue + i * modes[3].scale), 255, 255);
CHSV thisColor = CHSV((uint8_t)(hue + i * modes[3].Scale), 255, 255);
for (uint8_t j = 0; j < HEIGHT; j++)
drawPixelXY(i, j, thisColor); //leds[getPixelNumber(i, j)] = thisColor;
}
@@ -207,7 +207,7 @@ void rainbowHorizontal()
// ------------- цвета -----------------
void colorsRoutine()
{
hue += modes[4].scale;
hue += modes[4].Scale;
for (int32_t i = 0; i < NUM_LEDS; i++)
{
leds[i] = CHSV(hue, 255, 255);
@@ -219,7 +219,7 @@ void colorRoutine()
{
for (int32_t i = 0; i < NUM_LEDS; i++)
{
leds[i] = CHSV(modes[14].scale * 2.5, 255, 255);
leds[i] = CHSV(modes[14].Scale * 2.5, 255, 255);
}
}
@@ -239,7 +239,7 @@ void snowRoutine()
{
// заполняем случайно верхнюю строку
// а также не даём двум блокам по вертикали вместе быть
if (getPixColorXY(x, HEIGHT - 2) == 0 && (random(0, 100 - modes[15].scale) == 0))
if (getPixColorXY(x, HEIGHT - 2) == 0 && (random(0, 100 - modes[15].Scale) == 0))
drawPixelXY(x, HEIGHT - 1, 0xE0FFFF - 0x101010 * random(0, 4));
else
drawPixelXY(x, HEIGHT - 1, 0x000000);
@@ -254,7 +254,7 @@ void matrixRoutine()
// заполняем случайно верхнюю строку
uint32_t thisColor = getPixColorXY(x, HEIGHT - 1);
if (thisColor == 0)
drawPixelXY(x, HEIGHT - 1, 0x00FF00 * (random(0, 100 - modes[16].scale) == 0));
drawPixelXY(x, HEIGHT - 1, 0x00FF00 * (random(0, 100 - modes[16].Scale) == 0));
else if (thisColor < 0x002000)
drawPixelXY(x, HEIGHT - 1, 0);
else
@@ -299,7 +299,7 @@ void lightersRoutine()
}
FastLED.clear();
if (++loopCounter > 20) loopCounter = 0;
for (uint8_t i = 0; i < modes[17].scale; i++)
for (uint8_t i = 0; i < modes[17].Scale; i++)
{
if (loopCounter == 0) // меняем скорость каждые 255 отрисовок
{

View File

@@ -37,8 +37,8 @@ void madnessNoise()
if (loadingFlag)
{
loadingFlag = false;
scale = modes[5].scale;
speed = modes[5].speed;
scale = modes[5].Scale;
speed = modes[5].Speed;
}
fillnoise8();
for (uint8_t i = 0; i < WIDTH; i++)
@@ -58,8 +58,8 @@ void rainbowNoise()
{
loadingFlag = false;
currentPalette = RainbowColors_p;
scale = modes[9].scale;
speed = modes[9].speed;
scale = modes[9].Scale;
speed = modes[9].Speed;
colorLoop = 1;
}
fillNoiseLED();
@@ -71,8 +71,8 @@ void rainbowStripeNoise()
{
loadingFlag = false;
currentPalette = RainbowStripeColors_p;
scale = modes[10].scale;
speed = modes[10].speed;
scale = modes[10].Scale;
speed = modes[10].Speed;
colorLoop = 1;
}
fillNoiseLED();
@@ -90,8 +90,8 @@ void zebraNoise()
currentPalette[4] = CRGB::White;
currentPalette[8] = CRGB::White;
currentPalette[12] = CRGB::White;
scale = modes[11].scale;
speed = modes[11].speed;
scale = modes[11].Scale;
speed = modes[11].Speed;
colorLoop = 1;
}
fillNoiseLED();
@@ -103,8 +103,8 @@ void forestNoise()
{
loadingFlag = false;
currentPalette = ForestColors_p;
scale = modes[12].scale;
speed = modes[12].speed;
scale = modes[12].Scale;
speed = modes[12].Speed;
colorLoop = 0;
}
fillNoiseLED();
@@ -116,8 +116,8 @@ void oceanNoise()
{
loadingFlag = false;
currentPalette = OceanColors_p;
scale = modes[13].scale;
speed = modes[13].speed;
scale = modes[13].Scale;
speed = modes[13].Speed;
colorLoop = 0;
}
@@ -130,8 +130,8 @@ void plasmaNoise()
{
loadingFlag = false;
currentPalette = PartyColors_p;
scale = modes[8].scale;
speed = modes[8].speed;
scale = modes[8].Scale;
speed = modes[8].Speed;
colorLoop = 1;
}
fillNoiseLED();
@@ -143,8 +143,8 @@ void cloudNoise()
{
loadingFlag = false;
currentPalette = CloudColors_p;
scale = modes[6].scale;
speed = modes[6].speed;
scale = modes[6].Scale;
speed = modes[6].Speed;
colorLoop = 0;
}
fillNoiseLED();
@@ -156,8 +156,8 @@ void lavaNoise()
{
loadingFlag = false;
currentPalette = LavaColors_p;
scale = modes[7].scale;
speed = modes[7].speed;
scale = modes[7].Scale;
speed = modes[7].Speed;
colorLoop = 0;
}
fillNoiseLED();

View File

@@ -30,19 +30,19 @@ void parseUDP()
else if (inputBuffer.startsWith("EFF"))
{
saveEEPROM();
EepromManager::SaveModesSettings(&currentMode, modes);
currentMode = (byte)inputBuffer.substring(3).toInt();
loadingFlag = true;
FastLED.clear();
delay(1);
sendCurrent();
FastLED.setBrightness(modes[currentMode].brightness);
FastLED.setBrightness(modes[currentMode].Brightness);
}
else if (inputBuffer.startsWith("BRI"))
{
modes[currentMode].brightness = constrain(inputBuffer.substring(3).toInt(), 1, 255);
FastLED.setBrightness(modes[currentMode].brightness);
modes[currentMode].Brightness = constrain(inputBuffer.substring(3).toInt(), 1, 255);
FastLED.setBrightness(modes[currentMode].Brightness);
settChanged = true;
eepromTimer = millis();
sendCurrent();
@@ -50,7 +50,7 @@ void parseUDP()
else if (inputBuffer.startsWith("SPD"))
{
modes[currentMode].speed = inputBuffer.substring(3).toInt();
modes[currentMode].Speed = inputBuffer.substring(3).toInt();
loadingFlag = true;
settChanged = true;
eepromTimer = millis();
@@ -59,7 +59,7 @@ void parseUDP()
else if (inputBuffer.startsWith("SCA"))
{
modes[currentMode].scale = inputBuffer.substring(3).toInt();
modes[currentMode].Scale = inputBuffer.substring(3).toInt();
loadingFlag = true;
settChanged = true;
eepromTimer = millis();
@@ -82,27 +82,27 @@ void parseUDP()
else if (inputBuffer.startsWith("ALM_SET"))
{
byte alarmNum = (char)inputBuffer[7] - '0';
uint8_t alarmNum = (char)inputBuffer[7] - '0';
alarmNum -= 1;
if (inputBuffer.indexOf("ON") != -1)
{
alarm[alarmNum].state = true;
alarms[alarmNum].State = true;
sendAlarms();
}
else if (inputBuffer.indexOf("OFF") != -1)
{
alarm[alarmNum].state = false;
alarms[alarmNum].State = false;
sendAlarms();
}
else
{
int32_t almTime = inputBuffer.substring(8).toInt();
alarm[alarmNum].time = almTime;
byte hour = floor(almTime / 60);
byte minute = almTime - hour * 60;
int32_t alarmTime = inputBuffer.substring(8).toInt();
alarms[alarmNum].Time = alarmTime;
uint8_t hour = floor(alarmTime / 60);
uint8_t minute = alarmTime - hour * 60;
sendAlarms();
}
saveAlarm(alarmNum);
EepromManager::SaveAlarmsSettings(&alarmNum, alarms);
}
else if (inputBuffer.startsWith("ALM_GET"))
@@ -113,7 +113,7 @@ void parseUDP()
else if (inputBuffer.startsWith("DAWN"))
{
dawnMode = inputBuffer.substring(4).toInt() - 1;
saveDawnMmode();
EepromManager::SaveDawnMode(&dawnMode);
sendAlarms();
}
@@ -146,6 +146,20 @@ void parseUDP()
sendTimer();
}
else if (inputBuffer.startsWith("FAV_GET"))
{
sendFavorites();
}
else if (inputBuffer.startsWith("FAV_SET"))
{
FavoritesManager::ConfigureFavorites(inputBuffer.c_str());
//FavoritesManager::SetStatus(inputBuffer);
sendFavorites();
settChanged = true;
eepromTimer = millis();
}
else
{
inputBuffer = "";
@@ -182,11 +196,11 @@ void sendCurrent()
inputBuffer += " ";
inputBuffer += String(currentMode);
inputBuffer += " ";
inputBuffer += String(modes[currentMode].brightness);
inputBuffer += String(modes[currentMode].Brightness);
inputBuffer += " ";
inputBuffer += String(modes[currentMode].speed);
inputBuffer += String(modes[currentMode].Speed);
inputBuffer += " ";
inputBuffer += String(modes[currentMode].scale);
inputBuffer += String(modes[currentMode].Scale);
inputBuffer += " ";
inputBuffer += String(ONflag);
inputBuffer += " ";
@@ -205,21 +219,19 @@ void sendCurrent()
#else
inputBuffer += String(millis());
#endif
#ifdef GENERAL_DEBUG
Serial.println(inputBuffer);
#endif
}
void sendAlarms()
{
inputBuffer = "ALMS ";
for (byte i = 0; i < 7; i++) {
inputBuffer += String(alarm[i].state);
for (byte i = 0; i < 7; i++)
{
inputBuffer += String(alarms[i].State);
inputBuffer += " ";
}
for (byte i = 0; i < 7; i++) {
inputBuffer += String(alarm[i].time);
for (byte i = 0; i < 7; i++)
{
inputBuffer += String(alarms[i].Time);
inputBuffer += " ";
}
inputBuffer += (dawnMode + 1);
@@ -235,3 +247,19 @@ void sendTimer()
inputBuffer += " ";
inputBuffer += String(TimerManager::TimerRunning ? (uint16_t)floor((TimerManager::TimeToFire - millis()) / 1000) : 0);
}
void sendFavorites()
{
inputBuffer = "FAV";
inputBuffer += " ";
inputBuffer += String((uint8_t)FavoritesManager::FavoritesRunning);
inputBuffer += " ";
inputBuffer += String((uint16_t)FavoritesManager::Interval);
inputBuffer += " ";
inputBuffer += String((uint16_t)FavoritesManager::Dispersion);
for (uint8_t i = 0; i < MODE_AMOUNT; i++)
{
inputBuffer += " ";
inputBuffer += String((uint8_t)FavoritesManager::FavoriteModes[i]);
}
}

View File

@@ -52,14 +52,14 @@ void timeTick()
thisTime = timeClient.getHours() * 60 + timeClient.getMinutes();
// проверка рассвета
if (alarm[thisDay].state && // день будильника
thisTime >= (alarm[thisDay].time - dawnOffsets[dawnMode]) && // позже начала
thisTime < (alarm[thisDay].time + DAWN_TIMEOUT)) // раньше конца + минута
if (alarms[thisDay].State && // день будильника
thisTime >= (alarms[thisDay].Time - dawnOffsets[dawnMode]) && // позже начала
thisTime < (alarms[thisDay].Time + DAWN_TIMEOUT)) // раньше конца + минута
{
if (!manualOff) // будильник не был выключен вручную (из приложения или кнопкой)
{
// величина рассвета 0-255
int32_t dawnPosition = 255 * ((float)(thisTime - (alarm[thisDay].time - dawnOffsets[dawnMode])) / dawnOffsets[dawnMode]);
int32_t dawnPosition = 255 * ((float)(thisTime - (alarms[thisDay].Time - dawnOffsets[dawnMode])) / dawnOffsets[dawnMode]);
dawnPosition = constrain(dawnPosition, 0, 255);
CHSV dawnColor = CHSV(map(dawnPosition, 0, 255, 10, 35),
map(dawnPosition, 0, 255, 255, 170),
@@ -118,4 +118,4 @@ void resolveNtpServerAddress(bool &ntpServerAddressResolved) // ф
ntpServerAddressResolved = true;
}
}
#endif USE_NTP
#endif

View File

@@ -5,7 +5,7 @@ class timerMinim
public:
timerMinim(uint32_t interval); // объявление таймера с указанием интервала
void setInterval(uint32_t interval); // установка интервала работы таймера
boolean isReady(); // возвращает true, когда пришло время. Сбрасывается в false сам (AUTO) или вручную (MANUAL)
bool isReady(); // возвращает true, когда пришло время. Сбрасывается в false сам (AUTO) или вручную (MANUAL)
void reset(); // ручной сброс таймера на установленный интервал
private:
@@ -24,7 +24,7 @@ void timerMinim::setInterval(uint32_t interval)
_interval = interval;
}
boolean timerMinim::isReady()
bool timerMinim::isReady()
{
if ((long)millis() - _timer >= _interval)
{