Twitter Message Problem - posting variables?

Hi all

I’m a ammature, so please be gentle.

I’m needing a bit of help with my weather station code. I’ve managed to get the arduino (UNO) to read the sensors (BMP085 & DHT22) & DS1307 and write the values to the SDcard, LCD and Serial without many problems. I’m now wanting to incorporate twitter into my project. So the weather station will tweet the values periodically or when certain parameter are met etc.

I’ve had to order the Mega2560 as the code is now exceeding the limitation of my UNO since the addition of the Twitter (probably due to my poor coding skills).

I’ve used the Singlepost example in the Twitter library and got it to work, but it only sends the TEXT within the " ", how can I reconfigure the code so that I can pull all the data from the sensors etc into the // char msg = “Hello, World! I’m Arduino!”; // line? From what I understand the Twitter “line” need to be of a char nature, therefore I would need to put all the values (floats, int, ???) into a “string” and then convert into a char string? I’m losing my self here…

I’ve tried a bit of googling and it seems that printf() may work, but I’m never used it and not sure how to implement it, possibly the string function as well? I’m not sure!

In the text I would have to include the date and time from the DS1307, as if the tweet is the same (parameters haven’t changed) it will be rejected as a duplicate, therefore including the date and time it would never seen as a duplication - I hope?

Any help is much appreciated.

/*
 Weather datalogger 
 by Justin
 	
 The circuit:
 * analog sensors on analog ins 0, 1, and 2
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4
 	 
 */

#include <SD.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h> // For I2C LCD
#include <RTClib.h> // For DS1307 RTC 
#include <BMP085.h> // Barometric Sensor
#include "DHT.h" // Humidity Sensor
#include <SPI.h> 
#include <Ethernet.h>
#include <Twitter.h>


#define DHTPIN 2  // Humidity sensor output pin to digital pin2

#define DHTTYPE DHT22   // DHT 22  (AM2302)

DHT dht(DHTPIN, DHTTYPE);  

LiquidCrystal_I2C lcd(0x27,16,2);  // Sets I2C LCD address is 0x27, some differ, for a 16 chars and 2 line display, 
                                   //"lcd" in command is LCD name, use "lcd2" for multile LCDs.  
RTC_DS1307 RTC;

BMP085 bmp;

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

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

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

// Message to post

// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.
const int chipSelect = 4; // above
unsigned long pressure = 0;
int realalt = 0;
float bmptemp = 0;

char msg[] = "Hello, World! I'm Arduino!";  //twitter message here.


void setup()
{
  delay(1000);
  Ethernet.begin(mac, ip);  // or you can use DHCP for autoomatic IP address configuration.
                            // Ethernet.begin(mac);  
  Serial.begin(9600);
  Wire.begin();
  bmp.begin();
  dht.begin();
  
  lcd.init();                // initialize the lcd  
  lcd.backlight();
  lcd.print("Weather V1.0"); // Print a "startup" message to the LCD.
  delay(2000);
  lcd.clear();

  RTC.begin();                 // Startup RTC

  if (!RTC.isrunning()) {      // Checks if RTC is running
    Serial.println("RTC is NOT Running");    // Prints line to serial monitor for debugging
    RTC.adjust(DateTime(__DATE__,__TIME__)); // Line sets the RTC to the date & time this sketch was compiled
  }                                          // RTC setup subroutine?
  
  Serial.print("Initializing SD card...");
  lcd.print("Init SD Card");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
  lcd.clear();
  lcd.print ("card initial");
  
  File logFile = SD.open("WEATHER1.csv", FILE_WRITE);
  if (logFile)
  {
    logFile.println(", , , ,"); //Just a leading blank line, incase there was previous data
    String header = "Time, Pressure, Alt, Temp, Humidity, Temp2";
    logFile.println(header);
    logFile.close();
    Serial.println(header);
  }
  else
  {
    Serial.println("Couldn't open log file");
    lcd.print("problem card");   
  }
}

