trialrunner
Published © GPL3+

Simple fine-drawn analog and word CLOCK ON E-PAPER

3.7" E paper shows time synchronized at powerup in the style of an analog clock as well as of the corresponding group of words.

IntermediateShowcase (no instructions)910
Simple fine-drawn analog and word CLOCK ON E-PAPER

Things used in this project

Hardware components

ESP32
Espressif ESP32
ESP8266 works as well. Flash size of Arduino UNO may not be sufficient
×1
Jumper wires (generic)
Jumper wires (generic)
×8
Arduino Mega 2560
Arduino Mega 2560
could be used too
×1

Story

Read more

Schematics

suggested wiring link

suggested wiring for using GxEPD2

Code

paperlikeClock

C/C++
code depends on libraries. flash it onto your esp
#include <Arduino.h>
char words[35];

const char nums[][31] = {"Zwölf", "Eins", "Zwei", "Drei", "Vier",
                         "Fünf", "Sechs", "Sieben", "Acht", "Neun",
                         "Zehn", "Elf", "Zwölf", "Dreizehn",
                         "Vierzehn", "Fünfzehn", "Sechzehn", "Siebzehn",
                         "Achtzehn", "Neunzehn", "Zwanzig", "Einundzwanzig",
                         "Zweiundzwanzig", "Dreiundzwanzig", "Vierundzwanzig",
                         "Fünfundzwanzig", "Sechsundzwanzig", "Siebenundzwanzig",
                         "Achtundzwanzig", "Neunundzwanzig"};

#define ENABLE_GxEPD2_GFX 0

#include <GxEPD2_BW.h>

#include <U8g2_for_Adafruit_GFX.h>

GxEPD2_BW<GxEPD2_370_TC1, GxEPD2_370_TC1::HEIGHT> display(GxEPD2_370_TC1(/*CS=5*/ SS, /*DC=*/17, /*RST=*/16, /*BUSY=*/4)); // ED037TC1, Waveshare 3.7"
#define MAX_DISPLAY_BUFFER_SIZE 65536ul                                                                                    // e.g.

U8G2_FOR_ADAFRUIT_GFX u8g2Fonts;

int h;
int m;
int startMillis;
bool nurEinmal;

const float pi = 3.14159265359;

///////////////////////////////
#include <WiFi.h>
#include "time.h"

const char *ssid = "WLAN_919280";
const char *password = "CimaBrenta2022!%";

const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 3600;
const int daylightOffset_sec = 3600;
///////////////////////////////////

void updateTime()
{
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo))
  {
    Serial.println("Failed to obtain time");
    return;
  }
  char timeHour[3];
  strftime(timeHour, 3, "%H", &timeinfo);
  h = atoi(timeHour);
  Serial.println("----Update-Time----");
  Serial.println(h);
  char timeMinute[3];
  strftime(timeMinute, 3, "%M", &timeinfo);
  m = atoi(timeMinute);
  Serial.println(m);
  Serial.println("------STATUS------");
  Serial.println(WiFi.status() != WL_CONNECTED ? "CONNECTED" : "DISCONNECTED");
  Serial.println("------------------");
  if (nurEinmal)
  {
    char timeSek[3];
    strftime(timeSek, 3, "%S", &timeinfo);
    int s = atoi(timeSek);
    startMillis -= s * 1000;
  }
}

void showText(char name[], const uint8_t *font)
{

  uint16_t bg = GxEPD_WHITE;
  uint16_t fg = GxEPD_BLACK;
  u8g2Fonts.setFontMode(1);
  u8g2Fonts.setFontDirection(0);
  u8g2Fonts.setForegroundColor(fg);
  u8g2Fonts.setBackgroundColor(bg);
  u8g2Fonts.setFont(font);
  int16_t tw = u8g2Fonts.getUTF8Width(name);
  // int16_t ta = u8g2Fonts.getFontAscent();
  // int16_t td = u8g2Fonts.getFontDescent();
  // int16_t th = ta - td;
  uint16_t x = (display.width() - tw) / 2;
  uint16_t y = 40;

  display.setPartialWindow(0, y - 35 + 2, display.width(), 35 + 8);
  display.firstPage();
  do
  {
    display.fillScreen(bg);
    // display.drawLine(x,y, x,y+16, GxEPD_BLACK);
    u8g2Fonts.setCursor(x, y);
    u8g2Fonts.print(name);
  } while (display.nextPage());
}

void hlines(int r, int rx, int ry)
{
  for (int h = 0; h < 12; h++)
  {
    float ah = (float)h * 1 / 6.0000000 * pi;
    int shx1 = round(sin(ah) * ((float)r - 5));
    int shy1 = round(cos(ah) * ((float)r - 5));
    int shx2 = round(sin(ah) * ((float)r + 1));
    int shy2 = round(cos(ah) * ((float)r + 1));
    display.drawLine(rx + shx1, ry - shy1, rx + shx2, ry - shy2, GxEPD_BLACK);
  }
  /*
  for(int m = 0; h < 60; m++){
    float am = m * 1/30.00000000 * pi;
    int shx1 = round(sin(am) * ((float)r-4));
    int shy1 = round(cos(am) * ((float)r-4));
    int shx2 = round(sin(am) * ((float)r+0));
    int shy2 = round(cos(am) * ((float)r+0));
    display.drawLine(rx + shx1,ry - shy1, rx + shx2, ry - shy2 , GxEPD_BLACK);
  }
  */
}

