Problem with dns.getHostByName("pool.ntp.org",timeServer);

Hi everybody,

in my sketch in the Setup section I use the command dns.begin (x,y); and then dns.getHostByName("pool.ntp.org",timeServer);
it works fine for me and I get the expected ntp IP addr.
As the HW should run forever, it would be good to get new ntp server IP from time to time.
To achieve this I tried to put the expression dns.getHostByName("pool.ntp.org",timeServer); into a function or just in loop() as the setup() is processed only once.

But here the problem begins: I encounter this compiler error:
error: request for member 'getHostByName' in 'dns', which is of non-class type ''

Can anybody help me on this? I do not understand the error message.

greetz
purehunter

You clearly did not bother reading the sticky before posting here, or there would be some code for us to look at. So, why should we help you?

I do not understand the error message.

How could it be more explicit? dns is not defined wherever it is you are trying to use it.

Nice tone!

Try again: I stripped down the sketch to the intresting parts. There are 2 points with the dns.getHostByName() call. One is working [in the setup()] and one leads to the compiler error [in ntpSync()]:

error: request for member 'getHostByName' in 'dns', which is of non-class type ''

What can I do to use dns.getHostByName() frequently to fresh up the used server IP? Or for other purposes?

// NTP time
// IDE 1.0.3 Win7/64
// DHCP Server required
// LCD connected for debugging


#include <MsTimer2.h>
#include <Time.h>
#include <LiquidCrystal.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Dns.h>

// LCD 
#define LCD_RS 15
#define LCD_E 16
#define LCD_D4 21
#define LCD_D5 20
#define LCD_D6 19
#define LCD_D7 18

LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);

// Ethernet library configuration
byte mac[] = { 0x24, 0x7B, 0xA2, 0x4A, 0x52, 0x10 };
IPAddress timeServer(0, 0, 0, 0);

/* ALTER THESE VARIABLES AT YOUR OWN RISK */
// local port to listen for UDP packets
unsigned int localPort = 75;
// NTP time stamp is in the first 48 bytes of the message
const int NTP_PACKET_SIZE= 48;      
// Buffer to hold incoming and outgoing packets
byte packetBuffer[NTP_PACKET_SIZE];  
// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;                    

boolean s_flag = false;



void setup() {                

    lcd.begin(20, 4);

// Setup Ethernet by DHCP
    lcd.setCursor(0,0);
    lcd.print("Wait for DHCP Server");
    if (Ethernet.begin(mac) == 0) {  // start Ethernet by DHCP conf.
      lcd.setCursor(0,0);
      lcd.print("DHCP config failed! ");
     }

  DNSClient dns;
  dns.begin(Ethernet.dnsServerIP());
  dns.getHostByName("pool.ntp.org",timeServer); // at this point the function works
  lcd.setCursor(0,1); //col,row
  lcd.print("NTP: ");
  lcd.print(timeServer);
 
  Udp.begin(localPort);
  lcd.setCursor(0,0);
  lcd.print("NTP sync ...        ");
  setSyncProvider(getNtpTime);
  while(timeStatus()== timeNotSet)
     ; // wait until the time is set by the sync provider
  setSyncInterval(86400);    // Set seconds between re-sync 86400 = 24hr
  //setSyncInterval(120);                           

  MsTimer2::set(1000, update1s); // 1s period
  MsTimer2::start();

} 
  
  
void loop() {

  if (s_flag){
    s_flag=false;  
    digitalClockDisplay();
    ntpSync();
  }
}  



void update1s(){
// das Flag zeigt an, ob 1s um ist
s_flag=true;
}

void ntpSync(){

  if (((minute() % 3)==0) && (second()==0)){
//  dns.getHostByName("pool.ntp.org",timeServer); //at this point the function causes a Compiler error 
    setSyncProvider(getNtpTime);
  }   
}



void digitalClockDisplay(){
  // digital clock display of the time
  lcd.setCursor(0,0); //col,row
  lcd.print(day());
  lcd.print(".");
  lcd.print(month());
  lcd.print(".");
  lcd.print(year()-2000);
  lcd.print(" ");
  lcd.print(hour());
  printDigits(minute());
  if(timeStatus()!= timeNeedsSync) // if ntp sync lost, don't show the seconds to indicate this
    printDigits(second());
  else
    lcd.print("   ");
  lcd.print("  ");
 
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding
  // colon and leading 0
  lcd.print(":");
  if(digits < 10)
    lcd.print('0');
  lcd.print(digits);
}

