[SOLVED] "Send tweet with timestamp" sketch hangs, shows no activity

Hello. I'm a new Arduino user and this is my first post on this forum. This post is going to be a bit more concise than it was originally going to be because I am rewriting it from scratch after losing all of my work. Apparently, Command + 2 finger swipe on Firefox on my MacBook is equivalent to pressing the back button, which is equivalent to taking nearly an hour's worth of your life and throwing it into the %#!$ing garbage... Anyway...

I'm using an Arduino UNO R2 with a Wiznet W5100-compliant ethernet shield and IDE 1.0.1.

I'm building an application (picture below) for my hackerspace that announces that we're open or closed via a tweet with a time stamp. Originally I script-kittied together two sketches that could do half of the job independently: when pressing a pushbutton, one script sends a tweet that we're opened or closed and lights up a green LED if we're open and a red LED if we're closed. The other sketch accesses the internet to get the current time, converts it to 12 hour time in my time zone and displays it in the serial monitor. Separately, both scripts work like champs. The problem comes when I try to consolidate the two together.

I verify the script (posted below) and it passes. I upload it successfully to the Arduino ( < 18kb). But then nothing happens. No error codes, nothing displayed in the serial monitor (not even the "start" print statement from the beginning of the loop() function), no tweet is sent when I press the button, no LED lights up.

What do you think? Thank you for any input you can give me.

Jeremy
Xerocraft Hackerspace
Tucson, AZ
xerocraft.org

The Sketch:

#include <SPI.h> // needed in Arduino 0019 or later
#include <Ethernet.h>
#include <Twitter.h>
#include <EthernetUdp.h>

// The includion of EthernetDNS is not needed in Arduino IDE 1.0 or later.
// Please uncomment below in Arduino IDE 0022 or earlier.
//#include <EthernetDNS.h>

#define LED_red 5    // the pin for the red LED
#define LED_grn 6    // the pin for the green LED
#define BUTTON 7     // input pin of the pushbutton

int btn_val = 0;     // stores the state of the input pin
int btn_oldval = 0;  // stores the previous value of "btn_val" 

int shop_status = 0;  // 0 = We're currently CLOSED
                      // 1 = We're currently OPEN

// Ethernet Shield Settings
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// If you don't specify the IP address, DHCP is used(only in Arduino 1.0 or later).
// byte ip[] = { 192, 168, 2, 250 };

unsigned int localPort = 8888;      // local port to listen for UDP packets

IPAddress timeServer(192, 43, 244, 18); // 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
EthernetUDP Udp;

// Your Token to Tweet (get it from http://arduino-tweet.appspot.com/)
Twitter twitter("not-for-you-silly");

// Messages to post
  char msgOpen[] = "We're open!";
  char msgClosed[] = "We're closed!";

String strTime;

void setup()
{
  pinMode(LED_red, OUTPUT);    // tell Arduino LED_red is an output
  pinMode(LED_grn, OUTPUT);    // tell Arduino LED_grn is an output
  pinMode(BUTTON, INPUT);      // tell Arduino BUTTON is an input
}

void loop()
{
  Serial.println("start");
  btn_val = digitalRead(BUTTON);    // read input value and store it fresh
  
  // check if there was a transition
  if ((btn_val == HIGH) && (btn_oldval == LOW)) {
    if (shop_status == 0) {        // then that means we're now OPEN
       getTime();
       sendTweet(msgOpen, strTime);
       digitalWrite(LED_grn, HIGH);    // Turn green LED on
       digitalWrite(LED_red, LOW);     // Turn red LED off 

    } else {      // or else shop_status == 1, which means that we're now CLOSED
       getTime();
       sendTweet(msgClosed, strTime);
       digitalWrite(LED_grn, LOW);    // Turn green LED off
       digitalWrite(LED_red, HIGH);     // Turn red LED on 
    }
    
    shop_status = 1 - shop_status;
    delay(60000);                                  
  }   
  
  btn_oldval = btn_val;    // btn_val is now old so store it

}

