• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Вопрос Переподключение к wifi

YDen

Member
Здравствуйте.
Подскажите пожалуйста. Стоит задача сделать переподключение ЕСП при обрыве связи. Такой код решит эту задачу:
Код:
void setup_wifi()
{
  // We start by connecting to a WiFi network
  // Удаляем предыдущие конфигурации WIFI сети
  WiFi.disconnect(); // обрываем WIFI соединения
  WiFi.softAPdisconnect(); // отключаем отчку доступа(если она была
  WiFi.mode(WIFI_OFF); // отключаем WIFI
  delay(500);

  // присваиваем статичесий IP адрес
  WiFi.mode(WIFI_STA); // режим клиента
  WiFi.config(IPAddress(192, 168, 1, 73), IPAddress(192, 168, 1, 1), IPAddress(255, 255, 255, 0), IPAddress(192, 168, 1, 1));

  delay(10);
  WiFi.begin(ssid, password);
}
Вызов в loop:
Код:
if (WiFi.status() == WL_CONNECTED)
     {
    //код
      }
  else
  {
    //запуск подключения wifi
    if (currentMillis_wifi - previousMillis_wifi >= interval_wifi)
    {
      previousMillis_wifi = currentMillis_wifi;
      setup_wifi();
    }

  }
благодарю
 

YDen

Member
что мешает проверь это самому?
Этот код у меня работает, правда всего пару дней. Пока траблов не заметил. Ранее постоянно "терялись" ЕСП.
Интересна оптимизация кода.
Стоит ли заново инициализировать соединение с указанием ip, удалять информацию о сетях?
Этот код не лишний?
Код:
// Удаляем предыдущие конфигурации WIFI сети
  WiFi.disconnect(); // обрываем WIFI соединения
  WiFi.softAPdisconnect(); // отключаем отчку доступа(если она была
  WiFi.mode(WIFI_OFF); // отключаем WIFI
  delay(500);
  // присваиваем статичесий IP адрес
  WiFi.mode(WIFI_STA); // режим клиента
  WiFi.config(IPAddress(192, 168, 1, 73), IPAddress(192, 168, 1, 1), IPAddress(255, 255, 255, 0), IPAddress(192, 168, 1, 1));
благодарю
 

enjoynering

Well-known member
зачем изобретать велосипед. все уже есть в arduino core

Код:
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
 

enjoynering

Well-known member
Код:
WiFi.softAPdisconnect(); // отключаем отчку доступа(если она была
WiFi.mode(WIFI_OFF); // отключаем WIFI
WiFi.softAPdisconnect(false) - не выключает передатчик, тупо обрывает связь c клиентами путем установления пароля и юзера в NULL. а вот WiFi.softAPdisconnect(true) вызывает WiFi.enableAP(false) которая красиво вызывает WiFi.mode() и отключает AP на совсем.

WiFi.softAPdisconnect(false) достаточно для безглючной смены паролей, ip и тд. То есть не надо дополнительно выключать передатчик командой WiFi.mode(WIFI_OFF).

Уж если хотите временно выключить wifi то делайте так:
Код:
if (WiFi.getPersistent() == true) WiFi.persistent(false);   //disable saving wifi config into SDK flash area
WiFi.mode(WIFI_OFF); // отключаем WIFI
WiFi.persistent(true);   //enable saving wifi config into SDK flash area
перед временным WiFi.softAPdisconnect() тоже надо делать так:
Код:
if (WiFi.getPersistent() == true) WiFi.persistent(false);   //disable saving wifi config into SDK flash area
WiFi.softAPdisconnect(false); //setting ssid/pass to null
WiFi.persistent(true);   //enable saving wifi config into SDK flash area
иначе дырку во флешке протрете
 
Последнее редактирование:

enjoynering

Well-known member
Благодарю.
Эти две строки в сетап поставить?

вас в гугле забанили? один из первых запросов поиске выдал это

* @brief Set whether the ESP8266 station will connect to the recorded AP
* automatically when the power is on. It will do so by default.
*
* @attention 1. If this API is called in user_init, it is effective immediately
* after the power is on. If it is called in other places, it will
* be effective the next time when the power is on.
* @attention 2. This configuration will be saved in Flash system parameter area if changed.

*
* @param bool set : If it will automatically connect to the AP when the power is on
* - true : it will connect automatically
* - false: it will not connect automatically
ну и так как происходит постоянная запись этих параметров во flash при их вызове, то лучше вызывать так

