/* * Personnal Weather Station sketch for Weater Underground with a ESP8266 * BLANCHARD Jordan - http://www.chynehome.com */ #include #include #include #include #include #include #include #include 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"; float altitudepws = 125.00; //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) int temp_offset = -4; // Temp. Offset int humi_offset = 10; // Humidity Offset //---------------------PIN GPIO MAP---------------- int rainils = 10; //Rain REED-ILS sensor int windils = 14; //WIND REED-ILS sensor int windsensor = A0; //Wind Dir sensor //---------------------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.00; float raincount1h = 0.00; const float pi = 3.14159265; // pi number float calcgustspeed; float calcwindspeed; float sensor_count = 0.00f; float winddir_sum = 0.00f; float tempout_sum = 0.00f; float humidity_sum = 0.00f; float baro_sum = 0.00f; unsigned long rain_last=0; unsigned long wind_last=0; int addr=0; float pressure; String eepromstring = "0.00"; Adafruit_BME280 bme; void setup(){ pinMode(rainils, INPUT); pinMode(windils, 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(); Wire.begin(); if (!bme.begin()) { Serial.println("Could not find a valid BME280 sensor, check wiring!"); ESP.restart(); } EEPROM.begin(512); //RESET EEPROM CONTENT - ONLY EXECUTE ONE TIME - AFTER COMMENT /*Serial.println("CLEAR "); eepromClear(); Serial.println("SET "); eepromSet("raincount", "9.00"); eepromSet("raincount1h", "0.00"); Serial.println("LIST "); Serial.println(eepromList());*/ //END - RESET EEPROM CONTENT - ONLY EXECUTE ONE TIME - AFTER COMMENT //GET STORED RAINCOUNT IN EEPROM Serial.println("GET EEPROM"); eepromstring=eepromGet("raincount"); raincount=eepromstring.toFloat(); Serial.print("RAINCOUNT VALUE FROM EEPROM: "); Serial.println(raincount); eepromstring=eepromGet("raincount1h"); raincount1h=eepromstring.toFloat(); Serial.print("RAINCOUNT1H VALUE FROM EEPROM: "); Serial.println(raincount1h); //END - GET STORED RAINCOUNT IN EEPROM if (raincount1h==0) { count1h = millis(); } count5sec = millis(); count60sec = millis(); //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(); tempout_sum = tempout_sum + ( bme.readTemperature() + temp_offset ); humidity_sum = humidity_sum + ( bme.readHumidity() + humi_offset ); baro_sum = baro_sum + ( bme.readSealevelPressure(altitudepws)/100.00f ); sensor_count = sensor_count + 1.00f; count5sec = millis(); if (debug) { Serial.print("Other Sensor each 5sec: "); tempout_eu = tempout_sum / sensor_count; humidity_eu = humidity_sum / sensor_count; dewpout_eu = ( tempout_eu - ((100.00f - humidity_eu)/5.00f) ); baro_eu = baro_sum / sensor_count; winddir_eu = winddir_sum / sensor_count; Serial.print("Temp: "); Serial.print(tempout_eu); Serial.print(" - Dew Point: "); Serial.print(dewpout_eu); Serial.print(" - Humidity: "); Serial.print(humidity_eu); Serial.print(" - Pressure: "); Serial.print(baro_eu); Serial.print(" - Wind Dir: "); 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; } //get all value of sensor winddir_eu = winddir_sum / sensor_count; windspeed_eu = speedwind(); //wind gust for 60sec windgust_eu = tempwindgust; tempwindgust = 0; tempout_eu = tempout_sum / sensor_count; humidity_eu = humidity_sum / sensor_count; dewpout_eu = ( tempout_eu - ((100.00f - humidity_eu)/5.00f) ); baro_eu = baro_sum / sensor_count; rain1h_eu = 0.80f * raincount1h; rain24h_eu = 0.800f * raincount; winddir_sum = 0.00f; tempout_sum = 0.00f; humidity_sum = 0.00f; baro_sum = 0.00f; sensor_count = 0.00f; 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"); //STORE RAINCOUNT IN EEPROM Serial.println("SET EEPROM"); eepromstring = String(raincount,2); eepromSet("raincount", eepromstring); eepromstring = String(raincount1h,2); eepromSet("raincount1h", eepromstring); //END - STORE RAINCOUNT IN EEPROM 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*3)) { Serial.println("task each week"); 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 winddirstate = analogRead(windsensor); if ( (winddirstate >= 210) && (winddirstate <= 220) ) { winddir_eu = 0; } if ( (winddirstate >= 0) && (winddirstate <= 25) ) { winddir_eu = 45; } if ( (winddirstate >= 25) && (winddirstate <= 75) ) { winddir_eu = 90; } if ( (winddirstate >= 75) && (winddirstate <= 120) ) { winddir_eu = 135; } if ( (winddirstate >= 120) && (winddirstate <= 150) ) { winddir_eu = 180; } if ( (winddirstate >= 150) && (winddirstate <= 180) ) { winddir_eu = 225; } if ( (winddirstate >= 180) && (winddirstate <= 205) ) { winddir_eu = 270; } if ( (winddirstate >= 205) && (winddirstate <= 210) ) { winddir_eu = 315; } if (debug) { Serial.print("Wind Dir: "); Serial.print(winddir_eu); Serial.print(" Pin Status: "); Serial.println(winddirstate); } 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>1000) { if (raincount1h==0) { count1h = millis(); } raincount1h = raincount1h + 1.00f; raincount = raincount + 1.00f; if (debug) { Serial.print("Nb rain drop: "); Serial.println(raincount); } } } //---------------------------------------------------------Wind Speed---------------------------------------------- float speedwind() { // cli(); float pulseswindrmp = ( pulseswind / 60.00f ); calcwindspeed = ( pulseswindrmp * 2.50f ); 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.00f ); calcgustspeed = ( pulsesgustrmp * 2.50f ); 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); } //---------------------------------------------------------EEPROM---------------------------------------------- void eepromSet(String name, String value){ Serial.println("eepromSet"); String list=eepromDelete(name); String nameValue="&" + name + "=" + value; //Serial.println(list); //Serial.println(nameValue); list+=nameValue; for (int i = 0; i < list.length(); ++i){ EEPROM.write(i,list.charAt(i)); } EEPROM.commit(); Serial.print(name); Serial.print(":"); Serial.println(value); } String eepromDelete(String name){ Serial.println("eepromDelete"); int nameOfValue; String currentName=""; String currentValue=""; int foundIt=0; char letter; String newList=""; for (int i = 0; i < 512; ++i){ letter= char(EEPROM.read(i)); if (letter=='\n'){ if (foundIt==1){ }else if (newList.length()>0){ newList+="=" + currentValue; } break; } else if (letter=='&'){ nameOfValue=0; currentName=""; if (foundIt==1){ foundIt=0; }else if (newList.length()>0){ newList+="=" + currentValue; } } else if (letter=='='){ if (currentName==name){ foundIt=1; }else{ foundIt=0; newList+="&" + currentName; } nameOfValue=1; currentValue=""; } else{ if (nameOfValue==0){ currentName+=letter; }else{ currentValue+=letter; } } } for (int i = 0; i < 512; ++i){ EEPROM.write(i,'\n'); } EEPROM.commit(); for (int i = 0; i < newList.length(); ++i){ EEPROM.write(i,newList.charAt(i)); } EEPROM.commit(); Serial.println(name); Serial.println(newList); return newList; } void eepromClear(){ Serial.println("eepromClear"); for (int i = 0; i < 512; ++i){ EEPROM.write(i,'\n'); } } String eepromList(){ Serial.println("eepromList"); char letter; String list=""; for (int i = 0; i < 512; ++i){ letter= char(EEPROM.read(i)); if (letter=='\n'){ break; }else{ list+=letter; } } Serial.println(list); return list; } String eepromGet(String name){ Serial.println("eepromGet"); int nameOfValue; String currentName=""; String currentValue=""; int foundIt=0; String value=""; char letter; for (int i = 0; i < 512; ++i){ letter= char(EEPROM.read(i)); if (letter=='\n'){ if (foundIt==1){ value=currentValue; } break; } else if (letter=='&'){ nameOfValue=0; currentName=""; if (foundIt==1){ value=currentValue; break; } } else if (letter=='='){ if (currentName==name){ foundIt=1; }else{ } nameOfValue=1; currentValue=""; } else{ if (nameOfValue==0){ currentName+=letter; }else{ currentValue+=letter; } } } Serial.print(name); Serial.print(":"); Serial.println(value); return value; }