void sendTweet(char* msg, String stringTime) {                        // change to boolean
  Ethernet.begin(mac);    // using DHCP for autoomatic IP address configuration.
  Serial.begin(9600);
  
  // start Ethernet and UDP
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
  Udp.begin(localPort);
  
  char msgChar[30];
  String strMsg = String(msg);
  strMsg += String(stringTime);
  strMsg.toCharArray(msgChar,30);
  
  Serial.println("connecting ...");
  Serial.println(msgChar);
  if (twitter.post(msgChar)) {
    // Specify &Serial to output received response to Serial.
    // If no output is required, you can just omit the argument, e.g.
    // int status = twitter.wait();
    int status = twitter.wait(&Serial);
    if (status == 200) {
      Serial.println("OK.");
    } else {
      Serial.print("failed : code ");
      Serial.println(status);
    }
  } else {
    Serial.println("connection failed.");
  }
}

String getTime() {
  int hour = 0;
  int timezone = -7;   // AZ timezone is UTC-7.
 
  sendNTPpacket(timeServer); // send an NTP packet to a time server

    // wait to see if a reply is available
  delay(1000);  
  if ( Udp.parsePacket() ) {  
    // 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;             

    const unsigned long seventyYears = 2208988800UL;     
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;                               

    int hour24 = ((epoch % 86400L) / 3600) + timezone; // print the hour (86400 equals secs per day). 
    if (hour24 < 0)
      hour24 += 24;

    if (hour24 == 0)
        hour = 12;
    else if (hour24 <= 12) 
        hour = hour24;
    else  
        hour = hour24 - 12;

    int minute = (epoch % 3600) / 60;
      
    if (minute < 10) {
      if (hour24 < 12) {
            strTime = String(hour);
            String strMin = String(minute);
            strTime += (":0" + strMin + "am");
            return strTime;
//            Serial.println(strTime);
/*            
            Serial.print(hour);
            Serial.print(":0");
            Serial.print(minute);
            Serial.print("am");
*/      
      } else {
            strTime = String(hour);
            String strMin = String(minute);
            strTime += (":0" + strMin + "pm");
            return strTime;
//          Serial.println(strTime);
/*
            Serial.print(hour);
            Serial.print(":0");
            Serial.print(minute);
            Serial.print("pm");
*/            
      }
    } else {
      if (hour24 < 12) {
            strTime = String(hour);
            String strMin = String(minute);
            strTime += (":" + strMin + "am");
            return strTime;
//            Serial.println(strTime);          
/*
            Serial.print(hour);
            Serial.print(':');
            Serial.print(minute);
            Serial.print("am");
*/
      } else {
            strTime = String(hour);
            String strMin = String(minute);
            strTime += (":" + strMin + "pm");
            return strTime;
//            Serial.println(strTime);
/*
            Serial.print(hour);
            Serial.print(':');
            Serial.print(minute);
            Serial.print("pm");
 */
      }
    }
  }
}

// send an NTP request to the time server at the given address 
unsigned long sendNTPpacket(IPAddress& 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: 		   
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket(); 
}

The Setup:

Suggest you call Serial.begin(9600) once in setup, instead of repeatedly some time later. Hopefully you will then see your startup messages and know your sketch is running so you can move on with debugging it.

Why does getTime() return a String, when the String being returned is a global variable, and the return value is never used?

You should ditch the String class, and learn to use char arrays.

This post is going to be a bit more concise than it was originally going to be because I am rewriting it from scratch after losing all of my work. Apparently, Command + 2 finger swipe on Firefox on my MacBook is equivalent to pressing the back button, which is equivalent to taking nearly an hour's worth of your life and throwing it into the %#!$ing garbage...

That happened to me yesterday. Words failed me. I rewrote the post in TextEdit which doesn't throw everything away if you hit the back arrow the wrong way.

As PaulS says ...

Please note that, at present, the String library has bugs as discussed here and here.

In particular, the dynamic memory allocation used by the String class may fail and cause random crashes.

I recommend reworking your code to manage without String. Use C-style strings instead (strcpy, strcat, strcmp, etc.).

Thank you for the information about moving away from the String class. I will do that.

I did what PeterH suggested and got a little farther in the execution. Now it looks like I'm getting stuck at the "Udp.beginPacket(address, 123);" statement in sendNTPpacket().

Here's what the serial monitor says:

start
btn_val: 0
start
btn_val: 1 <<here's where i pressed the button and changed the value
shop_status: 0
getTime() begins!
hour: 0
timezone: -7
About to access timeServer: 192.43.244.18
sendNTPpacket() begins!
memset set!
adding to packetBuffer!
packetBuffer set!

Amended code:

void setup()
{
  pinMode(LED_red, OUTPUT);    // tell Arduino LED_red is an output
  pinMode(LED_grn, OUTPUT);    // tell Arduino LED_grn is an output
  pinMode(BUTTON, INPUT);      // tell Arduino BUTTON is an input
  
  Serial.begin(9600);
}


void loop()
{
  Serial.println("start");
  delay(1000);
  btn_val = digitalRead(BUTTON);    // read input value and store it fresh
  Serial.print("btn_val: ");
  Serial.println(btn_val);
  
  // check if there was a transition
  if ((btn_val == HIGH) && (btn_oldval == LOW)) {
    if (shop_status == 0) {        // then that means we're now OPEN
       Serial.print("shop_status: ");
       Serial.println(shop_status);
       getTime();
       Serial.print("getTime(): ");
       Serial.println(getTime());
       sendTweet(msgOpen, strTime);
       Serial.print("msgOpen: ");
       Serial.println(msgOpen);
       Serial.print("strTime: ");
       Serial.println(strTime);
       digitalWrite(LED_grn, HIGH);    // Turn green LED on
       digitalWrite(LED_red, LOW);     // Turn red LED off 

    } else {      // or else shop_status == 1, which means that we're now CLOSED
       getTime();
       sendTweet(msgClosed, strTime);
       digitalWrite(LED_grn, LOW);    // Turn green LED off
       digitalWrite(LED_red, HIGH);     // Turn red LED on 
    }
    
    shop_status = 1 - shop_status;
    delay(60000);                                      // Change to 60000
  }
  
  
  btn_oldval = btn_val;    // btn_val is now old so store it

}


String getTime() {
  Serial.println("getTime() begins!");
  int hour = 0;
  int timezone = -7;   // AZ timezone is UTC-7.
  
              Serial.print("hour: ");
            Serial.println(hour);
            
                        Serial.print("timezone: ");
            Serial.println(timezone);
 
 Serial.print("About to access timeServer: ");
 Serial.println(timeServer);
 
// Udp.begin(localPort);
 
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  
  Serial.println("Hello?");
  
  Serial.print("timeserver accessed: ");
  Serial.println(timeServer);

    // wait to see if a reply is available
  delay(1000);  
  if ( Udp.parsePacket() ) {  
    // 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;             

    const unsigned long seventyYears = 2208988800UL;     
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;                               

    int hour24 = ((epoch % 86400L) / 3600) + timezone; // print the hour (86400 equals secs per day). 
    
            Serial.print("hour24: ");
            Serial.println(hour24);
    
    if (hour24 < 0)
      hour24 += 24;

    if (hour24 == 0)
        hour = 12;
    else if (hour24 <= 12) 
        hour = hour24;
    else  
        hour = hour24 - 12;

            Serial.print("hour: ");
            Serial.println(hour);

    int minute = (epoch % 3600) / 60;
    
            Serial.print("minute: ");
            Serial.println(minute);
      
    if (minute < 10) {
      if (hour24 < 12) {
            strTime = String(hour);
            String strMin = String(minute);
            strTime += (":0" + strMin + "am");
            return strTime;
//            Serial.println(strTime);
/*            
            Serial.print(hour);
            Serial.print(":0");
            Serial.print(minute);
            Serial.print("am");
*/      
      } else {                            // else hour24 > 12
            strTime = String(hour);
            String strMin = String(minute);
            strTime += (":0" + strMin + "pm");
            return strTime;
//          Serial.println(strTime);
/*
            Serial.print(hour);
            Serial.print(":0");
            Serial.print(minute);
            Serial.print("pm");
*/            
      }
    } else {                              // else minute > 10
      if (hour24 < 12) {
            strTime = String(hour);
            String strMin = String(minute);
            strTime += (":" + strMin + "am");
            return strTime;
//            Serial.println(strTime);          
/*
            Serial.print(hour);
            Serial.print(':');
            Serial.print(minute);
            Serial.print("am");
*/
      } else {                            // else hour24 > 12
            strTime = String(hour);
            String strMin = String(minute);
            strTime += (":" + strMin + "pm");
            return strTime;
            Serial.print("strTime: ");
            Serial.println(strTime);
/*
            Serial.print(hour);
            Serial.print(':');
            Serial.print(minute);
            Serial.print("pm");
 */
      }
    }
  }
}