/*-------- NTP code ----------*/

unsigned long getNtpTime()
{
  sendNTPpacket(timeServer); // send an NTP packet to a time server
    delay(500);
    
    if ( Udp.parsePacket() ) { 
     Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read packet into buffer


     //the timestamp starts at byte 40, convert four bytes into a long integer
     unsigned long hi = word(packetBuffer[40], packetBuffer[41]);
     unsigned long low = word(packetBuffer[42], packetBuffer[43]);
     // this is NTP time (seconds since Jan 1 1900
     unsigned long secsSince1900 = hi << 16 | low;  
     // Unix time starts on Jan 1 1970
     const unsigned long seventyYears = 2208988800UL;     
     unsigned long epoch = secsSince1900 - seventyYears + adjustDstEurope();  // subtract 70 years, add Daylight Saving and Timezone adjust
     return epoch;
  }
  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
//unsigned long sendNTPpacket(IPAddress address)
void sendNTPpacket(IPAddress address)
{


  memset(packetBuffer, 0, NTP_PACKET_SIZE);  // set all bytes in the buffer to 0

  // Initialize values needed to form NTP request
  packetBuffer[0] = B11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum
  packetBuffer[2] = 6;     // Max Interval between messages in seconds
  packetBuffer[3] = 0xEC;  // Clock Precision
  // bytes 4 - 11 are for Root Delay and Dispersion and were set to 0 by memset
  packetBuffer[12]  = 49;  // four-byte reference ID identifying
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // send the packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123

  Udp.write(packetBuffer,NTP_PACKET_SIZE);

  Udp.endPacket();

}


int adjustDstEurope()
{
  // last sunday of march
  int beginDSTDate=  (31 - (5* year() /4 + 4) % 7);
  //Serial.println(beginDSTDate);
  int beginDSTMonth=3;
  //last sunday of october
  int endDSTDate= (31 - (5 * year() /4 + 1) % 7);
  //Serial.println(endDSTDate);
  int endDSTMonth=10;
  // DST is valid as:
  if (((month() > beginDSTMonth) && (month() < endDSTMonth))
      || ((month() == beginDSTMonth) && (day() >= beginDSTDate))
      || ((month() == endDSTMonth) && (day() <= endDSTDate)))
  return 7200;  // DST europe = utc +2 hour
  else return 3600; // nonDST europe = utc +1 hour
}

I stripped down the sketch to the intresting parts. There are 2 points with the dns.getHostByName() call. One is working [in the setup()]

  DNSClient dns;
  dns.begin(Ethernet.dnsServerIP());
  dns.getHostByName("pool.ntp.org",timeServer); // at this point the function works

and one leads to the compiler error [in ntpSync()]:

void ntpSync(){
  if (((minute() % 3)==0) && (second()==0)){
//  dns.getHostByName("pool.ntp.org",timeServer); //at this point the function causes a Compiler error

dns is declared local to setup(). It goes out of existence at the end of the setup function. If you want to use dns elsewhere, you have two choices. One is to re-declare it as a local variable (and initialize it again) where you also want to use it. The other is to make dns a global variable.

When you try to use a variable out of scope, the compiler has no idea what type that variable is supposed to be. It knows, because of the . in the name that getHostByName() is a method, and it knows that methods get called on class instances, and it knows that dns is not an instance of a class (because it is not in scope). It has no idea what class it was intended to be an instance of.

@PaulS
thanks for your hint! Now I got it.

But there is another problem where I don't have a clue, what goes wrong, as I just use the code that is used in 99% of examples with minimal modification.
It seems to me, that there is no response from the time server, but I can't believe that.

Before I implemented the dns code for the usage of NTP pools, I used fixed IP's for the time server. Then the effect was, that I found one NTP server where I got the time always immediately. Nearly all other server IP's I used, led to the same situation as I have it now with 99% of the IP's from the pool: the program will stuck in the endless loop in the setup() :

  lcd.print("NTP sync ...        ");
  setSyncProvider(getNtpTime);
  while(timeStatus()== timeNotSet)
     ; // wait until the time is set by the sync provider

The complete code is

// NTP time
// IDE 1.0.3 Win7/64
// DHCP Server required
// LCD connected for debugging


#include <MsTimer2.h>
#include <Time.h>
#include <LiquidCrystal.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Dns.h>

// LCD 
#define LCD_RS 15
#define LCD_E 16
#define LCD_D4 21
#define LCD_D5 20
#define LCD_D6 19
#define LCD_D7 18

LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);

// Ethernet library configuration
byte mac[] = { 0x24, 0x7B, 0xA2, 0x4A, 0x52, 0x10 };
IPAddress timeServer(0, 0, 0, 0);

/* ALTER THESE VARIABLES AT YOUR OWN RISK */
// local port to listen for UDP packets
unsigned int localPort = 75;
// NTP time stamp is in the first 48 bytes of the message
const int NTP_PACKET_SIZE= 48;      
// Buffer to hold incoming and outgoing packets
byte packetBuffer[NTP_PACKET_SIZE];  
// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;                    

boolean s_flag = false;



void setup() {                

    lcd.begin(20, 4);

// Setup Ethernet by DHCP
    lcd.setCursor(0,0);
    lcd.print("Wait for DHCP Server");
    if (Ethernet.begin(mac) == 0) {  // start Ethernet by DHCP conf.
      lcd.setCursor(0,0);
      lcd.print("DHCP config failed! ");
     }

  DNSClient dns;
  dns.begin(Ethernet.dnsServerIP());
  dns.getHostByName("pool.ntp.org",timeServer); // at this point the function works
  lcd.setCursor(0,1); //col,row
  lcd.print("NTP: ");
  lcd.print(timeServer);
 
  Udp.begin(localPort);
  lcd.setCursor(0,0);
  lcd.print("NTP sync ...        ");
  setSyncProvider(getNtpTime);
  while(timeStatus()== timeNotSet)
     ; // wait until the time is set by the sync provider
  setSyncInterval(86400);    // Set seconds between re-sync 86400 = 24hr
  //setSyncInterval(120);                           

  MsTimer2::set(1000, update1s); // 1s period
  MsTimer2::start();

} 
  
  
void loop() {

  if (s_flag){
    s_flag=false;  
    digitalClockDisplay();
    ntpSync();
  }
}  



void update1s(){
// das Flag zeigt an, ob 1s um ist
s_flag=true;
}

void ntpSync(){

  if (((minute() % 3)==0) && (second()==0)){
//  dns.getHostByName("pool.ntp.org",timeServer); //at this point the function causes a Compiler error 
    setSyncProvider(getNtpTime);
  }   
}



void digitalClockDisplay(){
  // digital clock display of the time
  lcd.setCursor(0,0); //col,row
  lcd.print(day());
  lcd.print(".");
  lcd.print(month());
  lcd.print(".");
  lcd.print(year()-2000);
  lcd.print(" ");
  lcd.print(hour());
  printDigits(minute());
  if(timeStatus()!= timeNeedsSync) // if ntp sync lost, don't show the seconds to indicate this
    printDigits(second());
  else
    lcd.print("   ");
  lcd.print("  ");
 
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding
  // colon and leading 0
  lcd.print(":");
  if(digits < 10)
    lcd.print('0');
  lcd.print(digits);
}

/*-------- NTP code ----------*/

unsigned long getNtpTime()
{
  sendNTPpacket(timeServer); // send an NTP packet to a time server
    delay(500);
    
    if ( Udp.parsePacket() ) { 
     Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read packet into buffer


     //the timestamp starts at byte 40, convert four bytes into a long integer
     unsigned long hi = word(packetBuffer[40], packetBuffer[41]);
     unsigned long low = word(packetBuffer[42], packetBuffer[43]);
     // this is NTP time (seconds since Jan 1 1900
     unsigned long secsSince1900 = hi << 16 | low;  
     // Unix time starts on Jan 1 1970
     const unsigned long seventyYears = 2208988800UL;     
     unsigned long epoch = secsSince1900 - seventyYears + adjustDstEurope();  // subtract 70 years, add Daylight Saving and Timezone adjust
     return epoch;
  }
  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
//unsigned long sendNTPpacket(IPAddress address)
void sendNTPpacket(IPAddress address)
{


  memset(packetBuffer, 0, NTP_PACKET_SIZE);  // set all bytes in the buffer to 0

  // Initialize values needed to form NTP request
  packetBuffer[0] = B11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum
  packetBuffer[2] = 6;     // Max Interval between messages in seconds
  packetBuffer[3] = 0xEC;  // Clock Precision
  // bytes 4 - 11 are for Root Delay and Dispersion and were set to 0 by memset
  packetBuffer[12]  = 49;  // four-byte reference ID identifying
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // send the packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123

  Udp.write(packetBuffer,NTP_PACKET_SIZE);

  Udp.endPacket();

}


int adjustDstEurope()
{
  // last sunday of march
  int beginDSTDate=  (31 - (5* year() /4 + 4) % 7);
  //Serial.println(beginDSTDate);
  int beginDSTMonth=3;
  //last sunday of october
  int endDSTDate= (31 - (5 * year() /4 + 1) % 7);
  //Serial.println(endDSTDate);
  int endDSTMonth=10;
  // DST is valid as:
  if (((month() > beginDSTMonth) && (month() < endDSTMonth))
      || ((month() == beginDSTMonth) && (day() >= beginDSTDate))
      || ((month() == endDSTMonth) && (day() <= endDSTDate)))
  return 7200;  // DST europe = utc +2 hour
  else return 3600; // nonDST europe = utc +1 hour
}
  setSyncProvider(getNtpTime);

This defines the function to call, when the time needs to be synced.

void ntpSync()
{
  if (((minute() % 3)==0) && (second()==0))
  {
    setSyncProvider(getNtpTime);
  }   
}

How is calling that function again here useful?

I use that code quite sucessfully. Here is what I started with:
http://arduino.cc/forum/index.php/topic,137789.0.html
You should see it now.

Move the declaration for DNSClient dns; into global memory. It is local to setup() in your code.

edit: Or use another declaration in your other function.

@SurferTim

Move the declaration for DNSClient dns;
...
edit: Or use another declaration in your other function.

I declared it already in the function according Pauls hint. That worked.

The mentioned thread I already knew. It uses the same -functional- code than I. The only modifications I did is the function declaration (unsigned long -> void)
as I got compiler warnings at that point.

// send an NTP request to the time server at the given address
//unsigned long sendNTPpacket(IPAddress address)
void sendNTPpacket(IPAddress address)
{

and I tried out several delays

unsigned long getNtpTime()
{
  sendNTPpacket(timeServer); // send an NTP packet to a time server
    delay(500);
    
    if ( Udp.parsePacket() ) {

What I mostly wondering about is the fact that with some servers it works fine, also the re-syncing

@PaulS

How is calling that function again here useful?

Why not re-syncing?
Do you have a better idea?
I don't have a RTC so I thought it would be good to re-sync time after time

Why not re-syncing?

That function does not cause re-syncing. It simply defines the function to call when a resync is needed. You only need to define that once.

I don't have a RTC so I thought it would be good to re-sync time after time

It would be. But, you need to make changes in getNtpTime() to make that happen, not have ntpSync() re-assert that getNtpTime() is the correct function to call.

That is not what compiles on my IDE. This does. Note the ampersand(&) in the parameter.

unsigned long sendNTPpacket(IPAddress& address)
{

You should be able to change it to void return, but you must include the &.

edit: I changed mine to void return, and it compiled.

@SurferTim
curious, I definitely did not remove the "&" from the example I copied, as I don't understand its meaning. Can you tell me, what it means at this place? I know it in regard to pointers, but oly in front of the name.
First I thought, it works with that Ampersand added in, but further tries showed the same as before: sometime it works, mostly not.

From my view "void" should be ok for that function, as it doesn't return anything.

@PaulS
In the instruction for the time.h, I found this:
Functions for managing the timer services are:
...
setSyncProvider(getTimeFunction);// Set the external time

  • // provider*
    setSyncInterval(interval); // Set the number of
  • // seconds between re-sync*

So after reading your question, may it be correct to use the "setSyncProvider()" only once in combination with "setSyncInterval()" and thats it?

I don't know anything about those functions. I use this. Well, mine is now a bit more complex, but the basic idea is the same. It checks every 10 minutes.

Thanks SurferTim!
Your example works also in my environment. I will use it as the base for my implementation.

kind regards from cold Berlin
purehunter