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

Устройство с ESP8266, отправка данных в реальном времени

Legion12

New member
Добрый день, форумчане.
Я "как обычно" - ничего похожего не нашла, поэтому делюсь в новой теме, прошу ткнуть носом, коли не знала :(

Постараюсь описать как можно подробнее:

1. Есть устройство, к которому подключается ESP8266.
2. Устройство шлет в COM-порт данные в формате JSON, ESP8266 по тому же COM-порту их принимает.
3. На веб-странице реализован XMLHttpRequest.
4. С веб-страницы шлется запрос, ESP8266 берет из COM-порта строку - JSON - и шлет в браузер.
5. JSON прилетает, спокойно парсится на уровне веб-страницы, данные выводятся куда надо.

Это все понятно, это все работает, это все проверено.

Проблема в том, что это все должно происходить в РЕЖИМЕ РЕАЛЬНОГО ВРЕМЕНИ. Данные с устройства в COM-порт идут беспрерывно, с задержкой минимум в 10мс, максимум в 200мс, и их точно также беспрерывно нужно выводить на веб-страницу.

Постоянно слать запросы - не вариант.
Во-первых, проблема в javascript - xmlhttprequest напрочь отказывается работать в цикле. Решение запихать его в setInterval(function, delay):
JavaScript:
  setInterval (function request() {
          var answer;
           xhr.open('GET', 'W', true);
     xhr.onreadystatechange = function() {
        if(this.readyState == 4 && this.status == 200) {
         answer = JSON.parse(this.responseText);
        p.innerHTML = answer.P;
        s.innerHTML = answer.S;
        }
      }
      xhr.send(''); },600);
Работает, да, но функция асинхронная, поэтому не успев получить данные, уже шлет новые запросы. Как заставить ее работать в режиме "получил данные - только после этого шли запрос" я не пойму.
И здесь же - во-вторых, от кучи принятых ответов браузер в один прекрасный момент(где-то через полчаса) делает "ЧПОК" и виснет намертво. Предполагается, что устройство работает долгие часы, и такого сбоя происходить не должно. Как удалять из кэша браузера обработанные ответы на запрос - тоже тайна.

В общем-то мне самой кажется, что все это реализовано крепко неправильно и меня побьют:(
В этой связи: а есть ли вообще способы реализовать постоянную отправку данных на веб-страницу, минуя xmlhttprequest? Если нет, то как жить?:(
ESP программируется в ArduinoIDE.
 

pvvx

Активный участник сообщества
Основной вариант: Отказаться от AJAX и использовать websocket (!)

Прочие глупости:
JavaScript:
// Onload = GetNewAjax()

GetNewAjax() {ajax_get('/_myjsonfile_', ajax_cb,'{_json_post_data_}');}

ajax_cb(o){
    if(!o) return;
    ....
    setTimeout("GetNewAjax()", 100);
}

// Функция передачи и запроса данных
function ajax_get(url, callback, code) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4) {
            console.log('response: ' + xmlhttp.status);
            if (xmlhttp.status == 200) {
                if (typeof xmlhttp.response === 'string') callback(JSON.parse(xmlhttp.response));
                else callback(xmlhttp.response);
            }
            else callback(null);
            xmlhttp.abort();
            xmlhttp = null;
        }
    };
    xmlhttp.ontimeout = function() {callback(null);};
    // option:
    if(window.location.protocol == 'file:') {
        xmlhttp.open("POST", 'http://xxxx.local'+url, true);
        xmlhttp.setRequestHeader("Authorization", "Basic ???????=");
    } else
        xmlhttp.open("POST", url, true);
    xmlhttp.timeout = 4000;
       xmlhttp.responseType = "json";
    xmlhttp.send(code);
}
 

pvvx

Активный участник сообщества
Предполагается, что устройство работает долгие часы, и такого сбоя происходить не должно.
Для или с ESP это несовместимо.
Как удалять из кэша браузера обработанные ответы на запрос - тоже тайна.
Примеры Выключение кэширования и прочее в поиске "HTTP no cache"

 

pvvx

