Relógio com NodeMCU ESP8266 usando NTP
A imagem parece a mesma do post anterior sobre o NodeMCU ESP8266 com display Oled, mas o assunto aqui é outro: vamos ver como você pode criar um relógio com NodeMCU e Display Oled I2C, atualizando a hora através da internet via protocolo NTP sem precisar de nenhum hardware adicional.

O módulo NodeMCU ESP8266 vai se conectar ao seu roteador wifi e efetuar uma conexão com o servidor NTP (um “servidor de horário”), atualizando em tempo real as informações no display. Você pode usar o mesmo princípio para criar outros projetos com o NodeMCU (ou outros módulos ESP8266), que envolvam a utilização de horários específicos, controle de tempo, etc.
O que é o NTP – Network Time Protocol
O NTP – Network Time Protocol – é um protocolo criado especialmente para sincronizar relógios com servidores na internet, usando UDP na porta 123. Uma estrutura de servidores NTP é dividida em camadas, ou estratos, numerados de 0 a 16. Essa estrutura basicamente tem como referência uma fonte de horário (um GPS ou um relógio atômico, por exemplo), e distribui essa informação para todos os computadores ou dispositivos que se conectam à ela.
![]() |
| Imagem: xmodulo.com |
E por que o NTP é importante? Os computadores e dispositivos, de certa maneira, tendem a ter um relógio não confiável: podem atrasar ou adiantar por características de hardware, ou ter o seu horário alterado acidentalmente pelo usuário ou até mesmo por vírus e outros programas. Em uma época em que tudo deve estar conectado e sincronizado, é de extrema importância garantir a integridade dos dados armazenados, seja para rodar um backup em um horário pré-estabelecido, gravar corretamente um log de acessos em um servidor ou até mesmo por questões de auditoria de dados.
Circuito relógio com NodeMCU e Display Oled
O nosso relógio com NodeMCU e Display Oled vai usar exatamente o mesmo circuito do post anterior. Vamos apenas alterar o programa para que este busque o horário atualizado no servidor NTP. Conecte então o seu display oled I2C no NodeMCU ESP8266 seguindo o esquema abaixo:

Relembrando que a comunicação I2C será feita pelo pino D1 para o SDA e o D2 para o SCL, e a alimentação do display será de 3.3V.
Programa relógio com NodeMCU usando NTP
O programa abaixo foi baseado no programa original contido no guia A Beginner´s Guide to the ESP8266. Ele usa basicamente as bibliotecas do ESP8266, mais a biblioteca SSD1306Wire.h mencionada no post anterior para configuração do display Oled.
Adicionei as funções de comunicação com o display e também os comandos para mostrar o horário no display (linhas 102 à 117). Antes de carregar o programa, você deve configurar as redes wifi disponíveis para o NodeMCU nas linhas 123 a 125, e pode também incluir mais redes, se necessário.
//Programa: Relogio com NodeMCU ESP8266 e display Oled - NTP
//Referencia: A Beginner's Guide to the ESP8266 - Pieter P.
//Adaptacoes e alteracoes: Arduino e Cia
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include <SSD1306Wire.h>
//Cria uma instancia da classe ESP8266WiFiMulti, chamada 'wifiMulti'
ESP8266WiFiMulti wifiMulti;
//Cria uma instancia da classe WifiUDP para enviar e receber dados
WiFiUDP UDP;
IPAddress timeServerIP;
//Define o servidor NTP utilizado
const char* NTPServerName = "b.ntp.br";
//Time stamp do NTP se encontra nos primeiros 48 bytes da mensagem
const int NTP_PACKET_SIZE = 48;
//Buffer para armazenar os pacotes transmitidos e recebidos
byte NTPBuffer[NTP_PACKET_SIZE];
//Pinos do NodeMCU - Interface I2C: SDA => D1, SCL => D2
//Inicializa o display Oled
SSD1306Wire display(0x3c, D1, D2);
void setup()
{
Serial.begin(115200);
delay(10);
Serial.println("rn");
//Inicia a comunicacao com os hothospts configurados
startWiFi();
startUDP();
if (!WiFi.hostByName(NTPServerName, timeServerIP))
{
//Obtem o endereco IP do servidor NTP
Serial.println("DNS lookup failed. Rebooting.");
Serial.flush();
ESP.reset();
}
Serial.print("IP do servidor NTP:t");
Serial.println(timeServerIP);
Serial.println("rnEnviando requisicao NTP...");
sendNTPpacket(timeServerIP);
//Inicializacao do display
display.init();
display.flipScreenVertically();
}
//Requisita horario do servidor NTP a cada minuto
unsigned long intervalNTP = 60000;
unsigned long prevNTP = 0;
unsigned long lastNTPResponse = millis();
uint32_t timeUNIX = 0;
unsigned long prevActualTime = 0;
void loop()
{
unsigned long currentMillis = millis();
if (currentMillis - prevNTP > intervalNTP)
{
//Verificar se passou um minuto da ultima requisicao
prevNTP = currentMillis;
Serial.println("rnEnviando requisicao NTP ...");
sendNTPpacket(timeServerIP);
}
uint32_t time = getTime();
if (time)
{
timeUNIX = time - 10800;
Serial.print("Resposta NTP:t");
Serial.println(timeUNIX);
lastNTPResponse = currentMillis;
} else if ((currentMillis - lastNTPResponse) > 3600000) {
Serial.println("Mais de 1 hora desde a ultima resposta NTP. Reiniciando.");
Serial.flush();
ESP.reset();
}
uint32_t actualTime = timeUNIX + (currentMillis - lastNTPResponse) / 1000;
if (actualTime != prevActualTime && timeUNIX != 0)
{
//Verifica se passou um segundo desde a ultima impressao de valores no serial monitor
prevActualTime = actualTime;
Serial.printf("rUTC time:t%d:%d:%d ", getHours(actualTime), getMinutes(actualTime), getSeconds(actualTime));
Serial.println();
}
//Mostrando a hora no display
//Apaga o display
display.clear();
display.setTextAlignment(TEXT_ALIGN_CENTER);
//Seleciona a fonte
display.setFont(ArialMT_Plain_10);
//Mostra o titulo na parte superior do display
display.drawString(63, 10, "NTP Clock ESP8266");
//Mostra o horario atualizado
display.setFont(ArialMT_Plain_24);
display.drawString(29, 29, String(getHours(actualTime)));
display.drawString(45, 28, ":");
display.drawString(62, 29, String(getMinutes(actualTime)));
display.drawString(78, 28, ":");
display.drawString(95, 29, String(getSeconds(actualTime)));
display.display();
}
void startWiFi()
{
//Coloque aqui as redes wifi necessarias
wifiMulti.addAP("NOME_DA_REDE_WIFI_1", "SENHA_DA_REDE_WIFI_1");
wifiMulti.addAP("NOME_DA_REDE_WIFI_2", "SENHA_DA_REDE_WIFI_2");
wifiMulti.addAP("NOME_DA_REDE_WIFI_3", "SENHA_DA_REDE_WIFI_3");
Serial.println("Conectando");
while (wifiMulti.run() != WL_CONNECTED)
{
//Aguarda a conexao da rede wifi
delay(250);
Serial.print('.');
}
Serial.println("rn");
Serial.print("Conectado a rede ");
Serial.println(WiFi.SSID());
Serial.print("Endereco IP:t");
Serial.print(WiFi.localIP());
Serial.println("rn");
}
void startUDP()
{
Serial.println("Iniciando UDP");
//Inicializa UDP na porta 23
UDP.begin(123);
Serial.print("Porta local:t");
Serial.println(UDP.localPort());
Serial.println();
}
uint32_t getTime()
{
if (UDP.parsePacket() == 0)
{
return 0;
}
UDP.read(NTPBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
//Combina os 4 bytes do timestamp em um numero de 32 bits
uint32_t NTPTime = (NTPBuffer[40] << 24) | (NTPBuffer[41] << 16) | (NTPBuffer[42] << 8) | NTPBuffer[43];
//Converte o horario NTP para UNIX timestamp
//Unix time comeca em 1 de Jan de 1970. Sao 2208988800 segundos no horario NTP:
const uint32_t seventyYears = 2208988800UL;
//Subtrai setenta anos do tempo
uint32_t UNIXTime = NTPTime - seventyYears;
return UNIXTime;
}
void sendNTPpacket(IPAddress& address)
{
//Seta todos os bytes do buffer como 0
memset(NTPBuffer, 0, NTP_PACKET_SIZE);
//Inicializa os valores necessarios para formar a requisicao NTP
NTPBuffer[0] = 0b11100011; // LI, Version, Mode
//Envia um pacote requisitando o timestamp
UDP.beginPacket(address, 123);
UDP.write(NTPBuffer, NTP_PACKET_SIZE);
UDP.endPacket();
}
inline int getSeconds(uint32_t UNIXTime)
{
return UNIXTime % 60;
}
inline int getMinutes(uint32_t UNIXTime)
{
return UNIXTime / 60 % 60;
}
inline int getHours(uint32_t UNIXTime)
{
return UNIXTime / 3600 % 24;
}
Carregado o programa, o NodeMCU vai se conectar na rede wifi disponível, abrir a conexão UDP e efetuar a requisição NTP. Todo o processo pode ser acompanhado pelo serial monitor:

Após a conexão o horário será mostrado no display e atualizado à cada segundo.
Experimente também usar bibliotecas prontas para conexão NTP, como a NtpClientLib, e também veja opções de uso do protocolo NTP com Arduino, que você pode usar por exemplo com conexões ethernet ou shields wifi.

Opa!
Obrigado pelo retorno. Fico feliz em ajudar. 🙂
Abraço!
Adilson
nao esta recebendo a requisiçao
Oi Fabiano,
Na linha 19, tenta usar o servidor b.ntp.br
Abraço!
Adilson
Boa tarde, tive o mesmo problema que o Fabiano fiz os procedimentos citado e foi solucionado. Obrigado e parabéns em compartilhar estas informações. Fique com Deus. "b.ntp.br"
Oi Paulino!
Muito obrigado. Já atualizei o programa no post também. 🙂
Abraço!
Adilson
Funcionou certinho… Muito obrigado….mas tenho uma duvida! como faço para mudar o fuso horário pois meu estado não segue a hora de Brasilia
Oi Erison,
Dê uma olhada neste link aqui, creio que tenha o que você precisa:
https://forum.arduino.cc/index.php?topic=601512.0
Abraço!
Adilson
Olá boa tarde. Implementei hoje isto e não retorna a requisição.
Olá, tudo bem?
Como faço para usar o codigo sem display?Eu já tirei algumas partes, mas o codigo ficou sem funcionamento!!
Olá, tudo bem?
Como faço para usar o codigo sem display?Eu já tirei algumas partes, mas o codigo ficou sem funcionamento!!
Teria como postar um codigo simples, sem nenhum display e so mostrando no monitor serial?