Код:
if (WiFi.getAutoConnect() != true)    //configuration will be saved into SDK flash area
{
  WiFi.setAutoConnect(true);   //on power-on automatically connects to last used hwAP
  WiFi.setAutoReconnect(true);    //automatically reconnects to hwAP in case it's disconnected
}
 
Последнее редактирование:

enjoynering

Well-known member
ну и еще не надо вызывать WiFi.mode(WIFI_STA) перед WiFi.begin(ssid, password).

WiFi.begin(ssid, password) в своем теле вызывает WiFi.enableSTA(true) которая красиво вызывает WiFi.mode(WIFI_STA).

тоже самое с точкой доступа - не надо вызывать WiFi.WiFi.enableAP(true) перед WiFi.softAP(ssid, password).

в WiFi.softAP(ssid, password) все уже есть!!!
 

YDen

Member
вас в гугле забанили? один из первых запросов поиске выдал это



ну и так как происходит постоянная запись этих параметров во flash при их вызове, то лучше вызывать так

Код:
if (WiFi.getAutoConnect() != true)    //configuration will be saved into SDK flash area
{
  WiFi.setAutoConnect(true);   //on power-on automatically connects to last used hwAP
  WiFi.setAutoReconnect(true);    //automatically reconnects to hwAP in case it's disconnected
}
Т.е в сетапе?
 

pvvx

Активный участник сообщества
ну и так как происходит постоянная запись этих параметров во flash при их вызове, то лучше вызывать так
Интересно, а почему происходит постоянная запись параметров, когда это дополнительное действие и любой стандартный пример Arduino начинается с установок режимов WiFi?
Т.е. функции по настройке WiFi у ESP8266 не соответствует базовым стандартам Arduino?
Каков смысл этой встроенной функциональности по сохранению настроек, если она нигде не используется и её надо отлючать?
В чем красота когда существуют параметры по умолчанию, которых вы не знаете, т.к. они берутся из ранее сохраненных от какой-то сессии работы с WiFi?
Всё это похоже введено для усложнения, а не красоты...
Причина разнообразия примеров по настройке WiFi строиться из описанного выше и последующих исправлений в SDK Espressif, с попыткой оставить совместимость с более старыми вариантами кода. Т.е. теперь, в текущей версии, требуются дополнительные костыли для привода кода к базовому варианту функционирования в среде Arduino. В следующей версии это может быть заменено и удалено.
Викопедия и Гугл этого не описывает и посылка туда не даст правильных ответов.

Вам как пример:
WiFi.begin() без параметров должно включать WiFi, после чего должны быть доступны функции сканирования сети без организации какой-либо точки доступа или станции.
В ESP8266 вы лишены этой функциональности.
 
Последнее редактирование:

enjoynering

Well-known member
вы скорее всего правы. весь этот зоопарк из вызова одной функциии через другую с дублированием самих себя очень похоже на костыль-совместимости с предудущими версиями arduino esp8266 core. Надо отдать должное, они вняли вашей критике и теперь перед сохранием пароля и ssid проверяют его с сохраненным на флешке и не перезаписывают зря. ну и для самых продвинутых внедрили запрет на запись путем вызова функции WiFi.persistent(false). вот пример WiFi.begin(ssid, password) для запуска клиента:

Код:
wl_status_t ESP8266WiFiSTAClass::begin(const char* ssid, const char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) {

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

    if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) {
        // fail SSID too long or missing!
        return WL_CONNECT_FAILED;
    }

    if(passphrase && strlen(passphrase) > 64) {
        // fail passphrase too long!
        return WL_CONNECT_FAILED;
    }

    struct station_config conf;
    strcpy(reinterpret_cast<char*>(conf.ssid), ssid);

    if(passphrase) {
        if (strlen(passphrase) == 64) // it's not a passphrase, is the PSK, which is copied into conf.password without null term
            memcpy(reinterpret_cast<char*>(conf.password), passphrase, 64);
        else
            strcpy(reinterpret_cast<char*>(conf.password), passphrase);
    } else {
        *conf.password = 0;
    }

    if(bssid) {
        conf.bssid_set = 1;
        memcpy((void *) &conf.bssid[0], (void *) bssid, 6);
    } else {
        conf.bssid_set = 0;
    }

    struct station_config current_conf;
    wifi_station_get_config(&current_conf);
    if(sta_config_equal(current_conf, conf)) {
        DEBUGV("sta config unchanged");
    }
    else {
        ETS_UART_INTR_DISABLE();

        if(WiFi._persistent) {
            // workaround for #1997: make sure the value of ap_number is updated and written to flash
            // to be removed after SDK update
            wifi_station_ap_number_set(2);
            wifi_station_ap_number_set(1);

            wifi_station_set_config(&conf);
        } else {
            wifi_station_set_config_current(&conf);
        }

        ETS_UART_INTR_ENABLE();
    }

    ETS_UART_INTR_DISABLE();
    if(connect) {
        wifi_station_connect();
    }
    ETS_UART_INTR_ENABLE();

    if(channel > 0 && channel <= 13) {
        wifi_set_channel(channel);
    }

    if(!_useStaticIp) {
        wifi_station_dhcpc_start();
    }

    return status();
}
полный код находится по адресу - Arduino/ESP8266WiFiSTA.cpp at master · esp8266/Arduino · GitHub
чтоб до конца понять, надо еще заглядывать сюда - Arduino/ESP8266WiFiGeneric.cpp at master · esp8266/Arduino · GitHub
 
