initial commit calendar face #16

pull/1/head
Thomas Ballmann 4 years ago
parent fd43996364
commit 0f29a82542

@ -2,23 +2,19 @@
#define DATETIME_H
#include <arduino.h>
#include <time.h>
// TODO
struct time_struct
// @see http://www.cplusplus.com/reference/ctime/tm/
// @see http://www.cplusplus.com/reference/ctime/strftime/
struct datetime_struct : tm
{
char wday[4];
char month[4];
uint8_t month_num;
uint8_t mday;
uint8_t mil_hour;
uint8_t hour;
uint8_t min;
uint8_t sec;
uint8_t day_offset; // 1st day of the month offset, Monday = 0
int year;
uint8_t days_in_month;
};
extern RTC_DATA_ATTR struct time_struct now;
extern RTC_DATA_ATTR struct datetime_struct now;
void setupDateTime();

@ -3,100 +3,49 @@
#include <sys/time.h>
#include "datetime.h"
RTC_DATA_ATTR struct time_struct now; // keep track of time
//String time_zone_base = "UTC";
RTC_DATA_ATTR struct datetime_struct now;
// TODO offset
const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 3600;
const int daylightOffset_sec = 3600;
void printLocalTime();
int8_t get_date_dtls(String time_zone);
// TODO refactore complete file
void setupDateTime()
{
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
printLocalTime();
get_date_dtls("");
}
void printLocalTime()
int getNumberOfDays(int month, int year)
{
struct tm timeinfo;
if (!getLocalTime(&timeinfo))
// leap year condition, if month is 2
if (month == 2)
{
Serial.println("Failed to obtain time");
return;
if ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0))
return 29;
else
return 28;
}
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
// months which has 31 days
else if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
return 31;
else
return 30;
}
// Time APIs
int8_t get_date_dtls(String time_zone)
void setupDateTime()
{
//String time_zone_string = time_zone_base + time_zone;
//setenv("TZ", time_zone_string.c_str(), 1);
//setenv("TZ", "CET-1CEST,M3.5.0/02,M10.5.0/03", 1);
struct tm timeinfo;
if (!getLocalTime(&timeinfo))
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
if (!getLocalTime(&now))
{
Serial.println("Failed to obtain time");
return -1;
return;
}
time_t epoch = mktime(&timeinfo);
Serial.println(&now, "%A, %B %d %Y %H:%M:%S");
sscanf(ctime(&epoch), "%s %s %hhd %hhd:%hhd:%hhd %d", now.wday, now.month, &now.mday, &now.mil_hour, &now.min, &now.sec, &now.year);
//
now.days_in_month = getNumberOfDays(now.tm_mon + 1, now.tm_year);
now.month_num = now.tm_mon + 1;
now.month_num = timeinfo.tm_mon + 1;
// gives offset of first day of the month with respect to Monday
//https://www.tondering.dk/claus/cal/chrweek.php#calcdow
// 1=Monday to 7=Sunday
// https://www.tondering.dk/claus/cal/chrweek.php#calcdow
uint8_t a = (14 - now.month_num) / 12;
uint16_t y = now.year - a;
uint16_t y = (now.tm_year + 1900) - a;
uint16_t m = now.month_num + (12 * a) - 2;
// change +7 at the end to whatever first day of week you want.
// But change the header '"Mon Tue Wed Thu Fri Sat Sun"' as well above.
// currently +7 => Monday
// +1 => Sunday
now.day_offset = (((1 + y + (y / 4) - (y / 100) + (y / 400) + ((31 * m) / 12)) % 7) + 7) % 7;
// convert to 12 hour
if (now.mil_hour > 12)
{
now.hour = now.mil_hour - 12;
}
else
{
now.hour = now.mil_hour;
}
Serial.printf("Time is %d %d:%d:%d on %s on the %d/%d/%d . It is the month of %s. day_offset: %d\n", now.mil_hour, now.hour, now.min, now.sec, now.wday, now.mday, now.month_num, now.year, now.month, now.day_offset);
return 0;
}
/*
int8_t set_time()
{
struct tm t;
t.tm_year = 2020 - 1900;
t.tm_mon = 1 - 1; // Month, 1 - jan to 12 - dec
t.tm_mday = 27; // Day of the month
t.tm_hour = 9;
t.tm_min = 57;
t.tm_sec = 0;
t.tm_isdst = -1; // Is DST on? 1 = yes, 0 = no, -1 = unknown
time_t epoch;
epoch = mktime(&t);
struct timeval now;
now.tv_sec = epoch;
now.tv_usec = 0;
struct timezone tz = {-330, 0};
return settimeofday(&now, &tz);
}
*/
}

