Introduction: WiFi NodeMCU ESP8266 Google Clock

A simple easy WiFi clock using "Google" timestamp, with temperature, humidity and automatic brightness

Step 1: Schematics, Components

Components:

  • 1 x NodeMCU ESP 8086
  • 6 x MAX7219
  • 1x DHT22
  • 2x Resistor 10k
  • 1x LDR


Step 2: Code

You can download the code HERE

//V.3 - Data converted and daylight savings time

//V.4 - localized data, days... (use yours....)

//V.6 - thermometer and hygrometer

//V.7 - animated clock corrected + seconds +1,5

//V.8 - tuning thermometer and hygrometer

//v.9 - DST corrected / compiler error corrected (long)round

//v.10 - Date change at 00:00 corrected for GMT>0

//v.11 - automitc panel brightness (+3.3V ---|==10k==|---A0---|GND

// review: anthias64@gmail.com

// kudos original maker code can't find its name...

#include "Arduino.h"

#include

#include //ESP8266 Core WiFi Library (you most likely already have this in your sketch)

WiFiClient client;

#define NUM_MAX 6

// for NodeMCU 1.0

#define DIN_PIN 13 // D7

#define CS_PIN 0 // D3

#define CLK_PIN 14 // D5

#include "max7219.h"

#include "fonts.h"

#include "DHT.h" // sensor DHT

// DHT sensor

#define DHTPIN 12 // what pin we're connected to // GPIO 12 = D6

// Uncomment whatever type you're using!

//#define DHTTYPE DHT11 // DHT 11

#define DHTTYPE DHT22 // DHT 22 (AM2302)

//#define DHTTYPE DHT21 // DHT 21 (AM2301)

DHT dht(DHTPIN, DHTTYPE, 11); // for ESP8266

//DHT

float temperature = 0;

int temp = 0;

byte minus = 0;

int umidity = 0;

int poz, poz2;

int mult = 0;

float temp_offset = -1.0; // taratura termometro

float rh_offset = +3; // taratura igrometro

char TempLabel[] = " Temperatura: "; // Fixxed text

char UmiLabel[] = " Umidita': "; // Fixxed text

//modifica test ip

const char ssid[] = "xxxxxxxxxx"; // your network SSID (name)

const char password[] = "xxxxxxxxxxxxxxxxxxxxx"; // your network password

// Localized Months and DoWeek

String M_arr[13] = {" ", "Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"};

String Dow_arr[8] = {" ", "Lunedi", "Martedi", "Mercoledi", "Giovedi", "Venerdi", "Sabato", "Domenica"};

void setup()

{

Serial.begin(115200);

initMAX7219(); //

sendCmdAll(CMD_SHUTDOWN,1); //

sendCmdAll(CMD_INTENSITY,1); // brightness from 1 to 5

Serial.print("Connecting to ");

Serial.println(ssid);

WiFi.begin(ssid, password);

printStringWithShift("Connecting",30); //

delay (1000);

while (WiFi.status() != WL_CONNECTED) {

delay(500);

Serial.print(".");

}

Serial.print("IP number assigned by DHCP is ");

Serial.println(WiFi.localIP());

printStringWithShift((String(" IP:")+WiFi.localIP().toString()).c_str(), 30);//

delay(1000);//

// DHT

dht.begin();

temperature = dht.readTemperature() + temp_offset;

umidity = dht.readHumidity() + rh_offset;

Serial.print(temperature);

Serial.println(" gr.Celsius");

Serial.print(umidity);

Serial.println(" %RH");

if (temperature < 0)

{

temp = -10*temperature;

minus = 1;

}

else

{

minus = 0;

temp = 10*temperature;

}

}

// =============================DEFINE VARS==============================

#define MAX_DIGITS 20

byte dig[MAX_DIGITS]={0};

byte digold[MAX_DIGITS]={0};

byte digtrans[MAX_DIGITS]={0};

int updCnt = 0;

int dots = 0;

long dotTime = 0;

long clkTime = 0;

int dx=0;

int dy=0;

byte del=0;

int h,m,s;

float utcOffset = +1; // ==> your timezone

long localEpoc = 0;

long localMillisAtUpdate = 0;

