/** This test illustrates the use if yield methods and internal StatusRequest objects THIS TEST HAS BEEN TESTED ON NODEMCU V.2 (ESP8266) The WiFi initialization and NTP update is executed in parallel to blinking the onboard LED and an external LED connected to D2 (GPIO04) Try running with and without correct WiFi parameters to observe the difference in behaviour */ #define _TASK_SLEEP_ON_IDLE_RUN #define _TASK_STATUS_REQUEST #include #include #include Scheduler ts; // Callback methods prototypes void connectInit(); void ledCallback(); bool ledOnEnable(); void ledOnDisable(); void ledOn(); void ledOff(); void ntpUpdateInit(); // Tasks Task tConnect (TASK_SECOND, TASK_FOREVER, &connectInit, &ts, true); Task tLED (TASK_IMMEDIATE, TASK_FOREVER, &ledCallback, &ts, false, &ledOnEnable, &ledOnDisable); // Tasks running on events Task tNtpUpdate (&ntpUpdateInit, &ts); // Replace with WiFi parameters of your Access Point/Router: const char *ssid = "wifi_network"; const char *pwd = "wifi_password"; long ledDelayOn, ledDelayOff; #define LEDPIN D0 // Onboard LED pin - linked to WiFi #define LEDPIN2 D2 // External LED #define CONNECT_TIMEOUT 30 // Seconds #define CONNECT_OK 0 // Status of successful connection to WiFi #define CONNECT_FAILED (-99) // Status of failed connection to WiFi // NTP Related Definitions #define NTP_PACKET_SIZE 48 // NTP time stamp is in the first 48 bytes of the message IPAddress timeServerIP; // time.nist.gov NTP server address const char* ntpServerName = "time.nist.gov"; byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets unsigned long epoch; WiFiUDP udp; // A UDP instance to let us send and receive packets over UDP #define LOCAL_NTP_PORT 2390 // Local UDP port for NTP update void setup() { Serial.begin(74880); Serial.println(F("TaskScheduler test #14 - Yield and internal StatusRequests")); Serial.println(F("==========================================================")); Serial.println(); pinMode (LEDPIN, OUTPUT); pinMode (LEDPIN2, OUTPUT); tNtpUpdate.waitFor( tConnect.getInternalStatusRequest() ); // NTP Task will start only after connection is made } void loop() { ts.execute(); // Only Scheduler should be executed in the loop } /** Initiate connection to the WiFi network */ void connectInit() { Serial.print(millis()); Serial.println(F(": connectInit.")); Serial.println(F("WiFi parameters: ")); Serial.print(F("SSID: ")); Serial.println(ssid); Serial.print(F("PWD : ")); Serial.println(pwd); WiFi.mode(WIFI_STA); WiFi.hostname("esp8266"); WiFi.begin(ssid, pwd); yield(); ledDelayOn = TASK_SECOND / 2; ledDelayOff = TASK_SECOND / 4; tLED.enable(); tConnect.yield(&connectCheck); // This will pass control back to Scheduler and then continue with connection checking } /** Periodically check if connected to WiFi Re-request connection every 5 seconds Stop trying after a timeout */ void connectCheck() { Serial.print(millis()); Serial.println(F(": connectCheck.")); if (WiFi.status() == WL_CONNECTED) { // Connection established Serial.print(millis()); Serial.print(F(": Connected to AP. Local ip: ")); Serial.println(WiFi.localIP()); tConnect.disable(); } else { if (tConnect.getRunCounter() % 5 == 0) { // re-request connection every 5 seconds Serial.print(millis()); Serial.println(F(": Re-requesting connection to AP...")); WiFi.disconnect(true); yield(); // This is an esp8266 standard yield to allow linux wifi stack run WiFi.hostname("esp8266"); WiFi.mode(WIFI_STA); WiFi.begin(ssid, pwd); yield(); // This is an esp8266 standard yield to allow linux wifi stack run } if (tConnect.getRunCounter() == CONNECT_TIMEOUT) { // Connection Timeout tConnect.getInternalStatusRequest()->signal(CONNECT_FAILED); // Signal unsuccessful completion tConnect.disable(); Serial.print(millis()); Serial.println(F(": connectOnDisable.")); Serial.print(millis()); Serial.println(F(": Unable to connect to WiFi.")); ledDelayOn = TASK_SECOND / 16; // Blink LEDs quickly due to error ledDelayOff = TASK_SECOND / 16; tLED.enable(); } } } /** Initiate NTP update if connection was established */ void ntpUpdateInit() { Serial.print(millis()); Serial.println(F(": ntpUpdateInit.")); if ( tConnect.getInternalStatusRequest()->getStatus() != CONNECT_OK ) { // Check status of the Connect Task Serial.print(millis()); Serial.println(F(": cannot update NTP - not connected.")); return; } udp.begin(LOCAL_NTP_PORT); if ( WiFi.hostByName(ntpServerName, timeServerIP) ) { //get a random server from the pool Serial.print(millis()); Serial.print(F(": timeServerIP = ")); Serial.println(timeServerIP); sendNTPpacket(timeServerIP); // send an NTP packet to a time server } else { Serial.print(millis()); Serial.println(F(": NTP server address lookup failed.")); tLED.disable(); udp.stop(); tNtpUpdate.disable(); return; } ledDelayOn = TASK_SECOND / 8; ledDelayOff = TASK_SECOND / 8; tLED.enable(); tNtpUpdate.set( TASK_SECOND, CONNECT_TIMEOUT, &ntpCheck ); tNtpUpdate.enableDelayed(); } /** * Check if NTP packet was received * Re-request every 5 seconds * Stop trying after a timeout */ void ntpCheck() { Serial.print(millis()); Serial.println(F(": ntpCheck.")); if ( tNtpUpdate.getRunCounter() % 5 == 0) { Serial.print(millis()); Serial.println(F(": Re-requesting NTP update...")); udp.stop(); yield(); udp.begin(LOCAL_NTP_PORT); sendNTPpacket(timeServerIP); return; } if ( doNtpUpdateCheck()) { Serial.print(millis()); Serial.println(F(": NTP Update successful")); Serial.print(millis()); Serial.print(F(": Unix time = ")); Serial.println(epoch); tLED.disable(); tNtpUpdate.disable(); udp.stop(); } else { if ( tNtpUpdate.isLastIteration() ) { Serial.print(millis()); Serial.println(F(": NTP Update failed")); tLED.disable(); udp.stop(); } } } /** * Send NTP packet to NTP server */ void sendNTPpacket(IPAddress & address) { Serial.print(millis()); Serial.println(F(": sendNTPpacket.")); // set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); // Initialize values needed to form NTP request // (see URL above for details on the packets) packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; // all NTP fields have been given values, now // you can send a packet requesting a timestamp: udp.beginPacket(address, 123); //NTP requests are to port 123 udp.write(packetBuffer, NTP_PACKET_SIZE); udp.endPacket(); yield(); } /** * Check if a packet was recieved. * Process NTP information if yes */ bool doNtpUpdateCheck() { Serial.print(millis()); Serial.println(F(": doNtpUpdateCheck.")); yield(); int cb = udp.parsePacket(); if (cb) { // We've received a packet, read the data from it udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer //the timestamp starts at byte 40 of the received packet and is four bytes, // or two words, long. First, esxtract the two words: unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); // combine the four bytes (two words) into a long integer // this is NTP time (seconds since Jan 1 1900): unsigned long secsSince1900 = highWord << 16 | lowWord; // now convert NTP time into everyday time: // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: const unsigned long seventyYears = 2208988800UL; // subtract seventy years: epoch = secsSince1900 - seventyYears; return (epoch != 0); } return false; } /** * Flip the LED state based on the current state */ bool ledState; void ledCallback() { if ( ledState ) ledOff(); else ledOn(); } /** * Make sure the LED starts lit */ bool ledOnEnable() { ledOn(); return true; } /** * Make sure LED ends dimmed */ void ledOnDisable() { ledOff(); } /** * Turn LEDs on. * Set appropriate delay. * PLEASE NOTE: NodeMCU onbaord LED is active-low */ void ledOn() { ledState = true; digitalWrite(LEDPIN, LOW); digitalWrite(LEDPIN2, HIGH); tLED.delay( ledDelayOn ); } /** * Turn LEDs off. * Set appropriate delay. * PLEASE NOTE: NodeMCU onbaord LED is active-low */ void ledOff() { ledState = false; digitalWrite(LEDPIN, HIGH); digitalWrite(LEDPIN2, LOW); tLED.delay( ledDelayOff ); }