UNO R4 WiFi 0.0.0.0 IP address problem solved

Edit 1/28/2025: Added void TranslateUnixTime(uinty32_t manyseconds) ...

Having explored the DS1703 RTC I2C module with the Elegoo Mega Project kit and needing a faster CPU, I purchased a pair of UNO R4 WiFi boards, thinking through the benefits of having:
i) More memory,
ii) Wi-Fi time synchronization, and
iii) A built-in RTC that interrupts the CPU at a 2 Hz rate.

However, this was before I discovered that the R4's RTC clock rate is set by an on-chip RC oscillator(!), which could give the 'real' in real-time clock a lousy name. Indeed, my #1 UNO R4 board's RTC runs slow by 48 s per hour! The excellent hardware hack by Mr. Radio Pliers aside see his blog here, since I already had planned on using a Wi-Fi connection to an NTP server to keep the RTC on time, and since my application does not mind drift of up to ten seconds from atomic time, I elected to update the RTC from the NTP server every ten minutes. As a result, my RTC never drifts from atomic time by more than 6 or 7 seconds. It's not an excellent solution, but I deemed it good enough until (I hope) Arduino releases an R5 with a precision RTC oscillator. This all worked quite nicely, but although it connected quickly to my home Wi-Fi, about four times out of five, it would obtain the IP address 0.0.0.0 rather than something like 192.168.1.104. Somehow, related to the incorrect 0.0.0.0 IP address, the R4 would also get a strange value for Unix time, something like -123462. I tried everything I could think of, adding delays here and there in the software, reviewing the initial state of variables, and testing cold start, warm reset, cold start and reset. This bizarre behavior almost drove me up the wall, but the problem remained.

Just yesterday, I had an idea that perhaps local network traffic from my dual-band router was making my home network too busy for the (relatively simple-minded) UNO R4 WiFi. After I moved my TV to the 5 GHz Wi-Fi band, the UNO R4 WiFi connected correctly every time! My cable service comes in at 100 Mbps, and while most things connect directly to the router (via Cat5 Ethernet), a printer, a phone, and the UNO R4 WiFi all share the 2.4 GHz Wi-Fi. The TV, alone, uses 5 GHz WiFi.

Declarations:

#include <Arduino.h>          // Standard Arduino library
#include <Wire.h>             // I2C library by Pierre Valleau 1.0.0
#include "RTC.h"              // RTC library in the UNO R4 Board Package
#include <NTPClient.h>        // NTP library by Fabrice Weinberg 3.2.1
#include "arduino_secrets.h" 

#if defined(ARDUINO_UNOWIFIR4) // IDE board definition identifier for the Arduino UNO R4 WiFi board
  #include <WiFiS3.h>          // HTTP library for Uno R4 WiFi by Princetonino Piscos 
#endif

///////please #define your sensitive data in a tab named arduino_secrets.h
// e.g., #define SECRET_SSID "xxxxxxxx" //network name
//       #define SECRET_PASS "zzzzzzzz" //network password
char ssid[] = SECRET_SSID;    // Your network SSID (name)
char pass[] = SECRET_PASS;    // Your network password (use for WPA, or use as key for WEP)

int wifiStatus = WL_IDLE_STATUS;
WiFiUDP Udp; // A UDP instance to let us send and receive packets over UDP
NTPClient timeClient(Udp);

auto timeZoneOffsetHours = -8; // Pacific Time

const bool On = true;
const bool Off = false;
uint8_t displayBuffer[16];
bool AM = false;
bool PM = false;
int Value = 0;
uint16_t intCount = 0;

volatile bool irqFlag = false;

unsigned long UnixTime;
unsigned long UnixSave; // Used for reporting the amount of correction.
unsigned long manyseconds;
uint16_t RTCdrift;  // RTC drift.

const unsigned long SECONDS_IN_MINUTE = 60;
const unsigned long SECONDS_IN_HOUR = 3600;
const unsigned long SECONDS_IN_DAY = 86400UL;
const unsigned long SECONDS_IN_YEAR = 31536000UL;
const unsigned long SECONDS_IN_LEAP_YEAR = 31622400UL;
const int PST_OFFSET = -8 * SECONDS_IN_HOUR; // PST is UTC-8

Relevant code:

//#################################################################
void connectToWiFi(){
  // check if WiFi module installed. NOTE: Wi-Fi band: 2.4 GHz (b/g/n) only
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    while (true); // don't continue if WiFi not N/A.  
  }
  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware!");
  }
  Serial.println("(1) Beginning Wi-Fi Setup...");
  while (wifiStatus != WL_CONNECTED) {
    wifiStatus = WiFi.begin(ssid, pass); // For a WPA/WPA2 network. Comment out if open or WEP network:
    delay(10000); // wait 10 seconds for connection
  }
  Serial.print("    SSID: "); Serial.println(WiFi.SSID()); // Service Set Identifier (SSID).
  delay(1000);
  // Print the ip address of the UNO R4 WiFi board:
  IPAddress ip = WiFi.localIP();
  Serial.print("    IP Address: "); Serial.println(ip); // Local IP address of the UNO R4 WiFi.
  byte mac[6];
  WiFi.macAddress(mac);
  String macAddress = String(mac[5], HEX) + (":") + 
                      String(mac[4], HEX) + (":") + String(mac[3], HEX) + (":") +
                      String(mac[2], HEX) + (":") + String(mac[2], HEX) + (":") +
                      String(mac[1], HEX) + (":") + String(mac[0], HEX);
  Serial.println("    Wi-Fi MAC Address = " + macAddress);
  // Print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("    RSSI: "); Serial.print(rssi); Serial.println(" dBm"); // Received Signal Strength Indicator (RSSI)
  delay(1000); 
}

more:

