My Arduino-based Vantage Pro Plus

By: xe1gox , 2:41 AM GMT on February 14, 2017

My PWS reporting as IZAPOPAN15 is a refurbished Davis Vantage Pro Plus + 24HR FARS working under Arduino + WizNet Ethernet shield. Original Davis ISS board was damaged and the console missing, that's why I decided to run an Arduino as the new ISS board plus direct network connection capability for a very low price.

Here a picture of the Arduino ISS box during a code update:



For the code, I heavily modified the one found here: Link as well as other sites in order to adapt it to the current sensor suite available and my own needs. Thanks to Davis sensors documentation I was able to make them work and adjust their output values. For calibration I relied on the data reported from other 3 Davis VP2+ stations installed in the city. Data seems consistent since last calibration.

The station code is updated regularly to debug some issues or improve the Arduino performance.
Here's the actual running code:

#include "TimerOne.h"
#include "math.h"
#include "DHT.h"
#include "SPI.h"
#include "Ethernet.h" //Ethernet
#include "EthernetUdp.h" //Ethernet

#define DHTPIN 5 // what digital pin we're connected to
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321

//#define Bucket_Size 0.282 // bucket size to trigger tip count (mm)
#define Bucket_Size 0.011 // bucket size to trigger tip count (in)
#define Rainmeter_Pin 3 // digital pin of the rainmeter reed switch

#define WindSensor_Pin (2) // digital pin for wind speed sensor
#define WindVane_Pin (A3) // analog pin for wind direction sensor
#define VaneOffset 0 // define the offset for caclulating wind direction

#define radSensor_Pin A1 //analog pin UV sensor is connected to
#define uvSensor_Pin A2 //analog pin solar irradiance sensor is connected to


int DEBUG = 0; // DEBUG flag; if set to 1, will write values back via serial
int eth = 0; // Ethernet connectivity flag

// assign a MAC address for the ethernet controller here:
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
// assign an IP address for the controller:
//IPAddress ip(192, 168, 2, 100);
//IPAddress gateway(192, 168, 2, 1);
//IPAddress subnet(255, 255, 255, 0);
EthernetClient client;
unsigned int localPort = 8888;

char SERVER[] = "rtupdate.wunderground.com"; // Realtime update server - RapidFire
//char SERVER [] = "weatherstation.wunderground.com"; // Standard update server
char WEBPAGE [] = "GET /weatherstation/updateweatherstation.php?";
char ID [] = "IZAPOPAN15";
char PASSWORD [] = "XXXXXXX";
char c[10];

unsigned int connections = 0; // number of connections
unsigned int timeout = 30000; // Milliseconds -- 1000 = 1 Second

volatile unsigned long tipCount; // rain bucket tip counter used in interrupt routine
volatile unsigned long contactTime; // timer to manage any rain contact bounce in interrupt routine

volatile bool isSampleRequired; // this is set every 2.5sec to generate wind speed
volatile unsigned int timerCount; // used to count ticks for 2.5sec timer count
volatile unsigned int timerMinCount; // used to determine 1-minute count
volatile unsigned long rotations; // cup rotation counter for wind speed calcs
volatile unsigned long contactBounceTime; // timer to avoid contact bounce in wind speed sensor

float currentRainfall; // rain inches over the past hour -- the accumulated rainfall in the past 60 min
float totalRainfall; // rain inches so far today in local time
long lastTipcount; // keep track of bucket tips

volatile unsigned long uvValue;
volatile unsigned long solarValue;
int solarRad; //Solar radiation in w/m2
float uvIndex; // UV index varies from 0 - 16

float baromin; // barometric pressure in inHg

volatile float windSpeed;
volatile float lastWindGust;
volatile float windGust;
int vaneValue; // raw analog value from wind vane
int vaneDirection; // translated 0 - 360 wind direction
int calDirection; // calibrated direction after offset applied
int lastDirValue; // last recorded direction value

const int numReadings = 5; // array size
int readings[numReadings]; // the readings from the windvane
int readIndex = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average wind direction

unsigned int windGustTimer;
unsigned int currentRFtimer;
unsigned long totalRFtimer;



// Create DHT sensor object
DHT dht (DHTPIN, DHTTYPE);

