Run into a problem using snprintf() command with twitter posts

Hi I have written a code for a home security system. I have finished that part of the code and now am trying to add onto it by making it send texts to my phone when certain events happen. I am using the twitter library to do this and after much grief that twitter has given me on the duplicate message error I have finally figured it out...Kinda

I found that I can use the snprint() command and it works perfectly. I just use a variable (j) and increment it every time in the loop that way it never sends a duplicate message to twitter. Like here

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

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


// Ethernet Shield Settings
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00F, 0xD7, 0xA7 };


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

// Message to post
char msg[128];
int delayS = 60;
char j = 0;


void setup()
{
  Ethernet.begin(mac);
  Serial.begin(9600);
}

void loop()
{
  snprintf(msg, 128, "Im going fishing %ld",  j);

  Serial.println("Delaying ...");
  for(int i = 0; i < delayS; i++)
  {
    delay(1000);
    Serial.print(i);
    Serial.print(" ");
  }
  Serial.println();

  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.");
  }
  j++;
  delay (60000);
}

However I can not figure out how to increment the variable in my code for my security system. Also I'm not even sure if this is the problem cause I switched from using the variable to using millis() and it still doesn't work. I have a blue LED called bluePin and every time it goes past its for loop i want it to send me a message. It will only send the message once though...the first time the twitter.post() command is called.
Here is my code.

#include <SPI.h>#include <SPI.h> // needed in Arduino 0019 or later
#include <Ethernet.h>
#include <Twitter.h>
#include <Password.h> //http://www.arduino.cc/playground/uploads/Code/Password.zip
#include <Keypad.h> //http://www.arduino.cc/playground/uploads/Code/Keypad.zip
#include <Timer.h>

Password password = Password( "xxxxxxxx" ); // my passcode

const byte ROWS = 4; // Four rows
const byte COLS = 3; //  columns
// Define the Keymap
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};

byte rowPins[ROWS] = { 2, 7, 6, 4 };// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte colPins[COLS] = { 3, 1, 5 };// Connect keypad COL0, COL1 and COL2 to these Arduino pins.

// Create the Keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );


// Ethernet Shield Settings
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00F, 0xD7, 0xA7 };


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

// Message to post
char msg1[128];
char msg2[128];
char msg3[128];

int redPin = 9; // represents alarm being off (at home) LED
int bluePin = 15 ; // represents alarm being on (not home) LED
int checkRedLight = 8; // checks to see if alarm is off
int motionSensorsOn = 16; // Infared sensors turned on
int doorSensorsOn = 17; // Turns door sensors on
int checkDoorSensors = 18; // checks to see if door contacts have been broken or not
int checkMotionSensors = 14; // checks to see if the infared sensors have picked up any movement
int triggerAlarm = 19;// Sets off the burglar alarm
int iCanSeeYou = 0;
int val_2 = 0;
int val_3 = 0;
int val_4 = 0;
int val_5 = 0;
int i;
int armedCheck; // function used to monitor all sensors
int setAlarmOff; // function used to set burglar alarm off
int turnCamerasOn;  // function to turn on cameras
Timer t;


void setup()
{
  Ethernet.begin(mac);
  pinMode (redPin, OUTPUT);
  pinMode (bluePin, OUTPUT);
  pinMode (motionSensorsOn, OUTPUT);
  pinMode (doorSensorsOn, OUTPUT);
  pinMode (triggerAlarm, OUTPUT);
  pinMode (iCanSeeYou, OUTPUT);
  pinMode (checkDoorSensors, INPUT);
  pinMode (checkRedLight, INPUT);
  pinMode (checkMotionSensors, INPUT);

  keypad.addEventListener(keypadEvent); //add an event listener for this keypad
}

void loop(){
  keypad.getKey();
  t.update();
  snprintf(msg3, 128, "Im at the house %ld",  millis());
  snprintf(msg1, 128, "Im leaving the house %ld",  millis());
  snprintf(msg2, 128, "My alarm is going off %ld",  millis());
}

//take care of some special events
void keypadEvent(KeypadEvent eKey){
  switch (keypad.getState()){
    case PRESSED:
	switch (eKey){
	  case '*': checkPassword(); break;
	  case '#': password.reset(); break;
	  default: password.append(eKey);
     }
  }
}

