Вэбсокет и извращения над ним.
- Войдите на сайт для отправки комментариев
Добрыйго времени суток!
Как пример привожу код управление одной кнопкой про протоколу websocket. Хотелось бы поизвращатся над ним так, что бы получить более широкие возможности и понять как это рабтает. Это очень бы пригодилось в разных проектах и наверное не только мне. И так, сам исходник.
Код:
#include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> // Replace with your network credentials const char* ssid = "ssid"; const char* password = "******"; bool ledState = 0; // Create AsyncWebServer object on port 80 AsyncWebServer server(80); AsyncWebSocket ws("/ws"); void notifyClients() { ws.textAll(String(ledState)); } void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) { AwsFrameInfo *info = (AwsFrameInfo*)arg; if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) { data[len] = 0; if (strcmp((char*)data, "toggle") == 0) { ledState = !ledState; notifyClients(); } } } void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { switch (type) { case WS_EVT_CONNECT: Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); break; case WS_EVT_DISCONNECT: Serial.printf("WebSocket client #%u disconnected\n", client->id()); break; case WS_EVT_DATA: handleWebSocketMessage(arg, data, len); break; case WS_EVT_PONG: case WS_EVT_ERROR: break; } } void initWebSocket() { ws.onEvent(onEvent); server.addHandler(&ws); } String processor(const String& var){ Serial.println(var); if(var == "STATE"){ if (ledState){ return "ON"; } else{ return "OFF"; } } return String(); } void setup(){ // Serial port for debugging purposes Serial.begin(115200); pinMode(25, OUTPUT); digitalWrite(25, LOW); // Connect to Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi.."); } // Print ESP Local IP Address Serial.println(WiFi.localIP()); initWebSocket(); // Инициализируем SPIFFS: if (!SPIFFS.begin(true)) { // Serial.println("При монтировании SPIFFS произошла ошибка"); return; } // Route for root / web page server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { request->send(SPIFFS, "/index.html", "text/html", false, processor); }); // Start server server.begin(); } void loop() { ws.cleanupClients(); digitalWrite(25, ledState); }
JS
var gateway = `ws://${window.location.hostname}/ws`; var websocket; window.addEventListener('load', onLoad); // Инициализация обработчика нажатий кнопок: function onLoad(event) { initWebSocket(); initButton(); } function initWebSocket() { console.log('Попытка открыть соединение с веб-сокетом...'); websocket = new WebSocket(gateway); websocket.onopen = onOpen; websocket.onclose = onClose; websocket.onmessage = onMessage; } function onOpen(event) { console.log('Соединение открыто'); } function onClose(event) { console.log('Соединение закрыто'); setTimeout(initWebSocket, 2000); } function onMessage(event) { switch(event.data) { case '0': document.getElementById("state1").innerHTML = "OFF"; break case '1': document.getElementById("state1").innerHTML = "ON"; break } } function initButton() { document.getElementById('button').addEventListener('click', toggle1); } function toggle1() { websocket.send('toggle'); }
HTML
<!DOCTYPE HTML><html> <head> <title>ESP Web Server</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" href="data:,"> <title>ESP Web Server</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" href="data:,"> </head> <body> <div class="topnav"> <h1>ESP WebSocket сервер</h1> </div> <div class="content"> <div class="card"> <h2>Output - GPIO 2</h2> <p class="state">state: <span id="state">%STATE%</span></p> <p><button id="button" class="button">Toggle</button></p> </div> </div> </body> </html>
Эксперимент №1:
Сделать так, что бы кнопка срабатывала не только от нажатия, но и от показания датчика температуры. Скажем если температура превышает 25 гр. (будем считать что у нас универсальный датчик BME280, необходимые библиотеки типа установлены).
Заменить условие из строки 23 как указано ниже не проканает.
// if (strcmp((char *)data, "toggle") == 0) // заменить это if (bme.readTemperature() > 25) == 0) // на это
Хетелось бы понять как эта строка работает и как правильно совместить эти два условия?
Использовать логическое «или» (||), так в одном if оба условия объединишь.
Никак не работает. Во второй строке не хватает круглой скобки. А по первой, должно сравнивать пришедшую строку со строковым литералом "toogle", если есть совпадение, тогда выражение будет истинным, т.е ==0.
Если нужно заменить, тогда так должно быть: if (bme.readTemperature() > 25) Если совместить, то оба условия через || или or
Никак не работает. Во второй строке не хватает круглой скобки. А по первой, должно сравнивать пришедшую строку со строковым литералом "toogle", если есть совпадение, тогда выражение будет истинным, т.е ==0.
Если нужно заменить, тогда так должно быть: if (bme.readTemperature() > 25) Если совместить, то оба условия через || или or
Спасибо! С логическим оператором (или) всё ясно. Но до него даже очередь не дошла. У меня даже тупо замена не сработала.
Компилистя без ошибок, но условие не срабатывает. Может это связано с тем, что условие if (bme.readTemperature() > 25) спрятано внутри функции void handleWebSocketMessage?
bme.readTemperature() вообще никаким местом не связано с работой по сети.
Я его и в приведенном коде не наблюдаю
Возможно это связано с тем, что температура окружающей среды <25 ?
Скорее всего связано это с тем, что обсуждается код, который кроме ТС никто в глаза не видел )))
Я имею ввиду код с датчиком.
Скорее всего связано это с тем, что обсуждается код, который кроме ТС никто в глаза не видел )))
Я имею ввиду код с датчиком.
Конечно с ним! Исправляюсь, привожу код с датчиком.
Из loop в последовательный монитор температура выводится. Услувие if (bme.readTemperature() > 23) не опрашивается.
Потому что handleWebSocketMessage() не вызывается. Значит нужно иначе, например в loop’е.
Потому что handleWebSocketMessage() не вызывается. Значит нужно иначе, например в loop’е.
А куда деватся? Пришлось в loop-е мудрить. Только код малость громоздкий получается для такой маленькой задачки. Да и некоторые команды приходится дублировать, которые уже есть выше. И всё из-за того что внутри handleWebSocketMessage() не вызывается, то что мне так необходимо.
Слушай Бум, а можно как нибудь извратится так, что бы bme.readTemperature() > 25 опросить в loop'е, а результат сравнения отправить на исполнение выше, а именно в handleWebSocketMessage() ?
А смысл отправки этой? Все равно хэндлер только когда ты через вэб работаешь вызывается.
А смысл отправки этой? Все равно хэндлер только когда ты через вэб работаешь вызывается.
Смысл в том, что вместо всего этого нагромождения достаточно быбло бы в loop'e опросить это
При выполнении условия, отправить в хэндлер это
Тогда не понадобится весь этот громоздкий код что я привел чуть выше. Ну да ладно. Переходим к следущему извращению :)
Эксперимент №2:
Теперь прикрутил к нему таймер на миллис.
Таймер работает нормально. Может туплю, но очень хочется знать как подсчитать остаток времени до срабатывания таймера? Хочу этот остаток времени вывести в переменную и в дальнейшем отправить на вэб. панель или последовательный монитор например. Миллис, начинает отсчет с момента загрузки кода. Контроллер то знает, включили- пора считать. А мне как узнать когда его включили? :)
А как вы узнаёте, сколько яйцо варилось?
А как вы узнаёте, сколько яйцо варилось?
Так видно ж - если покраснело, то мало варилось, а если больно - варилось долго.
Теперь тема действительно про извращения становится.
А смысл отправки этой? Все равно хэндлер только когда ты через вэб работаешь вызывается.
Смысл в том, что вместо всего этого нагромождения достаточно быбло бы в loop'e опросить это
При выполнении условия, отправить в хэндлер
Ну тогда Вам нужно лезть в библиотеку и разбираться как вызывается этот самый хэндлер, просто - али с чем еще это связано и т.п.
А как вы узнаёте, сколько яйцо варилось?
Так видно ж - если покраснело, то мало варилось, а если больно - варилось долго.
Теперь тема действительно про извращения становится.
Именно так это и реализуется - через вычисление разницы.
А вот ваши фантазии про какие-то режимы ожидания таймера на миллис, включение и выключения его и пр. в контексте Wiring не имеют ничего общего с реальностью.