Firas Rihan
Firas Rihan

Reputation: 71

Esp8266 Timer instead of delay

I'm working on a smart Irrigation system built on an ESP8266 microcontroller coded on Arduino ide; basically I want to send data of temperature to my database every 4 minutes, check the sensors every 10 minutes, or execute any code after a certain time , but I don't want to use delay() since other codes in the same loop should keep on executing. So, is there a way to use another function that can execute the rest code and when the timer is done it executes the sending to database? Thanks

Upvotes: 1

Views: 1730

Answers (1)

J...
J...

Reputation: 31443

The Arduino package manager has a library called NTPClient, which provides, as you might guess, an NTP client. Using this with the system clock lets you keep reasonable time without a battery-backed RTC.

Once you know what time it is, scheduling events becomes trivial. This isn't a fully working example, but should give you the idea. The docs have more information. The NTPClient also works quite well with the AceTime library for time zone and other management.

#include <NTPClient.h>
#include <WiFiUdp.h>
#include <ESP8266WiFi.h>
#include <AceTime.h>
#include <ctime>

using namespace ace_time;
using namespace ace_time::clock;
using namespace std;

WiFiUDP ntpUDP;
const long utcOffsetInSeconds = 0;  
// Get UTC from NTP - let AceTime figure out the local time
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds, 3600);  
//3600s/h - sync time once per hour, this is sufficient.
// don't hammer pool.ntp.org!


static BasicZoneProcessor estProcessor;
static SystemClockLoop systemClock(nullptr /*reference*/, nullptr /*backup*/);

const char* ssid = // your SSID;
const char* password = // your wifi password;
 
void setup() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("Connecting to wifi...");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println('.');
    delay(500);
  }
  systemClock.setup();
  timeClient.begin();
}

int clockUpdateCounter = 50000;  
void loop(){
  // Update the system clock from the NTP client periodically
  if (++clockUpdateCounter > 50000){  // can be more elegant than this... depends on your loop speed, can actually use the real time for this too, I'm just making this simple because I don't have a lot of time...
    clockUpdateCounter = 0;
    timeClient.update();
    // doesn't matter how often you call timeClient.update().
    // you can put this in the main loop() if you want.  
    // We supplied 3600s as the refresh interval in the constructor
    // and internally .update() checks whether enough time has passed 
    // before making a request to the NTP server itself
    auto estTz = TimeZone::forZoneInfo(&zonedb::kZoneAmerica_Toronto, &estProcessor);
    auto estTime = ZonedDateTime::forUnixSeconds(timeClient.getEpochTime(), estTz);
    // using the system clock is optional, but has a few 
    // conveniences.  Here we just make sure that the systemClock remains 
    // sync'd with the NTP server.  Doesn't matter how often you do this
    // but usually around once an hour is plenty
    systemClock.setNow(estTime.toEpochSeconds());
  }
  systemClock.loop();
  delay(30);
}

The above keeps the system clock in sync with the NTP server. You can then use the system clock to fetch the time and use it for all types of timing purposes. eg :

 // get Time
  acetime_t nowT = systemClock.getNow();
  auto estTz = TimeZone::forZoneInfo(&zonedb::kZoneAmerica_Toronto, &estProcessor);
  auto nowTime = ZonedDateTime::forEpochSeconds(nowT, estTz);

Checking the time is fast, so you can do it inside loop() and only trigger the action when whatever time has elapsed.

This is a particularly nice solution for database integration since you can record a real timestamp of the actual date and time when logging your data to the database.

Upvotes: 2

Related Questions