Web интерфейс управления сервоприводами ESP8266 есть скеч. цена в мере розумного

zDimaBY
Offline
Зарегистрирован: 10.06.2018

Подскажите что я делаю не так ? Позиция лево-право: undefined  Позиция верх-вниз: работает нормально

За исправления кода скину $

Вот код можно компилировать.



#include <Servo.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
 
const char *ssid = "Aleksander";
const char *password = "11406080";
 
Servo myservo;  // создаем экземпляр класса «Servo»,
Servo myservo1;  // чтобы с его помощью управлять сервоприводом;
                // большинство плат позволяют
                // создать 12 объектов класса «Servo»
 
// GPIO-контакт, к которому подключен сервопривод:
static const int servoPin = 13;
static const int servo1Pin = 14;
 
// создаем веб-сервер на порте «80»:
WiFiServer server(80);
 
// переменная для хранения HTTP-запроса:
String header;
String header1;
// несколько переменных для расшифровки значения в HTTP-запросе GET:
String valueString = String(5);
String valueString1 = String(5);
int pos1 = 0;
int pos2 = 0;
int pos11 = 0;
int pos22 = 0;
 
void setup() {
  Serial.begin(115200);
 
  myservo.attach(servoPin);  // привязываем сервопривод,
  myservo.attach(servo1Pin); // подключенный к контакту «servoPin»,
                             // к объекту «myservo»
 
  // подключаемся к WiFi при помощи заданных выше SSID и пароля: 
  Serial.print("Connecting to ");  //  "Подключаемся к "
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // печатаем локальный IP-адрес и запускаем веб-сервер:
  Serial.println("");
  Serial.println("WiFi connected.");  //  "WiFi подключен."
  Serial.println("IP address: ");     //  "IP-адрес: "
  Serial.println(WiFi.localIP());
  server.begin();
}
 
void loop(){
  // начинаем прослушивать входящих клиентов:
  WiFiClient client = server.available();
 
  if (client) {                     // если подключился новый клиент,     
    Serial.println("New Client.");  // печатаем сообщение
                                    // «Новый клиент.»
                                    // в мониторе порта;
    String currentLine = "";        // создаем строку для хранения
                                    // входящих данных от клиента;
    while (client.connected()) {    // цикл while() будет работать
                                    // все то время, пока клиент
                                    // будет подключен к серверу;
      if (client.available()) {     // если у клиента есть данные,
                                    // которые можно прочесть, 
        char c = client.read();     // считываем байт, а затем    
        Serial.write(c);            // печатаем его в мониторе порта
        header += c;
        if (c == '\n') {            // если этим байтом является
                                    // символ новой строки
          // если получили два символа новой строки подряд,
          // то это значит, что текущая строчка пуста;
          // это конец HTTP-запроса клиента,
          // а значит – пора отправлять ответ:
          if (currentLine.length() == 0) {
            // HTTP-заголовки всегда начинаются
            // с кода ответа (например, «HTTP/1.1 200 OK»)
            // и информации о типе контента
            // (чтобы клиент понимал, что получает);
            // в конце пишем пустую строчку:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
                       //  "Соединение: отключено"
            client.println();
 
            // показываем веб-страницу:
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            client.println("<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial; margin-left:auto; margin-right:auto;}");
            client.println(".slider { width: 300px; }</style>");
            client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script>");
                     
            // веб-страница:
            client.println("</head><body><h1>ESP8266 Управление сервомотором антенны</h1>");
                                        //  "Управление сервомотором
                                        //   с помощью платы ESP32"
            client.println("<p>Позиция верх-вниз: <span id=\"servoPos\"></span></p>");     
            client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider\" onchange=\"servo(this.value)\" value=\""+valueString+"\"/>");
            client.println("<p>Позиция лево-право: <span id=\"servoPos1\"></span></p>");
            client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider1\" id=\"servoSlider1\" onchange=\"servo1(this.value1)\" value1=\""+valueString1+"\"/>");
            
            client.println("<script>var slider = document.getElementById(\"servoSlider\");");
            client.println("var slider1 = document.getElementById(\"servoSlider1\");");
            client.println("var servoP = document.getElementById(\"servoPos\"); servoP.innerHTML = slider.value;");
            client.println("var servoP1 = document.getElementById(\"servoPos1\"); servoP1.innerHTML = slider1.value1;");
            client.println("slider.oninput = function() { slider.value = this.value; servoP.innerHTML = this.value; }");
            client.println("slider1.oninput = function() { slider1.value1 = this.value1; servoP1.innerHTML = this.value1; }");
            client.println("$.ajaxSetup({timeout:1000}); function servo(pos) { ");
            client.println("$.get(\"/?value=\" + pos + \"&\"); {Connection: close};}");
            client.println("$.ajaxSetup({timeout:1000}); function servo1(pos1) { ");
            client.println("$.get(\"/?value=\" + pos1 + \"&\"); {Connection: close};}</script>");
           
            client.println("</body></html>");     
            
            //GET /?value=180& HTTP/1.1
            if(header.indexOf("GET /?value=")>=0) {
              pos1 = header.indexOf('=');
              pos2 = header.indexOf('&');
              pos11 = header1.indexOf('=');
              pos22 = header1.indexOf('&');
              valueString = header.substring(pos1+1, pos2);
              valueString1 = header1.substring(pos11+1, pos22);
              // вращаем ось сервомотора:
              myservo.write(valueString.toInt());
              Serial.println(valueString);
              myservo1.write(valueString1.toInt());
              Serial.println(valueString1); 
            }         
            // конец HTTP-ответа задается 
            // с помощью дополнительной пустой строки:
            client.println();
            // выходим из цикла while(): 
            break;
          } else { // если получили символ новой строки,
                   // очищаем текущую строку «currentLine»:
            currentLine = "";
          }
        } else if (c != '\r') {  // если получили любые данные,
                                 // кроме символа возврата каретки,
          currentLine += c;      // добавляем эти данные 
                                 // в конец строки «currentLine»
        }
      }
    }
    // очищаем переменную «header[]»:
    header = "";
    header1 = "";
    // отключаем соединение:
    client.stop();
    Serial.println("Client disconnected.");
               //  "Клиент отключился."
    Serial.println("");
  }
}

 

