diff --git a/android/LedLamp.aia b/android/LedLamp.aia index 6911458..8ea2582 100644 Binary files a/android/LedLamp.aia and b/android/LedLamp.aia differ diff --git a/android/LedLamp.apk b/android/LedLamp.apk index b3b6bfb..5de91c8 100644 Binary files a/android/LedLamp.apk and b/android/LedLamp.apk differ diff --git a/android/Декомпозиция.txt b/android/Декомпозиция.txt index efada89..053dd5e 100644 --- a/android/Декомпозиция.txt +++ b/android/Декомпозиция.txt @@ -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 diff --git a/firmware/GyverLamp_v1.4/EepromManager.h b/firmware/GyverLamp_v1.4/EepromManager.h new file mode 100644 index 0000000..2363275 --- /dev/null +++ b/firmware/GyverLamp_v1.4/EepromManager.h @@ -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 +#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: +}; diff --git a/firmware/GyverLamp_v1.4/FavoritesManager.h b/firmware/GyverLamp_v1.4/FavoritesManager.h new file mode 100644 index 0000000..2775cdb --- /dev/null +++ b/firmware/GyverLamp_v1.4/FavoritesManager.h @@ -0,0 +1,245 @@ +#pragma once +#include +#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; + } +}; diff --git a/firmware/GyverLamp_v1.4/GyverLamp_v1.4.ino b/firmware/GyverLamp_v1.4/GyverLamp_v1.4.ino index 4ccaf20..4b89bbe 100644 --- a/firmware/GyverLamp_v1.4/GyverLamp_v1.4.ino +++ b/firmware/GyverLamp_v1.4/GyverLamp_v1.4.ino @@ -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 #include @@ -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, ¤tMode, + &(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, ¤tMode, 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, + ¤tMode, + &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 подключение и т.д. (?) } diff --git a/firmware/GyverLamp_v1.4/OtaManager.h b/firmware/GyverLamp_v1.4/OtaManager.h index 11afb67..ef8022f 100644 --- a/firmware/GyverLamp_v1.4/OtaManager.h +++ b/firmware/GyverLamp_v1.4/OtaManager.h @@ -1,3 +1,4 @@ +#pragma once /* * 11.07.2019 * Класс, который отслеживает действия пользователя по запросу обновления прошивки по воздуху и выполняет эту прошивку. diff --git a/firmware/GyverLamp_v1.4/TimerManager.h b/firmware/GyverLamp_v1.4/TimerManager.h index 05008d4..7a54fbf 100644 --- a/firmware/GyverLamp_v1.4/TimerManager.h +++ b/firmware/GyverLamp_v1.4/TimerManager.h @@ -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 && diff --git a/firmware/GyverLamp_v1.4/Types.h b/firmware/GyverLamp_v1.4/Types.h new file mode 100644 index 0000000..600961c --- /dev/null +++ b/firmware/GyverLamp_v1.4/Types.h @@ -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; +}; diff --git a/firmware/GyverLamp_v1.4/button.ino b/firmware/GyverLamp_v1.4/button.ino index 790d520..1e219a8 100644 --- a/firmware/GyverLamp_v1.4/button.ino +++ b/firmware/GyverLamp_v1.4/button.ino @@ -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 } } diff --git a/firmware/GyverLamp_v1.4/eeprom.ino b/firmware/GyverLamp_v1.4/eeprom.ino deleted file mode 100644 index 6dfdc71..0000000 --- a/firmware/GyverLamp_v1.4/eeprom.ino +++ /dev/null @@ -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(); -} diff --git a/firmware/GyverLamp_v1.4/effectTicker.ino b/firmware/GyverLamp_v1.4/effectTicker.ino index 281b94f..3a35311 100644 --- a/firmware/GyverLamp_v1.4/effectTicker.ino +++ b/firmware/GyverLamp_v1.4/effectTicker.ino @@ -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); diff --git a/firmware/GyverLamp_v1.4/effects.ino b/firmware/GyverLamp_v1.4/effects.ino index f7fb8ce..1202914 100644 --- a/firmware/GyverLamp_v1.4/effects.ino +++ b/firmware/GyverLamp_v1.4/effects.ino @@ -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 отрисовок { diff --git a/firmware/GyverLamp_v1.4/noiseEffects.ino b/firmware/GyverLamp_v1.4/noiseEffects.ino index a2b566e..32f8b82 100644 --- a/firmware/GyverLamp_v1.4/noiseEffects.ino +++ b/firmware/GyverLamp_v1.4/noiseEffects.ino @@ -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(); diff --git a/firmware/GyverLamp_v1.4/parsing.ino b/firmware/GyverLamp_v1.4/parsing.ino index bfddf91..3f6fc6c 100644 --- a/firmware/GyverLamp_v1.4/parsing.ino +++ b/firmware/GyverLamp_v1.4/parsing.ino @@ -30,19 +30,19 @@ void parseUDP() else if (inputBuffer.startsWith("EFF")) { - saveEEPROM(); + EepromManager::SaveModesSettings(¤tMode, 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]); + } +} diff --git a/firmware/GyverLamp_v1.4/time.ino b/firmware/GyverLamp_v1.4/time.ino index 50078d1..6fd30dd 100644 --- a/firmware/GyverLamp_v1.4/time.ino +++ b/firmware/GyverLamp_v1.4/time.ino @@ -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 diff --git a/firmware/GyverLamp_v1.4/timerMinim.h b/firmware/GyverLamp_v1.4/timerMinim.h index 8e43a7c..57f1deb 100644 --- a/firmware/GyverLamp_v1.4/timerMinim.h +++ b/firmware/GyverLamp_v1.4/timerMinim.h @@ -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) {