Difference between revisions of "Internet Clock 1"
(→Internet Clock - Code 2 - 128x128) |
|||
| (33 intermediate revisions by 3 users not shown) | |||
| Line 1: | Line 1: | ||
| + | === Internet Clock === | ||
[[Ideaspark-ESP32-0.96-OLED_Board| retour]]<br> | [[Ideaspark-ESP32-0.96-OLED_Board| retour]]<br> | ||
| − | <b>Internet Clock with ESP32 & OLED 128×64 Display</b> | + | |
| + | <b>Internet Clock with ESP32 & OLED 128×64 Display</b><br> | ||
| + | Base sur le travail de Techlogics.net (Blog) basé en Inde (GMT+5:30)<br> | ||
https://techlogics.net/create-an-internet-clock-with-esp32-oled-128x64-display-live-date-time-tutorial/ | https://techlogics.net/create-an-internet-clock-with-esp32-oled-128x64-display-live-date-time-tutorial/ | ||
| − | GMT Offsets<br> | + | <b>GMT Offsets</b><br> |
https://techlogics.net/how-to-use-gmt-offsets-in-your-arduino-projects-for-accurate-time-synchronization/ | https://techlogics.net/how-to-use-gmt-offsets-in-your-arduino-projects-for-accurate-time-synchronization/ | ||
| + | |||
| + | == Internet Clock - Code 1 - == | ||
| + | |||
| + | |||
| + | [[File:Grove Base for XIAO 1.PNG|200px]] | ||
| + | [[File:XIAO-ESP32S3 1.PNG|125px]] | ||
| + | [[File:OLED Display 128x64 recto.jpg|125px]] | ||
| + | ou | ||
| + | [[File:OLED-Display-0-96-SSD1315.png|150px]] | ||
| + | |||
| + | <b>Code 1</b>✅<br> | ||
| + | Grove Base for XIAO<br> | ||
| + | XIAO-ESP32S3 <br> | ||
| + | OLED 128x64 (SSD1308), Port <b>I2c</b> ✅<br> | ||
| + | ou<br> | ||
| + | OLED 128x64 (SSD1315), Port <b>I2c</b> ✅<br> | ||
| + | |||
| + | <pre> | ||
| + | // Initialize OLED display 0.96 inches (SSD1308) (Seeed-Studio) 128×64 | ||
| + | U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // | ||
| + | </pre> | ||
<pre> | <pre> | ||
| Line 144: | Line 168: | ||
}</pre> | }</pre> | ||
| + | == Internet Clock - Code 2 - 128x64 == | ||
| + | |||
| + | Code adapté pour tenir compte du <b>daylight</b>✅<br> | ||
| − | Code | + | [[File:Grove Base for XIAO 1.PNG|200px]] |
| + | [[File:XIAO-ESP32S3 1.PNG|125px]] | ||
| + | [[File:OLED Display 128x64 recto.jpg|125px]] | ||
| + | ou | ||
| + | [[File:OLED-Display-0-96-SSD1315.png|150px]] | ||
| + | |||
| + | <b>Code 2</b>✅<br> | ||
| + | Grove Base for XIAO<br> | ||
| + | XIAO-ESP32S3 <br> | ||
| + | OLED 128x64 (SSD1308), Port <b>I2c</b> ✅<br> | ||
| + | ou<br> | ||
| + | OLED 128x64 (SSD1315), Port <b>I2c</b> ✅<br> | ||
| + | |||
| + | <pre> | ||
| + | // Initialize OLED display 0.96 inches (SSD1308) (Seeed-Studio) 128×64 | ||
| + | U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // | ||
| + | </pre> | ||
<PRE> | <PRE> | ||
| Line 232: | Line 275: | ||
</PRE> | </PRE> | ||
| − | une version daylight & une page html de configuration<br> | + | == Internet Clock - Code 2 - 128x128 == |
| + | |||
| + | <PRE> | ||
| + | // Initialize OLED constructeur **adapté au SH1107 128x128** | ||
| + | U8G2_SH1107_SEEED_128X128_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); | ||
| + | </PRE> | ||
| + | |||
| + | <PRE> | ||
| + | #include <U8g2lib.h> | ||
| + | #include <Wire.h> | ||
| + | #include <WiFi.h> | ||
| + | #include <time.h> | ||
| + | |||
| + | // WiFi credentials | ||
| + | const char* ssid = "Your_wifi_SSID"; | ||
| + | const char* password = "Wifi_password"; | ||
| + | |||
| + | // Initialize OLED constructeur **adapté au SH1107 128x128** | ||
| + | U8G2_SH1107_SEEED_128X128_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); | ||
| + | |||
| + | void setup() { | ||
| + | Serial.begin(115200); | ||
| + | |||
| + | // Connexion Wi-Fi | ||
| + | WiFi.begin(ssid, password); | ||
| + | while (WiFi.status() != WL_CONNECTED) { | ||
| + | delay(1000); | ||
| + | Serial.println("Connecting to WiFi..."); | ||
| + | } | ||
| + | Serial.println("Connected to WiFi"); | ||
| + | |||
| + | // Initialisation OLED | ||
| + | u8g2.begin(); | ||
| + | |||
| + | // Configuration NTP + fuseau horaire Europe/Zurich avec DST | ||
| + | configTime(0, 0, "pool.ntp.org", "time.nist.gov"); | ||
| + | setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1); | ||
| + | tzset(); | ||
| + | } | ||
| + | |||
| + | void loop() { | ||
| + | struct tm timeinfo; | ||
| + | if (!getLocalTime(&timeinfo)) { | ||
| + | Serial.println("Failed to obtain time"); | ||
| + | return; | ||
| + | } | ||
| + | |||
| + | // Extraction des composants | ||
| + | int hours = timeinfo.tm_hour; | ||
| + | int minutes = timeinfo.tm_min; | ||
| + | int seconds = timeinfo.tm_sec; | ||
| + | int day = timeinfo.tm_mday; | ||
| + | int month = timeinfo.tm_mon + 1; | ||
| + | int year = timeinfo.tm_year + 1900; | ||
| + | |||
| + | String daysOfWeek[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; | ||
| + | String dayOfWeek = daysOfWeek[timeinfo.tm_wday]; | ||
| + | |||
| + | // Effacer l'écran | ||
| + | u8g2.clearBuffer(); | ||
| + | |||
| + | // Heure | ||
| + | u8g2.setFont(u8g2_font_ncenB18_tr); | ||
| + | String timeStr = String(hours) + ":" + | ||
| + | (minutes < 10 ? "0" + String(minutes) : String(minutes)) + ":" + | ||
| + | (seconds < 10 ? "0" + String(seconds) : String(seconds)); | ||
| + | int textWidth = u8g2.getStrWidth(timeStr.c_str()); | ||
| + | u8g2.setCursor((128 - textWidth) / 2, 50); | ||
| + | u8g2.print(timeStr); | ||
| + | |||
| + | // Date | ||
| + | u8g2.setFont(u8g2_font_ncenB10_tr); | ||
| + | String dateStr = (day < 10 ? "0" + String(day) : String(day)) + "/" + | ||
| + | (month < 10 ? "0" + String(month) : String(month)) + "/" + | ||
| + | String(year); | ||
| + | int dateTextWidth = u8g2.getStrWidth(dateStr.c_str()); | ||
| + | u8g2.setCursor((128 - dateTextWidth) / 2, 80); | ||
| + | u8g2.print(dateStr); | ||
| + | |||
| + | // Jour de la semaine | ||
| + | int dayOfWeekWidth = u8g2.getStrWidth(dayOfWeek.c_str()); | ||
| + | u8g2.setCursor((128 - dayOfWeekWidth) / 2, 100); | ||
| + | u8g2.print(dayOfWeek); | ||
| + | |||
| + | u8g2.sendBuffer(); | ||
| + | |||
| + | delay(1000); | ||
| + | } | ||
| + | </PRE> | ||
| + | |||
| + | == Internet Clock - Code 3 - == | ||
| + | |||
| + | Oled 128X64 avec une version <b>daylight</b> & une <b>page html</b> de configuration<br> | ||
<PRE> | <PRE> | ||
| Line 404: | Line 539: | ||
</PRE> | </PRE> | ||
| + | |||
| + | == Internet Clock - Code 4 - == | ||
| + | |||
| + | Basé sur le code 3, la même version <b>daylight</b> & une <b>page html</b> de configuration mais pour un écran Oled <b>128 x 128</b><br> | ||
| + | |||
| + | <PRE> | ||
| + | #include <U8g2lib.h> | ||
| + | #include <Wire.h> | ||
| + | #include <WiFi.h> | ||
| + | #include <time.h> | ||
| + | #include <ESPAsyncWebServer.h> | ||
| + | #include <Preferences.h> | ||
| + | |||
| + | // === OLED 128x128 SH1107 === | ||
| + | U8G2_SH1107_SEEED_128X128_1_SW_I2C | ||
| + | u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); | ||
| + | |||
| + | // === Stockage paramètres === | ||
| + | Preferences prefs; | ||
| + | |||
| + | // === Variables config === | ||
| + | String wifiSSID; | ||
| + | String wifiPASS; | ||
| + | String timezone; | ||
| + | int alarmHour; | ||
| + | int alarmMinute; | ||
| + | |||
| + | // === Serveur Web === | ||
| + | AsyncWebServer server(80); | ||
| + | |||
| + | // === Page HTML === | ||
| + | const char* htmlPage PROGMEM = R"rawliteral( | ||
| + | <!DOCTYPE html> | ||
| + | <html> | ||
| + | <head><meta charset="UTF-8"><title>ESP32 Config</title></head> | ||
| + | <body> | ||
| + | <h1>Configuration ESP32</h1> | ||
| + | <form action="/save" method="GET"> | ||
| + | <label>WiFi SSID:</label><br> | ||
| + | <input type="text" name="ssid" value="%SSID%"><br> | ||
| + | <label>WiFi Password:</label><br> | ||
| + | <input type="password" name="pass" value="%PASS%"><br><br> | ||
| + | |||
| + | <label>Fuseau horaire:</label><br> | ||
| + | <select name="tz"> | ||
| + | <option value="CET-1CEST,M3.5.0,M10.5.0/3" %TZ1%>Europe/Zurich</option> | ||
| + | <option value="UTC0" %TZ2%>UTC</option> | ||
| + | </select><br><br> | ||
| + | |||
| + | <label>Heure alarme:</label><br> | ||
| + | <input type="number" name="ah" min="0" max="23" value="%AH%"> : | ||
| + | <input type="number" name="am" min="0" max="59" value="%AM%"><br><br> | ||
| + | |||
| + | <input type="submit" value="Enregistrer"> | ||
| + | </form> | ||
| + | </body> | ||
| + | </html> | ||
| + | )rawliteral"; | ||
| + | |||
| + | // Remplacement des balises %VAR% | ||
| + | String processor(const String& var) { | ||
| + | if (var == "SSID") return wifiSSID; | ||
| + | if (var == "PASS") return wifiPASS; | ||
| + | if (var == "AH") return String(alarmHour); | ||
| + | if (var == "AM") return String(alarmMinute); | ||
| + | if (var == "TZ1") return (timezone == "CET-1CEST,M3.5.0,M10.5.0/3") ? "selected" : ""; | ||
| + | if (var == "TZ2") return (timezone == "UTC0") ? "selected" : ""; | ||
| + | return String(); | ||
| + | } | ||
| + | |||
| + | void setup() { | ||
| + | Serial.begin(115200); | ||
| + | |||
| + | // Charger paramètres | ||
| + | prefs.begin("config", false); | ||
| + | wifiSSID = prefs.getString("ssid", "Your_wifi_SSID"); | ||
| + | wifiPASS = prefs.getString("pass", "Wifi_password"); | ||
| + | timezone = prefs.getString("tz", "CET-1CEST,M3.5.0,M10.5.0/3"); | ||
| + | alarmHour = prefs.getInt("ah", 7); | ||
| + | alarmMinute = prefs.getInt("am", 0); | ||
| + | |||
| + | // Connexion Wi-Fi | ||
| + | WiFi.begin(wifiSSID.c_str(), wifiPASS.c_str()); | ||
| + | if (WiFi.waitForConnectResult() != WL_CONNECTED) { | ||
| + | Serial.println("WiFi non trouvé, démarrage en AP..."); | ||
| + | WiFi.softAP("ESP32_Config", "12345678"); | ||
| + | } else { | ||
| + | Serial.println("Connecté au WiFi"); | ||
| + | } | ||
| + | |||
| + | // Serveur Web | ||
| + | server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ | ||
| + | request->send_P(200, "text/html", htmlPage, processor); | ||
| + | }); | ||
| + | |||
| + | server.on("/save", HTTP_GET, [](AsyncWebServerRequest *request){ | ||
| + | if (request->hasParam("ssid")) wifiSSID = request->getParam("ssid")->value(); | ||
| + | if (request->hasParam("pass")) wifiPASS = request->getParam("pass")->value(); | ||
| + | if (request->hasParam("tz")) timezone = request->getParam("tz")->value(); | ||
| + | if (request->hasParam("ah")) alarmHour = request->getParam("ah")->value().toInt(); | ||
| + | if (request->hasParam("am")) alarmMinute = request->getParam("am")->value().toInt(); | ||
| + | |||
| + | prefs.putString("ssid", wifiSSID); | ||
| + | prefs.putString("pass", wifiPASS); | ||
| + | prefs.putString("tz", timezone); | ||
| + | prefs.putInt("ah", alarmHour); | ||
| + | prefs.putInt("am", alarmMinute); | ||
| + | |||
| + | request->send(200, "text/html", "<h1>Paramètres enregistrés. Redémarrage...</h1>"); | ||
| + | delay(2000); | ||
| + | ESP.restart(); | ||
| + | }); | ||
| + | |||
| + | server.begin(); | ||
| + | |||
| + | // Initialisation OLED | ||
| + | u8g2.begin(); | ||
| + | |||
| + | // Config NTP avec fuseau horaire choisi | ||
| + | configTime(0, 0, "pool.ntp.org", "time.nist.gov"); | ||
| + | setenv("TZ", timezone.c_str(), 1); | ||
| + | tzset(); | ||
| + | } | ||
| + | |||
| + | void loop() { | ||
| + | struct tm timeinfo; | ||
| + | if (!getLocalTime(&timeinfo)) { | ||
| + | Serial.println("Impossible d'obtenir l'heure"); | ||
| + | return; | ||
| + | } | ||
| + | |||
| + | // Extraction | ||
| + | int hours = timeinfo.tm_hour; | ||
| + | int minutes = timeinfo.tm_min; | ||
| + | int seconds = timeinfo.tm_sec; | ||
| + | int day = timeinfo.tm_mday; | ||
| + | int month = timeinfo.tm_mon + 1; | ||
| + | int year = timeinfo.tm_year + 1900; | ||
| + | String daysOfWeek[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; | ||
| + | String dayOfWeek = daysOfWeek[timeinfo.tm_wday]; | ||
| + | |||
| + | // Affichage OLED 128x128 | ||
| + | u8g2.clearBuffer(); | ||
| + | |||
| + | // Heure (plus grande police) | ||
| + | u8g2.setFont(u8g2_font_fub30_tr); // Police large pour 128x128 | ||
| + | String timeStr = String(hours) + ":" + | ||
| + | (minutes < 10 ? "0" + String(minutes) : String(minutes)); | ||
| + | int textWidth = u8g2.getStrWidth(timeStr.c_str()); | ||
| + | u8g2.setCursor((128 - textWidth) / 2, 50); | ||
| + | u8g2.print(timeStr); | ||
| + | |||
| + | // Secondes plus petites à côté | ||
| + | u8g2.setFont(u8g2_font_fub14_tr); | ||
| + | String secStr = (seconds < 10 ? "0" + String(seconds) : String(seconds)); | ||
| + | u8g2.setCursor((128 - textWidth) / 2 + textWidth + 4, 50); | ||
| + | u8g2.print(secStr); | ||
| + | |||
| + | // Date | ||
| + | u8g2.setFont(u8g2_font_ncenB14_tr); | ||
| + | String dateStr = (day < 10 ? "0" + String(day) : String(day)) + "/" + | ||
| + | (month < 10 ? "0" + String(month) : String(month)) + "/" + | ||
| + | String(year); | ||
| + | int dateTextWidth = u8g2.getStrWidth(dateStr.c_str()); | ||
| + | u8g2.setCursor((128 - dateTextWidth) / 2, 80); | ||
| + | u8g2.print(dateStr); | ||
| + | |||
| + | // Jour de la semaine | ||
| + | int dayOfWeekWidth = u8g2.getStrWidth(dayOfWeek.c_str()); | ||
| + | u8g2.setCursor((128 - dayOfWeekWidth) / 2, 100); | ||
| + | u8g2.print(dayOfWeek); | ||
| + | |||
| + | u8g2.sendBuffer(); | ||
| + | |||
| + | // Déclenchement alarme | ||
| + | if (hours == alarmHour && minutes == alarmMinute && seconds == 0) { | ||
| + | Serial.println("ALARM!"); | ||
| + | // Ici tu peux activer un buzzer ou LED | ||
| + | } | ||
| + | |||
| + | delay(1000); | ||
| + | } | ||
| + | |||
| + | </PRE> | ||
| + | |||
| + | == Internet Clock - Code 5 - == | ||
| + | |||
| + | avec 128x128 | ||
Latest revision as of 22:18, 24 September 2025
Contents
Internet Clock[edit]
Internet Clock with ESP32 & OLED 128×64 Display
Base sur le travail de Techlogics.net (Blog) basé en Inde (GMT+5:30)
GMT Offsets
https://techlogics.net/how-to-use-gmt-offsets-in-your-arduino-projects-for-accurate-time-synchronization/
Internet Clock - Code 1 -[edit]
Code 1✅
Grove Base for XIAO
XIAO-ESP32S3
OLED 128x64 (SSD1308), Port I2c ✅
ou
OLED 128x64 (SSD1315), Port I2c ✅
// Initialize OLED display 0.96 inches (SSD1308) (Seeed-Studio) 128×64 U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); //
#include <U8g2lib.h>
#include <Wire.h>
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <time.h>
// Replace with your WiFi credentials
const char* ssid = "Your_wifi_SSID";
const char* password = "Wifi_password";
// Initialize OLED display (128x128 SH1107)
// U8G2_SH1107_SEEED_128X128_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);
// Initialize OLED display (128x64 SH1106)
// U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
// Initialize OLED display (128x64 SSD1306) Ideaspark ESP32 0,96 OLED Board
U8G2_SSD1306_128X64_NONAME_F_SW_I2C
u8g2(U8G2_R0, /* clock=*/ 22, /* data=*/ 21, /* reset=*/ U8X8_PIN_NONE);
// NTP Client Setup
WiFiUDP ntpUDP;
// NTPClient timeClient(ntpUDP, "pool.ntp.org", 19800, 3600000); // Timezone offset (19800 seconds = UTC +5:30) Colombo
NTPClient timeClient(ntpUDP, "pool.ntp.org", 3600, 3600000); // Timezone offset (3600 seconds = UTC +1:00) Zurich
void setup() {
// Start serial communication for debugging
Serial.begin(115200);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Initialize the OLED
u8g2.begin();
// Start the NTP client
timeClient.begin();
//timeClient.setTimeOffset(19800); // Indian Standard Time colombo (UTC +5:30)
timeClient.setTimeOffset(3600); // Europe Standard Time Zurich (UTC +1:00)
}
void loop() {
timeClient.update(); // Update time from NTP server
// Get current time in seconds
unsigned long currentEpoch = timeClient.getEpochTime();
// Convert epoch time (unsigned long) to time_t (signed long)
time_t currentTime = (time_t)currentEpoch;
// Convert time to time structure
struct tm* timeInfo;
timeInfo = localtime(¤tTime); // Convert to time structure
// Extract time components
int hours = timeInfo->tm_hour;
int minutes = timeInfo->tm_min;
int seconds = timeInfo->tm_sec;
// Extract date components
int day = timeInfo->tm_mday;
int month = timeInfo->tm_mon + 1; // tm_mon is zero-based, so add 1
int year = timeInfo->tm_year + 1900; // tm_year is years since 1900, so add 1900
// Extract day of the week (0 = Sunday, 1 = Monday, etc.)
String daysOfWeek[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
String dayOfWeek = daysOfWeek[timeInfo->tm_wday];
// Clear the display
u8g2.clearBuffer();
// Set font size for the clock
u8g2.setFont(u8g2_font_ncenB18_tr); // Larger font (18px)
// Format the time
String timeStr = String(hours) + ":" + (minutes < 10 ? "0" + String(minutes) : String(minutes)) + ":" + (seconds < 10 ? "0" + String(seconds) : String(seconds));
// Calculate the width of the time text to center it
int textWidth = u8g2.getStrWidth(timeStr.c_str());
// Set the cursor position to center the time text
int x = (128 - textWidth) / 2; // Center horizontally on 128x64 screen
int y = 24; // Set Y position to the middle of the screen for time
// Draw the time at the center of the screen
u8g2.setCursor(x, y);
u8g2.print(timeStr);
// Set font size for the date
u8g2.setFont(u8g2_font_ncenB10_tr); // Smaller font (10px) for the date
// Format the date as DD/MM/YYYY with leading zeroes if necessary
String dayStr = (day < 10) ? "0" + String(day) : String(day);
String monthStr = (month < 10) ? "0" + String(month) : String(month);
String dateStr = dayStr + "/" + monthStr + "/" + String(year);
// Calculate the width of the date text to center it
int dateTextWidth = u8g2.getStrWidth(dateStr.c_str());
// Set the cursor position to center the date text
int dateX = (128 - dateTextWidth) / 2; // Center horizontally
int dateY = 40; // Move the date 2px up from the previous position
// Draw the date below the time
u8g2.setCursor(dateX, dateY);
u8g2.print(dateStr);
// Set font size for the day of the week
u8g2.setFont(u8g2_font_ncenB10_tr); // Smaller font (10px) for the day of the week
// Calculate the width of the day of the week text to center it
int dayOfWeekWidth = u8g2.getStrWidth(dayOfWeek.c_str());
// Set the cursor position to center the day of the week text
int dayOfWeekX = (128 - dayOfWeekWidth) / 2; // Center horizontally
int dayOfWeekY = 56; // Set Y position below the date text
// Draw the day of the week below the date
u8g2.setCursor(dayOfWeekX, dayOfWeekY);
u8g2.print(dayOfWeek);
// Send the buffer to the display
u8g2.sendBuffer();
delay(1000); // Update every second
}
Internet Clock - Code 2 - 128x64[edit]
Code adapté pour tenir compte du daylight✅
Code 2✅
Grove Base for XIAO
XIAO-ESP32S3
OLED 128x64 (SSD1308), Port I2c ✅
ou
OLED 128x64 (SSD1315), Port I2c ✅
// Initialize OLED display 0.96 inches (SSD1308) (Seeed-Studio) 128×64 U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); //
#include <U8g2lib.h>
#include <Wire.h>
#include <WiFi.h>
#include <time.h>
// WiFi credentials
const char* ssid = "Your_wifi_SSID";
const char* password = "Wifi_password";
// OLED display (SSD1306 128x64)
U8G2_SSD1306_128X64_NONAME_F_SW_I2C
u8g2(U8G2_R0, /* clock=*/ 22, /* data=*/ 21, /* reset=*/ U8X8_PIN_NONE);
void setup() {
Serial.begin(115200);
// Connexion Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Initialisation OLED
u8g2.begin();
// Configuration NTP + fuseau horaire Europe/Zurich avec DST
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1);
tzset();
}
void loop() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return;
}
// Extraction des composants
int hours = timeinfo.tm_hour;
int minutes = timeinfo.tm_min;
int seconds = timeinfo.tm_sec;
int day = timeinfo.tm_mday;
int month = timeinfo.tm_mon + 1;
int year = timeinfo.tm_year + 1900;
String daysOfWeek[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
String dayOfWeek = daysOfWeek[timeinfo.tm_wday];
// Effacer l'écran
u8g2.clearBuffer();
// Heure
u8g2.setFont(u8g2_font_ncenB18_tr);
String timeStr = String(hours) + ":" +
(minutes < 10 ? "0" + String(minutes) : String(minutes)) + ":" +
(seconds < 10 ? "0" + String(seconds) : String(seconds));
int textWidth = u8g2.getStrWidth(timeStr.c_str());
u8g2.setCursor((128 - textWidth) / 2, 24);
u8g2.print(timeStr);
// Date
u8g2.setFont(u8g2_font_ncenB10_tr);
String dateStr = (day < 10 ? "0" + String(day) : String(day)) + "/" +
(month < 10 ? "0" + String(month) : String(month)) + "/" +
String(year);
int dateTextWidth = u8g2.getStrWidth(dateStr.c_str());
u8g2.setCursor((128 - dateTextWidth) / 2, 40);
u8g2.print(dateStr);
// Jour de la semaine
int dayOfWeekWidth = u8g2.getStrWidth(dayOfWeek.c_str());
u8g2.setCursor((128 - dayOfWeekWidth) / 2, 56);
u8g2.print(dayOfWeek);
u8g2.sendBuffer();
delay(1000);
}
Internet Clock - Code 2 - 128x128[edit]
// Initialize OLED constructeur **adapté au SH1107 128x128** U8G2_SH1107_SEEED_128X128_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
#include <U8g2lib.h>
#include <Wire.h>
#include <WiFi.h>
#include <time.h>
// WiFi credentials
const char* ssid = "Your_wifi_SSID";
const char* password = "Wifi_password";
// Initialize OLED constructeur **adapté au SH1107 128x128**
U8G2_SH1107_SEEED_128X128_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
void setup() {
Serial.begin(115200);
// Connexion Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Initialisation OLED
u8g2.begin();
// Configuration NTP + fuseau horaire Europe/Zurich avec DST
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1);
tzset();
}
void loop() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return;
}
// Extraction des composants
int hours = timeinfo.tm_hour;
int minutes = timeinfo.tm_min;
int seconds = timeinfo.tm_sec;
int day = timeinfo.tm_mday;
int month = timeinfo.tm_mon + 1;
int year = timeinfo.tm_year + 1900;
String daysOfWeek[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
String dayOfWeek = daysOfWeek[timeinfo.tm_wday];
// Effacer l'écran
u8g2.clearBuffer();
// Heure
u8g2.setFont(u8g2_font_ncenB18_tr);
String timeStr = String(hours) + ":" +
(minutes < 10 ? "0" + String(minutes) : String(minutes)) + ":" +
(seconds < 10 ? "0" + String(seconds) : String(seconds));
int textWidth = u8g2.getStrWidth(timeStr.c_str());
u8g2.setCursor((128 - textWidth) / 2, 50);
u8g2.print(timeStr);
// Date
u8g2.setFont(u8g2_font_ncenB10_tr);
String dateStr = (day < 10 ? "0" + String(day) : String(day)) + "/" +
(month < 10 ? "0" + String(month) : String(month)) + "/" +
String(year);
int dateTextWidth = u8g2.getStrWidth(dateStr.c_str());
u8g2.setCursor((128 - dateTextWidth) / 2, 80);
u8g2.print(dateStr);
// Jour de la semaine
int dayOfWeekWidth = u8g2.getStrWidth(dayOfWeek.c_str());
u8g2.setCursor((128 - dayOfWeekWidth) / 2, 100);
u8g2.print(dayOfWeek);
u8g2.sendBuffer();
delay(1000);
}
Internet Clock - Code 3 -[edit]
Oled 128X64 avec une version daylight & une page html de configuration
#include <U8g2lib.h>
#include <Wire.h>
#include <WiFi.h>
#include <time.h>
#include <ESPAsyncWebServer.h>
#include <Preferences.h>
// === OLED ===
U8G2_SSD1306_128X64_NONAME_F_SW_I2C
u8g2(U8G2_R0, /* clock=*/ 22, /* data=*/ 21, /* reset=*/ U8X8_PIN_NONE);
// === Stockage paramètres ===
Preferences prefs;
// === Variables config ===
String wifiSSID;
String wifiPASS;
String timezone;
int alarmHour;
int alarmMinute;
// === Serveur Web ===
AsyncWebServer server(80);
// === Page HTML ===
const char* htmlPage PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>ESP32 Config</title></head>
<body>
<h1>Configuration ESP32</h1>
<form action="/save" method="GET">
<label>WiFi SSID:</label><br>
<input type="text" name="ssid" value="%SSID%"><br>
<label>WiFi Password:</label><br>
<input type="password" name="pass" value="%PASS%"><br><br>
<label>Fuseau horaire:</label><br>
<select name="tz">
<option value="CET-1CEST,M3.5.0,M10.5.0/3" %TZ1%>Europe/Zurich</option>
<option value="UTC0" %TZ2%>UTC</option>
</select><br><br>
<label>Heure alarme:</label><br>
<input type="number" name="ah" min="0" max="23" value="%AH%"> :
<input type="number" name="am" min="0" max="59" value="%AM%"><br><br>
<input type="submit" value="Enregistrer">
</form>
</body>
</html>
)rawliteral";
// Remplacement des balises %VAR%
String processor(const String& var) {
if (var == "SSID") return wifiSSID;
if (var == "PASS") return wifiPASS;
if (var == "AH") return String(alarmHour);
if (var == "AM") return String(alarmMinute);
if (var == "TZ1") return (timezone == "CET-1CEST,M3.5.0,M10.5.0/3") ? "selected" : "";
if (var == "TZ2") return (timezone == "UTC0") ? "selected" : "";
return String();
}
void setup() {
Serial.begin(115200);
// Charger paramètres
prefs.begin("config", false);
wifiSSID = prefs.getString("ssid", "Your_wifi_SSID");
wifiPASS = prefs.getString("pass", "Wifi_password");
timezone = prefs.getString("tz", "CET-1CEST,M3.5.0,M10.5.0/3");
alarmHour = prefs.getInt("ah", 7);
alarmMinute = prefs.getInt("am", 0);
// Connexion Wi-Fi
WiFi.begin(wifiSSID.c_str(), wifiPASS.c_str());
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi non trouvé, démarrage en AP...");
WiFi.softAP("ESP32_Config", "12345678");
} else {
Serial.println("Connecté au WiFi");
}
// Serveur Web
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", htmlPage, processor);
});
server.on("/save", HTTP_GET, [](AsyncWebServerRequest *request){
if (request->hasParam("ssid")) wifiSSID = request->getParam("ssid")->value();
if (request->hasParam("pass")) wifiPASS = request->getParam("pass")->value();
if (request->hasParam("tz")) timezone = request->getParam("tz")->value();
if (request->hasParam("ah")) alarmHour = request->getParam("ah")->value().toInt();
if (request->hasParam("am")) alarmMinute = request->getParam("am")->value().toInt();
prefs.putString("ssid", wifiSSID);
prefs.putString("pass", wifiPASS);
prefs.putString("tz", timezone);
prefs.putInt("ah", alarmHour);
prefs.putInt("am", alarmMinute);
request->send(200, "text/html", "<h1>Paramètres enregistrés. Redémarrage...</h1>");
delay(2000);
ESP.restart();
});
server.begin();
// Initialisation OLED
u8g2.begin();
// Config NTP avec fuseau horaire choisi
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
setenv("TZ", timezone.c_str(), 1);
tzset();
}
void loop() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Impossible d'obtenir l'heure");
return;
}
// Extraction
int hours = timeinfo.tm_hour;
int minutes = timeinfo.tm_min;
int seconds = timeinfo.tm_sec;
int day = timeinfo.tm_mday;
int month = timeinfo.tm_mon + 1;
int year = timeinfo.tm_year + 1900;
String daysOfWeek[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
String dayOfWeek = daysOfWeek[timeinfo.tm_wday];
// Affichage OLED
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB18_tr);
String timeStr = String(hours) + ":" +
(minutes < 10 ? "0" + String(minutes) : String(minutes)) + ":" +
(seconds < 10 ? "0" + String(seconds) : String(seconds));
int textWidth = u8g2.getStrWidth(timeStr.c_str());
u8g2.setCursor((128 - textWidth) / 2, 24);
u8g2.print(timeStr);
u8g2.setFont(u8g2_font_ncenB10_tr);
String dateStr = (day < 10 ? "0" + String(day) : String(day)) + "/" +
(month < 10 ? "0" + String(month) : String(month)) + "/" +
String(year);
int dateTextWidth = u8g2.getStrWidth(dateStr.c_str());
u8g2.setCursor((128 - dateTextWidth) / 2, 40);
u8g2.print(dateStr);
int dayOfWeekWidth = u8g2.getStrWidth(dayOfWeek.c_str());
u8g2.setCursor((128 - dayOfWeekWidth) / 2, 56);
u8g2.print(dayOfWeek);
u8g2.sendBuffer();
// Exemple : déclenchement alarme
if (hours == alarmHour && minutes == alarmMinute && seconds == 0) {
Serial.println("ALARM!");
// Ici tu peux activer un buzzer ou LED
}
delay(1000);
}
Internet Clock - Code 4 -[edit]
Basé sur le code 3, la même version daylight & une page html de configuration mais pour un écran Oled 128 x 128
#include <U8g2lib.h>
#include <Wire.h>
#include <WiFi.h>
#include <time.h>
#include <ESPAsyncWebServer.h>
#include <Preferences.h>
// === OLED 128x128 SH1107 ===
U8G2_SH1107_SEEED_128X128_1_SW_I2C
u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);
// === Stockage paramètres ===
Preferences prefs;
// === Variables config ===
String wifiSSID;
String wifiPASS;
String timezone;
int alarmHour;
int alarmMinute;
// === Serveur Web ===
AsyncWebServer server(80);
// === Page HTML ===
const char* htmlPage PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>ESP32 Config</title></head>
<body>
<h1>Configuration ESP32</h1>
<form action="/save" method="GET">
<label>WiFi SSID:</label><br>
<input type="text" name="ssid" value="%SSID%"><br>
<label>WiFi Password:</label><br>
<input type="password" name="pass" value="%PASS%"><br><br>
<label>Fuseau horaire:</label><br>
<select name="tz">
<option value="CET-1CEST,M3.5.0,M10.5.0/3" %TZ1%>Europe/Zurich</option>
<option value="UTC0" %TZ2%>UTC</option>
</select><br><br>
<label>Heure alarme:</label><br>
<input type="number" name="ah" min="0" max="23" value="%AH%"> :
<input type="number" name="am" min="0" max="59" value="%AM%"><br><br>
<input type="submit" value="Enregistrer">
</form>
</body>
</html>
)rawliteral";
// Remplacement des balises %VAR%
String processor(const String& var) {
if (var == "SSID") return wifiSSID;
if (var == "PASS") return wifiPASS;
if (var == "AH") return String(alarmHour);
if (var == "AM") return String(alarmMinute);
if (var == "TZ1") return (timezone == "CET-1CEST,M3.5.0,M10.5.0/3") ? "selected" : "";
if (var == "TZ2") return (timezone == "UTC0") ? "selected" : "";
return String();
}
void setup() {
Serial.begin(115200);
// Charger paramètres
prefs.begin("config", false);
wifiSSID = prefs.getString("ssid", "Your_wifi_SSID");
wifiPASS = prefs.getString("pass", "Wifi_password");
timezone = prefs.getString("tz", "CET-1CEST,M3.5.0,M10.5.0/3");
alarmHour = prefs.getInt("ah", 7);
alarmMinute = prefs.getInt("am", 0);
// Connexion Wi-Fi
WiFi.begin(wifiSSID.c_str(), wifiPASS.c_str());
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi non trouvé, démarrage en AP...");
WiFi.softAP("ESP32_Config", "12345678");
} else {
Serial.println("Connecté au WiFi");
}
// Serveur Web
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", htmlPage, processor);
});
server.on("/save", HTTP_GET, [](AsyncWebServerRequest *request){
if (request->hasParam("ssid")) wifiSSID = request->getParam("ssid")->value();
if (request->hasParam("pass")) wifiPASS = request->getParam("pass")->value();
if (request->hasParam("tz")) timezone = request->getParam("tz")->value();
if (request->hasParam("ah")) alarmHour = request->getParam("ah")->value().toInt();
if (request->hasParam("am")) alarmMinute = request->getParam("am")->value().toInt();
prefs.putString("ssid", wifiSSID);
prefs.putString("pass", wifiPASS);
prefs.putString("tz", timezone);
prefs.putInt("ah", alarmHour);
prefs.putInt("am", alarmMinute);
request->send(200, "text/html", "<h1>Paramètres enregistrés. Redémarrage...</h1>");
delay(2000);
ESP.restart();
});
server.begin();
// Initialisation OLED
u8g2.begin();
// Config NTP avec fuseau horaire choisi
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
setenv("TZ", timezone.c_str(), 1);
tzset();
}
void loop() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Impossible d'obtenir l'heure");
return;
}
// Extraction
int hours = timeinfo.tm_hour;
int minutes = timeinfo.tm_min;
int seconds = timeinfo.tm_sec;
int day = timeinfo.tm_mday;
int month = timeinfo.tm_mon + 1;
int year = timeinfo.tm_year + 1900;
String daysOfWeek[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
String dayOfWeek = daysOfWeek[timeinfo.tm_wday];
// Affichage OLED 128x128
u8g2.clearBuffer();
// Heure (plus grande police)
u8g2.setFont(u8g2_font_fub30_tr); // Police large pour 128x128
String timeStr = String(hours) + ":" +
(minutes < 10 ? "0" + String(minutes) : String(minutes));
int textWidth = u8g2.getStrWidth(timeStr.c_str());
u8g2.setCursor((128 - textWidth) / 2, 50);
u8g2.print(timeStr);
// Secondes plus petites à côté
u8g2.setFont(u8g2_font_fub14_tr);
String secStr = (seconds < 10 ? "0" + String(seconds) : String(seconds));
u8g2.setCursor((128 - textWidth) / 2 + textWidth + 4, 50);
u8g2.print(secStr);
// Date
u8g2.setFont(u8g2_font_ncenB14_tr);
String dateStr = (day < 10 ? "0" + String(day) : String(day)) + "/" +
(month < 10 ? "0" + String(month) : String(month)) + "/" +
String(year);
int dateTextWidth = u8g2.getStrWidth(dateStr.c_str());
u8g2.setCursor((128 - dateTextWidth) / 2, 80);
u8g2.print(dateStr);
// Jour de la semaine
int dayOfWeekWidth = u8g2.getStrWidth(dayOfWeek.c_str());
u8g2.setCursor((128 - dayOfWeekWidth) / 2, 100);
u8g2.print(dayOfWeek);
u8g2.sendBuffer();
// Déclenchement alarme
if (hours == alarmHour && minutes == alarmMinute && seconds == 0) {
Serial.println("ALARM!");
// Ici tu peux activer un buzzer ou LED
}
delay(1000);
}
Internet Clock - Code 5 -[edit]
avec 128x128