pleasedontcode

# Synchronized Timepiece rev_04

Mar 9th, 2026
35
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 14.49 KB | None | 0 0
  1. /********* Pleasedontcode.com **********
  2.  
  3.     Pleasedontcode thanks you for automatic code generation! Enjoy your code!
  4.  
  5.     - Terms and Conditions:
  6.     You have a non-exclusive, revocable, worldwide, royalty-free license
  7.     for personal and commercial use. Attribution is optional; modifications
  8.     are allowed, but you're responsible for code maintenance. We're not
  9.     liable for any loss or damage. For full terms,
  10.     please visit pleasedontcode.com/termsandconditions.
  11.  
  12.     - Project: # Synchronized Timepiece
  13.     - Version: 004
  14.     - Source Code NOT compiled for: Board 20
  15.     - Source Code created on: 2026-03-09 17:24:53
  16.  
  17. ********* Pleasedontcode.com **********/
  18.  
  19. /****** SYSTEM REQUIREMENTS *****/
  20. /****** SYSTEM REQUIREMENT 1 *****/
  21.     /* Display an analog clock with moving hour/minute */
  22.     /* hands synchronized via WiFi NTP (UTC+1 solar */
  23.     /* time). Animate a pendulum that swings left-right */
  24.     /* at 1 Hz natural frequency behind the clock face on */
  25.     /* ST7789 display. */
  26. /****** SYSTEM REQUIREMENT 2 *****/
  27.     /* Display analog clock with hour/minute hands */
  28.     /* synchronized via WiFi NTP (UTC+1 solar time) on */
  29.     /* ST7789 display */
  30. /****** SYSTEM REQUIREMENT 3 *****/
  31.     /* Animate pendulum swinging left-right at 1 Hz */
  32.     /* natural frequency behind clock face */
  33. /****** END SYSTEM REQUIREMENTS *****/
  34.  
  35.  
  36. /****** DEFINITION OF LIBRARIES *****/
  37. #include <WiFi.h>
  38. #include <time.h>
  39. #include <SPI.h>
  40. #include <TFT_eSPI.h>
  41. #include <math.h>
  42.  
  43. /****** DISPLAY CONFIGURATION *****/
  44. /* ST7789 display instance - pin configuration done in User_Setup.h of TFT_eSPI */
  45. TFT_eSPI tft = TFT_eSPI();
  46.  
  47. /****** NETWORK CONFIGURATION *****/
  48. /* WiFi credentials - User must modify these to actual network credentials */
  49. const char* ssid = "YOUR_SSID";
  50. const char* password = "YOUR_PASSWORD";
  51.  
  52. /* NTP Server for time synchronization */
  53. const char* ntpServer = "pool.ntp.org";
  54. const long gmtOffset_sec = 3600;  /* UTC+1 (1 hour = 3600 seconds) - System Requirement 2 */
  55. const int daylightOffset_sec = 0;  /* No daylight saving adjustment */
  56.  
  57. /****** CLOCK PARAMETERS *****/
  58. /* Clock face center coordinates (adjust based on display resolution) */
  59. const int centerX = 160;
  60. const int centerY = 120;
  61. const int clockRadius = 80;
  62.  
  63. /* Hand lengths (pixels) */
  64. const int hourHandLength = 40;
  65. const int minuteHandLength = 60;
  66. const int secondHandLength = 70;
  67.  
  68. /****** PENDULUM PARAMETERS *****/
  69. /* System Requirement 1 and 3: Pendulum swing parameters */
  70. const float pendulumFrequency = 1.0;  /* 1 Hz natural frequency (System Requirement 3) */
  71. const float pendulumAmplitude = 30.0; /* Swing amplitude in pixels */
  72. const int pendulumBaseY = centerY + 50;  /* Base of pendulum below clock */
  73. const int pendulumLength = 60;  /* Length of pendulum arm in pixels */
  74.  
  75. /****** FUNCTION PROTOTYPES *****/
  76. void setup(void);
  77. void loop(void);
  78. void initializeWiFi(void);
  79. void synchronizeNTP(void);
  80. void drawClockFace(void);
  81. void drawClockHands(int hours, int minutes, int seconds);
  82. void drawPendulum(float phase);
  83. void drawHourHand(int hours, int minutes);
  84. void drawMinuteHand(int minutes, int seconds);
  85. void drawSecondHand(int seconds);
  86. void drawCircle(int x, int y, int radius, uint16_t color);
  87. void drawLine(int x0, int y0, int x1, int y1, uint16_t color, int thickness);
  88. void updateDisplay(void);
  89. float degreesToRadians(float degrees);
  90.  
  91. /****** GLOBAL VARIABLES *****/
  92. /* Time variables for NTP synchronization */
  93. unsigned long lastNTPSync = 0;
  94. unsigned long ntpSyncInterval = 3600000;  /* Sync every hour (3600000 ms) */
  95.  
  96. /* Pendulum animation variables */
  97. float pendulumPhase = 0.0;
  98. unsigned long lastPendulumUpdate = 0;
  99.  
  100. /* Time tracking variables */
  101. time_t lastDisplayTime = 0;
  102.  
  103. /****** SETUP FUNCTION *****/
  104. void setup(void)
  105. {
  106.     /* Initialize serial for debugging and communication */
  107.     Serial.begin(115200);
  108.     delay(1000);
  109.    
  110.     Serial.println("\n\nStarting Analog Clock with WiFi NTP and Pendulum Animation...");
  111.    
  112.     /* Initialize TFT display for ST7789 */
  113.     tft.init();
  114.     tft.setRotation(1);  /* Set rotation to landscape mode (1 = 320x240 landscape) */
  115.     tft.fillScreen(TFT_BLACK);
  116.    
  117.     /* Display initialization message on TFT */
  118.     tft.setTextColor(TFT_WHITE, TFT_BLACK);
  119.     tft.setTextSize(2);
  120.     tft.drawCentreString("Initializing...", centerX, centerY - 20, 2);
  121.    
  122.     /* Initialize WiFi and synchronize with NTP server */
  123.     initializeWiFi();
  124.     synchronizeNTP();
  125.    
  126.     /* Mark the last NTP sync time */
  127.     lastNTPSync = millis();
  128.     lastPendulumUpdate = millis();
  129.    
  130.     Serial.println("Setup complete! Clock is now running.");
  131. }
  132.  
  133. /****** MAIN LOOP FUNCTION *****/
  134. void loop(void)
  135. {
  136.     /* Get current time from system clock - System Requirement 2 */
  137.     time_t now = time(nullptr);
  138.     struct tm* timeinfo = localtime(&now);
  139.    
  140.     /* Extract time components */
  141.     int hours = timeinfo->tm_hour;
  142.     int minutes = timeinfo->tm_min;
  143.     int seconds = timeinfo->tm_sec;
  144.    
  145.     /* Synchronize with NTP periodically (every hour) */
  146.     if (millis() - lastNTPSync > ntpSyncInterval)
  147.     {
  148.         synchronizeNTP();
  149.         lastNTPSync = millis();
  150.     }
  151.    
  152.     /* Clear the display area where clock is drawn */
  153.     updateDisplay();
  154.    
  155.     /* Draw clock face and hands - System Requirement 2 */
  156.     drawClockFace();
  157.     drawClockHands(hours, minutes, seconds);
  158.    
  159.     /* Update pendulum phase for animation at 1 Hz - System Requirement 1 and 3 */
  160.     unsigned long currentMillis = millis();
  161.     if (currentMillis - lastPendulumUpdate >= 50)  /* Update every 50ms for smooth animation */
  162.     {
  163.         /* Calculate phase increment: frequency * time elapsed * 2π */
  164.         float timeElapsed = (currentMillis - lastPendulumUpdate) / 1000.0;
  165.         pendulumPhase += (pendulumFrequency * timeElapsed) * 2.0 * 3.14159265359;
  166.        
  167.         /* Wrap phase to [0, 2π] range */
  168.         if (pendulumPhase > 2.0 * 3.14159265359)
  169.             pendulumPhase -= 2.0 * 3.14159265359;
  170.        
  171.         lastPendulumUpdate = currentMillis;
  172.     }
  173.    
  174.     /* Draw animated pendulum behind clock face - System Requirement 1 and 3 */
  175.     drawPendulum(pendulumPhase);
  176.    
  177.     /* Update display every 100ms for balanced CPU usage and visual smoothness */
  178.     delay(100);
  179. }
  180.  
  181. /****** INITIALIZE WIFI FUNCTION *****/
  182. void initializeWiFi(void)
  183. {
  184.     Serial.print("Attempting to connect to WiFi network: ");
  185.     Serial.println(ssid);
  186.    
  187.     /* Connect to WiFi network in station mode */
  188.     WiFi.mode(WIFI_STA);
  189.     WiFi.begin(ssid, password);
  190.    
  191.     int attempts = 0;
  192.     const int maxAttempts = 20;  /* Maximum 10 seconds (20 * 500ms) */
  193.    
  194.     /* Wait for WiFi connection with timeout */
  195.     while (WiFi.status() != WL_CONNECTED && attempts < maxAttempts)
  196.     {
  197.         delay(500);
  198.         Serial.print(".");
  199.         attempts++;
  200.     }
  201.    
  202.     /* Check if WiFi connection was successful */
  203.     if (WiFi.status() == WL_CONNECTED)
  204.     {
  205.         Serial.println("\nWiFi connection established!");
  206.         Serial.print("IP address: ");
  207.         Serial.println(WiFi.localIP());
  208.        
  209.         /* Display WiFi connection success status on TFT */
  210.         tft.setTextColor(TFT_GREEN, TFT_BLACK);
  211.         tft.setTextSize(1);
  212.         tft.drawCentreString("WiFi: Connected", centerX, centerY + 100, 1);
  213.         delay(1000);
  214.     }
  215.     else
  216.     {
  217.         Serial.println("\nFailed to connect to WiFi network");
  218.         Serial.println("System will continue with internal RTC if available");
  219.        
  220.         /* Display WiFi connection failure status on TFT */
  221.         tft.setTextColor(TFT_RED, TFT_BLACK);
  222.         tft.setTextSize(1);
  223.         tft.drawCentreString("WiFi: Failed", centerX, centerY + 100, 1);
  224.         delay(1000);
  225.     }
  226. }
  227.  
  228. /****** SYNCHRONIZE WITH NTP SERVER FUNCTION *****/
  229. void synchronizeNTP(void)
  230. {
  231.     Serial.println("Attempting to synchronize time with NTP server...");
  232.    
  233.     /* Only proceed if WiFi is connected */
  234.     if (WiFi.status() == WL_CONNECTED)
  235.     {
  236.         /* Configure time with NTP server using UTC+1 timezone - System Requirement 2 */
  237.         configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  238.        
  239.         /* Wait for time to be set by NTP */
  240.         Serial.print("Waiting for NTP time synchronization: ");
  241.         time_t now = time(nullptr);
  242.         int attempts = 0;
  243.         const int maxWaitAttempts = 20;
  244.        
  245.         /* Poll system time until it's set (unix epoch > 24 hours, i.e., > 86400) */
  246.         while (now < 24 * 3600 && attempts < maxWaitAttempts)
  247.         {
  248.             delay(500);
  249.             Serial.print(".");
  250.             now = time(nullptr);
  251.             attempts++;
  252.         }
  253.        
  254.         Serial.println();
  255.        
  256.         /* Verify that time was successfully synchronized */
  257.         if (now > 24 * 3600)
  258.         {
  259.             Serial.println("Time synchronized successfully!");
  260.             Serial.print("Current UTC+1 time: ");
  261.             Serial.println(ctime(&now));
  262.         }
  263.         else
  264.         {
  265.             Serial.println("NTP time synchronization failed - timeout");
  266.         }
  267.     }
  268.     else
  269.     {
  270.         Serial.println("WiFi not connected - cannot synchronize with NTP server");
  271.         Serial.println("Using system time (internal RTC if available)");
  272.     }
  273. }
  274.  
  275. /****** DRAW CLOCK FACE FUNCTION *****/
  276. void drawClockFace(void)
  277. {
  278.     /* Draw clock circle outline - System Requirement 2 */
  279.     drawCircle(centerX, centerY, clockRadius, TFT_WHITE);
  280.    
  281.     /* Draw 12 hour markers around the clock face */
  282.     for (int i = 0; i < 12; i++)
  283.     {
  284.         /* Calculate angle for each hour marker (30 degrees apart = 360/12) */
  285.         float angle = degreesToRadians(i * 30.0);
  286.        
  287.         /* Outer point of hour marker (near clock edge) */
  288.         int x1 = centerX + (int)((clockRadius - 5) * sin(angle));
  289.         int y1 = centerY - (int)((clockRadius - 5) * cos(angle));
  290.        
  291.         /* Inner point of hour marker (toward center) */
  292.         int x2 = centerX + (int)((clockRadius - 12) * sin(angle));
  293.         int y2 = centerY - (int)((clockRadius - 12) * cos(angle));
  294.        
  295.         /* Draw hour marker as a thick white line */
  296.         drawLine(x1, y1, x2, y2, TFT_WHITE, 2);
  297.     }
  298.    
  299.     /* Draw center pivot dot where clock hands meet */
  300.     tft.fillCircle(centerX, centerY, 4, TFT_WHITE);
  301. }
  302.  
  303. /****** DRAW CLOCK HANDS FUNCTION *****/
  304. void drawClockHands(int hours, int minutes, int seconds)
  305. {
  306.     /* Convert to 12-hour format for clock display */
  307.     hours = hours % 12;
  308.    
  309.     /* Draw all three clock hands */
  310.     drawHourHand(hours, minutes);
  311.     drawMinuteHand(minutes, seconds);
  312.     drawSecondHand(seconds);
  313. }
  314.  
  315. /****** DRAW HOUR HAND FUNCTION *****/
  316. void drawHourHand(int hours, int minutes)
  317. {
  318.     /* System Requirement 2: Display hour hand synchronized via NTP */
  319.     /* Hour hand angle calculation:
  320.        - 360 degrees / 12 hours = 30 degrees per hour
  321.        - 30 degrees / 60 minutes = 0.5 degrees per minute
  322.     */
  323.     float hourAngle = degreesToRadians(hours * 30.0 + minutes * 0.5);
  324.    
  325.     /* Calculate end point of hour hand using polar coordinates */
  326.     int x = centerX + (int)(hourHandLength * sin(hourAngle));
  327.     int y = centerY - (int)(hourHandLength * cos(hourAngle));
  328.    
  329.     /* Draw hour hand as a thick blue line */
  330.     drawLine(centerX, centerY, x, y, TFT_BLUE, 4);
  331. }
  332.  
  333. /****** DRAW MINUTE HAND FUNCTION *****/
  334. void drawMinuteHand(int minutes, int seconds)
  335. {
  336.     /* System Requirement 2: Display minute hand synchronized via NTP */
  337.     /* Minute hand angle calculation:
  338.        - 360 degrees / 60 minutes = 6 degrees per minute
  339.        - 6 degrees / 60 seconds = 0.1 degrees per second
  340.     */
  341.     float minuteAngle = degreesToRadians(minutes * 6.0 + seconds * 0.1);
  342.    
  343.     /* Calculate end point of minute hand using polar coordinates */
  344.     int x = centerX + (int)(minuteHandLength * sin(minuteAngle));
  345.     int y = centerY - (int)(minuteHandLength * cos(minuteAngle));
  346.    
  347.     /* Draw minute hand as a medium-thickness red line */
  348.     drawLine(centerX, centerY, x, y, TFT_RED, 3);
  349. }
  350.  
  351. /****** DRAW SECOND HAND FUNCTION *****/
  352. void drawSecondHand(int seconds)
  353. {
  354.     /* Second hand angle calculation:
  355.        - 360 degrees / 60 seconds = 6 degrees per second
  356.     */
  357.     float secondAngle = degreesToRadians(seconds * 6.0);
  358.    
  359.     /* Calculate end point of second hand using polar coordinates */
  360.     int x = centerX + (int)(secondHandLength * sin(secondAngle));
  361.     int y = centerY - (int)(secondHandLength * cos(secondAngle));
  362.    
  363.     /* Draw second hand as a thin yellow line */
  364.     drawLine(centerX, centerY, x, y, TFT_YELLOW, 1);
  365. }
  366.  
  367. /****** DRAW PENDULUM FUNCTION *****/
  368. void drawPendulum(float phase)
  369. {
  370.     /* System Requirement 1 and 3: Pendulum swings left-right at 1 Hz natural frequency */
  371.     /* The pendulum is drawn behind the clock face before clock hands are drawn */
  372.    
  373.     /* Calculate horizontal swing displacement using sinusoidal motion
  374.        - phase ranges from 0 to 2π for one complete cycle
  375.        - pendulumAmplitude controls maximum displacement
  376.        - sin(phase) produces smooth oscillation
  377.     */
  378.     float swingDisplacement = pendulumAmplitude * sin(phase);
  379.    
  380.     /* Calculate pendulum bob position */
  381.     int bobX = centerX + (int)swingDisplacement;
  382.     int bobY = pendulumBaseY + pendulumLength;
  383.    
  384.     /* Draw pendulum arm (line from base to bob) in cyan color */
  385.     drawLine(centerX, pendulumBaseY, bobX, bobY, TFT_CYAN, 1);
  386.    
  387.     /* Draw pendulum bob (small filled circle at the end of the arm) */
  388.     tft.fillCircle(bobX, bobY, 4, TFT_CYAN);
  389. }
  390.  
  391. /****** DRAW CIRCLE FUNCTION *****/
  392. void drawCircle(int x, int y, int radius, uint16_t color)
  393. {
  394.     /* Draw a circle using TFT_eSPI built-in circle drawing function */
  395.     tft.drawCircle(x, y, radius, color);
  396. }
  397.  
  398. /****** DRAW LINE FUNCTION *****/
  399. void drawLine(int x0, int y0, int x1, int y1, uint16_t color, int thickness)
  400. {
  401.     /* Draw a line with variable thickness
  402.        - thickness = 1: thin line
  403.        - thickness > 1: thick line created by drawing parallel offset lines
  404.     */
  405.    
  406.     if (thickness == 1)
  407.     {
  408.         /* Simple case: draw a single thin line */
  409.         tft.drawLine(x0, y0, x1, y1, color);
  410.     }
  411.     else
  412.     {
  413.         /* Thick line case: create thickness by drawing parallel lines */
  414.        
  415.         /* Calculate direction vector from start to end point */
  416.         int dx = x1 - x0;
  417.         int dy = y1 - y0;
  418.        
  419.         /* Calculate line length using Euclidean distance */
  420.         float length = sqrt((float)(dx * dx + dy * dy));
  421.        
  422.         if (length > 0)
  423.         {
  424.             /* Calculate perpendicular unit vector (rotated 90 degrees) */
  425.             float perpX = -dy / length;
  426.             float perpY = dx / length;
  427.            
  428.             /* Draw multiple parallel lines to create thickness effect */
  429.             int halfThickness = thickness / 2;
  430.             for (int t = -halfThickness; t <= halfThickness; t++)
  431.             {
  432.                 /* Calculate offset points perpendicular to the main line */
  433.                 int offset_x0 = x0 + (int)(perpX * t);
  434.                 int offset_y0 = y0 + (int)(perpY * t);
  435.                 int offset_x1 = x1 + (int)(perpX * t);
  436.                 int offset_y1 = y1 + (int)(perpY * t);
  437.                
  438.                 /* Draw offset line */
  439.                 tft.drawLine(offset_x0, offset_y0, offset_x1, offset_y1, color);
  440.             }
  441.         }
  442.         else
  443.         {
  444.             /* Special case: start and end points are the same */
  445.             /* Draw a circle instead of a line */
  446.             tft.fillCircle(x0, y0, thickness / 2, color);
  447.         }
  448.     }
  449. }
  450.  
  451. /****** UPDATE DISPLAY FUNCTION *****/
  452. void updateDisplay(void)
  453. {
  454.     /* Clear the display area where clock is drawn
  455.        This prevents visual artifacts (trails) from moving hands and pendulum
  456.        Clears a square region centered on the clock with extra margin
  457.     */
  458.     int clearRadius = clockRadius + 20;
  459.     tft.fillRect(centerX - clearRadius, centerY - clearRadius,
  460.                 clearRadius * 2, clearRadius * 2 + 60, TFT_BLACK);
  461. }
  462.  
  463. /****** HELPER MATH FUNCTION *****/
  464. float degreesToRadians(float degrees)
  465. {
  466.     /* Convert angle from degrees to radians
  467.        Used for trigonometric calculations in hand and pendulum positioning
  468.        Formula: radians = degrees * π / 180
  469.     */
  470.     return degrees * 3.14159265359 / 180.0;
  471. }
  472.  
  473. /* END CODE */
  474.  
Advertisement
Add Comment
Please, Sign In to add comment