Последнее редактирование:

pvvx

Активный участник сообщества
вы скорее всего правы. весь этот зоопарк из вызова одной функциии через другую с дублированием самих себя очень похоже на костыль-совместимости с предудущими версиями arduino esp8266 core.
Причину зоопарка я не разглашал :)
Она повязана на начальной реализации deep_sleep - чтобы ускорить подключение после просыпания.
В SDK ещё много чего зависит от начальных принятых алгоритмов, написанных кое-как и без обдумывания. Теперь исправляют, что для совместимости требует дополнительных ресурсов (страдает размер кода и скорость исполнения).
Отдельные дублирующие функции установок WiFi без записи в SDK появились вроде с 1.2 версии... До "Arduino" это дошло только в последних редакциях.
С версиями SDK, включая 2.0, с которыми пытался что-то слепить так не нашлось вариантов для установки всех необходимых параметров к WiFi не использующих функцию сохранения параметров во Flash, на что уходит много время - стирание сектора + запись его с невозможностью в это время работы кода из Flash.
SDK для ESP8266 составлено безграмотно, что накладывает многие ограничения. В ESP-32, уже год исправляют эту ситуацию в ESP-IDF.
Основа всего этого – закрытый код SDK без отделения драйвера WiFi. Только на него пока не принято давать исходники в общий доступ, и то это действие вызвано “другие не дают, и мы не будем” и никакими более вариантами.
 
Последнее редактирование:

enjoynering

Well-known member
теперь понятно, спасибо. для мня очень странно почему при вызове функции WiFi.mode() они не делают проверку конфига на флешке? тут спасение только в вызове WiFi.persistent(false) иначе после каждого изменения будет перезаписываться конфиг и лет через 5 флешке настанет каюк. спасибо хоть проверку на совпадение с текущим знвчением сделали.

Код:
bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) {
    if(wifi_get_opmode() == (uint8) m) {
        return true;
    }

    bool ret = false;

    ETS_UART_INTR_DISABLE();
    if(_persistent) {
        ret = wifi_set_opmode(m);
    } else {
        ret = wifi_set_opmode_current(m);
    }
    ETS_UART_INTR_ENABLE();

    return ret;
}
 

pvvx

Активный участник сообщества
теперь понятно, спасибо. для мня очень странно почему при вызове функции WiFi.mode() они не делают проверку конфига на флешке? тут спасение только в вызове WiFi.persistent(false) иначе после каждого изменения будет перезаписываться конфиг и лет через 5 флешке настанет каюк. спасибо хоть проверку на совпадение с текущим знвчением сделали.

Код:
bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) {
    if(wifi_get_opmode() == (uint8) m) {
        return true;
    }

    bool ret = false;

    ETS_UART_INTR_DISABLE();
    if(_persistent) {
        ret = wifi_set_opmode(m);
    } else {
        ret = wifi_set_opmode_current(m);
    }
    ETS_UART_INTR_ENABLE();

    return ret;
}
wifi_get_opmode() - это функция, вызывающая другую функцию (назовем _get_opmode) с параметром _get_opmode(1)
wifi_get_opmode_default() - это функция, вызывающая другую функцию с параметром _get_opmode(0)
_get_opmode() в зависимости от параметра:
0) выделяет в heap 1172 байта (размер блока параметров WiFi для SDK2.0), и вызывает считывание в полученный блок памяти (system_param_load()) области сохранения во Flash, считывает из полученного блока один байт, освобождает блок в heap. :)
1) обращается к структуре wifi_store, считывает и выдает из неё байт номера режима.