int day, month, year, dayOfWeek;

int monthnum = 0;

int downum = 0;

int summerTime = 0;

String date;

String dayloc;

String monthloc;

// =======================================================================

void loop()

{

if(updCnt<=0) { // every 10 scrolls, ~450s=7.5m

updCnt = 60;

Serial.println("Getting data ...");

// clr();

printStringWithShift(" Get Time...",30);

getTime();

Serial.println("Data loaded");

clkTime = millis();

}

contrast(); // //autobrightness

//print data

if(millis()-clkTime > 30000 && !del && dots) { // clock for 30s, then scrolls for about 30s

printStringWithShift(" ",40); //Space before

printStringWithShift(date.c_str(),40); //data1

// Reading temperature or humidity

int umidity = dht.readHumidity()+ rh_offset;

float temperature = dht.readTemperature()+ temp_offset;

//umidity = umidity + rh_offset;

//temperature = temperature + temp_offset;

Serial.println("Temp e Umid corretti");

Serial.println(temperature);

Serial.println(umidity);

int t2 = 10*temperature;

// print temperature

// http://www.arduino-hacks.com/converting-integer-t...

char c[3], d[2];

String str1, str2;

int t2z = t2/10;

int t2u = t2 - t2z*10;

str1=String(t2z);

str1.toCharArray(c,3);

str2=String(t2u);

str2.toCharArray(d,2);

printStringWithShift(TempLabel ,40); // Send scrolling Text

printStringWithShift("+" ,40);

printStringWithShift(c ,40);

printStringWithShift("," ,40);

printStringWithShift(d ,40);

printStringWithShift(" C^" ,40);

//delay(2000);

// print umidity

// http://www.arduino-hacks.com/converting-integer-t...

char b[3];

String str;

str=String(umidity);

str.toCharArray(b,3);

printStringWithShift(UmiLabel ,40); // Send scrolling Text

printStringWithShift(b ,40);

printStringWithShift(" %" ,40);

//delay(2000);

printStringWithShift(" ",40); //Space after

delay(200);

updCnt--;

clkTime = millis();

}

if(millis()-dotTime > 500) {

dotTime = millis();

dots = !dots;

}

updateTime(); // get time

// print clock

showAnimClock();

//showSimpleClock();

}

// =======================================================================

void showSimpleClock()

{

dx=dy=0;

clr();

showDigit(h/10, 0, dig6x8);

showDigit(h%10, 8, dig6x8);

showDigit(m/10, 17, dig6x8);

showDigit(m%10, 25, dig6x8);

showDigit(s/10, 34, dig6x8);

showDigit(s%10, 42, dig6x8);

setCol(15,dots ? B00100100 : 0);

setCol(32,dots ? B00100100 : 0);

refreshAll();

}

// =======================================================================

void showAnimClock()

