наиболее правильно организовать дёргание пинами

mishkas
Offline
Зарегистрирован: 03.08.2019

Доброго дня! 

пописывая в этом разделе понятно что я нуб уровня 0! 

есть esp8266.

в инете нашел какой-то скетч, залил через ардуино иде. 

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

на экране сейчас 2 кнопки

при нажатии выкл - кнопочка меняется на ВКЛ и, допустим, светодиод тухнет - тут всё правильно.

но если нажимаю вторую (правда в скетче для теста 5 сек, а не мин) кнопка меняется на вкл, светодиод тухнет, проходит 5 сек, светодиод включается, но левая кнопка не меняется..

мне кажется что в моем случае не самый лучший вариант организовывать простым выводом страницы html...

подскажите как лучше организовать нечто подобное? (думал о динамическом html  со скриптами, но в них тоже нуб..)

#include <ESP8266WiFi.h>
unsigned long timing;
const char* ssid = "home";//type your ssid
const char* password = "12345678";//type your password
int val = 0;
int ledPin = 2; // GPIO2 of ESP8266
WiFiServer server(80);//Service Port

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

pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);


timing = 0;

// Connect to WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");

// Start the server
server.begin();
Serial.println("Server started");

// Print the IP address
Serial.print("Use this URL to connect: ");
Serial.print("http://");
Serial.print(WiFi.localIP());
Serial.println("/");
}

void loop() {
// Check if a client has connected
WiFiClient client = server.available();
if (!client) {
  if ((timing != 0) and (millis() - timing > 5000)) {
  timing = 0;
  digitalWrite(ledPin, LOW);  
  Serial.println(millis() - timing);
}
return;
}

// Wait until the client sends some data
Serial.println("new client");
while(!client.available()){
delay(1);
}

// Read the first line of the request
String request = client.readStringUntil('\r');
Serial.println(request);
client.flush();

// Match the request

int value = LOW;
if (request.indexOf("/LED=0") != -1) {
digitalWrite(ledPin, LOW);
value = LOW;
} 
if (request.indexOf("/LED=1") != -1){
digitalWrite(ledPin, HIGH);
value = HIGH;
}

if (request.indexOf("/LED=5min") != -1){
  timing = millis();
  digitalWrite(ledPin, HIGH);  
  Serial.println(timing);
}

if ((timing != 0) and (millis() - timing > 5000)) {
  timing = 0;
  digitalWrite(ledPin, LOW);  
  Serial.println(millis() - timing);
}
 


//Set ledPin according to the request
//digitalWrite(ledPin, value);

// Return the response
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println(""); //  do not forget this one
client.println("<!DOCTYPE HTML>");
client.println("<html>");

client.println("<head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><title>Дергунчик!</title>");

client.println("<style type=\"text/css\">"); //стили
client.println("html {font-size: 18px;}");
client.println("body {width: 80%; margin: auto; text-align: center;}");
client.println("a {font-size: 1.5rem;}");
client.println("a.button0{position: relative;display: inline-block;width: 10em;height: 2.5em;line-height: 2.5em;vertical-align: middle;text-align: center;text-decoration: none;text-shadow: 0 -1px 1px #777;color: #fff;outline: none;border: 2px solid #F64C2B;border-radius: 5px;box-shadow: 0 0 0 60px rgba(0,0,0,0) inset, .1em .1em .2em #800;background: linear-gradient(#FB9575, #F45A38 48%, #EA1502 52%, #F02F17)}a.button25:active{top: .1em;left: .1em;box-shadow: 0 0 0 60px rgba(0,0,0,.05) inset}");
client.println("a.button1{position: relative;display: inline-block;width: 10em;height: 2.5em;line-height: 2.5em;vertical-align: middle;text-align: center;text-decoration: none;text-shadow: 0 -1px 1px #777;color: #fff;outline: none;border: 2px solid #00a903;border-radius: 5px;box-shadow: 0 0 0 60px rgba(0,0,0,0) inset, .1em .1em .2em #048800;background: linear-gradient(#92fb75, #44f438 48%, #39dc00 52%, #16a900)}a.button25:active{top: .1em;left: .1em;box-shadow: 0 0 0 60px rgba(0,0,0,.05) inset}");
client.println("p {font-size: 1rem;}");
client.println("</style>");

client.println("</head>");


val = digitalRead(ledPin); //считал состояние 1- почему-то выкл, а 0-вкл! :(


client.println("<body>"); //тельце

if(val == 0) { // если включено выводим кнопку вЫключить
client.println("<a class=\"button0\" href=\"/LED=1\">ВЫкл</a>");
} else {
client.println("<a class=\"button1\" href=\"/LED=0\">Вкл</a>");
}

client.println("<a class=\"button0\" href=\"/LED=5min\">Выкл - 5 мин - вкл</a>"); // кнопка выкл и чрез 5 мин вкл


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

delay(1);
Serial.println("Client disconnected");
Serial.println("");
Serial.println(timing);
}