@ -1,10 +1,22 @@
#include "faceCalendar.h"
#include "display.h"
#include "datetime.h"
#include "SPIFFS.h"
#include "pngle.h"
#include <Fonts/FreeMono12pt7b.h> // weekday - month year
#include <Fonts/FreeSansBold24pt7b.h> // current day
void display_calender();
void display_lines();
void display_picture();
void display_time();
void on_draw2(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4]);
using std::uint8_t;
static constexpr int MAX_WIDTH = 640 - 250;
static constexpr int MAX_HEIGHT = 384;
static int16_t curRowDelta[MAX_WIDTH + 1];
static int16_t nextRowDelta[MAX_WIDTH + 1];
void setupFaceCalendar()
{
@ -12,118 +24,186 @@ void setupFaceCalendar()
setupDateTime();
display.setRotation(0);
display.setFullWindow();
display.firstPage();
display.fillScreen(GxEPD_WHITE);
// draw...
display_lines();
//display_time();
display_picture();
display_calender();
display_time();
Serial.println("displayFlush");
display.nextPage();
// https://raw.githubusercontent.com/rgujju/paperdink/master/Images/full.jpg
// https://github.com/rgujju/paperdink/blob/master/Software/paperd.ink/GUI.cpp
// https://images.unsplash.com/photo-1580886349729-1bd109928600?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjExMDM0OH0&w=640&h=200&fm=png&fit=crop
// https://images.unsplash.com/photo-1580886349729-1bd109928600?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjExMDM0OH0&w=390&h=384&fm=png&fit=crop&colorquant=2
// final filter: &w=390&h=384&fm=png&fit=crop&duotone=000000,FFFFFF
// display_weather
}
void loopFaceCalendar()
{
}
void display_lines()
void display_calender()
{
// init
int16_t sideWidth = 250;
int16_t tbx, tby;
uint16_t tbw, tbh, x;
char label[64];
display.setTextColor(GxEPD_WHITE);
display.setTextSize(1);
display.setRotation(0);
// left side
display.fillRect(0, 0, sideWidth, display.height(), GxEPD_BLACK);
// weekday
strftime(label, 64, "%A", &now);
display.setFont(&FreeMono12pt7b);
display.getTextBounds(label, 0, 0, &tbx, &tby, &tbw, &tbh);
x = ((sideWidth - tbw) / 2) - tbx;
display.setCursor(x, 30);
display.println(label);
// today
display.setFont(&FreeSansBold24pt7b);
display.setTextSize(2);
display.getTextBounds("29", 0, 0, &tbx, &tby, &tbw, &tbh);
x = ((sideWidth - tbw) / 2) - tbx;
display.setCursor(x, 120);
display.println(now.tm_mday);
// month yearh
strftime(label, 64, "%B %Y", &now);
display.setTextSize(1);
display.setFont(&FreeMono12pt7b);
display.getTextBounds(label, 0, 0, &tbx, &tby, &tbw, &tbh);
x = ((sideWidth - tbw) / 2) - tbx;
display.setCursor(x, 150);
display.println(label);
// weekday headline
display.setFont(&FreeMonoBold9pt7b);
display.setCursor(20, 192);
display.println("Mo Tu We Th Fr Sa Su");
display.setCursor(20, 220);
// skip week days from previous month
for (uint8_t d = 1; d < now.day_offset; d++)
{
display.print(" ");
}
for (uint8_t d = 1; d <= now.days_in_month; d++)
{
display.printf("%2d ", d);
if ((d + now.day_offset - 1) % 7 == 0)
{
// new week
display.println("");
display.setCursor(20, display.getCursorY());
}
}
// TODO current weather
display.drawLine(15, 320, sideWidth - 15, 320, GxEPD_WHITE);
}
void display_picture()
{
// black area bottom
display.fillRect(0, (display.height() / 3) * 2, display.width(), (display.height() / 3), GxEPD_BLACK);
SPIFFS.begin();
displayOpen();
pngle_t *pngle = pngle_new();
pngle_set_draw_callback(pngle, on_draw2);
// vertical lines
display.fillRect((display.width() / 4), 0, 5, (display.height() / 3) * 2, GxEPD_BLACK);
display.fillRect((display.width() / 4), (display.height() / 3) * 2, 5, (display.height() / 3), GxEPD_WHITE);
//File file = SPIFFS.open("/blackPNG.png", "r");
File file = SPIFFS.open("/calendarPhoto.png", "r");
if (!file)
{
Serial.println(" file not found");
}
// TODO check why a small buffer is not working correct
char buff[1280] = {0};
while (int c = file.readBytes(buff, sizeof(buff)))
{
pngle_feed(pngle, buff, c);
}
file.close();
Serial.print(" width: ");
Serial.print(pngle_get_width(pngle));
Serial.print(" height: ");
Serial.println(pngle_get_height(pngle));
Serial.println(" read png done");
pngle_destroy(pngle);
}
/**
* @todo make it better :)
* Floyd-Steinberg-Algorithmus
*/
void display_calender()
void on_draw2(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4])
{
int16_t x1, y1;
uint16_t w, h;
display.setFont(&FreeMonoBold9pt7b);
display.setTextSize(1);
display.setTextColor(GxEPD_BLACK);
int16_t calender_base_y = 40;
int16_t calender_base_x = 120;
display.setCursor(calender_base_x, calender_base_y);
display.println("Mon Tue Wed Thu Fri Sat Sun");
display.getTextBounds("Mon Tue Wed Thu Fri Sat Sun", calender_base_x, calender_base_y, &x1, &y1, &w, &h);
uint8_t num_offset, print_valid = 0;
uint8_t day = 1;
for (uint8_t j = 0; j <= 5; j++)
uint8_t r = rgba[0]; // 0 - 255
uint8_t g = rgba[1]; // 0 - 255
uint8_t b = rgba[2]; // 0 - 255
//uint8_t a = rgba[3]; // 0: fully transparent, 255: fully opaque
int16_t gray = round(r * 0.3 + g * 0.59 + b * 0.11);
int16_t blackOrWhite;
// Add errors to color if there are
gray += curRowDelta[x];
if (gray <= 127)
{
for (uint8_t i = 1; i <= 7 && day <= 31; i++)
{
// you can hack around with this value to align your text properly based on what font, font size etc you are using
num_offset = 21; // 21 is what works for me for the first 2 columns
if (i >= 3 && i <= 7)
{
num_offset = 17; // then i need to reduce to 17
}
if (j == 0 && i == now.day_offset)
{
// start from the offset in the month, ie which day does 1st of the month lie on
print_valid = 1;
}
if (print_valid)
{
display.setCursor(calender_base_x + (i * (w / 7)) - num_offset, calender_base_y + ((j + 1) * h) + ((j + 1) * 7));
if (day == now.mday)
{
char str[3];
sprintf(str, "%d", day);
int16_t x2, y2;
uint16_t w2, h2;
display.getTextBounds(str, calender_base_x + (i * (w / 7)) - num_offset, calender_base_y + ((j + 1) * h) + ((j + 1) * 7), &x2, &y2, &w2, &h2);
display.fillRect(x2 - 4, y2 - 4, w2 + 8, h2 + 8, GxEPD_BLACK);
display.setTextColor(GxEPD_WHITE);
}
else
{
display.setTextColor(GxEPD_BLACK);
}
// once the offset is reached, start incrementing
display.println(day);
day += 1;
}
}
blackOrWhite = 0;
}
else
{
blackOrWhite = 255;
}
// display day
display.setTextColor(GxEPD_WHITE);
display.setFont(&FreeMonoBold9pt7b); // LARGE_FONT
display.setTextSize(1);
display.setCursor(33, 250);
display.println(now.mday);
int16_t oldPixel = gray;
int16_t newPixel = blackOrWhite;
// display month
display.setTextColor(GxEPD_WHITE);
display.setFont(&FreeMonoBold9pt7b); // MED_FONT
display.setTextSize(2);
display.setCursor(30, 290);
display.println(now.month);
int err = oldPixel - newPixel;
if (x > 0)
nextRowDelta[x - 1] += err * 3 / 16;
nextRowDelta[x] += err * 5 / 16;
nextRowDelta[x + 1] += err * 1 / 16;
curRowDelta[x + 1] += err * 7 / 16;
if (x == 0 && y > 0)
{
// new line
memcpy(curRowDelta, nextRowDelta, sizeof(curRowDelta));
memset(nextRowDelta, 0, sizeof(nextRowDelta));
}
displayWritePixel(x + 250, y, blackOrWhite);
}
void display_time()
{
/*
int16_t x1, y1;
uint16_t w, h;
//display time
display.setFont(&FreeMonoBold9pt7b); // LARGE_FONT
display.setFont(&FreeMonoBold9pt7b); // LARGE_FONT
display.setTextSize(1);
display.setTextColor(GxEPD_BLACK);
int16_t time_base_y = 60;
@ -152,4 +232,5 @@ void display_time()
{
display.println(now.min);
}
*/
}