//**************************************************************
// Convert Unix time (seconds) to year, month, day, hours12, minutes, seconds
//**************************************************************
void TranslateUnixTime(uint32_t manyseconds) {
  int year, month, day, hours, minutes, seconds;
  int hours12; 
  year = 1970;
  while (manyseconds >= (isLeapYear(year) ? SECONDS_IN_LEAP_YEAR : SECONDS_IN_YEAR)) {
    manyseconds -= isLeapYear(year) ? SECONDS_IN_LEAP_YEAR : SECONDS_IN_YEAR;
    year++;
  }
  const int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  month = 0;
  while (manyseconds >= SECONDS_IN_DAY * (daysInMonth[month] + (month == 1 && isLeapYear(year) ? 1 : 0))) {
    manyseconds -= SECONDS_IN_DAY * (daysInMonth[month] + (month == 1 && isLeapYear(year) ? 1 : 0));
    month++;
  }
  month++; // Adjust month to be 1-12 instead of 0-11
  day = manyseconds / SECONDS_IN_DAY + 1;
  manyseconds %= SECONDS_IN_DAY;
  hours = manyseconds / SECONDS_IN_HOUR;
  manyseconds %= SECONDS_IN_HOUR;
  minutes = manyseconds / SECONDS_IN_MINUTE;
  seconds = manyseconds % SECONDS_IN_MINUTE;
  //Convert to 12-hour clock:
  hours = hours % 24; // Reduce hours modulo 24
  minutes = minutes % 60; // Reduce minutes24 modulo 60 // or flag the minutes as an error (blinking decimal points)
  //
  hours12 = ((hours +11) % 12) + 1;
  //minutes = minutes24;
  //ampm12 = (hours12 >= 12);
  SetYear(year);
  SetMonth(month);
  SetDay(day);
  SetHours(hours12);
  SetMinutes(minutes); 
  if ((hours >= 12) | (hours == 0)) {
    SetPM();
  }
  else {
    SetAM();
  }
  Show(GREEN);
}

void setup() {
//---snip---
  connectToWiFi();
  RTC.begin();
  Serial.println("(2) Obtaining time information from the NTP server...");
  timeClient.begin();
  timeClient.update();

  // Get the current date and time from an NTP server and convert
  // it to (UTC - TZONE) by passing the local time zone offset in hours.
  // timeZoneOffsetHours moved to front %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  UnixTime = timeClient.getEpochTime() + (timeZoneOffsetHours * 3600);
  
  Serial.print("    NTP Unix time = "); Serial.println(UnixTime);
  RTCTime timeToSet = RTCTime(UnixTime);
  RTC.setTime(timeToSet);
  RTCTime currentTime; 
  RTC.getTime(currentTime); 
  Serial.println("(3) RTC was just updated using NTP to : " + String(currentTime));
  Serial.print("\nRTC Unix timestamp: "); 
  Serial.print(currentTime.getUnixTime()); Serial.println(" seconds since 1 Jan 1970.");
  Serial.print("Current Time: ");
  Serial.print(currentTime.getDayOfMonth()); 
  Serial.print("/");
  Serial.print(Month2int(currentTime.getMonth()));
  Serial.print("/");
  Serial.print(currentTime.getYear());
  Serial.print(" - ");
  if (currentTime.getHour() < 10) Serial.print(0);
  Serial.print(currentTime.getHour());
  Serial.print(":");
  if (currentTime.getMinutes() < 10) Serial.print(0);
  Serial.print(currentTime.getMinutes());
  Serial.print(":");
  if (currentTime.getSeconds() < 10) Serial.print(0);
  Serial.print(currentTime.getSeconds());
  Serial.println(" (DD/MM/YYYY - HH:MM:SS)");

  if (!RTC.setPeriodicCallback(periodicCallback, Period::N2_TIMES_EVERY_SEC)) {
    Serial.println("ERROR: Periodic callback not set!");
  }
}


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  L  O  O  P  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void loop() {
  RTCTime currentTime; // RTC is an object set to the current time.
  while(irqFlag == false) { } // Poll the interrupt flag to wait for the next 0.5 s interrupt. 
  RTC.getTime(currentTime); // Get current Unix Time from RTC (seconds since 1 Jan 1970) 
  uint32_t manyseconds = currentTime.getUnixTime();
  delay(100);
  TranslateUnixTime(manyseconds); //translate RTC time to the MMM DD YYYY HHMM AM/PM format.
  ledState = !ledState;
  //digitalWrite(LED_BUILTIN, ledState); // Debug only
  SetColon(ledState); // Blink the real Present Time colon at a 1 Hz rate. 
  Show(GREEN); // Update the real Present Time LED display.
  irqFlag = false;
  // Perform any other needed repeating tasks here.
  const uint16_t ResyncDelta = 1200; // 1200/2 = 600 seconds. Must be a multiple of 60  
  intCount++;
  if (intCount == ResyncDelta) {
    // Make a correction to the RTC time:
    intCount = 0;
    // Place code here to resync RTC to NTP time every ten minutes.
    UnixSave = UnixTime;
    timeClient.begin();
    timeClient.update();
    UnixTime = timeClient.getEpochTime() + (timeZoneOffsetHours * 3600);
    RTCTime timeToSet = RTCTime(UnixTime);
    RTC.setTime(timeToSet);
    // Calculate the NTP time correction in seconds: (ResyncMinutes * 60) - (delta UnixTime)
    RTCdrift = (ResyncDelta / 2) - UnixTime + UnixSave;
    Serial.print("RTC drift after "); Serial.print(ResyncDelta/120);Serial.print(" minutes is ");
    Serial.print(RTCdrift); Serial.println(" seconds.");
  } 
}

void periodicCallback() {irqFlag = true;} 

See? TV is bad for you.

1 Like