can't get a date from an NTP server

I have (partially) completed a weather station that sends data over my home LAN by connecting to the wifi access point. The system uses an Arduino Zero and a Wifi-101.The wireless link has been working fine.

I’m now trying to add ntp date-time lookup, but I can’t get that working. I’ve started with a slightly modified version of the Example WifiUdpNtpClient provided for the Wifi101 in the Arduino IDE.

/*	ntpZeroWifi.ino			22 June 2016		by RAGS
 *  
 *  designed for Arduino Zero + Arduino Wifi101 shield
 *  
 */

#include <SPI.h>
#include <RTCZero.h>
#include <WiFi101.h>
#include <WiFiUdp.h>

unsigned int localPort = 8888;      // local port to listen for UDP packets
IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
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
// A UDP instance to let us send and receive packets over UDP
WiFiUDP Udp;

RTCZero rtc;
/* Change these values to set the current initial time and date */
const byte seconds = 0;             // seconds needs to be zero
const byte minutes = 1;             // the rest don't matter
const byte hours = 1;
const byte day = 1;
const byte month = 1;
const byte year = 1;

char ssid[] = "hotwings";
char pass[] = "DunkirkNY17June1972";
int status = WL_IDLE_STATUS;
IPAddress ip(192, 168, 0, 110);


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

    WiFi.config(ip);
    while ( status != WL_CONNECTED) { 
        Serial.print("XX Attempting to connect to SSID: ");
        Serial.println(ssid);
        status = WiFi.begin(ssid, pass);
        delay(5000);
    } 
    printWifiStatus();
  
	rtc.begin();                    // initialize Real Time Clock
	rtc.setTime(hours, minutes, seconds);
	rtc.setDate(day, month, year);

	Serial.print("\nStarting connection to server...");
	if ( Udp.begin(localPort) )
		Serial.println(" connected .");
}

void loop() {

	sendNTPpacket(timeServer); // send an NTP packet to a time server
	// wait to see if a reply is available
	delay(1000);
	if ( Udp.parsePacket() ) {
    	Serial.println("packet received");
		// We've received a packet, read the data from it
		Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer

		//the timestamp starts at byte 40 of the received packet and is four bytes,
		// or two words, long. First, esxtract the two words:

		unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
		unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
		// combine the four bytes (two words) into a long integer
		// this is NTP time (seconds since Jan 1 1900):
		unsigned long secsSince1900 = highWord << 16 | lowWord;
		Serial.print("Seconds since Jan 1 1900 = " );
		Serial.println(secsSince1900);

		// now convert NTP time into everyday time:
		Serial.print("Unix time = ");
		// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
		const unsigned long seventyYears = 2208988800UL;
		// subtract seventy years:
		unsigned long epoch = secsSince1900 - seventyYears;
		// print Unix time:
		Serial.println(epoch);

		Serial.println(epoch % 60); // print the second
	} else {
		Serial.println("parsePacket failed!!!");
		Serial.print("remoteIP: ");
		Serial.println( Udp.remoteIP() );
		Serial.print("remotePort: ");
		Serial.println( Udp.remotePort() );
		while ( 1 );
	}
	// wait ten seconds before asking for the time again
	delay(10000);
}


void printWifiStatus() {
    Serial.print("SSID: ");
    Serial.println(WiFi.SSID());
    IPAddress ip = WiFi.localIP();
    Serial.print("IP Address: ");
    Serial.println(ip);
    long rssi = WiFi.RSSI();
    Serial.print("signal strength (RSSI):");
    Serial.print(rssi);
    Serial.println(" dBm");
}


unsigned long sendNTPpacket(IPAddress& address)
{
	Serial.println("1 - begin sendNTPpacket()");
	// set all bytes in the buffer to 0
	memset(packetBuffer, 0, NTP_PACKET_SIZE);
	// Initialize values needed to form NTP request
	// (see URL above for details on the packets)

	Serial.println("2 - assemble packet");
	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
	// 8 bytes of zero for Root Delay & Root Dispersion
	packetBuffer[12]  = 49;
	packetBuffer[13]  = 0x4E;
	packetBuffer[14]  = 49;
	packetBuffer[15]  = 52;

	// all NTP fields have been given values, now
	// you can send a packet requesting a timestamp:
	if ( Udp.beginPacket(address, 123) )
		Serial.println("3 - packet \"begun\" "); //NTP requests are to port 123

	Serial.print("4 - buffer= ");
	for ( int i=0; i < NTP_PACKET_SIZE; i++ )	{
		Serial.print( (int)packetBuffer[ i ], HEX );
		Serial.print(" ");
	}
	Serial.println();
  
	if ( Udp.write(packetBuffer, NTP_PACKET_SIZE) )
		Serial.println("5 - packet written ");

	if ( Udp.endPacket() )
  		Serial.println("6 - packet \"ended\".");
	Serial.println();
}

I’ve added print/println statements to try to find out where the code is failing. All that I’ve determined so far is that the Udp.parsePacket() command is not not getting what it needs(?) But after lots of staring at the code and searching for reports of similar problems, I just can’t figure this out.

