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

Вывод uptime ESP8266 на веб-страницу

Melandr

Member
Добрый день!
Ковыряю код, в котором на html-страницу выводится время работы ESP после перезапуска в секундах вот таким образом
C:
void handleData() {
  String message = F("{\"");
  message += FPSTR(vccArg);
  message += F("\":");
  message += String(ESP.getVcc() / 1024.0);
  message += F(",\"");
  message += FPSTR(wifimodeArg);
  message += F("\":\"");
  switch (WiFi.getMode()) {
    case WIFI_OFF:
      message += F("OFF");
      break;
    case WIFI_STA:
      message += F("Station");
      break;
    case WIFI_AP:
      message += F("Access Point");
      break;
    case WIFI_AP_STA:
      message += F("Hybrid (AP+STA)");
      break;
    default:
      message += F("Unknown!");
  }
  message += F("\",\"");
  message += FPSTR(mqttconnectedArg);
  message += F("\":");
  if (pubsubClient.connected())
    message += F("true");
  else
    message += F("false");
  message += F(",\"");
  message += FPSTR(freeheapArg);
  message += F("\":");
  message += String(ESP.getFreeHeap());
  message += F(",\"");
  message += FPSTR(uptimeArg);
  message += F("\":");
  message += String(millis() / 1000);
  message += F(",\"");
  message += FPSTR(relayArg);
  message += F("\":");
  if (digitalRead(relayPin) == relayLevel)
    message += F("true");
  else
    message += F("false");
  message += F("}");

  httpServer.send(200, F("text/html"), message);
}
Время работы ESP обновляется на веб-странице через JS такого вида
JavaScript:
  <script type="text/javascript">
    function openUrl(url) {
      var request = new XMLHttpRequest();
      request.open('GET', url, true);
      request.send(null);
    }
    function refreshData() {
      var request = new XMLHttpRequest();
      request.open('GET', '/data', true);
      request.onreadystatechange = function() {
        if (request.readyState == 4) {
          var data = JSON.parse(request.responseText);
          document.getElementById('vcc').innerHTML = data.vcc;
          document.getElementById('wifimode').innerHTML = data.wifimode;
          document.getElementById('mqttconnected').innerHTML = (data.mqttconnected != true ? "not " : "") + "connected";
          document.getElementById('freeheap').innerHTML = data.freeheap;
          document.getElementById('uptime').innerHTML = data.uptime;
          document.getElementById('relay').checked = data.relay;
        }
      }
      request.send(null);
    }
    setInterval(refreshData, 500);
  </script>
Вывод осуществляется в таком виде
HTML:
  <form>
    <h3>ESP Relay</h3>
    <p>
    VCC: <span id="vcc">?</span> V<br/>
    WiFi mode: <span id="wifimode">?</span><br/>
    MQTT broker: <span id="mqttconnected">?</span><br/>
    Heap free size: <span id="freeheap">0</span> bytes<br/>
    Uptime: <span id="uptime">0</span> seconds</p>
    <input type="checkbox" class="checkbox" id="relay" onchange="openUrl('/switch?on=' + this.checked);" />
    <label for="relay">Relay</label>
    <p>
    <input type="button" value="WiFi Setup" onclick="location.href='/wifi';" />
    <input type="button" value="MQTT Setup" onclick="location.href='/mqtt';" />
    <input type="button" value="Relay Setup" onclick="location.href='/relay';" />
    <input type="button" value="Reboot!" onclick="if (confirm('Are you sure to reboot?')) location.href='/reboot';" />
  </form>
