ESP32 - Check the Weather every 2 hours

Hi,

I have programmed my ESP32 to find out about tomorrows weather using Climacell's API.
I'd like to get it to check the weather every say 2 hours during the day but not bother at night.

What would be the best way to set up relatively long intervals of this nature.
Can anyone direct me to a code example that is economical on CPU resources.

Thanks in advance
Charlie

What comes to mind, would be to have the ESP32 start up, connect to the inet, get the time, disconnect, do the weather thing, save the hour to RTC fast ram(using 24 hour time), save any needed data to RTC fast ram, go to sleep for 5 minutes, wake up, get the hour, compare the hour to the one stored in RTC RAM, = or > 2 hours, yes: do the weather thing, save the the hour to RTC fast ram....

Yes, that would be great.
In fact, that's exactly what it does when starting up but I don't want it to go to sleep during the day.
I am not trying to spare CPU resources to lengthen my battery life because the ESP32 is connected to the mains.
So it's not power I'm trying to conserve, it's the load on the CPU whilst it's busy performing LED patterns
I'm sorry, I should have made that clearer from the start

That said, I like the sleep idea for when I want it to stop activity during the night.
So yes, I'll explore that idea for when I want it to shut down at night.

But for the day, I need another approach - any ideas?

the ide from my previous reply but not putting the esp32 to sleep. I'd use freeRTOS, the built in OS, to do the time checking task and when time expires trigger the working tasks, leaving the ESP32 to do other things.

The esp core comes with NTP and the unix time library API including support for local time which adjusts for DST using a standard POSIX TZ string stored in TZ environment variable.
Once you initialize NTP, it runs in the background. Once you set the TZ environment variable you can then use the time API functions to get the local time and do whatever you want based on the local time.

All that said, you may want to use a light sensor or motion sensor rather than specific times of day to disable things.
The RCWL-0516 motion sensor modules are cheap and very effective. I've used them on some clock projects to turn off the display after not detecting any movement for a while.
They work great, It can detect a single finger moving from several feet away.

--- bill

Hi Bill,

Thanks for this
I'm familiar with keeping tabs on the correct time - My pilot pretty much follows your recommendation.

Powering up on detection of movement and then reverting to sleep after detecting no movement also sounds like a great plan.

But what I'm really looking for is a way of setting up an interrupt to fire up every two hours rather than have a loop continually checking if sufficient time has elapsed. I'll let you know how I get on with my quest

OK,

I've taken a look around and it looks like the ESP32 has 4 internal clocks as documented by Espressif at:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/timer.html#_CPPv423timer_set_counter_value13timer_group_t11timer_idx_t8uint64_t

So it looks like I can use one of those.

To set it up I can initialise it's tick interval by setting the divider to its max value - 65,536
Since the native frequency is 80 Mhertz, we can reduce it to 1.22 KHertz - still pretty dam quick

So for every tick we can configure the timer to decrement its counter to our zero alarm value.

We want an interval of 2 hours which equates to (60x60x2) 7,200 seconds

And if we multiply that by our frequency we get a counter value of
(1220 Hertz x 7,200 seconds) 8,784,000

That value comfortably fits within a long integer (4 bytes) so we could be in luck as the counter is documented to accept a whopping 64 bit value. That said, it's unwise to make max/min assumptions based on parameter types - lets keep our fingers crossed.

So we now have a timer that is happily descending down quietly in the background to its alarm value of zero

And when it hits the alarm value we can configure it to fire off our very own Interrupt Service Routine (ISR) to check the weather forecast.

There is a feature for the counter to automatically reload and start all over again but I think I'll handle this within the ISR as I'm now thinking of reverting to Sleep mode at night

Well that's the theory. I'll let you know how I get on :slight_smile:

I have the same problem, I just use a cheap 5 dollar mechanical timer to turn everything on and off. Been working for 3 years now.

Wise words,

We should always avoid re-inventing the wheel and keep our solutions grounded.
My project is for the bedroom and the thought of cutting the power whilst I am asleep sounds very inviting
I'll bear it in mind

Thanks

Idahowalker:
the ide from my previous reply but not putting the esp32 to sleep. I'd use freeRTOS, the built in OS, to do the time checking task and when time expires trigger the working tasks, leaving the ESP32 to do other things.

Ahh freeRTOS - it's a wonderful feature.
I'm in fact leveraging it so that the LEDs are controlled via core1 and the web server via core0. It's to get around interrupts being periodically suspended as part of servicing the LEDs. So if I am to come up with an interrupts timing solution, I'll need to ensure it's using core0

Thanks

Yea, the hardware timer works great.

here is a task being triggered once a minute, by a hardware timer, but only does the real work after an hour:

void fCollectHistory( void * parameter )
{
  int StorageTriggerCount = 59;
  for (;;)
  {
    xEventGroupWaitBits (eg, evtCollectHistory, pdTRUE, pdTRUE, portMAX_DELAY );
    //log_i( "history triggered" );
    StorageTriggerCount++; //triggered by the timer isr once a minute count 60 minutes
    if ( StorageTriggerCount == 60 )
    {
      xSemaphoreTake( sema_HistoryCompleted, portMAX_DELAY );
      // log_i( " store the history" );
      oPressureHistoryPtr[IntDataPtr[1]] = ePtr[5];
      oIAQ_HistoryPtr[IntDataPtr[1]] = ePtr[6];
      oHumidityHistoryPtr[IntDataPtr[1]] = ePtr[4];
      oTemperaturePtr[IntDataPtr[1]] = ePtr[3];
      IntDataPtr[1]++;
      xSemaphoreGive( sema_HistoryCompleted );
      //log_i( "pointer %d stored %f", IntDataPtr[1] - 1, oPressureHistoryPtr[IntDataPtr[1] - 1] );
      if ( IntDataPtr[1] == IntDataPtr[0] )
      {
        IntDataPtr[1] = 0;
      }
      StorageTriggerCount = 0;
    }
    StorageTriggerCount );
    // log_i( " high watermark %d",  uxTaskGetStackHighWaterMark( NULL ) );
  }
  vTaskDelete( NULL );
} //void fCollectHistory( void * parameter )

here is the timer code

void IRAM_ATTR onTimer()
{
  BaseType_t xHigherPriorityTaskWoken;
  iDoTheBME280Thing++;

  if ( iDoTheBME280Thing == 60000 )
  {
    xEventGroupSetBitsFromISR( eg, evtGroupBits, &xHigherPriorityTaskWoken );
    iDoTheBME280Thing = 0;
  }
}

"beeing economical on cpu-ressources" does this mean your ESP32 is running on a battery?
if yes why don't you simply use the command deepsleep?

deepsleep can be configured to use the internal RTC for timing.

have a look here

ESP32 Deep Sleep with Arduino IDE and Wake Up Sources

best regards Stefan

StefanL38:
"beeing economical on cpu-ressources" does this mean your ESP32 is running on a battery?
if yes why don't you simply use the command deepsleep?

deepsleep can be configured to use the internal RTC for timing.

have a look here
ESP32 Deep Sleep with Arduino IDE and Wake Up Sources | Random Nerd Tutorials

ESP32 Deep Sleep with Arduino IDE and Wake Up Sources

best regards Stefan

What I should have make clearer is that I'm looking to have the CPU busy controlling WS2812 LEDs and would prefer to minimise any further load to the CPU. Yes, there are two CPUs but the other is busy with BLE/WIFI tasks and so the requirement holds - low additional impact to the CPU.
I'm going with a hardware timer that is incorporated as part of the ESP32 dev board and hope to have my efforts posted soon