Introduction

A few months ago I started working on Arduino to build my project, a weather station that offered data through the Internet.

The objectives were mainly these:

The final result of the project is a weather station made with an Arduino Yún and two sensors that publishes data on Xively.

NOTE: This page is about version 2.0 of the weather station. Version 1.0 isn't a good choice anymore, because it needs DynDNS and it stopped being free in Spring 2014, and because Wishield isn't made anymore either. But as a reference, you can find the 1.0 version page here.


Why Dalton?

John Dalton (1766-1844) was an English chemist and physicist best known for his work in the development of atomic theory and his research in colour blindness. But he was also one of the first meteorologists, and kept for 57 years a meteorological diary with more than 200.000 observations. Naming Dalton this weather station is my humble homage to a great scientist.


Hardware

This is the hardware needed for this project:

1 Arduino Yún. One of the latest additions to the Arduino family, it is a Wifi-enabled Arduino with lots of potential and ease of use.
1 temperature sensor. I chose the SHT-15 sensor because it includes temperature and humidity in just one sensor, comes in a nice breakout board (so, no resistors needed) and there was already-proven code available on the Internet (yes, I'm a lazy programmer :) ).
1 barometric pressure sensor. I've used a BMP085 sensor. Once again, it came in a breakout board and the people of Adafruit have included it in their excellent Adafruit Unified Sensor Driver. It also offers temperature data, so it's redundant, but this works on our favor, since it allows, as I've done, to get a temperature measure from each sensor and calculate the average, giving a more precise measure.
8 wires. Use whatever suits you, of course, but I like very much this kind of breadboard wires, easy to connect to Arduino pins.
A microUSB power supply. You can only supply power to the Yún through its microUSB port.
A project case. Use whatever suits you. I recycled a Ferrero Rocher transparent plastic box. :)

Building the weather station

This is the circuit to build with the components

click to enlarge

Image made with Fritzing


The BMP085 is i2c, so it is connected to the i2c port of the Yún, which is not located in the usual analog pins. SDA is on digital pin 2 and SCL on digital pin 3. The SHT15 needs two digital pins and we're using 5 and 6.

There are two versions of the BMP085 breakout board. I have the 3.3V version, so it goes to the 3.3V pin. NEVER connect it to 5V. The good thing of the 3.3V version is that since these two sensors use different voltages, we have two GND pins, one sensor is i2c and the other is digital, and they both come in a breakout board, we need no breadboard.

Here you are a couple of photos of the real thing (click the photos to enlarge):

This is Dalton, already in its case, but still on the bench being programmed and tested.

And here we are Dalton, already on its location happily sending data to the Internet of Things.



Configuring your Xively feed

We won't go through all the details of opening a developer account on Xively since the instructions offered on the site are very clear. Once we have our account, we have to go to the Develop section and add a device. I called mine YunTemps and configured it as a Public Device so that everyone can access the weather data.

This will create the device and its corresponding feed and URL, plus the keys we will need later on our sketch. To end this initial configuration, we have to add channels. These channels will be the ones receiving the data from our station. The creation of a channel is also a simple process: you add a Channel ID, tags (optional), the units used and the units symbol.

The most important part is the Channel ID, that we will need also later on the sketch to tell Xively where the data we are sending should go. For this project, we need to create these channels:

That's all for now. We can now move to programming the Arduino sketch.



Sketch

As the time of this writing (july 2014), you need a beta version of the Arduino IDE to work with a Yún. So, if you are using the "normal", final version, you will have to download and install this beta..

You will also need a couple of libraries from Adafruit for the BMP085 sensor: the Adafruit Unified Sensor Driver and the Adafruit_BMP085 Arduino Library version 2. Download and copy them in the libraries folder of the Arduino IDE as usual.

Yún also requires that you configure it to connect it to your Wifi network. The steps are very simple and you will find a complete tutorial for this and all the steps required to be able to work with your Yún on the Arduino site.

The complete sketch is here. You will also need this passwords.h file. Now we will explain the most relevant things of the sketch.

First of all, the passwords.h file. You just have to insert here your Xively API key and your Feed ID. You will find all this information at the Develop section of your device on Xively.

#define APIKEY        ""                  // replace your xively api key here
#define FEEDID        XXXXXXXX                   // replace your feed ID
#define USERAGENT     "YunTemps" 

Now the sketch itself. We start with the required includes.

#include <Process.h>
#include "passwords.h"
#include <Adafruit_Sensor.h> //new libraries for BMP085
#include <Adafruit_BMP085_U.h>  //new libraries for BMP085
#include <math.h>
#include <Wire.h> //required by Adafruit libraries

Next we define a constant, postingInterval that will mark the frequency of our station sending data to Xively. I've given it a value of 30000 milliseconds (5 minutes), but you can change to the value that better suits you. Then we define a couple of variables: lastRequest for controlling the last time we sent data, and dataString, that we will use to build the string of data we will send to Xively.

const unsigned long postingInterval = 300000; 
unsigned long lastRequest = 0;  
String dataString = "";