void loop(){
  
  DateTime now = RTC.now();
  
  unsigned long pressure = bmp.readPressure(); //testing 
  int realalt = bmp.readAltitude(101400);
  float bmptemp = bmp.readTemperature();
  
  float h = dht.readHumidity();
  float t = dht.readTemperature();
   
  if (isnan(t) || isnan(h)) {
    Serial.println("Failed to read from DHT");
  } else {
   
  //Open a file to write to
  //Only one file can be open at a time
  File logFile = SD.open("WEATHER1.csv", FILE_WRITE);
  if (logFile)
  {
    logFile.print(now.hour(), DEC);
    logFile.print(":");
    logFile.print(now.minute(), DEC);
    logFile.print(":");
    logFile.print(now.second(), DEC);
    logFile.print(", ");
    logFile.print(pressure);
    logFile.print(", ");
    logFile.print(realalt);
    logFile.print(", ");
    logFile.print(bmptemp);
    logFile.print(", ");
    logFile.print(h);
    logFile.print(", ");
    logFile.println(t);
    logFile.close();
    
    Serial.print(now.hour(), DEC);
    Serial.print(":");
    Serial.print(now.minute(), DEC);
    Serial.print(":");
    Serial.print(now.second(), DEC);
    Serial.print(", Press = ");
    Serial.print(pressure);
    Serial.print(", Real Alt = ");
    Serial.print(realalt);
    Serial.print(", Humidity = ");
    Serial.print(h);
    Serial.print(", Temp2 = ");
    Serial.print(t);
    Serial.print(", Pressure unsigned long = ");  //testing...
    Serial.println(pressure);
     
    lcd.clear();
    lcd.print(now.hour(), DEC);
    lcd.print(":");
    lcd.print(now.minute(), DEC);
    lcd.print(":");
    lcd.print(now.second(), DEC);
    lcd.print("  ");
    lcd.print(h);
    lcd.print("%");
    lcd.setCursor(0, 1);
    lcd.print(pressure);
    lcd.setCursor(6, 1);
    lcd.print(bmptemp);
    lcd.print("/");
    lcd.print(t);
    
   if (h > 30)
   {
     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.");
  }
   }
  }
  else
  {
    Serial.println("Couldn't open log file");
    lcd.setCursor(0, 1);
    lcd.print("Problem - Card");
  }
  delay(20000); // Refresh every 20 Seconds
  } 
}

Use a large enough array, NOT one that the compiler determines the size of. char msg[] = "Hello, World! I'm Arduino!"; //twitter message here. char msg[80];

Then, you'll need to use a combination of functions to assign a value to msg. Use dtostrf() to convert the floats to strings, and strcat() to concatenate those strings (and/or text) to msg.

Hi Paul

Thanks for your reply.

Do you know if there are any "easy to understand" tutorials or dtostrf() & dtostrf() for Dummies out there?

I've done a bit of searching but can't find any examples with simple explanations, for those not so well seasoned coders :blush:

Thanks for your assistance.

The signature for dtostrf is: char *dtostrf (double val, signed char width, unsigned char prec, char *s)

You can ignore the return value. val is the value to be converted to a string. width is the amount of space that the result should have. prec is the number of digits after the decimal point. s is where to store the string.

char buff[16];
float val =14.7;
dtostrf(val, 10, 3, buff);

should result in buff containing " 14.700".

char msg[80];
msg[0] = '\0';
strcat("It's cold out: ");
strcat(buff);

should result in msg containing "It's cold out: 14.700".

Ok, so I should've been more specific......"dtostrf() & dtostrf() for Really Dumb Dummies :roll_eyes:

Is my understanding right here?

char buff[16];   // buff is a temp "allocation" with 16 characters availible?
float val =14.7; // sets float value of variable "val" = 14.7, I can just use the "h" in my code as its the Humitidy float from sensor
dtostrf(val, 10, 3, buff); // Take the value of "val" allocates 10 "spaces" and decimals it at 3 position, stores it as "buff"

should result in buff containing "    14.700".

Is this correct? if so, can we also use "buff2, buff3 etc?

char msg[80]; // creates msg with "allocation" with 80 characters availible
msg[0] = '\0';  // No idea?
strcat("It's cold out: "); // prints the "its....out" text. But to where?
strcat(buff);   // prints the characters stored in buff, again, not sure where for how it prints? does it print it into the msg?

should result in msg containing "It's cold out:   14.700".

Thanks

Is this correct? if so, can we also use "buff2, buff3 etc?

