Code: Select all
/*
This MODIFIED sketch connects to a website (http://www.rtupdate.wunderground.com)
Using an Arduino Wiznet Ethernet shield To upload your weather conditions to wunderground.com,
We make a standard HTTP GET request with the ID, PASSWORD and weather conditions as GET parameters.
You must first create an account with wunderground for this to werk!
Various notes throughout attempt to explain why i did what i did to make it werk.
This sketch also incorporates an NTP RTC update code to make sure that the time is always correct and
resets the RTC Soft or Hard to UTC ZULU Wunderground wants "UTC ZULU HOUR".
Results for this can be monitored @ http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=KFLFORTM67
Binary sketch size: 28,058 bytes (of a 32,256 byte maximum)
Circuit:
* Arduino UNO adafruit
* Ethernet shield attached to pins 10, 11, 12, 13
* DHT to pin A0 adafruit
* Wind direction to pin A1(360 var resistor)
* Anemometer to Digtal 2 (INT0) (reed)
* Rain tip to Digital 3 (INT1) (hall effect)
* BMP to I2C adafruit
* RTC to I2C adafruit
**
Originaly created 18 Dec 2009
by David A. Mellis
modified 9 Apr 2012
by Tom Igoe, based on work by Adrian McEwen
**
**
Modified To upload weather conditions to wunderground.com
1,Jan 2014
By the drunkin programer
*
*/
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h> // New from IDE 1.0
#include <Wire.h>
#include "DHT.h"
#include <Adafruit_BMP085.h>
#include "RTClib.h"
//Pins
#define DHTPIN A0 // DHT 22 (AM2302)
#define vane A1
#define anemometer 2 // D2 Wind speed
#define rainTip 3 // pin D3 Rain bucket
#define led 13 // Notification of SENDING DATA
#define DHTTYPE DHT22 // DHT 22 (AM2302)
//IPAddress SERVER(38,102,137,157); // numeric IP for wunderground.com
char SERVER[] = "rtupdate.wunderground.com"; // Realtime update server
//char SERVER [] = "weatherstation.wunderground.com"; //standard server
char WEBPAGE [] = "GET /weatherstation/updateweatherstation.php?";
char ID [] = "BANNED";
char PASSWORD [] = "BANNED";
// Pick one below
// byte timeServer[] = {192, 43, 244, 18}; // time.nist.gov NTP server
byte timeServer[] = {
132, 163, 4, 101}; // ntp1.nl.net NTP server
//byte timeServer[] = {132, 163, 4, 102}; // time-b.timefreq.bldrdoc.gov NTP server
// byte timeServer[] = (132, 163, 4, 103);
const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message
byte pb[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };//Hard config my mac
//IPAddress ip(192,168,1,109);//Hard config ip
EthernetClient client;
unsigned int localPort = 8888;
const float pi = 3.14159265; // pi, not apple, not pumpkin, not pizza, not even related to Raspberry Pi. http://www.raspberrypi.org/ This is the REAL PI for RPM/Wind speed calculations
// Radius from vertical anemometer axis to a cup center (mm)
const int radio = 60;
// (changing "Wait")changes the windspeed calculation "period" automaticly
const unsigned long Wait = 1250; // Amount of Time to wait till Re-connecting, Changing this also
const unsigned long period = Wait * 2; // Measurement period (miliseconds)
const unsigned long IDLE_TIMEOUT_MS = 1000;
unsigned int counter = 0; // pulse count for wind sensor
unsigned int RPM = 0; // Revolutions per minute
unsigned int Sample = 0; // Sample number
unsigned int TIME = 10; // count down from 10 and reat the rtc
unsigned int connections = 0; // number of connections
unsigned int winddir = 0.0; // Wind direction
unsigned int rainin = 0; // counter for Rain
unsigned int rainSample = 0; // counter for Rain Samples
float windspeedmph = 0/ 0.445; // Wind speed (m/s)
float windgustmph = 0; // Max wind speed
//---DEWPOINT CALC!-------------------------------
double dewPoint(double tempf, double humidity)
{
double A0= 373.15/(273.15 + tempf);
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);
}
//---DEWPOINT CALC!-------------------------------
EthernetUDP Udp; // UDP for the time server
DHT dht(DHTPIN, DHTTYPE); // DHT 22 (AM2302)
Adafruit_BMP085 bmp; // BMP Sensor
RTC_DS1307 rtc; // Hardware RTC time
//RTC_Millis rtc; // Software RTC time
void setup(void)
{
attachInterrupt(1, addrain, RISING); // attachInterrupt 1 sp that it can count the rain constantly
// (it does'nt tip that often and we dont need to calcualate).
Serial.begin(38400);
Wire.begin(); //Rtc
rtc.begin(); //uncomment to use hardware rtc
//uncomment below to reset the time !
//rtc.adjust(DateTime(__DATE__, __TIME__));// leave uncommented if using software rtc
bmp.begin();
dht.begin();
pinMode(anemometer, INPUT); //Anemometer input(spins like made when the wind blows).
digitalWrite(anemometer, HIGH); // set this high so when it detects a change it records it via INT(0)
pinMode(rainTip, INPUT);// rain tip input
digitalWrite(rainTip, HIGH); // set this high so when it detects a change it records it via INT(1)
Serial.println(F("NTP2RTC / Ethernet shield to Wunderground Test!\n"));
Serial.print(F("\nInitializing..."));
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
//Ethernet.begin(mac, ip);
// Serial.println(ip);
}
Serial.print("Local I.P: ");
Serial.println(Ethernet.localIP());
Serial.println("Ready!");
Serial.println("End of the Setup Function");
}
void loop(void)
{
// Lets see what time the RTC is set at!
DateTime now = rtc.now();
Serial.println("+++++++++++++++++++++++++");
Serial.println("RTC current TIME ");
if(now.hour() < 10){ // Zero padding if value less than 10 ie."09" instead of "9"
Serial.print(" ");
Serial.print((now.hour() > 12) ? now.hour() - 12 : ((now.hour() == 0) ? 12 : now.hour()), DEC); // Conversion to AM/PM
}
else{
Serial.print((now.hour() > 12) ? now.hour() - 12 : ((now.hour() == 0) ? 12 : now.hour()), DEC); // Conversion to AM/PM
}
Serial.print(':');
if (now.minute() <= 10){
Serial.print("0");
}
Serial.print(now.minute());
Serial.print(':');
if (now.second() <= 10){
Serial.print("0");
}
Serial.println(now.second());
//Clear the rainin, windgustmph and rainSample every 10 loops.
//if you let the results runn they will add up on wunderground and report constant additions to wing gust and rain fall
//But you must report the readings for a rew posts for wunderground to realize it is a real reading and not a false one
if (rainSample >=10){
rainin = 0;//Clear the rainCount
rainSample = 0;// Clear the rain samples
windgustmph = 0; //clear Max wind speed
}
Sample ++; // add "loop's
TIME--; // Subtract Count doun from 10 to reset the RTC
rainSample++; // add and when limmit reached clear the results
windvelocity();
RPMcalc();
WindSpeed();
Heading();
float tempf = dht.readTemperature();
float humidity = dht.readHumidity();
float baromin = bmp.readPressure()* 0.0002953;// Calc for converting Pa to inHg (wunderground)
float dewptf = (dewPoint(dht.readTemperature(), dht.readHumidity())); //Dew point calc(wunderground)
// max wind speed holder(wunderground)
if (windspeedmph > windgustmph) {
windgustmph = windspeedmph;
}
Serial.print("Posting Sample # ");// tells us how many loops
Serial.println(Sample);
Serial.print("Posts till clock Reset ");// tells us when the clock will try a reset might fail every now and then but werks!
Serial.println(TIME);
Serial.println();
Serial.println("-------------------------------------");
/*
// Debug, or you can sit up all night watching it.
Serial.print("wind dir= ");
Serial.print(winddir);
Serial.println(" deg's");
Serial.print("windspeed mph= ");
Serial.println(windspeedmph);
Serial.print("wind gust mph= ");
Serial.println(windgustmph);
Serial.print("temp= ");
Serial.print(tempf);
Serial.println(" *F");
Serial.print("rain in= ");
Serial.println(rainin / 2.0 / 100.0);
Serial.print("baro= ");
Serial.print(baromin);
Serial.println(" inHg");
Serial.print("dew point= ");
Serial.println(dewptf);
Serial.print("humidity= ");
Serial.println(humidity);
Serial.println();
Serial.print("Waiting ");
Serial.print(Wait*2/1000.0);
Serial.println(" seconds.");*/
if (TIME <= 1) {// Hey, if the TIME reached 1 then contact the NTP site and try to set the RTC to UTC ZULU
TIME = 10; // Make the countdown start from 10 again
Udp.begin(localPort);// Call from this line.......PLEASE
Serial.println("UpDating CLOCK");
Serial.print("RTC before: ");
PrintDateTime(rtc.now());// Show me the time
Serial.println();
int packetSize = Udp.parsePacket(); //<<<<<<<<<<<<NEW LINE HERE
// send an NTP packet to a time server
sendNTPpacket(timeServer);// Ask the bum for the time... and say please!
// wait to see if a reply is available
delay(1000);
if ( Udp.available() ) {
// read the packet into the buffer
Udp.read(pb, packetSize); // New from IDE 1.0 <<<<<<<<<<<<<MODIFIED LINE
unsigned long t1, t2, t3, t4;
t1 = t2 = t3 = t4 = 0;
for (int i=0; i< 4; i++)
{
t1 = t1 << 8 | pb[16+i];
t2 = t2 << 8 | pb[24+i];
t3 = t3 << 8 | pb[32+i];
t4 = t4 << 8 | pb[40+i];
}
float f1,f2,f3,f4;
f1 = ((long)pb[20] * 256 + pb[21]) / 65536.0;
f2 = ((long)pb[28] * 256 + pb[29]) / 65536.0;
f3 = ((long)pb[36] * 256 + pb[37]) / 65536.0;
f4 = ((long)pb[44] * 256 + pb[45]) / 65536.0;
const unsigned long seventyYears = 2208988800UL;
t1 -= seventyYears;
t2 -= seventyYears;
t3 -= seventyYears;
t4 -= seventyYears;
PrintDateTime(DateTime(t4));
Serial.println(f4,4);
Serial.println();
//WUNDERGROUND COMMENTS
//Adjust your timezone ... in my case I substract 5 hours for West Florida Time
//**** YOU MUST Add "X" hours (in my case + 5) to the client.print(now.hour() + 5); ****
// to get back to UTC ZULU, or Wunderground wont show RAPID FIRE or display incorrect times for you observations
//WUNDERGROUND COMMENTS
t4 -= (5 * 3600L); // Notice the L for long calculations!!
t4 += 1; // adjust the delay(1000) at begin of loop!
if (f4 > 0.4) t4++; // adjust fractional part, see above
rtc.adjust(DateTime(t4));
Serial.print("RTC after : ");
PrintDateTime(rtc.now());
Serial.println();
Serial.println("done ...");
// endless loop
//while(1);
}
else
{
Serial.println("No UDP available ...");
Serial.println("ARRRRRRRRRRRRrrr !!!");// wait 10 more loop's.
}
}
Serial.println("+++++++++++++++++++++++++");
Serial.println();
if (client.connect(SERVER, 80)) { // Money Shot!
Serial.println("Sending DATA ");
client.print(WEBPAGE);
client.print("ID=");
client.print(ID);
client.print("&PASSWORD=");
client.print(PASSWORD);
client.print("&dateutc=");
client.print(now.year());
client.print("-");
client.print(now.month());
client.print("-");
client.print(now.day());
client.print("+");
client.print(now.hour()+5);// YOU MUST Add 5 hours to get back to UTC or Wunderground wont show RAPID FIRE
client.print("%3A");
client.print(now.minute());
client.print("%3A");
client.print(now.second());
client.print("&winddir=");
client.print(winddir);
client.print("&windspeedmph=");
client.print(windspeedmph);
client.print("&windgustmph=");
client.print(windgustmph);
client.print("&tempf=");
client.print(tempf);
client.print("&rainin=");
client.print(rainin / 2.0 / 100.0);
client.print("&baromin=");
client.print(baromin);
client.print("&dewptf=");
client.print(dewptf);
client.print("&humidity=");
client.print(humidity);
//client.print("&action=updateraw");//Standard update
client.print("&softwaretype=Arduino%20UNO%20version1&action=updateraw&realtime=1&rtfreq=2.5");//Rapid Fire
client.println();
Serial.println("Upload complete");
}
else {
Serial.println(F("Connection failed"));
return;
}
Serial.println("-------------------------------------");
Serial.println("Server Response!");
unsigned long lastRead = millis();
while (client.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {
while (client.available()) {
char c = client.read();
Serial.print(c);
lastRead = millis();
}
}
client.stop();// Wipe it off and get ready to do it again
delay(Wait);// 30sec +/-
Serial.println();
Serial.println("-------------------------------------");
}// end loop
//MISC--------------------------------------------------
void windvelocity(){
windspeedmph = 0;
counter = 0;
attachInterrupt(0, addcount, RISING);//anemometer
//attachInterrupt(1, addrain, RISING); // Read the Rain tips Hall Effect
unsigned long millis();
long startTime = millis();
while(millis() < startTime + period) {
}
detachInterrupt(0);
//detachInterrupt(1);
}
void RPMcalc(){
RPM=((counter*4)*60)/(period/1000); // Calculate revolutions per minute (RPM)
}
void WindSpeed(){
windspeedmph = ((2 * pi * radio * RPM)/60) / 1000;
}
void addcount(){
counter++;
}
void addrain(){
rainin++;
}
void Heading(){
float windDir =(analogRead(vane)* 5.00 / 1023.0); // Wind direction
if ((windDir > 4.94)||(windDir < 0.01))
(winddir = 0.0);// North
if ((windDir >= 0.02)&&(windDir < 0.30))
(winddir = 22.5);//NNE
if ((windDir >= 0.31)&&(windDir < 0.72))
(winddir = 45.0);//NE
if ((windDir >= 0.72)&&(windDir < 0.99))
(winddir= 67.5);//ENE
if ((windDir >= 1.00)&&(windDir < 1.25))
(winddir = 90.0);//E
if ((windDir >= 1.26)&&(windDir < 1.52))
(winddir= 112.5);//ESE
if ((windDir >= 1.53)&&(windDir < 1.91))
(winddir= 135.0);//SE
if ((windDir >= 1.92)&&(windDir < 2.40))
(winddir = 157.5);//SSE
if ((windDir >= 2.41)&&(windDir < 2.73))
(winddir = 180.0);//S
if ((windDir >= 2.74)&&(windDir < 2.96))
(winddir = 202.5);//SSW
if ((windDir >= 2.97)&&(windDir < 3.37))
(winddir = 225.0);//SW
if ((windDir >= 3.38)&&(windDir < 3.55))
(winddir = 247.5);//WSW
if ((windDir >= 3.56)&&(windDir < 3.85))
(winddir = 270.0);//W
if ((windDir >= 4.13)&&(windDir < 4.06))
(winddir = 292.5);//WNW
if ((windDir >= 4.07)&&(windDir < 4.32))
(winddir = 315.0);//NW
if ((windDir >= 4.33)&&(windDir < 4.93))
(winddir = 337.5);//NNW
}
///////////////////////////////////////////
//
// MISC
//
void PrintDateTime(DateTime t)
{
char datestr[24];
sprintf(datestr, "%04d-%02d-%02d %02d:%02d:%02d ", t.year(), t.month(), t.day(), t.hour(), t.minute(), t.second());
Serial.print(datestr);
}
// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(byte *address)
{
// set all bytes in the buffer to 0
memset(pb, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
pb[0] = 0b11100011; // LI, Version, Mode
pb[1] = 0; // Stratum, or type of clock
pb[2] = 6; // Polling Interval
pb[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
pb[12] = 49;
pb[13] = 0x4E;
pb[14] = 49;
pb[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
#if ARDUINO >= 100
// IDE 1.0 compatible:
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(pb,NTP_PACKET_SIZE);
Udp.endPacket();
#else
Udp.sendPacket( pb,NTP_PACKET_SIZE, address, 123); //NTP requests are to port 123
#endif
}
///////////////////////////////////////////
//
// End of program
//