Software apps and online services
Why another DIY weather station? I wanted to make a durable, weatherproof, accurate, and reliable weather station. There didn't seem to be any existing projects that meet all these criteria so here's my version!
I'm sure my code and circuits can be improved for performance and power usage, feel free to suggest something! And comments are welcome for anything else.
To begin, we need to review basic weather monitoring principles. The data we collect can only be as accurate as the local conditions the station is in. So the most important factor is situating the station in the proper location. I'll quote from a government guideline document:
- Should be placed on a patch of level ground, over a surface representative of the area.
- Should be mounted in a ventilated radiation shield.
- Height between 4’ 1” and 6’ 7” above ground (1.25 – 2.0 m)
- Place sensors at a horizontal distance of 2 times the height of the nearest object (tree, structure, etc)
- Keep away from other sources of heat such as chimneys, air vents, air conditioners, etc.
For wind and rain sensor placement, the horizontal distance is 10 and 4 times the height of the nearest obstruction. Knowing that I will not have anything close to those conditions, I decided to measure only temperature, humidity, and pressure. However, I've designed this project to be able to accommodate additional sensors at a later time.
I knew I needed to design a robust enclosure for all the components, select the proper off the shelf components where applicable, design auxiliary circuits, and program the integration with Weather Underground. It was important that the finished product look and feel professional as well. I'll walk through the design decisions for each component. I had already decided on the Particle Photon due to its ease of use and built in cloud connectivity.
Keep in mind that although this was the rough order of design, most components had to be designed/selected simultaneously, considering the whole system and integration.
The largest component in the project is the radiation shield, because it houses everything inside except the solar panel. I quickly realized a 3D printed component of that size range would be prohibitively expensive, and of lower quality than an injection molded plastic. Therefore a commercial off the shelf component was selected, based on size (it has to be big enough to fit the particle photon at the very least), material (white molded plastic), and cost: the La Crosse Technology 925-1418 Sensor Protection Shield with Mount.
After receiving the radiation shield, I took measurements of relevant dimensions and those determined the size of the sensor and microcontroller enclosure.
I selected the BME280 as a robust, accurate, and reasonably priced sensor. Both Adafruit and Sparkfun make breakouts for this sensor; I went with Sparkfun.
The ventilation fan had to fit inside the cylindrical inner diameter of the radiation shield. The fan should run off the same voltage as the Particle Photon for efficiency. I also targeted something that drew less than 500mA as a starting point. Weatherproofing was also important so in the end I selected an IP57 brushless fan at 5V drawing 220mA: Mechatronics Fan Group G4020M05B-RSR-EM.
Outdoor circuits should be protected from moisture, sunlight, and temperature extremes. However, there obviously are components which need to be exposed to a certain degree: the solar panel, ventilation fan, and the environmental sensor. The particle photon, battery, secondary circuits (battery measurement, solar charger, etc.) need to be protected in a separate enclosure.
Initially several commercial weatherproof electrical junction boxes were considered, but none of them had the exact form factor required, and in addition, it would ultimately look "hacked" together. I decided to design a 3D printed part for the enclosure. Knowing that the part would need tight tolerances for a o-ring seal, I selected SLA (stereolithography) as the process due to its high resolution and small minimum feature size.
There are two main ways moisture can penetrate the enclosure: water vapor transmission (WVTR) through the walls, and leak paths through the seals.
There are many materials for SLA, but Nylon 6 or 12 is common and cheap. Acrylic also produces good prints but is over twice as expensive. The downside to Nylon is that it has a huge WVTR compared to acrylic, and I was skeptical that over the course of a year that even 2mm wall thickness would have slow enough water vapor diffusion. With the semi-granular nature of the STL printing process, there is even more risk. My solution was to coat all surfaces exposed to the outside with an acrylic spray.
For the o-ring seal, I selected one made from EPDM, a polymer commonly used in water based applications. It is highly resistant to water vapor transmission and does not swell through immersion in water. I used a silicone o-ring lubricant to help create a better seal by closing micro gaps. It's important to pay attention to the type of lubricant because some formulations may attack either the EPDM or the nylon of the enclosure.
To apply sealing pressure to the o-ring, I designed a four bolt pattern at the corners of the enclosure, which creates a highly uneven pressure distribution along the length of the o-ring, but still seems to do enough in this application. In a high performance sealing application I would definitely select a stiffer material for the enclosure to correct that problem.
How should wires pass through the enclosure? The components which are designed to be permanently attached (fan and sensor board) are passed through holes, and then sealed with epoxy.
For the solar panel wires, I used a 4 wire connector with an o-ring so that the inside enclosure can be separated from the radiation shield. This leaves two wires to make the station expandable in the future (extra sensor, etc).
To absorb the moisture that does leak into the enclosure, as well as the residual moisture trapped during assembly, I sourced a desiccant pack which has a capacity big enough the dehumidify the enclosed volume, which is about 6.7 cubic inches.
Once sealed, after 11 days outside there was no color change in a color-change desiccant. This indicates that there are no major leak paths.
I also sprayed the radiation shield with water, while a color changing powder (white to green) was applied to a paper towel roll placed inside. Surprisingly, no droplets made their way inside!
The biggest reliability risk to the exposed sensor is condensation. If the enclosure with the sensor was exposed directly to the atmosphere and sky, there would be condensation on many nights. Why is that? It's the same principle that causes condensation on cars parked outside without a covering, for example.
Condensation occurs when the temperature of an object is lower than the dew point (saturation temperature of air with water vapor). Radiative cooling is a factor that can exacerbate condensation problems.
As seen in the image above, radiative cooling occurs when radiation from the earth's surface is greater than the downwards radiation coming from the open sky and clouds (if present). Clouds emit radiation which counterbalance the radiation lost from Earth's surface, resulting in less cooling. Taking this one step further, adding an enclosure which acts as a barrier to infrared radiation will limit the amount of emitted radiation which is lost to the open sky drastically. Without radiation losses to the sky, the sensor will equalize with the ambient air temperature, leading to more accurate readings and hopefully, reduced condensation.
To utilize solar panels efficiently, we need to regulate the current draw to prevent voltage collapse. I chose to use an off the shelf component from Adafruit as it is reasonably priced and had the form factor needed: USB / DC / Solar Lithium Ion/Polymer charger - v2. I followed the excellent build instructions from Adafruit, making sure to solder in the thermresistor for over/under temperature protection. In addition, I desoldered the barrel jack which was too bulky to fit in the enclosure properly. This solar charger uses a voltage tracking circuit that targets 4.5V, so as long as the solar panel's maximum power point is reasonably close to that, it will be efficient enough.
Battery Management circuits
There's a great blog post about low power voltage measurements, which I used to create two measurement circuits on the high side which draw no current when "off" (using a ePMOS and a RC circuit). The transistors in these circuits were chosen One circuit measures the battery voltage, and the other measures the solar panel voltage. The high current draw devices (fan, etc.) are only allowed to turn on if the solar panel is charging the battery. This ensures that power is managed conservatively-- in addition, the fan is needed to ventilate the enclosure when it is heated by the sun, so if the sun is not shining, the solar panel is not charging the battery, and the fan is not needed anyways!
Fan Speed Circuit
The fan is controlled through a low side eNMOS circuit with flyback Schottky diode for inductive voltage spike protection (Schottky selected due to fast PWM switching). The brushless fan did not need extra capacitors to filter out high frequency noise, but needs the diode to prevent very high voltage spikes. Even with the diode in place, spikes reached 32V after the motor current was cut (MOSFET Vmax = 40V). I measured this with long wires connecting stuff together on a breadboard, and with a mechanical switch. With a MOSFET's slower transition time and less inductance on the PCB, I expect these spikes to decrease even further (todo!). For now, there seems to be no damage to the circuits.
The Adafruit solar charger outputs roughly 4V from the lithium ion battery when fully charged, and up to 7V from the solar panel via its passthrough feature. On the other end of the range, when the sun is not out and the battery is at low capacity, the voltage could be closer to 3.5V. This is outside the range of the onboard 5V -> 3.3V regulator on the Particle Photon, so an external power supply was needed, which would power both the Photon and the fan. I selected the Pololu 5V Step-Up/Step-Down Voltage Regulator S7V7F5, which operates in the range of 2.7V to 11.8V and is about 90% efficient with minimum 500mA output current capability.
See the linked Github project for my code. I use the Sparkfun BME280 library from Markus Haack (https://github.com/mhaack).
The Photon spends most of its time in sleep mode to save power. On each wakeup, the main loop() runs once.
- Checks the last time a reset occurred and if greater than 1 week, resets the Photon. I was running into a hanging issue after about 11 days of runtime so hopefully this clears whatever errors are accumulating.
- If the solar panel is providing enough power to charge the battery, the fan is run for 50 sec and then the sensor is queried. Why 50sec? See section below. If the solar panel is not providing enough power to charge, don't run the fan and just take a sensor reading.
- The battery voltage is checked with WiFi off. Note: voltage is checked while the battery is under lower load than if it is transmitting data over WiFi. So this method is only a rough estimate. If a reference current sink circuit was implemented, this could improve accuracy.
- Running the fan motor also checks the battery voltage during runtime as a rough check of remaining battery capacity-- if it's 3.3V or less, the Photon goes into sleep for a long time (hopefully this would be a red flag to whoever is looking at the Weather Underground data). Why 3.3V? See battery section.
- The fan PWM duty cycle was were chosen to keep current draw at a reasonable level. Of course the frequency needs to be high enough so that the motor effectively averages out the input square wave signal. Note also that the MOSFET controlling the motor power uses more current as the PWM frequency increases (due to charge/discharge of gate capacitance).
- The sensor measurement is compared to the previous one. To save power, WiFi and data upload is only activated if the measurement is different by a chosen threshold amount.
- If WiFi times out, the Photon goes back to sleep.
- Data is published to a Webhook in the Particle Cloud. See Webhook section.
- Photon waits for publish success or timeout before going to sleep.
Humidity and pressure don't change very much between fan on and off. However, temperature does. I took measurements every 5 seconds for 1 min while the station was in direct sunlight and partial shade with low wind (at least 10 minute wait time in between measurements):
Each line is a time series of measurements from 0 being fan off to 60 seconds on. There's four scenarios for temperature:  decreases quickly and then levels off,  continuously decreases,  minor change,  increase in temperature. I removed 3 and 4 to focus on the ones most likely caused by radiation shield overheating. Because in the above graph it is difficult to determine rate of change, I plotted the difference from one period to the next:
Bit of an eye chart but around the 10th period, or 50 seconds, most of the lines are leveling off.
Most of this excessive heating inside the enclosure is due to radiation being absorbed or transmitted by the plastic radiation shield and then heating the interior. To understand how to counteract this, let's take a look at the solar spectrum:
We can see that the radiation at sea level, the red curve, has the highest irradiance in the visible range. However, the infrared range, although being lower in energy per wavelength, covers more wavelengths. Outside the atmosphere, about 46% of energy is visible, and 46% infrared. Once the atmosphere scatters and absorbs selectively, the direct radiation is 45% to 64% infrared, with visible being the balance. Diffuse radiation is about 75% visible.
What does this mean? Overall, roughly half of radiation impinging on the radiation shield is infrared, and half is visible. Both sections of the spectrum contribute to heating, and the reflectance of the surface determines the amount of heating.
From our analysis of the spectrum, it's clear that to reduce radiation absorption and transmittance, we must make the surface as reflective as possible in both the visible and infrared ranges.
A surface that is equally reflective across the visible spectrum looks white to our eyes (note that Emissivity + Reflectivity = 1). We can't see the reflectance in the IR spectrum without using equipment. Luckily, this is an active area of research and there's plenty of data available.
In Fig. 8 we see from the "standard TiO2 loading over white" that it's highly reflective in visible and near-infrared. It's not reflective in UV, but UV energy is less than 5% of the total, so that's a minor concern. The next figure shows that carbon black absorbs nearly everything over a very wide range of wavelengths. This also means that it will emit well over those wavelengths.
We should paint the radiation shield with a reflective coating to limit the amount of absorbed or transmitted radiation. Titanium dioxide is one of the standard pigments used to make paints white, so I'll choose a spray paint using TiO2.
I tested a piece of plastic from the actual radiation shield by painting half of it white. Leaving it out in direct sunshine for 15 min, the painted side measured 3 to 5 degrees F cooler than the unpainted side! (using an IR thermometer measuring the opposite side).
With the entire shield spray painted, I expect this coating to keep the enclosure a little bit cooler in intense sunshine.
The Webhooks make it very easy to publish to weather underground. Create a new webhook and fill out the fields as shown, using the station ID and password that is created on the weather underground website:
The battery needs to be rechargeable, produce between 3.3V and 5V at expected current draw (to keep the power supply operating in an efficient range), have a form factor that fits in the enclosure, and have capacity large enough to keep the station running for a week without solar charging.
Lithium Ion is rechargeable and has nominal 3.7V with high (>1A) current draws. The form factor of 18350 is a perfect size for the enclosure, and contains roughly 900mAh.
I chose a protected cell so that I don't have to worry about over-discharging the battery: Efest 18350 900mAh Battery - Protected Flat Top.
To determine true capacity, I measured the battery during a constant 400mA discharge. Because the expected max current draw is around 300mA, this is conservative.
Looks good up until about 3.3V, where the output voltage starts collapsing. That's why I set the low battery check at 3.3V. Again, this is a conservative value because this is at a current draw of 400mA, while the check occurs at probably less than 25% of that. The total battery capacity is at least 2.9Wh or 800mAh.
Is this good enough to power the station for 1 week without external power?
Using a ee-203 current monitor, which plots current as i=10^(-V), the following graphs were obtained (3.7V from bench supply):
The following table lists the energy usage for the various ways one measurement cycle can be completed.
Note the 3.2mA for the sleep current draw. This seems pretty high for a deep sleep mode! Further investigation is needed to find out what is causing this current drain (floating GIPO? leakage from caps? secondary circuit left powered on? something in the software? Leave ideas in the comments, please!).
With the fan on, we use 56mA (wifi off) to 524mA (fan PWM high), with 10 ms period, 50% duty cycle. The average is therefore 262mA over the 50s the fan is on. However, the fan only turns on when the solar panel is charging the battery, so I assume the energy flow into the system is overall positive, and this high current draw will not be an issue.
With a 2.9Wh battery, we have 10, 440J of energy. Using P=IV, the 3.2mA in sleep mode at nominal 3.7V is 0.01184W. I calculated the appropriate sleep time between measurements assuming we need 7 days (604, 800s) without charging, and that a cloud connection takes place every measurement. This is conservative because the code allows for the station to avoid connecting if the measured values are similar to the previous one.
(604800/x)*(0.01184*(x-7.64)+3.79) = 10440
x= 682s = 11 min 22s
I set the sleep time to 12 minutes.
We want to be able to charge the battery at a reasonable rate. The solar charger takes a maximum 6V nominal solar panel, with preset max charge rate of 500mA (although this is adjustable). This is 0.625C (500mAh/800mAh), within the guidelines for charging Li-Ion batteries (0.5C to 1C).
It's a bit of a challenge to source cheap solar cells that still output a decent amount of power. For example, the Sparkfun or Adafruit 6V panels are around $30. I found a 5 pack of panels on Amazon for $4/pc. However, it's a unknown brand, time for some solar cell characterization!
I took these measurements at 4PM shortly after the summer solstice in California (so pretty much the most solar radiation you can expect all year).
Angling the panel from horizontal and facing it South will help maximize solar irradiation on the panel. Following the guidelines, I set my panel to face true south at an angle of 30 deg from horizontal, which is a good average for northern and southern California, where I'll be using the stations. I also set it at 50 deg, which is the recommended angle for the winter, when cloudy weather is more likely.
The panel was facing directly true south for 2 trials labeled "-S" and towards wherever the sun was at "30deg at sun". The angles are all from horizontal.
At the maximum power point for "30deg-S", the voltage is about 5.9V and output current is 183mA for a total of about 1W. For a cheap solar cell, this is adequate. The Adafruit solar charger uses a MCP73871 chip with Voltage Proportional Charge Control (VPCC), set to 4.5V. The charger will adjust current draw to maintain 4.5V charging.
At 4.5V, about 0.87 W is available. A rough estimate of the lower bound is that a fully discharged battery (2.9Wh) can be charged in 3.3 hrs (2.9/0.87).
We can see that December in California has the lowest solar energy, approximately 51% of the peak in June (for Average Tilt at Latitude or ATaL).
To improve my solar modeling, I used the clearness index method with Orgill and Holland's model, which was correlated at Toronto, Canada. These models are sensitive to location (latitude, longitude), however it is difficult to find correlated models for arbitrary locations so I used one that was roughly close. This model, like others of its type, calculate total irradiation (I_total) on an inclined surface as follows:
First, the total extraterrestrial horizontal irradiation is calculated for any given moment in time. Then the measured GHI from the NREL database is compared to yield the ratio GHI/I_h_extra, otherwise known as the clearness index k_t.
The clearness index is the key part of the Orgill and Holland model, which allows us to estimate the amount of diffuse radiation for a given total radiation. Once the diffuse component is calculated, the beam (or direct) radiation is found from:
I_bh = I_h - I_dh
At this point, we know the amount of beam, diffuse, and total radiation on horizontal surfaces on Earth, and we can convert that to equivalents for inclined surfaces:
I_total = I_bh * R_b + I_dh*(1+cos(a))/2 + albedo*I_h*(1-cos(a))/2
where I_h = total irradiation on horizontal surface, or GHI, R_b = ratio of beam radiation from extraterrestrial to surface, I_bh = direct or beam radiation on a horizontal surface, I_dh = diffuse irradiation on horizontal surface, a = tilt angle, albedo = reflectivity of the ground, generally averaged at 0.2
Using this procedure, I averaged clearness indicies from 1991 to 2005 for Hayward, CA, and produced the following plots:
We can see that a low tilt angle in June results in the highest irradiation, in part due to the long days and the maximum declination of the earth, which creates better incidence angles for direct beam radiation. However, this comes at the expense of irradiation in the winter months. To improve the average irradiation over the whole year, I wrote a script to find the optimum tilt angle. The results show that the optimum is around 37 degrees. Why is it not at 35 degrees, where there is maximum irradiation (red curve)? This is because for a weather station, with relatively constant energy needs year-round, it is more important that the incoming power does not drop below a specified minimum. This occurs (see blue line in the first pic) around 37 degrees.
To estimate the power curve in December, where irradiation is lowest, I had to extrapolate the measured data from 4PM on June 29th to December. There's a 37% increase from 4PM to solar noon, which is the maximum on the 29th. Realistically, the solar cell has a limit to the amount of power it can generate, so I limited this to 20%. Then from a 30 degree angle (measured) to a 37 degree angle (intended), I found a 4.7% drop in power. From June to December, the avaliable power then drops by another 71%.
Therefore the estimate is 0.87W * 1.2 * 0.95 * 0.29 = 0.29W (although the curves for power vs voltage do change shape slightly with light intensity, I have assumed this is a small effect). This means the shortest charge time in December is 10 hrs. With only 9.5 hrs of daylight in December, this leaves little margin for bad weather. I'll update this page when winter comes around to see if this is sufficient!
Taking into account the actual charge profile, I could be underestimating. However, this seems to be in the right ballpark to keep the station running indefinitely with normal direct sunlight in California. True winter conditions or extreme latitude conditions will require resizing the solar panel and or battery.
To check to see if on a daily basis the station's energy balance is correct, I plotted the charging profile vs time. Looks like a sleep time of 720s, or 12 minutes, is theoretically ok:
A crucial note for the above analysis: it does not take into account that solar cell efficiency decreases with cell temperature. This is an important factor in overall cell power output, and is taken into account on larger PV installations.
With regard to the relevant weather variables, and qualitatively speaking, it was found that the PV cell temperature rise over the ambient is extremely sensitive to wind speed, less to wind direction, and practically insensitive to the atmospheric temperature . On the other hand, it obviously depends strongly on the impinging irradiation, i.e. the solar radiation flux on the cell or module. Energy Procedia 33 ( 2013 ) 311 – 321
However, I do not have the tools to measure this factor accurately, and so will disregard it, trusting the conservative estimates of energy usage to account for this.
In addition, the solar panel does not convert "total irradiation" into electrical energy, it can only convert incoming radiation with wavelengths less than the band gap. Therefore the above analysis probably overestimates the amount of energy available, because it compares total irradiation instead of the true range of wavelengths. Most of the infrared and near- infrared wavelengths which contribute to total irradiation are unusable from the solar cell's standpoint.
One issue I found was that there seems to be corrosion starting on the white connectors within the solar panel. I'll keep an eye on this to see if it gets worse, but you get what you pay for with these cheap panels.
- check fan voltage spikes during operation on actual PCB
- Try to reduce sleep current below 3mA!!
- FIXED: code updated to remove wifi connect collision with user code. No longer hangs, 1 month continuous operation so far.
- Solar irradiation modeling improved. Now uses real world data in combination with model to predict hourly and monthly energy inputs. Sleep time between measurements unchanged.
- Added section on condensation
- Added section on reflectance of white plastic in visible and IR. Radiation shield now painted with TiO2 white paint, should reduce temperature rise due to radiation by a few degrees.
- Added section on solar cell efficiency vs cell temperature