Connect to wifi with Task ESP32-FreeRTOS

Hi,
I have 2 tasks.
Task1: Connects to MQTT
Task2: Connects to wifi if not connected. If disconnected then reconnect..at least thats what i want to do
Both Tasks same priorities but no connection can be made.. its something with vTaskDelay i gues..

void InternetConnectionCode( void * pvParameters ){
  for(;;){
    vTaskDelay(10);
    if(WiFi.status() != WL_CONNECTED){
    // We start by connecting to a WiFi network
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);
    WiFi.begin(ssid, password);
    //vTaskDelay(3000);
    while(WiFi.status() != WL_CONNECTED) {
      vTaskDelay(500);
      Serial.print(".");     
    }
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
  }
  } 
}
void MQTTConnectListenCode( void * pvParameters ){
  // Serial.print("Task1 running on core ");
  // Serial.println(xPortGetCoreID());
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);  
  for(;;){
     if (!client.connected()) {
       // Loop until we're reconnected
         while (!client.connected()) {
         Serial.print("Attempting MQTT connection...");
     // Create a random client ID
          String clientId = "myuser1";
    //clientId += String(random(0xffff), HEX);
    // Attempt to connect
           if (client.connect(clientId.c_str(),MQTT_USER,MQTT_PASSWORD)) {
               Serial.println("connected");
               vTaskDelay(1000);
      //Once connected, publish an announcement...
     //client.publish("alarm/myuser1", "hello world");
      // ... and resubscribe
               client.subscribe(MQTT_SERIAL_RECEIVER_CH,1);
    } else {
               Serial.print("failed, rc=");
               Serial.print(client.state());
               Serial.println(" try again in 5 seconds");
      
               vTaskDelay(5000);
    }
  }
       }
       else{
        client.loop();
       }    
       }
  }

Why i cannot connect to wifi? Basically both tasks "work" but connection to wifi cannot be done.. after few resets SOMETIMES it connects..

What do the debug prints show? What happens if you try to connect in the setup() function before starting task scheduler?

gfvalvo:
What do the debug prints show? What happens if you try to connect in the setup() function before starting task scheduler?

Im not getting any errors..But just prints ...... (because of vTaskDelay(500); Serial.print(".");
But no connection..
few .... and then mqtt tries to connect unsucessfully and then again ..... and again mqtt etc

gfvalvo:
What do the debug prints show? What happens if you try to connect in the setup() function before starting task scheduler?

it works like a charm in the setup() but i want it in a task to check if disconnected->connect

1 Like
#include <WiFi.h>
#include <PubSubClient.h>
#include "certs.h"
#include "sdkconfig.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
////
Adafruit_BME280 bme280( GPIO_NUM_5 ); // hardware SPI
////
WiFiClient   wifiClient;
PubSubClient MQTTclient( mqtt_server, mqtt_port, wifiClient );
////
SemaphoreHandle_t sema_MQTT_KeepAlive;
////
byte mac[6];
////
void setup()
{
  sema_MQTT_KeepAlive   = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
  ////
  SPI.begin();
  bme280.begin();
  xTaskCreatePinnedToCore( MQTTkeepalive, "MQTTkeepalive", 20000, NULL, 3, NULL, 1 );
  xTaskCreatePinnedToCore( DoTheBME280Thing, "DoTheBME280Thing", 20000, NULL, 4, NULL, 1);
} //void setup()
//
void DoTheBME280Thing( void *pvParameters )
{
  float temperature = 0.0f;
  float pressure    = 0.0f;
  float humidity    = 0.0f;
  //wait for a mqtt connection
  while ( !MQTTclient.connected() )
  {
    vTaskDelay( 250 );
  }
  for (;;)
  {
    temperature = ( 1.8f * bme280.readTemperature() ) +32.0f;
    pressure    = bme280.readPressure() / 133.3223684f; // mmHg
    humidity    = bme280.readHumidity();
    log_i( " temperature %f, Pressure %f, Humidity %f", temperature, pressure, humidity);
    xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
    if ( MQTTclient.connected() )
    {
      MQTTclient.publish( topicInsideTemp, String(temperature).c_str() );
      vTaskDelay( 2 ); // gives the Raspberry Pi 4 time to receive the message and process
      MQTTclient.publish( topicInsideHumidity, String(humidity).c_str() );
      vTaskDelay( 2 ); // no delay and RPi is still processing previous message
      MQTTclient.publish( topicInsidePressure, String(pressure).c_str() );
    }
    xSemaphoreGive( sema_MQTT_KeepAlive );
    vTaskDelay( 1000 * 15 );
    log_i( "DoTheBME280Thing high watermark %d",  uxTaskGetStackHighWaterMark( NULL ) );
  }
  vTaskDelete ( NULL );
}
////
/*
    Important to not set vTaskDelay to less then 10. Errors begin to develop with the MQTT and network connection.
    makes the initial wifi/mqtt connection and works to keeps those connections open.
*/
void MQTTkeepalive( void *pvParameters )
{
  // setting must be set before a mqtt connection is made
  MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
  for (;;)
  {
    //check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
    if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
    {
      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles MQTTlient.loop() is running no other mqtt operations should be in process
      MQTTclient.loop();
      xSemaphoreGive( sema_MQTT_KeepAlive );
    }
    else {
      log_i( "MQTT keep alive found MQTT status %s WiFi status %s", String(wifiClient.connected()), String(WiFi.status()) );
      if ( !(WiFi.status() == WL_CONNECTED) )
      {
        connectToWiFi();
      }
      connectToMQTT();
    }
    vTaskDelay( 250 ); //task runs approx every 250 mS
  }
  vTaskDelete ( NULL );
}
////
void connectToMQTT()
{
  // create client ID from mac address
  String clientID = String(mac[0]) + String(mac[5]) ;
  log_i( "connect to mqtt as client %s", clientID );
  while ( !MQTTclient.connected() )
  {
    MQTTclient.connect( clientID.c_str(), mqtt_username, mqtt_password );
    log_i( "connecting to MQTT" );
    vTaskDelay( 250 );
  }
  log_i("MQTT Connected");
}
//
void connectToWiFi()
{
  log_i( "connect to wifi" );
  while ( WiFi.status() != WL_CONNECTED )
  {
    WiFi.disconnect();
    WiFi.begin( SSID, PASSWORD );
    log_i(" waiting on wifi connection" );
    vTaskDelay( 4000 );
  }
  log_i( "Connected to WiFi" );
  WiFi.macAddress(mac);
  log_i( "mac address %d.%d.%d.%d.%d", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]  );
  WiFi.onEvent( WiFiEvent );
}
////
void WiFiEvent(WiFiEvent_t event)
{
  switch (event) {
    case SYSTEM_EVENT_STA_CONNECTED:
      log_i("Connected to access point");
      break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
      log_i("Disconnected from WiFi access point");
      break;
    case SYSTEM_EVENT_AP_STADISCONNECTED:
      log_i("WiFi client disconnected");
      break;
    default: break;
  }
}
////
void loop() { }

