Advertisement
RehabCZ

NTP to DCF77 converter for ESP8266.

Apr 10th, 2025 (edited)
442
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.93 KB | Source Code | 0 0
  1. #include <ESP8266WiFi.h>
  2. #include <NTPClient.h>
  3. #include <EEPROM.h>
  4. #include <WiFiUdp.h>
  5. #include <time.h>
  6.  
  7. // ========== CONFIG STARTS HERE ==========//
  8.  
  9. /* Address of NTP server from which we would grab time data */
  10. #define NTPSERVER "tik.cesnet.cz"
  11.  
  12. /*
  13. +----------+------------------------------------------------------+---------+
  14. | TIME VAL |                     DESCRIPTION                      | GMT VAL |
  15. +----------+------------------------------------------------------+---------+
  16. |    43200 | International Date Line West                         | -12:00  |
  17. |   -39600 | Midway Island, Samoa                                 | -11:00  |
  18. |   -36000 | Hawaii                                               | -10:00  |
  19. |   -34200 | French Polynesia, Marquesas Islands                  | -09:30  |
  20. |   -32400 | Alaska                                               | -09:00  |
  21. |   -28800 | Pacific Time (US & Canada)                           | -08:00  |
  22. |   -25200 | Mountain Time (US & Canada)                          | -07:00  |
  23. |   -21600 | Central Time (US & Canada), Guadalajara, Mexico city | -06:00  |
  24. |   -18000 | Eastern time (US & Canada)                           | -05:00  |
  25. |   -16200 | Venezuela                                            | -04:30  |
  26. |   -14400 | Atlantic time (Canada), Manaus, Santiago             | -04:00  |
  27. |   -12600 | Newfoundland                                         | -03:30  |
  28. |   -10800 | Greenland, Brasilia, Montevideo                      | -03:00  |
  29. |    -7200 | Mid-Atlantic                                         | -02:00  |
  30. |    -3600 | Azores                                               | -01:00  |
  31. |        0 | GMT: Dublin, Edinburgh, Lisbon, London               | 00:00   |
  32. |     3600 | Amsterdam, Berlin, Rome, Vienna, Prague, Brussels    | +01:00  |
  33. |     7200 | Athens, Istanbul, Beirut, Cairo, Jerusalem           | +02:00  |
  34. |    10800 | St. Petersburg, Minsk, Baghdad, Moscow               | +03:00  |
  35. |    12600 | Iran                                                 | +03:30  |
  36. |    14400 | Volgograd, Baku, Yerevan                             | +04:00  |
  37. |    16200 | Afghanistan                                          | +04:30  |
  38. |    18000 | Yekaterinburg, Tashkent                              | +05:00  |
  39. |    19800 | Chennai, Kolkata, Mumbai, New Delhi                  | +05:30  |
  40. |    20700 | Nepal                                                | +05:45  |
  41. |    21600 | Omsk, Almaty                                         | +06:00  |
  42. |    23400 | Myanmar, Cocos Islands                               | +06:30  |
  43. |    25200 |                                                      | +07:00  |
  44. |    28800 | Krasnoyarsk, Ulaan Bataar, Perth                     | +08:00  |
  45. |    32400 | Irkutsk                                              | +09:00  |
  46. |    34200 | Australian Central Standard Time                     | +09:30  |
  47. |    36000 | Yakutsk, Canberra, Melbourne, Sydney, Hobart         | +10:00  |
  48. |    37800 | Lord Howe Standard Time                              | +10:30  |
  49. |    39600 | Vladivostok, Solomon Is., New Caledonia              | +11:00  |
  50. |    41400 | Norfolk Islan                                        | +11:30  |
  51. |    43200 | Magadan, Auckland, Wellington                        | +12:00  |
  52. |    45900 | New Zealand, Chatham Island                          | +12:45  |
  53. |    46800 | Nuku'alofa                                           | +13:00  |
  54. |    50400 | Kiribati, Line Islands                               | +14:00  |
  55. +----------+------------------------------------------------------+---------+
  56. */
  57. #define TIMEOFFSET 32400
  58.  
  59. /* WIFI Network credentials */
  60. const char ssid[] = "MPCB_internet";
  61. const char passwd[] = "MPbudejovice?";
  62.  
  63. // ========== CONFIG ENDS HERE ========== //
  64.  
  65. /* Define output device pin */
  66. #define DCF77_OUTPUT 13
  67.  
  68. /* Define indicator led pins */
  69. #define PIN_LED_WIFI_STATUS 10
  70. #define PIN_LED_NTP_STATUS 11
  71. #define PIN_LED_DEVICE_STATUS 12
  72.  
  73. /* Define size of EEPROM storage */
  74. #define EEPROM_BYTES 512
  75.  
  76. WiFiUDP ntpUDP;
  77.  
  78. NTPClient timeClient(ntpUDP, NTPSERVER, TIMEOFFSET, 0);
  79.  
  80. int count = 0;
  81. int unixtime;
  82. int starttime;
  83.  
  84. long lobit = 0;   // 0 - 28
  85. long hibit = 0;   // 29 - 59
  86.  
  87. /**
  88. * Helper function to check if WiFi connection is established
  89. */
  90. bool isWiFiConnected() { return WiFi.status() == WL_CONNECTED; }
  91.  
  92. /**
  93. * Helper function to initialize WiFi connection and handle timeout
  94. */
  95. bool initWiFiConnection()
  96. {
  97.   int i = 0;
  98.   Serial.println("INFO: Waiting for WiFi connection");
  99.   while(!isWiFiConnected()) {
  100.     Serial.print(".");
  101.     delay(1000);
  102.     ++i;
  103.     if(i > 60)
  104.       break;
  105.   }
  106.   if(WiFi.status() != WL_CONNECTED)
  107.     return false;
  108.  
  109.   // Print network details
  110.   Serial.println("INFO: WiFi connection successfully established");
  111.   Serial.println("INFO: Obtained IP address: ");
  112.   Serial.print(WiFi.localIP());
  113.  
  114.   return true;
  115. }
  116.  
  117. /**
  118.  * Helper function to erase all stored data in EEPROM
  119.  */
  120. void eeprom_clear() { for (int i = 0; i < bytes; i++) { EEPROM.write(i, 0); } EEPROM.commit(); }
  121.  
  122. /**
  123.  * Helper function to remove specific EEPROM value based on key
  124.  */
  125. void eeprom_remove(int key) { if (EEPROM.get(key) != 0) EEPROM.write(key, 0); }
  126.  
  127. /**
  128. * Properly schedule DCF output for precise time management
  129. */
  130. void timer0_ISR (void)
  131. {
  132.   int curbit;
  133.   int sec;
  134.   sec = count / 10;
  135.   if(lobit != 0) {
  136.     if(count < 290) {
  137.       curbit = (lobit >> sec) & 1;
  138.     } else {
  139.       curbit = (hibit >> (sec - 29)) & 1;
  140.     }
  141.  
  142.     if(sec != 59) {
  143.       if (count % 10 == 0) {
  144.         digitalWrite(DCF77_OUTPUT, HIGH);
  145.       } else if(count % 10 == 1 && curbit == 0) {
  146.         digitalWrite(DCF77_OUTPUT, LOW);
  147.       } else if(count % 10 == 2 && curbit == 1) {
  148.         digitalWrite(DCF77_OUTPUT, LOW);
  149.       }
  150.     }
  151.   }
  152.   if(count == 590) {
  153.     generate_dcf77();
  154.   }
  155.   if(count % 10 == 0)
  156.     ++unixtime;
  157.   ++count;
  158.   if(count == 600)
  159.     count = 0;
  160.   timer0_write(ESP.getCycleCount() + 8000000L); // 8MHz == 100ms
  161. }
  162.  
  163. /**
  164. * Construct DCF77 signal
  165. */
  166. void generate_dcf77()
  167. {
  168.   int minutes, hours, week, day, month, year;
  169.   int parity;
  170.   int i;
  171.   struct tm *date;
  172.   int nexttime = unixtime + 2 + 60;
  173.   time_t now = nexttime;
  174.  
  175.   minutes = (nexttime % 3600) / 60;
  176.   hours = (nexttime % 86400L) / 3600;
  177.   week = ((nexttime / 86400L) + 3) % 7 + 1;
  178.  
  179.   date = localtime(&now);
  180.   day = date->tm_mday;
  181.   month = date->tm_mon + 1;
  182.   year = date->tm_year-100;
  183.  
  184.   // Print encoded time data
  185.   Serial.print(year);
  186.   Serial.print("-");
  187.   Serial.print(month);
  188.   Serial.print("-");
  189.   Serial.print(day);
  190.   Serial.print("/");
  191.   Serial.print(week);
  192.   Serial.print(" ");
  193.   Serial.print(hours);
  194.   Serial.print(":");
  195.   Serial.println(minutes);
  196.  
  197.   lobit = 0;
  198.   hibit = 0;
  199.  
  200.   lobit |= 1 << 18;   // CET
  201.   lobit |= 1 << 20;   // Start Bit
  202.   lobit |= (minutes % 10) << 21;   // Minutes
  203.   lobit |= (minutes / 10) << 25;
  204.  
  205.   hibit |= (hours % 10);   // Hours
  206.   hibit |= (hours / 10) << 4;
  207.   hibit |= (day % 10) << 7;   // Day of month
  208.   hibit |= (day / 10) << 11;
  209.   hibit |= week << 13;   // Day of week
  210.   hibit |= (month % 10) << 16;  // Month number
  211.   hibit |= (month / 10) << 20;
  212.   hibit |= (year % 10) << 21;   // Year within century
  213.   hibit |= (year / 10) << 25;
  214.  
  215.   parity = 0;
  216.   for(i = 21; i <= 27; ++i) {
  217.     parity += (lobit >> i) & 1;
  218.   }
  219.   if(parity & 1)
  220.     lobit |= 1 << 28;
  221.  
  222.   parity = 0;
  223.   for(i = 0; i <= 5; ++i) {
  224.     parity += (hibit >> i) & 1;
  225.   }
  226.   if(parity & 1)
  227.     hibit |= 1 << 6;
  228.  
  229.   parity = 0;
  230.   for(i = 7; i <= 28; ++i) {
  231.     parity += (hibit >> i) & 1;
  232.   }
  233.   if(parity & 1)
  234.     hibit |= 1 << 29;
  235. }
  236.  
  237. // ========== MAIN SETUP FUNCTION ========== //
  238. void setup()
  239. {
  240.   Serial.begin(115200);
  241.  
  242.   WiFi.mode(WIFI_STA);
  243.   WiFi.begin(ssid, passwd);
  244.  
  245.   EEPROM.begin(EEPROM_BYTES);
  246.  
  247.   // If we can't establish WiFi connection enter deep sleep
  248.   if(initWiFiConnection() == false) {
  249.     Serial.println("ERROR: Can't establish WiFi connection!");
  250.     ESP.deepSleep(0);
  251.     return;
  252.   }
  253.  
  254.   timeClient.begin();
  255.   timeClient.update();
  256.  
  257.   unixtime = timeClient.getEpochTime();
  258.   starttime = unixtime;
  259.   count = (unixtime % 60) * 10;
  260.   Serial.println(unixtime);
  261.  
  262.   // If we can't establish NTP connection enter deep sleep
  263.   if(unixtime < 946652400) { // before 2000/01/01 00:00:00
  264.     Serial.println("ERROR: Can't obtain time data from provided NTP server!");
  265.     ESP.deepSleep(0);
  266.     return;
  267.   }
  268.  
  269.   // After obtaining NTP time data we can disconnect from WiFi
  270.   WiFi.disconnect();
  271.   delay(1);
  272.   WiFi.mode(WIFI_OFF);
  273.   WiFi.forceSleepBegin();
  274.   delay(1);
  275.  
  276.   // Broadcast DCF signal to output pin
  277.   pinMode(DCF77_OUTPUT, OUTPUT);
  278.   noInterrupts();
  279.   timer0_isr_init();
  280.   timer0_attachInterrupt(timer0_ISR);
  281.   timer0_write(ESP.getCycleCount() + 8000000L); // 8MHz == 100ms
  282.   interrupts();
  283.  
  284.   EEPROM.end();
  285. }
  286.  
  287. // ========== MAIN LOOP FUNCTION ========== //
  288. void loop()
  289. {
  290.   if(unixtime - starttime > 60 * 5) {
  291.     ESP.deepSleep(0);
  292.   }
  293. }
Tags: NTP DCF
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement