espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.58k stars 7.4k forks source link

Espressif NTP library and Arduino Ethernet library incompatibility #10252

Open gabrielbravov opened 2 months ago

gabrielbravov commented 2 months ago

Board

ESP32 Dev Module Breakout Board (aliexpress version)

Device Description

I have an ESP32 Wroom Breakout Board and Ethernet Module with W5500 IC connected trough SPI and CS pin attached to GPIO5.

Hardware Configuration

No, just the w5500 module.

W5500 ESP32 MOSI-> GPIO23 MISO-> GPIO19 CLK -> GPIO18 CS -> GPIO5 VCC -> +3V3 GND -> GND

Version

latest master (checkout manually)

IDE Name

Platformio

Operating System

Ubuntu 22.04 LTS

Flash frequency

default config

PSRAM enabled

yes

Upload speed

9600

Description

NTP Example from https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP32/examples/Time/SimpleTime/SimpleTime.ino works nice with WiFi, but when i change the code to use Ethernet with static ip, the code never reach the NTP server to recieve actual date and time and just answer via Serial Monitor "No time available (yet)".

I created an example code to works with both configurations (WiFi and Ethernet), if a comment the line N° 11 that says "#define Ethernet" it connects via WiFi and if i uncomment this line, it's connect via Ethernet.

I tried to make an NTP request using the same port using my linux machine via CLI with the command "ntpdate -q ntp.shoa.cl" (without quotation marks) and the server answer ok in my computer via ethernet but not in my esp32 via ethernet. I too tried other NTP servers from local network and outside without success.

This it's the platformio.ini code: `[env:esp32dev] platform = espressif32 board = esp32dev framework = arduino

monitor_speed = 9600 monitor_filters = time

lib_deps =

RECOMMENDED

Accept new functionality in a backwards compatible manner and patches

arduino-libraries/Ethernet`

Sketch

#include <Arduino.h>

#include <WiFi.h>
#include "time.h"
#include "esp_sntp.h"

#include <SPI.h>
#include <Ethernet.h>       // Ethernet library v2 is required

//If comment works with WiFi, if not works with Ethernet
#define ETHERNET

// const char *ssid = "YOUR_SSID";
// const char *password = "YOUR_PASS";

#ifdef ETHERNET
// Set your Static IP address
IPAddress local_IP(192, 168, 10, 126);
// Set your Gateway IP address
IPAddress gateway(192, 168, 10, 1);
IPAddress subnet(255, 255, 255, 0);

// Enter a MAC address and IP address for your controller below.
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xDE
};
#endif

#ifndef ETHERNET
// const char *ssid = "YOUR_SSID";
// const char *password = "YOUR_PASS";
#endif

// const char *ntpServer1 = "10.10.8.9";
const char *ntpServer1 = "1.debian.pool.ntp.org";

// const char *ntpServer2 = "ntp.shoa.cl";
// const long gmtOffset_sec = 0;
// const int daylightOffset_sec = 0;

void printLocalTime();
void timeavailable(struct timeval *t); // Callback function (gets called when time adjusts via NTP)
void getDate();
void getDateAndHour();

char fechaanterior[13] = "DD-MM-AA.csv";  //Auxiliar para escribir encabezado en cada .csv

// const char *time_zone = "<-04>4<-03>,M9.1.6/24,M4.1.6/24";  // TimeZone rule for Chile including daylight adjustment rules (optional).
                                                            //Obtenida de https://github.com/esp8266/Arduino/blob/master/cores/esp8266/TZ.h

void setup() {
  Serial.begin(9600);

  // First step is to configure WiFi STA and connect in order to get the current time and date.
  #ifndef ETHERNET
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  #endif

  #ifdef ETHERNET
  Ethernet.init(5);         // SS pin for spiV
  Ethernet.begin(mac, local_IP);  // start the Ethernet connection
  delay(1000);              // give the Ethernet shield a second to initialize
  Serial.print("Direccion IP: "); Serial.println(Ethernet.localIP());
  #endif

  /**
   * NTP server address could be acquired via DHCP,
   *
   * NOTE: This call should be made BEFORE esp32 acquires IP address via DHCP,
   * otherwise SNTP option 42 would be rejected by default.
   * NOTE: configTime() function call if made AFTER DHCP-client run
   * will OVERRIDE acquired NTP server address
   */
  // esp_sntp_servermode_dhcp(1);  // (optional) (create a crash loop if uncommented with ethernet connection)

  #ifndef ETHERNET
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" CONNECTED");
  #endif

  // set notification call-back function
  sntp_set_time_sync_notification_cb(timeavailable);

  /**
   * This will set configured ntp servers and constant TimeZone/daylightOffset
   * should be OK if your time zone does not need to adjust daylightOffset twice a year,
   * in such a case time adjustment won't be handled automagically.
   */
  // configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2);

  /**
   * A more convenient approach to handle TimeZones with daylightOffset
   * would be to specify a environment variable with TimeZone definition including daylight adjustmnet rules.
   * A list of rules for your zone could be obtained from https://github.com/esp8266/Arduino/blob/master/cores/esp8266/TZ.h
   */
  configTzTime("<-04>4<-03>,M9.1.6/24,M4.1.6/24", ntpServer1);
}

void loop() {
  delay(5000);
  printLocalTime();  // it will take some time to sync time :)
  getDate();
}

void printLocalTime() {
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo, 20000)) {
    Serial.println("No time available (yet)");
    return;
  }
  // Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");

  //Nomenclatura obtenida de https://cplusplus.com/reference/ctime/strftime/
  // Serial.println(&timeinfo, "%D"); //Fecha abreviada en ingles, no sirve
  // Serial.println(&timeinfo, "%d %m %Y %H:%M:%S");

  Serial.println("Time variables");
  char timeHour[3];
  strftime(timeHour,3, "%H", &timeinfo);
  Serial.print("Hora: ");
  Serial.println(timeHour);

  char timeMinute[3];
  strftime(timeMinute,3, "%M", &timeinfo);
  Serial.print("Minuto: ");
  Serial.println(timeMinute);

    char timeSecond[3];
  strftime(timeSecond,3, "%S", &timeinfo);
  Serial.print("Segundo: ");
  Serial.println(timeSecond);

  char timeWeekDay[3];
  strftime(timeWeekDay,10, "%d", &timeinfo);
  Serial.print("Día: ");
  Serial.println(timeWeekDay);

  char timeMonth[3];
  strftime(timeMonth,10, "%m", &timeinfo);
  Serial.print("Mes: ");
  Serial.println(timeMonth);

  char timeYear[5];
  strftime(timeYear,10, "%g", &timeinfo);
  Serial.print("Año: ");
  Serial.println(timeYear);
  Serial.println("###########");
}

// Callback function (gets called when time adjusts via NTP)
void timeavailable(struct timeval *t) {
  Serial.println("Got time adjustment from NTP!");
  printLocalTime();
}

void getDateAndHour(){

  struct tm timeinfo;
  if (!getLocalTime(&timeinfo, 20000)) {
    Serial.println("No time available (yet)");
    return;
  }

  char fecha[20];
  strftime(fecha, sizeof(fecha), "%d/%m/%y,%H:%M:%S,", &timeinfo);
  Serial.println(fecha);
}

void getDate(){

  struct tm timeinfo;
  if (!getLocalTime(&timeinfo, 20000)) {
    Serial.println("No time available (yet)");
    return;
  }

  char fecha[11];
  strftime(fecha, sizeof(fecha), "%d-%m-%y", &timeinfo);
  Serial.println(fecha);

}

Debug Message

Doesn't apply.

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

lbernstone commented 2 months ago

If you set core debug level to verbose, do you get any additional logging about what fails?

gabrielbravov commented 2 months ago

If you set core debug level to verbose, do you get any additional logging about what fails?

Nothing strange, just this: 17:43:16.216 -> #�����a8�D��l� �W(��ٴ�Oh�[ 68][V][esp32-hal-uart.c:463] uartBegin(): UART0 initialization done. 17:43:18.192 -> Direccion IP: 192.168.10.126 17:43:43.202 -> No time available (yet) 17:44:03.215 -> No time available (yet) 17:44:28.218 -> No time available (yet) 17:44:48.227 -> No time available (yet)

JAndrassy commented 2 months ago

are you sure that you are using "latest master (checkout manually)"?

the Arduino Ethernet library doesn't configure and use the ESP32 networking and the ESP32 SNTP is part of that.

me-no-dev commented 2 months ago

@gabrielbravov seems that you are running Arduino v2.0.17 through PlatformIO. I suggest to update to v3.0.4 (@Jason2866 can help with pio config) and then use our new ETH.h library, which is fully integrated with the network stack

Jason2866 commented 2 months ago

@gabrielbravov Easy when you already using Platformio. Go to https://github.com/pioarduino/platform-espressif32 It is described in the repo readme what change is needed.

gabrielbravov commented 2 months ago

It was solved with me-no-dev recommendation about to use ETH Library from espressif and changing the platform core from platformio.ini as Jason2866 recommended.

Thanks for the work.

Just a additional comment, the ETH Library has very few examples to understand how to change mac address or how to use static ip adresses, it would be useful if you can add more examples. Too, i would like to have a ping library (icmp echo) to work with framework arduino, the actual avaliable libraries from github are old, don't work with ethernet and are unsupported.

JAndrassy commented 2 months ago

@gabrielbravov, my EthernetESP32 library is an alternative to ETH which is much more similar to Arduino Ethernet library. and it has some examples. https://github.com/Networking-for-Arduino/EthernetESP32

lbernstone commented 2 months ago

Too, i would like to have a ping library (icmp echo) to work with framework arduino, the actual avaliable libraries from github are old, don't work with ethernet and are unsupported.

The esp-idf includes a ping library based on lwip. It would not be a huge effort to wrap some oop around it, but that really is outside the scope of arduino-esp32 and should be implemented as a 3rd party library.

me-no-dev commented 2 months ago

@gabrielbravov to use static IP you init ETH as follows:

// ETH pins
#define ETH_CS          15
#define ETH_IRQ          4
#define ETH_RST          5

// SPI pins
#define ETH_SPI_SCK     14
#define ETH_SPI_MISO    12
#define ETH_SPI_MOSI    13

void setup() {
  IPAddress ip(192, 168, 0, 8);
  IPAddress gw(192, 168, 0, 1);
  IPAddress mask(255, 255, 255, 0);
  IPAddress dns(192, 168, 0, 1);
  SPI.begin(ETH_SPI_SCK, ETH_SPI_MISO, ETH_SPI_MOSI);
  ETH.begin(ETH_PHY_W5500, 1, ETH_CS, ETH_IRQ, ETH_RST, SPI);
  ETH.config(ip, gw, mask, dns);
}