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

Как подружить WebSocketsServer с ESP8266HTTPClient?

Vovka

Member
Суть в следующем: соединение по сокету рвется после http-запроса к сайту.
Вот создал тестовый пример:
Код:
#define W_NAME    "*****"
#define W_PASSW    "*****"
#define W_SITE    "test.com"
#define W_SITE_PORT    80

#include <Wire.h>
#include <ESP8266WiFi.h>

#include <WebSocketsServer.h>
#include <Hash.h>
WebSocketsServer webSocket = WebSocketsServer(81);
void webSocketEvent(uint8_t num                    // IP
                                        , WStype_t type            // тип сообщения
                                        , uint8_t *payload    // сообщение
                                        , size_t length            // длина сообщения
    ) {
    String s;
    switch(type) {
    case WStype_DISCONNECTED: {    Serial.printf("webSocketEvent([%u]): Disconnected!\n", num);    break;    }
        case WStype_CONNECTED: {
            IPAddress ip = webSocket.remoteIP(num);
            Serial.printf("webSocketEvent([%u]): Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
            webSocket.sendTXT(num, "Connected!!!");    break; }
        case WStype_TEXT:{
            Serial.printf("webSocketEvent([%u]): get Text: %s\n", num, payload);
            if( length>6 && (strcmp((const char *)payload,"ws:ping")==0)){
                Serial.printf("webSocketEvent([%u]) send Text: %s\n", num, "esp:pong" );
                webSocket.sendTXT(num, "esp:pong");
                break;
            }
            // send message to client
            s = "message here: ";    s.concat( (const char *)payload, length );    webSocket.sendTXT(num, s);
//            webSocket.broadcastTXT("message here");    // send data to all connected clients
            break;
        }
        case WStype_BIN: {
            Serial.printf("webSocketEvent([%u]): get binary length: %u\n", num, length);
            hexdump(payload, length);
            // send message to client
            webSocket.sendBIN(num, payload, length);
            break;
        }
    }
}

#include <ESP8266WiFiMulti.h>
ESP8266WiFiMulti WiFiMulti;
#include <ESP8266WebServer.h>
ESP8266WebServer HTTP(80);
//#include <ESP8266HTTPUpdateServer.h>    // для обновления через WEB
//ESP8266HTTPUpdateServer httpUpdater;
#include <ESP8266HTTPClient.h>
HTTPClient http;

#include "web.h"
void handleNotFound(){
    String s;
    s = FPSTR(_htm_test);
    HTTP.send(200, "text/html", s );
}

static bool b1sec = false;
static bool b20sec = false;
static os_timer_t timer1s;
static char count20s = 20;
void timer1s_func()
{
    b1sec = true;
    if( !b20sec ) {
        if( count20s ) count20s--;
        if( !count20s ) { count20s = 20; b20sec = true; }
    }
}

void setup()
{
    Serial.begin(19200);
    // Serial.setDebugOutput(true);
    Serial.println();
    Serial.println();
    Serial.println();
    for(uint8_t t = 5; t > 0; t--) {
        Serial.printf("[SETUP] WAIT %d...\n", t);
        Serial.flush();
        delay(1000);
    }
    WiFiMulti.addAP( W_NAME, W_PASSW );

    WiFi.config(IPAddress(192, 168, 1, 254), IPAddress(192, 168, 1, 1), IPAddress(255, 255, 255, 0));

    Serial.print( "SETUP(). Go connect router" );
    while( WiFiMulti.run() != WL_CONNECTED ) {
        Serial.print("."); delay(1000);
    }
    Serial.print(" OK. IP="); Serial.println( WiFi.localIP() );

//    httpUpdater.setup(&HTTP, "/upd", "admin", "admin" ); // для ОТА

    HTTP.onNotFound(handleNotFound);
    // Запускаем HTTP сервер
    HTTP.begin();
    webSocket.begin();
    webSocket.onEvent(webSocketEvent);

    // запустим таймер 1сек
    os_timer_disarm(&timer1s);
    os_timer_setfn(&timer1s, (os_timer_func_t *)&timer1s_func, NULL);
    os_timer_arm(&timer1s, 1000, 1);    // 1000 миллисекунд=1cек, 1 - многократно. 0 -однократно.
}

void loop()
{
    String s;

    // ожидание WiFi соединения
    if( WiFiMulti.run() == WL_CONNECTED ) {
        HTTP.handleClient();
        webSocket.loop();
        if( b1sec ) {
            time_t t;
            tm *pt;
            t = time(nullptr);    pt = localtime(&t);
            s  = String( pt->tm_hour ); s += ":";
            s += String( pt->tm_min  ); s += ":";
            s += String( pt->tm_sec  ); s += " ";
            s += String( pt->tm_mday ); s += ".";
            s += String( pt->tm_mon+1); s += ".";
            s += String( pt->tm_year );
            webSocket.broadcastTXT( s ); // все подключившимся
            Serial.println( s );
            b1sec = false;
        }
        if( b20sec ) {
            Serial.print("[HTTP] begin...\n");
            if( http.begin( W_SITE, W_SITE_PORT, "/esp.php") ) {
                Serial.print("[HTTP] GET...\n");
                int httpCode = http.GET();
                if( httpCode ) {
                    // HTTP header has been send and Server response header has been handled
                    Serial.printf("[HTTP] GET... code: %d\n", httpCode);
                    // файл найден на сервере
                    if( httpCode == 200 ) {
                        String payload = http.getString();
                        Serial.println( payload );
                        webSocket.broadcastTXT( payload );
                    }
                } else {
                    Serial.print("[HTTP] GET... failed, no connection or no HTTP server\n");
                }
                http.end();
            }
            b20sec = false;
        }
    }

}
Код:
const char _htm_test[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html><head>
<meta http-equiv='Content-Type' content='text/html; charset=windows-1251'>
<meta http-equiv='Content-Language' content='ru'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<meta http-equiv='pragma' content='no-cache'>
<meta http-equiv='cache-control' content='no-cache'>
<title>TEST</title>
<script language='javascript'>
function startWebsocket() {
    var adr='ws://192.168.1.254:81/';
    var connection = new WebSocket(adr);
    var wsstat=-1; //Статус подключения
    var wsp=0;
    var idd=document.getElementById('lans');
    idd.innerHTML='Попытка подключения...';
    function wsping(){
        if(wsstat!=connection.readyState){
            wsstat=connection.readyState;
            switch(wsstat){
                case 0: idd.innerHTML='Соединение ещё не открыто';break;
                case 1: idd.innerHTML=''; break;
                case 2: idd.innerHTML='Соединение в процессе закрытия';break;
                case 3: idd.innerHTML='Соединение закрыто или не может открыться';break;
            }
        }
        connection.send('ws:ping');
        wsp=setTimeout(wsping, 2500);
    }
    connection.onopen = function () {
        idd.innerHTML='подключено';
        wsp=setTimeout(wsping, 2500);
    };
    connection.onclose = function(evt) {
     if(wsp)clearTimeout(wsp);wsp=0;wsstat=0;
     idd.innerHTML= 'WebSocket CLOSED: ('+evt.code+') '+evt.reason;
     connection=0;setTimeout(startWebsocket, 5000);
    };
    connection.onerror = function (error) {
        idd.innerHTML = 'WebSocket Error: ' + error.message;
    };
    connection.onmessage = function (evt) {
        var data=evt.data;
        if(typeof(data)=='string'&&data!=='esp:pong') idd.innerHTML=data;
        clearTimeout(wsp);wsp=setTimeout(wsping, 2500);
    };
}
window.onload=function(){startWebsocket()};
</script>
</head><body>
<h3>T е с т</h3>
<span id='lans'>&nbsp;</span>
</body></html>
)rawliteral";

Когда заходим по IP, есп выдает html-страничку, которае делает соединение с есп по сокету. есп раз в секунду (для наглядности) отправляет время-дату.
Все работает, пока есп не отсчитает 20 секунд (продовал и другое время) и делает http-запрос к сайту в интернете. После этого соединение по сокету обрывается!
Как это исправить?
 
Сверху Снизу