Активный участник сообщества
Работает, да, но функция асинхронная, поэтому не успев получить данные, уже шлет новые запросы. Как заставить ее работать в режиме "получил данные - только после этого шли запрос" я не пойму.
Сам пример дан ранее.
Так-же в функции ajax_get() вы можете описать вызовы ваших функций по любым ошибкам.
Ещё пример:
Код:
function ajax_get(d) {
    var xhr; 
    if(window.XMLHttpRequest) xhr = new XMLHttpRequest();
    else if(window.ActiveXObject) xhr = new ActiveXObject("Microsoft.XMLHTTP")
    if (!xhr) {cfg.err = 9; console.log(msg("Your browser does not support AJAX!")); return };
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            console.log('response: ' + xhr.status);
            if (xhr.status == 200) {
            console.log('response: ' + xhr.response);
            Load(xhr.response); }
            else {cfg.err = 6;    console.error('XMLHttpRequest: response ' + xhr.status)}
            xhr.abort();
            xhr = null;
        }
    };
    xhr.ontimeout = function() {cfg.err = 2; console.error('XMLHttpRequest: timeout')};
    xhr.onerror = function () {cfg.err = 6;    console.error('XMLHttpRequest error!')};   
    xhr.open('POST', cfg.urlh+'/mdb.cgi?m=2', true);
    xhr.timeout = 4000; // @https://github.com/stephanebachelier/superapi/issues/5
    if(cfg.urlh != '') xhr.setRequestHeader('Authorization', 'Basic ????????=');
    xhr.responseType = 'json';
       xhr.send(d);
}}
Примеры выдрал из работающих, удалил ненужное и т.д. Вам надо эти примеры изменить под свои нужды, в частности на "GET" если не надо что-то передавать как запрос через "POST" и другое...
За вас писать (играть) никто не будет, т.к. это и есть главное в игре с ESP :)
 

Legion12

New member
Решение проблемы, вдруг кому нужно:

C++:
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <WebSocketsServer.h>

String ssidAP = "Wireless"; //------ точка доступа
String passwordAP = "123456"; //----------------- пароль
IPAddress ip(192, 168, 11, 4);
ESP8266WebServer server(80); // старт сервера на 80 порту
WebSocketsServer socket = WebSocketsServer(91);// старт сокета на 91 порту

void setup(void) {

  WiFi.setPhyMode(WIFI_PHY_MODE_11N);
  WiFi.mode(WIFI_AP); //
  WiFi.softAPConfig(ip, ip, IPAddress(255, 255, 255, 0));
  WiFi.softAP(ssidAP,passwordAP);
  Serial.begin(115200); // старт уарта
  Serial.setTimeout(50);
  Serial.print("AP IP address: ");
  Serial.println(ip);
  server.begin(); //старт сервера
  socket.begin(); //старт сокета
  delay(200);
}

void sender(void){
r="";// data
if (r==""){}else{socket.broadcastTXT(r);}
 }

 
void loop(void) {
  server.handleClient();
  delay(1); 
   socket.loop();
   sender();
  }

И на стороне веб-страницы:
JavaScript:
 var socket = new WebSocket("ws://192.168.11.4:91/"); // подключение к веб-сокету ip:port

socket.onopen = op; // коннект
socket.onmessage = message; // принятое сообщение

 function message(e) {
    // прием и обработка данных
 }
 

Legion12

New member
Поправка, код будет такой:
JavaScript:
 var address='ws://192.168.11.4:91';
var socket = new WebSocket(address); // подключение к веб-сокету ip:port
Иначе будет вылезать неприятный и непонятный косяк... В этой теме подробнее :/
 

CodeNameHawk

Moderator
Команда форума
А если попробовать вместо
Код:
var socket = new WebSocket("ws://192.168.11.4:91/"); // подключение к веб-сокету ip:port
такой адресс
Код:
var socket = new WebSocket("ws://192.168.11.4:91"); // подключение к веб-сокету ip:port
 

Legion12

New member
А если попробовать вместо
Код:
var socket = new WebSocket("ws://192.168.11.4:91/"); // подключение к веб-сокету ip:port
такой адресс
Код:
var socket = new WebSocket("ws://192.168.11.4:91"); // подключение к веб-сокету ip:port
Более того, даже если эта строка закомментирована - косяк все равно остается. Удалить строку - косяка нет.
 

EvgeniyS

Member
А если попробовать:
JavaScript:
var socket = new WebSocket('ws://' + document.location.host + '/ws', ['arduino']);
И неважно какой там ip адрес
 

EvgeniyS

Member
Немного неправильно написал для вашего случая, поправлюсь:
JavaScript:
var socket = new WebSocket('ws://' + document.location.host + ':91/', ['arduino']);
 
Сверху Снизу