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

esp8266webserver+SPIFFS передача переменной в HTML

uVolt

New member
Всех с наступившим! В связи с новогодними мероприятиями не могу собраться в кучу. Прошу сведущих помочь с вопросом. Я весьма далёк от высокоуровневого программирования и поэтому ни как не могу понять как передать переменную в HTML файл. Код собрал как конструктор из примеров. Проверил, работает. Но при нажатии на кнопку переходит на ссылку в соответствии с кнопкой /on или /off и выводит соответствующий текст на страничке. А мне надо чтоб не было перехода а оставалась эта-же страничка но менялось значение переменной %STATE% на страничке.
В скетче использовал FTP и файловую систему SPIFFS.
Код:
#include <ESP8266WiFi.h> 
#include <ESP8266WebServer.h>
#include <FS.h> 
#include <ESP8266FtpServer.h>
#include <ESP8266HTTPUpdateServer.h>

const char* OTAUSER = "";
const char* OTAPASSWORD = "";
const char* OTAPATH = "/update";  
const byte relay = 2;
const char* user = "user";
const char* ssid = "Keenetic-3384"; 
const char* password = "12345678";

ESP8266HTTPUpdateServer httpUpdater;
ESP8266WebServer HTTP(80);

FtpServer ftpSrv; 
 
void setup() {
  pinMode(relay, OUTPUT);  
  Serial.begin(115200); 

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  Serial.print(" ssid: ");
  Serial.print(ssid);
  Serial.print(" password: ");
  Serial.print(password);
 
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
  SPIFFS.begin();
  httpUpdater.setup(&HTTP,  OTAPATH ,  OTAUSER ,   OTAPASSWORD);
  HTTP.begin();
  ftpSrv.begin(user,password);

  Serial.print("\nMy IP to connect via Web-Browser or FTP: ");  
  Serial.println(WiFi.localIP()); 
  Serial.println("\n");
 
  // Обработка HTTP-запросов
  HTTP.on("/on", []() {
    HTTP.send(200, "text/plain", on_());
  });
  HTTP.on("/off", []() {
    HTTP.send(200, "text/plain", off_());
  });
  HTTP.onNotFound([]() {
    if (!handleFileRead(HTTP.uri()))
      HTTP.send(404, "text/plain", "Not Found");
  });
}
 
void loop() {
  HTTP.handleClient(); 
  ftpSrv.handleFTP(); 
}
 

String on_() {
  String STATE;
    STATE = "on";
  digitalWrite(relay, 0); 
  Serial.println("\r\n");
  Serial.println(STATE);
  return "on";
}
 
String off_() {
  String STATE;
    STATE = "off";
  digitalWrite(relay, 1);
  Serial.println("\r\n");
  Serial.println(STATE);
  return "off"; 
}
 
bool handleFileRead(String path) { 
  if (path.endsWith("/")) path += "index.html"; 

  String contentType = getContentType(path);
  if (SPIFFS.exists(path)) {
    File file = SPIFFS.open(path, "r");
    size_t sent = HTTP.streamFile(file, contentType); 
    file.close();
    return true; 
  }
  return false; 
}
 
String getContentType(String filename) { 
  if (filename.endsWith(".html")) return "text/html";
  else if (filename.endsWith(".css")) return "text/css";
  else if (filename.endsWith(".js")) return "application/javascript";
  else if (filename.endsWith(".png")) return "image/png";
  else if (filename.endsWith(".jpg")) return "image/jpeg"; 
  else if (filename.endsWith(".gif")) return "image/gif";
  else if (filename.endsWith(".ico")) return "image/x-icon";  
  return "text/plain"; 
}
Код:
<!DOCTYPE html>
<html>
  <head>
    <title>ESP WEB SERVER</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" href="style.css">
    <link rel="icon" type="image/png" href="favicon.png">
    <link rel="stylesheet" href="/stile.css">
  </head>
  <body>
    <div class="topnav">
      <h1>ESP WEB SERVER</h1>
    </div>
    <div class="content">
      <div class="card-grid">
        <div class="card">
          <p class="card-title"><i class="fas fa-lightbulb"></i> GPIO 2</p>
          <p>
            <a href="on"><button class="button-on">ON</button></a>
            <a href="off"><button class="button-off">OFF</button></a>
          </p>
          <p class="state">State: %STATE%</p>
          <p><a href="/update">Update</a></p>
        </div>
      </div>
    </div>
  </body>
</html>
Код:
html {
  font-family: Arial, Helvetica, sans-serif;
  display: inline-block;
  text-align: center;
}

h1 {
  font-size: 1.8rem;
  color: white;
}

p {
  font-size: 1.4rem;
}

.topnav {
  overflow: hidden;
  background-color: #0A1128;
}

body { 
  margin: 0;
}

.content {
  padding: 5%;
}