Yes, that's correct. Reuse buff, after copying the contents to msg, rather than creating a whole series of small buffers.

Ok, getting somewhere 8)

Sorry, but are the rest of my understandings correct? (posted within the code blocks) just helps me with understanding the logic.

What command actually puts the info into "msg"?

If I'm getting this right, you can do the dtostrf convertion on one parameter, put it into msg, convert another (reusing the same buff) write it to msg, and so on, and when you read msg you will have the accumilation of all the data writen into msg? if so, then how do you clear msg for the next message? char msg[80] = ""; ?

What command actually puts the info into "msg"?

The strcat() function.

If I'm getting this right, you can do the dtostrf convertion on one parameter, put it into msg, convert another (reusing the same buff) write it to msg, and so on, and when you read msg you will have the accumilation of all the data writen into msg?

Yes.

how do you clear msg for the next message?

msg[0] = '\0';

This is all basic C string manipulation. You will do yourself a world of good if you get a C book.

Paul, you're a kind man, Thanks for all you help and patience!

I had a problem with the code, but picked up a error. I needed the “prefix” of “msg” put in the brackets in the strcat() function.

char msg[80];
msg[0] = ‘\0’;
strcat(msg, "It’s cold out: ");
strcat(msg, buff);

:slight_smile:

LightySA: I needed the "prefix"

It's actually called an argument.

You are concatenating the second argument of buff to the first argument msg.

Hi all, I'm back again..... :blush:

Got the all the code working and sending out all my data as required, but I just have one problem, its a decimal placement problem.

I'm getting a value from the barometric pressure sensor which I'm storing as "unsigned long pressurefull", this value is generally between 98500 - 102500, roughtly, depending on weather.

Thanks to the above help I've managed to write this to the string to be sent out via Twitter, but instead of just showing a full 5/6 digits (eg 98500), I would like to format it to have 2 decimal points, eg 985.00 - 1025.00.

I set the dtostrf() to "2" precision points, eg: dtostrf(pressurefull, 10, 2, (buff); but all I land up with is 98500.00 / 102500.00, it just adds ".00" to the end of the input.

So I tried a bit of math : pressure = pressurefull / 100; thinking it would move the decimal butit just dropped the last two digits from the end of the unsigned long, eg 98556 now just becomes 985

How can I do this to get a dtostrf() output of 985.56 from a reading of 98556 from the BMP085 pressure sensor?

Thanks in advance!

Don't bother with floats.

Say you had val = 98512

98512 / 100 = 985 -- whole number

98512 % 100 = 12 -- fractional part

So to print it with a decimal, you would simply write something like this:

sprintf(buffer, "%d.%02d", wholeNumber, fraction);

So I tried a bit of integer math : pressure = pressurefull / 100; thinking it would move the decimal butit just dropped the last two digits from the end of the unsigned long, eg 98556 now just becomes 985

If you tried float math, instead, you’d have better results:

pressure = pressurefull / 100.0;

Hi Paul, I gave it a bash but still getting the same results…

Just to confirm, simplified version of my code:

unsigned long pressurefull;
unsigned long pressure;

void loop()

unsigned long pressurefull = bmp.readPressure();
unsigned long pressure = pressurefull / 100.0; //Aslo tried /100.00

dtostrf(pressure, 9, 2, buffer);
strcat(msg, " Pressure :");
strcat(msg, buffer);

Output :

Pressurefull = 98512
pressure = 985
msg = 985.00

Just not winning!

@Arrch, since I’m writing to a Char string and not a LCD or Serial, I’m unsure if that would work?

LightySA: @Arrch, since I'm writing to a Char string and not a LCD or Serial, I'm unsure if that would work?

What does that have to do with it? sprintf() puts formatted data into a char string.

unsigned long pressure = pressurefull / 100.0; //Aslo tried /100.00

So, you think that you can store 985.12 in an integer variable? I don’t.

Ahhh, thanks Paul, I'll take that as a slap on the back of the head, and a well deserved one at that! :grin:

Float pressure = pressurefull / 100.0;

And it work!!!!!

@Arrch, I thought that printf() was used for printing multiple variable in one string for printing to LCD etc, didn't realize it printed to a char string.... Clearly I've got more than my fair share to learn, but I'm really enjoying to process!