diff --git a/android/LedLamp.aia b/android/LedLamp.aia new file mode 100644 index 0000000..9f039dc Binary files /dev/null and b/android/LedLamp.aia differ diff --git a/android/LedLamp.apk b/android/LedLamp.apk new file mode 100644 index 0000000..db9d0b5 Binary files /dev/null and b/android/LedLamp.apk differ diff --git a/android/LedLampClassic.aia b/android/LedLampClassic.aia deleted file mode 100644 index 69c75d9..0000000 Binary files a/android/LedLampClassic.aia and /dev/null differ diff --git a/android/LedLampClassic.apk b/android/LedLampClassic.apk deleted file mode 100644 index dc8eaca..0000000 Binary files a/android/LedLampClassic.apk and /dev/null differ diff --git a/android/Декомпозиция.txt b/android/Декомпозиция.txt new file mode 100644 index 0000000..c93e62b --- /dev/null +++ b/android/Декомпозиция.txt @@ -0,0 +1,131 @@ +Функциональная декомпозиция, диаграмма "классов" + +UI всё, что связано с отображением +1. ScreenManager выор отображаемого экрана +2. MainScreen управление UI'ем главного экрана (видимость, enable, цвета, позиции и т.д.) +3. ConnectivityScreen управление UI'ем функций главного экрана (видимость, enable, цвета, позиции и т.д.) +4. ModesScreen управление UI'ем функций экрана выбора эффектов (видимость, enable, цвета, позиции и т.д.) +5. FavoritesScreen управление UI'ем функций экрана избранных эффектов (видимость, enable, цвета, позиции и т.д.) +6. AlarmScreen управление UI'ем функций экрана будильника (видимость, enable, цвета, позиции и т.д.) +7. TimerScreen управление UI'ем функций экрана таймера (видимость, enable, цвета, позиции и т.д.) + +Backend всё, что связано с логикой +8. DeviceManager backend функции, связанных с управлением лампами (состояние, эффекты, подключение и т.д.) +9. DiscoverManager +10. PollingManager +11. StringHelper + +System все системные объекты и функции +11. System_DB хранилище +12. System_WiFi модуль работы с WiFi + + + +Свойства и методы "классов" + +ScreenManager + ShowScreen метод: принимает номер "экрана", устанавливает свойство видимости в true для этого экрана и в false для остальных экранов; вызывает перерисовку "экранов" + RebuildAllScreens метод: перерисовывает "экраны", делает их блоки видимыми или видимыми в зависимости от выставленных свойств видимости + CloseApplication метод: закрывает приложение + +MainScreen + Visible свойство: "Видимость главного экрана" + BlockControlEventsEmitting свойство: "Не генерировать события от элементов управления" (слайдеров, кнопок и т.д.); нужно, например, чтобы предотвратить slider.setPosition при его enable/disable + Initialize метод (событие): действия при инициализации "экрана" (однократно) + BackPressed метод (событие): действия при нажатии системной кнопки "Назад" на главном "экране" + ConnectivityButtonClick метод (событие): действия при нажатии кнопки перехода на "экран" устройств + ModesButtonClick метод (событие): действия при нажатии кнопки перехода на "экран" эффектов + FavoritesButtonClick метод (событие): действия при нажатии кнопки перехода на "экран" избранных эффектов + AlarmButtonClick метод (событие): действия при нажатии кнопки перехода на "экран" будильника + TimerButtonClick метод (событие): действия при нажатии кнопки перехода на "экран" таймера + OnOffButtonClick метод (событие): действия при нажатии кнопки Вкл/Выкл + BrightnessSliderPositionChanged метод (событие): действия при изменении слайдера яркости + SpeedSliderPositionChanged метод (событие): действия при изменении слайдера скокрости + ScaleSliderPositionChanged метод (событие): действия при изменении слайдера масштаба + UpdateControls метод: обновить отображение элементов управления (статусы enabled/disabled) в зависимости от сохранённых свойств (модели данных) + SetDebugText метод: установить отладочный текст основной отладочной текстовой метке + SetDebugTimeText метод: установить отладочный текст дополнительной отладочной текстовой метке + +ConnectivityScreen + Visible свойство: "Видимость экрана устройств" + IpAddressInputLostFocus метод (событие): действия при потери фокуса поля ввода IP адреса + PortInputLostFocus метод (событие): действия при потери фокуса поля ввода порта + SaveConnectionButtonClick метод (событие): действия при нажатии на кнопку "Добавить" + RemoveConnectionButtonClick метод (событие): действия при нажатии на кнопку "Удалить" + SaveAllConnectionButtonClick метод (событие): действия при нажатии на кнопку "Сканировать и добавить" + DeviceSocketListViewAfterPicking метод (событие): действия при выборе устройства из списка сохранённых и его подключение + BaсkButtonClick метод (событие): действия при UI кнопки "Назад" на "экране" устройств + UpdateConnectivityStatus метод: обновить статус устройства "Подключен"/"Отключен" на "экране" устройств + UpdateCurrentDeviceSocket метод: отобразить текущее устройство (DeviceManager.CurrentDeviceSocket) в полях ввода IP адреса и порта на "экране" устройств + UpdateCurrentDevicesSockets метод: отобразить текущий список сохранённых устройств (DeviceManager.Devices) на "экране" устройств + ValidateAndAddDeviceSocketToList метод: валидировать значения полей ввода IP адреса и порта и добавть запись в список сохранённых устройств; перерисовать этот список + SetConnectionStatus метод: установить статус Подлкючен/Отключен соответствующей текстовой метке на этом экране + UpdateScreen метод: обновить все элементы управления на "экране" устройств согласно модели данных + +ModesScreen + Visible свойство: "Видимость экрана эффектов" + ModesListViewAfterPicking метод (событие): действия при выборе эффекта из списка эффектов + BaсkButtonClick метод (событие): действия при UI кнопки "Назад" на "экране" эффектов + +FavoritesScreen + Visible свойство: "Видимость экрана устройств" + BaсkButtonClick метод (событие): действия при UI кнопки "Назад" на "экране" избранных эффектов + +AlarmScreen + Visible свойство: "Видимость экрана устройств" + BaсkButtonClick метод (событие): действия при UI кнопки "Назад" на "экране" будильника + +TimerScreen + Visible свойство: "Видимость экрана устройств" + BaсkButtonClick метод (событие): действия при UI кнопки "Назад" на "экране" таймера + +DeviceManager + Connected свойство: подключено ли устройство (лампа)? точнее, был ли получен ответ на последнюю высланную ему команду + State свойство: полученное командой GET состояние устройства (CURR...) + Devices свойство: список устройств (хранимое свойство) + CurrentDeviceSocket свойство: текущее устройство (хранимое свойство) + Modes свойство: список доступных режимов, захардкожен одновременно в лампе и в приложении, должен совпадать + Initialize метод: вычитывание хранимых свойств и инициализация соответствующих переменных + ConnectDeviceSocket метод: стартовать таймер (polling timer) с регулярной отправкой команд GET/DEB на устройство + DisconnectDeviceSocket метод: остановить таймер (polling timer) с регулярной отправкой команд GET/DEB на устройство; очистить свойства Connected и State + GetCurrentModeId метод: получить номер текущего эффекта из свойства State + GetCurrentModeId метод: получить имя текущего эффекта из свойства State + GetCurrentBrightness метод: получить значение текущей яркости из свойства State + GetCurrentSpeed метод: получить значение текущей скорости из свойства State + GetCurrentScale метод: получить значение текущего масштаба из свойства State + GetCurrentOn метод: получить значение текущей состояния Вкл/Выкл из свойства State + GetCurrentEspMode метод: получить значение текущей состояния ESP_MODE из свойства State + GetCurrentUseNtp метод: получить значение текущей состояния USE_NTP из свойства State + SaveDeviceSocketSettings метод: сохранить с базу данных приложения хранимые значения (текущее стройство и список устройств) + ValidateIpPort метод: валидировать переданное в качестве параметра значение IP адреса или порта + +DiscoverManager + TimeoutMs свойство: время ожидания ответа от устройств на multicast команду DISCOVER + SendMulticastCommand метод: стартовать UDP сервер (для отправки multicast команды DISCOVER на адрес широковещательных сообщений сети и получения ответа) + UdpServerStarted метод (событие): отправить multicast команду DISCOVER на адрес широковещательных сообщений сети; стартовать таймер завершения работы сервера + UdpServerDataRecieved метод (событие): получить и обработать ответы от устройств на multicast команду DISCOVER + TimerTimerNow метод (событие): завершить работу UDP сервера и таймера (при первом срабатывании события таймера) + GetBroacdastIP метод: получить адрес широковещательных сообщений мобильного устройства, используя текущий IP адрес WiFi подключения + +PollingManager + Timeout свойство: время ожидания ответа от устройств на команды управления + UdpPort свойство: номер UDP порта + TimerIntervalMs свойство: время работы таймера (ограничение используемого компонента), по его истечении таймер постоянно перезапускается для непрерывной работы + TimerTickMs свойство: интервал времени, через который будет сгенерировано событие таймера + TimerTickCounter свойство: счётчик срабатываний таймера, нужен чтобы вызывать команды управления/запроса состяния устройств по очереди x из n - одна команда (GET), y из n - другая (DEB) + StartTimer метод: старт polling таймера + TimerTimerNow метод (событие): действия при срабатывании события polling таймера (отправка команд и перезапуск таймера) + UdpClientRecieved метод (событие): действия при получении ответа на отправленные команды от подключенного устройства + SendUdpCommand метод: отправить команду, принятую в качестве входного параметра на подключенное устройство + SendGetDebCommandToDevice метод: отправить команды GET или DEB (в зависимости от входного параметра) на подключенное устройство + SendPowerOnOffCommandToDevice метод: отправить команды On/Off (в зависимости от входного параметра) на подключенное устройство + SendSetModeCommandToDevice метод: отправить команду смены эффекта на подключенное устройство + SendSetBrightnessCommandToDevice метод: отправить команду установки яркости на подключенное устройство + SendSetSpeedCommandToDevice метод: отправить команду установки скорости на подключенное устройство + SendSetScaleCommandToDevice метод: отправить команду установки масштаба на подключенное устройство + HandleDeviceResponse метод: обработка ответа от подключенного устройства на отправленные команды + +StringHelper + GetIpPortString метод: получить строку формата IP:PORT из входных параметров IP и PORT + GetIpFromIpPortString метод: получить IP из входного параметра формата IP:PORT + GgetPortFromIpPortString метод: получить PORT из входного параметра формата IP:PORT diff --git a/firmware/GyverLamp_v1.4/GyverLamp_v1.4.ino b/firmware/GyverLamp_v1.4/GyverLamp_v1.4.ino index 7e5a41c..9593ca3 100644 --- a/firmware/GyverLamp_v1.4/GyverLamp_v1.4.ino +++ b/firmware/GyverLamp_v1.4/GyverLamp_v1.4.ino @@ -30,6 +30,13 @@ -- работает при подключенной кнопке (потому что режим прошивки активируется кнопкой) --- 16.07.2019 - Исправлено регулярное подвисание матрицы на 1-2 секунды при отсутствии подключения к интернету (но при успешном подключении к WiFi) + --- 28.07.2019 + - Доработано взаимодействие с android приложением (отправка состояния после каждой операции) + --- 01.08.2019 + - Возврат к стандартной библиотеке GyverButton (изменениё из неё перенесено в button.ino + - Добавлены 2 эффекта: Светлячки со шлейфом и Белый свет + - При запросе обновления по воздуху (2 четверных касания к кнопке) лампа переключается в режим "Матрица" для визуального подтверждения готовности к прошивке + - В android приложение добавлена функция сканирования сети и добавления ламп с помощью multicast пакетов, доработка прошивки под это */ // Ссылка для менеджера плат: @@ -88,7 +95,7 @@ uint8_t AP_STATIC_IP[] = {192, 168, 4, 1}; // статичес // ============= ДЛЯ РАЗРАБОТЧИКОВ ===== #define LED_PIN (2U) // пин ленты #define BTN_PIN (4U) // пин кнопки -#define MODE_AMOUNT (18U) +#define MODE_AMOUNT (20U) // количество режимов #define NUM_LEDS (WIDTH * HEIGHT) #define SEGMENTS (1U) // диодов в одном "пикселе" (для создания матрицы из кусков ленты) diff --git a/firmware/GyverLamp_v1.4/OtaManager.h b/firmware/GyverLamp_v1.4/OtaManager.h index 2398593..0a97d44 100644 --- a/firmware/GyverLamp_v1.4/OtaManager.h +++ b/firmware/GyverLamp_v1.4/OtaManager.h @@ -32,7 +32,7 @@ class OtaManager public: static OtaPhase OtaFlag; - void RequestOtaUpdate() // пользователь однократно запросил обновление по воздуху + bool RequestOtaUpdate() // пользователь однократно запросил обновление по воздуху; возвращает true, когда переходит в режим обновления - startOtaUpdate() { if (ESP_MODE != 1) { @@ -40,7 +40,7 @@ class OtaManager Serial.printf("Запрос обновления по воздуху поддерживается только в режиме ESP_MODE = 1\n"); #endif - return; + return false; } if (OtaFlag == OtaPhase::None) @@ -52,7 +52,7 @@ class OtaManager Serial.printf("Получено первое подтверждение обновления по воздуху\nОжидание второго подтверждения\n"); #endif - return; + return false; } if (OtaFlag == OtaPhase::GotFirstConfirm) @@ -64,8 +64,10 @@ class OtaManager #endif startOtaUpdate(); - return; + return true; } + + return false; } void HandleOtaUpdate() diff --git a/firmware/GyverLamp_v1.4/button.ino b/firmware/GyverLamp_v1.4/button.ino index 740667c..790d520 100644 --- a/firmware/GyverLamp_v1.4/button.ino +++ b/firmware/GyverLamp_v1.4/button.ino @@ -34,7 +34,7 @@ void buttonTick() if (ONflag && touch.isTriple()) { - if (--currentMode < 0) currentMode = 0; + if (--currentMode < 0) currentMode = MODE_AMOUNT - 1; FastLED.setBrightness(modes[currentMode].brightness); loadingFlag = true; settChanged = true; @@ -43,10 +43,15 @@ void buttonTick() delay(1); } - if (ONflag && touch.isQuadruple()) + if (ONflag && touch.hasClicks() && touch.getClicks() >= 4) { #ifdef OTA - otaManager.RequestOtaUpdate(); + if (otaManager.RequestOtaUpdate()) + { + currentMode = 16; // принудительное включение режима "Матрица" для индикации перехода в режим обновления по воздуху + FastLED.clear(); + delay(1); + } #endif } diff --git a/firmware/GyverLamp_v1.4/effectTicker.ino b/firmware/GyverLamp_v1.4/effectTicker.ino index bb3bbdf..20937aa 100644 --- a/firmware/GyverLamp_v1.4/effectTicker.ino +++ b/firmware/GyverLamp_v1.4/effectTicker.ino @@ -45,6 +45,10 @@ void effectsTick() break; case 17: lightersRoutine(); break; + case 18: lightBalls(); + break; + case 19: whiteColor(); + break; } FastLED.show(); } diff --git a/firmware/GyverLamp_v1.4/effects.ino b/firmware/GyverLamp_v1.4/effects.ino index 655499b..f7fb8ce 100644 --- a/firmware/GyverLamp_v1.4/effects.ino +++ b/firmware/GyverLamp_v1.4/effects.ino @@ -329,6 +329,61 @@ void lightersRoutine() } } + +// ------------- LightBalls (светлячки со шлейфом) ------------- +const uint8_t BorderWidth = 2; + +void lightBalls() +{ + // Apply some blurring to whatever's already on the matrix + // Note that we never actually clear the matrix, we just constantly + // blur it repeatedly. Since the blurring is 'lossy', there's + // an automatic trend toward black -- by design. + uint8_t blurAmount = dim8_raw(beatsin8(3,64,100)); + blur2d(leds, WIDTH, HEIGHT, blurAmount); + + // Use two out-of-sync sine waves + uint8_t i = beatsin8( 91, BorderWidth, WIDTH-BorderWidth); + uint8_t j = beatsin8( 109, BorderWidth, WIDTH-BorderWidth); + uint8_t k = beatsin8( 73, BorderWidth, WIDTH-BorderWidth); + uint8_t m = beatsin8( 123, BorderWidth, WIDTH-BorderWidth); + + // The color of each point shifts over time, each at a different speed. + uint16_t ms = millis(); + leds[XY( i, j)] += CHSV( ms / 29, 200, 255); + leds[XY( j, k)] += CHSV( ms / 41, 200, 255); + leds[XY( k, m)] += CHSV( ms / 73, 200, 255); + leds[XY( m, i)] += CHSV( ms / 97, 200, 255); + +} +// Trivial XY function for the SmartMatrix; use a different XY +// function for different matrix grids. See XYMatrix example for code. +uint16_t XY(uint8_t x, uint8_t y) +{ + uint16_t i; + if (y & 0x01) + { + // Odd rows run backwards + uint8_t reverseX = (WIDTH - 1) - x; + i = (y * WIDTH) + reverseX; + } + else + { + // Even rows run forwards + i = (y * WIDTH) + x; + } + return i; +} + +// ------------- белый свет ------------- +void whiteColor() +{ + for (int i = 0; i < NUM_LEDS; i++) + { + leds[i] = CHSV(0, 0, 255); + } +} + /* void lightersRoutine() { diff --git a/firmware/GyverLamp_v1.4/noiseEffects.ino b/firmware/GyverLamp_v1.4/noiseEffects.ino index ae8ebc6..6562e69 100644 --- a/firmware/GyverLamp_v1.4/noiseEffects.ino +++ b/firmware/GyverLamp_v1.4/noiseEffects.ino @@ -183,7 +183,7 @@ void fillNoiseLED() data = qsub8(data, 16); data = qadd8(data, scale8(data, 39)); - if ( dataSmoothing ) + if (dataSmoothing) { uint8_t olddata = noise[i][j]; uint8_t newdata = scale8( olddata, dataSmoothing) + scale8( data, 256 - dataSmoothing); diff --git a/firmware/GyverLamp_v1.4/parsing.ino b/firmware/GyverLamp_v1.4/parsing.ino index 2acd020..a2fd7e4 100644 --- a/firmware/GyverLamp_v1.4/parsing.ino +++ b/firmware/GyverLamp_v1.4/parsing.ino @@ -4,6 +4,8 @@ void parseUDP() if (packetSize) { + Serial.print("income"); + int32_t n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE); packetBuffer[n] = 0; inputBuffer = packetBuffer; @@ -118,8 +120,39 @@ void parseUDP() saveDawnMmode(); } + else if (inputBuffer.startsWith("DISCOVER")) // обнаружение приложением модуля esp в локальной сети + { + if (ESP_MODE == 1) // работает только в режиме WiFi клиента + { + inputBuffer = "IP"; + inputBuffer += " "; + inputBuffer += String(WiFi.localIP()[0]) + "." + + String(WiFi.localIP()[1]) + "." + + String(WiFi.localIP()[2]) + "." + + String(WiFi.localIP()[3]); + inputBuffer += ":"; + inputBuffer += String(ESP_UDP_PORT); + } + } + + else + { + inputBuffer = ""; + } + + if (inputBuffer.length() <= 0) + { + return; + } + + if (Udp.remoteIP() == WiFi.localIP()) // не реагировать на свои же пакеты + { + return; + } + char reply[inputBuffer.length() + 1]; inputBuffer.toCharArray(reply, inputBuffer.length() + 1); + inputBuffer.remove(0); // очистка буфера, читобы не он не интерпретировался, как следующий udp пакет Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); Udp.write(reply); Udp.endPacket(); @@ -145,6 +178,14 @@ void sendCurrent() inputBuffer += String(modes[currentMode].scale); inputBuffer += " "; inputBuffer += String(ONflag); + inputBuffer += " "; + inputBuffer += String(ESP_MODE); + inputBuffer += " "; + #ifdef USE_NTP + inputBuffer += "1"; + #else + inputBuffer += "0"; + #endif #ifdef GENERAL_DEBUG Serial.println(inputBuffer); diff --git a/libraries/GyverButton/GyverButton.cpp b/libraries/GyverButton/GyverButton.cpp index ec3f6a6..43816b9 100644 --- a/libraries/GyverButton/GyverButton.cpp +++ b/libraries/GyverButton/GyverButton.cpp @@ -106,13 +106,6 @@ boolean GButton::isTriple() { return true; } else return false; } -boolean GButton::isQuadruple() { - if (flags.tickMode) GButton::tick(); - if (flags.counter_flag && last_counter == 4) { - flags.counter_flag = false; - return true; - } else return false; -} boolean GButton::hasClicks() { if (flags.tickMode) GButton::tick(); if (flags.counter_flag) { diff --git a/libraries/GyverButton/GyverButton.h b/libraries/GyverButton/GyverButton.h index efd5583..42044f8 100644 --- a/libraries/GyverButton/GyverButton.h +++ b/libraries/GyverButton/GyverButton.h @@ -76,7 +76,6 @@ class GButton boolean isSingle(); // возвращает true при одиночном клике. Сбрасывается после вызова boolean isDouble(); // возвращает true при двойном клике. Сбрасывается после вызова boolean isTriple(); // возвращает true при тройном клике. Сбрасывается после вызова - boolean isQuadruple(); // возвращает true при четверном клике. Сбрасывается после вызова boolean hasClicks(); // проверка на наличие кликов. Сбрасывается после вызова uint8_t getClicks(); // вернуть количество кликов