Scheduler_example14_Yield.ino 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /**
  2. This test illustrates the use if yield methods and internal StatusRequest objects
  3. THIS TEST HAS BEEN TESTED ON NODEMCU V.2 (ESP8266)
  4. The WiFi initialization and NTP update is executed in parallel to blinking the onboard LED
  5. and an external LED connected to D2 (GPIO04)
  6. Try running with and without correct WiFi parameters to observe the difference in behaviour
  7. */
  8. #define _TASK_SLEEP_ON_IDLE_RUN
  9. #define _TASK_STATUS_REQUEST
  10. #include <TaskScheduler.h>
  11. #include <ESP8266WiFi.h>
  12. #include <WiFiUdp.h>
  13. Scheduler ts;
  14. // Callback methods prototypes
  15. void connectInit();
  16. void ledCallback();
  17. bool ledOnEnable();
  18. void ledOnDisable();
  19. void ledOn();
  20. void ledOff();
  21. void ntpUpdateInit();
  22. // Tasks
  23. Task tConnect (TASK_SECOND, TASK_FOREVER, &connectInit, &ts, true);
  24. Task tLED (TASK_IMMEDIATE, TASK_FOREVER, &ledCallback, &ts, false, &ledOnEnable, &ledOnDisable);
  25. // Tasks running on events
  26. Task tNtpUpdate (&ntpUpdateInit, &ts);
  27. // Replace with WiFi parameters of your Access Point/Router:
  28. const char *ssid = "wifi_network";
  29. const char *pwd = "wifi_password";
  30. long ledDelayOn, ledDelayOff;
  31. #define LEDPIN D0 // Onboard LED pin - linked to WiFi
  32. #define LEDPIN2 D2 // External LED
  33. #define CONNECT_TIMEOUT 30 // Seconds
  34. #define CONNECT_OK 0 // Status of successful connection to WiFi
  35. #define CONNECT_FAILED (-99) // Status of failed connection to WiFi
  36. // NTP Related Definitions
  37. #define NTP_PACKET_SIZE 48 // NTP time stamp is in the first 48 bytes of the message
  38. IPAddress timeServerIP; // time.nist.gov NTP server address
  39. const char* ntpServerName = "time.nist.gov";
  40. byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
  41. unsigned long epoch;
  42. WiFiUDP udp; // A UDP instance to let us send and receive packets over UDP
  43. #define LOCAL_NTP_PORT 2390 // Local UDP port for NTP update
  44. void setup() {
  45. Serial.begin(74880);
  46. Serial.println(F("TaskScheduler test #14 - Yield and internal StatusRequests"));
  47. Serial.println(F("=========================================================="));
  48. Serial.println();
  49. pinMode (LEDPIN, OUTPUT);
  50. pinMode (LEDPIN2, OUTPUT);
  51. tNtpUpdate.waitFor( tConnect.getInternalStatusRequest() ); // NTP Task will start only after connection is made
  52. }
  53. void loop() {
  54. ts.execute(); // Only Scheduler should be executed in the loop
  55. }
  56. /**
  57. Initiate connection to the WiFi network
  58. */
  59. void connectInit() {
  60. Serial.print(millis());
  61. Serial.println(F(": connectInit."));
  62. Serial.println(F("WiFi parameters: "));
  63. Serial.print(F("SSID: ")); Serial.println(ssid);
  64. Serial.print(F("PWD : ")); Serial.println(pwd);
  65. WiFi.mode(WIFI_STA);
  66. WiFi.hostname("esp8266");
  67. WiFi.begin(ssid, pwd);
  68. yield();
  69. ledDelayOn = TASK_SECOND / 2;
  70. ledDelayOff = TASK_SECOND / 4;
  71. tLED.enable();
  72. tConnect.yield(&connectCheck); // This will pass control back to Scheduler and then continue with connection checking
  73. }
  74. /**
  75. Periodically check if connected to WiFi
  76. Re-request connection every 5 seconds
  77. Stop trying after a timeout
  78. */
  79. void connectCheck() {
  80. Serial.print(millis());
  81. Serial.println(F(": connectCheck."));
  82. if (WiFi.status() == WL_CONNECTED) { // Connection established
  83. Serial.print(millis());
  84. Serial.print(F(": Connected to AP. Local ip: "));
  85. Serial.println(WiFi.localIP());
  86. tConnect.disable();
  87. }
  88. else {
  89. if (tConnect.getRunCounter() % 5 == 0) { // re-request connection every 5 seconds
  90. Serial.print(millis());
  91. Serial.println(F(": Re-requesting connection to AP..."));
  92. WiFi.disconnect(true);
  93. yield(); // This is an esp8266 standard yield to allow linux wifi stack run
  94. WiFi.hostname("esp8266");
  95. WiFi.mode(WIFI_STA);
  96. WiFi.begin(ssid, pwd);
  97. yield(); // This is an esp8266 standard yield to allow linux wifi stack run
  98. }
  99. if (tConnect.getRunCounter() == CONNECT_TIMEOUT) { // Connection Timeout
  100. tConnect.getInternalStatusRequest()->signal(CONNECT_FAILED); // Signal unsuccessful completion
  101. tConnect.disable();
  102. Serial.print(millis());
  103. Serial.println(F(": connectOnDisable."));
  104. Serial.print(millis());
  105. Serial.println(F(": Unable to connect to WiFi."));
  106. ledDelayOn = TASK_SECOND / 16; // Blink LEDs quickly due to error
  107. ledDelayOff = TASK_SECOND / 16;
  108. tLED.enable();
  109. }
  110. }
  111. }
  112. /**
  113. Initiate NTP update if connection was established
  114. */
  115. void ntpUpdateInit() {
  116. Serial.print(millis());
  117. Serial.println(F(": ntpUpdateInit."));
  118. if ( tConnect.getInternalStatusRequest()->getStatus() != CONNECT_OK ) { // Check status of the Connect Task
  119. Serial.print(millis());
  120. Serial.println(F(": cannot update NTP - not connected."));
  121. return;
  122. }
  123. udp.begin(LOCAL_NTP_PORT);
  124. if ( WiFi.hostByName(ntpServerName, timeServerIP) ) { //get a random server from the pool
  125. Serial.print(millis());
  126. Serial.print(F(": timeServerIP = "));
  127. Serial.println(timeServerIP);
  128. sendNTPpacket(timeServerIP); // send an NTP packet to a time server
  129. }
  130. else {
  131. Serial.print(millis());
  132. Serial.println(F(": NTP server address lookup failed."));
  133. tLED.disable();
  134. udp.stop();
  135. tNtpUpdate.disable();
  136. return;
  137. }
  138. ledDelayOn = TASK_SECOND / 8;
  139. ledDelayOff = TASK_SECOND / 8;
  140. tLED.enable();
  141. tNtpUpdate.set( TASK_SECOND, CONNECT_TIMEOUT, &ntpCheck );
  142. tNtpUpdate.enableDelayed();
  143. }
  144. /**
  145. * Check if NTP packet was received
  146. * Re-request every 5 seconds
  147. * Stop trying after a timeout
  148. */
  149. void ntpCheck() {
  150. Serial.print(millis());
  151. Serial.println(F(": ntpCheck."));
  152. if ( tNtpUpdate.getRunCounter() % 5 == 0) {
  153. Serial.print(millis());
  154. Serial.println(F(": Re-requesting NTP update..."));
  155. udp.stop();
  156. yield();
  157. udp.begin(LOCAL_NTP_PORT);
  158. sendNTPpacket(timeServerIP);
  159. return;
  160. }
  161. if ( doNtpUpdateCheck()) {
  162. Serial.print(millis());
  163. Serial.println(F(": NTP Update successful"));
  164. Serial.print(millis());
  165. Serial.print(F(": Unix time = "));
  166. Serial.println(epoch);
  167. tLED.disable();
  168. tNtpUpdate.disable();
  169. udp.stop();
  170. }
  171. else {
  172. if ( tNtpUpdate.isLastIteration() ) {
  173. Serial.print(millis());
  174. Serial.println(F(": NTP Update failed"));
  175. tLED.disable();
  176. udp.stop();
  177. }
  178. }
  179. }
  180. /**
  181. * Send NTP packet to NTP server
  182. */
  183. void sendNTPpacket(IPAddress & address)
  184. {
  185. Serial.print(millis());
  186. Serial.println(F(": sendNTPpacket."));
  187. // set all bytes in the buffer to 0
  188. memset(packetBuffer, 0, NTP_PACKET_SIZE);
  189. // Initialize values needed to form NTP request
  190. // (see URL above for details on the packets)
  191. packetBuffer[0] = 0b11100011; // LI, Version, Mode
  192. packetBuffer[1] = 0; // Stratum, or type of clock
  193. packetBuffer[2] = 6; // Polling Interval
  194. packetBuffer[3] = 0xEC; // Peer Clock Precision
  195. // 8 bytes of zero for Root Delay & Root Dispersion
  196. packetBuffer[12] = 49;
  197. packetBuffer[13] = 0x4E;
  198. packetBuffer[14] = 49;
  199. packetBuffer[15] = 52;
  200. // all NTP fields have been given values, now
  201. // you can send a packet requesting a timestamp:
  202. udp.beginPacket(address, 123); //NTP requests are to port 123
  203. udp.write(packetBuffer, NTP_PACKET_SIZE);
  204. udp.endPacket();
  205. yield();
  206. }
  207. /**
  208. * Check if a packet was recieved.
  209. * Process NTP information if yes
  210. */
  211. bool doNtpUpdateCheck() {
  212. Serial.print(millis());
  213. Serial.println(F(": doNtpUpdateCheck."));
  214. yield();
  215. int cb = udp.parsePacket();
  216. if (cb) {
  217. // We've received a packet, read the data from it
  218. udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
  219. //the timestamp starts at byte 40 of the received packet and is four bytes,
  220. // or two words, long. First, esxtract the two words:
  221. unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
  222. unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
  223. // combine the four bytes (two words) into a long integer
  224. // this is NTP time (seconds since Jan 1 1900):
  225. unsigned long secsSince1900 = highWord << 16 | lowWord;
  226. // now convert NTP time into everyday time:
  227. // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
  228. const unsigned long seventyYears = 2208988800UL;
  229. // subtract seventy years:
  230. epoch = secsSince1900 - seventyYears;
  231. return (epoch != 0);
  232. }
  233. return false;
  234. }
  235. /**
  236. * Flip the LED state based on the current state
  237. */
  238. bool ledState;
  239. void ledCallback() {
  240. if ( ledState ) ledOff();
  241. else ledOn();
  242. }
  243. /**
  244. * Make sure the LED starts lit
  245. */
  246. bool ledOnEnable() {
  247. ledOn();
  248. return true;
  249. }
  250. /**
  251. * Make sure LED ends dimmed
  252. */
  253. void ledOnDisable() {
  254. ledOff();
  255. }
  256. /**
  257. * Turn LEDs on.
  258. * Set appropriate delay.
  259. * PLEASE NOTE: NodeMCU onbaord LED is active-low
  260. */
  261. void ledOn() {
  262. ledState = true;
  263. digitalWrite(LEDPIN, LOW);
  264. digitalWrite(LEDPIN2, HIGH);
  265. tLED.delay( ledDelayOn );
  266. }
  267. /**
  268. * Turn LEDs off.
  269. * Set appropriate delay.
  270. * PLEASE NOTE: NodeMCU onbaord LED is active-low
  271. */
  272. void ledOff() {
  273. ledState = false;
  274. digitalWrite(LEDPIN, HIGH);
  275. digitalWrite(LEDPIN2, LOW);
  276. tLED.delay( ledDelayOff );
  277. }