Выполнение void loop() без подключения к wifi и mqtt

Здравствуйте. Делаю для себя устройство для умного дома (защита от протечки водоснабжения) на базе esp32.
Используется wifi и mqtt.
Проблема заключается в том, что если пропадет wifi соединение или подключение к mqtt брокеру, то скетч прервется и будет пытаться реконектиться. То есть не будут опрашиваться датчики и управляться сервоприводы на кранах.
Прошу помощи в переделки скетча таким образом, чтобы и датчики опрашивались и подключение и к wifi и к mqtt продолжало выполняться.
Много лет назад уже делал себе такое устройство и проблема была та же, но я, постеснявшись спросить решение у людей в интернете, просто использовал в связке arduino nano и esp8266. За опрос датчиков и управление кранами отвечала ардуино, а данные в mqtt отправляла esp8266.
Сейчас в новое место жительства нужно еще одно устройство, и хотел реализовать уже на одной esp32.
Хочется именно квалифицированной помощи, чтобы максимально исключить программные баги в таком ответственном устройстве.

#include <WiFi.h>
#include <PubSubClient.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

const char* ssid = "mywifirouter";
const char* password = "12345678";
const char* mqttServer = "192.168.100.4";
const int mqttPort = 1883;
const char* mqttUser = "user";
const char* mqttPassword = "password";

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {

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

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

  Serial.println("Connected to the WiFi network");

  client.setServer(mqttServer, mqttPort);

  while (!client.connected()) {
    Serial.println("Connecting to MQTT...");

    if (client.connect("ESP32Client", mqttUser, mqttPassword)) {

      Serial.println("connected");

    } else {
      Serial.print("failed with state ");
      Serial.print(client.state());
      delay(2000);
    }
  }
  ArduinoOTA.setHostname("esp32_MQTT_Test");
  ArduinoOTA
    .onStart([]() {
      String type;
      if (ArduinoOTA.getCommand() == U_FLASH)
        type = "sketch";
      else  // U_SPIFFS
        type = "filesystem";

      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });

  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  client.publish("esp32/esp32test", "Hello from Alex");
}

void loop() {
  ArduinoOTA.handle();
  client.loop();
  //далее мой код (опрос датчиков и т.п.)
}

Перенести тему в “Ищу исполнителя”?

ESP32 + Arduino Core + FreeRTOS + Blynk = дом с зачатками разума / Хабр → Про FreeRTOS таски

Если Садмана не понял то чуть подробнее:

#include <Что-то там>

MyGlobal myLovelyGlobalVariable;

void setup() {

// всякая служебная фигня про сеть
//...

xTaskCreate(
      myTask,
      "The name for my task",
      4096, //размер стека для моей задачи
      NULL, //тебе не надо
      1,       // приоритет, тебе не нужно
      NULL //снова забей, тебе не нужно
      );
}

void myTask(void * p) {
//вот тут пишешь всю свою работу с датчиками, регуляторами 
//и внутрижопными жужжателями

//***то что выполнится ОДИН раз - как setup
//int i,j,k; // твои переменные всякие
// например
const int myLED = LED_BUILTIN;
pinMode(myLED, OUTPUT);

for(;;) {
//а вот тут всё, что хотел написать в loop() ;)
digitalWrite(myLED, !digitalRead(myLED));
    delay(1000); 
//О да! Тут можно использовать делеи сколько угодно. 
//другой поток (Task) никак от них не зависит. 
//Этих самых потоков можешь писать сколько угодно, 
// у меня обычно не один десяток. Просто помни, что каждый "тик" по умолчанию 1 мс. 
// если не знаешь, что такое системный "тик" не напрягайся, значит тебе это еще не нужно
}

}

void loop() {
// вот тут твоего кода НЕ НУЖНО, только системные и сетевые вещи
}
  1. Я правильно понимаю, это какое-то подобие многозадачности?
    То есть я могу разбить скетч на несколько задач: одна будет постоянно следить за сетевым соединением и переподключаться, а другая задача будет опрашивать датчики и в случаи тревоги закрыть краны?
  2. Почему переменные и pinModы назначаются внутри таски, а не перед void setup() и не в самом void setup()?

Почему подобие? Нормальный мультитаскинг на RTOS.

Потому что а) область видимости и b) никто не мешает заглобалить.

В выключателях света на ESP8266, в loop(), я оставлял только всю работу с Wi-Fi и mqtt.
Всю обработку событий, включение и выключение реле перенесены в Ticker.
Так же и со счетчиками воды.

В таком виде, пропадание Wi-Fi, в принципе никак не ощущается.

  1. “Подобие”??? FreeRTOS совершенно нормальная многозадачная ОС. Если привык к pthread, то эта библиотека тоже есть под FreeRTOS. Можешь ей пользоваться. Можно таксами системными - как нравится, так и делай, как привык.
    Да!!! Так и положено писать подобные вещи. Для этого и нужна ОС. Делать разные задачи в РАЗНЫХ потоках управления, не мешая друг другу. “Не мона, а нуна!” (с). :wink:
  2. Да как хочешь. Это же пример. “Иллюстрация” - знаешь такое слово? ;))