Here’s a typical serial output:

XX Attempting to connect to SSID: hotwings
SSID: hotwings
IP Address: 192.168.0.110
signal strength (RSSI):-71 dBm

Starting connection to server... connected .
1 - begin sendNTPpacket()
2 - assemble packet
3 - packet "begun" 
4 - buffer= E3 0 6 EC 0 0 0 0 0 0 0 0 31 4E 31 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
5 - packet written 
6 - packet "ended".

parsePacket failed!!!
remoteIP: 0.0.0.0
remotePort: 0

Can anyone suggest why the remoteIP is coming up 0.0.0.0 and the port is 0? That might get me started on a solution.

BTW, with the Zero and 101 running off my laptop computer (also wifi), the laptop has no problem fetching the time from the same ntp server that’s built into this code.

What am I missing?

… Rich

Did you ask her nicely?

(sorry)

...R

Robin2:
Did you ask her nicely?

(sorry)

...R

Damn, that is what I was going to ask.

PaulS:
Damn, that is what I was going to ask.

Hey. Don't take the OP's girl. :slight_smile:

...R

Fins to the left. Fins to the right. Wireshark time. :slight_smile:

edit: No need for Wireshark. The sharks got the NTP server. It isn't up. Try another NTP server IP.

Boy, did I leave myself open with that one. I guess I should have said something less vulnerable, like: "I can't get ntp to give me the time of day ..."

So anyway, I've tried 3 different ntp servers - the NIST one that came with the example and 2 specific pool.ntp.org servers - and delay times from 1000 to 15,000 milliseconds to wait for the server.

The ntpdate program gets some when it hits on any of these servers, but the Arduino gets no satisfaction. (more of the same joke)

Maybe it is time for Wireshark.

Both the PC and the Arduino WiFi are connected to the same access point?

I've just begun reading up on wireshark. I never used it before, so I scratched my head for a moment when you referred to it, SurferTim. And then I looked it up.

My first thought was to start up airsnort, but I haven't used that for years, so I'd probably have the same learning curve but different results.

Thanks for the tip. I'll continue to play.

If you got this, which your serial output shows, then some device accepted that UDP packet.

	if ( Udp.endPacket() )
  		Serial.println("6 - packet \"ended\".");

I installed wireshark and played with it a bit.

When I make an NTP request using the laptop, I see an obvious sequence of packets for the request and reply.

When I run the Arduino, I see the exchange for it connecting to the wireless access point and then 9 ARP requests ("who has 74.117...?", as wireshark says). There are no NTP exchanges like the ones I see with the laptop.

I tried revising the WiFi.config statement to: WiFi.config( ip, dns, gateway ), with dns and gateway defined appropriately for my LAN, but that didn't make a difference.

But it seems there's a DNS problem. The only difference between the laptop and Arduino systems that comes to mind right now is that the laptop has a hostname but the Arduino does not. I don't think that should matter - only the numeric addresses shoudl matter (?)

" who has 74.117...?" Why is the WiFi device asking that? It should be asking "who has 192.168.0 1?" That is the gateway, isn't it?

An interesting question. Yes, 192.168.0.1 is the gateway, which I defined clearly for it in an earlier IPAddress gateway( 192, 168, 0, 1 ); statement and the new WiFi.config.

The code sends the request to the "timeServer" (sendNTPpacket(timeServer);), which was 74.117.... in this case. I don't see any other address-related instructions. Clearly the request has to go THROUGH the gateway, but wireshark doesn't show other packets (e.g., from the laptop or desktops on the local net) as going TO the gateway. Packets going outside the local net all show only the remote address and the local address.

But I don't understand exactly what it's doing with a "who has?" question.

I'll continue looking for relevant stuff.

That is the device asking which other device has this IP address. I'm not familiar with the new wifi shield as I am with the ethernet shield, but the ethernet shield has no ARP table, so it must ask "who has" with every transaction.

Are you seeing the "who has" response from the gateway to all devices? Obviously your PC can communicate with the NTP server, correct?

It finally occurred to me that one of the servers on my LAN is an NTP server (the computer in my ham radio shack). I'd never used it as a server before - all the other computers use ntpdate in the middle of the night to get their time updates.

When I used the hamshack computer's IPAddress for the time server, the Arduino issued only one ARP request and then got the time from the hamshack.

Meanwhile, I've read up a bit on ARP tables, network layering, etc. So I now understand the first paragraph of your last posting, SurferTim. I'll continue my reading on ARP. I'd really like the Arduino to be able to find and access servers on the other side (Internet) of the gateway.

I don't understand the second paragraph: "Are you seeing ...." Yes, the PC's on the LAN can all communicate with external NTP servers (using ntpdate and ntp).

Many thanks to SurferTim. I've learned a lot already on this project. If you need to drop this thread because it's "solved", I understand. Or if you can hang in there to help me with this gateway issue, I'll appreciate that too.

... Rich

Best to leave it here. Some other user might find this thread useful.

I use my RPi as an NTP server. It is an NTP server by default if you use Raspian OS.

Raspberry PIs are on my agenda.

Tnx again. 73