Data e hora no ESP8266 com NTP

Todos sabemos da importância do tempo, e sabemos que ele não para e não sofre nenhuma influência, pelo menos com a tecnologia que temos hoje!

No artigo de hoje, vou mostrar como utilizar o NTP (Network Time Protocol), que é um protocolo utilizado para a sincronização dos relógios dos computadores. Este protocolo é amplamente utilizado em sistemas, que nem sempre possuem grande exatidão, havendo a necessidade de sincronismo.

Em sistemas embarcados, que necessitam de relógios, é comumente utilizado o RTC (Real Time Clock), que serve para contar o tempo. O RTC pode contar com baterias dedicadas para manter a contagem do tempo mesmo na ausência de energia no restante do circuito.

RTC no ESP8266

O ESP8266, não possui um RTC convencional. O ESP tem apenas um contador de tempo que é zerado sempre que a alimentação é cortada.

Para utilizar RTC no ESP, é necessário adicionar um hardware, porém para sistemas em que quase sempre há uma conexão com a Internet, podemos utilizar o NTP como um relógio de tempo real, bastando apenas uma sincronização com o servidor de tempo.

Time Epoch

O time epoch (UNIX Time) é uma representação de tempo que conta os segundos desde o dia 1 de Janeiro 1970, e é amplamente utilizada em sistemas, já que ocupa menos espaço e simplifica algumas operações, principalmente na comparação de datas.

Para o exemplo de NTP no ESP, vamos utilizar o time epoch como representação de tempo.

Código

Para o exemplo de código, vamos utilizar a plataforma Arduino e a biblioteca NTPClient. A IDE é o platformIO.

Para a intalação da biblioteca:

platformio lib install 551

 

Note que na variável utc, definimos o fuso horário, que no caso do Brasil é UTC -3:00.

int16_t utc = -3; //UTC -3:00 Brazil

O servidor de tempo (a.st1.ntp.br), foi utilizado da base do ntp.br.

Para forçar a atualização do relógio no servidor NTP, basta chamar a função forceUpdate.

É importante lembrar que somente na inicialização ou quando a atualização é forçada, a conexão com a internet é necessária.

Para obter o horário em formato Gregoriano, utilize a função timeClient.getFormattedTime().

Conclusão

Em sistemas em que saber o tempo é importante, é essencial utilizar de um RTC, ou a técnica de sincronização com NTP. Acontece que no universo da Internet das Coisas, entende-se que a conexão com a internet não será problema, sendo assim a sincronização com o NTP é uma solução muito eficaz.

O RTC por hardware já é o mais indicado para sistemas em que não há internet.

Happy Hacking!