Пробую в скетче преобразовать секунды в вид 00:00:00 в виде строки такой функцией
Код:
String millis2time(){
  String Time="";
  unsigned long ss;
  byte mm,hh;
  ss=millis()/1000;
  hh=ss/3600;
  mm=(ss-hh*3600)/60;
  ss=(ss-hh*3600)-mm*60;
  if(hh<10)Time+="0";
  Time+=(String)hh+":";
  if(mm<10)Time+="0";
  Time+=(String)mm+":";
  if(ss<10)Time+="0";
  Time+=(String)ss;
  return Time;
}
Скетч компилируется, но данные на странице не отображаются, при этом, если ввести в браузере в адресной строке IP_адрес_ESP/data
то отображается JSON файл, с актуальным временем работы ESP. При обновлении страницы время работы меняется, но на саму веб-страницу переменные не выводятся.
Также пробовал подставить просто строку
String uptime = "456";
message += String(uptime);
Все равно не выводится это значение.
При этом, если выводит так
int uptime = 456;
message += String(uptime);
тогда выводится значение на веб-страницу.
Если пробовать вывести строку
message += millis2time();
то в JSON файле информация обновляется, но на страницу также не выводится
Буду рад, если подскажете, в какую сторону копать. Заранее спасибо.
 

Melandr

Member
'Выдает ошибку unexpected number in JSON at position at JSON.parse:
которая означает, что JSON объект не может начинаться с 0. Как это можно обойти?
 

enjoynering

Well-known member
Очевидно же - сделать проверку на null и undefined

If (time != null || time != unidentified)
{
//Your code here
}
 

Melandr

Member
Для меня не очевидно, я только учусь. Не могли бы поподробнее объяснить. Нужно проверку делать в js? Для меня js вообще пока темный лес. Насколько я понял, при использовании метода JSON.parse в строке, которой передается время работы имеются два символа, которые парсер не может разобрать, так как они конфликтуют с синтаксисом. Первое - ноль в начале, второе - разделитель "двоеточее" в строке.
Тут https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/JSON написано , что ведущие нули запрещены.
вот эта строка document.getElementById('uptime').innerHTML = data.uptime; должна получить время наработки, но не идет.
ЗЫ: при этом json открываю {"vcc":2.93,"wifimode":"Station","mqttconnected":false,"freeheap":40776,"uptime": 02:03:14,"relay":false}
 

Melandr

Member
Попробовал на сайте https://jsonlint.com/ проверить получаемую строку json
{"vcc":2.93,"wifimode":"Station","mqttconnected":false,"freeheap":41000,"uptime":00:02:25,"relay":false}
после проверки получаем
{
"vcc": 2.93,
"wifimode": "Station",
"mqttconnected": false,
"freeheap": 41000,
"uptime": 00: 02: 25,
"relay": false
}
и ругается на 6 строку - "uptime": 00: 02: 25,
Error: Parse error on line 6:
...: 41000, "uptime": 00: 02: 25, "relay"
----------------------^
Expecting 'STRING', 'NUMBER', 'NULL', 'TRUE', 'FALSE', '{', '[', got 'undefined'
Можно ли как-то обойти это ограничение?
 

Melandr

Member
Судя по строке json, метод JSON.parse(request.responseText); неправильно преобразует "uptime". Я хочу отображать строку, а он переводит ее в число. Можно ли как-то принудительно указать, что это строка?
 

l15ar

Member
ни фига се!
в скринах:
"uptime":00:06:37,
что за бардак!!!?
можно так: "uptime":"00:06:37",
или так: "uptime":[00,06,37],
но не так "uptime":00:06:37,
_________________^__^______нельзя использовать этот символ, кроме как разделитель полей.
имя_поля : значение_поля, ...
лучше преобразовать время в секунды.
 

Melandr

