• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

ESP WebSocket примеры

zsm812

New member
Друзья , поделитесь пожалуйста примерами двухстороннего обмена данных ESP32 и вебстраницы через WebSocket , этот пример не могу постичь до конца, пытаюсь вывести на страницу примера значения с DTH22 но значения обновляются только с перезагрузкой страницы.
 

CodeNameHawk

Moderator
Команда форума
Вы хотите, чтобы мы угадали, что делаете нет, не видя кода?
 

zsm812

New member
Вы хотите, чтобы мы угадали, что делаете нет, не видя кода?
Ни в коем случае, прошу лишь примеры покидать.

Код:
/*********
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-websocket-server-arduino/
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*********/

// Import required libraries
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "DHT.h"
#define DHTPIN 17
DHT dht(DHTPIN, DHT22);

// Replace with your network credentials
const char* ssid = "*****";
const char* password = "*****";

String temperature;
String humidity;

bool ledState = 0;
const int ledPin = 2;

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>ESP Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <style>
  html {
    font-family: Arial, Helvetica, sans-serif;
    text-align: center;
  }
  h1 {
    font-size: 1.8rem;
    color: white;
  }
  h2{
    font-size: 1.5rem;
    font-weight: bold;
    color: #143642;
  }
  .topnav {
    overflow: hidden;
    background-color: #143642;
  }
  body {
    margin: 0;
  }
  .content {
    padding: 30px;
    max-width: 600px;
    margin: 0 auto;
  }
  .card {
    background-color: #F8F7F9;;
    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
    padding-top:10px;
    padding-bottom:20px;
  }
  .button {
    padding: 15px 50px;
    font-size: 24px;
    text-align: center;
    outline: none;
    color: #fff;
    background-color: #0f8b8d;
    border: none;
    border-radius: 5px;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: rgba(0,0,0,0);
   }
   /*.button:hover {background-color: #0f8b8d}*/
   .button:active {
     background-color: #0f8b8d;
     box-shadow: 2 2px #CDCDCD;
     transform: translateY(2px);
   }
   .state {
     font-size: 1.5rem;
     color:#8c8c8c;
     font-weight: bold;
   }
  </style>
<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 Server</h1>
  </div>
  <div class="content">
    <div class="card">
      <h2>Output - GPIO 2</h2>
      <p class="state">state: <span id="state">%STATE%</span></p>
      <p class="state">temp: <span id="temp">%TEMP%</span></p>
      <p><button id="button" class="button">Toggle</button></p>
    </div>
  </div>
<script>
  var gateway = `ws://${window.location.hostname}/ws`;
  var websocket;
  window.addEventListener('load', onLoad);
  function initWebSocket() {
    console.log('Trying to open a WebSocket connection...');
    websocket = new WebSocket(gateway);
    websocket.onopen    = onOpen;
    websocket.onclose   = onClose;
    websocket.onmessage = onMessage; // <-- add this line
  }
  function onOpen(event) {
    console.log('Connection opened');
  }
  function onClose(event) {
    console.log('Connection closed');
    setTimeout(initWebSocket, 2000);
  }
  function onMessage(event) {
    var state;
    if (event.data == "1"){
      state = "ON";
    }
    else{
      state = "OFF";
    }
    document.getElementById('state').innerHTML = state;
  }
  function onLoad(event) {
    initWebSocket();
    initButton();
  }
  function initButton() {
    document.getElementById('button').addEventListener('click', toggle);
  }
  function toggle(){
    websocket.send('toggle');
  }
</script>
</body>
</html>
)rawliteral";

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();
      digitalWrite(ledPin, ledState);
    }
  }
}

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";
    }
  }

  if(var == "TEMP"){

       return String(temperature) ;
    }

 
  return String();
}

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, 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();

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Start server
  server.begin();

   dht.begin();
}

void loop() {
  ws.cleanupClients();
  temperature=String(dht.readTemperature());
  humidity=String(dht.readHumidity());
  Serial.println(temperature);
  Serial.println(humidity);
 
  delay(2000);
 
}
 