void setup() {

if (Ethernet.begin(mac) ) { // Turn the internet ON
eth = 1;
}

Serial.begin(9600);

if (DEBUG) {

Serial.println("Davis Vantage Pro Plus Weather Station");
Serial.println("++ Debugging Console ++");
Serial.println(F("\nInitializing......\t"));

if (eth) {

Serial.println("Ethernet Initialization: COMPLETE\t");
Serial.println("Assigned IP address: "); Serial.print(Ethernet.localIP());
Serial.println("\t");
}
else {
Serial.println("Something went wrong during Ethernet startup! :( \t");
}
}

baromin = 25.086; //temporary fixed value

// initialize all the rain sensor readings to 0
lastTipcount = 0;
tipCount = 0;
currentRainfall = 0;
totalRainfall = 0;
currentRFtimer = 0;
totalRFtimer = 0;

// initialize all the anemometer readings to 0
lastDirValue = 0;
rotations = 0;
windGust = 0;
lastWindGust = 0;
windGustTimer = 0;
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}

// initialize all the timer values to 0
timerCount = 0;
timerMinCount = 0;


// initialize all the solar values to 0
solarValue = 0;
solarRad = 0;
uvValue = 0;
uvIndex = 0;

// DHT sensor initialization
dht.begin();
delay(2000); // allow 2 seconds for sensor module to settle down

pinMode(Rainmeter_Pin, INPUT);
pinMode(WindSensor_Pin, INPUT);
attachInterrupt(digitalPinToInterrupt(Rainmeter_Pi n), isr_rg, FALLING);
attachInterrupt(digitalPinToInterrupt(WindSensor_P in), isr_rotation, FALLING);
pinMode(uvSensor_Pin, INPUT);
pinMode(radSensor_Pin, INPUT);

// setup the timer for 0.5 second
Timer1.initialize(500000);
Timer1.attachInterrupt(isr_timer);
sei();// Enable Interrupts
}

void loop() {

//get the sensor data
float h = dht.readHumidity();
float t = dht.readTemperature();
float tempf = (t * 9.0) / 5.0 + 32.0; //was dht.readTemperature, need to convert native C to F
float dewptf = (dewPoint(t, dht.readHumidity())); //Dew point calc(wunderground) //replaced dht.readtemp with converted temp

uvValue = analogRead(uvSensor_Pin);
uvIndex = (uvValue / 1024.0) * 70.5; //calibrado en 70.5 01-02-17
uvIndex = constrain(uvIndex, 0, 16);
if (uvIndex < 0.97) {
uvIndex = 0;
}

solarValue = analogRead(radSensor_Pin);
solarRad = map(solarValue, 0, 1023, 0, 2788); //calibrado en 2788 01-02-17
solarRad = constrain(solarRad, 0, 1800);
if (solarRad < 14) {
solarRad = 0;
}


// update total rainfall if required
if (tipCount != lastTipcount) {
cli(); // disable interrupts
lastTipcount = tipCount;
totalRainfall = tipCount * Bucket_Size;
currentRainfall = totalRainfall;
sei(); // enable interrupts
}


if (timerMinCount > 1) { // if 5 seconds timer is up then send data

timerMinCount = 0; //reset the timer
getWindDirection();
currentRFtimer++;
totalRFtimer++;
windGustTimer++;

if (DEBUG) { //Start of debug data loop

Serial.println("---------------------------------- ------------");
Serial.print("T: "); Serial.print(t); Serial.print(char(176)); Serial.print("C");
Serial.print(" | "); Serial.print(tempf); Serial.print(char(176)); Serial.print("F\t");
Serial.print("DP: "); Serial.print(dewptf); Serial.print(char(176)); Serial.print("F\t");
Serial.print("H: "); Serial.print(h); Serial.print("%\t");
Serial.print("P: "); Serial.print(baromin); Serial.print("inHg\t");
Serial.print("R: "); Serial.print(currentRainfall); Serial.print(" mm\t");
Serial.print("S: "); Serial.print(windSpeed); Serial.print(" mph\t");
Serial.print("D: "); Serial.print(calDirection); Serial.print(char(176)); Serial.print("\t");
Serial.print("R: "); Serial.print(solarRad); Serial.print(" W/m^2\t");
Serial.print("UV: "); Serial.print(uvIndex); Serial.print("\t");
Serial.println(" ");
} //End debug data loop

//Send data to Weather Underground
if (client.connect(SERVER, 80)) {
if (DEBUG) {
Serial.println("Sending data... ");
}
//Wrap the data for Wunderground
client.print(WEBPAGE);
client.print("ID=");
client.print(ID);
client.print("&PASSWORD=");
client.print(PASSWORD);
client.print("&dateutc=");
client.print("now"); //can use instead of RTC if sending in real time
client.print("&winddir=");
client.print(calDirection);
client.print("&windspeedmph=");
client.print(windSpeed);
if (lastWindGust != 0) {
client.print("&windgustmph=");
client.print(lastWindGust);
}
client.print("&tempf=");
client.print(tempf);
if (currentRainfall != 0) {
client.print("&rainin=");
client.print(currentRainfall);
}
client.print("&dailyrainin=");
client.print(totalRainfall);
client.print("&baromin=");
client.print(baromin);
client.print("&dewptf=");
client.print(dewptf);
client.print("&humidity=");
client.print(h);
client.print("&solarradiation=");
client.print(solarRad);
client.print("&UV=");
client.print(uvIndex);
//client.print("&action=updateraw"); //Standard update
client.print("&softwaretype=Arduino%20UNO%20R3&act ion=updateraw&realtime=1&rtfreq=5"); //Rapid Fire update
client.println();
if (client.available()) {
char c = client.read();
}
client.stop();
client.flush();

if (DEBUG) {
Serial.println("Upload COMPLETE\t");
Serial.println("Server response: "); Serial.print(c);
}

}
else {
if (DEBUG) {
Serial.println(F("Connection FAILED\t"));
Serial.println("Server response: "); Serial.print(c);
}
return;
}

if (currentRFtimer >= 732) { //timer to clear the current rainfall to 0mm every hour
currentRainfall = 0;
currentRFtimer = 0;
Ethernet.maintain();
}

if (totalRFtimer >= 17568) { //timer to clear the daily rain count at 00:00
totalRainfall = 0;
totalRFtimer = 0;
}

if (windGustTimer >= 61) { //timer to reset wind gusts to 0 every 5 minutes
windGust = 0;
lastWindGust = 0;
windGustTimer = 0;
}
}
}