void checkPassword(){                 // function to check the passcode and arm or disarm the system
  if (password.evaluate()){
     twitter.post(msg3);
     digitalWrite (bluePin, LOW);  
     digitalWrite (redPin, HIGH);
     digitalWrite (motionSensorsOn, LOW);
     digitalWrite (doorSensorsOn, LOW);
     digitalWrite (triggerAlarm, LOW);
     digitalWrite (iCanSeeYou, LOW);
     t.stop (setAlarmOff);
     t.stop (armedCheck);
 
  } else{
     digitalWrite (redPin, LOW);
       for ( i = 0; i <= 60; i++) {    // allows me 60 sec to get out of my house before all sensors are activated
         digitalWrite (bluePin, HIGH);
         delay (500);
         digitalWrite (bluePin, LOW);
         delay(500);
       }
    digitalWrite (bluePin, HIGH);
    twitter.post(msg1); 
    int check = t.after(1000, setAlarm); // jumps to setAlarm function after said seconds
}}
 void setAlarm() {                    // function used to arm the system and to begin the countdown to turn all sensors on 
        digitalWrite (motionSensorsOn, HIGH); 
        digitalWrite (doorSensorsOn, HIGH);
        delay(10000);
        armedCheck = t.every(1000, checkSensors);
      }  //jumps to checkSensors function every second
   

  
  void checkSensors () {             // function used to check all sensors every second
   
    val_2 = digitalRead (checkDoorSensors);
    val_4 = digitalRead (checkMotionSensors);
      if (val_4 == HIGH || val_2 == HIGH) {  
         setAlarmOff = t.after(50000, alarmOn);  // if any sensors have been triggered then it jumps to alarmOn function
         turnCamerasOn = t.after (15000, camerasOn); // if any sensors have been triggered then it jumps to cameras on 
         t.stop (armedCheck);
      }
        
  }
  
  void alarmOn() {
    val_3 = digitalRead (checkRedLight);  
      if (val_3 == LOW) {
         digitalWrite (triggerAlarm, HIGH); //burglar alarm going off
         twitter.post(msg2);
         int doIt = t.after (15000, youCaughtBitch); }
      else { digitalWrite (triggerAlarm, LOW);
        t.stop (armedCheck);
      }
  }
  
  void camerasOn () {
    val_5 = digitalRead (checkRedLight);
      if (val_5 == LOW ) {
        digitalWrite (iCanSeeYou, HIGH);
      }
      else { digitalWrite (iCanSeeYou, LOW);
         t.stop (armedCheck);
      }
  }
  
  void youCaughtBitch () {
    digitalWrite (triggerAlarm, LOW); // turns buglar alarm off after said time
  }

Like I said above I have tried using a variable (x) instead of the millis() and writting an increment statement after the twitter.post(msg1) command..didn't work. I also tried the following within the void loop()

if (bluePin== HIGH) {
for (y=0; y<1; y++) {
x++;
}
}
That doesn't work either. Can anyone point me in the right direction? Is there a command that will automatically reset the board and would that be a good idea? Also as you can tell by my code I really hoping that I could get it to send me different messages when different events happen. Is this even possible? I can't find anything on it. In my code it will only send one message, the first one called upon, and no others. And it will only send this message once unless the board is restarted. Therein lies my problems. Thank you for your time.

I just use a variable (j) and increment it every time in the loop that way it never sends a duplicate message to twitter.

Why is j a char, rather than a byte or int?

  snprintf(msg, 128, "Im going fishing %ld",  j);

%ld is not the correct format specifier for a char. %ld is for a long int. j is a char, not a long int.

In the other code, you should be calling snprintf() just before posting the message. You do not need three large buffers. You only need one.

I suspect that the second code is running out of memory.

From what I can see you are trying to use Timer to do the work.

If so, you need to tell timer what to do.

Have a look at the examples on the arduino playground: Arduino Playground - HomePage and pay close attention to t.every()

Your code other than that looks fine.
Consider not updating the strings constantly in loop() but rather in the function that is triggered.

I will have a look at writing my own cut down version of your code and see if we can't come up with something useful between us.

Regards

Greg
from http://labby.co.uk/2012/08/arduino-twitter-post/

To PaulS,
Thanks. I did not know this information. I will try it out as soon as I get home (which will be Monday). I'll let you know if it works. I was confused on what to use whether it should be int or char. I am a beginner and I have a beginner book for arduino C code but the whole arrays, strings, pointers kinda confuses me. I'm going to have to go back and reread.