пытаюсь вывести на страницу примера значения с DTH22 но значения обновляются только с перезагрузкой страницы.
Посмотрите что выводится в отладочной консоли браузера, и в Serial порт на ESP32.
ps: Тема вообще то не совсем тривиальная, ибо ESP может поддерживать ограниченное к-во соединений. Следует внимательно следить за закрытием ранее открытых каналов. Прогуляйтесь по ссылкам ниже, там я приводил упрощенные примеры по мотивам Rui Santos. Они, на мой взгляд, куда понятнее для понимания и модификации.

 

CodeNameHawk

Moderator
Команда форума
Первое нет ваших комментариев, типа, добавил эту строку, а делает это и это, если произошло это.
Второе delay тут точно не годится, цикл loop должен крутится без задержек, чтобы соцкеты могли работать.
Опрос температуры и её отправку организуйте при помощи millis.
 

zsm812

New member
Спасибо , буду изучать. delay не мешает серверу как ни странно, нажатия отрабатываются без задержки двухсекундной.
 

zsm812

New member
Друзья , спасибо , удалось динамически выводить температуру и влажность в примере с кнопками от humaxoid ( перенесенный на файловую систему пример отсюда)
посылаю так:
Код:
ws.textAll("temperature1=" + String(t));
на странице разбираю так:
Код:
var arrayS = event.data.split("=");
  switch (trim = arrayS[0]) {
    case 'temperature1': document.getElementById("temp").innerHTML = arrayS[1]; break
    case 'humidity1': document.getElementById("hum").innerHTML = arrayS[1]; break
    }
не знаю на сколько это правильно, но работает, и кнопкам не мешает.

теперь обратная задача , пытаюсь послать данные из формы на странице в контроллер и к примеру вывести в серийный порт.

нажатие на кнопку "Готово" вызывает функцию

Код:
function Complete()
        {
           var Elem = document.Sel1.Message.value;
           alert(Elem);
           websocket.send('message'+ Elem)
        }
которая посылает ключ 'message' + данные из формы на WS сервер, но как разобрать вообще не врубаюсь, т.к. эта часть кода практически непонятна кроме изменения 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, "toggle1") == 0) {ledState1 = !ledState1;notifyClients1();}
    if (strcmp((char*)data, "toggle2") == 0) {ledState2 = !ledState2;notifyClients2();}
    if (strcmp((char*)data, "toggle3") == 0) {ledState3 = !ledState3;notifyClients3();}
    if (strcmp((char*)data, "toggle4") == 0) {ledState4 = !ledState4;notifyClients4();}
    if (strcmp((char*)data, "toggle5") == 0) {ledState5 = !ledState5;notifyClients5();}
    if (strcmp((char*)data, "toggle6") == 0) {ledState6 = !ledState6;notifyClients6();}
    if (strcmp((char*)data, "message") == 0) {Serial.println("OK");}

  }
}
пока просто ОК печатается когда "message" приходит.
прилагаю проект и библиотеки.
 
та часть кода практически непонятна кроме изменения ledState )) .
У меня библиотека другая но общий смысл примерно такой же. Так мой type это похоже ваш info->opcode
передаю я со стороны html страницы команды(message по вашему) вида [p0, p1...] мой payload это ваша data

C:
void webSocketEvent(byte num, WStype_t type, uint8_t * payload, size_t length){
    switch(type)
    {
      case WStype_ERROR:
        //Serial.printf("info: [%u] WStype_ERROR\n ",num);
        break;
      case WStype_DISCONNECTED:
        //Serial.printf("info: [%u] WStype_DISCONNECTED\n",num);
        //Serial.printf("info: [%u] Clients=%u \n",num, webSocket.connectedClients(true));
        break;
      case WStype_CONNECTED :
        //Serial.printf("info: [%u] WStype_CONNECTED\n");
        //Serial.printf("info: [%u] Clients=%u \n",num, webSocket.connectedClients(true));
        break;
      case WStype_BIN :
        //Serial.printf("info: [%u] WStype_BIN\n",num);
        break;
      case WStype_FRAGMENT_TEXT_START :
        //Serial.printf("info: [%u] WStype_FRAGMENT_TEXT_START\n",num);
        break;
      case WStype_FRAGMENT_BIN_START :
        //Serial.printf("info: [%u] WStype_FRAGMENT_BIN_START\n",num);
        break;
      case WStype_FRAGMENT :
        //Serial.printf("info: [%u] WStype_FRAGMENT\n",num);
        break;
      case WStype_FRAGMENT_FIN :
        //Serial.printf("info: [%u] WStype_FRAGMENT_FIN\n",num);
        break;
      case WStype_PING :
        //Serial.printf("info: [%u] WStype_PING\n",num);
        break;
      case WStype_PONG :
        //Serial.printf("info: [%u] WStype_PONG\n",num);
        break;
      case WStype_TEXT:
        Serial.printf("info;[%u] WStype_TEXT %s\n",num, payload);
        if(length==2)
        {
          if((char) payload[0]=='p')
          {
              switch((char) payload[1]){
              case '0':
                sendCode(post0On,post0Off);
                webSocket.broadcastTXT("info: ping0");
                break;
              case '1':
                sendCode(post1On,post1Off);
                break;
              case '2':
                sendCode(post2On,post2Off);
                break;
              case '3':
                sendCode(post3On,post3Off);
                break;
              case '4':
                sendCode(post4On,post4Off);
                break;
              case '5':
                sendCode(post5On,post5Off);
                break;
              case '6':
                pingAll();
                break;
              case '7':
                pingOffAll();
                break;
              }
          }
        }
        break;
    }
}
 