// send an NTP request to the time server at the given address 
unsigned long sendNTPpacket(IPAddress& address) 
{
  Serial.println("sendNTPpacket() begins!");
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE); 
  
  Serial.println("memset set!");
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  
    Serial.println("adding to packetBuffer!");
  
  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;

    Serial.println("packetBuffer set!");
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp: 		   
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  
    Serial.println("beginPacket set!");
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  
    Serial.println("write set!");
  Serial.print("NTP_PACKET_SIZE: ");
  Serial.println(NTP_PACKET_SIZE);
   
  
  Udp.endPacket(); 
}

Ok, I messed around with the code some more and I'm able to send the "We're open!" tweet with a time stamp. But for some reason when I try to send the "We're closed!" tweet, it gets hung up in the sendNTPpacket() method at the Udp.endPacket(); statement. What do you think?

My new code:

#include <SPI.h> // needed in Arduino 0019 or later
#include <Ethernet.h>
#include <Twitter.h>
#include <EthernetUdp.h>

// The includion of EthernetDNS is not needed in Arduino IDE 1.0 or later.
// Please uncomment below in Arduino IDE 0022 or earlier.
//#include <EthernetDNS.h>

#define LED_red 5    // the pin for the red LED
#define LED_grn 6    // the pin for the green LED
#define BUTTON 7     // input pin of the pushbutton

int btn_val = 0;     // stores the state of the input pin
// int btn_oldval = 0;  // stores the previous value of "btn_val" 

int shop_status = 0;  // 0 = We're currently CLOSED
                      // 1 = We're currently OPEN
                      
// int shop_oldstatus = 0;  // stores the previous value of "shop_status"                      

                     // 0 = green LED off and red LED on. "We're CLOSED"
                     // 1 = green LED on and red LED off "We're OPEN"

// Ethernet Shield Settings
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// If you don't specify the IP address, DHCP is used(only in Arduino 1.0 or later).
// byte ip[] = { 192, 168, 2, 250 };

unsigned int localPort = 8888;      // local port to listen for UDP packets

IPAddress timeServer(192, 43, 244, 18); // 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
EthernetUDP Udp;

// Your Token to Tweet (get it from http://arduino-tweet.appspot.com/)
Twitter twitter("839253360-JuNm5OmdkZXyKRLIRMlOovOy94q1mlXut5Ya5p0o");

// Messages to post
  char msgOpen[] = "We're open!";
  char msgClosed[] = "We're closed!";

String strTime;




void setup()
{
  pinMode(LED_red, OUTPUT);    // tell Arduino LED_red is an output
  pinMode(LED_grn, OUTPUT);    // tell Arduino LED_grn is an output
  pinMode(BUTTON, INPUT);      // tell Arduino BUTTON is an input
  
  Serial.begin(9600);
  
//    Ethernet.begin(mac);
  //  Udp.begin(localPort);
}





void loop()
{
  Serial.println("Ready!");
  delay(1000);
  btn_val = digitalRead(BUTTON);    // read input value and store it fresh
  
  // check if there was a transition
  if ((btn_val == HIGH)) {
        Ethernet.begin(mac);
    Udp.begin(localPort);
    if (shop_status == 0) {        // then that means we're now OPEN
       Serial.print("shop_status: ");
       Serial.println(shop_status);
       Serial.println("");
       getTime();
       sendTweet(msgOpen, strTime);
       digitalWrite(LED_grn, HIGH);    // Turn green LED on
       digitalWrite(LED_red, LOW);     // Turn red LED off 

    } else {      // or else shop_status == 1, which means that we're now CLOSED
           Serial.print("shop_status: ");
       Serial.println(shop_status);
       Serial.println("");
       getTime();

       sendTweet(msgClosed, strTime);
       digitalWrite(LED_grn, LOW);    // Turn green LED off
       digitalWrite(LED_red, HIGH);     // Turn red LED on 
    }
    
    shop_status = 1 - shop_status;
    delay(60000);                                      // Change to 60000
  }
}