Драйвер WiFi, обычно, может может работать в разных режимах. Т.к. у нас два основных типа - AP и STA, то драйвер WiFi делиться на два типа работы. Т.е. фактически при AP+STA загружены и включены два драйвера. Проверить какой драйвер и в каком режиме сейчас активен по данным из flash не выйдет, если установка его произошла без сохранения параметров во flash.

wifi_set_opmode(x) - это тоже функция, с вызывающая другую _set_opmode(x, 1)
wifi_set_opmode_current(x) - это тоже функция, с вызывающая другую _set_opmode(x, 0)

_set_opmode(x, flag) примерно то-же самое - в зависимости от flag вызывает считывание из flash (system_param_load(...), system_param_save_with_protect(...) ) структуры wifi_store[1172] с запросом размещения в heap pvPortMalloc(1172, id функции для отладки)....
Миллион ненужных действий и диких китайских алгоритмов... Описывать даже не охота... :)

Что примечательного в этом всём:
system_param_save_with_protect() вызывает wifi_param_save_protect_with_check() в которой
pvPortZalloc(), (#) spi_flash_erase_sector(), spi_flash_write(), spi_flash_read(), ets_memcmp() и если не равно - возврат к началу стирания и записи (#) без какого либо счета неудач, в конце - vPortFree().

Если у вас упало или плавает питание, то процесс стирания и записи происходит до победного конца - дыры в Flash.
Первые варианты SDK у Espressif писал какой-то школьник, не проходивший программ обучения программированию (наверно денег у Espressif не было нанять проф.программиста). К версии SDK2.0 осталось 40% его алгоритмов. Остальные, более ужасные, были исправлены. Но множество "фич" так и осталось... К примеру SDK собирается только с выключенными всеми wraning у компилятора. Иначе образуется большой список ошибок по поводу не проинициализированных переменных, неверных вызовов пр параметрам функций и т.д. По этому от версии к версии разные баги в SDK и потом выдают новые патчи (назвав это оптимаза :) ). Так-же был прикол - на вопрос что была за ошибка и почему патч, программист ответил - пересобрал заново либы и оно исправилось... :)
На таком материале и сделана Arduino на ESP8266 другими, в основном энтузиастами... Ну и никогда не получите исходников SDK - это будет шоу.
По этому когда указываете какой код - надо приводить номер версии SDK и патчей.
 
Последнее редактирование:

nikolz

Well-known member
теперь понятно, спасибо. для мня очень странно почему при вызове функции WiFi.mode() они не делают проверку конфига на флешке? тут спасение только в вызове WiFi.persistent(false) иначе после каждого изменения будет перезаписываться конфиг и лет через 5 флешке настанет каюк. спасибо хоть проверку на совпадение с текущим знвчением сделали.
никто не мешает добавить проверку на Си например так :
Код:
//-----------------------это фрагмент из рабочей программы ---------------------
if (wifi_get_opmode()!=STATION_MODE) wifi_set_opmode(STATION_MODE);
if(wifi_get_phy_mode() != PHY_MODE_11N)    wifi_set_phy_mode(PHY_MODE_11N);
if (wifi_station_get_auto_connect()==0)    wifi_station_set_auto_connect(1);
    uint8 e1=strcmp(stationConf.ssid,_SSID);
    uint8 e2=strcmp(stationConf.password,_PASSWORD);
    if (e1!=0 ||e2!=0){
          os_bzero(&stationConf,sizeof(struct station_config));
        ets_strcpy(stationConf.ssid,_SSID);
        ets_strcpy(stationConf.password,_PASSWORD);
          wifi_station_set_config(&stationConf);
        wifi_station_set_reconnect_policy(true);
}
 

pvvx

