/* * Personnal Weather Station sketch for Weater Underground with a ESP8266 * BLANCHARD Jordan - http://www.chynehome.com */ #include #include #include #include #include #include #include "DHT.h" #define DHTPIN 2 #define DHTTYPE DHT22 Adafruit_BMP085 bmp; DHT dht(DHTPIN, DHTTYPE); ESP8266WiFiMulti wifiMulti; extern "C" { #include "user_interface.h" } //---------------------Setup Wifi------------------ const char* ssid1 = "SSID_1"; //I use multiple SSID In my home, but you can only define one. const char* password1 = "PASS_1"; const char* ssid2 = "SSID_2"; const char* password2 = "PASS_2"; const char* ssid3 = "SSID_3"; const char* password3 = "PASS_3"; const char* ssid4 = "SSID_4"; const char* password4 = "PASS_4"; const char* ssid5 = "SSID_5"; const char* password5 = "PASS_5"; //---------------------WU PSW ID------------------- const char* WUID = "WU_PSW_ID"; const char* WUPASS = "PASSWORD_WU"; int altitudepws = 125; //LOCAL Alitude of the PWS to get relative pressure //---------------------NTP VAR--------------------- unsigned int localPort = 2390; IPAddress timeServerIP; const char* ntpServerName = "time.nist.gov"; const int NTP_PACKET_SIZE = 48; byte packetBuffer[ NTP_PACKET_SIZE]; WiFiUDP udp; unsigned long epoch; //---------------------WEATHER VAR----------------- float windspeed_eu; float windgust_eu; float winddir_eu; float tempout_eu; float dewpout_eu; float humidity_eu; float baro_eu; float rain1h_eu; float rain24h_eu; //US String windspeed; String windgust; String winddir; String tempout; String dewpout; String humidity; String baro; String rain1h; String rain24h; int radio = 60; // Radio from vertical anemometer axis to a cup center (mm) //---------------------PIN GPIO MAP---------------- int rainils = 0; //Rain REED-ILS sensor int windils = 9; //WIND REED-ILS sensor int windir1 = 12; //Wind Direction IR sensor 1 int windir2 = 13; //Wind Direction IR sensor 2 int windir3 = 14; //Wind Direction IR sensor 3 int windir4 = 10; //Wind Direction IR sensor 4 int tempwind = A0; //Optional temp sensor, will be not used finaly //---------------------PROG VAR-------------------- const char* host = "weatherstation.wunderground.com"; unsigned long count5sec; unsigned long count60sec; unsigned long count1h; unsigned int pulseswind; unsigned int pulsesgust; float tempwindgust; bool debug = 0; //debug = 1 -> enable debug float raincount = 0; float raincount1h = 0; const float pi = 3.14159265; // pi number float calcgustspeed; float calcwindspeed; float winddir_sum = 0.00f; float winddir_count = 0.00f; unsigned long rain_last=0; unsigned long wind_last=0; int addr=0; void setup(){ pinMode(rainils, INPUT); pinMode(windils, INPUT); pinMode(windir1, INPUT); pinMode(windir2, INPUT); pinMode(windir3, INPUT); pinMode(windir4, INPUT); //wifi_set_sleep_type(NONE_SLEEP_T); //wifi_set_sleep_type(MODEM_SLEEP_T); wifi_set_sleep_type(LIGHT_SLEEP_T); Serial.begin(115200); Serial.print("Start Weather Station "); Serial.println(WUID); attachInterrupt(windils, rpm, FALLING); attachInterrupt(rainils, rain, FALLING ); startwifi(); if (!bmp.begin()) { Serial.println("Could not find a valid BMP085 sensor, check wiring!"); baro_eu = 1013.00f; } dht.begin(); count5sec = millis(); count60sec = millis(); //-----------Just For restore fist daily rain EEPROM.begin(64); addr=0; addr += EEPROM.get(addr, raincount); if ((raincount >= 10000) || (raincount < 0) ) { Serial.println("Wrong daily rain value in eeprom - reset value"); raincount=0; addr=0; addr += EEPROM.put(addr, raincount); //EEPROM.commit(); //i don't know why commit to eeprom reset the esp8266; I need to check... delay (1000); } Serial.print("Rain value in eeprom: "); Serial.println(raincount); //start interupt sei(); pulseswind = 0; pulsesgust = 0; } void loop(){ if ( (millis() - count5sec) >= 5000) { //Call speedgust() to store actual wind gust Serial.print("Take gust values each 5sec: "); Serial.println(speedgust()); //Add actual wind direction to average after 60sec winddir_sum = winddir_sum + DirWind(); winddir_count = winddir_count + 1.00f; count5sec = millis(); if (debug) { winddir_eu = winddir_sum / winddir_count; Serial.print("Take wind dir each 5sec: "); Serial.println(winddir_eu); } } if ( (millis() - count60sec) >= 60000) { ntptime(); Serial.println(""); Serial.println("Actual Local Time:"); Serial.print("Hour: "); Serial.println(localhour()); Serial.print("Min: "); Serial.println(localmin()); Serial.print("Sec: "); Serial.println(localsec()); Serial.println(""); Serial.println("Store and convert all sensor value fo WU each 60sec"); //reset Daily Rain each 24h if ((localhour() >= 23) && (localmin() >= 55)) { Serial.println("Reset Daily Rain"); raincount = 0; rain24h_eu = 0.00; //Store Daily rain in case of power failure addr=0; addr += EEPROM.put(addr, raincount); //EEPROM.commit(); //END Store Daily rain in case of power failure } //get all value of sensor winddir_eu = winddir_sum / winddir_count; winddir_sum = 0.00f; winddir_count = 0.00f; tempout_eu = Temp(); windspeed_eu = speedwind(); //wind gust for 60sec windgust_eu = tempwindgust; tempwindgust = 0; baro_eu = (bmp.readSealevelPressure(altitudepws)/100.00f); humidity_eu = dht.readHumidity(); dewpout_eu = tempout_eu - ((100.00f - humidity_eu)/5.00f); rain1h_eu = 0.30f * raincount1h; rain24h_eu = 0.30f * raincount; Serial.println(" "); Serial.println("EU to US conversion for WU "); Serial.println(" "); Serial.println("EU: "); Serial.print("Temp: "); Serial.println(tempout_eu); Serial.print("Dew Point: "); Serial.println(dewpout_eu); Serial.print("Humidity: "); Serial.println(humidity_eu); Serial.print("Pressure: "); Serial.println(baro_eu); Serial.print("Wind Speed: "); Serial.println(windspeed_eu); Serial.print("Wind Gust: "); Serial.println(windgust_eu); Serial.print("Wind Direction: "); Serial.println(winddir_eu); Serial.print("Rain 1h: "); Serial.println(rain1h_eu); Serial.print("Rain 24h: "); Serial.println(rain24h_eu); //make conversion to US for Wunderground windspeed = windspeed_eu * 0.62138f; windgust = windgust_eu * 0.62138f; winddir = winddir_eu; tempout = (( tempout_eu * 1.8 ) + 32); dewpout = (( dewpout_eu * 1.8 ) + 32); humidity = humidity_eu; baro = 0.02952998751 * baro_eu; rain1h = rain1h_eu / 25.40 ; rain24h = rain24h_eu / 25.40 ; Serial.println(" "); Serial.println("US: "); Serial.print("Temp: "); Serial.println(tempout); Serial.print("Dew Point: "); Serial.println(dewpout); Serial.print("Humidity: "); Serial.println(humidity); Serial.print("Pressure: "); Serial.println(baro); Serial.print("Wind Speed: "); Serial.println(windspeed); Serial.print("Wind Gust: "); Serial.println(windgust); Serial.print("Wind Direction: "); Serial.println(winddir); Serial.print("Rain 1h: "); Serial.println(rain1h); Serial.print("Rain 24h: "); Serial.println(rain24h); Serial.println(" "); Serial.println("Send Data to WU each 60sec"); senddata(); count60sec = millis(); //ESP.restart(); } if ( ((millis() - count1h) >= (60000*60*1)) && (raincount1h != 0)) { Serial.println("Reset hourly rain each hour"); raincount1h = 0; rain1h_eu = 0.00; } if ( millis() >= (60000*60*24)) { Serial.println("task each 24 hour"); //ESP.restart(); } } //---------------------------------------------------------WIFI SETUP---------------------------------------------- void startwifi() { Serial.print("Connecting to Wifi"); wifiMulti.addAP(ssid1, password1); //if you have less SSID, delete the others wifiMulti.addAP(ssid2, password2); wifiMulti.addAP(ssid3, password3); wifiMulti.addAP(ssid4, password4); wifiMulti.addAP(ssid5, password5); while (wifiMulti.run() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); startudp(); } //---------------------------------------------------------SEND TO WU---------------------------------------------- void senddata() { Serial.println("Send to WU Sensor Values"); Serial.print("connecting to "); Serial.println(host); // Use WiFiClient class to create TCP connections WiFiClient client; const int httpPort = 80; if (!client.connect(host, httpPort)) { Serial.println("connection failed"); startwifi(); return; } // We now create a URI for the request String url = "/weatherstation/updateweatherstation.php?ID="; url += WUID; url += "&PASSWORD="; url += WUPASS; url += "&dateutc=now&winddir="; url += winddir; url += "&windspeedmph="; url += windspeed; url += "&windgustmph="; url += windgust; url += "&tempf="; url += tempout; url += "&dewptf="; url += dewpout; url += "&humidity="; url += humidity; url += "&baromin="; url += baro; url += "&rainin="; url += rain1h; url += "&dailyrainin="; url += rain24h; url += "&weather=&clouds=&softwaretype=Arduino-ESP8266&action=updateraw"; Serial.print("Requesting URL: "); Serial.println(url); // This will send the request to the server client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); delay(10); // Read all the lines of the reply from server and print them to Serial while(client.available()){ String line = client.readStringUntil('\r'); Serial.print(line); } Serial.println(); Serial.println("closing connection"); //wifi_set_sleep_type(NONE_SLEEP_T); //wifi_set_sleep_type(MODEM_SLEEP_T); wifi_set_sleep_type(LIGHT_SLEEP_T); } //------------------------------------------------------Wind Direction-------------------------------------------------------------- float DirWind(){ int winddirstate1 = digitalRead(windir1); int winddirstate2 = digitalRead(windir2); int winddirstate3 = digitalRead(windir3); int winddirstate4 = digitalRead(windir4); if ( (winddirstate1 == HIGH) && (winddirstate2 == HIGH) && (winddirstate3 == HIGH) && (winddirstate4 == LOW) ) { winddir_eu = 315; } if ( (winddirstate1 == HIGH) && (winddirstate2 == HIGH) && (winddirstate3 == HIGH) && (winddirstate4 == HIGH) ) { winddir_eu = 337.5; } if ( (winddirstate1 == HIGH) && (winddirstate2 == LOW) && (winddirstate3 == HIGH) && (winddirstate4 == HIGH) ) { winddir_eu = 0; } if ( (winddirstate1 == HIGH) && (winddirstate2 == LOW) && (winddirstate3 == LOW) && (winddirstate4 == HIGH) ) { winddir_eu = 22.5; } if ( (winddirstate1 == HIGH) && (winddirstate2 == HIGH) && (winddirstate3 == LOW) && (winddirstate4 == HIGH) ) { winddir_eu = 45; } if ( (winddirstate1 == LOW) && (winddirstate2 == HIGH) && (winddirstate3 == LOW) && (winddirstate4 == HIGH) ) { winddir_eu = 67.5; } if ( (winddirstate1 == LOW) && (winddirstate2 == LOW) && (winddirstate3 == LOW) && (winddirstate4 == HIGH) ) { winddir_eu = 90; } if ( (winddirstate1 == LOW) && (winddirstate2 == LOW) && (winddirstate3 == HIGH) && (winddirstate4 == HIGH) ) { winddir_eu = 112.5; } if ( (winddirstate1 == LOW) && (winddirstate2 == HIGH) && (winddirstate3 == HIGH) && (winddirstate4 == HIGH) ) { winddir_eu = 135; } if ( (winddirstate1 == LOW) && (winddirstate2 == HIGH) && (winddirstate3 == HIGH) && (winddirstate4 == LOW) ) { winddir_eu = 157.5; } if ( (winddirstate1 == LOW) && (winddirstate2 == LOW) && (winddirstate3 == HIGH) && (winddirstate4 == LOW) ) { winddir_eu = 180; } if ( (winddirstate1 == LOW) && (winddirstate2 == LOW) && (winddirstate3 == LOW) && (winddirstate4 == LOW) ) { winddir_eu = 202.5; } if ( (winddirstate1 == LOW) && (winddirstate2 == HIGH) && (winddirstate3 == LOW) && (winddirstate4 == LOW) ) { winddir_eu = 225; } if ( (winddirstate1 == HIGH) && (winddirstate2 == HIGH) && (winddirstate3 == LOW) && (winddirstate4 == LOW) ) { winddir_eu = 247.5; } if ( (winddirstate1 == HIGH) && (winddirstate2 == LOW) && (winddirstate3 == LOW) && (winddirstate4 == LOW) ) { winddir_eu = 270; } if ( (winddirstate1 == HIGH) && (winddirstate2 == LOW) && (winddirstate3 == HIGH) && (winddirstate4 == LOW) ) { winddir_eu = 292.5; } if (debug) { Serial.print("Wind Dir: "); Serial.print(winddir_eu); Serial.print(" Pin Status: "); Serial.print(winddirstate1); Serial.print(" "); Serial.print(winddirstate2); Serial.print(" "); Serial.print(winddirstate3); Serial.print(" "); Serial.print(winddirstate4); Serial.println(" "); } return winddir_eu; } //-------------------------------------------------------Interupt Wind and Rain--------------------------------------------------------- void rpm() { long thisTime=micros()-wind_last; wind_last=micros(); if(thisTime>500) { pulseswind++; pulsesgust++; if (debug) { Serial.print("Nb wind turn: "); Serial.println(pulseswind); } } } // Interrupt routine void rain() { long thisTime=micros()-rain_last; rain_last=micros(); if(thisTime>500) { if (raincount1h==0) { count1h = millis(); } raincount1h++; raincount++; //Store Daily rain in case of power failure addr=0; addr += EEPROM.put(addr, raincount); //EEPROM.commit(); //END Store Daily rain in case of power failure if (debug) { Serial.print("Nb rain drop: "); Serial.println(raincount); } } } //---------------------------------------------------------Temperature---------------------------------------------- float Temp(){ analogRead(tempwind); delay(5); //int readingtemp = analogRead(tempwind); //float tempC = (3.1 * readingtemp * 100.0) / 1024; // read the value from LM35. // read 10 values for averaging. int val = 0; for(int i = 0; i < 10; i++) { val += analogRead(tempwind); delay(5); } // convert to temp: // temp value is in 0-1023 range // LM35 outputs 10mV/degree C. ie, 1 Volt => 100 degrees C // So Temp = (avg_val/1023)*5 Volts * 100 degrees/Volt //float tempC = val*30.00f/1023.00f; float tempC = (( bmp.readTemperature() + dht.readTemperature()) / 2.00f ); //average temp betwen BMP180 and DHT22 if (debug) { Serial.print("Temp. : "); Serial.println(tempC); } return tempC; } //---------------------------------------------------------Wind Speed---------------------------------------------- float speedwind() { // cli(); float pulseswindrmp = pulseswind / 60.000f; calcwindspeed = (2 * pi * radio * pulseswindrmp) / 60.000f; if (calcwindspeed > tempwindgust) { tempwindgust = calcwindspeed; } if (debug) { Serial.print("Total pulseswindrmp: "); Serial.print(pulseswindrmp); Serial.print(" Wind Speed: "); Serial.println(calcwindspeed); } pulseswind = 0; //sei(); return calcwindspeed; } //---------------------------------------------------------Wind Gust---------------------------------------------- float speedgust() { //cli(); float pulsesgustrmp = pulsesgust / 5.000f; calcgustspeed = (2 * pi * radio * pulsesgustrmp) / 60.000f; if (calcgustspeed > tempwindgust) { tempwindgust = calcgustspeed; } if (debug) { Serial.print("Total pulsesgustrmp: "); Serial.print(pulsesgustrmp); Serial.print(" Gust Speed: "); Serial.println(calcgustspeed); } pulsesgust = 0; //sei(); return calcgustspeed; } //---------------------------------------------------------UDP NTP-------------------------------------------------- void startudp() { Serial.println("Starting UDP"); udp.begin(localPort); Serial.print("Local port: "); Serial.println(udp.localPort()); } //---------------------------------------------------------NTP request---------------------------------------------- unsigned long sendNTPpacket(IPAddress& address) { Serial.println("sending NTP packet..."); // set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); // Initialize values needed to form NTP request // (see URL above for details on the packets) packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; // all NTP fields have been given values, now // you can send a packet requesting a timestamp: udp.beginPacket(address, 123); //NTP requests are to port 123 udp.write(packetBuffer, NTP_PACKET_SIZE); udp.endPacket(); } //---------------------------------------------------------NTP Time---------------------------------------------- unsigned long ntptime() { WiFi.hostByName(ntpServerName, timeServerIP); sendNTPpacket(timeServerIP); delay(1000); int cb = udp.parsePacket(); if (!cb) { Serial.println("no NTP packet yet"); } else { Serial.print("NTP packet received, length="); Serial.println(cb); // We've received a packet, read the data from it udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer //the timestamp starts at byte 40 of the received packet and is four bytes, // or two words, long. First, esxtract the two words: unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); // combine the four bytes (two words) into a long integer // this is NTP time (seconds since Jan 1 1900): unsigned long secsSince1900 = highWord << 16 | lowWord; // now convert NTP time into everyday time: // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: const unsigned long seventyYears = 2208988800UL; // subtract seventy years: epoch = secsSince1900 - seventyYears; if (debug) { Serial.print("Seconds since Jan 1 1900 = " ); Serial.println(secsSince1900); // print Unix time: Serial.print("Unix time = "); Serial.println(epoch); // print the hour, minute and second: Serial.print("The local time (UTC-4) is "); // UTC-4 by (epoch-(3600*4)) Serial.print(((epoch-(3600*4)) % 86400L) / 3600); // print the hour (86400 equals secs per day) Serial.print(':'); if ( (((epoch-(3600*4)) % 3600) / 60) < 10 ) { // In the first 10 minutes of each hour, we'll want a leading '0' Serial.print('0'); } Serial.print(((epoch-(3600*4)) % 3600) / 60); // print the minute (3600 equals secs per hour) Serial.print(':'); if ( ((epoch-(3600*4)) % 60) < 10 ) { // In the first 10 seconds of each minute, we'll want a leading '0' Serial.print('0'); } Serial.println((epoch-(3600*4)) % 60); // print the second } } } int localhour() { return (((epoch-(3600*4)) % 86400L) / 3600); } int localmin() { return (((epoch-(3600*4)) % 3600) / 60); } int localsec() { return ((epoch-(3600*4)) % 60); }