/*
Horloge_TFT ()
pour ESP32 Wroom + afficheur 3.5" TFT 480x320
par Silicium628
*/
/*=====================================================================================================
CONCERNANT L'AFFICHAGE TFT: connexion:
(Pensez à configurer le fichier User_Setup.h de la bibliothèque ~/Arduino/libraries/TFT_eSPI/ )
les lignes qui suivent ne sont qu'un commentaire pour vous indiquer la config à utiliser
placée ici, elle ne sont pas fonctionnelles
Il FAUT modifier le fichier User_Setup.h installé par le système Arduino dans ~/Arduino/libraries/TFT_eSPI/
// ESP32 pins used for the parallel interface TFT
#define TFT_CS 27 // Chip select control pin
#define TFT_DC 14 // Data Command control pin - must use a pin in the range 0-31
#define TFT_RST 26 // Reset pin
#define TFT_WR 12 // Write strobe control pin - must use a pin in the range 0-31
#define TFT_RD 13
#define TFT_D0 16 // Must use pins in the range 0-31 for the data bus
#define TFT_D1 4 // so a single register write sets/clears all bits
#define TFT_D2 2 // 23
#define TFT_D3 22
#define TFT_D4 21
#define TFT_D5 15 // 19
#define TFT_D6 25 // 18
#define TFT_D7 17
=====================================================================================================*/
String version="3.1";
uint8_t fond_blanc = 0;
#include <stdint.h>
#include <TFT_eSPI.h> // Hardware-specific library
#include "Free_Fonts.h"
#include "FS.h"
#include "SD.h"
TFT_eSPI TFT480 = TFT_eSPI(); // Configurer le fichier User_Setup.h de la bibliothèque TFT480_eSPI au préalable
#include <WiFi.h>
#include <HTTPClient.h>
const char* ssid = "TPGPS_34";
const char* password = "94r6tkJ31";
//IP address with URL path
const char* srvName_HR = "http://192.168.4.1/HR";
String recp_HR = "{}";
uint8_t WiFi_status=0;
uint32_t memoMillis = 0;
uint32_t currentMillis;
const uint32_t tempo = 2000;
uint16_t annee;
uint8_t mois;
uint8_t jour;
uint8_t annee_in=0;
uint8_t mois_in=0;
uint8_t jour_in=0;
uint8_t heures=0;
uint8_t memo_heures;
uint8_t minutes=0;
uint8_t memo_minutes=0;
uint8_t secondes=0;
uint8_t jour_de_la_semaine;
uint8_t heures_in=0;
uint8_t minutes_in=0;
uint8_t secondes_in=0;
uint16_t compte1=0;
//uint16_t compte2=0;
String annee_txt;
String mois_txt;
String jour_txt;
String date_txt;
String memo_date_txt="---";
uint8_t SDcardOk=0;
uint8_t num_image;
//uRTCLib rtc(0x68); // MODULE HORLOGE TEMPS REEL; 0x68 = adresse sur le bus I2C
//const int led2 = 12;
//bool led2_etat = LOW;
/*
const int GPIO_bouton0 = 13; // Bouton interne
bool bouton0_etat;
bool memo_bouton0_etat;
const int GPIO_bouton1 = 14; // bouton externe
bool bouton1_etat;
bool memo_bouton1_etat;
const int GPIO_bouton2 = 27; // bouton externe
bool bouton2_etat;
bool memo_bouton2_etat;
*/
uint32_t memoM1 = 0;
uint32_t memoM2 = 0;
const uint32_t tempo1 = 2000; // 2000 ms = 2s
const uint32_t tempo2 = 300*1000; // 300s = 5mn
uint8_t stop_affichage =0;
// #define TIME_TO_SLEEP 1000 /* Time ESP32 will go to sleep (en ms) */
// uint8_t sleep_enable = 1;
#define NOIR 0x0000
#define MARRON 0x9240
#define ROUGE 0xF800
#define ROSE 0xFBDD
#define ORANGE 0xFBC0
#define JAUNE 0xFFE0
#define JAUNE_PALE 0xF7F4
#define VERT 0x07E0
#define VERT_FONCE 0x02E2
#define OLIVE 0x05A3
#define CYAN 0x07FF
#define BLEU_CLAIR 0x455F
#define AZUR 0x1BF9
#define BLEU 0x001F
#define MAGENTA 0xF81F
#define VIOLET1 0x781A
#define VIOLET2 0xECBE
#define GRIS_TRES_CLAIR 0xDEFB
#define GRIS_CLAIR 0xA534
#define GRIS 0x8410
#define GRIS_FONCE 0x5ACB
#define GRIS_TRES_FONCE 0x2124
#define BLANC 0xFFFF
//int startX = 40, startY = 10;
uint16_t couleur_txt = BLANC;
uint16_t couleur_fond = GRIS_TRES_FONCE;
uint16_t couleur_fond_txt = VERT_FONCE;
uint32_t bmp_offset = 0;
static void smartdelay(unsigned long ms)
{
unsigned long start = millis();
while (millis() - start < ms) {;}
}
void init_SDcard()
{
String s1;
TFT480.fillRect(0, 0, 480, 320, NOIR); // efface
TFT480.setTextColor(BLANC, NOIR);
TFT480.setFreeFont(FF1);
uint16_t y=0;
TFT480.drawString("ND - Navigation Display", 0, y);
y+=20;
s1="version " + version;
TFT480.drawString(s1, 0, y);
y+=40;
TFT480.setTextColor(VERT, NOIR);
TFT480.drawString("Init SDcard", 0, y);
y+=20;
if(!SD.begin())
{
TFT480.drawString("Card Mount Failed", 0, y);
delay (2000);
TFT480.fillRect(0, 0, 480, 320, NOIR); // efface
return;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE)
{
TFT480.drawString("No SDcard", 0, y);
delay (2000);
TFT480.fillRect(0, 0, 480, 320, NOIR); // efface
return;
}
SDcardOk=1;
TFT480.drawString("SDcard Type: ", 0, y);
if(cardType == CARD_SD) {TFT480.drawString("SDSC", 150, y);}
else if(cardType == CARD_SDHC) {TFT480.drawString("SDHC", 150, y);}
y+=20;
uint32_t cardSize = SD.cardSize() / (1024 * 1024);
s1=(String)cardSize + " GB";
TFT480.drawString("SDcard size: ", 0, y);
TFT480.drawString(s1, 150, y);
// listDir(SD, "/", 0);
//Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
//Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
delay (1000);
TFT480.fillRect(0, 0, 480, 320, NOIR); // efface
}
void httpGetHeureDate()
{
// Serial.println("envoi req HR");
TFT480.fillCircle(470, 5, 5,BLEU );
delay(200);
HTTPClient http2;
http2.begin(srvName_HR);
int httpResponseCode = http2.GET();
if (httpResponseCode>0)
{
recp_HR = http2.getString();
}
http2.end();
TFT480.fillCircle(470, 5, 5,VERT );
// Serial.println("reponse: ");
// Serial.println(recp_HR);
}
void ajuste_HR()
{
// Serial.print("length="); Serial.println(recp_HR.length());
if(recp_HR.length() == 18)
{
WiFi_status =1;
// Serial.println("ajuste_HR");
// Serial.println( recp_HR);
// String data_in = "11:40:30"
heures_in =(recp_HR.substring(0,2)).toInt();
// Serial.println(heures_in);
minutes_in =(recp_HR.substring(3,5)).toInt();
// Serial.println(minutes_in);
secondes_in =(recp_HR.substring(6,8)).toInt();
// Serial.println(secondes_in);
//secondes_in++; // pour compenser le temps de traitement
if (heures != heures_in) {heures = heures_in;}
if (minutes != minutes_in) {minutes = minutes_in;}
if (secondes != secondes_in) {secondes = secondes_in;}
jour_in =(recp_HR.substring(9,11)).toInt();
// Serial.println(jour_in);
mois_in =(recp_HR.substring(12,14)).toInt();
// Serial.println(mois_in);
annee_in =(recp_HR.substring(15,17)).toInt();
// Serial.println(annee_in);
if (jour != jour_in) {jour = jour_in;}
if (mois != mois_in) {mois = mois_in;}
if (annee != annee_in) {annee = annee_in;}
}
else {WiFi_status=0;}
}
void calcul_jour_de_la_semaine()
{
// d'après l'Algorithme de Mike Keith
uint16_t d, m, y, z, jds;
d=jour;
m=mois;
y=annee;
if (m>=3)
{
jds = ( ((23*m)/9) + d + 4 + y + (y/4) - (y/100) + (y/400) - 2 ) % 7;
}
else
{
z = y-1;
jds = ( ((23*m)/9) + d + 4 + y + (z/4) - (z/100) + (z/400) ) % 7;
}
jour_de_la_semaine = jds;
}
String conv_time(uint8_t t)
{
String r;
r=String(t);
if (t<10) {r="0"+r;}
return r;
}
void affiche_date()
{
date_txt="";
calcul_jour_de_la_semaine();
switch (jour_de_la_semaine)
{
case 0: { date_txt+="Dim ";} break;
case 1: { date_txt+="Lun ";} break;
case 2: { date_txt+="Mar ";} break;
case 3: { date_txt+="Mer ";} break;
case 4: { date_txt+="Jeu ";} break;;
case 5: { date_txt+="Ven ";} break;
case 6: { date_txt+="Sam ";} break;
}
date_txt += String(conv_time(jour))+" ";
switch (mois)
{
case 1: {date_txt+="Janv "; } break;
case 2: {date_txt+="Fev "; } break;
case 3: {date_txt+="Mars "; } break;
case 4: {date_txt+="Avr "; } break;
case 5: {date_txt+="Mai "; } break;
case 6: {date_txt+="Juin "; } break;
case 7: {date_txt+="Juil "; } break;
case 8: {date_txt+="Aout "; } break;
case 9: {date_txt+="Sept "; } break;
case 10: {date_txt+="Oct "; } break;
case 11: {date_txt+="Nov "; } break;
case 12: {date_txt+="Dec "; } break;
}
if (annee_in >0) // pour éviter d'afficher une date fantaisiste au départ
{
uint16_t annee_in2 = annee_in + 2000;
annee_txt = (String)annee_in2;
// Serial.print("annee_txt="); Serial.println(annee_txt);
date_txt += annee_txt;
//memo_date_txt = date_txt;
TFT480.setTextColor(JAUNE, NOIR);
TFT480.setFreeFont(FF6);
TFT480.setTextSize(1);
TFT480.drawString(date_txt,0,300);
}
}
void affiche_heure()
{
String s1;
if (memo_minutes != minutes)
{
memo_minutes = minutes;
//TFT480.fillRect(0, 50, 479, 125, couleur_fond_txt);
num_image = random(1, 23);
affi_img(0, 0, num_image);
s1="";
if(heures<10){s1+="0";}
s1 += String(heures);
s1 += ":";
if(minutes<10){s1+="0";}
s1 += String(minutes);
TFT480.setTextColor(couleur_txt, couleur_fond_txt);
//TFT480.setFreeFont(FF24);
TFT480.setFreeFont(FF8);
TFT480.setTextSize(3);
TFT480.setTextColor(NOIR);
TFT480.drawString(s1, 20+5, 50+5);
TFT480.setTextColor(couleur_txt);
TFT480.drawString(s1, 20, 50);
affiche_date();
}
TFT480.setTextColor(couleur_txt, couleur_fond_txt);
TFT480.setFreeFont(FF7);
TFT480.setTextSize(1);
s1="";
if(secondes<10){s1+="0";}
s1 += String(secondes);
TFT480.fillRect(400, 200, 40, 24, couleur_fond_txt);
TFT480.drawString(s1, 400, 200);
if(WiFi_status == 1) { TFT480.fillCircle(470, 5, 5,VERT );} else { TFT480.fillCircle(470, 5, 5,ROUGE );}
}
uint8_t decToBcd( int val )
{
return (uint8_t) ((val / 10 * 16) + (val % 10));
}
uint16_t bmp_width;
uint16_t bmp_heigh;
uint16_t Color_To_565(uint8_t r, uint8_t g, uint8_t b)
{
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
}
void RGB565_to_888(uint16_t color565, uint8_t *R, uint8_t *G, uint8_t *B)
{
*R=(color565 & 0xFFFFF800) >> 8;
*G=(color565 & 0x7E0) >> 3;
*B=(color565 & 0x1F) << 3 ;
}
uint16_t read_16(File fp)
{
uint8_t low;
uint16_t high;
low = fp.read();
high = fp.read();
return (high<<8)|low;
}
uint32_t read_32(File fp)
{
uint16_t low;
uint32_t high;
low = read_16(fp);
high = read_16(fp);
return (high<<8)|low;
}
void write_16(uint16_t v16, File fp)
{
uint8_t low, high;
low = v16 & 0xFF;
high= v16 >>8;
fp.write(low);
fp.write(high);
}
void write_32(uint32_t v32, File fp)
{
uint16_t low, high;
low = v32 & 0xFFFF;
high= v32 >>16;
write_16(low, fp);
write_16(high, fp);
}
bool teste_bmp_header(File fp)
{
if(read_16(fp) != 0x4D42) { return false; } // (2 bytes) The header field used to identify the BMP
read_32(fp); // (4 bytes) get bmp size (nombre total d'octets)
read_32(fp); // (4 bytes) get creator information
bmp_offset = read_32(fp); // (4 bytes) get offset information
read_32(fp);//get DIB information
// ici on a lu 16 octets
bmp_width = read_32(fp); //(4 bytes) get width and heigh information
bmp_heigh = read_32(fp); //(4 bytes)
// ici on a lu 24 octets
//if(read_16(fp)!= 1) {return false;}
read_16(fp);
//if(read_32(fp)!= 0) {return false;}
return true;
}
uint8_t LumCtr(uint8_t vi, float lum, float ctr)
{
float v2;
uint8_t result;
v2 = ((float)vi - lum) * ctr;
if (v2<0) {v2=0;}
if (v2>255) {v2=255;}
result = (uint8_t) v2;
return result;
}
void draw_bmp(uint16_t x0, uint16_t y0, File* fp)
{
//sram = freeRam(); Serial.print("03-freeRam="); Serial.println(sram);
uint16_t i,j,k,p,m=0;
uint16_t y1;
uint8_t bmp_data[2*3]={0};
uint16_t bmp_color[2];
uint8_t rot =1;
fp->seek(bmp_offset);
for(i=0; i<bmp_heigh; i++)
{
for(j=0; j<(bmp_width/2); j++)
{
m=0;
fp->read(bmp_data,2*3);
for(k=0; k<2; k++)
{
bmp_color[k]= Color_To_565(bmp_data[m+2], bmp_data[m+1], bmp_data[m+0]);
m+=3;
}
for(p=0; p<2; p++)
{
if (rot==0)
{
y1=y0;
TFT480.drawPixel(x0+i, y0+j*2+p, bmp_color[p]);
}
if (rot==1)
{
//y1=160-y0;
y1=y0;
TFT480.drawPixel(x0+j*2+p,320-(y1+i), bmp_color[p]);
}
}
}
}
}
void affi_img(uint16_t x0, uint16_t y0, uint8_t num)
{
File bmp_file;
TFT480.setFreeFont(FF1);
TFT480.setTextColor(ORANGE, NOIR);
String numtxt = String(num);
String filename;
filename ="/bmp/";
filename += numtxt;
filename += ".bmp";
//bmp_file = SD.open("/bmp/1.bmp");
bmp_file = SD.open(filename);
if(!bmp_file)
{
//efface_carte(x0,y0);
bmp_file.close();
// Serial.println("ici1");
return;
}
if(!teste_bmp_header(bmp_file))
{
bmp_file.close();
// Serial.println("ici2");
return;
}
// Serial.println("ici3");
draw_bmp(x0, y0, &bmp_file);
bmp_file.close();
// delay(1000);
}
void setup()
{
//esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * 1000);
//esp_sleep_enable_ext0_wakeup((gpio_num_t)BUTTON_PIN, LOW);
// Serial.begin(19200);
num_image = random(1, 23);
init_SDcard();
// Serial.println("display.init()");
TFT480.init();
TFT480.setRotation(3); // 0..3 à voir, suivant disposition de l'afficheur et sa disposition
TFT480.fillScreen(NOIR);
TFT480.setTextColor(BLANC, NOIR);
TFT480.setFreeFont(FF1);
uint16_t y=0;
TFT480.drawString("Horloge TFT", 0, y);
y+=20;
String s1="version " + version;
TFT480.drawString(s1, 0, y);
y+=20;
TFT480.setTextColor(BLEU, NOIR);
TFT480.drawString("Heure GPS", 0, y);
y+=20;
TFT480.setTextColor(JAUNE, NOIR);
TFT480.drawString("Client WiFi", 0, y);
y+=40;
/*
TFT480.setFreeFont(FF24);
TFT480.setTextSize(4);
uint16_t y=0;
TFT480.drawString("12:34", 0, y);
*/
delay (2000);
if(fond_blanc == 1) {TFT480.fillScreen(BLANC);} else {TFT480.fillScreen(NOIR);}
TFT480.setCursor(0, 20, 4);
TFT480.setTextColor(JAUNE, NOIR);
TFT480.print("Connexion au serveur GPS WiFi:");
WiFi.persistent(false);
WiFi.begin(ssid, password);
delay(1000);
// Serial.println("Connecting");
TFT480.setTextColor(BLEU, NOIR);
//TFT480.setTextFont(1);
TFT480.setCursor(0, 40, 1);
while(WiFi.status() != WL_CONNECTED)
{
delay(500);
TFT480.print(".");
// Serial.print(".");
}
// Serial.println("");
// Serial.print("Connected to WiFi - IP Address : ");
// Serial.println(WiFi.localIP());
// Serial.println("\n");
TFT480.setTextColor(VERT, NOIR);
TFT480.println(" ");
TFT480.println("OK");
smartdelay(500);
TFT480.fillScreen(NOIR);
TFT480.setCursor(130, 0, 2); // Set "cursor" at top left corner of display (0,0) and select font 4
TFT480.setTextColor(TFT_BLUE, TFT_BLACK);
TFT480.println("Client WiFi");
delay(500);
TFT480.fillScreen(couleur_fond);
TFT480.setTextColor(CYAN, couleur_fond);
TFT480.setFreeFont(FF5);
TFT480.setTextSize(1);
TFT480.drawString("GPS Time",0,0);
//affi_img(0, 0, num_image);
//affiche_date();
compte1=9;
httpGetHeureDate();
ajuste_HR();
affiche_heure();
}
void incremente_heure(uint8_t nb_s)
{
for (uint8_t n=0; n<nb_s; n++)
{
if (secondes < 59) {secondes+=1;}
else
{
secondes=0;
if (minutes < 59) {minutes+=1;}
else
{
minutes=0;
if (heures < 23) {heures+=1;}
else
heures=0;
}
}
}
}
void loop()
{
compte1++;
// Serial.println(compte1);
if ((compte1 % 20)==0) // toutes les 20s
{
recp_HR = "{}";
if(WiFi.status()== WL_CONNECTED )
{
httpGetHeureDate();
ajuste_HR();
}
}
incremente_heure(1); // +1s
smartdelay(1000);
affiche_heure();
}