fridgetester
fridgetester аватар
Offline
Зарегистрирован: 09.02.2019

Если верх-вниз действительно работает, то поправлю скетч для лево-право за 500р, fridgetester@mail.ru

ЗЫ: оплата, разумеецца, вперёд.

b707
Offline
Зарегистрирован: 26.05.2017

zDimaBY - вставьте код правильно, с номерами строк, чтоб я мог указать вам ошибку

zDimaBY
Offline
Зарегистрирован: 10.06.2018
#include <Servo.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

const char *ssid = "Aleksander";
const char *password = "11406080";

Servo myservo;  // создаем экземпляр класса «Servo»,
Servo myservo1;  // чтобы с его помощью управлять сервоприводом;
                // большинство плат позволяют
                // создать 12 объектов класса «Servo»

// GPIO-контакт, к которому подключен сервопривод:
static const int servoPin = 13;
static const int servo1Pin = 14;

// создаем веб-сервер на порте «80»:
WiFiServer server(80);

// переменная для хранения HTTP-запроса:
String header;
String header1;
// несколько переменных для расшифровки значения в HTTP-запросе GET:
String valueString = String(5);
String valueString1 = String(5);
int pos1 = 0;
int pos2 = 0;
int pos11 = 0;
int pos22 = 0;

void setup() {
  Serial.begin(115200);

  myservo.attach(servoPin);  // привязываем сервопривод,
  myservo.attach(servo1Pin); // подключенный к контакту «servoPin»,
                             // к объекту «myservo»

  // подключаемся к WiFi при помощи заданных выше SSID и пароля: 
  Serial.print("Connecting to ");  //  "Подключаемся к "
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // печатаем локальный IP-адрес и запускаем веб-сервер:
  Serial.println("");
  Serial.println("WiFi connected.");  //  "WiFi подключен."
  Serial.println("IP address: ");     //  "IP-адрес: "
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  // начинаем прослушивать входящих клиентов:
  WiFiClient client = server.available();

  if (client) {                     // если подключился новый клиент,     
    Serial.println("New Client.");  // печатаем сообщение
                                    // «Новый клиент.»
                                    // в мониторе порта;
    String currentLine = "";        // создаем строку для хранения
                                    // входящих данных от клиента;
    while (client.connected()) {    // цикл while() будет работать
                                    // все то время, пока клиент
                                    // будет подключен к серверу;
      if (client.available()) {     // если у клиента есть данные,
                                    // которые можно прочесть, 
        char c = client.read();     // считываем байт, а затем    
        Serial.write(c);            // печатаем его в мониторе порта
        header += c;
        if (c == '\n') {            // если этим байтом является
                                    // символ новой строки
          // если получили два символа новой строки подряд,
          // то это значит, что текущая строчка пуста;
          // это конец HTTP-запроса клиента,
          // а значит – пора отправлять ответ:
          if (currentLine.length() == 0) {
            // HTTP-заголовки всегда начинаются
            // с кода ответа (например, «HTTP/1.1 200 OK»)
            // и информации о типе контента
            // (чтобы клиент понимал, что получает);
            // в конце пишем пустую строчку:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
                       //  "Соединение: отключено"
            client.println();

            // показываем веб-страницу:
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            client.println("<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial; margin-left:auto; margin-right:auto;}");
            client.println(".slider { width: 300px; }</style>");
            client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script>");
                     
            // веб-страница:
            client.println("</head><body><h1>ESP8266 Управление сервомотором антенны</h1>");
                                        //  "Управление сервомотором
                                        //   с помощью платы ESP32"
            client.println("<p>Позиция верх-вниз: <span id=\"servoPos\"></span></p>");     
            client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider\" onchange=\"servo(this.value)\" value=\""+valueString+"\"/>");
            client.println("<p>Позиция лево-право: <span id=\"servoPos1\"></span></p>");
            client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider1\" id=\"servoSlider1\" onchange=\"servo1(this.value1)\" value1=\""+valueString1+"\"/>");
            
            client.println("<script>var slider = document.getElementById(\"servoSlider\");");
            client.println("var slider1 = document.getElementById(\"servoSlider1\");");
            client.println("var servoP = document.getElementById(\"servoPos\"); servoP.innerHTML = slider.value;");
            client.println("var servoP1 = document.getElementById(\"servoPos1\"); servoP1.innerHTML = slider1.value1;");
            client.println("slider.oninput = function() { slider.value = this.value; servoP.innerHTML = this.value; }");
            client.println("slider1.oninput = function() { slider1.value1 = this.value1; servoP1.innerHTML = this.value1; }");
            client.println("$.ajaxSetup({timeout:1000}); function servo(pos) { ");
            client.println("$.get(\"/?value=\" + pos + \"&\"); {Connection: close};}");
            client.println("$.ajaxSetup({timeout:1000}); function servo1(pos1) { ");
            client.println("$.get(\"/?value=\" + pos1 + \"&\"); {Connection: close};}</script>");
           
            client.println("</body></html>");     
            
            //GET /?value=180& HTTP/1.1
            if(header.indexOf("GET /?value=")>=0) {
              pos1 = header.indexOf('=');
              pos2 = header.indexOf('&');
              pos11 = header1.indexOf('=');
              pos22 = header1.indexOf('&');
              valueString = header.substring(pos1+1, pos2);
              valueString1 = header1.substring(pos11+1, pos22);
              // вращаем ось сервомотора:
              myservo.write(valueString.toInt());
              Serial.println(valueString);
              myservo1.write(valueString1.toInt());
              Serial.println(valueString1); 
            }         
            // конец HTTP-ответа задается 
            // с помощью дополнительной пустой строки:
            client.println();
            // выходим из цикла while(): 
            break;
          } else { // если получили символ новой строки,
                   // очищаем текущую строку «currentLine»:
            currentLine = "";
          }
        } else if (c != '\r') {  // если получили любые данные,
                                 // кроме символа возврата каретки,
          currentLine += c;      // добавляем эти данные 
                                 // в конец строки «currentLine»
        }
      }
    }
    // очищаем переменную «header[]»:
    header = "";
    header1 = "";
    // отключаем соединение:
    client.stop();
    Serial.println("Client disconnected.");
               //  "Клиент отключился."
    Serial.println("");
  }
}

 