@ -1,7 +1,7 @@
#include <Arduino.h>
#include "imagePNG.h"
#include "pngle.h"
#include "SPIFFS.h"
//#include "SPIFFS.h"
#include "display.h"
pngle_t *pngle;
@ -17,7 +17,6 @@ void setupImagePNG()
void pngOpenFramebuffer()
{
//Serial.println("pngOpenFramebuffer");
displayOpen();
pngle = pngle_new();
@ -35,48 +34,10 @@ void pngWriteFramebuffer(int offset, uint8_t bitmap[], int c)
void pngFlushFramebuffer()
{
//Serial.println("pngFlushFramebuffer");
pngle_destroy(pngle);
displayFlush();
/*
SPIFFS.begin();
displayOpen();
pngle_t *pngle = pngle_new();
pngle_set_draw_callback(pngle, on_draw);
File file = SPIFFS.open("/blackPNG.png", "r");
if (!file)
{
Serial.println(" file not found");
}
// get filesize
long size = file.size();
// read contents of the file into the vector
char *buffer = (char *)malloc((unsigned long)size);
if (!buffer)
{
file.close();
Serial.println(" allow failedd");
}
file.readBytes(buffer, (size_t)size);
file.close();
Serial.println(" read png");
int ret = pngle_feed(pngle, buffer, size);
//Serial.println(" return: " + ret);
//Serial.println(" width: " + pngle_get_width(pngle));
//Serial.println(" height: " + pngle_get_height(pngle));
Serial.println(" read png done");
pngle_destroy(pngle);
displayFlush();
*/
}
/*
void setupImagePNG__demo()
{

Loading…
Cancel
Save