I wanted to get the Internet time with my ESP8266 WiFi shield and I used Arduino's UdpNtpClient example as a reference, but it hasn't been working.
The code I'm using is as follows:
#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiServer.h>
#include <WiFiUdp.h>
#include <ThingSpeak.h>
// The SparkFunESP8266WiFi library uses SoftwareSerial
// to communicate with the ESP8266 module. Include that
// library first:
#include <SoftwareSerial.h>
// Include the ESP8266 AT library:
#include <SparkFunESP8266WiFi.h>
//////////////////////////////
// WiFi Network Definitions //
//////////////////////////////
// Replace these two character strings with the name and
// password of your WiFi network.
const char mySSID[] = "IFH Loft";
const char myPSK[] = "ifhJanuary";
ESP8266Client client;
//////////////////////////
// Thingspeak Constants //
//////////////////////////
// Phant detsination server:
unsigned long myChannelNumber = 64341;
const char * myWriteAPIKey = "4JRIMA3GJF3PIQKE";
///////////////////
//Time Retrieval //
///////////////////
unsigned int localPort = 8888;
char timeServer[] = "time.nist.gov";
const int NTP_PACKET_SIZE = 48;
byte packetBuffer[ NTP_PACKET_SIZE];
WiFiUDP Udp;
long y = 0;
unsigned long sketchTime = 0L;
unsigned long lastPolledTime = 0L;
////////////////////////
//Variable Definitions//
////////////////////////
int Calc;
void setup()
{
int status;
Serial.begin(9600);
// To turn the MG2639 shield on, and verify communication
// always begin a sketch by calling cell.begin().
status = esp8266.begin();
if (status <= 0)
{
Serial.println(F("Unable to communicate with shield. Looping"));
while(1) ;
}
esp8266.setMode(ESP8266_MODE_STA); // Set WiFi mode to station
if (esp8266.status() <= 0) // If we're not already connected
{
if (esp8266.connect(mySSID, myPSK) < 0)
{
Serial.println(F("Error connecting"));
while (1) ;
}
}
// Get our assigned IP address and print it:
Serial.print(F("My IP address is: "));
Serial.println(esp8266.localIP());
ThingSpeak.begin(client);
}
void loop()
{
sendNTPpacket(timeServer);
Serial.println("test 3");
delay(1000);
if (Udp.parsePacket()){
Serial.println("test 4");
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;
Serial.print("Seconds since Jan 1 1900 = ");
Serial.println(secsSince1900);
Serial.print("Unix time = ");
const unsigned long seventyYears = 2208988800UL;
unsigned long epoch = secsSince1900 - seventyYears;
Serial.println(epoch);
}
Calc = 2;
ThingSpeak.writeField(myChannelNumber, 1, Calc, myWriteAPIKey);
}
void sendNTPpacket(char *address) {
// 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)
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:
Serial.println("test");
Udp.beginPacket(*address, 123); //NTP requests are to port 123
Serial.println("test2");
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
I put a few test print lines, and I found that the "if (Udp.parsePacket()){" is being overlooked, which I guess means it isn't receiving any packets? Is there a reason that's the case? I'm not sure what that really means..
Thanks for the help!
So I switched examples and I used this NTP client example to find the time. This time, when I print unixTime, the result is always zero. Anyone have a reason for this?
Here's my updated code:
#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiServer.h>
#include <WiFiUdp.h>
#include <ThingSpeak.h>
// The SparkFunESP8266WiFi library uses SoftwareSerial
// to communicate with the ESP8266 module. Include that
// library first:
#include <SoftwareSerial.h>
// Include the ESP8266 AT library:
#include <SparkFunESP8266WiFi.h>
//////////////////////////////
// WiFi Network Definitions //
//////////////////////////////
// Replace these two character strings with the name and
// password of your WiFi network.
const char mySSID[] = "IFH Lounge";
const char myPSK[] = "ifhJanuary";
ESP8266Client client;
//////////////////////////
// Thingspeak Constants //
//////////////////////////
// Phant detsination server:
unsigned long myChannelNumber = 64341;
const char * myWriteAPIKey = "4JRIMA3GJF3PIQKE";
///////////////////
//Time Retrieval //
///////////////////
//unsigned int localPort = 8888;
//char timeServer[] = "time.nist.gov";
const int NTP_PACKET_SIZE = 48;
byte packetBuffer[ NTP_PACKET_SIZE];
static WiFiUDP Udp;
long y = 0;
unsigned long sketchTime = 0L;
unsigned long lastPolledTime = 0L;
////////////////////////
//Variable Definitions//
////////////////////////
int Calc;
void setup()
{
int status;
Serial.begin(9600);
// To turn the MG2639 shield on, and verify communication
// always begin a sketch by calling cell.begin().
status = esp8266.begin();
if (status <= 0)
{
Serial.println(F("Unable to communicate with shield. Looping"));
while(1) ;
}
esp8266.setMode(ESP8266_MODE_STA); // Set WiFi mode to station
if (esp8266.status() <= 0) // If we're not already connected
{
if (esp8266.connect(mySSID, myPSK) < 0)
{
Serial.println(F("Error connecting"));
while (1) ;
}
}
// Get our assigned IP address and print it:
Serial.print(F("My IP address is: "));
Serial.println(esp8266.localIP());
ThingSpeak.begin(client);
}
void loop()
{
unsigned long unixTime = ntpUnixTime(Udp);
Serial.println(unixTime);
Calc = 7;
ThingSpeak.writeField(myChannelNumber, 1, Calc, myWriteAPIKey);
}
unsigned long inline ntpUnixTime (UDP &udp)
{
static int udpInited = udp.begin(123); // open socket on arbitrary port
const char timeServer[] = "pool.ntp.org"; // NTP server
// Only the first four bytes of an outgoing NTP packet need to be set
// appropriately, the rest can be whatever.
const long ntpFirstFourBytes = 0xEC0600E3; // NTP request header
// Fail if WiFiUdp.begin() could not init a socket
if (! udpInited)
return 0;
// Clear received data from possible stray received packets
udp.flush();
// Send an NTP request
if (! (udp.beginPacket(timeServer, 123) // 123 is the NTP port
&& udp.write((byte *)&ntpFirstFourBytes, 48) == 48
&& udp.endPacket()))
return 0; // sending request failed
// Wait for response; check every pollIntv ms up to maxPoll times
const int pollIntv = 150; // poll every this many ms
const byte maxPoll = 15; // poll up to this many times
int pktLen; // received packet length
for (byte i=0; i<maxPoll; i++) {
if ((pktLen = udp.parsePacket()) == 48)
break;
delay(pollIntv);
}
if (pktLen != 48)
return 0; // no correct packet received
// Read and discard the first useless bytes
// Set useless to 32 for speed; set to 40 for accuracy.
const byte useless = 40;
for (byte i = 0; i < useless; ++i)
udp.read();
// Read the integer part of sending time
unsigned long time = udp.read(); // NTP time
for (byte i = 1; i < 4; i++)
time = time << 8 | udp.read();
// Round to the nearest second if we want accuracy
// The fractionary part is the next byte divided by 256: if it is
// greater than 500ms we round to the next second; we also account
// for an assumed network delay of 50ms, and (0.5-0.05)*256=115;
// additionally, we account for how much we delayed reading the packet
// since its arrival, which we assume on average to be pollIntv/2.
time += (udp.read() > 115 - pollIntv/8);
// Discard the rest of the packet
udp.flush();
return time - 2208988800ul; // convert NTP time to Unix time
}
Read the code. There could be a dozen reasons. Put some Serial.print() statements in the function and figure out which one is the real reason. Then, we can think about addressing that one.
Thanks for the advice PaulS. Within the unixtime function, there are a few situations that return a "0" value. I iteratively changed the return value of each to see which was affected. So, WiFi.egin() was able to initiate a socket, but the sending request failed. That is, the reason behind the return of zero was:
if (! (udp.beginPacket(timeServer, 123) // 123 is the NTP port
&& udp.write((byte *)&ntpFirstFourBytes, 48) == 48
&& udp.endPacket()))
return 0;
Could this be the same issue I was running into with the previous code?