// For ESP32 Dev board (only tested with ILI9341 display)
// The hardware SPI can be mapped to any pins
// #define TFT_MISO 19
// #define TFT_MOSI 23
// #define TFT_SCLK 18
// #define TFT_CS 15 // Chip select control pin
// #define TFT_DC 2 // Data Command control pin
// #define TFT_RST 4 // Reset pin (could connect to RST pin)
#include <TFT_eSPI.h>
#include "clem.h"
#include <WiFi.h>
#include <WiFiClient.h>
#include <time.h>
//#include <WiFiManager.h>
#define GFXFF 1
#define CF_NB07 &NotoSans_Bold7pt7b
// Maximum of 3 servers
#define NTP_SERVERS "us.pool.ntp.org", "pool.ntp.org", "time.nist.gov"
const char* TZ_INFO = "PST8PDT,M3.2.0/2,M11.1.0/2"; // enter your time zone (https://remotemonitoringsystems.ca/time-zone-abbreviations.php)
char buf[80];
time_t tnow;
struct tm* timeinfo;
struct RTCData {
int hour, minute, second;
int year, month, day, dayOfWeek;
};
RTCData cur;
unsigned long ms = 0;
const int lcdWidth = 240;
const int lcdHeight = 320;
const int secondhandW = 10;
const int secondhandH = 200;
const int minutehandH = 180;
const int hourhandH = 140;
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite dial = TFT_eSprite(&tft);
TFT_eSprite secondhand = TFT_eSprite(&tft);
TFT_eSprite minutehand = TFT_eSprite(&tft);
TFT_eSprite hourhand = TFT_eSprite(&tft);
void setup() {
Serial.begin(115200);
// connect to wifi
WiFi.mode(WIFI_STA);
//WiFiManager wm;
WiFi.begin("Wokwi-GUEST", "");
while (WiFi.status() != WL_CONNECTED) {
delay(250);
Serial.println(".");
}
tft.init();
tft.setRotation(0);
tft.fillScreen(TFT_BLACK);
tft.setFreeFont(CF_NB07);
tft.setTextColor(TFT_YELLOW);
tft.setCursor(0, 40);
tft.println("To Setup WiFi connect to:");
tft.println("SetupClockWiFi");
tft.println("and browse to 192.168.4.1");
/*
wm.setConnectTimeout(30); // how long to try to connect for before continuing
bool res;
// res = wm.autoConnect(); // auto generated AP name from chipid
res = wm.autoConnect("SetupClockWiFi"); // anonymous ap
//res = wm.autoConnect("AutoConnectAP","password"); // password protected ap
if (!res) {
Serial.println("Failed to connect");
// ESP.restart();
} else {
//if you get here you have connected to the WiFi
Serial.println("");
Serial.print("Connected to ");
Serial.println(WiFi.SSID());
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
*/
// connect to time server
configTime(0, 0, NTP_SERVERS); // must be executed after wifi is connected
// Set timezone to US Pacific Time
setenv("TZ", TZ_INFO, 1);
//Get NTP Time
//tnow = time(nullptr); // acceptable alternate in a single line
time(&tnow);
Serial.println("Connect to time server");
tft.fillScreen(TFT_BLACK);
tft.setCursor(10, 20);
tft.println("Connecting to time server");
while (tnow < 24 * 3600) // wait until unix time exceeds one day after day zero (1 Jan 1970)
{
Serial.print(".");
tft.print(".");
int count;
if (count++ > 300) {
tft.fillScreen(TFT_BLACK);
tft.setCursor(10, 20);
count = 0;
}
Serial.print(String(ctime(&tnow)));
delay(100);
tnow = time(nullptr);
}
tft.fillScreen(TFT_WHITE);
tft.setSwapBytes(true);
tft.pushImage(8, 0, 216, 320, epd_bitmap_Clementine);
Serial.println("PT: " + String(ctime(&tnow)));
timeinfo = localtime(&tnow);
Serial.println(String(timeinfo->tm_hour));
Serial.println(String(timeinfo->tm_min));
Serial.println(String(timeinfo->tm_sec));
}
void loop() {
// execute every second
if (millis() - ms > 1000) {
ms = millis();
// Refresh time
time(&tnow);
timeinfo = localtime(&tnow);
cur.hour = timeinfo->tm_hour;
cur.minute = timeinfo->tm_min;
cur.second = timeinfo->tm_sec;
// Calculate the angles of the clock hands
float hourAngle = (cur.hour % 12 + cur.minute / 60.0) * 30;
float minuteAngle = cur.minute * 6;
float secondAngle = cur.second * 6;
Serial.println(secondAngle);
// Create sprites - sprites don't seem to draw in Wokwi...
/*
secondhand.createSprite(secondhandW, secondhandH); //10 wide by 200 tall - pivot in the center
minutehand.createSprite(secondhandW, minutehandH);
hourhand.createSprite(secondhandW, hourhandH);
dial.createSprite(lcdWidth, lcdHeight);
dial.setPivot(lcdWidth / 2, lcdHeight / 2); //not really needed since center is default for rotation
//dial.pushImage(0, 0, 240, 180, dial);
// Draw clock hands - use default pivot point for rotations
// These sprites are twice as long as needed and pivot from the middle by default.
// But since they are transparent, it is fine.
hourhand.fillSprite(TFT_TRANSPARENT); // erase previous
hourhand.drawWedgeLine(secondhandW / 2, 0, secondhandW / 2, hourhandH / 2, 3, 4, TFT_GOLD);
hourhand.pushRotated(&dial, hourAngle, TFT_TRANSPARENT);
minutehand.fillSprite(TFT_TRANSPARENT); // erase previous
minutehand.drawWedgeLine(secondhandW / 2, 0, secondhandW / 2, minutehandH / 2, 2, 4, TFT_GOLD);
minutehand.pushRotated(&dial, minuteAngle, TFT_TRANSPARENT);
secondhand.fillSprite(TFT_TRANSPARENT); // erase previous
secondhand.drawWedgeLine(secondhandW / 2, 0, secondhandW / 2, secondhandH / 2, 1, 3, TFT_RED);
secondhand.pushRotated(&dial, secondAngle, TFT_TRANSPARENT);
// Push to TFT
dial.pushSprite(0, 0, TFT_TRANSPARENT);
// Clean up
secondhand.deleteSprite();
minutehand.deleteSprite();
hourhand.deleteSprite();
dial.deleteSprite();
*/
}
}