String getTime() {
  int hour = 0;
  int timezone = -7;   // AZ timezone is UTC-7.
  
  sendNTPpacket(timeServer); // send an NTP packet to a time server

    // wait to see if a reply is available
  delay(1000);  
  if ( Udp.parsePacket() ) {  
    // 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;             

    const unsigned long seventyYears = 2208988800UL;     
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;                               

    int hour24 = ((epoch % 86400L) / 3600) + timezone; // print the hour (86400 equals secs per day). 
    
            Serial.print("hour24: ");
            Serial.println(hour24);
    
    if (hour24 < 0)
      hour24 += 24;

    if (hour24 == 0)
        hour = 12;
    else if (hour24 <= 12) 
        hour = hour24;
    else  
        hour = hour24 - 12;

            Serial.print("hour: ");
            Serial.println(hour);

    int minute = (epoch % 3600) / 60;
    
            Serial.print("minute: ");
            Serial.println(minute);
      
    if (minute < 10) {
      if (hour24 < 12) {
            strTime = String(hour);
            String strMin = String(minute);
            strTime += (":0" + strMin + "am");
            return strTime;
//            Serial.println(strTime);
/*            
            Serial.print(hour);
            Serial.print(":0");
            Serial.print(minute);
            Serial.print("am");
*/      
      } else {                            // else hour24 > 12
            strTime = String(hour);
            String strMin = String(minute);
            strTime += (":0" + strMin + "pm");
            return strTime;
//          Serial.println(strTime);
/*
            Serial.print(hour);
            Serial.print(":0");
            Serial.print(minute);
            Serial.print("pm");
*/            
      }
    } else {                              // else minute > 10
      if (hour24 < 12) {
            strTime = String(hour);
            String strMin = String(minute);
            strTime += (":" + strMin + "am");
            return strTime;
//            Serial.println(strTime);          
/*
            Serial.print(hour);
            Serial.print(':');
            Serial.print(minute);
            Serial.print("am");
*/
      } else {                            // else hour24 > 12
            strTime = String(hour);
            String strMin = String(minute);
            strTime += (":" + strMin + "pm");
            return strTime;
            Serial.print("strTime: ");
            Serial.println(strTime);
/*
            Serial.print(hour);
            Serial.print(':');
            Serial.print(minute);
            Serial.print("pm");
 */
      }
    }
  }
}




void sendTweet(char* msg, String stringTime) {                        // change to boolean
//  Ethernet.begin(mac);    // using DHCP for autoomatic IP address configuration.

  
  // start Ethernet and UDP
  if (Ethernet.begin(mac) == 0) {                              //move this
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)                                                      // BAD!
      ;
  }
//  Udp.begin(localPort);
  
  char msgChar[30];
  String strMsg = String(msg);
  strMsg += String(stringTime);
  strMsg.toCharArray(msgChar,30);
  
  Serial.println("connecting ...");
  Serial.println(msgChar);
  if (twitter.post(msgChar)) {
    // Specify &Serial to output received response to Serial.
    // If no output is required, you can just omit the argument, e.g.
    // int status = twitter.wait();
    int status = twitter.wait(&Serial);
    if (status == 200) {
      Serial.println("OK.");
    } else {
      Serial.print("failed : code ");
      Serial.println(status);
    }
  } else {
    Serial.println("connection failed.");
  }
}




