• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе 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']);
 
Сверху Снизу