извините за длинный пост. не нашел спойлер в меню редактора..

beshur
Offline
Зарегистрирован: 01.08.2019

Привет.

Похоже, проблема в том, что после клика на "Выкл - 5 мин - вкл" страница сразу перезагружается, и клиент уже никак не получит уведомление о том, что состояние val изменилось.

Я бы добавил в HTML небольшой скрипт, который опрашивал бы ESP о состоянии, и обновлял страницу:

<script>
// интервал, срабатывает каждую секунду
setInterval(function() {
  // Запрос состояния, нужно добавить хендлер в адруино код
  fetch("/state")
    .then(function(response) {
      // нужная кнопка на странице
      var button = document.querySelector('.button1'); 
      if (response.body == 1) {
        button.innerText = "Выкл";
      } else {
        button.innerText = "Вкл";
     }
    });
}, 1000);
</script>

Надо еще добавить обработчик запроса state и возвращать в теле ответа значение val, вместо всей страницы HTML.

mishkas
Offline
Зарегистрирован: 03.08.2019

Спасибо за ответ. Надо над ним поразмыслить.

сейчас ищу в инете простейший ajax.

можно обратиться к ESP, допустим, по адресу http://10.10.10.2/state, а он в страничку вернет состояние.

скорее всего примерно об этом же Вы и сказали...

beshur
Offline
Зарегистрирован: 01.08.2019

fetch() - это простейший современный ajax

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

А поддержка какая у ардуино html и ajax? Мне просто самому интересно. Доп библиотеки надо юзать или что?

Morroc
Offline
Зарегистрирован: 24.10.2016

В данном случае ESP должен просто формировать правильный HTML и возвращать ответ на запрос /state, ничего сверх уже использованного, к примеру, в первом посте не требуется.

mishkas
Offline
Зарегистрирован: 03.08.2019

Простите за, возможно, глупые вопросы..
не смог найти где описывается функция fetch (пробовал искать как функцию из ESP8266WiFi.h, а так-же просто в инете) наверное меня интересует то что она возвращает (я так понял это объект)

дело в том что после:

if (response.body == 1) {

у меня никогда не возвращалось "1"

попробовал ниже сделать так:

client.println("        button.innerText = response.body;");

вместо:

client.println("      if (response.body == 1) {");
client.println("        button.innerText = \"Выкл\";");
client.println("      } else {");
client.println("        button.innerText = \"Вкл\";");
client.println("     }");

на кнопке появляется "object ReadableStream"

обработчик /state добавил

if (request.indexOf("/state") != -1){
  val = digitalRead(ledPin);
  Serial.print("состояние pin2 ");
  Serial.println(val);
  client.print(val);
}

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

 

ну и почему-то не работал скрипт если написан не полный путь (мелочь, но пока не разобрался)

fetch("/state")

а если пишу:

fetch(\"http://192.168.8.85/state\")

то браузер уже не ругается при просмотре sources в инструментах хрома

не знаю нужен ли полный скетч для понимания:

#include <ESP8266WiFi.h>
unsigned long timing;
const char* ssid = "hohohoho";//type your ssid
const char* password = "11111111";//type your password
int val = 0;
int ledPin = 2; // GPIO2 of ESP8266
WiFiServer server(80);//Service Port

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

pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);


timing = 0;

// Connect to WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");

// Start the server
server.begin();
Serial.println("Server started");

// Print the IP address
Serial.print("Use this URL to connect: ");
Serial.print("http://");
Serial.print(WiFi.localIP());
Serial.println("/");
}