// send an NTP request to the time server at the given address 
unsigned long sendNTPpacket(IPAddress& 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: 		   
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  
  Udp.endPacket();                                   // Sketch hangs up here.
}
  btn_val = digitalRead(BUTTON);    // read input value and store it fresh
  
  // check if there was a transition
  if ((btn_val == HIGH)) {

Wrong. The if statement is NOT checking for a transition. It is simply checking for a state. That could be the same state as last time.

        Ethernet.begin(mac);
    Udp.begin(localPort);

This should be done in setup(), not in loop().

    if (shop_status == 0) {        // then that means we're now OPEN
       Serial.print("shop_status: ");
       Serial.println(shop_status);
       Serial.println("");
       getTime();
    } else {      // or else shop_status == 1, which means that we're now CLOSED
           Serial.print("shop_status: ");
       Serial.println(shop_status);
       Serial.println("");
       getTime();

Why? You do the same stuff in both cases. This code doesn't belong in the if/else blocks.

I see you still haven't ditched the String class...

Thank you for the info. Can we please focus on the question I asked in reply #5?

for some reason when I try to send the "We're closed!" tweet, it gets hung up in the sendNTPpacket() method at the Udp.endPacket(); statement.

Part of the original problem that caused me to write this post still exists. The sketch hangs and I don't understand why. I'm very new to Arduino and was never a particularly good coder. For right now I want to focus on the broken code. I'll get to the inelegant code later.

Doing this thousands of times:

    Udp.begin(localPort);

might cause memory to be consumed and the code to crash. Please fix the things are you asked to fix, whether or not you think they are relevant.

GoodAsh03:
Can we please focus on the question I asked in reply #5?

You don't know what's causing the problem. Any of the faults in your sketch might be causing or contributing to it. I suggest you fix any faults that can be found. Perhaps along the way you will cure your main problem. If not, at least you will have ruled out all these obvious potential causes. IMO it's pointless trying to look for further faults until the known faults are fixed.

I cleaned up the code and got rid of the String class but I still get the same problem: when I press the button again to send a second tweet, the code starts to run but gets hung up in the sendNTPpacket() method at the Udp.endPacket(); statement.

new code:

#include <SPI.h> // needed in Arduino 0019 or later
#include <Ethernet.h>
#include <Twitter.h>
#include <EthernetUdp.h>
#include <stdlib.h>

// The includion of EthernetDNS is not needed in Arduino IDE 1.0 or later.
// Please uncomment below in Arduino IDE 0022 or earlier.
//#include <EthernetDNS.h>

#define LED_red 5    // the pin for the red LED
#define LED_grn 6    // the pin for the green LED
#define BUTTON 7     // input pin of the pushbutton

int btn_val = 0;     // stores the state of the input pin 

int shop_status = 0;  // 0 = We're currently CLOSED
                      // 1 = We're currently OPEN

// Ethernet Shield Settings
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// If you don't specify the IP address, DHCP is used(only in Arduino 1.0 or later).
// byte ip[] = { 192, 168, 2, 250 };

unsigned int localPort = 8888;      // local port to listen for UDP packets

IPAddress timeServer(192, 43, 244, 18); // 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
EthernetUDP Udp;

// Your Token to Tweet (get it from http://arduino-tweet.appspot.com/)
Twitter twitter("you-shall-not-pass");

// Messages to post
  char msgOpen[] = "We're open";       // 11 chars
  char msgClosed[] = "We're closed";   // 13 chars
  char tweet[141];                      // The tweet to send
  char timestamp[8];

// ************************************************************

void setup()
{
  pinMode(LED_red, OUTPUT);    // tell Arduino LED_red is an output
  pinMode(LED_grn, OUTPUT);    // tell Arduino LED_grn is an output
  pinMode(BUTTON, INPUT);      // tell Arduino BUTTON is an input
  
  Serial.begin(9600);
  
  Ethernet.begin(mac);
  Udp.begin(localPort);
}

// ************************************************************

void loop()
{
  delay(1000);
  Serial.print("Ready! btn_val: ");
  
  btn_val = digitalRead(BUTTON);          // read input value and store it fresh
  Serial.println(btn_val);
  
  // check if button has been pressed
  if ((btn_val == HIGH)) {
    if (shop_status == 0) {              // we were closed but now we're OPENING
       Serial.print("shop_status: ");
       Serial.println(shop_status);
       Serial.println("We're closed. Time to OPEN!");
       Serial.println("");
       
       strcpy(tweet, msgOpen);
       
    } else {                             // else shop_status == 1, which means we were open but now we're CLOSING
       Serial.print("shop_status: ");
       Serial.println(shop_status);
       Serial.println("We're open. Time to CLOSE!");
       Serial.println("");   
       
       strcpy(tweet, msgClosed);
    }
    
       boolean gotTime = getTime();    // returns TRUE if timestamp was created successfully
       
       if (gotTime) {                   // == 1, then the timestamp was created successfully
         strcat(tweet, " as of ");
         strcat(tweet, timestamp);
       }                                // ELSE returned 0, send tweet w/o timestamp
     
       strcat(tweet, "!");
    
       sendTweet(tweet);
       Serial.print("Tweet successfully sent: ");
       Serial.println(tweet);
       
//       shop_status = 1 - shop_status;       

       if (shop_status){                // == 1, then we're now OPEN
         digitalWrite(LED_grn, HIGH);    // Turn green LED on
         digitalWrite(LED_red, LOW);     // Turn red LED off 
       } else {                        // == 0, then we're now CLOSED
         digitalWrite(LED_grn, LOW);    // Turn green LED off
         digitalWrite(LED_red, HIGH);     // Turn red LED on 
       }
    delay(60000);                        // one minute required by website
  }
}

// ************************************************************

boolean getTime() {
  Serial.println("getTime() begins!");
  Serial.println("");
  
  int hour = 0;
  int timezone = -7;   // AZ timezone is UTC-7.
  
  Serial.println("Moving to sendNTPpacket()!");
  Serial.println("");
  
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  
  Serial.println("Back to getTime()!");

  // wait to see if a reply is available
  delay(1000);  
  if ( Udp.parsePacket() ) {  
    // 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;             

    const unsigned long seventyYears = 2208988800UL;     
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;                               

    int hour24 = ((epoch % 86400L) / 3600) + timezone; // print the hour (86400 equals secs per day). 
    
    if (hour24 < 0)
      hour24 += 24;

    if (hour24 == 0)
        hour = 12;
    else if (hour24 <= 12) 
        hour = hour24;
    else  
        hour = hour24 - 12;

    int minute = (epoch % 3600) / 60;
    
    // build the timestamp
    char hourStr [3];
    char minStr [3]; 
    
    itoa(hour, hourStr, 10);
    itoa(minute, minStr, 10);
    
    strcpy(timestamp, hourStr);    
    
    if (minute < 10)
      strcat(timestamp, ":0");
    else
      strcat(timestamp, ":");
      
    strcat(timestamp, minStr);
  
    if (hour24 < 12)
      strcat(timestamp, "am");
    else
      strcat(timestamp, "pm");  
  }
  Serial.print("Current time: ");
  Serial.println(timestamp);
  
  return 1;                                        // add return 0;
}

// ************************************************************

void sendTweet(char* msg) {                        // change to boolean
  Serial.println("sendTweet() begins!");

  if (Ethernet.begin(mac) == 0) {                           //move this
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)                                                     // BAD!
      Serial.println("infinite loop!");
  }

  Serial.println("connecting ...");
  if (twitter.post(msg)) {
    // Specify &Serial to output received response to Serial.
    // If no output is required, you can just omit the argument, e.g.
    // int status = twitter.wait();
    int status = twitter.wait(&Serial);
    if (status == 200) {
      Serial.println("OK.");
    } else {
      Serial.print("failed : code ");
      Serial.println(status);
    }
  } else {
    Serial.println("connection failed.");
  }
  Serial.println("sendTweet() ENDING!");
  Serial.println("");
}

// ************************************************************

// send an NTP request to the time server at the given address 
unsigned long sendNTPpacket(IPAddress& address)
{
  Serial.println("sendNTPpacket() begins!");
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE); 
  
  Serial.println("memset set!");
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  
    Serial.println("adding to packetBuffer!");
  
  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;

    Serial.println("packetBuffer set!");
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp: 		   
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  
    Serial.println("beginPacket set!");
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  
    Serial.println("write set!");
  Serial.print("NTP_PACKET_SIZE: ");
  Serial.println(NTP_PACKET_SIZE);
   
  
  Udp.endPacket();                              // << Code hangs here when I try to send a second tweet
  Serial.println("packet ended!");
  Serial.println("sendNTPpacket() ENDING!");
  Serial.println("");
}