Member
Так я об этом же и пишу. ESP формирует uptime следующим кодом:
Код:
String millis2time(){
  String Time="";
  unsigned long ss;
  byte mm,hh;
  ss=millis()/1000;
  hh=ss/3600;
  mm=(ss-hh*3600)/60;
  ss=(ss-hh*3600)-mm*60;
  if(hh<10)Time+="0";
  Time+=(String)hh+":";
  if(mm<10)Time+="0";
  Time+=(String)mm+":";
  if(ss<10)Time+="0";
  Time+=(String)ss;
  return Time;
}
То есть , я передаю uptime в виде строки "00:00:00".
Почему на скриншотах уже отображается uptime как 00:00:00 я не знаю
javascript, возможно, при использовании метода parse преобразует полученное значение "uptime" в number. И, соответственно, выдает ошибку, так как используется ведущий 0 и разделитель ":"
время работы передавалось в секундах в исходном коде, но я хочу уже на веб-странице отобразить его в формате ХХ дней 00:00:00
В JS я еще плохо разбираюсь, потому как сделать правильно не могу понять. пробовал использовать второй необязательный параметр метода parse в виде, указанном ниже,, но тоже не идет
JavaScript:
  <script type="text/javascript">
    function openUrl(url) {
      var request = new XMLHttpRequest();
      request.open('GET', url, true);
      request.send(null);
    }
    function refreshData() {
      var request = new XMLHttpRequest();
      request.open('GET', '/data', true);
      request.onreadystatechange = function() {
        if (request.readyState == 4) {
          var data = JSON.parse(request.responseText, function(key, value) {
            if (key == 'uptime') return new Date(value);
            return value;
          });
          document.getElementById('vcc').innerHTML = data.vcc;
          document.getElementById('wifimode').innerHTML = data.wifimode;
          document.getElementById('mqttconnected').innerHTML = (data.mqttconnected != true ? "not " : "") + "connected";
          document.getElementById('freeheap').innerHTML = data.freeheap;
          document.getElementById('uptime').innerHTML = data.uptime;
          document.getElementById('relay').checked = data.relay;
        }
      }
      request.send(null);
    }
    setInterval(refreshData, 500);
  </script>
 

l15ar

Member
не занимайтесь фигнёй, преобразуйте в кол-во секунд, ещё лучше - 30сек интервалов(минутных).
выводите целое число, там, в javascript пересчитать в минуты, часы, дни, ерунда, школьник сделает..
ИМХО
 

Melandr

Member
Я думал, что проще сделать преобразование на ESP,и выводить в JS уже строку.
 

l15ar

Member
Я думал, что проще сделать преобразование на ESP,и выводить в JS уже строку.
Поймите одну вещь, не нужно делать бесполезную работу на устройстве, которое и так ограниченно в ресурсах!
Поэтому, если есть параметр(ы) который(е) можно выдать наружу без обработки внутри, выдавайте наружу как есть, с минимальной обработкой!
Не нужно выдавать наружу никаких строк, кроме тех, которые нельзя предугадать, во остальных случаях - выдавайте целочисленный код(вместо строк).
Если можно не использовать JSON, нужно не использовать, было бы желание, не используйте, это трата памяти и ресурсов!
Если можно не использовать строковых преобразований, не используйте их, это трата ресурсов..
По факту получается, пытаются собрать веб-страницу прямо в контроллере(ESP), это извините - бред..
Всё что нужно для динамики веб-страницы, делается средствами AJAX, веб-сокеты, UDP, отрисовывается обычным Javascript, на котором можно сделать всё!
Короткие серии обмена между ESP и веб-клиентом использующий javascript. Не нужно ничего более этого.
Более того, на том nodejs можно сделать локальный сервер статистики и управления.
:\
 

l15ar

Member
Касаемо ресурсов, которые нужно отдать веб-клиенту(браузеру), необходимо делать редирект на соответствующий ресурс(сервер,сервис,..), на котором они будут лежат(вы туда их запишите).
Не нужно их отдавать непосредственно с контроллера(ESP). По факту, большинство так и делают, отдают с контроллера.. :\
 

l15ar

Member
И ещё, если можно выполнить какую то работу на внешнем устройстве(расчёт), нужно выполнять эту работу на внешнем устройстве, результат вернуть контроллеру(не нужно мучить контроллер).
 

enjoynering

Well-known member
ИМХО, автор взялся за не посильную ю, для него, задачу. Вам все показали, но все рано топчетесь в трёх соснах. Я бы вам посоветовал прочесть какую-нибудь книгу по JS. И вот увидите ваш вопрос отпадёт сам собой.
 

Melandr

Member
Всем большое спасибо за очень "конструктивную" помощь. Ответ лежал на поверхности, в первом посте темы. Проблема была в формировании строки с правильным использованием обратного слеша и кавычек.
2020-09-12_095751.jpg
l15ar
Спасибо за ссылки, интересно будет посмотреть, так как весь фронтэнд для ESP делается через JS и не хватает знаний.
 
Сверху Снизу