void showClock(int h, int m, int rx, int ry, int r)
{
  h = h % 12;

  float ah = (float)h * 1 / 6.0000000 * pi + (float)m * (1 / 360.0000000 * pi);
  float am = m * 1 / 30.00000000 * pi;
  // ah = pi/2.0000;
  // am = 0;

  int shx = round(sin(ah) * ((float)r - 8) / 1.600);
  int shy = round(cos(ah) * ((float)r - 8) / 1.600);
  int smx = round(sin(am) * ((float)r - 8));
  int smy = round(cos(am) * ((float)r - 8));

  // Serial.println(shx);
  // Serial.println(shy);
  // Serial.println(smx);
  // Serial.println(smy);

  int px = rx - r;
  px = px - (px % 8);
  int py = ry - r;
  py = py - (py % 8);
  int pw = r * 2;
  pw = pw - (pw % 8) + 8 * 2;
  int ph = r * 2;
  ph = ph - (ph % 8) + 8 * 2;

  display.setPartialWindow(px, py, pw, ph);
  display.firstPage();
  do
  {
    display.fillScreen(GxEPD_WHITE);
    display.drawCircle(rx, ry, r, GxEPD_BLACK);
    hlines(r, rx, ry);
    display.drawLine(rx, ry, rx + shx, ry - shy, GxEPD_BLACK);
    display.drawLine(rx, ry, rx + smx, ry - smy, GxEPD_BLACK);
  } while (display.nextPage());
}

void Words(int h, int m)
{
  h = h % 24;
  m = m % 60;

  for (int i = 0; i < sizeof(words); i++)
  {
    words[i] = 0;
  }

  if (m == 0)
  {
    display.setFullWindow();
    display.firstPage();
    do
    {
      display.fillScreen(GxEPD_WHITE);

    } while (display.nextPage());

    if (h == 1)
    {
      sprintf(words, "%s Uhr", "Ein");
    }
    else
    {
      sprintf(words, "%s Uhr", nums[h]);
    }
  }
  else if (m == 1)
  {
    sprintf(words, "eine Minute nach %s", nums[h % 12]);
  }
  else if (m == 59)
  {
    sprintf(words, "EINE Minute vor %s", nums[(h % 12) + 1]);
  }
  else if (m == 15)
  {
    sprintf(words, "Viertel nach %s", nums[(h % 12)]);
  }
  else if (m == 30)
  {
    sprintf(words, "Halb %s", nums[(h % 12) + 1]);
  }
  else if (m == 45)
  {
    sprintf(words, "Viertel vor %s", nums[(h % 12) + 1]);
  }
  else if (m <= 30)
  {
    sprintf(words, "%s nach %s", nums[m], nums[h % 12]);
  }
  else if (m > 30)
  {
    sprintf(words, "%s vor %s", nums[60 - m], nums[(h % 12) + 1]);
  }
}

int countChars()
{
  int len = sizeof(words);
  int count = 0;
  for (int i = 0; i < len; i++)
  {
    if (words[i] > 0)
    {
      Serial.print("Buchstaben: ");
      Serial.println(words[i]);
      count++;
    }
  }
  return count;
}

void setup()
{
  Serial.begin(9600);
  Serial.println();

  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");

  // Init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  nurEinmal = true;
  updateTime();
  nurEinmal = false;
  Serial.print("StartMillis: ");
  Serial.println(startMillis);
  Serial.print("Millis: ");
  Serial.println(millis());

  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);

  Serial.println("setup");
  display.init();
  display.setRotation(1);
  display.setTextWrap(true);
  u8g2Fonts.begin(display);

  delay(50);
  Serial.println("setup done");

  Words(h, m);
  showText(words, u8g2_font_timB24_tf);
  showClock(h, m, 240, 167, 110);
  delay(1000);
}

void loop()
{
  if (millis() - startMillis >= 59999)
  {
    startMillis = millis();

    m++;
    m = m % 60;
    if (m == 0)
    {
      h++;
      h = h % 24;
    }
    delay(50);
    Words(h, m);
    int si = countChars();
    Serial.print("nr of chars in words = ");
    Serial.println(si);
    if (si > 20)
    {
      showText(words, u8g2_font_timB24_tf);
    }
    else
    {
      showText(words, u8g2_font_osb35_tf);
    }
    showClock(h, m, 240, 167, 110);
    delay(1000);
  }
}

Credits

trialrunner

trialrunner

0 projects • 0 followers

Comments