E-paper screens are particularly suitable for displaying content that only changes after a longer time. So I thought a clock would perfectly fit on this 3.7" E paper display.
NOTE: The software is in BETA stage and considered the first version that runs at all. I am sharing it so that you can maybe extend, improve it or use parts of it and make it compatible with a very similar project.
The display which is connected to the ESP32 via SPI Interface, is driven with the GxEPD2 library and the fonts are provided by the U8g2_for_Adafruit_GFX library whose methods work inside the picture loop (paged drawing) of GxEPD2.
The time information is received from a public ntp (network time protocol) server in the setup and then copied to the time structure (struct tm) named timeinfo in updateTime(). Admittedly I have zero knowlegde in programming and thus the synchronization of the time could be programmed much more effectively and smart. I used the strftime function to generate three strings for hour, minute and second and then converted them back to integers. Once at start the number of seconds at this moment is then subtracted from the minute the clock normally waits until it updates the time to the next minute and refreshes the display. This means assuming the time is exactly 11:11:50 the clock will only wait 10 seconds and then switches to the next minute.
This is how it looks like for the seconds:
char timeSek[3];
strftime(timeSek,3, "%S", &timeinfo);
int s = atoi(timeSek);
startMillis -= s * 1000;
Additionally the time is represented in an expression in 12 hour format (except the full hours are shown in 24h format by default). 0 o'clock and 12 o'clock are both printed as "Twelfe o'clock". Of course you have to adapt the numerals and the words in the Words(int h, int m) function to your language. In order to convert time information to a string I use sprintf() to concatenate the numerals and the other words and save them to a global char array (Would it be better to initalize this char array containing the time phrase in a scope?). The numerals however take a lot of flash size.
example:
else if (m <= 30){
sprintf(words,"%s past%s", nums[m], nums[h % 12]);
}
The actual function to show the text is very similar to the examples of the GxEPD2 library. Note that the text is always in the middle and the y-coordinate being the bottom of a character ("g" for example goes down beyond that y-coordinate). Since I have later dicided to implement that the font switches between two with diffrent sizes, depending on how long the expression of time is, the partial window will always be set to a size that covers both font sizes and the complete width of the display. As seen in showClock() I ensured that the coordinates of the partial window are a multiple of eight. I wasnt sure which coordinates have to comply with this rule, which is why I rounded all to a multiple of 8 (look at code below). The font (const uin8_t) is handed to the function void showText(char name[], const uint8_t *font) as a pointer.
Coordinate (0, 0) is in upper left corner. Y increases from top to bottom.
In showClock():
int px = rx - r;//middlepoint-radius
px = px - (px % 8);//round down to multiple of eight
int py = ry - r;
py = py - (py % 8);
int pw = r*2;pw = pw - (pw % 8) + 8 * 2;//roundupint
ph = r*2;ph = ph - (ph % 8) + 8 * 2;
If your panel does not support partial refresh change that line to display.setFullWindow(). Such full refresh happens anyway every full hour in order to clean the display.
For printing the analog Clock I used sin() and cos(). All parameters are in radial unit. For example the minute clock hand moves 1/30 π each minute which is equivalent to 6 degrees = 360deg / 60. The library makes it possible to draw the lines and the circle.
Coordinates for end of clock hands:
const float pi = PI
float ah = (float)h * 1/6.0000000 * pi + (float)m * (1/360.0000000 * pi);
float am = m * 1/30.00000000 * pi;
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));
I tried to make the showClock funtion scalable so at least to some extent you should be able to change the postion of the circular clock and the radius.
Certainly this project can be made with another e paper panel that is compatible with the GxEPD2 library.
I think the project turned out quite neatly. However there is plenty to improve in terms of software. A better solution should also feature deep sleep. In combination with the e paper tchnology which needs very littel energy the clock could run very long on battery.
I hope I was able to inspire you a little bit.
------licencing:--------------------------------------
ZinggJM
GNU Licence: See all original codes: GxEPD2: https://github.com/ZinggJM/GxEPD2 . Author of the library GxEPD2 that provides examples which were used and modified
https://github.com/ZinggJM/GxEPD2/blob/master/LICENSE
-------------------------------------------------------
Oliver Kraus
BSD Licence : See all original codes: https://github.com/olikraus/U8g2_for_Adafruit_GFX . Author of the U8g2 font library. See exact c. notices:
https://github.com/olikraus/U8g2_for_Adafruit_GFX/blob/master/LICENSE
Comments