You may want to try calling Udp.stop() or Udp.flush() at the end of the NTP function. If it is sending the first correctly but hanging after that, it sounds like a resource issue to me. I've never tried this and maybe someone can verify, can you open EthernetUdp.cpp and add some Serial.println()'s to debug and see why its hanging there?

unsigned long sendNTPpacket(IPAddress& address)
{
  Serial.println("sendNTPpacket() begins!");
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE); 
  
  Serial.println("memset set!");
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  
    Serial.println("adding to packetBuffer!");
  
  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;

    Serial.println("packetBuffer set!");
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp: 		   
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  
    Serial.println("beginPacket set!");
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  
    Serial.println("write set!");
  Serial.print("NTP_PACKET_SIZE: ");
  Serial.println(NTP_PACKET_SIZE);
   
  
  Udp.endPacket();                              // << Code hangs here when I try to send a second tweet
  Serial.println("packet ended!");
  Serial.println("sendNTPpacket() ENDING!");
  Serial.println("");
  Udp.flush();
  Serial.println("Flush out Udp instance";
}

GoodAsh03:
I cleaned up the code and got rid of the String class but I still get the same problem:

You have debugging prints. How about copying them into a forum message?

Hi Nick. I added Udp.flush(); right before Udp.endPacket(); but that didn't fix the problem. Here's what the serial monitor says:

Ready! btn_val: 0
Ready! btn_val: 1 << I push the button
shop_status: 0
We're closed. Time to OPEN!

getTime() begins!

Moving to sendNTPpacket()!

sendNTPpacket() begins!
memset set!
adding to packetBuffer!
packetBuffer set!
beginPacket set!
write set!
NTP_PACKET_SIZE: 48
packet ended!
sendNTPpacket() ENDING!

Back to getTime()!
Current time: 3:39pm
sendTweet() begins!
connecting ...
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
Vary: Accept-Encoding
Date: Tue, 30 Oct 2012 22:39:02 GMT
Server: Google Frontend

OKOK.
sendTweet() ENDING!

Tweet successfully sent: We're open as of 3:39pm!

Ready! btn_val: 0
Ready! btn_val: 1 << I push the button the second time
shop_status: 1
We're open. Time to CLOSE!

getTime() begins!

Moving to sendNTPpacket()!

sendNTPpacket() begins!
memset set!
adding to packetBuffer!
packetBuffer set!
beginPacket set!
write set!
NTP_PACKET_SIZE: 48 << The sketch hangs here

Inside EthernetUdp.h :

#define UDP_TX_PACKET_MAX_SIZE 24

Your code:

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

You may want to try increasing UDP_TX_PACKET_MAX_SIZE to 48 (in the library) and try again.

That didn't work either =(

I also tried moving Udp.flush() to right after Udp.read(packetBuffer,NTP_PACKET_SIZE) in getTime() and still no progress. My ethernet shield was not made by Arduino but it is Wiznet W5100-compliant. Could that be the problem?

It's strange. Why would it work once but not twice?

Let's see...

  • Something got corrupted the first time.
  • Something wasn't closed that should have been (or some data not reset)

I got it working! I commented out

  if (Ethernet.begin(mac) == 0) {                           
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)                                                     
      Serial.println("infinite loop!");
      delay(1000);

in sendTweet() and that solved it. That statement was in the wrong place anyway. Thanks for all your help!

Great project! I thought I would have a go at putting this together. My project is not to replicate this code exactly, but to get the timestamp functionality working for a 15pin PLC driven Arduino to send timestamped tweets for each unique PLC trigger.

I assembled the code from the posts in this thread into what i think is the correct copy/paste order of code to make the code work as described. Played around with it for a while to try get it working, full sketch below. I am mostly having success, but have come across some issues, and was wondering if anyone can point me in the right direction.

Issue 1: Timestamp is being generated into Arduino's Serial window, timestamp is showing correct date, but the time is 1hr off. I have adjusted the GMT in the code to "+10" ( for AEST), but it does not seem to effect/fix the genertaed time stamp. Have tried +9, + 11 GMT, but the generated timestamp does not move it's time from +1hr from my current local time. Something strange going on with the timestamp?

Issue 2: Timestamp does not get passed onto the final tweet (maybe related to issue 1). Below is the serial monitor output, you can see that the timestamp is generated on the "DATE:" line, but it fails to get inserted into the tweet message on the last line.... "Tweet successfully sent: We're open as of !".......it is missing the timestamp on the end on the char string - "Were open as of"...
Is it because the timestamp is somehow returning 0/false to the "if (gotTime)"part of the loop. (it is indicated in comments of sketch as "// ELSE returned 0, send tweet w/o timestamp")

Thanks for any help, much appreciated!

Next Post will have Serial monitor results and Arduino Sketch...

SERIAL MONITOR RESULTS:

Ready! btn_val: 0
Ready! btn_val: 1
shop_status: 0
We're closed. Time to OPEN!

getTime() begins!

Moving to sendNTPpacket()!

sendNTPpacket() begins!
memset set!
adding to packetBuffer!
packetBuffer set!
beginPacket set!
write set!
NTP_PACKET_SIZE: 48
packet ended!
sendNTPpacket() ENDING!

Flush out Udp instance
Back to getTime()!
Current time:
sendTweet() begins!
connecting ...
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
Vary: Accept-Encoding
Date: Mon, 03 Dec 2012 05:29:40 GMT ( <---- GENERATED TIMESTAMP - 1HR AHEAD OF CURRENT LOCAL TIME )
Server: Google Frontend

OKOK.
sendTweet() ENDING!

Tweet successfully sent: We're open as of ! ( <---- MISSING TIMESTAMP ON END OF TWEET MESSAGE :smiley: )