{

byte digPos[6]={0,8,17,25,34,42};

int digHt = 12;

int num = 6;

int i;

if(del==0) {

del = digHt;

for(i=0; i

dig[0] = h/10 ? h/10 : 10;

dig[1] = h%10;

dig[2] = m/10;

dig[3] = m%10;

dig[4] = s/10;

dig[5] = s%10;

for(i=0; i

} else

del--;

clr();

for(i=0; i

if(digtrans[i]==0) {

dy=0;

showDigit(dig[i], digPos[i], dig6x8);

} else {

dy = digHt-digtrans[i];

showDigit(digold[i], digPos[i], dig6x8);

dy = -digtrans[i];

showDigit(dig[i], digPos[i], dig6x8);

digtrans[i]--;

}

}

dy=0;

setCol(15,dots ? B00100100 : 0);

setCol(32,dots ? B00100100 : 0);

refreshAll();

delay(10); //default 30

}

// =======================================================================

void showDigit(char ch, int col, const uint8_t *data)

{

if(dy<-8 | dy>8) return;

int len = pgm_read_byte(data);

int w = pgm_read_byte(data + 1 + ch * len);

col += dx;

for (int i = 0; i < w; i++)

if(col+i>=0 && col+i<8*NUM_MAX) {

byte v = pgm_read_byte(data + 1 + ch * len + 1 + i);

if(!dy) scr[col + i] = v; else scr[col + i] |= dy>0 ? v>>dy : v<<-dy;

}

}

// =======================================================================

void setCol(int col, byte v)

{

if(dy<-8 | dy>8) return;

col += dx;

if(col>=0 && col<8*NUM_MAX)

if(!dy) scr[col] = v; else scr[col] |= dy>0 ? v>>dy : v<<-dy;

}

// =======================================================================

int showChar(char ch, const uint8_t *data)

{

int len = pgm_read_byte(data);

int i,w = pgm_read_byte(data + 1 + ch * len);

for (i = 0; i < w; i++)

scr[NUM_MAX*8 + i] = pgm_read_byte(data + 1 + ch * len + 1 + i);

scr[NUM_MAX*8 + i] = 0;

return w;

}

// =======================================================================

int dualChar = 0;

unsigned char convertPolish(unsigned char _c)

{

unsigned char c = _c;

if(c==196 || c==197 || c==195) {

dualChar = c;

return 0;

}

if(dualChar) {

switch(_c) {

case 133: c = 1+'~'; break; // 'ą'

case 135: c = 2+'~'; break; // 'ć'

case 153: c = 3+'~'; break; // 'ę'

case 130: c = 4+'~'; break; // 'ł'

case 132: c = dualChar==197 ? 5+'~' : 10+'~'; break; // 'ń' and 'Ą'

case 179: c = 6+'~'; break; // 'ó'

case 155: c = 7+'~'; break; // 'ś'

case 186: c = 8+'~'; break; // 'ź'

case 188: c = 9+'~'; break; // 'ż'

//case 132: c = 10+'~'; break; // 'Ą'

case 134: c = 11+'~'; break; // 'Ć'

case 152: c = 12+'~'; break; // 'Ę'

case 129: c = 13+'~'; break; // 'Ł'

case 131: c = 14+'~'; break; // 'Ń'

case 147: c = 15+'~'; break; // 'Ó'

case 154: c = 16+'~'; break; // 'Ś'

case 185: c = 17+'~'; break; // 'Ź'

case 187: c = 18+'~'; break; // 'Ż'

default: break;

}

dualChar = 0;

return c;

}

switch(_c) {

case 185: c = 1+'~'; break;

case 230: c = 2+'~'; break;

case 234: c = 3+'~'; break;

case 179: c = 4+'~'; break;

case 241: c = 5+'~'; break;

case 243: c = 6+'~'; break;

case 156: c = 7+'~'; break;

case 159: c = 8+'~'; break;

case 191: c = 9+'~'; break;

case 165: c = 10+'~'; break;

case 198: c = 11+'~'; break;

case 202: c = 12+'~'; break;

case 163: c = 13+'~'; break;

case 209: c = 14+'~'; break;

case 211: c = 15+'~'; break;

case 140: c = 16+'~'; break;

case 143: c = 17+'~'; break;

case 175: c = 18+'~'; break;

default: break;

}

return c;

}

// =======================================================================

void printCharWithShift(unsigned char c, int shiftDelay) {

c = convertPolish(c);

if (c < ' ' || c > '~'+25) return;

c -= 32;

int w = showChar(c, font);

for (int i=0; i

delay(shiftDelay);

scrollLeft();

refreshAll();

}

}

// =======================================================================

void printStringWithShift(const char* s, int shiftDelay){

while (*s) {

printCharWithShift(*s, shiftDelay);

s++;

}

}

// =======================================================================

void getTime()

{

WiFiClient client;

if (!client.connect("www.google.com", 80)) {

Serial.println("connection to google failed");

return;

}

client.print(String("GET / HTTP/1.1\r\n\n") +

String("Host: www.google.com\r\n\n") +

String("Connection: close\r\n\n\r\n\n"));

int repeatCounter = 0;

while (!client.available() && repeatCounter < 10) {

delay(500);

//Serial.println(".");

repeatCounter++;

}

String line;

client.setNoDelay(false);

while(client.connected() && client.available()) {

line = client.readStringUntil('\n');

line.toUpperCase();

// Serial.println(line); //test stringa

if (line.startsWith("DATE: ")) {

//date = " "+line.substring(6, 22);

date =line.substring(6, 22);

date.toUpperCase();

Serial.println(date); //check

int day = atoi (date.substring(5,7).c_str()); //day number

int year = 2000 + atoi (date.substring(13,16).c_str()); //year number

monthnum = month2index(date.substring(8,11)); // convert month in mumber

month = monthnum; //check

downum = dow2index(date.substring(0,3)); // convert dow in mumber

dayOfWeek = downum; //check

monthloc = M_arr[month]; // localize month

dayloc = Dow_arr[dayOfWeek]; // localize DayOfWeek

date = dayloc + " " + day + " " + monthloc + " " + year;

// decodeDate(date); //data3

h = line.substring(23, 25).toInt();

m = line.substring(26, 28).toInt();

s = line.substring(29, 31).toInt()+1.5; //correzione ora

// summerTime = checkSummerTime();

// calcolo ora legale

Serial.print("Ora GMT: " );

Serial.print(h); //check

Serial.print(" : " );

Serial.print(m); //check

Serial.print(" : " );

Serial.print(s); //check

Serial.println(""); //check

Serial.print("Data: " );

Serial.println(date); //check

//day = 31;

//year = 2021;

//month = 10;

if(month>3 && month<=10) summerTime=1;

if(month==3 && day>=31-(((5*year/4)+4)%7) ) summerTime=1;

if(month==10 && day>=31-(((5*year/4)+1)%7) ) summerTime=0;

Serial.print("Summertime: ");

Serial.println(summerTime);

unsigned short MoZiff[12] = { 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 }; //Monatsziffer

unsigned short Tage_Monat[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

if(h+utcOffset+summerTime>23) {

// if(++day>31) { day=1; month++; }; // needs better patch

// if(++dayOfWeek>7) dayOfWeek=1;

h = h - 24;

dayOfWeek = dayOfWeek +1;

if(dayOfWeek>7) dayOfWeek=1;

day = day + 1;

if (day > Tage_Monat[month - 1]) {

day = 1;

month = month + 1;

if (month > 12) {

month = 1;

year = year + 1;

}

}

}

monthloc = M_arr[month]; // localize month

dayloc = Dow_arr[dayOfWeek]; // localize DayOfWeek

date = dayloc + ", " + day + " " + monthloc + " " + year;

localMillisAtUpdate = millis();

localEpoc = (h * 60 * 60 + m * 60 + s);

}

}

client.stop();

}

// =======================================================================

//convert month string in month number

int month2index (String month)

{

String months[12] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};

for (int i = 0; i < 12; i++) {

if (months[i] == month)

return i + 1;

}

return 0;

}

// =======================================================================

//convert dow string in dow number

int dow2index (String dayOfWeek)

{

String dows[7] = {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};

for (int i = 0; i < 12; i++) {

if (dows[i] == dayOfWeek)

return i + 1;

}

return 0;

}

// =======================================================================

//check if it is summer time

// int checkSummerTime()

//{

//if(month>3 && month<10) return 1;

//if(month==3 && day>=31-(((5*year/4)+4)%7) ) return 1;

//if(month==10 && day<31-(((5*year/4)+1)%7) ) return 0;

//return 0;

// return 1;

//}

// =======================================================================

void updateTime()

{

long curEpoch = localEpoc + ((millis() - localMillisAtUpdate) / 1000);

//long epoch = round(curEpoch + 3600 * (utcOffset+summerTime) + 86400L) % 86400L;

long epoch = (long)round(curEpoch + 3600 * (utcOffset+summerTime) + 86400L) % 86400L; // fix compiler error

//long epoch = round(curEpoch + 3600 * (utcOffset+summerTime) + 86400L);

h = ((epoch % 86400L) / 3600) % 24;

m = (epoch % 3600) / 60;

s = epoch % 60;

}

// =======================================================================

void contrast()

{

int lumina = analogRead(A0); //autobrightness (+3.3V ---|==10k==|---A0---|GND (niq_ro)

lumina = map(lumina, 0, 1023, 0, 4); //broghtness 0-4

//Serial.print("brightness = ");

//Serial.print(lumina);

//Serial.println (" / 4");

sendCmdAll(CMD_INTENSITY, lumina);

}