zDimaBY
Offline
Зарегистрирован: 10.06.2018

Через https://kwork.ru работаете ?

b707
Offline
Зарегистрирован: 26.05.2017

код списали что ли, ничего в нем не смыслите?

строка 36 и 37 - одна должна быть myservo.attach(), а вторая myservo1.attach() - а у вас обе строки для одного и того же серво

zDimaBY
Offline
Зарегистрирован: 10.06.2018

строка 36 и 37 это понимаю.. но не понимаю как брать запрос с 2-х ползунков один показывает значения undefined

Списал, смыслю но не все например с 124 до 130 не очень понимаю 

b707
Offline
Зарегистрирован: 26.05.2017

zDimaBY пишет:

строка 36 и 37 это понимаю..

так исправляйте, так работать заведомо не будет

zDimaBY
Offline
Зарегистрирован: 10.06.2018

Исправил. https://ibb.co/jvW830v но думаю на это ничего не повлияло имею виду "Позиция лево-право: undefined"

b707
Offline
Зарегистрирован: 26.05.2017

а, увидел, у вас еще код сайта неверный, строчки 116-119 видимо изначально брали из примера, где был один запрос, и тупо скопировали дважды? - так работать не будет.

И еще в строке 124 и дальше всунули какой-то header1, не понимая, что это значит.

В итоге у вас в коде передается только один параметр слайдера, не важно какой...

В общем, переписать это несложно, но уже выходит за рамки "помощи в форуме". Обращайтесь к фриджетестеру выше

zDimaBY
Offline
Зарегистрирован: 10.06.2018

fridgetester - помог, спасибо большое. Все решено.

junior_developer
Offline
Зарегистрирован: 27.11.2017

А можно ли вместо запроса

GET /?value=45& HTTP/1.1  // например, угол поворота сервопривода 45.
использовать
GET /?value1=45&value2=90& HTTP/1.1 // угол поворота первого сервопривода 45, второго 90

а так написать можно?

client.println("$.ajaxSetup({timeout:1000}); function servo(pos_1, pos_2) { "); // принять два значения (позиция первого сервопривода и второго)
client.println("$.get(\"/?value1=\" + pos_1 + \"&value2=\" + pos_2 + \"&\");{Connection: close};}");

Или лучше всё-таки сделать отдельные функции для каждого сервопривода? И проверять на соответствие
 

if(header.indexOf("GET /?value1=")>=0) // первый сервопривод
if(header.indexOf("GET /?value2=")>=0) // второй

Подскажите пожалуйста, кто разбирается!

zDimaBY
Offline
Зарегистрирован: 10.06.2018

В 1 функцию.

junior_developer
Offline
Зарегистрирован: 27.11.2017
Вот как это можно сделать на JavaScript с помощью всего одного массива!
<!doctype html>
<html dir="ltr" lang="ru">
  <head>
    <meta charset="utf-8">
    <title>Новая вкладка</title>
    </head>
  <body>
<script>
let header = "GET /?value1=45&value2=90&value3=105& HTTP/1.1";

let positions =[]; // массив для позиций символов в строке
 if(header.indexOf("GET /?value")>=0) { // если начало заголовка появилось...
let	currentPos = header.indexOf('='); 
while (currentPos != -1) {
    positions.push(currentPos);
	currentPos = header.indexOf('=', currentPos+1);
 }	 

currentPos = header.indexOf('&'); 
while (currentPos != -1) {
    positions.push(currentPos);
	currentPos = header.indexOf('&', currentPos+1);
 }	 
}
	    let	valueString1 = header.substring(positions[0]+1, positions[3]);
		let	valueString2 = header.substring(positions[1]+1, positions[4]);
		let	valueString3 = header.substring(positions[2]+1, positions[5]);
		console.log(valueString1);
		console.log(valueString2);
		console.log(valueString3);
		console.log(positions);