To Greg,
Hey I'm not sure what you want me to catch by looking at the t.every command. I am using it in my code now. Could you give me a hint? Also I will use your idea of incrementing within the called function.

I did a lot more research after I posted this and found out that the IDE i was using has bugs when it comes to posting different messages using twitter. I found this out around 4am, after pulling my hair out for five hours trying to get it to work. I could only laugh at myself. So i downloaded a new IDE and it works in the former code perfectly but not so much in the latter. Your ideas sound like good ones so I will be trying them out asap. Thanks again for the advice and time.

Hey guys I used your ideas and re-wrote my code. I changed the char variable (x) to an int long so I it will be the right format for %ld. I took out two buffers and now only have one. I use the snprint() command in the function, right before the twitter.post. I incremented the variable (x) in checkpassword function by ten. Here is my new code if you want to look at it.

#include <SPI.h>#include <SPI.h> // needed in Arduino 0019 or later
#include <Ethernet.h>
#include <Twitter.h>
#include <Password.h> //http://www.arduino.cc/playground/uploads/Code/Password.zip
#include <Keypad.h> //http://www.arduino.cc/playground/uploads/Code/Keypad.zip
#include <Timer.h>

Password password = Password( "xxxxx" ); // my passcode

const byte ROWS = 4; // Four rows
const byte COLS = 3; //  columns
// Define the Keymap
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};

byte rowPins[ROWS] = { 2, 7, 6, 4 };// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte colPins[COLS] = { 3, 1, 5 };// Connect keypad COL0, COL1 and COL2 to these Arduino pins.

// Create the Keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

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


// Ethernet Shield Settings
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00F, 0xD7, 0xA7 };


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

// Message to post
char msg[128];
long int x;
int redPin = 9; // represents alarm being off (at home) LED
int bluePin = 15 ; // represents alarm being on (not home) LED
int checkRedLight = 8; // checks to see if alarm is off
int motionSensorsOn = 16; // Infared sensors turned on
int doorSensorsOn = 17; // Turns door sensors on
int checkDoorSensors = 18; // checks to see if door contacts have been broken or not
int checkMotionSensors = 14; // checks to see if the infared sensors have picked up any movement
int triggerAlarm = 19;// Sets off the burglar alarm
int iCanSeeYou = 0;
int val_2 = 0;
int val_3 = 0;
int val_4 = 0;
int val_5 = 0;
int i;
int armedCheck; // function used to monitor all sensors
int setAlarmOff; // function used to set burglar alarm off
int turnCamerasOn;  // function to turn on cameras
Timer t;


void setup()
{
  Ethernet.begin(mac);
  pinMode (redPin, OUTPUT);
  pinMode (bluePin, OUTPUT);
  pinMode (motionSensorsOn, OUTPUT);
  pinMode (doorSensorsOn, OUTPUT);
  pinMode (triggerAlarm, OUTPUT);
  pinMode (iCanSeeYou, OUTPUT);
  pinMode (checkDoorSensors, INPUT);
  pinMode (checkRedLight, INPUT);
  pinMode (checkMotionSensors, INPUT);

  keypad.addEventListener(keypadEvent); //add an event listener for this keypad
}

void loop(){
  keypad.getKey();
  t.update();
}

//take care of some special events
void keypadEvent(KeypadEvent eKey){
  switch (keypad.getState()){
    case PRESSED:
	switch (eKey){
	  case '*': checkPassword(); break;
	  case '#': password.reset(); break;
	  default: password.append(eKey);
     }
  }
}

