ESP32 FreeRTOS scheduling task with delays in days?

Hello everyone,

I'm a little bit lost on how I should schedule tasks that can delay long periods of time and still be accurate (a few seconds off is ok), imagine it toggles switch A every 2 days, or switch B every 5 days. What I'm not sure about is since ESP32 RTC clock is not that accurate, running it for months would certainly cause some inaccuracy. I guess I need a task to update the local time every once in a while with ntp time. However, I'm not sure how to get the time available for the tasks that are controlling the switch. What's the best way/practice to do this? I also heard that tasks that involved Wifi connections can crash the system if not careful, so is there anything I need to be aware of?

I'm new to RTOS, so I greatly appreciate any pointers. Thank you very much

The RTC can be configured to periodically sync to internet timer servers using NTP protocol.

Thank you very much! That's cool that it can do that. Does that means I can use vTaskDelay() for days on a task and the ESP32 will handle the timing, or should I do something else? I'm not too sure if there's a better way for this

Not sure. Maybe you could use vTaskDelayUntil() to get you close. Then when the task wakes up it could check the RTC and delay a little longer as needed.

That's a good idea, thank you!

You also make the task to capture time in unix forma, which is in seconds, and add the delay value to it and store it as wakeup time then make the task to periodically check time. if it has reached wakeup time then call functions or run commands.

I would use the ESP32's micro cycle count which can handle count in microseconds up to 207 years.

esp_timer_get_time(); is the macro call to get the time in uSeconds of the cycle count.I use xTaskGetTickCount(); to wake up the task on a regular basis to check the cycle count elapsed time.

void fDoMoistureDetector( void * parameter )
{
  //wait for a mqtt connection
  while ( !MQTTclient.connected() )
  {
    vTaskDelay( 250 );
  }
  int      TimeToPublish = 5000000; //5000000uS
  int      TimeForADreading = 100 * 1000; // 100mS
  uint64_t TimePastPublish = esp_timer_get_time(); // used by publish
  uint64_t TimeADreading   = esp_timer_get_time();
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 10; //delay for 10mS
  float    RemainingMoisture = 100.0f; //prevents pump turn on during start up
  bool     pumpOn = false;
  uint64_t PumpOnTime = esp_timer_get_time();
  int      PumpRunTime = 11000000;
  uint64_t PumpOffWait = esp_timer_get_time();
  uint64_t PumpOffWaitFor = 60000000; //one minute
  float    lowMoisture = 23.0f;
  float    highMoisture = 40.0f;
  for (;;)
  {
    xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
    //read AD values every 100mS.
    if ( (esp_timer_get_time() - TimeADreading) >= TimeForADreading )
    {
      xEventGroupSetBits( eg, evtADCreading0 );
      TimeADreading = esp_timer_get_time();
    }
    xQueueReceive(xQ_RM, &RemainingMoisture, 0 ); //receive queue stuff no waiting
    //read gpio 0 is water level good. Yes: OK to run pump : no pump off.   remaining moisture good, denergize water pump otherwise energize water pump.
    if ( RemainingMoisture >= highMoisture )
    {
      WaterPump0_off();
    }
    if ( !pumpOn )
    {
      log_i( "not pump on ");
      if ( gpio_get_level( GPIO_NUM_0 ) )
      {
        if ( RemainingMoisture <= lowMoisture )
        {
          //has one minute passed since last pump energize, if so then allow motor to run
          if ( (esp_timer_get_time() - PumpOffWait) >= PumpOffWaitFor )
          {
            WaterPump0_on();
            log_i( "pump on " );
            pumpOn = !pumpOn;
            PumpOnTime = esp_timer_get_time();
          }
        }
        //xSemaphoreGive( sema_RemainingMoisture );
      } else {
        log_i( "water level bad " );
        WaterPump0_off();
        PumpOffWait = esp_timer_get_time();
      }
    } else {
      /*
         pump goes on runs for X seconds then turn off, then wait PumpOffWaitTime before being allowed to energize again
      */
      if ( (esp_timer_get_time() - PumpOnTime) >= PumpRunTime )
      {
        log_i( "pump off " );
        WaterPump0_off(); // after 5 seconds turn pump off
        pumpOn = !pumpOn;
        PumpOffWait = esp_timer_get_time();
      }
    }
    // publish to MQTT every 5000000uS
    if ( (esp_timer_get_time() - TimePastPublish) >= TimeToPublish )
    {
      xQueueOverwrite( xQ_RemainingMoistureMQTT, (void *) &RemainingMoisture );// data for mqtt publish
      TimePastPublish = esp_timer_get_time(); // get next publish time
    }
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete( NULL );
}// end fDoMoistureDetector()

After looking into unix time, this might be better for my application. I can set a trigger time by inputting the day, month, hour, minutes in epoch and just need to compare to that value, so it'll be less calculation.

Thank you for your suggestion

That's very interesting, but is it really accurate or there might be some drift? I'm certain it won't matter if you need to track a few seconds since the counter won't overflow, but I'm looking for a way to trigger at the same time of the day over months. I'm not sure if it's reliable enough to trigger at exactly 5 pm every single day over a year for example. I think I need to incorporate RTC for my project

The 64-bit signed microsecond timer value returned by esp_timer_get_time() won't over flow for more than 290,000 years. Will that work for your application :rofl: :joy: :joy:

I meant as in the accuracy. I'm aware that it won't overflow for a very long time, but the inaccuracy could build up if the counter wasn't correct. The first trigger is at 5 pm, after a week, it's 5:01 pm, after a month or so, it could be at 5:05 pm, and the error would compound as time goes on. I'm not too sure if it would drift that much, but I would prefer having something like NTP to sync, plus the ability to get realtime would make scheduling the correct time easier.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.