Protocolo de tempo NTP com ESP
É comum que em projetos de automação e robótica seja necessário saber a hora correta, para marcar a hora em que uma ação ocorreu ou até para ativar sensores em certo horário. Vamos aprender a adicionar um RTC (Real Time Clock – Relógio de tempo Real) ao ESP sem precisar de um hardware externo, como por exemplo um DS1307 ou do DS3231. Para isso, usaremos o NTP que só precisa de uma conexão com a internet o que é facilmente resolvido quando o assunto é projetos com ESP e IoT.
Sobre o NTP
Do Wikipédia:
O NTP é um protocolo para sincronização dos relógios dos computadores baseado no protocolo UDP sob a porta 123, para sincronização do relógio de um conjunto de computadores em redes de dados com latência variável. O NTP permite manter o relógio de um computador com a hora sempre certa e com grande exatidão.
O NTP serve tanto para atualizar e também manter os horários e datas sincronizadas entre dispositivos. Não há muitas explicações sobre isto, porém caso queira aprender mais sobre o NTP, clique AQUI ou AQUI.
Digamos que você tem uma rede de sensores, e precisa que eles liguem as 20h da noite, as melhores alternativas para isto, são um RTC externo/interno ou até o NTP caso haja conexão com a internet. Para o exemplo deste tutorial, acenderemos o LED Onboard de acordo com o horário que iremos definir. Com o NTP, também é possível arrumar a data e hora de um RTC externo que esteja errado!
Neste GIF, é mostrado o funcionamento do exemplo deste tutorial, no qual o LED foi acionado as 19:23:30.
Mãos à obra
Componentes necessários
Montando o projeto
Nesse projeto usaremos apenas a placa NodeMCU. Usaremos o LED que já vem na placa ligado ao Pino D4 para fazer nossa experiência. Também funciona com ESP32.
Código do projeto
Não se esqueça de alterar as credenciais do WiFi e usar o fuso horário correto. Também altere para o horário que desejar, como o tutorial foi feito as 19:23, usamos este valor.
#include <NTPClient.h>//Biblioteca do NTP. #include <WiFiUDP.h>//Biblioteca do UDP. #include <ESP8266WiFi.h>//Biblioteca do WiFi. WiFiUDP udp;//Cria um objeto "UDP". NTPClient ntp(udp, "a.st1.ntp.br", -3 * 3600, 60000);//Cria um objeto "NTP" com as configurações. #define led D4//Define o LED ao pino D4. String hora;//Váriavel que armazenara o horario do NTP. void setup() { Serial.begin(9600);//Inicia a comunicação serial. pinMode(led, OUTPUT);//Define o pino como saida. digitalWrite(led, 1);//Apaga o LED. WiFi.mode(WIFI_STA); WiFi.begin("SUA REDE", "SUA SENHA");//Conecta ao WiFi. delay(2000);//Espera a conexão. ntp.begin();//Inicia o NTP. ntp.forceUpdate();//Força o Update. } void loop() { hora = ntp.getFormattedTime();//Armazena na váriavel HORA, o horario atual. Serial.println(hora);//Printa a hora já formatada no monitor. if (hora == "19:23:30")//Se a hora atual for igual à que definimos, irá acender o led. { digitalWrite(led, 0);//Acende } delay(1000);//Espera 1 segundo. }
Entendendo a fundo
Software
-Declarando o objeto
NTPClient ntp(udp, "a.st1.ntp.br", -3 * 3600, 60000);//Cria um objeto "NTP" com as configurações.
Aqui é criado o objeto NTP com os seguintes parâmetros:
- Objeto UDP.
- Servidor do NTP, Acesse ESTE link para ver os servidores brasileiros disponíveis.
- Fuso horário multiplicado por segundos, apenas altere o fuso horário se for necessário.
- intervalo de updates para atualização da hora, é necessário para manter a hora correta. O padrão é 1 Minuto.
-Função NTPClient::begin() e forceUpdate()
ntp.begin();//Inicia o NTP. ntp.forceUpdate();//Força o Update.
Iniciamos o NTP e também forçamos o update para certificar de que a hora esteja certa.
-Salvando a hora atual
hora = ntp.getFormattedTime();//Armazena na váriavel HORA, o horario atual.
Esta função ntp.getFormattedTime() retorna uma string com a hora atual, contendo HH:MM:SS. Salvamos isto na nossa String hora
Também é possível pegar os dados separados ou até o dia. Veja as funções da biblioteca!
-Acionando o LED com a hora
if (hora == "19:23:30")//Se a hora atual for igual à que definimos, irá acender o led. { digitalWrite(led, 0);//Acende }
Caso a variável que contem a hora atual seja igual à definida, neste caso é 19:23:30, acenderá o LED.
Desafio
O desafio desta vez, é manter o LED aceso entre intervalos de tempo, por exemplo das 13h até as 16h. Para isto, pode-se usar a boa e velha lógica booleana ou a função constrain() do arduino. Boa sorte!
Considerações finais
A implementação deste simples protocolo pode ser de grande ajuda e utilidade em seus projetos que tenham conexão com a Internet. Dúvidas? Sugestões? Críticas? Comente abaixo!
Estudante de Engenharia da Computação pela USC, pretende se aprimorar e fazer a diferença nesta imensa área da tecnologia. Apaixonado por IoT, sistemas embarcados, microcontroladores e integração da computação nos mais diversos fins práticos e didáticos.
29 Comments
Deixe uma pergunta, sugestão ou elogio! Estamos ansiosos para ter ouvir!Cancelar resposta
Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.
Olá, José! Sobre o seu desafio ele é justamente o problema que estou tendo pra implementarem um código para comunicação de dois ESP-32 via LoRa. Se separo o código somente para acender o LED com restrições de horário, ele funciona perfeitamente, mas quando implemento no código ele se conecta ao servidor, printa a hora da conexão, mas não atualiza o horário depois disso nem o printa. Poderia me ajudar?
Onde encontro as outras bibliotecas?
Boa noite, José Morais.
Excelente artigo e muito esclarecedor.
Eu só não compreendi bem em qual momento a hora é fornecida pelo RTC interno do Esp32 e quando é fornecida pelo NTP. Seria sempre informada pelo RTC interno e só usaria o NTP cliente para atualizar de 1 em 1 minuto? É isso mesmo? E caso a rede wifi falhe? Como esse comando NTPClient trata essa falha de comunicação? Seguiria com as configuração anterior, mesmo que sendo acometida por drifting, até que consiga restabelecer conexão wifi? Ou é preciso a gente criar um tratamento na unha para essa situação e como sugeriria?
Pelos testes iniciais que fiz aqui, aplicando 10.000 milisegundos = 10 segundos para atualização e após desligar a rede Wifi, o RTC interno do ESP32 continuou operando normalmente, não tendo gerando drifting visível em 10 minutos corridos.
O horário é mantido internamente mesmo no Arduino (sem RTC interno), através dos próprios timers. Voltando ao ESP32, o drift será percebido ao longo do tempo CASO o NTP pare de atualizar o horário. O NTP deve ser executado apenas no tempo estabelecido, logo, entre estes tempos, o tempo é mantido por funções internas. Lembrando que o drift máximo padrão pro RTC interno do ESP32 vai ser 5% ao dia, porém, a IDF já faz calibração em todo boot, então o drift acaba sendo bem menor que 5%.
Obrigado pelo retorno, José Morais. Apanhando agora em compreender como referenciar os pinos do ESP32 dev kit com o Arduino IDE. Boas festas e um 2020 prá lá de ótimo para você.
Não sei, se é só comigo, mas não consigo fazer sincronizar com o servidor NTP
Esse link tem outra aplicação de NTP e ESP com um display OLED: https://www.arduinoecia.com.br/2018/04/relogio-nodemcu-esp8266-display-oled-ntp.html
Olá. Saberia me dizer como faço para converter a a data e hora obtida via protocolo NTP para po formato UNIX TIME e atualizar meu relógio interno RTC?
Mas é claro! Viva o UNIX TIME hehe, facilita muitas coisas… Procure sobre a biblioteca “time.h” do próprio C, com ele você consegue pegar uma String (data formatada) e converter para UNIX (ou vice-versa e etc). Utilizei a time.h pra algo parecido no post do “RTC ESP32”
Como proceder ?
‘WiFiUDP’ does not name a type
O primeiro erro foi esse, WiFiUDP.h: No such file or directory, então mudei para WiFiUdp e passou. E agora o erro é esse ‘WiFiUDP’ does not name a type kk
Parabéns José, belo exemplo.
Sabe como fazer para obter a hora de acordo com o horário de verão ?
Grato, Odilon
Eu tenho um ESP pegando a hora via internet e um que não está conectado na internet.
Dá para buscar a informação de data e hora no ESP que está pegando a informação pela internet?
Sim, você pode usar TCP ou UDP para transmitir a informação entre ambos caso precise de algo sem fio. Ou também pode usar algo como SPI, I2C e UART para transmitir com fios
Preciso de ajuda aqui, estou usando seu código para acender uma fileira de leds, mas estou com alguns problemas na parte do tempo ligado, basicamente eu quero o seguinte: liga gradativamente 12:00 e 12:300 fica totalmente ligada, e 20:00 desliga gradativamente e 20:30 fica totalmente desligada, essa parte consegui fazer, o problema é que quero que aconteça o seguinte, caso eu desligue e ligue o esp, entre 12:31 e 219:59 quero que ele ligue totalmente os leds, e se eu ligar entre 20:31 e 11:59 quero que permaneçam apagados, se puder me ajudar agradeço, chamei no messenger também caso seja melhor pra explicar
Olá José,
eu estou recebendo este erro, pode me ajudar?
“Documents\Arduino\libraries\ESP8266WiFi\src/ESP8266WiFiType.h:26:19: fatal error: queue.h: No such file or directory
compilation terminated.”
Que errinho mais complicado em hehe, isso tem cara de ser do rtos… De qualquer maneira, creio que seja com as bibliotecas internas, sugiro que você reinstale todas as bibliotecas do esp8266 (core). Não sei se resolverá mas pode tentar…
Eu consegui resolver isso, realmente é um problema de biblioteca interna, o arquivo queue.h estava escrito de forma diferente no diretório original, só alterei o nome! Mas obrigado pela dica, as bibliotecas do esp8266 estão todas bagunçadas realmente! rsrsrs
José, com o NTP consigo levantar a data?
Abaixo levantamos a hora …
hora = ntp.getFormattedTime()
obrigado
Me parece que esta biblioteca em particular não, procure por outra que deve ser mais simples. A única possíbilidade que vi por cima nessa biblioteca é utilizar a função Epochtime que retorna o tempo desde janeiro 1970 (Unix time), com isso você pode chegar no ano, mes, dia, hora, minuto e segundo.
Oi José! Primeiramente, obrigado pela resposta;
Vc poderia me ajudar como unir os 2 códigos corretamente, pois, ñ é a questão de unir e sim, como unir, pois eu não tenho experiência!
E tb quais as bibliotecas de qual código eu deixaria de usar e de qual código eu usaria, lembrando que eu eliminaria o DS1307 e passaria usar somente o NTP com ESP66? Obrigado++
Olá José! Será que, por bondade e gentileza, vc poderia me dar uma ajuda com o seguinte:
Eu tenho esse código Arduino, que é de um Relógio Digital com Display TFT e RTC DS1307 mas, gostaria de eliminar o RTC e usar o NTP com ESP8266 Nodemcu porém, não tenho conhecimento suficiente para tal.
O código é esse abaixo: (as fontes estão em duas novas abas)
/* UTFT Digital Clock
* http://arduino-project.net/chasy-na-arduino-tft01-22sp/
* https://www.youtube.com/watch?v=l2ZvO5DHExo
*/
#include //inclui a biblioteca DS1307
DS1307 rtc(A4, A5); //inicializa entradas
#include //inclui a biblioteca UTFT
extern uint8_t DotMatrix_M[]; //Liga a fonte DotMatrix_M
extern uint8_t SevenSeg_XXXL_Num[]; //Liga a fonte SevenSeg_XXXL_Num
UTFT myGLCD(TFT01_22SP,9,8,12,11,10); //Liga o display TFT01_22SP
void setup( )
{
rtc.halt(false); //inicializa o relógio
myGLCD.InitLCD(); //inicializa o display
myGLCD.fillScr(0, 0, 0); //mostra a tela em preto
}
void loop( )
{
String stringOne = rtc.getTimeStr();
myGLCD.setColor(65, 105, 225); //cor da fonte das horas
myGLCD.setFont(SevenSeg_XXXL_Num); //fonte para exibir
myGLCD.print(stringOne.substring(0,2), 12, 60); //indicação das horas
myGLCD.print(stringOne.substring(3,5), 180, 60); //indicação dos minutos
myGLCD.fillCircle(160, 88, 7); //Ponto superior
myGLCD.fillCircle(160, 133, 7); //Ponto inferior
myGLCD.setColor(0, 255, 0); //cor da fonte da data
myGLCD.setFont(DotMatrix_M); //fonte para exibir
myGLCD.print(rtc.getDateStr(), 80, 190); //exibição da data
}
Os créditos do projeto é do Russo Иван Мартынюк e, talvez é de seu interesse.
Sem mais, deixo-lhe meus agradecimentos.
Daniel, recomendo que você teste esses 2 componentes separadamente no ESP66 e caso ambos funcionem, faça a integração (juntar) os 2 no mesmo projeto. Se os 2 funcionarem perfeitamente, por conta da compatibilidade entre o ESP e Arduino, o NTP também irá funcionar, bastando integra-lo.
Ola , gostaria de saber como pegar a Data e formatar para dd/mm/yyyy?
Não achei métodos simples com essa biblioteca, sugiro pesquisar por outra biblioteca ou fazer “na mão” com o UNIX TIME.
Olá, tenho um projeto com um ESP8266 que está se comunicando por MQTT pela porta 1883, sabes se tem como usar os dois protocolos juntos? E para que serve a linha: WiFi.mode(WIFI_STA);?
Sim, o ESP permite multiplas portas. Essa função serve para habilitar o modo estação do ESP, fazendo com que ele se conecte em alguma rede WiFi.