void loop() {
// Check if a client has connected
WiFiClient client = server.available();
if (!client) {
return;
}

// Wait until the client sends some data
Serial.println("new client");
while(!client.available()){
delay(1);
}

// Read the first line of the request
String request = client.readStringUntil('\r');
Serial.println(request);
client.flush();

// Match the request

int value = LOW;
if (request.indexOf("/LED=0") != -1) {
digitalWrite(ledPin, LOW);
value = LOW;
} 
if (request.indexOf("/LED=1") != -1){
digitalWrite(ledPin, HIGH);
value = HIGH;
}

if (request.indexOf("/state") != -1){
  val = digitalRead(ledPin);
  Serial.print("состояние pin2 ");
  Serial.println(val);
  client.println(val);
}

 
// Return the response
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println(""); //  do not forget this one
client.println("<!DOCTYPE HTML>");
client.println("<html>");


val = digitalRead(ledPin); //считал состояние. 1- почему-то выкл, а 0-вкл! :(

client.println("<head>");
client.println("<meta charset=\"utf-8\">");
client.println("<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>");
client.println("</script>");



client.println("<script>");
// интервал, срабатывает каждую секунду
client.println("setInterval(function() {");
  // Запрос состояния, нужно добавить хендлер в адруино код
client.println("  fetch(\"http://192.168.8.85/state\")");
client.println("    .then(function(response) {");
      // нужная кнопка на странице
client.println("      var button = document.querySelector('.button1');");
/*client.println("      if (response.body == 1) {");
client.println("        button.innerText = \"Выкл\";");
client.println("      } else {");
client.println("        button.innerText = \"Вкл\";");
client.println("     }");*/

client.println("        button.innerText = response.body;");

client.println("    });");
client.println("}, 1000);");
client.println("</script>");


client.println("</head>");



client.println("<body>"); //тельце

client.println("<button class=\"button1\">...</button>");
client.println("<a class=\"button0\" href=\"/LED=1\">OFF</a>&nbsp;");
client.println("<a class=\"button0\" href=\"/LED=0\">ON</a>&nbsp;");

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

 

mishkas
Offline
Зарегистрирован: 03.08.2019

возможно дело в том что после /state возвращается вся лабуда с кнопками..

а скрипту нужна только 1 или 0

пробовал в отдельную функцию вывод лабуды вынести, что-то перестает  всё работать.. (сначала ругался компилятор на неопознанность переменной client. я попробовал её опубликовать ещё до void setup)

:(

Morroc
Offline
Зарегистрирован: 24.10.2016

mishkas пишет:
возможно дело в том что после /state возвращается вся лабуда с кнопками..

анекдот вспомнился про старушку и врача ) зачем вы на /state возвращаете лабуду с кнопками ?

mishkas
Offline
Зарегистрирован: 03.08.2019

Morroc пишет:

 зачем вы на /state возвращаете лабуду с кнопками ?

я не специально. так написано в теле цикла LOOP. я пытался вывод вынести в отдельную функцию, но ничего не выводится. думаю с функциями не умею работать как следует.. 

почему-то если пишу в обработчике запроса:

if (request.indexOf("/state") != -1){
  val = digitalRead(ledPin);
  Serial.print("состояние pin2 ");
  Serial.println(val);
  client.println(val);
}

то client.println выводит содержимое на страницу, а если заношу в функцию (чтобы в loop когда надо и не надо не выводилось)

типа: 

htmlOutput() {
client.println("<p>privet</p>");
}

и вызываю функцию где необходимо, то никакого содержимого в браузер не отправляется..

переменную client вне функций инициализировал.. вроде..

 

:( я знаю что надо книжечку сначала какую-нибудь прочесть прежде чем что-либо делать.

Morroc
Offline
Зарегистрирован: 24.10.2016

Без полного кода сложно сказать, но вы можете написать блок if ... else либо case чтобы обрабатывать каждую ситуацию, требующую ответа на запрос, отдельно - тогда будет возвращаться конкретный один ответ, без "лабуды" (когда она не нужна). Другой вариант что то типа

if ((request.indexOf("/LED=0") != -1) || (request.indexOf("/LED=1") != -1) || (request.indexOf("/LED=5min") != -1)) {
  if (request.indexOf("/LED=0") != -1) { 
...
    digitalWrite(ledPin, HIGH); 
    Serial.println(timing);
  }
} else {
  client.println("HTTP/1.1 200 OK");
...
  client.println("</html>");
}

третий вариант опять же разбить все на отдельные блоки (в каждом блоке один вариант ответа), обернуть каждый в if (!flag_already_answered) {}; и после каждого заключительного client.println(...); в ответе взводить флаг flag_already_answered = true; (не забыть сбросить flag_already_answered = false;  в начале если объявили его зачем то глобально) и т.д. и т.п.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

mishkas пишет:

:( я знаю что надо книжечку сначала какую-нибудь прочесть прежде чем что-либо делать.

А если знаете, так чего не делаете?

mishkas
Offline
Зарегистрирован: 03.08.2019

offtop

дело в том что это увлечение, его надо успевать помимо работы и семьи ))))))
и с экрана читать - жуть! инструкцию можно, рассказик мелкий можно, а книгу - невозможно ))))
но книжечку я скачал ещё 2 недели назад по ссылочке с этого же форума ))) и даже начал, но 5 минут и бросил. слишком много сил с экрана читать.. решил что другим способом почитаю как нибудь..