Активный участник сообщества
никто не мешает добавить проверку на Си например так :
Код:
//-----------------------это фрагмент из рабочей программы ---------------------
if (wifi_get_opmode()!=STATION_MODE) wifi_set_opmode(STATION_MODE);
if(wifi_get_phy_mode() != PHY_MODE_11N)    wifi_set_phy_mode(PHY_MODE_11N);
if (wifi_station_get_auto_connect()==0)    wifi_station_set_auto_connect(1);
    uint8 e1=strcmp(stationConf.ssid,_SSID);
    uint8 e2=strcmp(stationConf.password,_PASSWORD);
    if (e1!=0 ||e2!=0){
          os_bzero(&stationConf,sizeof(struct station_config));
        ets_strcpy(stationConf.ssid,_SSID);
        ets_strcpy(stationConf.password,_PASSWORD);
          wifi_station_set_config(&stationConf);
        wifi_station_set_reconnect_policy(true);
}
Никто не мешает поставить 16МБайт Flash, но XIP ограничен 1МБ и туда уже не лезет "оптимаза" от китайцев.
Так-же вам только 'никто' мешает поставить psRAM и копировать в неё Flash при старте или указать компилятору заменить вызов обращения к функциям записи-чтения flash на свои и вставить там проверку на запись одного и того-же, но при каждом соединении в этих 1172 байтах что-то изменяется...
Но все эти костыли не исправят ровным счетом ничего.
 

Aleksandr_Sam

New member
вы скорее всего правы. весь этот зоопарк из вызова одной функциии через другую с дублированием самих себя очень похоже на костыль-совместимости с предудущими версиями arduino esp8266 core. Надо отдать должное, они вняли вашей критике и теперь перед сохранием пароля и ssid проверяют его с сохраненным на флешке и не перезаписывают зря. ну и для самых продвинутых внедрили запрет на запись путем вызова функции WiFi.persistent(false). вот пример WiFi.begin(ssid, password) для запуска клиента:

Код:
wl_status_t ESP8266WiFiSTAClass::begin(const char* ssid, const char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) {

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

    if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) {
        // fail SSID too long or missing!
        return WL_CONNECT_FAILED;
    }

    if(passphrase && strlen(passphrase) > 64) {
        // fail passphrase too long!
        return WL_CONNECT_FAILED;
    }

    struct station_config conf;
    strcpy(reinterpret_cast<char*>(conf.ssid), ssid);

    if(passphrase) {
        if (strlen(passphrase) == 64) // it's not a passphrase, is the PSK, which is copied into conf.password without null term
            memcpy(reinterpret_cast<char*>(conf.password), passphrase, 64);
        else
            strcpy(reinterpret_cast<char*>(conf.password), passphrase);
    } else {
        *conf.password = 0;
    }

    if(bssid) {
        conf.bssid_set = 1;
        memcpy((void *) &conf.bssid[0], (void *) bssid, 6);
    } else {
        conf.bssid_set = 0;
    }

    struct station_config current_conf;
    wifi_station_get_config(&current_conf);
    if(sta_config_equal(current_conf, conf)) {
        DEBUGV("sta config unchanged");
    }
    else {
        ETS_UART_INTR_DISABLE();

        if(WiFi._persistent) {
            // workaround for #1997: make sure the value of ap_number is updated and written to flash
            // to be removed after SDK update
            wifi_station_ap_number_set(2);
            wifi_station_ap_number_set(1);

            wifi_station_set_config(&conf);
        } else {
            wifi_station_set_config_current(&conf);
        }

        ETS_UART_INTR_ENABLE();
    }

    ETS_UART_INTR_DISABLE();
    if(connect) {
        wifi_station_connect();
    }
    ETS_UART_INTR_ENABLE();

    if(channel > 0 && channel <= 13) {
        wifi_set_channel(channel);
    }

    if(!_useStaticIp) {
        wifi_station_dhcpc_start();
    }

    return status();
}
полный код находится по адресу - Arduino/ESP8266WiFiSTA.cpp at master · esp8266/Arduino · GitHub
чтоб до конца понять, надо еще заглядывать сюда - Arduino/ESP8266WiFiGeneric.cpp at master · esp8266/Arduino · GitHub
Помогите разобраться.
Где можно найти тело метода "wifi_station_set_config" и "wifi_station_set_config_current"?
В репозитории я не нашел.

ESP8266WiFiSTA.cpp (esp8266/Arduino)
Код:
if(WiFi._persistent) {
    wifi_station_set_config(&conf);
} else {
    wifi_station_set_config_current(&conf);
}
 

Aleksandr_Sam

New member
Aleksandr_Sam, Aleksandr_Sam,
Помогите разобраться.
Где можно найти тело метода "wifi_station_set_config" и "wifi_station_set_config_current"?
В репозитории я не нашел.

ESP8266WiFiSTA.cpp (esp8266/Arduino)
Код:
if(WiFi._persistent) {
    wifi_station_set_config(&conf);
} else {
    wifi_station_set_config_current(&conf);
}
В этом документе?
https://www.espressif.com/sites/def...on/2c-esp8266_non_os_sdk_api_reference_en.pdf
 
Сверху Снизу