mirror of
https://github.com/gunner47/GyverLamp.git
synced 2025-08-07 09:00:30 +03:00
Добавлено управление по протоколу MQTT; добавлена возможность вывода отладочных сообщений в telnet; исправлены ошибки (будильник, управление яркостью кнопкой, затирание параметров WiFi при включении)
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESP8266WebServer.h>
|
||||
|
||||
|
||||
// ============= НАСТРОЙКИ =============
|
||||
// --- ESP -----------------------------
|
||||
@@ -34,6 +36,12 @@ const uint8_t AP_STATIC_IP[] = {192, 168, 4, 1}; // статичес
|
||||
#define NTP_ADDRESS ("ntp2.colocall.net") // сервер времени
|
||||
#define NTP_INTERVAL (30UL * 60UL * 1000UL) // интервал синхронизации времени (30 минут)
|
||||
|
||||
// --- ВНЕШНЕЕ УПРАВЛЕНИЕ --------------
|
||||
#define USE_MQTT (true) // true - используется mqtt клиент, false - нет
|
||||
#if USE_MQTT
|
||||
#define MQTT_RECONNECT_TIME (10U) // время в секундах перед подключением к MQTT брокеру в случае потери подключения
|
||||
#endif
|
||||
|
||||
// --- РАССВЕТ -------------------------
|
||||
#define DAWN_BRIGHT (200U) // максимальная яркость рассвета (0-255)
|
||||
#define DAWN_TIMEOUT (1U) // сколько рассвет светит после времени будильника, минут
|
||||
@@ -86,6 +94,18 @@ const uint8_t AP_STATIC_IP[] = {192, 168, 4, 1}; // статичес
|
||||
//#define MAX_UDP_BUFFER_SIZE (UDP_TX_PACKET_MAX_SIZE + 1)
|
||||
#define MAX_UDP_BUFFER_SIZE (129U) // максимальный размер буффера UDP сервера
|
||||
|
||||
#define GENERAL_DEBUG_TELNET (true) // true - отладочные сообщения будут выводиться в telnet вместо Serial порта (для удалённой отладки без подключения usb кабелем)
|
||||
#define TELNET_PORT (23U) // номер telnet порта
|
||||
|
||||
#if defined(GENERAL_DEBUG) && GENERAL_DEBUG_TELNET
|
||||
WiFiServer telnetServer(TELNET_PORT); // telnet сервер
|
||||
WiFiClient telnet; // обработчик событий telnet клиента
|
||||
bool telnetGreetingShown = false; // признак "показано приветствие в telnet"
|
||||
#define LOG telnet
|
||||
#else
|
||||
#define LOG Serial
|
||||
#endif
|
||||
|
||||
// --- БИБЛИОТЕКИ ----------------------
|
||||
#define FASTLED_INTERRUPT_RETRY_COUNT (0U)
|
||||
#define FASTLED_ALLOW_INTERRUPTS (0U)
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <EEPROM.h>
|
||||
#include "EepromManager.h"
|
||||
#include "Constants.h"
|
||||
|
||||
#define DEFAULT_FAVORITES_INTERVAL (300U) // значение по умолчанию для интервала переключения избпранных эффектов в секундах
|
||||
#define DEFAULT_FAVORITES_DISPERSION (0U) // значение по умолчанию для разброса интервала переключения избпранных эффектов в секундах
|
||||
@@ -99,7 +100,7 @@ class FavoritesManager
|
||||
nextModeAt = getNextTime();
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.printf_P(PSTR("Переключение на следующий избранный режим: %d\n\n"), (*currentMode));
|
||||
LOG.printf_P(PSTR("Переключение на следующий избранный режим: %d\n\n"), (*currentMode));
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
@@ -16,8 +16,8 @@
|
||||
- Добавлено "#define USE_NTP" - позволяет запретить обращаться в интернет
|
||||
- Добавлено "#define ESP_USE_BUTTON - позволяет собирать лампу без физической кнопки, иначе яркость эффектов самопроизвольно растёт до максимальной
|
||||
- Переработаны параметры IP адресов, STA_STATIC_IP теперь пустой по умолчанию - избавляет от путаницы с IP адресами из неправильных диапазонов
|
||||
- Добавлено "#define GENERAL_DEBUG" - выводит в Serial некоторые отладочные сообщения
|
||||
- Добавлено "#define WIFIMAN_DEBUG (true)" - выводит в Serial отладочные сообщения библиотеки WiFiManager
|
||||
- Добавлено "#define GENERAL_DEBUG" - выводит в Serial/Telnet некоторые отладочные сообщения
|
||||
- Добавлено "#define WIFIMAN_DEBUG (true)" - выводит в Serial/Telnet отладочные сообщения библиотеки WiFiManager
|
||||
- Добавлена таблица с тест кейсами
|
||||
- Форматирование кода, комментарии
|
||||
--- 11.07.2019
|
||||
@@ -67,6 +67,13 @@
|
||||
- Убрана очистка параметров WiFi при старте с зажатой кнопкой; регулируется директивой ESP_RESET_ON_STASRT, которая определена как false по умолчанию
|
||||
--- 24.09.2019
|
||||
- Добавлены изменения из прошивка от Alex Gyver v1.5: бегущая строка с IP адресом лампы по пятикратному клику на кнопку
|
||||
--- 29.09.2019
|
||||
- Добавлена опция вывода отладочных сообщений по пртоколу telnet вместо serial для удалённой отладки
|
||||
- Исправлена ошибка регулировки яркости кнопкой
|
||||
--- 05.10.2019
|
||||
- Добавлено управление по протоколу MQTT
|
||||
- Исправлена ошибка выключения будильника кнопкой
|
||||
- Добавлена задержка в 1 секунду сразу после старта, в течение которой нужно нажать кнопку, чтобы очистить сохранённые параметры WiFi (если ESP_RESET_ON_STASRT == true)
|
||||
*/
|
||||
|
||||
// Ссылка для менеджера плат:
|
||||
@@ -93,6 +100,9 @@
|
||||
#ifdef OTA
|
||||
#include "OtaManager.h"
|
||||
#endif
|
||||
#if USE_MQTT
|
||||
#include "MqttManager.h"
|
||||
#endif
|
||||
#include "TimerManager.h"
|
||||
#include "FavoritesManager.h"
|
||||
#include "EepromManager.h"
|
||||
@@ -114,11 +124,28 @@ timerMinim timeTimer(3000);
|
||||
#ifdef ESP_USE_BUTTON
|
||||
GButton touch(BTN_PIN, LOW_PULL, NORM_OPEN);
|
||||
#endif
|
||||
|
||||
#ifdef OTA
|
||||
OtaManager otaManager;
|
||||
OtaPhase OtaManager::OtaFlag = OtaPhase::None;
|
||||
#endif
|
||||
|
||||
#if USE_MQTT
|
||||
AsyncMqttClient* mqttClient = NULL;
|
||||
AsyncMqttClient* MqttManager::mqttClient = NULL;
|
||||
char* MqttManager::mqttServer = NULL;
|
||||
char* MqttManager::mqttUser = NULL;
|
||||
char* MqttManager::mqttPassword = NULL;
|
||||
char* MqttManager::clientId = NULL;
|
||||
char* MqttManager::topicInput = NULL;
|
||||
char* MqttManager::topicOutput = NULL;
|
||||
bool MqttManager::needToPublish = false;
|
||||
char MqttManager::mqttBuffer[] = {};
|
||||
uint32_t MqttManager::mqttLastConnectingAttempt = 0;
|
||||
SendCurrentDelegate MqttManager::sendCurrentDelegate = NULL;
|
||||
// volatile uint32_t wifiLastConnectingAttempt = 0;
|
||||
#endif
|
||||
|
||||
// --- ИНИЦИАЛИЗАЦИЯ ПЕРЕМЕННЫХ -------
|
||||
uint16_t localPort = ESP_UDP_PORT;
|
||||
char packetBuffer[MAX_UDP_BUFFER_SIZE]; // buffer to hold incoming packet
|
||||
@@ -160,30 +187,47 @@ void setup()
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
|
||||
ESP.wdtDisable();
|
||||
//ESP.wdtEnable(WDTO_8S);
|
||||
|
||||
#if defined(ESP_USE_BUTTON) && ESP_RESET_ON_STASRT
|
||||
touch.setStepTimeout(100);
|
||||
touch.setClickTimeout(500);
|
||||
buttonTick();
|
||||
if (touch.state()) // сброс сохранённых SSID и пароля при старте с зажатой кнопкой, если разрешено
|
||||
// TELNET
|
||||
#if defined(GENERAL_DEBUG) && GENERAL_DEBUG_TELNET
|
||||
telnetServer.begin();
|
||||
for (uint8_t i = 0; i < 100; i++) // пауза 10 секунд в отладочном режиме, чтобы успеть подключиться по протоколу telnet до вывода первых сообщений
|
||||
{
|
||||
wifiManager.resetSettings();
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.println(F("Настройки WiFiManager сброшены"));
|
||||
#endif
|
||||
handleTelnetClient();
|
||||
delay(100);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ЛЕНТА
|
||||
ESP.wdtDisable();
|
||||
//ESP.wdtEnable(WDTO_8S);
|
||||
|
||||
|
||||
// КНОПКА
|
||||
#if defined(ESP_USE_BUTTON)
|
||||
touch.setStepTimeout(100);
|
||||
touch.setClickTimeout(500);
|
||||
#if ESP_RESET_ON_STASRT
|
||||
delay(1000); // ожидание инициализации модуля кнопки ttp223 (по спецификации 250мс)
|
||||
if (digitalRead(BTN_PIN))
|
||||
{
|
||||
wifiManager.resetSettings(); // сброс сохранённых SSID и пароля при старте с зажатой кнопкой, если разрешено
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
LOG.println(F("Настройки WiFiManager сброшены"));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// ЛЕНТА/МАТРИЦА
|
||||
FastLED.addLeds<WS2812B, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS)/*.setCorrection(TypicalLEDStrip)*/;
|
||||
FastLED.setBrightness(BRIGHTNESS);
|
||||
if (CURRENT_LIMIT > 0) FastLED.setMaxPowerInVoltsAndMilliamps(5, CURRENT_LIMIT);
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
|
||||
|
||||
// WI-FI
|
||||
wifiManager.setDebugOutput(WIFIMAN_DEBUG); // вывод отладочных сообщений
|
||||
//wifiManager.setMinimumSignalQuality(); // установка минимально приемлемого уровня сигнала WiFi сетей (8% по умолчанию)
|
||||
@@ -197,23 +241,23 @@ void setup()
|
||||
|
||||
WiFi.softAP(AP_NAME, AP_PASS);
|
||||
|
||||
Serial.println(F("Режим WiFi точки доступа"));
|
||||
Serial.print(F("IP адрес: "));
|
||||
Serial.println(WiFi.softAPIP());
|
||||
LOG.println(F("Режим WiFi точки доступа"));
|
||||
LOG.print(F("IP адрес: "));
|
||||
LOG.println(WiFi.softAPIP());
|
||||
|
||||
wifiServer.begin();
|
||||
}
|
||||
else // режим WiFi клиента (подключаемся к роутеру, если есть сохранённые SSID и пароль, иначе создаём WiFi точку доступа и запрашиваем их)
|
||||
{
|
||||
Serial.println(F("Режим WiFi клиента"));
|
||||
LOG.println(F("Режим WiFi клиента"));
|
||||
if (WiFi.SSID())
|
||||
{
|
||||
Serial.print(F("Подключение WiFi сети: "));
|
||||
Serial.println(WiFi.SSID());
|
||||
LOG.print(F("Подключение WiFi сети: "));
|
||||
LOG.println(WiFi.SSID());
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("WiFi сеть не определена, запуск WiFi точки доступа для настройки параметров подключения к WiFi сети..."));
|
||||
LOG.println(F("WiFi сеть не определена, запуск WiFi точки доступа для настройки параметров подключения к WiFi сети..."));
|
||||
}
|
||||
|
||||
if (STA_STATIC_IP)
|
||||
@@ -230,7 +274,7 @@ void setup()
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
Serial.println(F("Время ожидания ввода SSID и пароля от WiFi сети или подключения к WiFi сети превышено\nПерезагрузка модуля"));
|
||||
LOG.println(F("Время ожидания ввода SSID и пароля от WiFi сети или подключения к WiFi сети превышено\nПерезагрузка модуля"));
|
||||
|
||||
#if defined(ESP8266)
|
||||
ESP.reset();
|
||||
@@ -239,22 +283,35 @@ void setup()
|
||||
#endif
|
||||
}
|
||||
|
||||
Serial.print(F("IP адрес: "));
|
||||
Serial.println(WiFi.localIP());
|
||||
LOG.print(F("IP адрес: "));
|
||||
LOG.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
Serial.printf_P(PSTR("Порт UDP сервера: %u\n"), localPort);
|
||||
LOG.printf_P(PSTR("Порт UDP сервера: %u\n"), localPort);
|
||||
Udp.begin(localPort);
|
||||
|
||||
|
||||
// EEPROM
|
||||
EepromManager::InitEepromSettings( // инициализация EEPROM; запись начального состояния настроек, если их там ещё нет; инициализация настроек лампы значениями из EEPROM
|
||||
modes, alarms, &ONflag, &dawnMode, ¤tMode,
|
||||
&(FavoritesManager::ReadFavoritesFromEeprom),
|
||||
&(FavoritesManager::SaveFavoritesToEeprom));
|
||||
|
||||
|
||||
// NTP
|
||||
#ifdef USE_NTP
|
||||
timeClient.begin();
|
||||
#endif
|
||||
|
||||
|
||||
// MQTT
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
mqttClient = new AsyncMqttClient();
|
||||
MqttManager::setupMqtt(mqttClient, &sendCurrent); // создание экземпляров объектов для работы с MQTT, их инициализация и подключение к MQTT брокеру
|
||||
#endif
|
||||
|
||||
|
||||
// ОСТАЛЬНОЕ
|
||||
memset(matrixValue, 0, sizeof(matrixValue));
|
||||
randomSeed(micros());
|
||||
changePower();
|
||||
@@ -266,19 +323,25 @@ void loop()
|
||||
{
|
||||
parseUDP();
|
||||
effectsTick();
|
||||
|
||||
EepromManager::HandleEepromTick(&settChanged, &eepromTimeout, &ONflag,
|
||||
¤tMode, modes, &(FavoritesManager::SaveFavoritesToEeprom));
|
||||
¤tMode, modes, &(FavoritesManager::SaveFavoritesToEeprom));
|
||||
|
||||
#ifdef USE_NTP
|
||||
timeTick();
|
||||
#endif
|
||||
|
||||
#ifdef ESP_USE_BUTTON
|
||||
buttonTick();
|
||||
#endif
|
||||
|
||||
#ifdef OTA
|
||||
otaManager.HandleOtaUpdate(); // ожидание и обработка команды на обновление прошивки по воздуху
|
||||
#endif
|
||||
|
||||
TimerManager::HandleTimer(&ONflag, &settChanged, // обработка событий таймера отключения лампы
|
||||
&eepromTimeout, &changePower);
|
||||
|
||||
if (FavoritesManager::HandleFavorites( // обработка режима избранных эффектов
|
||||
&ONflag,
|
||||
¤tMode,
|
||||
@@ -292,6 +355,29 @@ void loop()
|
||||
FastLED.clear();
|
||||
delay(1);
|
||||
}
|
||||
|
||||
#if USE_MQTT
|
||||
if (ESP_MODE == 1 && mqttClient && WiFi.isConnected() && !mqttClient->connected())
|
||||
{
|
||||
MqttManager::mqttConnect(); // библиотека не умеет восстанавливать соединение в случае потери подключения к MQTT брокеру, нужно управлять этим явно
|
||||
MqttManager::needToPublish = true;
|
||||
}
|
||||
|
||||
if (MqttManager::needToPublish)
|
||||
{
|
||||
if (strlen(inputBuffer) > 0) // проверка входящего MQTT сообщения; если оно не пустое - выполнение команды из него и формирование MQTT ответа
|
||||
{
|
||||
processInputBuffer(inputBuffer, MqttManager::mqttBuffer, true);
|
||||
}
|
||||
|
||||
MqttManager::publishState();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GENERAL_DEBUG) && GENERAL_DEBUG_TELNET
|
||||
handleTelnetClient();
|
||||
#endif
|
||||
|
||||
ESP.wdtFeed(); // пнуть собаку
|
||||
yield(); // обработать все "служебные" задачи: wdt, WiFi подключение и т.д. (?)
|
||||
}
|
||||
|
342
firmware/GyverLamp_v1.4/MqttManager.h
Normal file
342
firmware/GyverLamp_v1.4/MqttManager.h
Normal file
@@ -0,0 +1,342 @@
|
||||
#ifdef USE_MQTT
|
||||
/*
|
||||
* Библиотека асинхронных MQTT запросов https://github.com/marvinroger/async-mqtt-client
|
||||
* Не умеет автоматически восстанавливать разорванное соединение с MQTT брокером, поэтому требует периодической проверки подключения
|
||||
* Зависит от библиотек:
|
||||
* ESPAsyncTCP https://github.com/me-no-dev/ESPAsyncTCP
|
||||
* AsyncTCP https://github.com/me-no-dev/AsyncTCP
|
||||
* Лампа подписана на топик: LedLamp/LedLamp_xxxxxxxx/cmnd, где xxxxxxxx - ESP.getChipID(); payload - строка, содержащая те же команды, что отправляются приложением (регистр важен):
|
||||
* P_ON - включить матрицу
|
||||
* P_OFF - выключить матрицу
|
||||
* EFF0 - сделать активным эффект №0 (нумерация с нуля)
|
||||
* BRI44 - установить яркость 44; диапазон [1..255]
|
||||
* SPD3 - установить скорость 3; диапазон [1..255]
|
||||
* SCA1 - установить масштаб 1; диапазон [1..100]
|
||||
* ALM_SET1 ON - завести будильник 1 (понедельник); ON - вкл, OFF - выкл
|
||||
* ALM_SET1 390 - установить время будильника 1 (понедельник) на 06:30 (количество минут от начала суток)
|
||||
* DAWN1 - установить "рассвет" за 5 минут до будильника (1 = 5 минут - номер опции в выпадающем списке в приложении, нумерация с единицы)
|
||||
* TMR_SET 1 3 300 - установить таймер; описание параметров - см. команду TMR ниже
|
||||
* FAV_SET 1 60 120 0 0 1 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 - установить режим "избранное", параметры - см. команду FAV ниже
|
||||
* Лампа отправляет своё состояние сразу после включения и после каждого изменения в топик LedLamp/LedLamp_00316765/state; payload:
|
||||
* "CURR 7 14 4 50 1 1 1 0 21:25:50", где:
|
||||
* CURR - идентификатор команды, CURR - текущее состояние лампы
|
||||
* 7 - номер текущего эффекта
|
||||
* 14 - яркость
|
||||
* 4 - скорость
|
||||
* 50 - масштаб
|
||||
* 1 - признак "матрица включена"
|
||||
* 1 - режим ESP_MODE
|
||||
* 1 - признак "работает таймер"
|
||||
* 0 - признак USE_NTP (пытаться синхронизировать время по серверам времени в интернете)
|
||||
* 21:25:50 - текущее время (если не синхронизировано, показывает время от старта модуля)
|
||||
* "ALMS 1 0 0 0 0 0 0 0 390 0 0 0 0 0 0 1"
|
||||
* ALMS - идентификатор команды, ALMS - настройки будильников
|
||||
* первые 7 цифр - признак "будильник заведён" по дням недели, начиная с понедельника
|
||||
* последующие 7 цифр - время в минутах от начала суток, на которое заведён будильник (по дням недели); 390 = 06:30
|
||||
* последняя цифра - опция "рассвет за ... минут", цифра указывает на номер значения в выпадающем списке: 1 - 5 минут, 2 - 10 минут... (см. в приложении)
|
||||
* "TMR 1 3 300"
|
||||
* TMR - идентификатор команды, TMR - таймер
|
||||
* 1 - признак "таймер взведён"
|
||||
* 3 - опция "выключить лампу через ...", цифра указывает на номер значения в выпадающем списке: 1 - не выключать, 2 - 1 минута... (см. в приложении)
|
||||
* 300 - количество секунд, через которое выключится лампа (0 - не выключать)
|
||||
* "FAV 1 60 120 0 0 1 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0"
|
||||
* FAV - идентификатор команды, FAV - избранное
|
||||
* 1 - режим "избранное" включен
|
||||
* 60 - интервал смены эффектов в секундах
|
||||
* 120 - случайный разброс смены эффектов (применяется дополнительно к интервалу) в секундах
|
||||
* 0 - признак "запомнить состояние" вкл/выкл режима "избранное" в энергонезависимую память
|
||||
* оставшиеся цифры - признак (0/1) "эффект №... добавлен в избранные", где номер цифры соотвтетсвует номеру эффекта в списке (см. приложение)
|
||||
*/
|
||||
|
||||
#include <AsyncMqttClient.h>
|
||||
#include "pgmspace.h"
|
||||
#include "Constants.h"
|
||||
#include "Types.h"
|
||||
|
||||
static const char TopicBase[] PROGMEM = "LedLamp"; // базовая часть топиков
|
||||
static const char TopicCmnd[] PROGMEM = "cmnd"; // часть командных топиков (входящие команды лампе)
|
||||
static const char TopicState[] PROGMEM = "state"; // часть топиков состояния (ответ от лампы)
|
||||
|
||||
static const char MqttServer[] PROGMEM = "192.168.0.100"; // строка с IP адресом MQTT брокера
|
||||
static const uint16_t MqttPort = 1883U; // порт MQTT брокера
|
||||
static const char MqttUser[] PROGMEM = ""; // пользователь MQTT брокера
|
||||
static const char MqttPassword[] PROGMEM = ""; // пароль пользователя MQTT брокера
|
||||
static const char MqttClientIdPrefix[] PROGMEM = "LedLamp_"; // id клиента MQTT брокера (к нему будет добавлен ESP.getChipId)
|
||||
|
||||
|
||||
class MqttManager
|
||||
{
|
||||
public:
|
||||
static uint32_t mqttLastConnectingAttempt;
|
||||
static void setupMqtt(AsyncMqttClient* mqttClient, SendCurrentDelegate sendCurrentDelegate);
|
||||
static void mqttConnect();
|
||||
static void onMqttConnect(bool sessionPresent);
|
||||
static void onMqttDisconnect(AsyncMqttClientDisconnectReason reason);
|
||||
static void onMqttMessage(char *topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total);
|
||||
static bool publish(const char *topic, const char *value);
|
||||
static void publishState();
|
||||
static bool needToPublish;
|
||||
static char mqttBuffer[MAX_UDP_BUFFER_SIZE];
|
||||
private:
|
||||
static char* mqttServer;
|
||||
static char* mqttUser;
|
||||
static char* mqttPassword;
|
||||
static char* topicInput; // TopicBase + '/' + MqttClientIdPrefix + ESP.getChipId + '/' + TopicCmnd
|
||||
static char* topicOutput; // TopicBase + '/' + MqttClientIdPrefix + ESP.getChipId + '/' + TopicState
|
||||
static char* clientId;
|
||||
static AsyncMqttClient* mqttClient;
|
||||
static const uint8_t qos = 0U; // MQTT quality of service
|
||||
static const uint32_t connectionTimeout = MQTT_RECONNECT_TIME * 1000U; // период времени для проверки (пере)подключения к MQTT брокеру, 10 секунд
|
||||
static char* byteToHex(char *out, uint8_t value);
|
||||
static bool allocStr(char **str, const char *src);
|
||||
static bool allocStr_P(char **str, PGM_P src);
|
||||
static SendCurrentDelegate sendCurrentDelegate;
|
||||
};
|
||||
|
||||
|
||||
void MqttManager::setupMqtt(AsyncMqttClient* mqttClient, SendCurrentDelegate sendCurrentDelegate)
|
||||
{
|
||||
allocStr_P(&MqttManager::mqttServer, MqttServer);
|
||||
allocStr_P(&MqttManager::mqttUser, MqttUser);
|
||||
allocStr_P(&MqttManager::mqttPassword, MqttPassword);
|
||||
|
||||
MqttManager::mqttClient = mqttClient;
|
||||
MqttManager::sendCurrentDelegate = sendCurrentDelegate;
|
||||
MqttManager::mqttClient->setServer(MqttManager::mqttServer, MqttPort);
|
||||
|
||||
char clientIdBuf[sizeof(MqttClientIdPrefix) + 8];
|
||||
strcpy_P(clientIdBuf, MqttClientIdPrefix);
|
||||
uint32_t chipId = ESP.getChipId();
|
||||
for (uint8_t i = 0; i < 4; ++i)
|
||||
{
|
||||
byteToHex(&clientIdBuf[i * 2 + sizeof(MqttClientIdPrefix) - 1], chipId >> ((3 - i) * 8));
|
||||
}
|
||||
allocStr(&clientId, clientIdBuf);
|
||||
MqttManager::mqttClient->setClientId(clientId);
|
||||
|
||||
if (MqttManager::mqttUser != NULL)
|
||||
{
|
||||
MqttManager::mqttClient->setCredentials(MqttManager::mqttUser, MqttManager::mqttPassword);
|
||||
}
|
||||
|
||||
uint8_t topicLength = sizeof(TopicBase) + 1 + strlen(clientId) + 1 + sizeof(TopicCmnd) + 1;
|
||||
topicInput = (char*)malloc(topicLength);
|
||||
sprintf_P(topicInput, PSTR("%s/%s/%s"), TopicBase, clientId, TopicCmnd); // topicInput = TopicBase + '/' + MqttClientIdPrefix + ESP.getChipId + '/' + TopicCmnd
|
||||
|
||||
topicLength = sizeof(TopicBase) + 1 + strlen(clientId) + 1 + sizeof(TopicState) + 1;
|
||||
topicOutput = (char*)malloc(topicLength);
|
||||
sprintf_P(topicOutput, PSTR("%s/%s/%s"), TopicBase, clientId, TopicState); // topicOutput = TopicBase + '/' + MqttClientIdPrefix + ESP.getChipId + '/' + TopicState
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
LOG.printf_P(PSTR("MQTT топик для входящих команд: %s\n"), topicInput);
|
||||
LOG.printf_P(PSTR("MQTT топик для исходящих ответов лампы: %s\n"), topicOutput);
|
||||
#endif
|
||||
|
||||
mqttClient->onConnect(onMqttConnect);
|
||||
mqttClient->onDisconnect(onMqttDisconnect);
|
||||
mqttClient->onMessage(onMqttMessage);
|
||||
}
|
||||
|
||||
void MqttManager::mqttConnect()
|
||||
{
|
||||
if ((!mqttLastConnectingAttempt) || (millis() - mqttLastConnectingAttempt >= connectionTimeout))
|
||||
{
|
||||
#ifdef GENERAL_DEBUG
|
||||
LOG.print(F("Подключение к MQTT брокеру \""));
|
||||
LOG.print(MqttManager::mqttServer);
|
||||
LOG.print(':');
|
||||
LOG.print(MqttPort);
|
||||
LOG.println(F("\"..."));
|
||||
#endif
|
||||
mqttClient->disconnect();
|
||||
mqttClient->connect();
|
||||
mqttLastConnectingAttempt = millis();
|
||||
}
|
||||
}
|
||||
|
||||
bool MqttManager::publish(const char *topic, const char *value)
|
||||
{
|
||||
if (mqttClient->connected())
|
||||
{
|
||||
#ifdef GENERAL_DEBUG
|
||||
LOG.print(F("Отправлено MQTT: топик \""));
|
||||
LOG.print(topic);
|
||||
LOG.print(F("\", значение \""));
|
||||
LOG.print(value);
|
||||
LOG.println('"');
|
||||
LOG.println();
|
||||
#endif
|
||||
|
||||
return mqttClient->publish(topic, qos, true, value, 0) != 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MqttManager::onMqttConnect(bool sessionPresent)
|
||||
{
|
||||
#ifdef GENERAL_DEBUG
|
||||
LOG.println(F("Подключено к MQTT брокеру"));
|
||||
#endif
|
||||
mqttLastConnectingAttempt = 0;
|
||||
|
||||
mqttClient->subscribe(topicInput, 1);
|
||||
publishState();
|
||||
}
|
||||
|
||||
void MqttManager::onMqttDisconnect(AsyncMqttClientDisconnectReason reason)
|
||||
{
|
||||
#ifdef GENERAL_DEBUG
|
||||
LOG.println(F("Отключено от MQTT брокера"));
|
||||
#endif
|
||||
}
|
||||
|
||||
void MqttManager::onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total)
|
||||
{
|
||||
if (payload != NULL) // сохраняем пришедшее MQTT сообщение для дальнейшей обработки
|
||||
{
|
||||
strncpy(mqttBuffer, payload, len);
|
||||
mqttBuffer[len] = '\0';
|
||||
}
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
LOG.print(F("Получено MQTT:"));
|
||||
LOG.print(F(" топик \""));
|
||||
LOG.print(topic);
|
||||
LOG.print("\"");
|
||||
/*
|
||||
LOG.print(F(" qos: "));
|
||||
LOG.println(properties.qos);
|
||||
LOG.print(F(" dup: "));
|
||||
LOG.println(properties.dup);
|
||||
LOG.print(F(" retain: "));
|
||||
LOG.println(properties.retain);
|
||||
LOG.print(F(" len: "));
|
||||
LOG.println(len);
|
||||
LOG.print(F(" index: "));
|
||||
LOG.println(index);
|
||||
LOG.print(F(" total: "));
|
||||
LOG.println(total);
|
||||
*/
|
||||
LOG.print(F(", значение \""));
|
||||
LOG.print(mqttBuffer);
|
||||
LOG.println("\"");
|
||||
LOG.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
void MqttManager::publishState()
|
||||
{
|
||||
if (mqttBuffer == NULL || strlen(mqttBuffer) <= 0)
|
||||
{
|
||||
sendCurrentDelegate(mqttBuffer); // если буфер MQTT ответа не задан, но метод MQTT публикации вызван, закполняем его текущим состоянием лампы
|
||||
}
|
||||
|
||||
if (mqttBuffer != NULL && strlen(mqttBuffer) > 0)
|
||||
{
|
||||
publish(topicOutput, mqttBuffer); // публикация буфера MQTT ответа
|
||||
mqttBuffer[0] = '\0'; // очистка буфера
|
||||
needToPublish = false; // сброс флага для предотвращения повторной публикации
|
||||
}
|
||||
}
|
||||
|
||||
char* MqttManager::byteToHex(char *out, uint8_t value)
|
||||
{
|
||||
uint8_t b;
|
||||
|
||||
b = value >> 4;
|
||||
if (b < 10)
|
||||
{
|
||||
out[0] = '0' + b;
|
||||
}
|
||||
else
|
||||
{
|
||||
out[0] = 'A' + (b - 10);
|
||||
}
|
||||
b = value & 0x0F;
|
||||
if (b < 10)
|
||||
{
|
||||
out[1] = '0' + b;
|
||||
}
|
||||
else
|
||||
{
|
||||
out[1] = 'A' + (b - 10);
|
||||
}
|
||||
out[2] = '\0';
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool MqttManager::allocStr(char **str, const char *src)
|
||||
{
|
||||
if (src && *src)
|
||||
{
|
||||
if (*str)
|
||||
{
|
||||
void *ptr = realloc(*str, strlen(src) + 1);
|
||||
|
||||
if (!ptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*str = (char*)ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
*str = (char*)malloc(strlen(src) + 1);
|
||||
if (!*str)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
strcpy(*str, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*str)
|
||||
{
|
||||
free(*str);
|
||||
*str = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MqttManager::allocStr_P(char **str, PGM_P src)
|
||||
{
|
||||
if (src && pgm_read_byte(src))
|
||||
{
|
||||
if (*str)
|
||||
{
|
||||
void *ptr = realloc(*str, strlen_P(src) + 1);
|
||||
|
||||
if (!ptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*str = (char*)ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
*str = (char*)malloc(strlen_P(src) + 1);
|
||||
if (!*str)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
strcpy_P(*str, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*str)
|
||||
{
|
||||
free(*str);
|
||||
*str = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
@@ -38,7 +38,7 @@ class OtaManager
|
||||
if (ESP_MODE != 1)
|
||||
{
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.print(F("Запрос обновления по воздуху поддерживается только в режиме ESP_MODE = 1\n"));
|
||||
LOG.print(F("Запрос обновления по воздуху поддерживается только в режиме ESP_MODE = 1\n"));
|
||||
#endif
|
||||
|
||||
return false;
|
||||
@@ -50,7 +50,7 @@ class OtaManager
|
||||
momentOfFirstConfirmation = millis();
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.print(F("Получено первое подтверждение обновления по воздуху\nОжидание второго подтверждения\n"));
|
||||
LOG.print(F("Получено первое подтверждение обновления по воздуху\nОжидание второго подтверждения\n"));
|
||||
#endif
|
||||
|
||||
return false;
|
||||
@@ -61,7 +61,7 @@ class OtaManager
|
||||
OtaFlag = OtaPhase::GotSecondConfirm;
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.print(F("Получено второе подтверждение обновления по воздуху\nСтарт режима обновления\n"));
|
||||
LOG.print(F("Получено второе подтверждение обновления по воздуху\nСтарт режима обновления\n"));
|
||||
#endif
|
||||
|
||||
startOtaUpdate();
|
||||
@@ -80,7 +80,7 @@ class OtaManager
|
||||
momentOfFirstConfirmation = 0;
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.print(F("Таймаут ожидания второго подтверждения превышен\nСброс флага в исходное состояние\n"));
|
||||
LOG.print(F("Таймаут ожидания второго подтверждения превышен\nСброс флага в исходное состояние\n"));
|
||||
#endif
|
||||
|
||||
return;
|
||||
@@ -93,7 +93,7 @@ class OtaManager
|
||||
momentOfOtaStart = 0;
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.print(F("Таймаут ожидания прошивки по воздуху превышен\nСброс флага в исходное состояние\nПерезагрузка\n"));
|
||||
LOG.print(F("Таймаут ожидания прошивки по воздуху превышен\nСброс флага в исходное состояние\nПерезагрузка\n"));
|
||||
delay(500);
|
||||
#endif
|
||||
|
||||
@@ -139,7 +139,7 @@ class OtaManager
|
||||
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.printf_P(PSTR("Start updating %s\n"), type.c_str());
|
||||
LOG.printf_P(PSTR("Start updating %s\n"), type.c_str());
|
||||
#endif
|
||||
});
|
||||
|
||||
@@ -148,7 +148,7 @@ class OtaManager
|
||||
OtaFlag = OtaPhase::Done;
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.print(F("Обновление по воздуху выполнено\nПерезапуск"));
|
||||
LOG.print(F("Обновление по воздуху выполнено\nПерезапуск"));
|
||||
delay(500);
|
||||
#endif
|
||||
});
|
||||
@@ -156,7 +156,7 @@ class OtaManager
|
||||
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total)
|
||||
{
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.printf_P(PSTR("Ход выполнения: %u%%\r"), (progress / (total / 100)));
|
||||
LOG.printf_P(PSTR("Ход выполнения: %u%%\r"), (progress / (total / 100)));
|
||||
#endif
|
||||
});
|
||||
|
||||
@@ -165,42 +165,42 @@ class OtaManager
|
||||
OtaFlag = OtaPhase::None;
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.printf_P(PSTR("Обновление по воздуху завершилось ошибкой [%u]: "), error);
|
||||
LOG.printf_P(PSTR("Обновление по воздуху завершилось ошибкой [%u]: "), error);
|
||||
#endif
|
||||
|
||||
if (error == OTA_AUTH_ERROR)
|
||||
{
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.println(F("Auth Failed"));
|
||||
LOG.println(F("Auth Failed"));
|
||||
#endif
|
||||
}
|
||||
else if (error == OTA_BEGIN_ERROR)
|
||||
{
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.println(F("Begin Failed"));
|
||||
LOG.println(F("Begin Failed"));
|
||||
#endif
|
||||
}
|
||||
else if (error == OTA_CONNECT_ERROR)
|
||||
{
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.println(F("Connect Failed"));
|
||||
LOG.println(F("Connect Failed"));
|
||||
#endif
|
||||
}
|
||||
else if (error == OTA_RECEIVE_ERROR)
|
||||
{
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.println(F("Receive Failed"));
|
||||
LOG.println(F("Receive Failed"));
|
||||
#endif
|
||||
}
|
||||
else if (error == OTA_END_ERROR)
|
||||
{
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.println(F("End Failed"));
|
||||
LOG.println(F("End Failed"));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.print(F("Сброс флага в исходное состояние\nПереход в режим ожидания запроса прошивки по воздуху\n"));
|
||||
LOG.print(F("Сброс флага в исходное состояние\nПереход в режим ожидания запроса прошивки по воздуху\n"));
|
||||
#endif
|
||||
});
|
||||
|
||||
@@ -211,11 +211,11 @@ class OtaManager
|
||||
momentOfOtaStart = 0;
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.printf_P(PSTR("Для обновления в Arduino IDE выберите пункт меню Инструменты - Порт - '%s at "), espHostName);
|
||||
Serial.print(WiFi.localIP());
|
||||
Serial.println(F("'"));
|
||||
Serial.printf_P(PSTR("Затем нажмите кнопку 'Загрузка' в течение %u секунд и по запросу введите пароль '%s'\n"), ESP_CONF_TIMEOUT, AP_PASS);
|
||||
Serial.println(F("Устройство с Arduino IDE должно быть в одной локальной сети с модулем ESP!"));
|
||||
LOG.printf_P(PSTR("Для обновления в Arduino IDE выберите пункт меню Инструменты - Порт - '%s at "), espHostName);
|
||||
LOG.print(WiFi.localIP());
|
||||
LOG.println(F("'"));
|
||||
LOG.printf_P(PSTR("Затем нажмите кнопку 'Загрузка' в течение %u секунд и по запросу введите пароль '%s'\n"), ESP_CONF_TIMEOUT, AP_PASS);
|
||||
LOG.println(F("Устройство с Arduino IDE должно быть в одной локальной сети с модулем ESP!"));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
33
firmware/GyverLamp_v1.4/TelnetManager.ino
Normal file
33
firmware/GyverLamp_v1.4/TelnetManager.ino
Normal file
@@ -0,0 +1,33 @@
|
||||
#if defined(GENERAL_DEBUG) && GENERAL_DEBUG_TELNET
|
||||
|
||||
void handleTelnetClient()
|
||||
{
|
||||
if (telnetServer.hasClient())
|
||||
{
|
||||
if (!telnet || !telnet.connected())
|
||||
{
|
||||
if (telnet)
|
||||
{
|
||||
telnet.stop(); // клиент отключился
|
||||
telnetGreetingShown = false;
|
||||
}
|
||||
telnet = telnetServer.available(); // готов к подключению нового клиента
|
||||
}
|
||||
else
|
||||
{
|
||||
telnetServer.available().stop(); // один клиент уже подключен, блокируем подключение нового
|
||||
telnetGreetingShown = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (telnet && telnet.connected() && telnet.available())
|
||||
{
|
||||
if (!telnetGreetingShown)
|
||||
{
|
||||
telnet.println("Подключение к устройтву по протоколу telnet установлено\n-------");
|
||||
telnetGreetingShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -20,7 +20,7 @@ class TimerManager
|
||||
millis() >= TimerManager::TimeToFire)
|
||||
{
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.print(F("Выключение по таймеру\n\n"));
|
||||
LOG.print(F("Выключение по таймеру\n\n"));
|
||||
#endif
|
||||
|
||||
TimerManager::TimerRunning = false;
|
||||
|
@@ -13,3 +13,5 @@ struct ModeType
|
||||
uint8_t Speed = 30;
|
||||
uint8_t Scale = 40;
|
||||
};
|
||||
|
||||
typedef void (*SendCurrentDelegate)(char *outputBuffer);
|
||||
|
@@ -1,6 +1,8 @@
|
||||
#ifdef ESP_USE_BUTTON
|
||||
bool brightDirection;
|
||||
|
||||
static bool startButtonHolding = false; // флаг: кнопка удерживается для изменения яркости лампы
|
||||
|
||||
void buttonTick()
|
||||
{
|
||||
touch.tick();
|
||||
@@ -23,6 +25,10 @@ void buttonTick()
|
||||
settChanged = true;
|
||||
eepromTimeout = millis();
|
||||
loadingFlag = true;
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ONflag && clickCount == 2)
|
||||
@@ -34,6 +40,10 @@ void buttonTick()
|
||||
eepromTimeout = millis();
|
||||
FastLED.clear();
|
||||
delay(1);
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ONflag && clickCount == 3)
|
||||
@@ -45,9 +55,13 @@ void buttonTick()
|
||||
eepromTimeout = millis();
|
||||
FastLED.clear();
|
||||
delay(1);
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ONflag && clickCount == 4)
|
||||
if (clickCount == 4)
|
||||
{
|
||||
#ifdef OTA
|
||||
if (otaManager.RequestOtaUpdate())
|
||||
@@ -67,34 +81,39 @@ void buttonTick()
|
||||
while(!fillString(WiFi.localIP().toString().c_str())) delay(1);
|
||||
loadingFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ONflag && touch.isHolded())
|
||||
{
|
||||
brightDirection = !brightDirection;
|
||||
startButtonHolding = true;
|
||||
}
|
||||
|
||||
if (ONflag && touch.isStep())
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
uint8_t delta = modes[currentMode].Brightness < 10 // определение шага изменения яркости: при яркости [1..10] шаг = 1, при [11..16] шаг = 3, при [17..255] шаг = 15
|
||||
? 1
|
||||
: 5;
|
||||
modes[currentMode].Brightness =
|
||||
constrain(brightDirection
|
||||
? modes[currentMode].Brightness + delta
|
||||
: modes[currentMode].Brightness - delta,
|
||||
1, 255);
|
||||
FastLED.setBrightness(modes[currentMode].Brightness);
|
||||
settChanged = true;
|
||||
eepromTimeout = millis();
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.printf_P(PSTR("New brightness value: %d\n"), modes[currentMode].Brightness);
|
||||
LOG.printf_P(PSTR("New brightness value: %d\n"), modes[currentMode].Brightness);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
if (ONflag && !touch.isHold() && startButtonHolding) // кнопка отпущена после удерживания, нужно отправить MQTT сообщение об изменении яркости лампы
|
||||
{
|
||||
MqttManager::needToPublish = true;
|
||||
startButtonHolding = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@@ -78,4 +78,8 @@ void changePower()
|
||||
{
|
||||
FavoritesManager::TurnFavoritesOff();
|
||||
}
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
void parseUDP()
|
||||
{
|
||||
int32_t packetSize = Udp.parsePacket();
|
||||
char buff[MAX_UDP_BUFFER_SIZE], *endToken = NULL;
|
||||
|
||||
if (packetSize)
|
||||
{
|
||||
@@ -10,10 +9,39 @@ void parseUDP()
|
||||
strcpy(inputBuffer, packetBuffer);
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.print(F("Inbound UDP packet: "));
|
||||
Serial.println(inputBuffer);
|
||||
LOG.print(F("Inbound UDP packet: "));
|
||||
LOG.println(inputBuffer);
|
||||
#endif
|
||||
|
||||
if (Udp.remoteIP() == WiFi.localIP()) // не реагировать на свои же пакеты
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char reply[MAX_UDP_BUFFER_SIZE];
|
||||
processInputBuffer(inputBuffer, reply, true);
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1) // отправка ответа выполнения команд по MQTT, если разрешено
|
||||
strcpy(MqttManager::mqttBuffer, reply); // разрешение определяется при выполнении каждой команды отдельно, команды GET, DEB, DISCOVER и OTA, пришедшие по UDP, игнорируются (приходят раз в 2 секунды от приложения)
|
||||
#endif
|
||||
|
||||
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
|
||||
Udp.write(reply);
|
||||
Udp.endPacket();
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
LOG.print(F("Outbound UDP packet: "));
|
||||
LOG.println(reply);
|
||||
LOG.println();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void processInputBuffer(char *inputBuffer, char *outputBuffer, bool generateOutput)
|
||||
{
|
||||
char buff[MAX_UDP_BUFFER_SIZE], *endToken = NULL;
|
||||
|
||||
if (!strncmp_P(inputBuffer, PSTR("DEB"), 3))
|
||||
{
|
||||
#ifdef USE_NTP
|
||||
@@ -25,7 +53,7 @@ void parseUDP()
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("GET"), 3))
|
||||
{
|
||||
sendCurrent();
|
||||
sendCurrent(inputBuffer);
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("EFF"), 3))
|
||||
@@ -36,8 +64,12 @@ void parseUDP()
|
||||
loadingFlag = true;
|
||||
FastLED.clear();
|
||||
delay(1);
|
||||
sendCurrent();
|
||||
sendCurrent(inputBuffer);
|
||||
FastLED.setBrightness(modes[currentMode].Brightness);
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("BRI"), 3))
|
||||
@@ -48,7 +80,11 @@ void parseUDP()
|
||||
loadingFlag = true;
|
||||
settChanged = true;
|
||||
eepromTimeout = millis();
|
||||
sendCurrent();
|
||||
sendCurrent(inputBuffer);
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("SPD"), 3))
|
||||
@@ -58,7 +94,11 @@ void parseUDP()
|
||||
loadingFlag = true;
|
||||
settChanged = true;
|
||||
eepromTimeout = millis();
|
||||
sendCurrent();
|
||||
sendCurrent(inputBuffer);
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("SCA"), 3))
|
||||
@@ -68,7 +108,11 @@ void parseUDP()
|
||||
loadingFlag = true;
|
||||
settChanged = true;
|
||||
eepromTimeout = millis();
|
||||
sendCurrent();
|
||||
sendCurrent(inputBuffer);
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("P_ON"), 4))
|
||||
@@ -78,7 +122,11 @@ void parseUDP()
|
||||
settChanged = true;
|
||||
eepromTimeout = millis();
|
||||
changePower();
|
||||
sendCurrent();
|
||||
sendCurrent(inputBuffer);
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("P_OFF"), 5))
|
||||
@@ -87,7 +135,11 @@ void parseUDP()
|
||||
settChanged = true;
|
||||
eepromTimeout = millis();
|
||||
changePower();
|
||||
sendCurrent();
|
||||
sendCurrent(inputBuffer);
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("ALM_SET"), 7))
|
||||
@@ -97,12 +149,12 @@ void parseUDP()
|
||||
if (strstr_P(inputBuffer, PSTR("ON")) - inputBuffer == 9)
|
||||
{
|
||||
alarms[alarmNum].State = true;
|
||||
sendAlarms();
|
||||
sendAlarms(inputBuffer);
|
||||
}
|
||||
else if (strstr_P(inputBuffer, PSTR("OFF")) - inputBuffer == 9)
|
||||
{
|
||||
alarms[alarmNum].State = false;
|
||||
sendAlarms();
|
||||
sendAlarms(inputBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -110,14 +162,19 @@ void parseUDP()
|
||||
alarms[alarmNum].Time = atoi(buff);
|
||||
uint8_t hour = floor(alarms[alarmNum].Time / 60);
|
||||
uint8_t minute = alarms[alarmNum].Time - hour * 60;
|
||||
sendAlarms();
|
||||
sendAlarms(inputBuffer);
|
||||
}
|
||||
EepromManager::SaveAlarmsSettings(&alarmNum, alarms);
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
strcpy(MqttManager::mqttBuffer, inputBuffer);
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("ALM_GET"), 7))
|
||||
{
|
||||
sendAlarms();
|
||||
sendAlarms(inputBuffer);
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("DAWN"), 4))
|
||||
@@ -125,7 +182,11 @@ void parseUDP()
|
||||
memcpy(buff, &inputBuffer[4], strlen(inputBuffer)); // взять подстроку, состоящую последних символов строки inputBuffer, начиная с символа 5
|
||||
dawnMode = atoi(buff) - 1;
|
||||
EepromManager::SaveDawnMode(&dawnMode);
|
||||
sendAlarms();
|
||||
sendAlarms(inputBuffer);
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("DISCOVER"), 8)) // обнаружение приложением модуля esp в локальной сети
|
||||
@@ -143,7 +204,7 @@ void parseUDP()
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("TMR_GET"), 7))
|
||||
{
|
||||
sendTimer();
|
||||
sendTimer(inputBuffer);
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("TMR_SET"), 7))
|
||||
@@ -158,12 +219,16 @@ void parseUDP()
|
||||
TimerManager::TimeToFire = millis() + strtoull(buff, &endToken, 10) * 1000;
|
||||
|
||||
TimerManager::TimerHasFired = false;
|
||||
sendTimer();
|
||||
sendTimer(inputBuffer);
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("FAV_GET"), 7))
|
||||
{
|
||||
FavoritesManager::SetStatus(inputBuffer);
|
||||
FavoritesManager::SetStatus(inputBuffer);
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("FAV_SET"), 7))
|
||||
@@ -172,6 +237,10 @@ void parseUDP()
|
||||
FavoritesManager::SetStatus(inputBuffer);
|
||||
settChanged = true;
|
||||
eepromTimeout = millis();
|
||||
|
||||
#if (USE_MQTT && ESP_MODE == 1)
|
||||
MqttManager::needToPublish = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
else if (!strncmp_P(inputBuffer, PSTR("OTA"), 3))
|
||||
@@ -198,29 +267,16 @@ void parseUDP()
|
||||
return;
|
||||
}
|
||||
|
||||
if (Udp.remoteIP() == WiFi.localIP()) // не реагировать на свои же пакеты
|
||||
if (generateOutput) // если запрошен вывод ответа выполнения команд, копируем его в исходящий буфер
|
||||
{
|
||||
return;
|
||||
strcpy(outputBuffer, inputBuffer);
|
||||
}
|
||||
|
||||
char reply[strlen(inputBuffer) + 1];
|
||||
strcpy(reply, inputBuffer);
|
||||
inputBuffer[0] = '\0'; // очистка буфера, читобы не он не интерпретировался, как следующий udp пакет
|
||||
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
|
||||
Udp.write(reply);
|
||||
Udp.endPacket();
|
||||
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.print(F("Outbound UDP packet: "));
|
||||
Serial.println(reply);
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
inputBuffer[0] = '\0'; // очистка буфера, читобы не он не интерпретировался, как следующий входной пакет
|
||||
}
|
||||
|
||||
void sendCurrent()
|
||||
void sendCurrent(char *outputBuffer)
|
||||
{
|
||||
sprintf_P(inputBuffer, PSTR("CURR %u %u %u %u %u %u"),
|
||||
sprintf_P(outputBuffer, PSTR("CURR %u %u %u %u %u %u"),
|
||||
currentMode,
|
||||
modes[currentMode].Brightness,
|
||||
modes[currentMode].Speed,
|
||||
@@ -229,40 +285,40 @@ void sendCurrent()
|
||||
ESP_MODE);
|
||||
|
||||
#ifdef USE_NTP
|
||||
strcat_P(inputBuffer, PSTR(" 1"));
|
||||
strcat_P(outputBuffer, PSTR(" 1"));
|
||||
#else
|
||||
strcat_P(inputBuffer, PSTR(" 0"));
|
||||
strcat_P(outputBuffer, PSTR(" 0"));
|
||||
#endif
|
||||
|
||||
sprintf_P(inputBuffer, PSTR("%s %u"), inputBuffer, (uint8_t)TimerManager::TimerRunning);
|
||||
sprintf_P(outputBuffer, PSTR("%s %u"), outputBuffer, (uint8_t)TimerManager::TimerRunning);
|
||||
|
||||
#ifdef USE_NTP
|
||||
sprintf_P(inputBuffer, PSTR("%s %s"), inputBuffer, timeClient.getFormattedTime().c_str());
|
||||
sprintf_P(outputBuffer, PSTR("%s %s"), outputBuffer, timeClient.getFormattedTime().c_str());
|
||||
#else
|
||||
sprintf_P(inputBuffer, PSTR("%s %ull"), inputBuffer, millis());
|
||||
sprintf_P(outputBuffer, PSTR("%s %ull"), outputBuffer, millis());
|
||||
#endif
|
||||
}
|
||||
|
||||
void sendAlarms()
|
||||
void sendAlarms(char *outputBuffer)
|
||||
{
|
||||
strcpy_P(inputBuffer, PSTR("ALMS"));
|
||||
strcpy_P(outputBuffer, PSTR("ALMS"));
|
||||
|
||||
for (byte i = 0; i < 7; i++)
|
||||
{
|
||||
sprintf_P(inputBuffer, PSTR("%s %u"), inputBuffer, (uint8_t)alarms[i].State);
|
||||
sprintf_P(outputBuffer, PSTR("%s %u"), outputBuffer, (uint8_t)alarms[i].State);
|
||||
}
|
||||
|
||||
for (byte i = 0; i < 7; i++)
|
||||
{
|
||||
sprintf_P(inputBuffer, PSTR("%s %u"), inputBuffer, alarms[i].Time);
|
||||
sprintf_P(outputBuffer, PSTR("%s %u"), outputBuffer, alarms[i].Time);
|
||||
}
|
||||
|
||||
sprintf_P(inputBuffer, PSTR("%s %u"), inputBuffer, dawnMode + 1);
|
||||
sprintf_P(outputBuffer, PSTR("%s %u"), outputBuffer, dawnMode + 1);
|
||||
}
|
||||
|
||||
void sendTimer()
|
||||
void sendTimer(char *outputBuffer)
|
||||
{
|
||||
sprintf_P(inputBuffer, PSTR("TMR %u %u %u"),
|
||||
sprintf_P(outputBuffer, PSTR("TMR %u %u %u"),
|
||||
TimerManager::TimerRunning,
|
||||
TimerManager::TimerOption,
|
||||
(TimerManager::TimerRunning ? (uint16_t)floor((TimerManager::TimeToFire - millis()) / 1000) : 0));
|
||||
|
@@ -32,7 +32,7 @@ void timeTick()
|
||||
if (!ntpServerAddressResolved)
|
||||
{
|
||||
#ifdef GENERAL_DEBUG
|
||||
Serial.println(F("Функции будильника отключены до восстановления подключения к интернету"));
|
||||
LOG.println(F("Функции будильника отключены до восстановления подключения к интернету"));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ void timeTick()
|
||||
{
|
||||
if (!manualOff) // будильник не был выключен вручную (из приложения или кнопкой)
|
||||
{
|
||||
LOG.println("Будильник включен");
|
||||
// величина рассвета 0-255
|
||||
int32_t dawnPosition = 255 * ((float)(thisTime - (alarms[thisDay].Time - pgm_read_byte(&dawnOffsets[dawnMode]))) / pgm_read_byte(&dawnOffsets[dawnMode]));
|
||||
dawnPosition = constrain(dawnPosition, 0, 255);
|
||||
@@ -75,15 +76,16 @@ void timeTick()
|
||||
}
|
||||
else
|
||||
{
|
||||
// не время будильника (ещё не начался или закончился по времени)
|
||||
if (dawnFlag)
|
||||
{
|
||||
dawnFlag = false;
|
||||
manualOff = false;
|
||||
FastLED.clear();
|
||||
delay(2);
|
||||
FastLED.show();
|
||||
changePower(); // выключение матрицы или установка яркости текущего эффекта в засисимости от того, была ли включена лампа до срабатывания будильника
|
||||
}
|
||||
manualOff = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,7 +104,7 @@ void resolveNtpServerAddress(bool &ntpServerAddressResolved) // ф
|
||||
#ifdef GENERAL_DEBUG
|
||||
if (ntpServerAddressResolved)
|
||||
{
|
||||
Serial.println(F("Подключение к интернету отсутствует"));
|
||||
LOG.println(F("Подключение к интернету отсутствует"));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -113,7 +115,7 @@ void resolveNtpServerAddress(bool &ntpServerAddressResolved) // ф
|
||||
#ifdef GENERAL_DEBUG
|
||||
if (!ntpServerAddressResolved)
|
||||
{
|
||||
Serial.println(F("Подключение к интернету установлено"));
|
||||
LOG.println(F("Подключение к интернету установлено"));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Reference in New Issue
Block a user