</script>
  </body>
</html>

в него "запихиваются" значения всех найденных позиций символа "=", а затем аналогичным образом, символа "&". Используется метод "push"

positions.push(currentPos); // запихнуть текущую позицию в массив
currentPos = header.indexOf('=', currentPos+1);
Ну вот, что интересно, почему-то если написать currentPos++ вместо currentPos+1 страница в браузере "зависает" и отладчик "отваливается"? 
Разве ++ не то же самое, что +1?
У кого есть свободная минута, можете посмотреть, если нетрудно? Никакого "железа" ведь не нужно. Просто вставить код и нажать F12 в браузере!
Ещё вариант по моему лучший, чем предыдущий:
<!doctype html>
<html dir="ltr" lang="ru">
  <head>
    <meta charset="utf-8">
    <title>Новая вкладка</title>
  </head>
  <body>
<script>
let header = "GET /?value1=45&value2=90&value3=105& HTTP/1.1";

let positions =[]; // массив для позиций символов в строке
 if(header.indexOf("GET /?value")>=0) { // если начало заголовка появилось...
let	currentLeftPos = header.indexOf('='); 
let	currentRightPos = header.indexOf('&'); 
while (currentLeftPos != -1 || currentRightPos != -1) { 
    positions.push(currentLeftPos); // запихнуть левую позицию
	positions.push(currentRightPos); // запихнуть правую позицию
    currentLeftPos = header.indexOf('=', currentLeftPos+1); 
    currentRightPos = header.indexOf('&', currentRightPos+1);
 }	 
}	 
        let	valueString1 = header.substring(positions[0]+1, positions[1]);
		let	valueString2 = header.substring(positions[2]+1, positions[3]);
		let	valueString3 = header.substring(positions[4]+1, positions[5]);
		console.log(valueString1);
		console.log(valueString2);
		console.log(valueString3);
		console.log(positions);
</script>
  </body>
</html>

 

 

smart_pic
Offline
Зарегистрирован: 17.04.2016

junior_developer пишет:

Ну вот, что интересно, почему-то если написать currentPos++ вместо currentPos+1 страница в браузере "зависает" и отладчик "отваливается"? 
Разве ++ не то же самое, что +1?

Не тоже самое. Операция ++ выполняется после того , как будет выполнено основное выражение, а +1 сначала будет прибавлено 1, а потом уже выполнено основное выражение.

Такова особенность выражения ++

 

 

 

 

 

 

 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Не забываем про наличие операции ++currentPos :)

junior_developer
Offline
Зарегистрирован: 27.11.2017

Да с плюсами перед переменной работает! Однако странно, что в отладчике, НЕ видно как currentPos увеличивается на 1.
Как не пиши, хоть ++currentPos, хоть currentPos+1 все равно.
Что это? Глюк отладчика или так и должно быть?
А вот если написать  так, видно! 

positions.push(currentPos);
currentPos++;
currentPos = header.indexOf('=', currentPos);
brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

У вас же не си. Зависания это может быть проблема отладчика, брaузера, да всего чего угодно. Может у вас где то брейк установлен и срабатывает. Зачем вы вообще отлаживаете этот простейший код ? Проверьте без отладчика и двигайтесь дальше.

Вот смотрите строка

currentLeftPos = header.indexOf('=', currentLeftPos++);

Происходит следующее в момент работы  header.indexOf значение currentLeftPos равно 12, по окончании работы оно увеличивается на единицу и становится 13, но поиск проводился с символа номер 12, а этот символ удовлетворяет условиям, поскольку вы присваиваете результат header.indexOf этой переменной, то она вновь становится 12

 

 

currentLeftPos = header.indexOf('=', currentLeftPos+1);

В момент работы  header.indexOf значение currentLeftPos равно 12, но в функцию header.indexOf передается значение 13, поскольку 12+1=13, поиск начинается с символа под номером 13 и успешно находится следующий, номер которого загружается в переменную currentLeftPos .
 
 
 
 

currentLeftPos = header.indexOf('=', ++currentLeftPos);

Значение currentLeftPos перед обращением в функцию поиска вычисляется и становится равно 13, поиск проводился с символа номер 13, следовательно поиск находит следующий символ.
 
Что удивляет ? Вам просто не понятен порядок работы операторов. И самое главное ВСЕ ЭТИ СТРОКИ ЗАГРУЖАЮТ В ПЕРЕМЕННУЮ РЕЗУЛЬТАТ header.indexOf и не имеет никакого значения что в момент загрузки находится в этой переменной.
 
<!doctype html>
<html dir="ltr" lang="ru">
  <head>
    <meta charset="utf-8">
    <title>Новая вкладка</title>
  </head>
  <body>
<script>
let header = "GET /?value1=45&value2=90&value3=105& HTTP/1.1";