Now we define a couple of constants that we will use on the dew point formula, we create an object to define the BMP085 sensor (as needed by the Adafruit library functions) and we create two variables holding the values of the pins where the SHT15 sensor is connected.

//constants for dew point formula
//we follow the formula Td = b*gamma(T,RH)/a-gamma(T,RH) where gamma(T,RH)=((a*T)/(b+T)+ln(RH/100))
// Td =dew point, T = temperature in celsius, RH = relative humidity
#define b 237.7
#define a 17.271

Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085); //defines the BMP085 sensor

//SHT15 pins

int dataPin = 5;
int sckPin = 6;

Next come the different functions used to get values from the SHT15. I can't comment too much here, since it's not my code. I'm using s version of Wayne's code made to show Celsius degrees. If you live in Fahrenheit lands, you could use the original version of the code. Check Wayne's blog for more information.

The next part of the code is the function sendData() that we will call when we need to send our weather data to Xively. It builds a string including the Xively site, our keys and feed id and the data string we will create in the loop() function to pass it as parameters for curl, a command-line tool for transferring data with URL syntax included in the Linux shell that takes care of Yún communications. To be able to call curl, we use a Process object, the base class for all the communications with the Yún shell. More information at the Arduino Reference.

void sendData() {
  String apiString = "X-ApiKey: ";
  apiString += APIKEY;

  String url = "https://api.xively.com/v2/feeds/";
  url += FEEDID;
  url += ".csv";// Send the HTTP PUT request

  // Is better to declare the Process here, so when the
  // sendData function finishes the resources are immediately
  // released. Declaring it global works too, BTW.
  Process xively;
  xively.begin("curl");
  xively.addParameter("-k");
  xively.addParameter("--request");
  xively.addParameter("PUT");
  xively.addParameter("--data");
  xively.addParameter(dataString);
  xively.addParameter("--header");
  xively.addParameter(apiString); 
  xively.addParameter(url);
  xively.run();

  // If there's incoming data from the net connection,
  // send it out the Serial:
  while (xively.available()>0) {
    char c = xively.read();
    Serial.write(c);
  }
}

Now the setup() function. We open Bridge and Serial, configure the SHT15 pins as outputs and initialize both sensors.

void setup() {
  Bridge.begin();
  Serial.begin(9600);
  
  pinMode(dataPin,OUTPUT);
  pinMode(sckPin,OUTPUT);
  resetSHT();
  
  /* Initialise the sensor */
  if(!bmp.begin())
  {
  /* There was a problem detecting the BMP085 ... check your connections */
  Serial.print("Ooops, no BMP085 detected ... Check your wiring or I2C ADDR!");
  while(1);
  }

  lastRequest = millis();
}

And finally, the loop() function. First of all, we get data from the BMP085 sensor. We create a sensor event (in Adafruit's library, a sensor reading) and read the pressure and temperature.

void loop() {
 long now = millis();
 
 /* Get a new sensor event */
  sensors_event_t event;
  bmp.getEvent(&event);
  float pressure = event.pressure;
  float temp_bmp;
  bmp.getTemperature(&temp_bmp);

Now we get the data from the SHT15 sensor...

  //SHT-15
  int temp_raw = getTempSHT(); // get raw temperature value
  float temp_degc = (temp_raw * D2) + D1;
  // Unit Conversion - See datasheet
  int rh_raw = getHumidSHT(); // get raw Humidity value
  float rh_lin = C3 * rh_raw * rh_raw + C2 * rh_raw + C1; // Linear conversion
  float rh_true = (temp_degc * (T1 + T2 * rh_raw) + rh_lin); // Temperature compensated RH

...and then we calculate the average temperature and the dew point.

  float temp_avrg = (temp_degc+temp_bmp)/2;
  float gamma = ((a*temp_avrg)/(b+temp_avrg))+log(rh_true/100);
  float dewpoint = (b*gamma)/(a-gamma);

And finally, if it's time to send data to Xively, we build the data string with the channel IDs we defined on Xively and the sensors values, and we call the sendData() function.

  if (now - lastRequest >= postingInterval) {
    dataString = "Temperature,";
    dataString += temp_avrg;
    dataString += "\nRelativeHumidity,";
    dataString += rh_true;
    dataString += "\nBarometricPressure,";
    dataString += pressure;
    dataString += "\nDewPoint,";
    dataString += dewpoint;
    dataString += "\nTemperatureBMP085,";
    dataString += temp_bmp;
    dataString += "\nTemperatureSHT15,";
    dataString += temp_degc;
    sendData();
    lastRequest = now;
  }
}

If everything goes well, after the first five minutes running, our station will begin to send data to Xively. You can take a look at my station's feed here.

Contact

If you want to comment something about the project, or if you need help building your own Dalton, or have any ideas to improve the station, you can get in touch with me: jlmartinmas <---at---> gmail.com. English and Spanish spoken. :)




© 2010 Kawasemi Corp.