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

Перевод на SPIFFS

humaxoid

New member
Если html в теле прошивки, то все работает нормально. Вот кусок кода.
Код:
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
Бла бла бла...
</head>
<body>
Тут содержимое странички
</body>
</html>
)rawliteral";

void setup() {
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
   request->send_P(200, "text/html", index_html, processor);
  });
}
Переводим в SPIFFS

Код:
void setup() {
  if (!SPIFFS.begin()) {
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }

 // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(SPIFFS, "text/html", "/index.html");
  });
Создаем отдельный файл index.html c аналогичным содержимым

HTML:
<!DOCTYPE HTML>
<html>
<head>
Бла бла бла...
</head>
<body>
Тут содержимое странички
</body>
</html>
И ложим его в папку data. Видим все работает как и положенно с одним большим НО! При первоначальной загрузке страници или при ее обновлении вместо статуса кнопок ON или OFF, видим переменную %STATE%. Но если нажать кнопку то все ОК.
 

humaxoid

New member
Так это я показал различия между двумя вариантами. Без SPIFFS и с SPIFFS. В таком случае привожу полный код.

Код:
// Import required libraries
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>

// Задаем сетевые настройки
const char* ssid = "*******";
const char* password = "********";
IPAddress local_IP(192, 168, 1, 68);  // Задаем статический IP-адрес:
IPAddress gateway(192, 168, 1, 102);  // Задаем IP-адрес сетевого шлюза:
IPAddress subnet(255, 255, 255, 0);    // Задаем маску сети:
IPAddress primaryDNS(8, 8, 8, 8);      // Основной ДНС (опционально)
IPAddress secondaryDNS(8, 8, 4, 4);    // Резервный ДНС (опционально)

bool ledState1 = 0;
bool ledState2 = 0;
bool ledState3 = 0;
bool ledState4 = 0;
bool ledState5 = 0;

AsyncWebServer server(80);
AsyncWebSocket ws("/ws");

//const char index_html[] PROGMEM = R"rawliteral(
//)rawliteral";

// Уведомляем клиентов о текущем состоянии светодиода
void notifyClients1() {ws.textAll(String(ledState1));}
void notifyClients2() {ws.textAll(String(ledState2+2));}
void notifyClients3() {ws.textAll(String(ledState3+4));}
void notifyClients4() {ws.textAll(String(ledState4+6));}
void notifyClients5() {ws.textAll(String(ledState5+8));}

/* функция обратного вызова, которая запускается всякий раз, когда мы получаем новые
  данные от клиентов по протоколу WebSocket. Если мы получаем сообщение “toggle”, мы
  переключаем значение переменной ledState. Кроме того, мы уведомляем всех клиентов,
  вызывая функцию notifyClients (). Таким образом, все клиенты получают уведомление об
  изменении и соответствующим образом обновляют интерфейс.*/
 
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();}
  }
}

// Настройка прослушивателя событий для обработки различных асинхронных шагов протокола WebSocket
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:                     // в ответ на запрос ping
    case WS_EVT_ERROR:                    // при получении ошибки от клиента
      break;
  }
}

// Инициализация WebSocket
void initWebSocket() {
  ws.onEvent(onEvent);
  server.addHandler(&ws);
}

String processor(const String& var) {
  Serial.println(var);
  if (var == "STATE1") {if (ledState1) {return "ON";}else {return "OFF";}}
  if (var == "STATE2") {if (ledState2) {return "ON";}else {return "OFF";}}
  if (var == "STATE3") {if (ledState3) {return "ON";}else {return "OFF";}}
  if (var == "STATE4") {if (ledState4) {return "ON";}else {return "OFF";}}
  if (var == "STATE5") {if (ledState5) {return "ON";}else {return "OFF";}}
}

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

  pinMode(32, OUTPUT); digitalWrite(32, LOW);
  pinMode(33, OUTPUT); digitalWrite(33, LOW);
  pinMode(25, OUTPUT); digitalWrite(25, LOW);
  pinMode(26, OUTPUT); digitalWrite(26, LOW);
  pinMode(27, OUTPUT); digitalWrite(27, LOW);

  // Настраиваем статический IP-адрес:
  if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
    Serial.println("Режим клиента не удалось настроить");
  }

  if (!SPIFFS.begin()) {
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }

  // 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(SPIFFS, "text/html", "/index.html");
  });

  server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(SPIFFS, "/style.css", "text/css");
  });

  server.on("/script.js", HTTP_GET, [](AsyncWebServerRequest * request) {
   request->send(SPIFFS, "/script.js", "text/javascript");
  });

  // Start server
  server.begin();
}