It appears that none of these #includes are required to compile in the Arduino IDE. Is the functionality they provide not used in this code? Or, are they included automatically by the IDE and thus #including them is the sketch is superfluous?

//#include "sdkconfig.h"
//#include "esp_system.h"
//#include "freertos/FreeRTOS.h"
//#include "freertos/task.h"
//#include "freertos/timers.h"
//#include "freertos/event_groups.h"

I had noticed the timer was not used and removed it from my code, after making the post.

The rest of the libraries loaded are being used.

Thanks for the code. I will implant yours in my project.
And thanks gfvalvo also for your time.

Idahowalker:
The rest of the libraries loaded are being used.

Interesting. As I said, it compiles without the #include(s). Although, I didn't try running it.

BTW, I did try using log_i(), but got no output on the serial monitor. What prerequisite code in setup() is required to send log_i() to Serial?

gfvalvo:
Interesting. As I said, it compiles without the #include(s). Although, I didn’t try running it.

BTW, I did try using log_i(), but got no output on the serial monitor. What prerequisite code in setup() is required to send log_i() to Serial?

#include “sdkconfig.h”

Set debug level to debug or info

No joy. "Starting" prints, "Hello World" doesn't:

#include "sdkconfig.h"

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("Starting");
  esp_log_level_set("*", ESP_LOG_DEBUG);
  log_i("Hello World");
}

void loop() {
}

or #include "esp_system.h"

One is for the ESP32 esq names; like GPIO_NUM_5, and the other for a few other things including log_n, log_i, log_d, and log_v.

Nope. Is there an actual answer? Arduino IDE 1.8.12, ESP32 1.0.4:

#include "esp_system.h"

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("Starting");
  esp_log_level_set("*", ESP_LOG_DEBUG);
  log_i("Hello World");
}

void loop() {
}
ets Jun  8 2016 00:22:57

rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:8896
load:0x40080400,len:5816
entry 0x400806ac
Starting

And don't forget to make your proper Tools | Core Debug Level.

ESP32 API Logging Library Logging library - ESP32 - — ESP-IDF Programming Guide latest documentation

Actually, I think the problem is here, from esp32-hal-log.h

#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
#define log_i(format, ...) log_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__)
#define isr_log_i(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__)
#else
#define log_i(format, ...)
#define isr_log_i(format, ...)
#endif

ARDUHAL_LOG_LEVEL is not high enough and the condition is defaulting log_i() to nothing. ARDUHAL_LOG_LEVEL is defined in the same file:

#define ARDUHAL_LOG_LEVEL CORE_DEBUG_LEVEL

and CORE_DEBUG_LEVEL appears to be set by a compiler flag in platform.txt:

build.extra_flags=-DESP32 -DCORE_DEBUG_LEVEL={build.code_debug} {build.defines}

Will need to dig into it more.

So, this issue appears to be 3 years old with no solution: esp32-hal-log.h macros not usable by default · Issue #893 · espressif/arduino-esp32 · GitHub. So, it's somewhat of a mystery how @Idahowalker got it to work.

EDIT:
Dooohhhh.... Forgive my rant.

Yupper, like I been posting there is a need to properly set the core debug level.