p-a-h-a

Member
Ковырялся тоже с библиотекой WebSockets от Markus Sattler (стандартная из менеджера библиотек гитхаб).
1690631974394.png
Пример набросал. Несколько раз в секунду страничка получает json данные. При движении слайдера и по кнопке отправляет данные на ESP8266. Время отображено в микросекундах. Логин и пароль от wifi пишем в 79 строке.
C++:
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WebSocketsServer.h> //
#include <ESP8266WebServer.h>

ESP8266WebServer server(80);
WebSocketsServer webSocket(81);

uint32_t loopCounter, maxSendTime, sendTime, sliderValue;

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>

<head>
    <title>ESP Web Server</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <h1>ESP WebSocket Server</h1>
    <input id="Slider" type="range" min="0" max="255" value="Slider value: 0" step="1" oninput="sendDats();" />
    <p id="Slider_text"></p>
    <p class="state">Incoming text: <span id="state">0</span></p>
    <p><button id="button" class="button">Reset</button></p>

    <script>
        let gateway = `ws://${window.location.hostname}:81/`;
        let websocket;
        window.addEventListener('load', onLoad);
        function initWebSocket() {
            websocket = new WebSocket(gateway);
            websocket.onclose = onClose;
            websocket.onmessage = onMessage;
        }
        function onClose(event) {
            setTimeout(initWebSocket, 100);
        }
        function onMessage(event) {
            let state;
            state = event.data;
            //console.log(JSON.parse(event.data));
            document.querySelector("#state").textContent = state;
            document.querySelector("#Slider_text").textContent = "Slider value: " + JSON.parse(event.data).sliderValue;
        }
        function onLoad(event) {
            initWebSocket();
            document.getElementById('button').addEventListener('click', reset);
        }
        function reset() {
            websocket.send('reset');
        }
        function sendDats() {
            let sendValue = parseInt(document.getElementById('Slider').value).toString();
            websocket.send(sendValue);
        }
    </script>
</body>

</html>
)rawliteral";

void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length)
{
  if (type == WStype_TEXT)
  {
    Serial.printf("[%u] get Text: %s\n", num, payload);
    sliderValue = atoi((char *)payload);

    if (strcmp((char *)payload, "reset") == 0)
      maxSendTime = loopCounter = 0;
  }
}

void setup()
{
  Serial.begin(115200);
  WiFi.begin("ZyXEL");

  while (WiFi.status() != WL_CONNECTED)
    yield();

  webSocket.begin();
  webSocket.onEvent(webSocketEvent);

  server.on("/", []()
            { server.send(200, "text/html", index_html); });
  server.begin();
}

void loop()
{
  delay(10);
  webSocket.loop();
  server.handleClient();

  String sendString = "{\"sendTime\":" + String(sendTime) +
                      ",\"maxSendTime\": " + String(maxSendTime) +
                      ",\"loopCounter\":" + String(loopCounter++) +
                      ",\"sliderValue\":" + String(sliderValue) +
                      "}";

  uint32_t startTime = micros();
  webSocket.broadcastTXT(sendString);
  sendTime = micros() - startTime;
  if (sendTime > maxSendTime)
    maxSendTime = sendTime;
}
 
Сверху Снизу