// Interrupt handler routine for timer interrupt
void isr_timer() {

timerCount++;

if (timerCount == 5) {
// convert to mph using the formula V=P(2.25/T)
// V = P(2.25/2.5) = P * 0.9
windSpeed = (rotations * 0.9);
rotations = 0;
timerCount = 0;
timerMinCount++; // increment count
if (windSpeed > 9.0 ) {
windGust = windSpeed;
if (windGust >= lastWindGust) {
lastWindGust = windGust;
}
}
}
}


// Interrupt handler routine to increment the rotation count for wind speed
void isr_rotation() {

if ((millis() - contactBounceTime) > 15 ) { // debounce the switch contact
rotations++;
contactBounceTime = millis();
}
}

// Interrupt handler routine that is triggered when the tipping buckets detects rain
void isr_rg() {

if ((millis() - contactTime) > 15 ) { // debounce of sensor signal
tipCount++;
contactTime = millis();
}
}

// Get Wind Direction
void getWindDirection() {

vaneValue = analogRead(WindVane_Pin);
vaneDirection = map(vaneValue, 0, 1023, 0, 360);
calDirection = vaneDirection + VaneOffset;

if (calDirection > 360)
calDirection = calDirection - 360;

if (calDirection > 360)
calDirection = calDirection - 360;

total = total - readings[readIndex]; // subtract the last reading
readings[readIndex] = calDirection; // read current direction
total = total + readings[readIndex]; // add the reading to the total
readIndex = readIndex + 1; // advance to the next position in the array
if (readIndex >= numReadings) { // if we're at the end of the array...
readIndex = 0; // ...wrap around to the beginning
}
average = total / numReadings; // calculate the average
calDirection = average;

}

// Calculate Dew Point
double dewPoint(double t, double humidity) {

double A0 = 373.15 / (273.15 + t);
double SUM = -7.90298 * (A0 - 1);
SUM += 5.02808 * log10(A0);
SUM += -1.3816e-7 * (pow(10, (11.344 * (1 - 1 / A0))) - 1) ;
SUM += 8.1328e-3 * (pow(10, (-3.49149 * (A0 - 1))) - 1) ;
SUM += log10(1013.246);
double VP = pow(10, SUM - 3) * humidity;
double T = log(VP / 0.61078);
return (((241.88 * T) / (17.558 - T)) * 1.8) + 32;

}

//ANOTHER DEW POINT FUNCTION
// delta max = 0.6544 wrt dewPoint()
// 6.9 x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
//double dewPoint(double t, double humidity) {
//double a = 17.271;
//double b = 237.7;
//double temp = (a * t) / (b + t) + log(humidity*0.01);
//double Td = (((b * temp) / (a - temp)) * 1.8) + 32;
//return Td;
//}



The views of the author are his/her own and do not necessarily represent the position of The Weather Company or its parent, IBM.

Reader Comments

No reader comments have been posted for this blog entry yet.

xe1gox doesn't have a bio yet.