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

Посоветуйте доработку скетча для надежности

CCat

Member
Здравствуйте! Залил через Arduino IDE следующий скетч для использования ESP8266 вместе с Arduino Nano - Arduino дает команды, когда коннектиться, какой у нас пароль и имя точки доступа, с которой надо соединиться, и по какому URL сделать запрос.
Сначала командую "connectWifi", после ответа "esp_connected" командую "getFromWifi" и вроде все ОК - получаю нужную мне строку.
Но чувствую, что-то не докрутил, чтобы ESP "покрасить и забыть".
Например, в строках 34-36 моего письма, любезная Катерина Матвевна
Код:
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
    }
(взято из примера) - это ж вроде бесконечный цикл получится, если коннекта так и не произойдет.
И вообще, может, нужна какая-то доработка типа "что-то ты походу завис, дружок - дай я тебя перезагружу". Я ж вообще могу ногу RESET ESP8266 спокойно замкнуть на землю аппаратно на Arduino для сброса.
В общем, если кто-то что посоветует по нижеследующему коду в плане надежности - буду очень рад.


Код:
#include <ESP8266WiFi.h>
#include "CommandsParser.h" //это для получения команд через serial

String connectWifi = "n";
char* ssid = NULL;
char* password = NULL;
String getFromWifi = "n";
char* host = NULL;
String url;

int start = 0;

CommandsParser cParser(Serial); // parse from Serial

void paramsHandler(const char* param, const char* value)
{
// здесь присваиваю значения connectWifi, ssid, password, getFromWifi, host, url по командам, пришедшим по serial
}

void setup() {
  Serial.begin(9600);
  delay(10);
  cParser.begin(paramsHandler);
}

void loop() {
  cParser.update();

  if (connectWifi == "y") {
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
    }
    Serial.println("esp_connected");
    connectWifi = "n";
  }
  if (getFromWifi == "y") {

    WiFiClient client;
    const int httpPort = 80;
    if (!client.connect(host, httpPort)) {
      Serial.println("esp_connection_failed");
      return;
    }

    // запрос на сервер
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                 "Host: " + host + "\r\n" +
                 "Connection: close\r\n\r\n");
    unsigned long timeout = millis();
    while (client.available() == 0) {
      if (millis() - timeout > 5000) {
        Serial.println("esp_client_timeout");
        client.stop();
        return;
      }
    }

    // читаем тело ответа и берем нужное - от "{"
    String body = "";
    boolean httpBody = false;
    while (client.available()) {
      String line = client.readStringUntil('\r');
      if (!httpBody && line.charAt(1) == '{') {
        httpBody = true;
      }
      if (httpBody) {
        body += line;
      }
    }
    //Serial.print("status=ok&output=");
    Serial.println(body);
    getFromWifi = "n";
  }
}
 

gerkimuyda

New member
В том-то и дело, что во всех примерах такой говнокод написан. И нигде не обрабатывается разрыв уже установленной связи.
Вообще, если отойти от "светодиодов ардуины", то как надо писать подобную логику? Правильно, все события вешать на прерывания, а в главном цикле работать с флажками и переменными.
Т.е. в вашем случае вы даете команду на подключение WiFi и устанавливаете обработчик на прерывание. Все, дальше - выходите их функции. Задачу выполнили.
Теперь обработчик висит и ждет события, которое обработает (подключение или ошибка и т.д.). В главном цикле смотрите на таймаут и предпринимаете другие шаги, если событий не произошло.
Как-то так :) Если постигните нирвану и решите подняться на уровень выше - вэлком ту eclipse/make :D
 
  • Like
Реакции: CCat

CCat

Member
Духовный наставник ;), подскажите, а
Код:
    if (!client.connect(host, httpPort)) {
      Serial.println("error=http_connection_fail");
      return;
    }
Тоже суть бесконечный цикл при неудаче? Я не совсем понимаю в данном фрагменте, return откинет назад к client.connect или вообще к циклу loop() заново?
 

gerkimuyda

New member
Это надо смотреть ГДЕ сей код написан. Если в loop() - то это эквивалентно прерыванию обработки текущего главного цикла и переход к следующему (т.к. система обработает свои грязные делишки в фоне, а потом запустит заново функцию loop()
Если это в функции отправки данных на сервер, которая перед отправкой устанавливает соединение, то это она так обрабатывает отказ от отправки по причине невозможности подключить вайфай.
Но именно "безконечного цикла" тут нет. Т.к. тут нет вообще цикла. Тут только оператор условия. Циклы - это WHILE, FOR, DO...
 

kab

New member
Духовный наставник ;), подскажите, а
Код:
    if (!client.connect(host, httpPort)) {
      Serial.println("error=http_connection_fail");
      return;
    }
Тоже суть бесконечный цикл при неудаче? Я не совсем понимаю в данном фрагменте, return откинет назад к client.connect или вообще к циклу loop() заново?
А вообще, если у Вас возникают сомнения, куда переходит программа в том или ином случае - иногда быстрее, чем разбираться умозрительно - наставить в программу строчек типа Serial.println("point 1"); .... Serial.println("point 2"); ... и т.д.

И в выводе в мониторе последовательного порта увидите сами, куда передалось управление
 

gerkimuyda

New member
Да, почти сразу вернется к выполнению 27 строки. Перед этим будет сделано что-то вроде esp_schedule(); esp_yield(); и т.д. Т.е. фоновая работа библиотеки ардуино.
 
  • Like