.card-grid {
  max-width: 800px;
  margin: 0 auto;
  display: grid;
  grid-gap: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

.card {
  background-color: white;
  box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
}

.card-title {
  font-size: 1.2rem;
  font-weight: bold;
  color: #034078
}

input[type=submit] {
  border: none;
  color: #FEFCFB;
  background-color: #034078;
  padding: 15px 15px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 16px;
  width: 100px;
  margin-right: 10px;
  border-radius: 4px;
  transition-duration: 0.4s;
  }

input[type=submit]:hover {
  background-color: #1282A2;
}

input[type=text], input[type=number], select {
  width: 50%;
  padding: 12px 20px;
  margin: 18px;
  display: inline-block;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
}

label {
  font-size: 1.2rem;
}
.value{
  font-size: 1.2rem;
  color: #1282A2; 
}
.state {
  font-size: 1.2rem;
  color: #1282A2;
}
button {
  border: none;
  color: #FEFCFB;
  padding: 15px 32px;
  text-align: center;
  font-size: 16px;
  width: 100px;
  border-radius: 4px;
  transition-duration: 0.4s;
}
.button-on {
  background-color: #034078;
}
.button-on:hover {
  background-color: #1282A2;
}
.button-off {
  background-color: #858585;
}
.button-off:hover {
  background-color: #252524;
}
 

Vovka

Member
А мне надо чтоб не было перехода а оставалась эта-же страничка но менялось значение переменной %STATE% на страничке.
Тут поможет javascript + XMLHttpRequest. Можно конечно и WebSocket, но это немного сложнее. Начните с XMLHttpRequest
 

uVolt

New member
Тут поможет javascript + XMLHttpRequest. Можно конечно и WebSocket, но это немного сложнее. Начните с XMLHttpRequest
Спасибо большое. Действительно javascript + XMLHttpRequest получилось реализовать. Получилось довольно лаконично, и вполне логично. Вот рабочий пример, правда пока без SPIFFS. Позже доработаю.
Код:
#include <ESP8266WiFi.h>
#include <FS.h>                                                         // Библиотека для работы с файловой системой
#include <ESP8266FtpServer.h>                                           // Библиотека для работы с SPIFFS по FTP
#include <ESP8266HTTPUpdateServer.h>
#include <ESP8266WebServer.h>
#include "index.h"
#define LED D0

const char* OTAUSER = "";
const char* OTAPASSWORD = "";
const char* OTAPATH = "/update";                                       // Путь, который будем дописывать после ip адреса в браузере.
const byte relay = 2;                                                  // Пин подключения сигнального контакта реле
const char* user = "user";
const char* ssid = "Keenetic-3384";                                             // Название генерируемой точки доступа
const char* password = "12345678";

ESP8266HTTPUpdateServer httpUpdater;
ESP8266WebServer server(80);                                           // Определяем объект и порт сервера для работы с HTTP
FtpServer ftpSrv;                                                      // Определяем объект для работы с модулем по FTP (для отладки HTML)

void handleRoot()
{
 String s = webpage;
 server.send(200, "text/html", s);
}
void led_control()
{
 String state = "OFF";
 String act_state = server.arg("state");
 if(act_state == "1")
 {
  digitalWrite(relay,HIGH); //LED ON (включение светодиода)
  state = "ON";
 }
 else
 {
  digitalWrite(relay,LOW); //LED OFF (выключение светодиода)
  state = "OFF";
 }
 
 server.send(200, "text/plane", state);
}
void setup(void)
{
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");
  pinMode(relay,OUTPUT);
 
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print("Connecting...");
  }
  httpUpdater.setup(&server,  OTAPATH ,  OTAUSER ,   OTAPASSWORD);
  server.begin();                                                         // Инициализируем Web-сервер
  ftpSrv.begin(user,password);                                            // Поднимаем FTP-сервер для удобства отладки работы HTML (логин, пароль)

  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
 
  server.on("/", handleRoot);
  server.on("/led_set", led_control);
}
void loop(void)
{
  server.handleClient();
  ftpSrv.handleFTP();                                                 // Обработчик FTP-соединений
}
Код:
const char webpage[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<style type="text/css">
.button {
  background-color: #4CAF50; /* Green */
  border: none;
  color: white;
  padding: 15px 32px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 16px;
}
</style>
<body style="background-color: #f9e79f ">
<center>
<div>
<h1>AJAX BASED ESP8266 WEBSERVER</h1>
  <button class="button" onclick="send(1)">LED ON</button>
  <button class="button" onclick="send(0)">LED OFF</button><BR>
</div>
 <br>
<div><h2>
  LED State: <span id="state">NA</span>
</h2>
</div>
          <p><a href="/update">Update</a></p>
<script>
function send(led_sts)
{
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("state").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "led_set?state="+led_sts, true);
  xhttp.send();
}
setInterval(function()
{
  getData();
}, 2000);
</script>
</center>
</body>
</html>
)=====";
 
Сверху Снизу