void checkPassword(){                 // function to check the passcode and arm or disarm the system
if (password.evaluate()) {
     digitalWrite (bluePin, LOW);  
     digitalWrite (redPin, HIGH);
     digitalWrite (motionSensorsOn, LOW);
     digitalWrite (doorSensorsOn, LOW);
     digitalWrite (triggerAlarm, LOW);
     digitalWrite (iCanSeeYou, LOW);
     snprintf(msg, 128, "Im at the house %ld",  x);
     twitter.post(msg);
     x = x + 10;
     t.stop (setAlarmOff);
     t.stop (armedCheck);
 
  } else{
     digitalWrite (redPin, LOW);
       for ( i = 0; i <= 60; i++) {    // allows me 60 sec to get out of my house before all sensors are activated
         digitalWrite (bluePin, HIGH);
         delay (500);
         digitalWrite (bluePin, LOW);
         delay(500);
       }
    digitalWrite (bluePin, HIGH);
    snprintf(msg, 128, "Im leaving the house %ld",  x);
    twitter.post(msg);
    int check = t.after(1000, setAlarm); // jumps to setAlarm function after said seconds
}}
 void setAlarm() {                    // function used to check if the system is armed and to begin the countdown to turn all sensors on 
        digitalWrite (motionSensorsOn, HIGH); 
        digitalWrite (doorSensorsOn, HIGH);
        delay(10000);
        armedCheck = t.every(1000, checkSensors);
      }  //jumps to checkSensors function every second
   

  
  void checkSensors () {             // function used to check all sensors every second
   
    val_2 = digitalRead (checkDoorSensors);
    val_4 = digitalRead (checkMotionSensors);
      if (val_4 == HIGH || val_2 == HIGH) {  
         setAlarmOff = t.after(50000, alarmOn);  // if any sensors have been triggered then it jumps to alarmOn function
         turnCamerasOn = t.after (15000, camerasOn); // if any sensors have been triggered then it jumps to cameras on 
         t.stop (armedCheck);
      }
        
  }
  
  void alarmOn() {
    val_3 = digitalRead (checkRedLight);  
      if (val_3 == LOW) {
         digitalWrite (triggerAlarm, HIGH);
         snprintf(msg, 128, "My alarm is going off %ld",  x);
         twitter.post(msg);
         int doIt = t.after (15000, youCaught); }
      else { digitalWrite (triggerAlarm, LOW);
        t.stop (armedCheck);
      }
  }
  
  void camerasOn () {
    val_5 = digitalRead (checkRedLight);
      if (val_5 == LOW ) {
        digitalWrite (iCanSeeYou, HIGH);
      }
      else { digitalWrite (iCanSeeYou, LOW);
         t.stop (armedCheck);
      }
  }
  
  void youCaught () {
    digitalWrite (triggerAlarm, LOW);
  }

To Greg,
Were you saying that I should use the t.every command to increment the variable every time an event happens?