Реакции: CCat

gerkimuyda

New member
А в чем принципиальное отличие?
Код:
bool ESP8266WiFiSTAClass::isConnected() {
return (status() == WL_CONNECTED);
}
И там и там вызывается функция status().

Почему тогда не
Код:
while( !WiFi.isConnected() )
 
  • Like
Реакции: kab

CCat

Member
Спасибо!
Поскольку многое в этой и подобных библиотеках выполняется фоном (вон, почитал про esp_yield(); и т.д.), не пойму - надо мне при каждом запросе выполнять строки 31-39, всякие "WiFi.begin(ssid, password);" или библиотека сама заботится о поддержании связи с точкой доступа?
И тогда нужно первую часть Марлезонского балета (31-39) исполнять только "при включении", а вторую часть балета (41-77) - каждый раз, когда хочу получить строку с http-сервера?
 

enjoynering

Well-known member
каждый раз когда вызываете WiFi.begin(ssid, password); ардуино презаписывает назание точки доступа и пароль. в итоге через год, два таких манипуляций у вас на флешке будет дырка.

надо делать так

Код:
  if (WiFi.SSID() != stationConfig.ssid || WiFi.psk() != stationConfig.password)                    //don't rewrite flash with no reason
  {
    WiFi.begin(stationConfig.ssid, stationConfig.password);
  }
 else
{
  WiFi.begin();
}
 
Последнее редактирование:

CCat

Member
надо делать так
Вы имеете в виду, что нужно сравнивать получаемый пароль и ssid с теми, которые были заданы до этого, и если они те же, то в WiFi.begin() нет никакой надобности?

Так вроде же я не могу получить в скетче значения "что там у нас прописано во flash насчет пароля и ssid".
Но я могу сделать типа
Код:
if (!strcmp(previousSsid, ssid) || !strcmp(previousPassword, password))
  {
    WiFi.begin(); //без параметров законнектится с записанными во flash значениями
  }
else
  {
    WiFi.begin(ssid, password); 
  }
 
Последнее редактирование:

Алексей.

Active member
Извините, что не в тему, ну уж совсем не смог сдержаться.
Как-то так :) Если постигните нирвану и решите подняться на уровень выше - вэлком ту eclipse/make :D
Автор вышеуказанного топика (того что с UDK и уже закрытого), откровенно говорит, что ему совершенно не интересна разработка под линукс, так что простым пользователям, живущим в альтернативной (от микрософт) реальности свободно распространяемого ПО это UDK нужно будет допиливать, так что, быстрого старта как с NONOS и RTOS не получится.
 

enjoynering

Well-known member
Вы имеете в виду, что нужно сравнивать получаемый пароль и ssid с теми, которые были заданы до этого, и если они те же, то в WiFi.begin() нет никакой надобности?
кол. циклов записи у флеш пямяти ОГРАНИЧЕН. ардуино презаписывает на флеш название точки доступа и пароль каждый раз при вызове - WiFi.begin(ssid, password). в итоге через год, два таких манипуляций у вас на флешке будет дырка.

теперь понятно?
 
  • Like
Реакции: CCat

CCat

Member
теперь понятно?
Про флеш я понял, Вы правы, спасибо! Я не понял сначала Вашего кода.
Потом почитал про WiFi.SSID() и WiFi.psk() и дошло.
Вопрос тогда в одном - если пароль и ssid тот же, запускать ли WiFi.begin() без параметров, или WiFi.reconnect(), или ничего не делать?
 
Последнее редактирование:

enjoynering

Well-known member
судя по Arduino/ESP8266WiFiSTA.cpp at master · esp8266/Arduino · GitHub

да лучше вызвать WiFi.begin();

вот это кусок

Код:
/**
* Use to connect to SDK config.
* @return wl_status_t
*/
wl_status_t ESP8266WiFiSTAClass::begin() {

    if(!WiFi.enableSTA(true)) {
        // enable STA failed
        return WL_CONNECT_FAILED;
    }

    ETS_UART_INTR_DISABLE();
    wifi_station_connect();
    ETS_UART_INTR_ENABLE();

    if(!_useStaticIp) {
        wifi_station_dhcpc_start();
    }
    return status();
}
 
  • Like
Реакции: CCat

gerkimuyda

New member
Автор вышеуказанного топика (того что с UDK и уже закрытого), откровенно говорит, что ему совершенно не интересна разработка под линукс, так что простым пользователям, живущим в альтернативной (от микрософт) реальности свободно распространяемого ПО это UDK нужно будет допиливать, так что, быстрого старта как с NONOS и RTOS не получится.
Живущие в альтернативной реальности сами не лыком шиты и имеют возможности коррекции компилинга этого проекта под свои нужды.
И никто не исключает вариант с виртуальный компом. Я так под виндой и сделал для ESP - виртуальный комп с AVR-studio от Атмела для всяких Atmega 328P и ESP SDK.
 

enjoynering

Well-known member
вот вам еще одна полезность. вставляется после установления связи

Код:
  if (WiFi.getAutoConnect() != true) WiFi.setAutoConnect(true);  //on power-on automatically connects to last used hwAP
  WiFi.setAutoReconnect(true);                     //automatically reconnects to hwAP in case it is disconnected
 
  • Like
Реакции: CCat
Сверху Снизу