20 Comments

  1. tiago alexandre batista

    Opa, show de bola, agora é só fundir esse code com o projeto de webserver

    Reply
  2. Robson

    Só faltou o principal, a biblioteca do ESP8266:
    fatal error: ESP8266WiFi.h: No such file or directory

    Reply
    1. Pedro Minatel (Post author)

      Robson, está com a IDE Arduino?

      Reply
      1. Edmilson

        EU estou com a IdE do arduino e está dando esse erro

        Reply
        1. Pedro Minatel (Post author)

          O arquivo está com a extensão .ino? Está selecionada a placa ESP8266 nas configurações da IDE?

          Reply
  3. Rômulo Azevedo

    É possível acionar uma saída fazendo uma comparação com o horário gerado?

    Reply
  4. Rômulo Azevedo

    É possível extrair dia, mês e ano do servidor NTP?

    Reply
    1. Pedro Minatel (Post author)

      Sim, por meios de funções de conversão de time epoch, como esse exemplo: http://www.epochconverter.com/programming/c

      Abrs,
      Pedro

      Reply
  5. Amando Oliveira

    bom dia Pedro!
    como faço para exibir no lcd a hora com esse seu exemplo acima?

    Reply
  6. Sérgio

    O retorno que tenho da hora está sempre na faixa 0-12 e não na faixa 0-23. O que faço para tê-la na faixa 0-23? Obrigado.

    Reply
  7. Thomé Lucas

    Olá, muito interessante isso. Funciona com o Arduino UNO tb?
    Outra coisa, se eu quiser que um rele ligue as 20:30 e desligue as 21:10.

    Como eu vou comparar as variáveis hora e minuto?

    Reply
    1. NEY SILVA

      Divida a informação em pedaços conforme o codigo abaixo. No caso só estou pegando os segundos.
      String a=timeClient.getFormattedTime();
      Serial.print(a);
      Serial.print(” “);
      seg=(a.substring(6, 8));
      Serial.println(seg);

      Reply
  8. Roger Correa

    Pedro,

    Pra mim só funcionou depois que mudei o servidor para pool.ntp.org.

    Reply
    1. Pedro Minatel (Post author)

      Roger, existem várias opções de servidores. É interessante até usar mais de uma opção dentro do código.

      Reply
  9. Daniel Fabro

    E a correção durante o horário de verão? Já que o servidor NTP não corrige automaticamente.

    Reply
    1. Pedro Minatel (Post author)

      Daniel, esse tratamento tem que ser feito manualmente, no ESP ou no seu backend. Em aplicações que eu já trabalhei, o ajuste era feito por um backend.

      Reply
  10. Daniel Fabro

    Oi Pedro, obrigado pela resposta, acho muito bacana o seu trabalho, parabéns. Vou colar aqui, um código que desenvolvi, para o caso de alguém se interessar por um ajuste automaticamente do horário de verão brasileiro feito direto no ESP. Atenciosamente Daniel.

    #include
    #include
    #include

    char ssid[] = “**********”; // your network SSID (name)
    char pass[] = “**********”; // your network password

    unsigned int localPort = 2390; // local port to listen for UDP packets
    IPAddress timeServerIP; // time.nist.gov NTP server address
    const char* ntpServerName = “time.nist.gov”;
    const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
    byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
    WiFiUDP udp;

    void setup()
    {
    Serial.begin(115200);
    Serial.println();
    Serial.println();

    // We start by connecting to a WiFi network
    Serial.print(“Connecting to “);
    Serial.println(ssid);
    WiFi.begin(ssid, pass);

    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(“.”);
    }
    Serial.println(“”);

    Serial.println(“WiFi connected”);
    Serial.println(“IP address: “);
    Serial.println(WiFi.localIP());

    Serial.println(“Starting UDP”);
    udp.begin(localPort);
    Serial.print(“Local port: “);
    Serial.println(udp.localPort());
    }

    void loop()
    {
    WiFi.hostByName(ntpServerName, timeServerIP);
    sendNTPpacket(timeServerIP);
    delay(1500);

    int cb = udp.parsePacket();
    if (!cb) {
    Serial.println(“no packet yet”);
    }
    else {
    udp.read(packetBuffer, NTP_PACKET_SIZE);
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    const unsigned long seventyYears = 2208988800UL;
    unsigned long epoch = secsSince1900 – seventyYears;
    setTime(epoch – 10800);
    setTime(epoch – timeZone());
    displayCurrentTime();
    delay(10000);
    }
    }

    int timeZone()
    {
    int previousSunday = day() – weekday();
    if (month() 10) return 7200;
    else if (month() == 2 && previousSunday = 14) return 7200;
    else return 10800;
    }

    void displayCurrentTime()
    {
    Serial.print(hour());
    Serial.print(“:”);
    Serial.print(minute());
    Serial.print(“:”);
    Serial.print(second());
    Serial.println();
    }

    unsigned long sendNTPpacket(IPAddress& address)
    {
    Serial.println(“sending NTP packet…”);
    memset(packetBuffer, 0, NTP_PACKET_SIZE);
    packetBuffer[0] = 0b11100011; // LI, Version, Mode
    packetBuffer[1] = 0; // Stratum, or type of clock
    packetBuffer[2] = 6; // Polling Interval
    packetBuffer[3] = 0xEC; // Peer Clock Precision
    packetBuffer[12] = 49;
    packetBuffer[13] = 0x4E;
    packetBuffer[14] = 49;
    packetBuffer[15] = 52;
    udp.beginPacket(address, 123); //NTP requests are to port 123
    udp.write(packetBuffer, NTP_PACKET_SIZE);
    udp.endPacket();
    }

    Reply
  11. Daniel Fabro

    Eu uso esse código a algum tempo, funciona perfeitamente. Já passou 3 vezes pelo horário de verão. As bibliotecas necessárias são:
    #include ESP8266WiFi.h
    #include WiFiUdp.h
    #include TimeLib.h

    Abraço.

    Reply
  12. Whilton

    tem como adicionar um relógio na pagina do servidor esp?

    Reply
  13. Alessandro Pinho

    show de bola.

    Reply

Deixe seu comentário