Introduction: Weather Station Arduino and Processing
Build a mobile or home weather station and graph the data in real time on your computer. The graph maps out wind speed, pressure, temperature, and wind direction for 10 minutes then saves the image as a jpeg and starts over.
Step 1: Anemometer Build
The anemometer I built was built with materials I had on hand. I based the build around a DC motor I had that spins freely with little effort. the diagram list the parts I used.
Step 2: BMP085 Housing
The BMP085 barometric pressure sensor uses I2C bus to communicate with the Arduino. When choosing a BMP085 breakout board the main feature to look for is 5v capability as this will broaden the range of possibilities and simplify wiring. I recommend http://www.adafruit.com/products/391. I used CAT5e to connect the anemometer and sensor to the Arduino in my vehicle. the max distance you can run I2C on CAT5e wire is about 25 feet. for distances longer than 25 feet I would consider wireless. I painted the Coke can white to cut down the false temp reading during full sun.
Step 3: Arduino Code
#include <Wire.h>
#include <Adafruit_Sensor.h> //library avaliable at adafruit.com
#include <Adafruit_BMP085.h> //library avaliable at adafruit.com
Adafruit_BMP085 bmp = Adafruit_BMP085(10085);
int wSpeed;
int wDirect;
int temp1;
int press1;
int wsee;
/**************************************************************************/
/*
Arduino setup function (automatically called at startup)
*/
/**************************************************************************/
void setup(void)
{
Serial.begin(9600);
/* 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);
}
}
void loop(void)
{
/* Get a new sensor event */
sensors_event_t event;
bmp.getEvent(&event);
wsee=analogRead(A0);
wSpeed=map(wsee,0,1023,0,1534); //after testing this gave me accurate wind speed
wDirect=analogRead(A1); //it will be different for your anemometer
/* Display the results (barometric pressure is measure in hPa) */
if (event.pressure)
{
/* Display atmospheric pressue in hPa */
press1=map(event.pressure,850,1100,0,1023);
/* Calculating altitude with reasonable accuracy requires pressure *
* sea level pressure for your position at the moment the data is *
* converted, as well as the ambient temperature in degress *
* celcius. If you don't have these values, a 'generic' value of *
* 1013.25 hPa can be used (defined as SENSORS_PRESSURE_SEALEVELHPA *
* in sensors.h), but this isn't ideal and will give variable *
* results from one day to the next. *
* *
* You can usually find the current SLP value by looking at weather *
* websites or from environmental information centers near any major *
* airport. *
* *
* For example, for Paris, France you can check the current mean *
* pressure and sea level at: http://bit.ly/16Au8ol */
/* First we get the current temperature from the BMP085 */
float temperature;
bmp.getTemperature(&temperature);
temp1=map(temperature,-30,55,0000,1023);
}
if (wSpeed<1000&&wSpeed>99){
Serial.print("0"); //these if statements add 0's to the
Serial.print(wSpeed); //leading edge to create a string of
} //16 numbers to send over the USB
else if(wSpeed<100&&wSpeed>9)
{
Serial.print("00");
Serial.print(wSpeed);
}
else if(wSpeed<10){
Serial.print("000");
Serial.print(wSpeed);
}
else{
Serial.print(wSpeed);
}
if (press1<1000&&press1>99){
Serial.print("0");
Serial.print(press1);
}
else if(press1<100&&press1>9)
{
Serial.print("00");
Serial.print(press1);
}
else if(press1<10){
Serial.print("000");
Serial.print(press1);
}
else{
Serial.print(press1);
}
if (temp1<1000&&temp1>99){
Serial.print("0");
Serial.print(temp1);
}
else if(temp1<100&&temp1>9)
{
Serial.print("00");
Serial.print(temp1);
}
else if(temp1<10){
Serial.print("000");
Serial.print(temp1);
}
else{
Serial.print(temp1);
}
if (wDirect<1000&&wDirect>99){
Serial.print("0");
Serial.print(wDirect);
}
else if(wDirect<100&&wDirect>9)
{
Serial.print("00");
Serial.print(wDirect);
}
else if(wDirect<10){
Serial.print("000");
Serial.print(wDirect);
}
else{
Serial.print(wDirect);
}
Serial.print("\n");
delay(996); //2 - 2 delays for analog to digital converter
// to stabalize and 996 delay to generate one sec intervals
} .
#include <Adafruit_Sensor.h> //library avaliable at adafruit.com
#include <Adafruit_BMP085.h> //library avaliable at adafruit.com
Adafruit_BMP085 bmp = Adafruit_BMP085(10085);
int wSpeed;
int wDirect;
int temp1;
int press1;
int wsee;
/**************************************************************************/
/*
Arduino setup function (automatically called at startup)
*/
/**************************************************************************/
void setup(void)
{
Serial.begin(9600);
/* 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);
}
}
void loop(void)
{
/* Get a new sensor event */
sensors_event_t event;
bmp.getEvent(&event);
wsee=analogRead(A0);
wSpeed=map(wsee,0,1023,0,1534); //after testing this gave me accurate wind speed
wDirect=analogRead(A1); //it will be different for your anemometer
/* Display the results (barometric pressure is measure in hPa) */
if (event.pressure)
{
/* Display atmospheric pressue in hPa */
press1=map(event.pressure,850,1100,0,1023);
/* Calculating altitude with reasonable accuracy requires pressure *
* sea level pressure for your position at the moment the data is *
* converted, as well as the ambient temperature in degress *
* celcius. If you don't have these values, a 'generic' value of *
* 1013.25 hPa can be used (defined as SENSORS_PRESSURE_SEALEVELHPA *
* in sensors.h), but this isn't ideal and will give variable *
* results from one day to the next. *
* *
* You can usually find the current SLP value by looking at weather *
* websites or from environmental information centers near any major *
* airport. *
* *
* For example, for Paris, France you can check the current mean *
* pressure and sea level at: http://bit.ly/16Au8ol */
/* First we get the current temperature from the BMP085 */
float temperature;
bmp.getTemperature(&temperature);
temp1=map(temperature,-30,55,0000,1023);
}
if (wSpeed<1000&&wSpeed>99){
Serial.print("0"); //these if statements add 0's to the
Serial.print(wSpeed); //leading edge to create a string of
} //16 numbers to send over the USB
else if(wSpeed<100&&wSpeed>9)
{
Serial.print("00");
Serial.print(wSpeed);
}
else if(wSpeed<10){
Serial.print("000");
Serial.print(wSpeed);
}
else{
Serial.print(wSpeed);
}
if (press1<1000&&press1>99){
Serial.print("0");
Serial.print(press1);
}
else if(press1<100&&press1>9)
{
Serial.print("00");
Serial.print(press1);
}
else if(press1<10){
Serial.print("000");
Serial.print(press1);
}
else{
Serial.print(press1);
}
if (temp1<1000&&temp1>99){
Serial.print("0");
Serial.print(temp1);
}
else if(temp1<100&&temp1>9)
{
Serial.print("00");
Serial.print(temp1);
}
else if(temp1<10){
Serial.print("000");
Serial.print(temp1);
}
else{
Serial.print(temp1);
}
if (wDirect<1000&&wDirect>99){
Serial.print("0");
Serial.print(wDirect);
}
else if(wDirect<100&&wDirect>9)
{
Serial.print("00");
Serial.print(wDirect);
}
else if(wDirect<10){
Serial.print("000");
Serial.print(wDirect);
}
else{
Serial.print(wDirect);
}
Serial.print("\n");
delay(996); //2 - 2 delays for analog to digital converter
// to stabalize and 996 delay to generate one sec intervals
} .
Step 4:
If you don't already have Processing you can download it free at http://processing.org/ . My code is sloppy and inefficient I am sure but with the little experience I have the fact that it is working is good for now.
Step 5: Processing Code
import processing.serial.*;
PFont p;
Serial myPort; // The serial port
int xPos = 100; // horizontal position of the graph
void setup () {
size(700,500);
p=createFont("Arial",16,true);
background(0); //set background black
for(int u=99;u<width;u=u+60) //loop creates vertical grid
{
stroke(100);
line(u,0,u,height-99);
}
for(int t=height-99;t>0;t=t-25) //loop creates horizontal grid
{
stroke(100);
line(99,t,width,t);
}
textFont(p,12); //set font size to 12
textAlign(LEFT);
fill(255,0,0); //red
text("Wind Speed MPH",100,height-25); //print wind speed
fill(0,255,0); //green
text("Barometric pressure mb",210,height-25);
fill(0,0,255); //blue
text("Degrees Celsius",355,height-25);
fill(255); //white
text("Wind direction N = 0 deg",460,height-25);
fill(100); //gray
textAlign(RIGHT);
text("0",110,height-87);
for (int m=160;m<width;m=m+60) //loop places 0-9 for minutes
{
int Min=(m-100)/60;
fill(100);
textAlign(CENTER);
text(Min,m,height-87);
}
fill(100);
textAlign(CENTER);
text("Minutes",width/2,height-70);
for(int p=400;p>0;p=p-50) //loop places numbers on vertical grid every other line
{
float pat=map(p,400,0,0,200);
int pati=int(pat); //changes float pat to an int
fill(255,0,0);
textAlign(RIGHT);
text(pati,98,p+5); //wind speed measurements
float patie=map(p,400,0,850,1100);
int paties=int(patie);
fill(0,255,0);
text(paties,75,p+5);//pressure measurements
float patiesTemp=map(p,400,0,-30,55);
int patiesTemp1=int (patiesTemp);
fill(0,0,255);
text(patiesTemp1,45,p+5); //temp measurements
float patiesDirec=map(p,400,0,0,359);
int patiesDirect=int(patiesDirec);
fill(255);
text(patiesDirect,25,p+5); //wind direction measurements
}
// List all the available serial ports
println(Serial.list());
// I know that the first port in the serial list on my mac
// is always my Arduino, so I open Serial.list()[0].
// Open whatever port is the one you're using.
myPort = new Serial(this, Serial.list()[0], 9600);
// don't generate a serialEvent() unless you get a newline character:
myPort.bufferUntil('\n');
// set inital background:
}
void draw(){}
void serialEvent (Serial myPort) {
// get the ASCII string:
String inString = myPort.readStringUntil('\n');
String xWindSpeed= inString.substring(0,4);
String xPressure= inString.substring(4,8);
String xtemp= inString.substring(8,12);
String xWindDirect=inString.substring(12,16);
int yWindSpeed=int(xWindSpeed);
int yPressure=int(xPressure);
int ytemp=int(xtemp);
int yWindDirect=int(xWindDirect);
float WindSpeed=map(yWindSpeed,0,1023,height-104,-3);
float Pressure=map(yPressure,0,1023,height-104,-3);
float temp=map(ytemp,0,1023,height-104,-3);
float WindDirect=map(yWindDirect,0,1023,height-104,-3);
stroke(255,0,0,150);
line(xPos,WindSpeed+4,xPos,WindSpeed);
stroke(0,255,0,150);
line(xPos,Pressure+4,xPos,Pressure);
stroke(0,0,255,150);
line(xPos,temp+4,xPos,temp);
stroke(255,255,255,150);
line(xPos,WindDirect+4,xPos,WindDirect);
xPos++;
if (xPos >= width) { //if the graph is full save image as jpeg and start over
saveFrame("Weather-####.jpg");
xPos=100;
p=createFont("Arial",16,true);
background(0); //set background black
for(int u=99;u<width;u=u+60) //loop creates vertical grid
{
stroke(100);
line(u,0,u,height-99);
}
for(int t=height-99;t>0;t=t-25) //loop creates horizontal grid
{
stroke(100);
line(99,t,width,t);
}
textFont(p,12); //set font size to 12
textAlign(LEFT);
fill(255,0,0); //red
text("Wind Speed MPH",100,height-25); //print wind speed
fill(0,255,0); //green
text("Barometric pressure mb",210,height-25);
fill(0,0,255); //blue
text("Degrees Celsius",355,height-25);
fill(255); //white
text("Wind direction N = 0 deg",460,height-25);
fill(100); //gray
textAlign(RIGHT);
text("0",110,height-87);
for (int m=160;m<width;m=m+60) //loop places 0-9 for minutes
{
int Min=(m-100)/60;
fill(100);
textAlign(CENTER);
text(Min,m,height-87);
}
fill(100);
textAlign(CENTER);
text("Minutes",width/2,height-70);
for(int p=400;p>0;p=p-50) //loop places numbers on vertical grid every other line
{
float pat=map(p,400,0,0,200);
int pati=int(pat); //changes float pat to an int
fill(255,0,0);
textAlign(RIGHT);
text(pati,98,p+5); //wind speed measurements
float patie=map(p,400,0,850,1100);
int paties=int(patie);
fill(0,255,0);
text(paties,75,p+5);//pressure measurements
float patiesTemp=map(p,400,0,-30,55);
int patiesTemp1=int (patiesTemp);
fill(0,0,255);
text(patiesTemp1,45,p+5); //temp measurements
float patiesDirec=map(p,400,0,0,359);
int patiesDirect=int(patiesDirec);
fill(255);
text(patiesDirect,25,p+5); //wind direction measurements
}
if (xPos < width) {
// increment the horizontal position:
xPos++;
}
}
}
PFont p;
Serial myPort; // The serial port
int xPos = 100; // horizontal position of the graph
void setup () {
size(700,500);
p=createFont("Arial",16,true);
background(0); //set background black
for(int u=99;u<width;u=u+60) //loop creates vertical grid
{
stroke(100);
line(u,0,u,height-99);
}
for(int t=height-99;t>0;t=t-25) //loop creates horizontal grid
{
stroke(100);
line(99,t,width,t);
}
textFont(p,12); //set font size to 12
textAlign(LEFT);
fill(255,0,0); //red
text("Wind Speed MPH",100,height-25); //print wind speed
fill(0,255,0); //green
text("Barometric pressure mb",210,height-25);
fill(0,0,255); //blue
text("Degrees Celsius",355,height-25);
fill(255); //white
text("Wind direction N = 0 deg",460,height-25);
fill(100); //gray
textAlign(RIGHT);
text("0",110,height-87);
for (int m=160;m<width;m=m+60) //loop places 0-9 for minutes
{
int Min=(m-100)/60;
fill(100);
textAlign(CENTER);
text(Min,m,height-87);
}
fill(100);
textAlign(CENTER);
text("Minutes",width/2,height-70);
for(int p=400;p>0;p=p-50) //loop places numbers on vertical grid every other line
{
float pat=map(p,400,0,0,200);
int pati=int(pat); //changes float pat to an int
fill(255,0,0);
textAlign(RIGHT);
text(pati,98,p+5); //wind speed measurements
float patie=map(p,400,0,850,1100);
int paties=int(patie);
fill(0,255,0);
text(paties,75,p+5);//pressure measurements
float patiesTemp=map(p,400,0,-30,55);
int patiesTemp1=int (patiesTemp);
fill(0,0,255);
text(patiesTemp1,45,p+5); //temp measurements
float patiesDirec=map(p,400,0,0,359);
int patiesDirect=int(patiesDirec);
fill(255);
text(patiesDirect,25,p+5); //wind direction measurements
}
// List all the available serial ports
println(Serial.list());
// I know that the first port in the serial list on my mac
// is always my Arduino, so I open Serial.list()[0].
// Open whatever port is the one you're using.
myPort = new Serial(this, Serial.list()[0], 9600);
// don't generate a serialEvent() unless you get a newline character:
myPort.bufferUntil('\n');
// set inital background:
}
void draw(){}
void serialEvent (Serial myPort) {
// get the ASCII string:
String inString = myPort.readStringUntil('\n');
String xWindSpeed= inString.substring(0,4);
String xPressure= inString.substring(4,8);
String xtemp= inString.substring(8,12);
String xWindDirect=inString.substring(12,16);
int yWindSpeed=int(xWindSpeed);
int yPressure=int(xPressure);
int ytemp=int(xtemp);
int yWindDirect=int(xWindDirect);
float WindSpeed=map(yWindSpeed,0,1023,height-104,-3);
float Pressure=map(yPressure,0,1023,height-104,-3);
float temp=map(ytemp,0,1023,height-104,-3);
float WindDirect=map(yWindDirect,0,1023,height-104,-3);
stroke(255,0,0,150);
line(xPos,WindSpeed+4,xPos,WindSpeed);
stroke(0,255,0,150);
line(xPos,Pressure+4,xPos,Pressure);
stroke(0,0,255,150);
line(xPos,temp+4,xPos,temp);
stroke(255,255,255,150);
line(xPos,WindDirect+4,xPos,WindDirect);
xPos++;
if (xPos >= width) { //if the graph is full save image as jpeg and start over
saveFrame("Weather-####.jpg");
xPos=100;
p=createFont("Arial",16,true);
background(0); //set background black
for(int u=99;u<width;u=u+60) //loop creates vertical grid
{
stroke(100);
line(u,0,u,height-99);
}
for(int t=height-99;t>0;t=t-25) //loop creates horizontal grid
{
stroke(100);
line(99,t,width,t);
}
textFont(p,12); //set font size to 12
textAlign(LEFT);
fill(255,0,0); //red
text("Wind Speed MPH",100,height-25); //print wind speed
fill(0,255,0); //green
text("Barometric pressure mb",210,height-25);
fill(0,0,255); //blue
text("Degrees Celsius",355,height-25);
fill(255); //white
text("Wind direction N = 0 deg",460,height-25);
fill(100); //gray
textAlign(RIGHT);
text("0",110,height-87);
for (int m=160;m<width;m=m+60) //loop places 0-9 for minutes
{
int Min=(m-100)/60;
fill(100);
textAlign(CENTER);
text(Min,m,height-87);
}
fill(100);
textAlign(CENTER);
text("Minutes",width/2,height-70);
for(int p=400;p>0;p=p-50) //loop places numbers on vertical grid every other line
{
float pat=map(p,400,0,0,200);
int pati=int(pat); //changes float pat to an int
fill(255,0,0);
textAlign(RIGHT);
text(pati,98,p+5); //wind speed measurements
float patie=map(p,400,0,850,1100);
int paties=int(patie);
fill(0,255,0);
text(paties,75,p+5);//pressure measurements
float patiesTemp=map(p,400,0,-30,55);
int patiesTemp1=int (patiesTemp);
fill(0,0,255);
text(patiesTemp1,45,p+5); //temp measurements
float patiesDirec=map(p,400,0,0,359);
int patiesDirect=int(patiesDirec);
fill(255);
text(patiesDirect,25,p+5); //wind direction measurements
}
if (xPos < width) {
// increment the horizontal position:
xPos++;
}
}
}
Step 6: Running Everything Together
The wind direction says 0 the whole time because the wind vane I built did not work properly and this is why I chose not to go over the build. Every 10 min the graph is saved as jpg and can be accessed through processings sketch folder. this graph is the first storm I tested my equipment in and it shows the temp drop and the wind speed increase.