I have a similar project where I use twitter to send me text messages. To get around the duplicate issue I use NTPTime (http://arduino.cc/en/Tutorial/UdpNtpClient) library and just tack on the time to my twitter post. You could also just use millis() or millis() / 1000.0

I'm thinking of scrapping twitter and use tropo.com. Here a post I wrote about it: http://arduino.cc/forum/index.php/topic,157840.0.html

Hey Scott I'd really like to post the time onto my tweets. I downloaded the time library but it doesn't work. The examples won't even compile. What IDE do I need?

The examples won't even compile.

Why not?

What IDE do I need?

Google.

I don't know why it doesn't work. I have donwloaded libraries before so I know how to put them in my code but for some reason the #include isn't highlighted when I put the time library in it which I'm guessing is the reason why it won't compile in my code. I'm still kinda new to everything so its probably something stupid i'm doing

mattrloper:
Hey Scott I'd really like to post the time onto my tweets. I downloaded the time library but it doesn't work. The examples won't even compile. What IDE do I need?

See attached sample sketch. I'm using Arduino IDE 1.0.4. You don't need the time.h library for this.

Twitter_Time_Test.ino (5.15 KB)

I took a look at the Twitter_Time_Test. It complies on my IDE. I am also using 1.0.4. Although I am using an Uno and i think if I used the NTP it might take up too much space on my board. Well it and my alarm code together would. Plus it looks a little advanced for me lol. I have saved it though cause I might can use it one day. I read that you can somehow set the date/time yourself and the board will just start at that time once you power it up and it wouldn't use as much memory. I looked at an example of this in my time library but like I said for some reason it won't compile.

I looked at an example of this in my time library but like I said for some reason it won't compile.

Yes, you did say that. What the compiler did NOT say was "No, that won't compile!". It provided much more specific messages, that you have not posted, when you tried to compile code that you have not posted.

Can you see that you need to post some code? Can you see that you need to post the error messages? Or, quit whining and move on.

Here is a example straight out of the Time library. I haven't adjusted it or anything. Didn't touch it

/*
 * TimeAlarmExample.pde
 *
 * This example calls alarm functions at 8:30 am and at 5:45 pm (17:45)
 * and simulates turning lights on at night and off in the morning
 * A weekly timer is set for Saturdays at 8:30:30
 *
 * A timer is called every 15 seconds
 * Another timer is called once only after 10 seconds
 *
 * At startup the time is set to Jan 1 2011  8:29 am
 */
 
#include <Time.h>
#include <TimeAlarms.h>

void setup()
{
  Serial.begin(9600);
  setTime(8,29,0,1,1,11); // set time to Saturday 8:29:00am Jan 1 2011
  // create the alarms 
  Alarm.alarmRepeat(8,30,0, MorningAlarm);  // 8:30am every day
  Alarm.alarmRepeat(17,45,0,EveningAlarm);  // 5:45pm every day 
  Alarm.alarmRepeat(dowSaturday,8,30,30,WeeklyAlarm);  // 8:30:30 every Saturday 

 
  Alarm.timerRepeat(15, Repeats);            // timer for every 15 seconds    
  Alarm.timerOnce(10, OnceOnly);             // called once after 10 seconds 
}

void  loop(){  
  digitalClockDisplay();
  Alarm.delay(1000); // wait one second between clock display
}

// functions to be called when an alarm triggers:
void MorningAlarm(){
  Serial.println("Alarm: - turn lights off");    
}

void EveningAlarm(){
  Serial.println("Alarm: - turn lights on");           
}

void WeeklyAlarm(){
  Serial.println("Alarm: - its Monday Morning");      
}

void ExplicitAlarm(){
  Serial.println("Alarm: - this triggers only at the given date and time");       
}

void Repeats(){
  Serial.println("15 second timer");         
}

void OnceOnly(){
  Serial.println("This timer only triggers once");  
}

void digitalClockDisplay()
{
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println(); 
}

void printDigits(int digits)
{
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

Here are the errors I get when I compile it

TimeAlarmExample.pde: In function 'void setup()':
TimeAlarmExample:20: error: 'setTime' was not declared in this scope
TimeAlarmExample:22: error: 'Alarm' was not declared in this scope
TimeAlarmExample:24: error: 'dowSaturday' was not declared in this scope
TimeAlarmExample.pde: In function 'void loop()':
TimeAlarmExample:33: error: 'Alarm' was not declared in this scope
TimeAlarmExample.pde: In function 'void digitalClockDisplay()':
TimeAlarmExample:64: error: 'hour' was not declared in this scope
TimeAlarmExample:65: error: 'minute' was not declared in this scope
TimeAlarmExample:66: error: 'second' was not declared in this scope

I deleted my copies of the Time and TimeAlarms libraries. I went to Arduino Playground - HomePage, and clicked on the two links in the Update: note to get the newest Time and TimeAlarms libraries. I pasted your code into a new sketch, and got only one "error":

Binary sketch size: 6,562 bytes (of a 30,720 byte maximum)

mattrloper:
I took a look at the Twitter_Time_Test. It complies on my IDE. I am also using 1.0.4. Although I am using an Uno and i think if I used the NTP it might take up too much space on my board. Well it and my alarm code together would.

You can reduce the twitter_Time_Test program size a lot by getting rid of this:

  if (Ethernet.begin(mac) == 0) 
  {  // Takes about 60 seconds to fail
    Serial.println(F("Failed to configure Ethernet using DHCP"));
  }
  else
  {
    Serial.println(F("Connected to Ethernet using DHCP"));
    Udp.begin(localPort);
  }

And replacing with with this:

  // start Ethernet and UDP
  Ethernet.begin(mac, ip);
  Udp.begin(localPort);

Thanks PaulS. I did that and it works now. It will compile. Sorry it has been a while since I have been on the forum. I have finally finished my code for my system and it works great. I am going to try to put the time and date onto my twitter post through the snprintf() command.

Thanks ScottG for all your help. Especially in giving me the idea to use the snprint() command and how to get it up on twitter.

I have one more question though. I thought I read that I can set the time/date manually using a specific command through the time library (although I can't remember where I read it). Is this true or do I need a external source like NTP or GPS?

Once again Thanks guys

The Arduino can keep track of the time, if it knows what time it is at some point. Some Arduinos have better time keeping ability than others, depending on whether they use a crystal or not. Some use a resonator, which is not as accurate.

GPS get data from a much more accurate source than the Arduino can hope to be, as does NTP. An external RTC will be more accurate, too.

It all depends on how accurate you need to be. When twitting, the right month is probably good enough.

Oops, seems I misspelled something...