let positions =[]; // массив для позиций символов в строке
 if(header.indexOf("GET /?value")>=0) { // если начало заголовка появилось...
let	currentLeftPos = header.indexOf('='); 
let	currentRightPos = header.indexOf('&'); 
while (currentLeftPos != -1 || currentRightPos != -1) { 
    alert(currentLeftPos+' '+currentRightPos);
    positions.push(currentLeftPos); // запихнуть левую позицию
    positions.push(currentRightPos); // запихнуть правую позицию
    currentLeftPos = header.indexOf('=', currentLeftPos++); 
    currentRightPos = header.indexOf('&', currentRightPos++);
 }	 
}	 
        let	valueString1 = header.substring(positions[0]+1, positions[1]);
		let	valueString2 = header.substring(positions[2]+1, positions[3]);
		let	valueString3 = header.substring(positions[4]+1, positions[5]);
		console.log(valueString1);
		console.log(valueString2);
		console.log(valueString3);
		console.log(positions);
</script>
  </body>
</html>

 

 
junior_developer
Offline
Зарегистрирован: 27.11.2017

Большое спасибо Вам за детальное объяснение!

zDimaBY
Offline
Зарегистрирован: 10.06.2018

#include <Servo.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h> // Библиотека для OTA-прошивки
const char *ssid = "Aleksander"; //Имя сети вайфай
const char *password = "11406080"; // пароль вайфай
Servo myservo;  // создаем экземпляр класса «Servo»,
Servo myservo1; // чтобы с его помощью управлять сервоприводом;
                // большинство плат позволяют
                // создать 12 объектов класса «Servo»
// GPIO-контакт, к которому подключен сервопривод:
static const int servoPin = 5;
static const int servo1Pin = 4;

// создаем веб-сервер на порте «80»:
WiFiServer server(80);

// переменная для хранения HTTP-запроса:
String header;
// несколько переменных для расшифровки значения в HTTP-запросе GET:
String valueString = String(170);
String valueString1 = String(180);
int pos1 = 0;
int pos2 = 0;

void setup() {
  Serial.begin(115200);

  myservo.attach(servoPin, 544, 1520);;  // привязываем сервопривод,
  myservo1.attach(servo1Pin); // подключенный к контакту «servoPin»,
                             // к объекту «myservo»
  // подключаемся к WiFi при помощи заданных выше SSID и пароля: 
  Serial.print("Connecting to ");  //  "Подключаемся к "
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  ArduinoOTA.setHostname("ESP8266_Серво-привод_антенны"); // Задаем имя сетевого порта
  //ArduinoOTA.setPassword((const char *)"0000"); // Задаем пароль доступа для удаленной прошивки
  ArduinoOTA.begin(); // Инициализируем OTA
  // печатаем локальный IP-адрес и запускаем веб-сервер:
  Serial.println("");
  Serial.println("WiFi connected.");  //  "WiFi подключен."
  Serial.println("IP address: ");     //  "IP-адрес: "
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  ArduinoOTA.handle(); // Всегда готовы к прошивке
  // начинаем прослушивать входящих клиентов:
  WiFiClient client = server.available();

  if (client) {                     // если подключился новый клиент,     
    Serial.println("New Client.");  // печатаем сообщение
                                    // «Новый клиент.»
                                    // в мониторе порта;
    String currentLine = "";        // создаем строку для хранения
                                    // входящих данных от клиента;
    while (client.connected()) {    // цикл while() будет работать
                                    // все то время, пока клиент
                                    // будет подключен к серверу;
      if (client.available()) {     // если у клиента есть данные,
                                    // которые можно прочесть, 
        char c = client.read();     // считываем байт, а затем    
        Serial.write(c);            // печатаем его в мониторе порта
        header += c;
        if (c == '\n') {            // если этим байтом является
                                    // символ новой строки
          // если получили два символа новой строки подряд,
          // то это значит, что текущая строчка пуста;
          // это конец HTTP-запроса клиента,
          // а значит – пора отправлять ответ:
          if (currentLine.length() == 0) {
            // HTTP-заголовки всегда начинаются
            // с кода ответа (например, «HTTP/1.1 200 OK»)
            // и информации о типе контента
            // (чтобы клиент понимал, что получает);
            // в конце пишем пустую строчку:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
                       //  "Соединение: отключено"
            client.println();

            // показываем веб-страницу:
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            client.println("<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial; margin-left:auto; margin-right:auto;}");
            client.println(".slider { width: 300px; }</style>");
            client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script>");
                     
            // веб-страница:
            client.println("</head><body><h1>ESP8266 Управление сервомотором антенны</h1>");
                                        //  "Управление сервомотором
                                        //   с помощью платы ESP32"
            client.println("<p>Позиция верх-вниз: <span id=\"servoPos\"></span></p>");     
            client.println("<input type=\"range\" min=\"70\" max=\"180\" class=\"slider\" id=\"servoSlider\" onchange=\"servo(this.value)\" value=\""+valueString+"\"/>");
            client.println("<p>Позиция лево-право: <span id=\"servoPos1\"></span></p>");
            client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider1\" onchange=\"servo1(this.value)\" value=\""+valueString1+"\"/>");
            
            client.println("<script>var slider = document.getElementById(\"servoSlider\");");
            client.println("var slider1 = document.getElementById(\"servoSlider1\");");
            client.println("var servoP = document.getElementById(\"servoPos\"); servoP.innerHTML = slider.value;");
            client.println("var servoP1 = document.getElementById(\"servoPos1\"); servoP1.innerHTML = slider1.value;");
            client.println("slider.oninput = function() { slider.value = this.value; servoP.innerHTML = this.value; }");
            client.println("slider1.oninput = function() { slider1.value = this.value; servoP1.innerHTML = this.value; }");
            client.println("$.ajaxSetup({timeout:1000}); function servo(pos) { ");            
            client.println("$.get(\"/?value=\" + pos + \"&\"); {Connection: close};}");
            client.println("function servo1(pos) { ");            
            client.println("$.get(\"/?value1=\" + pos + \"&\"); {Connection: close};}</script>");
            
            client.println("</body></html>");     
            
            //GET /?value=180& HTTP/1.1
            if(header.indexOf("GET /?value=")>=0) 
            {
              pos1 = header.indexOf('=');
              pos2 = header.indexOf('&');
              valueString = header.substring(pos1+1, pos2);
              
              //Rotate the servo
              myservo.write(valueString.toInt());
              Serial.print("Got servro val: "); 
              Serial.println(valueString); 
            }
            else if(header.indexOf("GET /?value1=")>=0) 
            {
              pos1 = header.indexOf('=');
              pos2 = header.indexOf('&');
              valueString1 = header.substring(pos1+1, pos2);
              
              //Rotate the servo
              myservo1.write(valueString1.toInt());
              Serial.print("Got servro1 val: "); 
              Serial.println(valueString1); 
            }
            
            // конец HTTP-ответа задается 
            // с помощью дополнительной пустой строки:
            client.println();
            // выходим из цикла while(): 
            break;
          } else { // если получили символ новой строки,
                   // очищаем текущую строку «currentLine»:
            currentLine = "";
          }
        } else if (c != '\r') {  // если получили любые данные,
                                 // кроме символа возврата каретки,
          currentLine += c;      // добавляем эти данные 
                                 // в конец строки «currentLine»
        }
      }
    }
    // очищаем переменную «header[]»:
    header = "";    
    // отключаем соединение:
    client.stop();
    Serial.println("Client disconnected.");
               //  "Клиент отключился."
    Serial.println("");
  }
}