void loop() {
  ws.cleanupClients();
  digitalWrite(32, ledState1);
  digitalWrite(33, ledState2);
  digitalWrite(25, ledState3);
  digitalWrite(26, ledState4);
  digitalWrite(27, ledState5);
}
index.html
HTML:
<!DOCTYPE HTML>
<html>
<head>
  <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <link rel="stylesheet" type="text/css" href="style.css">
  <script src="script.js"></script>
  <title>ESP Web Server</title>
</head>
<body>
  <div class="topnav">
    <h1>ESP WebSocket Server</h1>
  </div>
  <div class="content">
    <div class="card">
      <h2>Out - GPIO 32</h2>
      <p class="state">Status: <span id="state1">%STATE1%</span></p>
      <p><button id="button1" class="button">Button 1</button></p> 
      <h2>Out - GPIO 33</h2>
      <p class="state">Status: <span id="state2">%STATE2%</span></p>
      <p><button id="button2" class="button">Button 2</button></p>
      <h2>Out - GPIO 25</h2>
      <p class="state">Status: <span id="state3">%STATE3%</span></p>
      <p><button id="button3" class="button">Button 3</button></p>
      <h2>Out - GPIO 26</h2>
      <p class="state">Status: <span id="state4">%STATE4%</span></p>
      <p><button id="button4" class="button">Button 4</button></p>
      <h2>Out - GPIO 27</h2>
      <p class="state">Status: <span id="state5">%STATE5%</span></p>
      <p><button id="button5" class="button">Button 5</button></p>
    </div>
  </div>
</body>
</html>
java 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;
  }
 
  function onOpen(event) {
    console.log('Connection opened');
  }
  function onClose(event) {
    console.log('Connection closed');
    setTimeout(initWebSocket, 2000);
  }

  function onMessage(event) {
    switch(event.data) {
      case '0': document.getElementById("state1").innerHTML = "OFF"; break
      case '1': document.getElementById("state1").innerHTML = "ON"; break
      case '2': document.getElementById("state2").innerHTML = "OFF"; break
      case '3': document.getElementById("state2").innerHTML = "ON"; break
      case '4': document.getElementById("state3").innerHTML = "OFF"; break
      case '5': document.getElementById("state3").innerHTML = "ON"; break
      case '6': document.getElementById("state4").innerHTML = "OFF"; break
      case '7': document.getElementById("state4").innerHTML = "ON"; break
      case '8': document.getElementById("state5").innerHTML = "OFF"; break
      case '9': document.getElementById("state5").innerHTML = "ON"; break
    }
    }
 
  function onLoad(event) {initWebSocket();initButton();}

  function initButton() {
    document.getElementById('button1').addEventListener('click', toggle1);
    document.getElementById('button2').addEventListener('click', toggle2);
    document.getElementById('button3').addEventListener('click', toggle3);
    document.getElementById('button4').addEventListener('click', toggle4);
    document.getElementById('button5').addEventListener('click', toggle5);
  }
 
  function toggle1(){websocket.send('toggle1');}
  function toggle2(){websocket.send('toggle2');}
  function toggle3(){websocket.send('toggle3');}
  function toggle4(){websocket.send('toggle4');}
  function toggle5(){websocket.send('toggle5');}
 

humaxoid

New member
Для наглядности привожу скрины.
После загрузке страницы или при ее обновлении, должно быть так! Т.е статус должен сразу читатся корректно.

1234.jpg

На самом деле дела обстоят так:

123.jpg

Если нажать на одну из кнопок, то статус прочитался (до первого обновления страницы).
 

CodeNameHawk

Moderator
Команда форума
На самом деле дела обстоят так:
Ну так вы так и посылаете
<p class="state">Status: <span id="state1">%STATE1%</span></p>

Вам надо, при загрузке страницы или после ее загрузки, например через websocket запросить значения кнопок и вывести их на страницу.
Есть другой вариант, читаете с диска файл index.html в временную переменную, потом при помощи snprintf() добавляете значения STATE и отдаете это в вебсервер.
Если старый вариант работает, то зачем его менять, в нем вы наверное сразу посылаете значения всех STATE.
 
Последнее редактирование:

Ildarmustafin86

Active member
Все, я понял вашу проблему. Не пробовали посылать первичное состояние кнопок при подключении к websocket (WS_EVT_CONNECT)?
 

Ildarmustafin86

Active member
Можно эти 5 состояний кнопок упаковать в байт и передать, а потом распаковать.
 

humaxoid

New member
Спасибо парни за наводку. Нашел косяк! Надо было данные посылать через processor. Вот так нужно было:
Код:
request->send(SPIFFS, "/index.html", "text/html",false, processor);
 
Сверху Снизу