а по теме:

нашел где водится fetch! он проживает в мануалах по jqery javascript html и т.п. ))
нашел что там есть несколько параметров возвращаемых данных (body, text, json), но мой, почему-то, возвращает неизвестно что и пока я не знаю как посмотреть что он выводит..

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Да бросьте вы это - книжки умные с экрана читать. Они у вас в печатном виде да под рукой всегда должны быть, с закладками. Я вот тоже с экрана не очень умные книги читать, хотя фантастическую литературу или там рассказики какие и можно вроде. Не знаю. Может староват становлюсь + но раньше только бумагу и читал. Душевнее чтоли....

Morroc
Offline
Зарегистрирован: 24.10.2016

Что там за экраны у вас ? С современного экрана читается легче - контраст / четкость / разрешение уже сравнимы с бумагой, шрифт можно подобрать любой какой нравится и бумажка серой не будет как в дешевых изданиях, а на новой мобиле OLED экран вообще фантастика. К этому добавляем возможность мгновенно скопировать/загуглить/перевести что нибудь и... бумажка всё.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Morroc пишет:

Что там за экраны у вас ? С современного экрана читается легче - контраст / четкость / разрешение уже сравнимы с бумагой, шрифт можно подобрать любой какой нравится и бумажка серой не будет как в дешевых изданиях, а на новой мобиле OLED экран вообще фантастика. К этому добавляем возможность мгновенно скопировать/загуглить/перевести что нибудь и... бумажка всё.

И тут вспоминается старый анекдот на современный лад - Задницу олед дисплеем подтирать не очень комфортно )))

А вообще - каждому что по духу. Бумажное воспринимается лучше (для меня), можно листать, гнуть, загибать, вырывать листы даже (!), но это возрастное возможно просто... 

Morroc
Offline
Зарегистрирован: 24.10.2016

BOOM пишет:

можно листать, гнуть, загибать, вырывать листы даже (!)

вот это да ! офигеть ! :) а еще поджечь можно !