Готовый код. Кому нужно будет.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

zDimaBY пишет:

Готовый код. Кому нужно будет.

не взлетит, сайт ссылки ломает...к примеру 98 строка

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Не ломает, открой код в отдельном окошке, там строка без переносов.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

brokly пишет:

Не ломает, открой код в отдельном окошке, там строка без переносов.

у меня сломано (FIREFOX) поправил как надо:

          client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script>");

junior_developer
Offline
Зарегистрирован: 27.11.2017

Насколько я понял, это подгружается библиотека jQuery с какого-то удаленного сервера, и это значит, что без доступа к нему скетч нормально работать не будет! Интересно, как добавить её прямо в память модуля и использовать локально?
Если бы не куча дополнительных символов, то наверно просто вставить содержимое между тегами <script> </script> в которых стоит ссылка на источник.

sadman41
Offline
Зарегистрирован: 19.10.2016

На SPIFFS положить, если влезет.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

84 килобайта, влезет. Только со SPIFFS грузится будет долго, нужно с кешированием шаманить. Только воз из этого скрипта могут быть обращения к другим ресурсам, это точно нужно проверять. 

sadman41
Offline
Зарегистрирован: 19.10.2016

Браузер закэширует. Наврядли стоит ESP-шкой CDN заменять.

junior_developer
Offline
Зарегистрирован: 27.11.2017
C помощью Ctrl+F попробовал найти в коде последовательность "http". Есть только 2 соответствия, и это не ссылки, а "XMLHttpRequest". 
{try{return new e.XMLHttpRequest}   // первое
(i["X-Requested-With"]="XMLHttpRequest") // второе

Ни к каким внешним ресурсам, насколько я понял, библиотека не обращается.
Значит файл с ней можно загрузить в файловую систему и просто указать на него ссылку?
И эта строка
client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script>");

станет выглядеть так:
client.println("<script src=\"/jquery.min.js\"></script>");
Верно?
 
Конечно в начале файла нужно вставить
#include <FS.h> // библиотека для работы с файловой системой
в setup  инициализировать её
SPIFFS.begin();
а дальше в функцию handleFileRead добавить:
else if(path.endsWith("/jquery.min.js")) path += "jquery.min.js";
bool handleFileRead(String path){ // Функция работы с файловой системой
  if(path.endsWith("/")) path += "index.html"; // Если устройство вызывается по корневому адресу, то должен вызываться файл index.html (добавляем его в конец адреса)
  else if(path.endsWith("/jquery.min.js")) path += "jquery.min.js";   // файл библиотеки                    
  String contentType = getContentType(path); // С помощью функции getContentType (описана ниже) определяем по типу файла (в адресе обращения) какой заголовок необходимо возвращать по его вызову
  if(SPIFFS.exists(path)){// Если в файловой системе существует файл по адресу обращения
    File file = SPIFFS.open(path, "r"); //  Открываем файл для чтения
    size_t sent = HTTP.streamFile(file, contentType);//  Выводим содержимое файла по HTTP, указывая заголовок типа содержимого contentType
    file.close();//  Закрываем файл
    return true;//  Завершаем выполнение функции, возвращая результатом ее исполнения true (истина)
  }
  return false; // Завершаем выполнение функции, возвращая результатом ее исполнения false (если не обработалось предыдущее условие)
}
// и еще нужна функция для возврата правильного заголовка
String getContentType(String filename){ // Функция, возвращающая необходимый заголовок типа содержимого в зависимости от расширения файла
  if (filename.endsWith(".html")) return "text/html";// Если файл заканчивается на ".html", то возвращаем заголовок "text/html" и завершаем выполнение функции
  else if (filename.endsWith(".css")) return "text/css";// Если файл заканчивается на ".css", то возвращаем заголовок "text/css" и завершаем выполнение функции
  else if (filename.endsWith(".js")) return "application/javascript";// Если файл заканчивается на ".js", то возвращаем заголовок "application/javascript" и завершаем выполнение функции
  else if (filename.endsWith(".png")) return "image/png";// Если файл заканчивается на ".png", то возвращаем заголовок "image/png" и завершаем выполнение функции
  else if (filename.endsWith(".jpg")) return "image/jpeg";// Если файл заканчивается на ".jpg", то возвращаем заголовок "image/jpg" и завершаем выполнение функции
  else if (filename.endsWith(".gif")) return "image/gif";// Если файл заканчивается на ".gif", то возвращаем заголовок "image/gif" и завершаем выполнение функции
  else if (filename.endsWith(".ico")) return "image/x-icon";// Если файл заканчивается на ".ico", то возвращаем заголовок "image/x-icon" и завершаем выполнение функции
  return "text/plain";// Если ни один из типов файла не совпал, то считаем что содержимое файла текстовое, отдаем соответствующий заголовок и завершаем выполнение функции
}
Или я ошибаюсь?
brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Нет конечно. Скорее всего нужно так:

if(path.endsWith("/jquery.min.js")) path = "/jquery.min.js";

Только вот , по моему, стандартный SPIFFS не поддерживает две точки в имени. Так что имя файлы нужно привести к нормальному виду. Более того конструкция if(path.endsWith("/")) path += "index.html" не однозначна, например на запрос типа /blablabla/ она будет пытаться отправить файл /blablabla/index.html, которого , конечно, на диске не будет.

rst
Offline
Зарегистрирован: 25.06.2018

junior_developer пишет:
C помощью Ctrl+F попробовал найти в коде последовательность "http".
А с чего решили что в коде может храниться только в таком виде?

Хранить в коде можно как угодно - как удобнее программе. Например в одном моём проекте, где нужно хранить много ссылок на разные HTTP-ресурсы, они хранятся в виде URL-ов без префикса протокола (http://). Протокол хранится отдельно - двоичным числом. Да и сами URL-ы хранятся в сжатом виде и тупым текстовым поиском их не найдёшь.

junior_developer
Offline
Зарегистрирован: 27.11.2017
Наверно проще всего скопировать всё содержимое скрипта в текстовый файл, например jquery_min.txt, загрузить его в файловую систему, и 
client.println("<script>"); // начало скрипта
jquery_min = SPIFFS.open("/jquery_min.txt", "r"); // открыть файл с текстом скрипта и присвоить его содержимое jquery_min
if (!jquery_min) { Serial.println("file open failed");} //  "открыть файл не удалось"
}
while (jquery_min.available()) {
  client.print(char(jquery_min.read())); // вывод всех символов
}
jquery_min.close();
client.println("</script>"); //конец скрипта

Код целиком

#include <Servo.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <FS.h> // Библиотека файловой системы
#include <ArduinoOTA.h> // Библиотека OTA-прошивки
const char *ssid = "SSID"; //Имя сети вайфай
const char *password = "password"; // пароль вайфай
File jquery_min; // для чтения файла
Servo myservo;  // создаем экземпляр класса «Servo»,
Servo myservo1; // чтобы с его помощью управлять сервоприводом;
// большинство плат позволяют
// создать 12 объектов класса «Servo»
// GPIO-контакт, к которому подключен сервопривод:
static const int servoPin = 5;
static const int servo1Pin = 4;

// создаем веб-сервер на порте «80»:
WiFiServer server(80);

// переменная для хранения HTTP-запроса:
String header;
String valueString = String(170);
String valueString1 = String(180);
int pos1 = 0;
int pos2 = 0;

void setup() {
  Serial.begin(115200);
  SPIFFS.begin();  // инициализируем библиотеку для работы с файловой системой
  Serial.print("Connecting to ");
  myservo.attach(servoPin, 544, 1520);;  // привязываем сервопривод,
  myservo1.attach(servo1Pin); // подключенный к контакту «servoPin»,
  // к объекту «myservo»
  // подключаемся к WiFi при помощи заданных выше SSID и пароля:
  Serial.print("Connecting to ");  //  "Подключаемся к "
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  ArduinoOTA.setHostname("ESP8266_Серво-привод_антенны"); // Задаем имя сетевого порта
  //ArduinoOTA.setPassword((const char *)"0000"); // Задаем пароль доступа для удаленной прошивки
  ArduinoOTA.begin(); // Инициализируем OTA
  // печатаем локальный IP-адрес и запускаем веб-сервер:
  Serial.println("");
  Serial.println("WiFi connected.");  //  "WiFi подключен."
  Serial.println("IP address: ");     //  "IP-адрес: "
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop() {
  ArduinoOTA.handle(); // Всегда готовы к прошивке
  // начинаем прослушивать входящих клиентов:
  WiFiClient client = server.available();

  if (client) {                     // если подключился новый клиент,
    Serial.println("New Client.");  // печатаем сообщение
    // «Новый клиент.»
    // в мониторе порта;
    String currentLine = "";        // создаем строку для хранения
    // входящих данных от клиента;
    while (client.connected()) {    // цикл while() будет работать
      // все то время, пока клиент
      // будет подключен к серверу;
      if (client.available()) {     // если у клиента есть данные,
        // которые можно прочесть,
        char c = client.read();     // считываем байт, а затем
        Serial.write(c);            // печатаем его в мониторе порта
        header += c;
        if (c == '\n') {            // если этим байтом является
          // символ новой строки
          // если получили два символа новой строки подряд,
          // то это значит, что текущая строчка пуста;
          // это конец HTTP-запроса клиента,
          // а значит – пора отправлять ответ:
          if (currentLine.length() == 0) {
            // HTTP-заголовки всегда начинаются
            // с кода ответа (например, «HTTP/1.1 200 OK»)
            // и информации о типе контента
            // (чтобы клиент понимал, что получает);
            // в конце пишем пустую строчку:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            //  "Соединение: отключено"
            client.println();

            // показываем веб-страницу:
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            client.println("<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial; margin-left:auto; margin-right:auto;}");
            client.println(".slider { width: 300px; }</style>");
            client.println("<script>"); // начало скрипта
            jquery_min = SPIFFS.open("/jquery_min.txt", "r"); // открыть файл с текстом скрипта и присвоить его содержимое jquery_min
            if (!jquery_min) {
              Serial.println("file open failed"); //  "открыть файл не удалось"
            }
            while (jquery_min.available()) {
              client.print(char(jquery_min.read())); // вывод всех символов
            }
            jquery_min.close();
            client.println("</script>"); //конец скрипта

            // веб-страница:
            client.println("</head><body><h1>ESP8266 Управление сервомотором антенны</h1>");
            //  "Управление сервомотором
            //   с помощью платы ESP32"
            client.println("<p>Позиция верх-вниз: <span id=\"servoPos\"></span></p>");
            client.println("<input type=\"range\" min=\"70\" max=\"180\" class=\"slider\" id=\"servoSlider\" onchange=\"servo(this.value)\" value=\"" + valueString + "\"/>");
            client.println("<p>Позиция лево-право: <span id=\"servoPos1\"></span></p>");
            client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider1\" onchange=\"servo1(this.value)\" value=\"" + valueString1 + "\"/>");

            client.println("<script>var slider = document.getElementById(\"servoSlider\");");
            client.println("var slider1 = document.getElementById(\"servoSlider1\");");
            client.println("var servoP = document.getElementById(\"servoPos\"); servoP.innerHTML = slider.value;");
            client.println("var servoP1 = document.getElementById(\"servoPos1\"); servoP1.innerHTML = slider1.value;");
            client.println("slider.oninput = function() { slider.value = this.value; servoP.innerHTML = this.value; }");
            client.println("slider1.oninput = function() { slider1.value = this.value; servoP1.innerHTML = this.value; }");
            client.println("$.ajaxSetup({timeout:1000}); function servo(pos) { ");
            client.println("$.get(\"/?value=\" + pos + \"&\"); {Connection: close};}");
            client.println("function servo1(pos) { ");
            client.println("$.get(\"/?value1=\" + pos + \"&\"); {Connection: close};}</script>");

            client.println("</body></html>");

            //GET /?value=180& HTTP/1.1
            if (header.indexOf("GET /?value=") >= 0)
            {
              pos1 = header.indexOf('=');
              pos2 = header.indexOf('&');
              valueString = header.substring(pos1 + 1, pos2);

              //Rotate the servo
              myservo.write(valueString.toInt());
              Serial.print("Got servro val: ");
              Serial.println(valueString);
            }
            else if (header.indexOf("GET /?value1=") >= 0)
            {
              pos1 = header.indexOf('=');
              pos2 = header.indexOf('&');
              valueString1 = header.substring(pos1 + 1, pos2);

              //Rotate the servo
              myservo1.write(valueString1.toInt());
              Serial.print("Got servro1 val: ");
              Serial.println(valueString1);
            }

            // конец HTTP-ответа задается
            // с помощью дополнительной пустой строки:
            client.println();
            // выходим из цикла while():
            break;
          } else { // если получили символ новой строки,
            // очищаем текущую строку «currentLine»:
            currentLine = "";
          }
        } else if (c != '\r') {  // если получили любые данные,
          // кроме символа возврата каретки,
          currentLine += c;      // добавляем эти данные
          // в конец строки «currentLine»
        }
      }
    }
    // очищаем переменную «header[]»:
    header = "";
    // отключаем соединение:
    client.stop();
    Serial.println("Client disconnected.");
    //  "Клиент отключился."
    Serial.println("");
  }
}

brokly пишет:

84 килобайта, влезет. Только со SPIFFS грузится будет долго, нужно с кешированием шаманить.

Да, Вы абсолютно правы! Эта простая страничка грузится почти 9 секунд! И даже реакция на перемещение ползунков примерно 1 секунда! 

rkit
Offline
Зарегистрирован: 23.11.2016

spiffs работает приемлемо. Веб-сервер медленный.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

rkit пишет:

spiffs работает приемлемо. Веб-сервер медленный.

Переход на внешнюю SDшку с фатом дает прирост скорости в два раза.