├── .gitattributes ├── .gitignore ├── Firmware ├── Retired HTU21D code │ ├── Weather_Shield_Basic │ │ └── Weather_Shield_Basic.ino │ ├── Weather_Shield_Weather_Station │ │ └── Weather_Shield_Weather_Station.ino │ └── Weather_Shield_with_GPS │ │ └── Weather_Shield_with_GPS.ino ├── Weather_Shield_Basic_V12 │ └── Weather_Shield_Basic_V12.ino ├── Weather_Shield_Weather_Station_V12 │ └── Weather_Shield_Weather_Station_V12.ino └── Weather_Shield_with_GPS_V12 │ └── Weather_Shield_with_GPS_V12.ino ├── Hardware ├── Weather Shield_V12.brd └── Weather Shield_V12.sch ├── LICENSE.md ├── Production └── 13585_Weather Shield_V12_Panel.brd └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## SparkFun Useful stuff 3 | ################# 4 | 5 | ## AVR Development 6 | *.eep 7 | *.elf 8 | *.lst 9 | *.lss 10 | *.sym 11 | *.d 12 | *.o 13 | *.srec 14 | *.map 15 | 16 | ## Notepad++ backup files 17 | *.bak 18 | 19 | ## BOM files 20 | *bom* 21 | 22 | ################# 23 | ## Eclipse 24 | ################# 25 | 26 | *.pydevproject 27 | .project 28 | .metadata 29 | bin/ 30 | tmp/ 31 | *.tmp 32 | *.bak 33 | *.swp 34 | *~.nib 35 | local.properties 36 | .classpath 37 | .settings/ 38 | .loadpath 39 | 40 | # External tool builders 41 | .externalToolBuilders/ 42 | 43 | # Locally stored "Eclipse launch configurations" 44 | *.launch 45 | 46 | # CDT-specific 47 | .cproject 48 | 49 | # PDT-specific 50 | .buildpath 51 | 52 | 53 | ############# 54 | ## Eagle 55 | ############# 56 | 57 | # Ignore the board and schematic backup files and lock files 58 | *.b#? 59 | *.s#? 60 | *.l#? 61 | *.lck 62 | 63 | 64 | ################# 65 | ## Visual Studio 66 | ################# 67 | 68 | ## Ignore Visual Studio temporary files, build results, and 69 | ## files generated by popular Visual Studio add-ons. 70 | 71 | # User-specific files 72 | *.suo 73 | *.user 74 | *.sln.docstates 75 | 76 | # Build results 77 | [Dd]ebug/ 78 | [Rr]elease/ 79 | *_i.c 80 | *_p.c 81 | *.ilk 82 | *.meta 83 | *.obj 84 | *.pch 85 | *.pdb 86 | *.pgc 87 | *.pgd 88 | *.rsp 89 | *.sbr 90 | *.tlb 91 | *.tli 92 | *.tlh 93 | *.tmp 94 | *.vspscc 95 | .builds 96 | *.dotCover 97 | 98 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 99 | #packages/ 100 | 101 | # Visual C++ cache files 102 | ipch/ 103 | *.aps 104 | *.ncb 105 | *.opensdf 106 | *.sdf 107 | 108 | # Visual Studio profiler 109 | *.psess 110 | *.vsp 111 | 112 | # ReSharper is a .NET coding add-in 113 | _ReSharper* 114 | 115 | # Installshield output folder 116 | [Ee]xpress 117 | 118 | # DocProject is a documentation generator add-in 119 | DocProject/buildhelp/ 120 | DocProject/Help/*.HxT 121 | DocProject/Help/*.HxC 122 | DocProject/Help/*.hhc 123 | DocProject/Help/*.hhk 124 | DocProject/Help/*.hhp 125 | DocProject/Help/Html2 126 | DocProject/Help/html 127 | 128 | # Click-Once directory 129 | publish 130 | 131 | # Others 132 | [Bb]in 133 | [Oo]bj 134 | sql 135 | TestResults 136 | *.Cache 137 | ClientBin 138 | stylecop.* 139 | ~$* 140 | *.dbmdl 141 | Generated_Code #added for RIA/Silverlight projects 142 | 143 | # Backup & report files from converting an old project file to a newer 144 | # Visual Studio version. Backup files are not needed, because we have git ;-) 145 | _UpgradeReport_Files/ 146 | Backup*/ 147 | UpgradeLog*.XML 148 | 149 | 150 | ############ 151 | ## Windows 152 | ############ 153 | 154 | # Windows image file caches 155 | Thumbs.db 156 | 157 | # Folder config file 158 | Desktop.ini 159 | 160 | 161 | ############# 162 | ## Mac OS 163 | ############# 164 | 165 | .DS_Store 166 | 167 | 168 | ############# 169 | ## Linux 170 | ############# 171 | 172 | # backup files (*.bak on Win) 173 | *~ 174 | 175 | 176 | ############# 177 | ## Python 178 | ############# 179 | 180 | *.py[co] 181 | 182 | # Packages 183 | *.egg 184 | *.egg-info 185 | dist 186 | build 187 | eggs 188 | parts 189 | bin 190 | var 191 | sdist 192 | develop-eggs 193 | .installed.cfg 194 | 195 | # Installer logs 196 | pip-log.txt 197 | 198 | # Unit test / coverage reports 199 | .coverage 200 | .tox 201 | 202 | #Translations 203 | *.mo 204 | 205 | #Mr Developer 206 | .mr.developer.cfg 207 | -------------------------------------------------------------------------------- /Firmware/Retired HTU21D code/Weather_Shield_Basic/Weather_Shield_Basic.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Weather Shield Example 3 | By: Nathan Seidle 4 | SparkFun Electronics 5 | Date: June 10th, 2016 6 | License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). 7 | 8 | This example prints the current humidity, air pressure, temperature and light levels. 9 | 10 | The weather shield is capable of a lot. Be sure to checkout the other more advanced examples for creating 11 | your own weather station. 12 | 13 | */ 14 | 15 | #include //I2C needed for sensors 16 | #include "SparkFunMPL3115A2.h" //Pressure sensor - Search "SparkFun MPL3115" and install from Library Manager 17 | #include "SparkFunHTU21D.h" //Humidity sensor - Search "SparkFun HTU21D" and install from Library Manager 18 | 19 | MPL3115A2 myPressure; //Create an instance of the pressure sensor 20 | HTU21D myHumidity; //Create an instance of the humidity sensor 21 | 22 | //Hardware pin definitions 23 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 24 | const byte STAT_BLUE = 7; 25 | const byte STAT_GREEN = 8; 26 | 27 | const byte REFERENCE_3V3 = A3; 28 | const byte LIGHT = A1; 29 | const byte BATT = A2; 30 | 31 | //Global Variables 32 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 33 | long lastSecond; //The millis counter to see when a second rolls by 34 | 35 | void setup() 36 | { 37 | Serial.begin(9600); 38 | Serial.println("Weather Shield Example"); 39 | 40 | pinMode(STAT_BLUE, OUTPUT); //Status LED Blue 41 | pinMode(STAT_GREEN, OUTPUT); //Status LED Green 42 | 43 | pinMode(REFERENCE_3V3, INPUT); 44 | pinMode(LIGHT, INPUT); 45 | 46 | //Configure the pressure sensor 47 | myPressure.begin(); // Get sensor online 48 | myPressure.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa 49 | myPressure.setOversampleRate(7); // Set Oversample to the recommended 128 50 | myPressure.enableEventFlags(); // Enable all three pressure and temp event flags 51 | 52 | //Configure the humidity sensor 53 | myHumidity.begin(); 54 | 55 | lastSecond = millis(); 56 | 57 | Serial.println("Weather Shield online!"); 58 | } 59 | 60 | void loop() 61 | { 62 | //Print readings every second 63 | if (millis() - lastSecond >= 1000) 64 | { 65 | digitalWrite(STAT_BLUE, HIGH); //Blink stat LED 66 | 67 | lastSecond += 1000; 68 | 69 | //Check Humidity Sensor 70 | float humidity = myHumidity.readHumidity(); 71 | 72 | if (humidity == ERROR_I2C_TIMEOUT) //Humidty sensor failed to respond 73 | { 74 | Serial.println("I2C communication to sensors is not working. Check solder connections."); 75 | 76 | //Try re-initializing the I2C comm and the sensors 77 | myPressure.begin(); 78 | myPressure.setModeBarometer(); 79 | myPressure.setOversampleRate(7); 80 | myPressure.enableEventFlags(); 81 | myHumidity.begin(); 82 | } 83 | else 84 | { 85 | Serial.print("Humidity = "); 86 | Serial.print(humidity); 87 | Serial.print("%,"); 88 | float temp_h = myHumidity.readTemperature(); 89 | Serial.print(" temp_h = "); 90 | Serial.print(temp_h, 2); 91 | Serial.print("C,"); 92 | 93 | //Check Pressure Sensor 94 | float pressure = myPressure.readPressure(); 95 | Serial.print(" Pressure = "); 96 | Serial.print(pressure); 97 | Serial.print("Pa,"); 98 | 99 | //Check tempf from pressure sensor 100 | float tempf = myPressure.readTempF(); 101 | Serial.print(" temp_p = "); 102 | Serial.print(tempf, 2); 103 | Serial.print("F,"); 104 | 105 | //Check light sensor 106 | float light_lvl = get_light_level(); 107 | Serial.print(" light_lvl = "); 108 | Serial.print(light_lvl); 109 | Serial.print("V,"); 110 | 111 | //Check batt level 112 | float batt_lvl = get_battery_level(); 113 | Serial.print(" VinPin = "); 114 | Serial.print(batt_lvl); 115 | Serial.print("V"); 116 | 117 | Serial.println(); 118 | } 119 | 120 | digitalWrite(STAT_BLUE, LOW); //Turn off stat LED 121 | } 122 | 123 | delay(100); 124 | } 125 | 126 | //Returns the voltage of the light sensor based on the 3.3V rail 127 | //This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) 128 | float get_light_level() 129 | { 130 | float operatingVoltage = analogRead(REFERENCE_3V3); 131 | 132 | float lightSensor = analogRead(LIGHT); 133 | 134 | operatingVoltage = 3.3 / operatingVoltage; //The reference voltage is 3.3V 135 | 136 | lightSensor = operatingVoltage * lightSensor; 137 | 138 | return (lightSensor); 139 | } 140 | 141 | //Returns the voltage of the raw pin based on the 3.3V rail 142 | //This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) 143 | //Battery level is connected to the RAW pin on Arduino and is fed through two 5% resistors: 144 | //3.9K on the high side (R1), and 1K on the low side (R2) 145 | float get_battery_level() 146 | { 147 | float operatingVoltage = analogRead(REFERENCE_3V3); 148 | 149 | float rawVoltage = analogRead(BATT); 150 | 151 | operatingVoltage = 3.30 / operatingVoltage; //The reference voltage is 3.3V 152 | 153 | rawVoltage = operatingVoltage * rawVoltage; //Convert the 0 to 1023 int to actual voltage on BATT pin 154 | 155 | rawVoltage *= 4.90; //(3.9k+1k)/1k - multiple BATT voltage by the voltage divider to get actual system voltage 156 | 157 | return (rawVoltage); 158 | } 159 | -------------------------------------------------------------------------------- /Firmware/Retired HTU21D code/Weather_Shield_Weather_Station/Weather_Shield_Weather_Station.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Weather Shield Example 3 | By: Nathan Seidle 4 | SparkFun Electronics 5 | Date: November 16th, 2013 6 | License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). 7 | 8 | Much of this is based on Mike Grusin's USB Weather Board code: https://www.sparkfun.com/products/10586 9 | 10 | This is a more advanced example of how to utilize every aspect of the weather shield. See the basic 11 | example if you're just getting started. 12 | 13 | This code reads all the various sensors (wind speed, direction, rain gauge, humidty, pressure, light, batt_lvl) 14 | and reports it over the serial comm port. This can be easily routed to an datalogger (such as OpenLog) or 15 | a wireless transmitter (such as Electric Imp). 16 | 17 | Measurements are reported once a second but windspeed and rain gauge are tied to interrupts that are 18 | calcualted at each report. 19 | 20 | This example code assumes the GPS module is not used. 21 | 22 | */ 23 | 24 | #include //I2C needed for sensors 25 | #include "SparkFunMPL3115A2.h" //Pressure sensor - Search "SparkFun MPL3115" and install from Library Manager 26 | #include "SparkFunHTU21D.h" //Humidity sensor - Search "SparkFun HTU21D" and install from Library Manager 27 | 28 | MPL3115A2 myPressure; //Create an instance of the pressure sensor 29 | HTU21D myHumidity; //Create an instance of the humidity sensor 30 | 31 | //Hardware pin definitions 32 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 33 | // digital I/O pins 34 | const byte WSPEED = 3; 35 | const byte RAIN = 2; 36 | const byte STAT1 = 7; 37 | const byte STAT2 = 8; 38 | 39 | // analog I/O pins 40 | const byte REFERENCE_3V3 = A3; 41 | const byte LIGHT = A1; 42 | const byte BATT = A2; 43 | const byte WDIR = A0; 44 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 45 | 46 | //Global Variables 47 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 48 | long lastSecond; //The millis counter to see when a second rolls by 49 | byte seconds; //When it hits 60, increase the current minute 50 | byte seconds_2m; //Keeps track of the "wind speed/dir avg" over last 2 minutes array of data 51 | byte minutes; //Keeps track of where we are in various arrays of data 52 | byte minutes_10m; //Keeps track of where we are in wind gust/dir over last 10 minutes array of data 53 | 54 | long lastWindCheck = 0; 55 | volatile long lastWindIRQ = 0; 56 | volatile byte windClicks = 0; 57 | 58 | //We need to keep track of the following variables: 59 | //Wind speed/dir each update (no storage) 60 | //Wind gust/dir over the day (no storage) 61 | //Wind speed/dir, avg over 2 minutes (store 1 per second) 62 | //Wind gust/dir over last 10 minutes (store 1 per minute) 63 | //Rain over the past hour (store 1 per minute) 64 | //Total rain over date (store one per day) 65 | 66 | byte windspdavg[120]; //120 bytes to keep track of 2 minute average 67 | 68 | #define WIND_DIR_AVG_SIZE 120 69 | int winddiravg[WIND_DIR_AVG_SIZE]; //120 ints to keep track of 2 minute average 70 | float windgust_10m[10]; //10 floats to keep track of 10 minute max 71 | int windgustdirection_10m[10]; //10 ints to keep track of 10 minute max 72 | volatile float rainHour[60]; //60 floating numbers to keep track of 60 minutes of rain 73 | 74 | //These are all the weather values that wunderground expects: 75 | int winddir = 0; // [0-360 instantaneous wind direction] 76 | float windspeedmph = 0; // [mph instantaneous wind speed] 77 | float windgustmph = 0; // [mph current wind gust, using software specific time period] 78 | int windgustdir = 0; // [0-360 using software specific time period] 79 | float windspdmph_avg2m = 0; // [mph 2 minute average wind speed mph] 80 | int winddir_avg2m = 0; // [0-360 2 minute average wind direction] 81 | float windgustmph_10m = 0; // [mph past 10 minutes wind gust mph ] 82 | int windgustdir_10m = 0; // [0-360 past 10 minutes wind gust direction] 83 | float humidity = 0; // [%] 84 | float tempf = 0; // [temperature F] 85 | float rainin = 0; // [rain inches over the past hour)] -- the accumulated rainfall in the past 60 min 86 | volatile float dailyrainin = 0; // [rain inches so far today in local time] 87 | //float baromin = 30.03;// [barom in] - It's hard to calculate baromin locally, do this in the agent 88 | float pressure = 0; 89 | //float dewptf; // [dewpoint F] - It's hard to calculate dewpoint locally, do this in the agent 90 | 91 | float batt_lvl = 11.8; //[analog value from 0 to 1023] 92 | float light_lvl = 455; //[analog value from 0 to 1023] 93 | 94 | // volatiles are subject to modification by IRQs 95 | volatile unsigned long raintime, rainlast, raininterval, rain; 96 | 97 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 98 | 99 | //Interrupt routines (these are called by the hardware interrupts, not by the main code) 100 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 101 | void rainIRQ() 102 | // Count rain gauge bucket tips as they occur 103 | // Activated by the magnet and reed switch in the rain gauge, attached to input D2 104 | { 105 | raintime = millis(); // grab current time 106 | raininterval = raintime - rainlast; // calculate interval between this and last event 107 | 108 | if (raininterval > 10) // ignore switch-bounce glitches less than 10mS after initial edge 109 | { 110 | dailyrainin += 0.011; //Each dump is 0.011" of water 111 | rainHour[minutes] += 0.011; //Increase this minute's amount of rain 112 | 113 | rainlast = raintime; // set up for next event 114 | } 115 | } 116 | 117 | void wspeedIRQ() 118 | // Activated by the magnet in the anemometer (2 ticks per rotation), attached to input D3 119 | { 120 | if (millis() - lastWindIRQ > 10) // Ignore switch-bounce glitches less than 10ms (142MPH max reading) after the reed switch closes 121 | { 122 | lastWindIRQ = millis(); //Grab the current time 123 | windClicks++; //There is 1.492MPH for each click per second. 124 | } 125 | } 126 | 127 | 128 | void setup() 129 | { 130 | Serial.begin(9600); 131 | Serial.println("Weather Shield Example"); 132 | 133 | pinMode(STAT1, OUTPUT); //Status LED Blue 134 | pinMode(STAT2, OUTPUT); //Status LED Green 135 | 136 | pinMode(WSPEED, INPUT_PULLUP); // input from wind meters windspeed sensor 137 | pinMode(RAIN, INPUT_PULLUP); // input from wind meters rain gauge sensor 138 | 139 | pinMode(REFERENCE_3V3, INPUT); 140 | pinMode(LIGHT, INPUT); 141 | 142 | //Configure the pressure sensor 143 | myPressure.begin(); // Get sensor online 144 | myPressure.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa 145 | myPressure.setOversampleRate(7); // Set Oversample to the recommended 128 146 | myPressure.enableEventFlags(); // Enable all three pressure and temp event flags 147 | 148 | //Configure the humidity sensor 149 | myHumidity.begin(); 150 | 151 | seconds = 0; 152 | lastSecond = millis(); 153 | 154 | // attach external interrupt pins to IRQ functions 155 | attachInterrupt(0, rainIRQ, FALLING); 156 | attachInterrupt(1, wspeedIRQ, FALLING); 157 | 158 | // turn on interrupts 159 | interrupts(); 160 | 161 | Serial.println("Weather Shield online!"); 162 | 163 | } 164 | 165 | void loop() 166 | { 167 | //Keep track of which minute it is 168 | if (millis() - lastSecond >= 1000) 169 | { 170 | digitalWrite(STAT1, HIGH); //Blink stat LED 171 | 172 | lastSecond += 1000; 173 | 174 | //Take a speed and direction reading every second for 2 minute average 175 | if (++seconds_2m > 119) seconds_2m = 0; 176 | 177 | //Calc the wind speed and direction every second for 120 second to get 2 minute average 178 | float currentSpeed = get_wind_speed(); 179 | windspeedmph = currentSpeed; //update global variable for windspeed when using the printWeather() function 180 | //float currentSpeed = random(5); //For testing 181 | int currentDirection = get_wind_direction(); 182 | windspdavg[seconds_2m] = (int)currentSpeed; 183 | winddiravg[seconds_2m] = currentDirection; 184 | //if(seconds_2m % 10 == 0) displayArrays(); //For testing 185 | 186 | //Check to see if this is a gust for the minute 187 | if (currentSpeed > windgust_10m[minutes_10m]) 188 | { 189 | windgust_10m[minutes_10m] = currentSpeed; 190 | windgustdirection_10m[minutes_10m] = currentDirection; 191 | } 192 | 193 | //Check to see if this is a gust for the day 194 | if (currentSpeed > windgustmph) 195 | { 196 | windgustmph = currentSpeed; 197 | windgustdir = currentDirection; 198 | } 199 | 200 | if (++seconds > 59) 201 | { 202 | seconds = 0; 203 | 204 | if (++minutes > 59) minutes = 0; 205 | if (++minutes_10m > 9) minutes_10m = 0; 206 | 207 | rainHour[minutes] = 0; //Zero out this minute's rainfall amount 208 | windgust_10m[minutes_10m] = 0; //Zero out this minute's gust 209 | } 210 | 211 | //Report all readings every second 212 | printWeather(); 213 | 214 | digitalWrite(STAT1, LOW); //Turn off stat LED 215 | } 216 | 217 | delay(100); 218 | } 219 | 220 | //Calculates each of the variables that wunderground is expecting 221 | void calcWeather() 222 | { 223 | //Calc winddir 224 | winddir = get_wind_direction(); 225 | 226 | //Calc windspeed 227 | //windspeedmph = get_wind_speed(); //This is calculated in the main loop on line 179 228 | 229 | //Calc windgustmph 230 | //Calc windgustdir 231 | //These are calculated in the main loop 232 | 233 | //Calc windspdmph_avg2m 234 | float temp = 0; 235 | for (int i = 0 ; i < 120 ; i++) 236 | temp += windspdavg[i]; 237 | temp /= 120.0; 238 | windspdmph_avg2m = temp; 239 | 240 | //Calc winddir_avg2m, Wind Direction 241 | //You can't just take the average. Google "mean of circular quantities" for more info 242 | //We will use the Mitsuta method because it doesn't require trig functions 243 | //And because it sounds cool. 244 | //Based on: http://abelian.org/vlf/bearings.html 245 | //Based on: http://stackoverflow.com/questions/1813483/averaging-angles-again 246 | long sum = winddiravg[0]; 247 | int D = winddiravg[0]; 248 | for (int i = 1 ; i < WIND_DIR_AVG_SIZE ; i++) 249 | { 250 | int delta = winddiravg[i] - D; 251 | 252 | if (delta < -180) 253 | D += delta + 360; 254 | else if (delta > 180) 255 | D += delta - 360; 256 | else 257 | D += delta; 258 | 259 | sum += D; 260 | } 261 | winddir_avg2m = sum / WIND_DIR_AVG_SIZE; 262 | if (winddir_avg2m >= 360) winddir_avg2m -= 360; 263 | if (winddir_avg2m < 0) winddir_avg2m += 360; 264 | 265 | //Calc windgustmph_10m 266 | //Calc windgustdir_10m 267 | //Find the largest windgust in the last 10 minutes 268 | windgustmph_10m = 0; 269 | windgustdir_10m = 0; 270 | //Step through the 10 minutes 271 | for (int i = 0; i < 10 ; i++) 272 | { 273 | if (windgust_10m[i] > windgustmph_10m) 274 | { 275 | windgustmph_10m = windgust_10m[i]; 276 | windgustdir_10m = windgustdirection_10m[i]; 277 | } 278 | } 279 | 280 | //Calc humidity 281 | humidity = myHumidity.readHumidity(); 282 | //float temp_h = myHumidity.readTemperature(); 283 | //Serial.print(" TempH:"); 284 | //Serial.print(temp_h, 2); 285 | 286 | //Calc tempf from pressure sensor 287 | tempf = myPressure.readTempF(); 288 | //Serial.print(" TempP:"); 289 | //Serial.print(tempf, 2); 290 | 291 | //Total rainfall for the day is calculated within the interrupt 292 | //Calculate amount of rainfall for the last 60 minutes 293 | rainin = 0; 294 | for (int i = 0 ; i < 60 ; i++) 295 | rainin += rainHour[i]; 296 | 297 | //Calc pressure 298 | pressure = myPressure.readPressure(); 299 | 300 | //Calc dewptf 301 | 302 | //Calc light level 303 | light_lvl = get_light_level(); 304 | 305 | //Calc battery level 306 | batt_lvl = get_battery_level(); 307 | } 308 | 309 | //Returns the voltage of the light sensor based on the 3.3V rail 310 | //This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) 311 | float get_light_level() 312 | { 313 | float operatingVoltage = analogRead(REFERENCE_3V3); 314 | 315 | float lightSensor = analogRead(LIGHT); 316 | 317 | operatingVoltage = 3.3 / operatingVoltage; //The reference voltage is 3.3V 318 | 319 | lightSensor = operatingVoltage * lightSensor; 320 | 321 | return (lightSensor); 322 | } 323 | 324 | //Returns the voltage of the raw pin based on the 3.3V rail 325 | //This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) 326 | //Battery level is connected to the RAW pin on Arduino and is fed through two 5% resistors: 327 | //3.9K on the high side (R1), and 1K on the low side (R2) 328 | float get_battery_level() 329 | { 330 | float operatingVoltage = analogRead(REFERENCE_3V3); 331 | 332 | float rawVoltage = analogRead(BATT); 333 | 334 | operatingVoltage = 3.30 / operatingVoltage; //The reference voltage is 3.3V 335 | 336 | rawVoltage = operatingVoltage * rawVoltage; //Convert the 0 to 1023 int to actual voltage on BATT pin 337 | 338 | rawVoltage *= 4.90; //(3.9k+1k)/1k - multiple BATT voltage by the voltage divider to get actual system voltage 339 | 340 | return (rawVoltage); 341 | } 342 | 343 | //Returns the instataneous wind speed 344 | float get_wind_speed() 345 | { 346 | float deltaTime = millis() - lastWindCheck; //750ms 347 | 348 | deltaTime /= 1000.0; //Covert to seconds 349 | 350 | float windSpeed = (float)windClicks / deltaTime; //3 / 0.750s = 4 351 | 352 | windClicks = 0; //Reset and start watching for new wind 353 | lastWindCheck = millis(); 354 | 355 | windSpeed *= 1.492; //4 * 1.492 = 5.968MPH 356 | 357 | /* Serial.println(); 358 | Serial.print("Windspeed:"); 359 | Serial.println(windSpeed);*/ 360 | 361 | return (windSpeed); 362 | } 363 | 364 | //Read the wind direction sensor, return heading in degrees 365 | int get_wind_direction() 366 | { 367 | unsigned int adc; 368 | 369 | adc = analogRead(WDIR); // get the current reading from the sensor 370 | 371 | // The following table is ADC readings for the wind direction sensor output, sorted from low to high. 372 | // Each threshold is the midpoint between adjacent headings. The output is degrees for that ADC reading. 373 | // Note that these are not in compass degree order! See Weather Meters datasheet for more information. 374 | 375 | if (adc < 380) return (113); 376 | if (adc < 393) return (68); 377 | if (adc < 414) return (90); 378 | if (adc < 456) return (158); 379 | if (adc < 508) return (135); 380 | if (adc < 551) return (203); 381 | if (adc < 615) return (180); 382 | if (adc < 680) return (23); 383 | if (adc < 746) return (45); 384 | if (adc < 801) return (248); 385 | if (adc < 833) return (225); 386 | if (adc < 878) return (338); 387 | if (adc < 913) return (0); 388 | if (adc < 940) return (293); 389 | if (adc < 967) return (315); 390 | if (adc < 990) return (270); 391 | return (-1); // error, disconnected? 392 | } 393 | 394 | 395 | //Prints the various variables directly to the port 396 | //I don't like the way this function is written but Arduino doesn't support floats under sprintf 397 | void printWeather() 398 | { 399 | calcWeather(); //Go calc all the various sensors 400 | 401 | Serial.println(); 402 | Serial.print("$,winddir="); 403 | Serial.print(winddir); 404 | Serial.print(",windspeedmph="); 405 | Serial.print(windspeedmph, 1); 406 | Serial.print(",windgustmph="); 407 | Serial.print(windgustmph, 1); 408 | Serial.print(",windgustdir="); 409 | Serial.print(windgustdir); 410 | Serial.print(",windspdmph_avg2m="); 411 | Serial.print(windspdmph_avg2m, 1); 412 | Serial.print(",winddir_avg2m="); 413 | Serial.print(winddir_avg2m); 414 | Serial.print(",windgustmph_10m="); 415 | Serial.print(windgustmph_10m, 1); 416 | Serial.print(",windgustdir_10m="); 417 | Serial.print(windgustdir_10m); 418 | Serial.print(",humidity="); 419 | Serial.print(humidity, 1); 420 | Serial.print(",tempf="); 421 | Serial.print(tempf, 1); 422 | Serial.print(",rainin="); 423 | Serial.print(rainin, 2); 424 | Serial.print(",dailyrainin="); 425 | Serial.print(dailyrainin, 2); 426 | Serial.print(",pressure="); 427 | Serial.print(pressure, 2); 428 | Serial.print(",batt_lvl="); 429 | Serial.print(batt_lvl, 2); 430 | Serial.print(",light_lvl="); 431 | Serial.print(light_lvl, 2); 432 | Serial.print(","); 433 | Serial.println("#"); 434 | 435 | } 436 | -------------------------------------------------------------------------------- /Firmware/Retired HTU21D code/Weather_Shield_with_GPS/Weather_Shield_with_GPS.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Weather Shield Example 3 | By: Nathan Seidle 4 | SparkFun Electronics 5 | Date: November 16th, 2013 6 | License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). 7 | 8 | Much of this is based on Mike Grusin's USB Weather Board code: https://www.sparkfun.com/products/10586 9 | 10 | This code reads all the various sensors (wind speed, direction, rain gauge, humidty, pressure, light, batt_lvl) 11 | and reports it over the serial comm port. This can be easily routed to an datalogger (such as OpenLog) or 12 | a wireless transmitter (such as Electric Imp). 13 | 14 | Measurements are reported once a second but windspeed and rain gauge are tied to interrupts that are 15 | calcualted at each report. 16 | 17 | This example code assumes the GP-635T GPS module is attached. 18 | 19 | */ 20 | 21 | #include //I2C needed for sensors 22 | #include "SparkFunMPL3115A2.h" //Pressure sensor - Search "SparkFun MPL3115" and install from Library Manager 23 | #include "SparkFunHTU21D.h" //Humidity sensor - Search "SparkFun HTU21D" and install from Library Manager 24 | #include //Needed for GPS 25 | #include //GPS parsing - Available through the Library Manager. 26 | 27 | TinyGPSPlus gps; 28 | 29 | static const int RXPin = 5, TXPin = 4; //GPS is attached to pin 4(TX from GPS) and pin 5(RX into GPS) 30 | SoftwareSerial ss(RXPin, TXPin); 31 | 32 | MPL3115A2 myPressure; //Create an instance of the pressure sensor 33 | HTU21D myHumidity; //Create an instance of the humidity sensor 34 | 35 | //Hardware pin definitions 36 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 37 | // digital I/O pins 38 | const byte WSPEED = 3; 39 | const byte RAIN = 2; 40 | const byte STAT1 = 7; 41 | const byte STAT2 = 8; 42 | const byte GPS_PWRCTL = 6; //Pulling this pin low puts GPS to sleep but maintains RTC and RAM 43 | 44 | // analog I/O pins 45 | const byte REFERENCE_3V3 = A3; 46 | const byte LIGHT = A1; 47 | const byte BATT = A2; 48 | const byte WDIR = A0; 49 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 50 | 51 | //Global Variables 52 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 53 | long lastSecond; //The millis counter to see when a second rolls by 54 | byte seconds; //When it hits 60, increase the current minute 55 | byte seconds_2m; //Keeps track of the "wind speed/dir avg" over last 2 minutes array of data 56 | byte minutes; //Keeps track of where we are in various arrays of data 57 | byte minutes_10m; //Keeps track of where we are in wind gust/dir over last 10 minutes array of data 58 | 59 | long lastWindCheck = 0; 60 | volatile long lastWindIRQ = 0; 61 | volatile byte windClicks = 0; 62 | 63 | //We need to keep track of the following variables: 64 | //Wind speed/dir each update (no storage) 65 | //Wind gust/dir over the day (no storage) 66 | //Wind speed/dir, avg over 2 minutes (store 1 per second) 67 | //Wind gust/dir over last 10 minutes (store 1 per minute) 68 | //Rain over the past hour (store 1 per minute) 69 | //Total rain over date (store one per day) 70 | 71 | byte windspdavg[120]; //120 bytes to keep track of 2 minute average 72 | int winddiravg[120]; //120 ints to keep track of 2 minute average 73 | float windgust_10m[10]; //10 floats to keep track of 10 minute max 74 | int windgustdirection_10m[10]; //10 ints to keep track of 10 minute max 75 | volatile float rainHour[60]; //60 floating numbers to keep track of 60 minutes of rain 76 | 77 | //These are all the weather values that wunderground expects: 78 | int winddir = 0; // [0-360 instantaneous wind direction] 79 | float windspeedmph = 0; // [mph instantaneous wind speed] 80 | float windgustmph = 0; // [mph current wind gust, using software specific time period] 81 | int windgustdir = 0; // [0-360 using software specific time period] 82 | float windspdmph_avg2m = 0; // [mph 2 minute average wind speed mph] 83 | int winddir_avg2m = 0; // [0-360 2 minute average wind direction] 84 | float windgustmph_10m = 0; // [mph past 10 minutes wind gust mph ] 85 | int windgustdir_10m = 0; // [0-360 past 10 minutes wind gust direction] 86 | float humidity = 0; // [%] 87 | float tempf = 0; // [temperature F] 88 | float rainin = 0; // [rain inches over the past hour)] -- the accumulated rainfall in the past 60 min 89 | volatile float dailyrainin = 0; // [rain inches so far today in local time] 90 | //float baromin = 30.03;// [barom in] - It's hard to calculate baromin locally, do this in the agent 91 | float pressure = 0; 92 | //float dewptf; // [dewpoint F] - It's hard to calculate dewpoint locally, do this in the agent 93 | 94 | float batt_lvl = 11.8; //[analog value from 0 to 1023] 95 | float light_lvl = 455; //[analog value from 0 to 1023] 96 | 97 | //Variables used for GPS 98 | //float flat, flon; // 39.015024 -102.283608686 99 | //unsigned long age; 100 | //int year; 101 | //byte month, day, hour, minute, second, hundredths; 102 | 103 | // volatiles are subject to modification by IRQs 104 | volatile unsigned long raintime, rainlast, raininterval, rain; 105 | 106 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 107 | 108 | //Interrupt routines (these are called by the hardware interrupts, not by the main code) 109 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 110 | void rainIRQ() 111 | // Count rain gauge bucket tips as they occur 112 | // Activated by the magnet and reed switch in the rain gauge, attached to input D2 113 | { 114 | raintime = millis(); // grab current time 115 | raininterval = raintime - rainlast; // calculate interval between this and last event 116 | 117 | if (raininterval > 10) // ignore switch-bounce glitches less than 10mS after initial edge 118 | { 119 | dailyrainin += 0.011; //Each dump is 0.011" of water 120 | rainHour[minutes] += 0.011; //Increase this minute's amount of rain 121 | 122 | rainlast = raintime; // set up for next event 123 | } 124 | } 125 | 126 | void wspeedIRQ() 127 | // Activated by the magnet in the anemometer (2 ticks per rotation), attached to input D3 128 | { 129 | if (millis() - lastWindIRQ > 10) // Ignore switch-bounce glitches less than 10ms (142MPH max reading) after the reed switch closes 130 | { 131 | lastWindIRQ = millis(); //Grab the current time 132 | windClicks++; //There is 1.492MPH for each click per second. 133 | } 134 | } 135 | 136 | 137 | void setup() 138 | { 139 | Serial.begin(9600); 140 | Serial.println("Weather Shield Example"); 141 | 142 | ss.begin(9600); //Begin listening to GPS over software serial at 9600. This should be the default baud of the module. 143 | 144 | pinMode(STAT1, OUTPUT); //Status LED Blue 145 | pinMode(STAT2, OUTPUT); //Status LED Green 146 | 147 | pinMode(GPS_PWRCTL, OUTPUT); 148 | digitalWrite(GPS_PWRCTL, HIGH); //Pulling this pin low puts GPS to sleep but maintains RTC and RAM 149 | 150 | pinMode(WSPEED, INPUT_PULLUP); // input from wind meters windspeed sensor 151 | pinMode(RAIN, INPUT_PULLUP); // input from wind meters rain gauge sensor 152 | 153 | pinMode(REFERENCE_3V3, INPUT); 154 | pinMode(LIGHT, INPUT); 155 | 156 | //Configure the pressure sensor 157 | myPressure.begin(); // Get sensor online 158 | myPressure.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa 159 | myPressure.setOversampleRate(7); // Set Oversample to the recommended 128 160 | myPressure.enableEventFlags(); // Enable all three pressure and temp event flags 161 | 162 | //Configure the humidity sensor 163 | myHumidity.begin(); 164 | 165 | seconds = 0; 166 | lastSecond = millis(); 167 | 168 | // attach external interrupt pins to IRQ functions 169 | attachInterrupt(0, rainIRQ, FALLING); 170 | attachInterrupt(1, wspeedIRQ, FALLING); 171 | 172 | // turn on interrupts 173 | interrupts(); 174 | 175 | Serial.println("Weather Shield online!"); 176 | 177 | } 178 | 179 | void loop() 180 | { 181 | //Keep track of which minute it is 182 | if (millis() - lastSecond >= 1000) 183 | { 184 | digitalWrite(STAT1, HIGH); //Blink stat LED 185 | 186 | lastSecond += 1000; 187 | 188 | //Take a speed and direction reading every second for 2 minute average 189 | if (++seconds_2m > 119) seconds_2m = 0; 190 | 191 | //Calc the wind speed and direction every second for 120 second to get 2 minute average 192 | float currentSpeed = get_wind_speed(); 193 | windspeedmph = currentSpeed; //update global variable for windspeed when using the printWeather() function 194 | //float currentSpeed = random(5); //For testing 195 | int currentDirection = get_wind_direction(); 196 | windspdavg[seconds_2m] = (int)currentSpeed; 197 | winddiravg[seconds_2m] = currentDirection; 198 | //if(seconds_2m % 10 == 0) displayArrays(); //For testing 199 | 200 | //Check to see if this is a gust for the minute 201 | if (currentSpeed > windgust_10m[minutes_10m]) 202 | { 203 | windgust_10m[minutes_10m] = currentSpeed; 204 | windgustdirection_10m[minutes_10m] = currentDirection; 205 | } 206 | 207 | //Check to see if this is a gust for the day 208 | if (currentSpeed > windgustmph) 209 | { 210 | windgustmph = currentSpeed; 211 | windgustdir = currentDirection; 212 | } 213 | 214 | if (++seconds > 59) 215 | { 216 | seconds = 0; 217 | 218 | if (++minutes > 59) minutes = 0; 219 | if (++minutes_10m > 9) minutes_10m = 0; 220 | 221 | rainHour[minutes] = 0; //Zero out this minute's rainfall amount 222 | windgust_10m[minutes_10m] = 0; //Zero out this minute's gust 223 | } 224 | 225 | //Report all readings every second 226 | printWeather(); 227 | 228 | digitalWrite(STAT1, LOW); //Turn off stat LED 229 | } 230 | 231 | smartdelay(800); //Wait 1 second, and gather GPS data 232 | } 233 | 234 | //While we delay for a given amount of time, gather GPS data 235 | static void smartdelay(unsigned long ms) 236 | { 237 | unsigned long start = millis(); 238 | do 239 | { 240 | while (ss.available()) 241 | gps.encode(ss.read()); 242 | } while (millis() - start < ms); 243 | } 244 | 245 | 246 | //Calculates each of the variables that wunderground is expecting 247 | void calcWeather() 248 | { 249 | //Calc winddir 250 | winddir = get_wind_direction(); 251 | 252 | //Calc windspeed 253 | //windspeedmph = get_wind_speed(); //This is calculated in the main loop on line 193 254 | 255 | //Calc windgustmph 256 | //Calc windgustdir 257 | //Report the largest windgust today 258 | windgustmph = 0; 259 | windgustdir = 0; 260 | 261 | //Calc windspdmph_avg2m 262 | float temp = 0; 263 | for (int i = 0 ; i < 120 ; i++) 264 | temp += windspdavg[i]; 265 | temp /= 120.0; 266 | windspdmph_avg2m = temp; 267 | 268 | //Calc winddir_avg2m 269 | temp = 0; //Can't use winddir_avg2m because it's an int 270 | for (int i = 0 ; i < 120 ; i++) 271 | temp += winddiravg[i]; 272 | temp /= 120; 273 | winddir_avg2m = temp; 274 | 275 | //Calc windgustmph_10m 276 | //Calc windgustdir_10m 277 | //Find the largest windgust in the last 10 minutes 278 | windgustmph_10m = 0; 279 | windgustdir_10m = 0; 280 | //Step through the 10 minutes 281 | for (int i = 0; i < 10 ; i++) 282 | { 283 | if (windgust_10m[i] > windgustmph_10m) 284 | { 285 | windgustmph_10m = windgust_10m[i]; 286 | windgustdir_10m = windgustdirection_10m[i]; 287 | } 288 | } 289 | 290 | //Calc humidity 291 | humidity = myHumidity.readHumidity(); 292 | //float temp_h = myHumidity.readTemperature(); 293 | //Serial.print(" TempH:"); 294 | //Serial.print(temp_h, 2); 295 | 296 | //Calc tempf from pressure sensor 297 | tempf = myPressure.readTempF(); 298 | //Serial.print(" TempP:"); 299 | //Serial.print(tempf, 2); 300 | 301 | //Total rainfall for the day is calculated within the interrupt 302 | //Calculate amount of rainfall for the last 60 minutes 303 | rainin = 0; 304 | for (int i = 0 ; i < 60 ; i++) 305 | rainin += rainHour[i]; 306 | 307 | //Calc pressure 308 | pressure = myPressure.readPressure(); 309 | 310 | //Calc dewptf 311 | 312 | //Calc light level 313 | light_lvl = get_light_level(); 314 | 315 | //Calc battery level 316 | batt_lvl = get_battery_level(); 317 | 318 | } 319 | 320 | //Returns the voltage of the light sensor based on the 3.3V rail 321 | //This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) 322 | float get_light_level() 323 | { 324 | float operatingVoltage = analogRead(REFERENCE_3V3); 325 | 326 | float lightSensor = analogRead(LIGHT); 327 | 328 | operatingVoltage = 3.3 / operatingVoltage; //The reference voltage is 3.3V 329 | 330 | lightSensor = operatingVoltage * lightSensor; 331 | 332 | return (lightSensor); 333 | } 334 | 335 | //Returns the voltage of the raw pin based on the 3.3V rail 336 | //This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) 337 | //Battery level is connected to the RAW pin on Arduino and is fed through two 5% resistors: 338 | //3.9K on the high side (R1), and 1K on the low side (R2) 339 | float get_battery_level() 340 | { 341 | float operatingVoltage = analogRead(REFERENCE_3V3); 342 | 343 | float rawVoltage = analogRead(BATT); 344 | 345 | operatingVoltage = 3.30 / operatingVoltage; //The reference voltage is 3.3V 346 | 347 | rawVoltage = operatingVoltage * rawVoltage; //Convert the 0 to 1023 int to actual voltage on BATT pin 348 | 349 | rawVoltage *= 4.90; //(3.9k+1k)/1k - multiple BATT voltage by the voltage divider to get actual system voltage 350 | 351 | return (rawVoltage); 352 | } 353 | 354 | //Returns the instataneous wind speed 355 | float get_wind_speed() 356 | { 357 | float deltaTime = millis() - lastWindCheck; //750ms 358 | 359 | deltaTime /= 1000.0; //Covert to seconds 360 | 361 | float windSpeed = (float)windClicks / deltaTime; //3 / 0.750s = 4 362 | 363 | windClicks = 0; //Reset and start watching for new wind 364 | lastWindCheck = millis(); 365 | 366 | windSpeed *= 1.492; //4 * 1.492 = 5.968MPH 367 | 368 | /* Serial.println(); 369 | Serial.print("Windspeed:"); 370 | Serial.println(windSpeed);*/ 371 | 372 | return (windSpeed); 373 | } 374 | 375 | //Read the wind direction sensor, return heading in degrees 376 | int get_wind_direction() 377 | { 378 | unsigned int adc; 379 | 380 | adc = analogRead(WDIR); // get the current reading from the sensor 381 | 382 | // The following table is ADC readings for the wind direction sensor output, sorted from low to high. 383 | // Each threshold is the midpoint between adjacent headings. The output is degrees for that ADC reading. 384 | // Note that these are not in compass degree order! See Weather Meters datasheet for more information. 385 | 386 | if (adc < 380) return (113); 387 | if (adc < 393) return (68); 388 | if (adc < 414) return (90); 389 | if (adc < 456) return (158); 390 | if (adc < 508) return (135); 391 | if (adc < 551) return (203); 392 | if (adc < 615) return (180); 393 | if (adc < 680) return (23); 394 | if (adc < 746) return (45); 395 | if (adc < 801) return (248); 396 | if (adc < 833) return (225); 397 | if (adc < 878) return (338); 398 | if (adc < 913) return (0); 399 | if (adc < 940) return (293); 400 | if (adc < 967) return (315); 401 | if (adc < 990) return (270); 402 | return (-1); // error, disconnected? 403 | } 404 | 405 | 406 | //Prints the various variables directly to the port 407 | //I don't like the way this function is written but Arduino doesn't support floats under sprintf 408 | void printWeather() 409 | { 410 | calcWeather(); //Go calc all the various sensors 411 | 412 | Serial.println(); 413 | Serial.print("$,winddir="); 414 | Serial.print(winddir); 415 | Serial.print(",windspeedmph="); 416 | Serial.print(windspeedmph, 1); 417 | /*Serial.print(",windgustmph="); 418 | Serial.print(windgustmph, 1); 419 | Serial.print(",windgustdir="); 420 | Serial.print(windgustdir); 421 | Serial.print(",windspdmph_avg2m="); 422 | Serial.print(windspdmph_avg2m, 1); 423 | Serial.print(",winddir_avg2m="); 424 | Serial.print(winddir_avg2m); 425 | Serial.print(",windgustmph_10m="); 426 | Serial.print(windgustmph_10m, 1); 427 | Serial.print(",windgustdir_10m="); 428 | Serial.print(windgustdir_10m);*/ 429 | Serial.print(",humidity="); 430 | Serial.print(humidity, 1); 431 | Serial.print(",tempf="); 432 | Serial.print(tempf, 1); 433 | Serial.print(",rainin="); 434 | Serial.print(rainin, 2); 435 | Serial.print(",dailyrainin="); 436 | Serial.print(dailyrainin, 2); 437 | Serial.print(",pressure="); 438 | Serial.print(pressure, 2); 439 | Serial.print(",batt_lvl="); 440 | Serial.print(batt_lvl, 2); 441 | Serial.print(",light_lvl="); 442 | Serial.print(light_lvl, 2); 443 | 444 | Serial.print(",lat="); 445 | Serial.print(gps.location.lat(), 6); 446 | Serial.print(",lng="); 447 | Serial.print(gps.location.lng(), 6); 448 | Serial.print(",altitude="); 449 | Serial.print(gps.altitude.meters()); 450 | Serial.print(",sats="); 451 | Serial.print(gps.satellites.value()); 452 | 453 | char sz[32]; 454 | Serial.print(",date="); 455 | sprintf(sz, "%02d/%02d/%02d", gps.date.month(), gps.date.day(), gps.date.year()); 456 | Serial.print(sz); 457 | 458 | Serial.print(",time="); 459 | sprintf(sz, "%02d:%02d:%02d", gps.time.hour(), gps.time.minute(), gps.time.second()); 460 | Serial.print(sz); 461 | 462 | Serial.print(","); 463 | Serial.println("#"); 464 | 465 | } 466 | 467 | -------------------------------------------------------------------------------- /Firmware/Weather_Shield_Basic_V12/Weather_Shield_Basic_V12.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | Weather Shield Example 5 | By: Nathan Seidle 6 | SparkFun Electronics 7 | Date: June 10th, 2016 8 | License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). 9 | 10 | This example prints the current humidity, air pressure, temperature and light levels. 11 | 12 | The weather shield is capable of a lot. Be sure to checkout the other more advanced examples for creating 13 | your own weather station. 14 | 15 | Updated by Joel Bartlett 16 | 03/02/2017 17 | Removed HTU21D code and replaced with Si7021 18 | 19 | */ 20 | 21 | #include //I2C needed for sensors 22 | #include "SparkFunMPL3115A2.h" //Pressure sensor - Search "SparkFun MPL3115" and install from Library Manager 23 | #include "SparkFun_Si7021_Breakout_Library.h" //Humidity sensor - Search "SparkFun Si7021" and install from Library Manager 24 | 25 | MPL3115A2 myPressure; //Create an instance of the pressure sensor 26 | Weather myHumidity;//Create an instance of the humidity sensor 27 | 28 | //Hardware pin definitions 29 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 30 | const byte STAT_BLUE = 7; 31 | const byte STAT_GREEN = 8; 32 | 33 | const byte REFERENCE_3V3 = A3; 34 | const byte LIGHT = A1; 35 | const byte BATT = A2; 36 | 37 | //Global Variables 38 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 39 | long lastSecond; //The millis counter to see when a second rolls by 40 | 41 | void setup() 42 | { 43 | Serial.begin(115200); 44 | Serial.println("Weather Shield Example"); 45 | 46 | pinMode(STAT_BLUE, OUTPUT); //Status LED Blue 47 | pinMode(STAT_GREEN, OUTPUT); //Status LED Green 48 | 49 | pinMode(REFERENCE_3V3, INPUT); 50 | pinMode(LIGHT, INPUT); 51 | 52 | //Configure the pressure sensor 53 | myPressure.begin(); // Get sensor online 54 | myPressure.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa 55 | myPressure.setOversampleRate(7); // Set Oversample to the recommended 128 56 | myPressure.enableEventFlags(); // Enable all three pressure and temp event flags 57 | 58 | //Configure the humidity sensor 59 | myHumidity.begin(); 60 | 61 | lastSecond = millis(); 62 | 63 | Serial.println("Weather Shield online!"); 64 | } 65 | 66 | void loop() 67 | { 68 | //Print readings every second 69 | if (millis() - lastSecond >= 1000) 70 | { 71 | digitalWrite(STAT_BLUE, HIGH); //Blink stat LED 72 | 73 | lastSecond += 1000; 74 | 75 | //Check Humidity Sensor 76 | float humidity = myHumidity.getRH(); 77 | 78 | if (humidity == 998) //Humidty sensor failed to respond 79 | { 80 | Serial.println("I2C communication to sensors is not working. Check solder connections."); 81 | 82 | //Try re-initializing the I2C comm and the sensors 83 | myPressure.begin(); 84 | myPressure.setModeBarometer(); 85 | myPressure.setOversampleRate(7); 86 | myPressure.enableEventFlags(); 87 | myHumidity.begin(); 88 | } 89 | else 90 | { 91 | Serial.print("Humidity = "); 92 | Serial.print(humidity); 93 | Serial.print("%,"); 94 | float temp_h = myHumidity.getTempF(); 95 | Serial.print(" temp_h = "); 96 | Serial.print(temp_h, 2); 97 | Serial.print("F,"); 98 | 99 | //Check Pressure Sensor 100 | float pressure = myPressure.readPressure(); 101 | Serial.print(" Pressure = "); 102 | Serial.print(pressure); 103 | Serial.print("Pa,"); 104 | 105 | //Check tempf from pressure sensor 106 | float tempf = myPressure.readTempF(); 107 | Serial.print(" temp_p = "); 108 | Serial.print(tempf, 2); 109 | Serial.print("F,"); 110 | 111 | //Check light sensor 112 | float light_lvl = get_light_level(); 113 | Serial.print(" light_lvl = "); 114 | Serial.print(light_lvl); 115 | Serial.print("V,"); 116 | 117 | //Check batt level 118 | float batt_lvl = get_battery_level(); 119 | Serial.print(" VinPin = "); 120 | Serial.print(batt_lvl); 121 | Serial.print("V"); 122 | 123 | Serial.println(); 124 | } 125 | 126 | digitalWrite(STAT_BLUE, LOW); //Turn off stat LED 127 | } 128 | 129 | delay(100); 130 | } 131 | 132 | //Returns the voltage of the light sensor based on the 3.3V rail 133 | //This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) 134 | float get_light_level() 135 | { 136 | float operatingVoltage = analogRead(REFERENCE_3V3); 137 | 138 | float lightSensor = analogRead(LIGHT); 139 | 140 | operatingVoltage = 3.3 / operatingVoltage; //The reference voltage is 3.3V 141 | 142 | lightSensor = operatingVoltage * lightSensor; 143 | 144 | return (lightSensor); 145 | } 146 | 147 | //Returns the voltage of the raw pin based on the 3.3V rail 148 | //This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) 149 | //Battery level is connected to the RAW pin on Arduino and is fed through two 5% resistors: 150 | //3.9K on the high side (R1), and 1K on the low side (R2) 151 | float get_battery_level() 152 | { 153 | float operatingVoltage = analogRead(REFERENCE_3V3); 154 | 155 | float rawVoltage = analogRead(BATT); 156 | 157 | operatingVoltage = 3.30 / operatingVoltage; //The reference voltage is 3.3V 158 | 159 | rawVoltage = operatingVoltage * rawVoltage; //Convert the 0 to 1023 int to actual voltage on BATT pin 160 | 161 | rawVoltage *= 4.90; //(3.9k+1k)/1k - multiple BATT voltage by the voltage divider to get actual system voltage 162 | 163 | return (rawVoltage); 164 | } 165 | 166 | -------------------------------------------------------------------------------- /Firmware/Weather_Shield_Weather_Station_V12/Weather_Shield_Weather_Station_V12.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Weather Shield Example 3 | By: Nathan Seidle 4 | SparkFun Electronics 5 | Date: November 16th, 2013 6 | License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). 7 | 8 | Much of this is based on Mike Grusin's USB Weather Board code: https://www.sparkfun.com/products/10586 9 | 10 | This is a more advanced example of how to utilize every aspect of the weather shield. See the basic 11 | example if you're just getting started. 12 | 13 | This code reads all the various sensors (wind speed, direction, rain gauge, humidity, pressure, light, batt_lvl) 14 | and reports it over the serial comm port. This can be easily routed to a datalogger (such as OpenLog) or 15 | a wireless transmitter (such as Electric Imp). 16 | 17 | Measurements are reported once a second but windspeed and rain gauge are tied to interrupts that are 18 | calculated at each report. 19 | 20 | This example code assumes the GPS module is not used. 21 | 22 | Updated by Joel Bartlett 23 | 03/02/2017 24 | Removed HTU21D code and replaced with Si7021 25 | 26 | Updated be Wes Furuya 27 | 06/19/2023 28 | Implemented "Weather Meter" Arduino library 29 | */ 30 | 31 | #include //I2C needed for sensors 32 | #include "SparkFunMPL3115A2.h" //Pressure sensor - Search "SparkFun MPL3115" and install from Library Manager 33 | #include "SparkFun_Si7021_Breakout_Library.h" //Humidity sensor - Search "SparkFun Si7021" and install from Library Manager 34 | #include "SparkFun_Weather_Meter_Kit_Arduino_Library.h" //Weather meter kit - Search "SparkFun Weather Meter" and install from Library Manager 35 | 36 | 37 | //Hardware pin definitions 38 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 39 | // digital I/O pins 40 | const byte WSPEED = 3; 41 | const byte RAIN = 2; 42 | const byte STAT1 = 7; 43 | const byte STAT2 = 8; 44 | 45 | // analog I/O pins 46 | const byte REFERENCE_3V3 = A3; 47 | const byte LIGHT = A1; 48 | const byte BATT = A2; 49 | const byte WDIR = A0; 50 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 51 | 52 | //Global Variables 53 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 54 | long lastSecond; //The millis counter to see when a second rolls by 55 | 56 | float humidity = 0; // [%] 57 | float tempf = 0; // [temperature F] 58 | //float baromin = 30.03;// [barom in] - It's hard to calculate baromin locally, do this in the agent 59 | float pressure = 0; 60 | 61 | float wind_dir = 0; // [degrees (Cardinal)] 62 | float wind_speed = 0; // [kph] 63 | float rain = 0; // [mm] 64 | 65 | float batt_lvl = 11.8; //[analog value from 0 to 1023] 66 | float light_lvl = 455; //[analog value from 0 to 1023] 67 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 68 | 69 | 70 | MPL3115A2 myPressure; //Create an instance of the pressure sensor 71 | Weather myHumidity; //Create an instance of the humidity sensor 72 | SFEWeatherMeterKit myweatherMeterKit(WDIR, WSPEED, RAIN); // Create an instance of the weather meter kit 73 | 74 | 75 | void setup() { 76 | Serial.begin(115200); 77 | Serial.println("Weather Shield Example"); 78 | 79 | pinMode(STAT1, OUTPUT); //Status LED Blue 80 | pinMode(STAT2, OUTPUT); //Status LED Green 81 | 82 | // pinMode(WSPEED, INPUT_PULLUP); // input from wind meters windspeed sensor 83 | // pinMode(RAIN, INPUT_PULLUP); // input from wind meters rain gauge sensor 84 | 85 | pinMode(REFERENCE_3V3, INPUT); 86 | pinMode(LIGHT, INPUT); 87 | 88 | //Configure the pressure sensor 89 | myPressure.begin(); // Get sensor online 90 | myPressure.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa 91 | myPressure.setOversampleRate(7); // Set Oversample to the recommended 128 92 | myPressure.enableEventFlags(); // Enable all three pressure and temp event flags 93 | 94 | //Configure the humidity sensor 95 | myHumidity.begin(); 96 | 97 | // The weather meter kit library assumes a 12-bit ADC 98 | // Configuring a 10-bit ADC resolution for the ATmega328 (RedBoard/Uno) 99 | myweatherMeterKit.setADCResolutionBits(10); 100 | 101 | // Begin weather meter kit 102 | myweatherMeterKit.begin(); 103 | 104 | lastSecond = millis(); 105 | 106 | // // attach external interrupt pins to IRQ functions 107 | // attachInterrupt(0, rainIRQ, FALLING); 108 | // attachInterrupt(1, wspeedIRQ, FALLING); 109 | 110 | // // turn on interrupts 111 | // interrupts(); 112 | 113 | Serial.println("Weather Shield online!"); 114 | } 115 | 116 | void loop() { 117 | //Keep track of which minute it is 118 | if (millis() - lastSecond >= 1000) { 119 | digitalWrite(STAT1, HIGH); //Blink stat LED 120 | 121 | lastSecond += 1000; 122 | 123 | //Report all readings every second 124 | printWeather(); 125 | } 126 | 127 | digitalWrite(STAT1, LOW); //Turn off stat LED 128 | 129 | delay(100); 130 | } 131 | 132 | //Calculates each of the variables that wunderground is expecting 133 | void calcWeather() { 134 | 135 | //Calc temp/humidity from Si7021 sensor 136 | humidity = myHumidity.getRH(); 137 | tempf = myHumidity.readTempF(); 138 | 139 | //Weather Meter Kit 140 | //Calc Wind 141 | wind_dir = myweatherMeterKit.getWindDirection(); 142 | wind_speed = myweatherMeterKit.getWindSpeed(); 143 | //Calc Rain 144 | rain = myweatherMeterKit.getTotalRainfall(); 145 | 146 | //Calc pressure from MPL3115A2 147 | pressure = myPressure.readPressure(); 148 | 149 | //Calc light level 150 | light_lvl = get_light_level(); 151 | 152 | //Calc battery level 153 | batt_lvl = get_battery_level(); 154 | } 155 | 156 | //Returns the voltage of the light sensor based on the 3.3V rail 157 | //This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) 158 | float get_light_level() { 159 | float operatingVoltage = analogRead(REFERENCE_3V3); 160 | 161 | float lightSensor = analogRead(LIGHT); 162 | 163 | operatingVoltage = 3.3 / operatingVoltage; //The reference voltage is 3.3V 164 | 165 | lightSensor = operatingVoltage * lightSensor; 166 | 167 | return (lightSensor); 168 | } 169 | 170 | //Returns the voltage of the raw pin based on the 3.3V rail 171 | //This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) 172 | //Battery level is connected to the RAW pin on Arduino and is fed through two 5% resistors: 173 | //3.9K on the high side (R1), and 1K on the low side (R2) 174 | float get_battery_level() { 175 | float operatingVoltage = analogRead(REFERENCE_3V3); 176 | 177 | float rawVoltage = analogRead(BATT); 178 | 179 | operatingVoltage = 3.30 / operatingVoltage; //The reference voltage is 3.3V 180 | 181 | rawVoltage = operatingVoltage * rawVoltage; //Convert the 0 to 1023 int to actual voltage on BATT pin 182 | 183 | rawVoltage *= 4.90; //(3.9k+1k)/1k - multiple BATT voltage by the voltage divider to get actual system voltage 184 | 185 | return (rawVoltage); 186 | } 187 | 188 | 189 | //Prints the various variables directly to the port 190 | //I don't like the way this function is written but Arduino doesn't support floats under sprintf 191 | void printWeather() { 192 | calcWeather(); //Go calc all the various sensors 193 | 194 | Serial.println(); 195 | Serial.print("humidity="); 196 | Serial.print(humidity, 1); 197 | Serial.print(" %RH, tempf="); 198 | Serial.print(tempf, 1); 199 | Serial.print(" F, pressure="); 200 | Serial.print(pressure, 2); 201 | Serial.print(" Pa, wind direction= "); 202 | Serial.print(wind_dir, 1); 203 | Serial.print(" deg, wind speed= "); 204 | Serial.print(wind_speed, 1); 205 | Serial.print(" kph, total rain= "); 206 | Serial.print(rain, 1); 207 | Serial.print(" mm, batt_lvl="); 208 | Serial.print(batt_lvl, 2); 209 | Serial.print(" V, light_lvl="); 210 | Serial.print(light_lvl, 2); 211 | Serial.print(","); 212 | Serial.println("#"); 213 | } 214 | -------------------------------------------------------------------------------- /Firmware/Weather_Shield_with_GPS_V12/Weather_Shield_with_GPS_V12.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Weather Shield Example 3 | By: Nathan Seidle 4 | SparkFun Electronics 5 | Date: November 16th, 2013 6 | License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). 7 | 8 | Much of this is based on Mike Grusin's USB Weather Board code: https://www.sparkfun.com/products/10586 9 | 10 | This code reads all the various sensors (wind speed, direction, rain gauge, humidity, pressure, light, batt_lvl, GPS data) 11 | and reports it over the serial comm port. This can be easily routed to a datalogger (such as OpenLog) or 12 | a wireless transmitter (such as Electric Imp). 13 | 14 | Measurements are reported once a second. The windspeed and rain gauge are tied to interrupts and are 15 | calculated at the instance of each report. 16 | 17 | This example code assumes the GP-735 GPS module is attached. 18 | 19 | Updated by Joel Bartlett 20 | 03/02/2017 21 | Removed HTU21D code and replaced with Si7021 22 | 23 | Updated be Wes Furuya 24 | 06/19/2023 25 | Implemented "Weather Meter" Arduino library 26 | Updated to TinyGPSPlus Arduino library 27 | */ 28 | 29 | #include //I2C needed for sensors 30 | #include "SparkFunMPL3115A2.h" //Pressure sensor - Search "SparkFun MPL3115" and install from Library Manager 31 | #include "SparkFun_Si7021_Breakout_Library.h" //Humidity sensor - Search "SparkFun Si7021" and install from Library Manager 32 | #include "SparkFun_Weather_Meter_Kit_Arduino_Library.h" //Weather meter kit - Search "SparkFun Weather Meter" and install from Library Manager 33 | #include //Needed for GPS 34 | #include //Parsing GPS data - Available through the Library Manager. 35 | 36 | 37 | //Hardware pin definitions 38 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 39 | // digital I/O pins 40 | const byte WSPEED = 3; 41 | const byte RAIN = 2; 42 | const byte STAT1 = 7; 43 | const byte STAT2 = 8; 44 | // const byte GPS_PWRCTL = 6; //Pulling this pin low puts GPS to sleep but maintains RTC and RAM 45 | static const int RXPin = 5, TXPin = 4; //GPS is attached to pin 4(TX from GPS) and pin 5(RX into GPS) 46 | static const uint32_t GPSBaud = 9600; // Default baud rate of the GP-735 GPS module 47 | 48 | 49 | // analog I/O pins 50 | const byte REFERENCE_3V3 = A3; 51 | const byte LIGHT = A1; 52 | const byte BATT = A2; 53 | const byte WDIR = A0; 54 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 55 | 56 | //Global Variables 57 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 58 | long lastSecond; //The millis counter to see when a second rolls by 59 | long lastChars = 0; //Character counter for GPS parsing 60 | 61 | float humidity = 0; // [%] 62 | float tempf = 0; // [temperature F] 63 | //float baromin = 30.03;// [barom in] - It's hard to calculate barom in locally, do this in the agent 64 | float pressure = 0; 65 | 66 | float wind_dir = 0; // [degrees (Cardinal)] 67 | float wind_speed = 0; // [kph] 68 | float rain = 0; // [mm] 69 | 70 | float batt_lvl = 11.8; //[analog value from 0 to 1023] 71 | float light_lvl = 455; //[analog value from 0 to 1023] 72 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 73 | 74 | 75 | MPL3115A2 myPressure; //Create an instance of the pressure sensor 76 | Weather myHumidity; //Create an instance of the humidity sensor 77 | SFEWeatherMeterKit myweatherMeterKit(WDIR, WSPEED, RAIN); // Create an instance of the weather meter kit 78 | 79 | TinyGPSPlus gps; 80 | SoftwareSerial ss(RXPin, TXPin); 81 | 82 | 83 | void setup() { 84 | Serial.begin(115200); 85 | ss.begin(GPSBaud); 86 | 87 | Serial.println("Weather Shield Example"); 88 | 89 | pinMode(STAT1, OUTPUT); //Status LED Blue 90 | pinMode(STAT2, OUTPUT); //Status LED Green 91 | 92 | // pinMode(GPS_PWRCTL, OUTPUT); 93 | // digitalWrite(GPS_PWRCTL, HIGH); //Pulling this pin low puts GPS to sleep but maintains RTC and RAM 94 | 95 | pinMode(REFERENCE_3V3, INPUT); 96 | pinMode(LIGHT, INPUT); 97 | 98 | //Configure the pressure sensor 99 | myPressure.begin(); // Get sensor online 100 | myPressure.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa 101 | myPressure.setOversampleRate(7); // Set Oversample to the recommended 128 102 | myPressure.enableEventFlags(); // Enable all three pressure and temp event flags 103 | 104 | //Configure the humidity sensor 105 | myHumidity.begin(); 106 | 107 | // The weather meter kit library assumes a 12-bit ADC 108 | // Configuring a 10-bit ADC resolution for the ATmega328 (RedBoard/Uno) 109 | myweatherMeterKit.setADCResolutionBits(10); 110 | 111 | // Begin weather meter kit 112 | myweatherMeterKit.begin(); 113 | 114 | lastSecond = millis(); 115 | 116 | Serial.println("Weather Shield online!"); 117 | } 118 | 119 | void loop() { 120 | //Keep track of which minute it is 121 | if (millis() - lastSecond >= 1000) { 122 | lastSecond += 1000; 123 | //Report all readings every second 124 | printWeather(); 125 | 126 | // Report GPS Data 127 | printGPS(); 128 | 129 | Serial.print(","); 130 | Serial.println("#"); 131 | } 132 | 133 | } 134 | 135 | 136 | void printGPS() { 137 | lastChars = gps.charsProcessed(); 138 | 139 | while (millis() - lastSecond < 900) { 140 | //If data is available, parse out the information 141 | if (ss.available() > 0) { 142 | gps.encode(ss.read()); 143 | 144 | // Check if GPS data was updated 145 | if (gps.location.isUpdated() && gps.date.isUpdated() && gps.time.isUpdated()) { 146 | digitalWrite(STAT2, HIGH); //Turn on stat LED (Green) 147 | 148 | // Check if all data is valid 149 | // if (gps.location.isValid() && gps.date.isValid() && gps.time.isValid()) { 150 | // digitalWrite(STAT2, HIGH); //Turn on stat LED (Green) 151 | // } 152 | 153 | break; 154 | } 155 | 156 | else { 157 | digitalWrite(STAT2, LOW); //Turn off stat LED 158 | } 159 | } 160 | } 161 | 162 | //Prints error message if not data has been receiver from the GPS module 163 | if (gps.charsProcessed() - lastChars < 10) { 164 | Serial.println(); 165 | Serial.println(F("No GPS data: check wiring/switch.")); 166 | digitalWrite(STAT2, LOW); //Turn off stat LED 167 | } 168 | 169 | parseGPS(); 170 | } 171 | 172 | 173 | void parseGPS() { 174 | 175 | if (gps.location.isValid()) { 176 | Serial.print(", lat="); 177 | Serial.print(gps.location.lat(), 6); 178 | Serial.print(", lng="); 179 | Serial.print(gps.location.lng(), 6); 180 | Serial.print(", altitude="); 181 | Serial.print(gps.altitude.meters()); 182 | Serial.print(", sats="); 183 | Serial.print(gps.satellites.value()); 184 | } else { 185 | Serial.print(F(", Location=INVALID")); 186 | } 187 | 188 | Serial.print(", date="); 189 | if (gps.date.isValid()) { 190 | Serial.print(gps.date.month()); 191 | Serial.print(F("/")); 192 | Serial.print(gps.date.day()); 193 | Serial.print(F("/")); 194 | Serial.print(gps.date.year()); 195 | } else { 196 | Serial.print(F("INVALID")); 197 | } 198 | 199 | Serial.print(", time="); 200 | if (gps.time.isValid()) { 201 | if (gps.time.hour() < 10) Serial.print(F("0")); 202 | Serial.print(gps.time.hour()); 203 | Serial.print(F(":")); 204 | if (gps.time.minute() < 10) Serial.print(F("0")); 205 | Serial.print(gps.time.minute()); 206 | Serial.print(F(":")); 207 | if (gps.time.second() < 10) Serial.print(F("0")); 208 | Serial.print(gps.time.second()); 209 | Serial.print(F(".")); 210 | if (gps.time.centisecond() < 10) Serial.print(F("0")); 211 | Serial.print(gps.time.centisecond()); 212 | Serial.print(" (GMT)"); 213 | } else { 214 | Serial.print(F("INVALID")); 215 | } 216 | } 217 | 218 | //Calculates each of the weather variables 219 | void calcWeather() { 220 | 221 | //Calc temp/humidity from Si7021 sensor 222 | humidity = myHumidity.getRH(); 223 | tempf = myHumidity.readTempF(); 224 | 225 | //Weather Meter Kit 226 | //Calc Wind 227 | wind_dir = myweatherMeterKit.getWindDirection(); 228 | wind_speed = myweatherMeterKit.getWindSpeed(); 229 | //Calc Rain 230 | rain = myweatherMeterKit.getTotalRainfall(); 231 | 232 | //Calc pressure from MPL3115A2 233 | pressure = myPressure.readPressure(); 234 | 235 | //Calc light level 236 | light_lvl = get_light_level(); 237 | 238 | //Calc battery level 239 | batt_lvl = get_battery_level(); 240 | } 241 | 242 | //Returns the voltage of the light sensor based on the 3.3V rail 243 | //This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) 244 | float get_light_level() { 245 | float operatingVoltage = analogRead(REFERENCE_3V3); 246 | 247 | float lightSensor = analogRead(LIGHT); 248 | 249 | operatingVoltage = 3.3 / operatingVoltage; //The reference voltage is 3.3V 250 | 251 | lightSensor = operatingVoltage * lightSensor; 252 | 253 | return (lightSensor); 254 | } 255 | 256 | //Returns the voltage of the raw pin based on the 3.3V rail 257 | //This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) 258 | //Battery level is connected to the RAW pin on Arduino and is fed through two 5% resistors: 259 | //3.9K on the high side (R1), and 1K on the low side (R2) 260 | float get_battery_level() { 261 | float operatingVoltage = analogRead(REFERENCE_3V3); 262 | 263 | float rawVoltage = analogRead(BATT); 264 | 265 | operatingVoltage = 3.30 / operatingVoltage; //The reference voltage is 3.3V 266 | 267 | rawVoltage = operatingVoltage * rawVoltage; //Convert the 0 to 1023 int to actual voltage on BATT pin 268 | 269 | rawVoltage *= 4.90; //(3.9k+1k)/1k - multiple BATT voltage by the voltage divider to get actual system voltage 270 | 271 | return (rawVoltage); 272 | } 273 | 274 | 275 | //Prints the weather variables directly to the port 276 | //I don't like the way this function is written but Arduino doesn't support floats under sprintf 277 | void printWeather() { 278 | calcWeather(); //Go calc all the various sensors 279 | 280 | digitalWrite(STAT1, HIGH); //Blink stat LED (Blue) 281 | 282 | Serial.println(); 283 | Serial.print("humidity="); 284 | Serial.print(humidity, 1); 285 | Serial.print(" %RH, tempf="); 286 | Serial.print(tempf, 1); 287 | Serial.print(" F, pressure="); 288 | Serial.print(pressure, 2); 289 | Serial.print(" Pa, wind direction= "); 290 | Serial.print(wind_dir, 1); 291 | Serial.print(" deg, wind speed= "); 292 | Serial.print(wind_speed, 1); 293 | Serial.print(" kph, total rain= "); 294 | Serial.print(rain, 1); 295 | Serial.print(" mm, batt_lvl="); 296 | Serial.print(batt_lvl, 2); 297 | Serial.print(" V, light_lvl="); 298 | Serial.print(light_lvl, 2); 299 | 300 | digitalWrite(STAT1, LOW); //Blink stat LED 301 | } 302 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | SparkFun License Information 2 | ============================ 3 | 4 | SparkFun uses two different licenses for our files — one for hardware and one for code. 5 | 6 | Hardware 7 | --------- 8 | 9 | **SparkFun hardware is released under [Creative Commons Share-alike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/).** 10 | 11 | Note: This is a human-readable summary of (and not a substitute for) the [license](http://creativecommons.org/licenses/by-sa/4.0/legalcode). 12 | 13 | You are free to: 14 | 15 | Share — copy and redistribute the material in any medium or format 16 | Adapt — remix, transform, and build upon the material 17 | for any purpose, even commercially. 18 | The licensor cannot revoke these freedoms as long as you follow the license terms. 19 | Under the following terms: 20 | 21 | Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 22 | ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. 23 | No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits. 24 | Notices: 25 | 26 | You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation. 27 | No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material. 28 | 29 | 30 | Code 31 | -------- 32 | 33 | **SparkFun code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT).** 34 | 35 | The MIT License (MIT) 36 | 37 | Copyright (c) 2015 SparkFun Electronics 38 | 39 | Permission is hereby granted, free of charge, to any person obtaining a copy 40 | of this software and associated documentation files (the "Software"), to deal 41 | in the Software without restriction, including without limitation the rights 42 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 43 | copies of the Software, and to permit persons to whom the Software is 44 | furnished to do so, subject to the following conditions: 45 | 46 | The above copyright notice and this permission notice shall be included in all 47 | copies or substantial portions of the Software. 48 | 49 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 50 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 51 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 52 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 53 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 54 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 55 | SOFTWARE. 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SparkFun Weather Shield 2 | ======================== 3 | 4 | [![SparkFun Weather Shield](https://cdn.sparkfun.com/assets/learn_tutorials/6/2/6/Arduino_Weather_Shield3.jpg)](https://www.sparkfun.com/products/13956) 5 | 6 | [*SparkFun Weather Shield (DEV-13956)*](https://www.sparkfun.com/products/13956) 7 | 8 | Weather Shield is an Arduino shield that gathers relative humidity, barometric pressure, temperature, light intensity, as well as optional rain, wind direction, and wind speed (using optional [external weather gauges](https://www.sparkfun.com/products/8942)). 9 | 10 | Repository Contents 11 | ------------------ 12 | 13 | * **/Firmware** - Example Arduino sketch to demostrate how to read from the various sensors. 14 | * **/Fritzing** - Fritzing Example wiring images 15 | * **/Hardware** - All the Eagle PCB design files (.brd, .sch). 16 | * **/Production** - Test bed files and production panel files 17 | 18 | Documentation 19 | -------------- 20 | * **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library. 21 | * **[MPL3115A2 Library](https://github.com/sparkfun/SparkFun_MPL3115A2_Breakout_Arduino_Library)** - MPL3115A2 library required for Weather Shield examples. 22 | * **[Si7021 Library](https://github.com/sparkfun/SparkFun_Si701_Breakout_Arduino_Library)** - Si7021 humidity sensor library required for Weather Shield examples. 23 | * **[Hookup Guide](https://learn.sparkfun.com/tutorials/arduino-weather-shield-hookup-guide-v12)** - Basic hookup guide for the Weather Shield v1.2. 24 | * **[SparkFun Fritzing repo](https://github.com/sparkfun/Fritzing_Parts)** - Fritzing diagrams for SparkFun products. 25 | * **[SparkFun 3D Model repo](https://github.com/sparkfun/3D_Models)** - 3D models of SparkFun products. 26 | * _**[HTU21D Library](https://github.com/sparkfun/SparkFun_HTU21D_Breakout_Arduino_Library)** - The HTU21D humidity sensor was used on DEV-12081 and prior versions of the Weather Shield so if you have an older version you may need this library to run the examples._ 27 | 28 | Product Versions 29 | ---------------- 30 | * [DEV-13956](https://www.sparkfun.com/products/13956)- V1.2 w/ Si7021 31 | * _[DEV-12081 (Retired)](https://www.sparkfun.com/products/13956)- HTU21D_ 32 | 33 | Version History 34 | --------------- 35 | * [v1.2](https://github.com/sparkfun/Weather_Shield/releases/tag/v1.2) - Latest Version 36 | * [v1.1](https://github.com/sparkfun/Weather_Shield/releases/tag/v1.1) - Initial Release 37 | 38 | License Information 39 | ------------------- 40 | 41 | This product is _**open source**_! 42 | 43 | Please review the LICENSE.md file for license information. 44 | 45 | If you have any questions or concerns on licensing, please contact techsupport@sparkfun.com. 46 | 47 | Distributed as-is; no warranty is given. 48 | 49 | - Your friends at SparkFun. 50 | --------------------------------------------------------------------------------