Using Adafruit IO
“How is the weather?” In modern times, for a reliable answer to that question, you’re much better off asking a machine than a human. Wouldn’t it be fun to build such a device yourself? With that in mind, in this project article, Mark explains how to build your own hobby weather station that is solar powered, runs over Wi-Fi and logs all its data to Adafruit IO.
If there is one topic that consistently comes up in small talk, it is the weather. In many of those conversations a huge topic is the unreliability of weather forecasts. In reality, there can be a marked difference in weather even the short distance between me and the nearest government weather station. The standard reporting time tends to be hourly, but weather conditions often can change far more rapidly.
The previous day’s weather also consistently raises questions. How hot or cold did it get? Did it rain at your house? That wind was crazy last night, wasn’t it? At times, weather systems can be localized, and while my house may have had no rain, a friend’s house a few kilometers away might have gotten a small flood.
I have always had an interest in the weather, maybe because I live in an area where the temperature can range from -40°C to +40°C, where we get among the most hours of sunlight in Canada, but we can get crazy summer thunderstorms rolling across the prairies and raging blizzards in the winter. After paying attention to the weather, it is apparent that many official sources are slow to update and not always accurate to my exact location.
At a technology conference five years ago, when the idea of Internet-connected devices aiding everyday life was becoming more popular, I attended a workshop on the Internet of Things (IoT). At the end of the workshop, there was a giveaway for the Intel Edison developer boards that had been used in the workshop, and I was lucky enough to get one. I was amazed that, with this small system, I could do so much.
When I arrived home, I started to look into what I could do with this new technology, and found a SparkFun BME280 breakout board that could measure temperature, pressure and humidity. After hooking up the sensor, it did what it advertised, telling me the local temperature. This spurred me to order more parts to build a complete weather station. The parts arrived and promptly got sidelined in a box, due to competing time priorities and frustrations with my lack of knowledge about microcontrollers (MCUs) and electronics, and how to get this project outdoors and, ironically, to survive the weather it was measuring.
Three things recently happened to renew my interest in completing this project. First, for Christmas I received some Adafruit components, allowing me to learn more about MCUs and discovering Adafruit IO. Second, I received a 3D printer for my birthday, letting me learn to build enclosures to host my electronics. And third, the pandemic hit, giving me more free time, which I used to dig out and complete my old project. The finished weather station is shown in Figure 1.
While designing the weather station I had three main objectives. The first was to enable the project to run remotely, with no wires connecting it to power or network. Second was to have the project send the measured data to the Internet so that it could be visualized and consumed by other projects. And third was to reuse mostly components that I already owned.
To achieve these objectives, I made three key decisions about the weather station. The project would be built using an Adafruit Feather M0 Wi-Fi. The project would run off a battery, recharged by solar power utilizing a SparkFun Sunny Buddy. The project would use Wi-Fi to connect to the Internet using Adafruit IO cloud service as the receiving server.
The free Adafruit IO service offers pre-built Arduino libraries to store data to their services, dashboards and charts to display the data, and has sufficient capacity to store the amount of data required. A subscription service called Adafruit IO+ is also available, with increased data, storage and feeds.
The sensors for the project include a SparkFun BME280 for temperature, pressure and humidity readings, and the SparkFun Weather Meters to measure wind speed, direction and rain amounts. The Adafruit Feather M0 has a built-in circuit to read the current battery voltage.
The weather station’s flow purposely was kept as simple as possible. The Feather M0 wakes up every minute to read the attached sensors and transmit the data to Adafruit IO. Not all measurements are sent every minute, since some need more data to be useful. After the measurements are sent, the processor goes into a deep sleep mode to wait for the next minute. To recover from any unexpected errors that may lock up the weather station, a watchdog timer is enabled that is reset every 10 seconds.
The electronics in the weather station are relatively straightforward. There are two main systems: the processing system, consisting of: 1) a Feather M0 hooked to the BME280, weather gauges and a reset button; and 2) the power system, comprising a Sunny Buddy solar charger hooked up to the solar cell, battery and power switch. The power system load output is connected to the battery port on the Feather. The assembled and soldered components are shown in Figure 2.
THE PROCESSING SYSTEM
The Adafruit Feather M0 Wi-Fi MCU was chosen for this project, because it has enough memory and processing power to manage resources. It has built-in Wi-Fi, saving the extra work and cost of attaching an external Wi-Fi board. A diagram of the Feather hooked up to the sensors is shown in Figure 3. The reset button is the easiest connection in the processing system. The button connects between the reset and ground pins on the Feather. Solder the button to each pin with a small piece of wire long enough to reach the mounting point on the side of the electronics enclosure box. In my setup, each wire was less than 2″ long.
The BME280 hooks up via the M0’s I2C bus. The BME280 requires connections to the Feather’s 3.3V power, ground, SDA and SLC pins. Of several different options for wiring this connection, using either individual wires or a 4-wire ribbon cable works. I suggest using a JST or similar connector near the Feather. This allows you to plug in and unplug the BME280 for easier assembly, since the sensor will reside in the radiation shield away from the electronics box.
In my build, the Feather was seated on a small circuit board that I designed to learn about circuit boards. I would suggest using a small breadboard or protoboard. The circuit board had holes to wire out to the BME280, to which I soldered one end of a JST connector. It is important to remember to keep the total wire length for the BME280 under 1 meter—the shorter the better. In my first build, the wire length was too great, and I was getting random lock-ups and misreads from the sensor. My current wire length is under 50cm.
The SparkFun Weather Gauge has two cables ending in RJ-11 connectors. I purchased two RJ-11 female sockets to allow the weather gauge connectors to disconnect easily when required. You may also cut the RJ-11 connectors off the weather gauge to connect the wires directly to the Feather. On the weather gauge, one connector is for the rain gauge, using two of the pins in the RJ-11. This RJ-11 connector connects to ground and D11 on the Feather M0.
The other weather gauge connector is for both wind speed and direction. The wind speed uses two of the RJ-11 pins connecting to ground and the Feather digital pin D6. The wind direction connection requires an analog measurement, because the value fluctuates based on the direction the gauge is pointing. To properly measure this value, a voltage divider is required. One pin from the RJ-11 connects to the Feather’s ground. The other pin connects to a 10kΩ resistor, and also ties into the Feather pin A2. The other side of the resistor goes to the Feather 3.3V pin. For more in-depth information on the SparkFun Weather Gauges see the tutorial at . This, and other references and resources, are available in RESOURCES at the end of the article.
THE POWER SYSTEM
The Sunny Buddy solar charger requires setup before it is connected to any of the other components. It requires soldering the connector to attach the solar panel, and configuring the potentiometer for optimal solar charging. For full details see the SparkFun guide at  to set yours up.
The power switch is connected to either one of the load terminals on the Sunny Buddy. Use a wire long enough to allow the switch to be mounted on the side of the electronics enclosure. The other side of the power switch and a wire from the other load terminal are connected to a two-wire JST connector. This JST connector plugs into the Feather battery connector. The battery plugs into the battery connector on the Sunny Buddy.
Note: Do not plug the Feather M0 into USB power while the load wires are also connected. The Feather has a built-in Li-Po charger that attempts to charge the attached battery when it has USB power. But in this setup, there is no battery. Instead, there are the load wires going to the Sunny Buddy. If you need to hook up the M0 via USB for any reason, first disconnect the power connector going to the Feather from the Sunny Buddy.
While the 3D-printed enclosures should prevent most water from getting on the electronics, there is still a possibility water could get into the case. As an extra layer of water protection, I applied the anti-corrosion spray CorrosionX (Corrosion Technologies) to the electronics. Be careful when spraying the BME280 module to prevent a small hole in its center (visible in Figure 3) from clogging. I covered the hole with a small piece of tape while I sprayed the rest of the circuit board, then removed the tape after I wiped away the excess spray.
Adafruit IO cloud service is an excellent platform for connecting IoT projects. It allows you to send data to the service, and lets you visualize the data and retrieve it later from other devices. The basic service is free, and includes 10 data feeds, 30 days of data storage and lets you record up to 30 data points per minute. This is more than enough capacity for this project. Adafruit has many tutorials on setting-up and using their service . The following describes the setup required for this project.
The first step is to sign up for an account at https://io.adafruit.com. After sign-up you will have access to your Adafruit IO username and key. Always protect your key, so that others cannot alter your data without your permission. You will add the username and key to the config.h file.
#define IO_USERNAME "YOUR USERNAME HERE"
#define IO_KEY "YOUR IO KEY HERE"
The weather station requires that you create nine feeds. The feed names must match exactly, or the code will need to be altered to match the new names you are using. The required feeds are:
1. Battery Voltage
7. Wind Direction
8. Wind Gust
9. Wind Speed
The names are self-explanatory, except for “Start,” which records the processor’s reason for a power-up/reset. This may be a first power-on, a reboot or a watch-dog reset. I added the Start feed to monitor any exceptions that happen, and to aid in debugging issues. You can view the feeds live as data arrive to them. Go to the Feeds menu and you can click on any individual feed to see all the values that have been recorded. The listing updates as new values come in.
You may also create a dashboard. Dashboards allow you to display information from many feeds in several formats concurrently. I created a dashboard (Figure 4) showing the feeds, so I could quickly check the weather at my house. Experiment to find what works best for you. Adafruit IO allows up to five dashboards, so you can make different dashboards to see your data displayed in different ways. To see streaming data on my station dashboard, create an account and go to: https://io.adafruit.com/Gamblor21/dashboards/weather .
CODE: TWO MAIN TASKS
The program to run the weather station is written in C for the Arduino platform. Following the standard format for Arduino, the code consists of two main tasks—setup and the loop function that takes the measurement. Most of the code will work as is, though some setup is required to configure the code for your specific use. The code and files discussed below are available for download on Circuit Cellar’s article code and files download webpage.
First you need to edit the file config.h. The config file holds your Adafruit IO username and key, and the SSID and password for the Wi-Fi router you will connect to. Set these items and save this file.
The next setup happens in the Weather_Station.ino file. First set your local altitude in meters above sea level. Google maps and other tools, including the Compass app built into iPhones, can give you this value.
// Set this to your location's altitude above sea level in meters
#define ALTITUDE 235
Next, check all the defined pins for the weather gauges. If, for any reason, you attached the gauges to different pins on the Feather, you will have to change the definitions here.
// Pins for the weather gauges. Wind/Rain are digital, Wind direction must be analog
#define VBAT_PIN A7
#define LED_PIN 5
#define WIND_PIN 6
#define RAIN_PIN 11
#define WIND_DIR_PIN A2
As previously note, the wind direction requires an analog measurement, because the value fluctuates based on the direction the gauge is pointing.
SETUP, LOOP AND INTERRUPT
The setup function: As named, the
setup() function sets up the weather station to run after it is powered on.
setup goes through several tasks. First, it sets all the I/O pins for input or output mode, and sets up interrupts to trigger for the wind and rain gauges. The interrupt functions are described in more detail later.
setup connects to Adafruit IO. This connection is kept active the entire time the weather station is running. The
io.run() function scattered throughout the code refreshes the connection and will reestablish it if required.
setup() then initializes the BME280 sensor that will read the temperature, humidity and pressure. The
setup code resets the sensor, in case it was not fully reset previously, and configures the sensor to the optimal values for a weather station. These values came from the BME280 specifications.
setup function sends the reason for the last reset to Adafruit IO, and turns on the watchdog timer. If the watchdog is not petted every 16 seconds, the project will reset. This reset may happen if any sensor or Wi-Fi fails. The last task is to set up the real-time clock (RTC) that will wake the project. An alarm is set to go off every 10 seconds to pet the watchdog timer and determine when it is time to do the weather measurements.
The loop function: The
loop() function continues to run infinitely after
setup has finished. The first thing
loop does is go to sleep. The project spends the majority of its time in low-power, sleep mode. This allows the project to operate with a battery for days without running out of power—even if it is cloudy and the solar panel is not generating any electricity. The station will sit in the low-power, sleep mode until any interrupt goes off. The interrupts trigger when either the wind or rain gauge registers a reading, or if the RTC alarm goes off—signaling it is time to pet the watchdog and take weather measurements.
The next section of code runs after the RTC alarm has gone off. All the other interrupts skip this section and immediately send the Feather back to sleep mode. The first thing that happens is the watchdog is petted, so that the system will not automatically reboot. The bulk of the code runs every minute after the RTC alarm triggers. The first task run is to flick the on-board LED on and off. I added this flashing LED as a tool to let me see that the program was running. This is optional and could be disabled in the code, saving a small amount of power
The next task is to ensure we are still connected to Adafruit IO. This is done by calling
io.run(). This function ensures that the program is still connected to Adafruit IO, reconnects if the connection has been lost and sends any pending transactions and receives any waiting responses. This function is called several times throughout the rest of the loop, because the WINC1500 buffers can get full if they are not read regularly. If you notice the Wi-Fi transmit light stuck on, it is likely the WINC1500 buffers are full and need to be read.
The weather measurements are made at different intervals. Some measurements are averaged over a longer time period, resulting in more accurate readings. The code is set to run measurements at 1-, 2- and 5-minute intervals. After one of these intervals has elapsed,
measure functions read one or more sensor values or variables that were already set by interrupts. The code may do some basic processing on the values, and then sends the final value to Adafruit IO. The final step of the
loop function is to reset the RTC alarm trigger, and set an alarm for the next 10-second step.
The interrupt functions: Interrupts allow the Feather to wake up from low-power mode, to increase counters when the wind and rain gauges register a reading. The timing of these interrupts depends solely on the gauges. For example, when it is very windy, the interrupt could trigger several times a second, whereas, if it is calm, there may be hours between triggers. The RTC also uses an interrupt to let the program know it is time to run the main loop.
Any interrupt function needs to complete its task quickly, because nothing else can execute on the MCU while the interrupt is executing. In addition, the longer the station is out of low-power sleep mode, the more power it is consuming. In the weather station, the interrupts either increase a variable or set the
alarm-trigger flag and exit immediately.
The final assembly (Figure 1) consists of several components, some of which are part of the SparkFun Weather Meters, and others that I custom designed and 3D printed. The Weather Meters comes with a 0.75” diameter metal pole to which all the components are mounted. The pole can then be mounted, using the supplied brackets, to any suitable surface around the yard. Remember to ensure that the solar panel will get light.
Radiation shield: The radiation shield (Figure 5) consists of several circular layers and a bottom cap. It protects the BME280 sensor from direct sunlight and rain, while still allowing air to flow across the sensor to make accurate weather readings. The shield uses neodymium magnets to hold sections together, allowing access to the inside. Or for a more permanent solution, they can be epoxied together (more on this later). Alternatively, clasps can be put on the top and bottom, to attach the shield with zip ties to the metal pole of the weather gauges.
To build a more permanent radiation shield, you have to 3D-print each layer of the shield separately. All the names referred to here match the names you will find in 3D STL Files.zip file, available from Circuit Cellar’s article code and files download page. You need to include one of each piece, except for two middle pieces and two clasps. The bottom piece is epoxied to one of the two middle pieces. And the top piece is epoxied to the second middle piece. The two clasps are epoxied to the top and bottom of the shield to attach to the metal pole of the Weather Meters.
Neodymium magnets are epoxied to the pegs and in the holes of the holder piece. Also attach magnets to the pegs of the top layer (to fit in the sensor layer holes) and to the holes of the bottom section (to attach to the pegs of the sensor layer). The BME280 will attach to the holder piece with an M2.5 screw and nut. Figure 6 shows the position of the magnets and the BME280.
Electronics enclosure: The electronics enclosure (Figure 7) holds all the other electronic components that must be protected from the elements. They include the Feather M0, Sunny Buddy, battery and switches. The box can fit a small protoboard cut to size, or you could mount the electronics using glue or tape. On the right side of the case are mounting holes for the Sunny Buddy that take 3.5mm screws. The battery compartment is on the top left of the box, where the battery can be inserted and secured with a small piece of tape. The interior of the electronics enclosure is shown in Figure 2.
The top piece of the enclosure slides over the case and snaps in place. It has overhangs to help keep out water from rain and snow, but it is not entirely waterproof. Holes in the bottom provide mounting points for the power switch and reset button, and access for wires going to the sensors (Figure 8).
Your final location for assembly depends on where you want to measure the weather. The more open space there is around your project, the less other objects may affect your readings—for example, a building blocking the wind, or a surface holding heat and raising the temperature. I mounted all the components of the station on the metal pole that comes with the SparkFun Weather Meter. The wind gauges are mounted at the top, followed by the radiation shield, the electronics enclosure and then the rain gauge near the bottom (Figure 1).
The solar panel is mounted with duct tape to the other side of the electronics enclosure. The solar panel should face the area that gets the most sunlight, preferably angled upward. The position of the sun will change throughout the year, so try to pick an optimal position, or adjust the orientation of the solar panel as the seasons change.
This weather station has been a long running project that has pushed me deeper into electronics and MCUs. The current iteration of the weather station is complete, but I have more ideas I would like to add to improve my weather station. Several of these ideas are described here, and if you choose to implement any of them please let me know, I would love to hear about it.
You could add a sensor to detect light levels, for time of day or night detection, and possibly for clear or cloudy detection. A sensor that can detect colors, rather than absolute light levels might be useful here. A lightning detector could be added to warn of nearby electrical storms. In addition to the rain gauge and pressure gauge, the severity of incoming weather could thereby be determined.
Currently, the station records mostly raw data. A lot of this data is not helpful in themselves, and need to be aggregated to be more useful. The station could keep track of sensor readings over a longer time period, and record the aggregated data. This would enable a second project to use the data without having to aggregate it before use.
Finally, you could try to answer the question on everyone’s mind: What is the weather going to be? The data could be read and interpreted through predefined rules or an AI system, to try to predict the weather. Because the weather station will eventually determine the actual weather, it turns out that such data can be used to help continuously train a prediction system.
I hope you enjoyed learning about my project. I would love to hear from anyone who builds a weather station following my methods, or implements any of my suggested improvements.
 SparkFun Weather Gaugesz
 SparkFun Sunny Buddy Setup Guide
 Adafruit IO Learn Guide
 My Weather Station’s Dashboard
Code on Github
Electronics Enclosure on Thingiverse
Radiation Shield on Thingiverse
PUBLISHED IN CIRCUIT CELLAR MAGAZINE • JANUARY 2021 #366 – Get a PDF of the issue