==
ЗЫ: Пипец! Создание Ардуино понизило порог вхождения в эмбеддинг-программирование просто ниже плинтуса! Популяризация - хорошо, но откуда берутся люди, которые НЕ ЗНАЮТ ВООБЩЕ НИЧЕГО? Зачем им нужна Ардуинка, чОрт побери?!

Извиняюсь за свою неграмотность в программировании, я инженер строитель, и вообще далеко не программист, поэтому и задаю вопросы на профильном форуме.
Просто я думал форум для того и нужен чтобы незнающие люди задавали вопросы, а знающие, по возможности, на них отвечали.

Я установил библиотеку. Пытаюсь скомпилировать хоть какой-нибудь скетч из примеров библиотеки и полный экран ошибок. Ошибки появляются, если выбирать плату esp32 или esp8266. На платах ардуины ошибки не вылазят.

In file included from C:\Users\Alexandr\AppData\Local\Temp.arduinoIDE-unsaved202316-11148-1rfsq7n.7zc6\AnalogRead_DigitalRead\AnalogRead_DigitalRead.ino:1:
c:\Users\Alexandr\Documents\Arduino\libraries\FreeRTOS\src/Arduino_FreeRTOS.h:133:10: error: #error INCLUDE_vTaskDelayUntil and INCLUDE_xTaskDelayUntil are both defined. INCLUDE_vTaskDelayUntil is no longer required and should be removed
#error INCLUDE_vTaskDelayUntil and INCLUDE_xTaskDelayUntil are both defined. INCLUDE_vTaskDelayUntil is no longer required and should be removed
^~~~~
In file included from c:\Users\Alexandr\Documents\Arduino\libraries\FreeRTOS\src/Arduino_FreeRTOS.h:1365,
from C:\Users\Alexandr\AppData\Local\Temp.arduinoIDE-unsaved202316-11148-1rfsq7n.7zc6\AnalogRead_DigitalRead\AnalogRead_DigitalRead.ino:1:
c:\Users\Alexandr\Documents\Arduino\libraries\FreeRTOS\src/FreeRTOSVariant.h:33:10: fatal error: avr/io.h: No such file or directory
#include <avr/io.h>
^~~~~~~~~~
compilation terminated.

exit status 1

Compilation error: exit status 1

Вы ошиблись, форум нужен не для этого.

Я Вам, ещё в самом первом в этой теме ответе, предложил перенести тему в раздел, где люди берутся делать работу за деньги. Вы проигнорировали. Напрасно. Поскольку Вы

это для Вас реальный вариант сделать Вашу хотелку.

Ну, или есть ещё вариант стать “далеко программистом”, но это потребует пары лет. Если Вы готовы - приступайте.

Так, как, переносить тему в платный раздел?

Зочем avr мешать с esp?

#include <esp_log.h>

#define LOG_TAG "Task tester"

const uint32_t reportInterval  = 3000;


inline TickType_t msToTick(uint32_t _ms) {
  return (_ms / portTICK_RATE_MS);
}

void reportStatistic(void* _pvParameters) {
  uint32_t reportInterval = msToTick(*((uint32_t*) _pvParameters));

  for (;;) {
    ESP_LOGI(LOG_TAG, "All need code here");
    // ....
    vTaskDelay(reportInterval);
  }
}

void setup() {
  Serial.begin(115200);
  xTaskCreate(reportStatistic, "reportStatistic", 2048, (void*) &reportInterval, 1, NULL);
)

void loop() { }

ой не верьте, Петрович и мне обещал, что за два года стану программистом, уж седьмой годик здесь, а программистом так и не стал )))

И зачем? Когда хобби - гончарный круг, все понимают, что ДО задания вопросов нужно учиться. Если хобби - программирования, то нужно прийти на форум и спрашивать полную херню!
Нормально, чё? 3.14здец какой-то!!!

Нужно, млеать, учится программированию!

Еще раз от новичка увижу слово “вылазят” - буду настаивать на бане для идиота. Я почти уверен, что администрация меня поддержит.

ЗЫ: Сделал сообщение Вики-записью. Кто согласен - подпишитесь!

1 лайк

sadman41, заменил #include <Arduino_FreeRTOS.h>, на #include <esp_log.h> и все заработало. Спасибо большое, буду изучать дальше.

Так, как, переносить тему в платный раздел?

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

WladDrakula, вы такой смешной =)
Таких лютых ЧСВшников последний раз встречал году в 2008.
Написал аж 2 сообщения подряд оффтопом, да еще и с оскорблениями.
Хорошо, что на форуме есть люди лучше вас.

p.s. Несколько лет изучал homeassistant, и привык к англоязычной аудитории, которой важно поддержать, а не унизить.

Да, как бэ, и по ардуино дохрена англоязычных форумов. Здесь что, медом помазано?

Что делать то будете, если ваш любимый изученный асистанс в один прекрасный момент рубанут на Россию наши западные “друзья”? Надо уже со своими облаками начинать работать плотнее. Не?

Это вместо простого “спасибо” за подробные объяснения? Вполне ожидаемо…

Среди офицеров СССР была присказка: “Куда солдата ни целуй - у него везде жопа!”. Это касается многих, не только солдат.

ТС просто не понял какую ты ему замечательную вещь как пример выложил…
Сей предмет не входит в круг его понятий
ЗЫ и заметь безвозмезно…

Удачи!