IMG_6646.jpeg

Beacon Hill Weather

Beacon Hill Weather (also known as PyWeather 4 internally to keep up with the PyWeather naming scheme) is a solar-powered weather station that I’ve been building since May 2024. It is my most ambitious project from a software and hardware perspective, combining 4 software stacks and countless hardware iterations to complete.

The premise is relatively simple - I’ve always wanted a weather station since I was a kid, but now as an adult engineer, I wanted to challenge myself to build one, piece by piece, instead of buying one off the shelf.

Beacon Hill Weather had to some extra challenges too - it needed to be entirely solar-powered (no reliable wired power on my roof), and communicate on Sub-GHz radio (2.4 GHz Wi-Fi isn’t reliable in a dense urban environment). It had to be entirely waterproof, but also New England weather-proof (it can call for single digit temperatures with heavy snow in January, but 95+ degree days in the summer).

Throughout the course of 7 months, I slowly pieced together all the hardware necessary to make the weather station, along with a receiver for data from the station, a backend API to ingest & serve weather data, along with a website to show it off to the world. Not to mind also creating a fault-tolerant software stack on the weather station, as you cannot debug a weather station while it’s pouring rain outside.

All of this combined into my best project to date, and something I’m incredibly proud of.

Timeframe: May 2024 - Present

You can check the latest weather at https://weather.owenthe.dev (URL is clickable)!

 And here’s your first look at Beacon Hill Weather. The station starts off with SparkFun’s Weather Kit, which included the anemometer, wind vane, and rain bucket. Everything else is hardware that I put on the station, so it’s grown a lot since then.

And here’s your first look at Beacon Hill Weather. The station starts off with SparkFun’s Weather Kit, which included the anemometer, wind vane, and rain bucket. Everything else is hardware that I put on the station, so it’s grown a lot since then.

The station is mounted on a pole that’s clamped on to 2 random brackets I found on the roof deck with hose clamps. In turn, the random brackets are also clamped down with more hose clamps.

The mounting for the station has gotten stronger and stronger over time, but it’s working! It’s survived some gnarly wind gusts (about 35 mph as measured by the station), and has no issue with heavy rain or snow. Eliminating the rotation & tilting that occurred in prior times was super important to get accurate wind direction & rain measurements.

Looking at the front, you’ll also notice the junction box which contains all of the station electronics - but we’ll talk about that later. There’s some labels on the outside of the box that discuss what this weather station is doing, and who to contact if needed. This is on a shared roof deck, so I wanted to be as transparent as possible with what’s going on.

 Taking a side profile of the station, you’ll see some of the holes I punched in the junction box to get wiring in and out of there for all the stations sensors.  To the left is the solar radiation shield (and arguably the thing that screams hello! I

Taking a side profile of the station, you’ll see some of the holes I punched in the junction box to get wiring in and out of there for all the stations sensors.

To the left is the solar radiation shield (and arguably the thing that screams hello! I am a weather station!) - so let’s quickly discuss that.

Solar radiation shields are used on real weather stations to protect temperature sensors from the sun. If solar radiation shields aren’t used (and you leave a temp sensor in the sun), it’ll measure 5-15 degrees higher than the ambient air, leaving your measurement not super useful.

Solar radiation shields help two-fold by protecting your temperature sensor from the sun in all directions - but they form little gaps so that wind can still blow through and reach the sensor.

These shields come in all sorts of sizes, but I chose the SRS100LX from Ambient Weather because it was a good price, and it looked well shielded enough to deal with the fact that my roof is white (which famously reflects sunlight & radiation back off of it). I didn’t realize how big it would be (it’s about 8-10 inches tall), but it makes this station more legit and it allows the solar panel to rest on it for an optimal angle. Win-win-win!

 As I touched on in the beginning of the article - there’s no reliable power on the roof of my building, so the entire weather station is solar powered.  To harness the power of the sun, there’s a 6 volt, 10 watt panel facing south to get all this po

As I touched on in the beginning of the article - there’s no reliable power on the roof of my building, so the entire weather station is solar powered.

To harness the power of the sun, there’s a 6 volt, 10 watt panel facing south to get all this power. Previously, I was using a 5 watt panel (also with just a 10,500 mAh battery bank).

While a 10-watt panel is a bit overkill for this project, I’d much rather go overkill on the power part of this project so the station doesn’t randomly die (and so far, it hasn’t!).

Having the bigger panel is super helpful too - on days where it’s only sunny for a couple of hours, I can quickly charge the battery to preserve capacity at night. During cloudy days, the panel generates about 1-1.5 watts, which is just a tad higher than the idling load of the station, also preserving capacity for the night.

The bigger panel also allows the battery to quickly get to 4.1 volts, then trickle charge for the rest of the day up to 4.2 volts for the rest of the day.

 Here’s a top view of the weather station where you can more clearly see the rainfall bucket, anemometer, and wind vane.  We’ll talk about that extra box (with duct tape) in the next photo.

Here’s a top view of the weather station where you can more clearly see the rainfall bucket, anemometer, and wind vane.

We’ll talk about that extra box (with duct tape) in the next photo.

 This is what I like to call the “top box” - it contains a VEML7700 light sensor and LTR390 UV Index sensor. They have to be up here to get accurate readings.  Due to UV readings spiking in the mornings (around 9:30 AM), I’ll be installing a 3D-print

This is what I like to call the “top box” - it contains a VEML7700 light sensor and LTR390 UV Index sensor. They have to be up here to get accurate readings.

Due to UV readings spiking in the mornings (around 9:30 AM), I’ll be installing a 3D-printed shield just to prevent direct sunrays from hitting this upper box soon. The duct tape was an attempt to solve this issue (that didn’t work).

 This is the inside of the junction box where all the station electronics are stored. It’s certainly not the prettiest thing in the world - the hardware of this station has gotten a lot more complex as time has gone on.  There’s 4 holes with varying

This is the inside of the junction box where all the station electronics are stored. It’s certainly not the prettiest thing in the world - the hardware of this station has gotten a lot more complex as time has gone on.

There’s 4 holes with varying PG-size gaskets to allow for wires to come in and out. There’s 15 ventilation holes on the bottom that allow for the station to breathe during hot summer days, and also for outdoor air to reach the air quality sensor.

What you’ll mainly see in this photo is the battery pack in the top right - these are two 10,500 mAh battery packs wired in series. 21k mAh seems excessive (and it is), but it quickly becomes not excessive when you have 5 cloudy days in a row and the station can’t really charge much. The station has never gone down because the battery has died. The lowest it’s ever gone is 3.37 volts. (and it had .37 volts to spare!).

There’s the solar power manager at the top - previously, I was using a BQ24047 but found it stopped charging the batteries at 4.1 volts which was stupid. This board also has 5V out included on it - previously, I had to use an Adafruit PowerBoost to get 5V out to the Pi. Overall, I like the Waveshare board a lot more than the Adafruit BQ24047 board.

The Pi sits on the bottom with a dual-HAT extender, one for the RFM69 bonnet (comms & display), another for the Pimoroni WeatherHAT, which includes the ADC to read data from the wind vane, anemometer, and rain bucket. It also has a BME280 onboard that I use for reading pressure and internal temperature.

A few notes in this photo: you’ll see a RTC hooked up past the air quality sensor on the bottom of the junction box. That RTC is no longer there, due to clock drift from cold temperatures. The air quality sensor is also properly mounted so the fan can suck in air from one of the ventilation holes.

 This is the official wiring diagram for the entire weather station. Just note that the solar panel is NOT 6 volts at 10 amps. That’s meant to say 6V/10W.

This is the official wiring diagram for the entire weather station. Just note that the solar panel is NOT 6 volts at 10 amps. That’s meant to say 6V/10W.

 Sub-GHz communication is largely centered around these Adafruit RFM69 bonnets. They’re a really cool piece of hardware - they have the RFM69 onboard, but also a bunch of breakout pins (which I’ve soldered headers for here), in addition to a 128×32 O

Sub-GHz communication is largely centered around these Adafruit RFM69 bonnets. They’re a really cool piece of hardware - they have the RFM69 onboard, but also a bunch of breakout pins (which I’ve soldered headers for here), in addition to a 128×32 OLED screen and 3 buttons.

(side note: these bonnets come in 433 MHz and 915 MHz variants - I chose the 915 MHz as I wanted to put a webcam on the station, but quickly realized the bitrate of the RFM69 couldn’t handle it. Slightly more importantly - 433 MHz is pretty crowded in the USA with a bunch of consumer electronics using it, but 915 MHz is a much clearer band, so I went with that for reliability at the cost of some range.)

I made good use of these three buttons & screen to make a small UI for getting station status on the roof - holding down each button will throw up a different screen. Holding down the left-most button comes up with four important stats: When a weather packet was last transmitted, how big the local database size is (i.e. how many packets are saved to disk but haven’t been transmitted to the receiver), what the station thinks the current time is, and station uptime.

The system time part is important to have on the station - especially because the station doesn’t have a RTC onboard. On boot (and every 24 hours thereafter), the station will reach out to the receiver and ask what time it is. It’ll wait for a reply and use some compensation to get the current time to within about half a second (plenty accurate for my use case).

To make a long story short, sometimes, the receiver will double or triple-transmit packets, and the RFM69 on the station will store these packets until accessed by someone (myself) in software. When this happened, I would access one packet, then 24 hours later, access another packet with the time from 24 hours ago, and clock sync would “fail”, make the station go back a day, and I’d start wondering why the station went down Having the local time printed on the station made debugging this issue very easy, but it’s all fixed now. I just empty all the packets and take the last one in the stack when syncing time.

 Pressing down the middle button shows information about the battery. This includes the estimated state of charge, voltage, and drain rate. The SoC and voltage are taken straight from the MAX17048 battery gauge onboard. The drain rate is taken from t

Pressing down the middle button shows information about the battery. This includes the estimated state of charge, voltage, and drain rate. The SoC and voltage are taken straight from the MAX17048 battery gauge onboard. The drain rate is taken from the MAX17048 for a little bit after boot, but after that, drain rate is calculated on the station by calculating it from the last 15 minutes of SoC estimates.

 The last button shows, well, the weather! You can indeed check the weather on the weather station. This screen was developed in the very, very, very early days of the weather station where there was no website, no receiver, and it was going to the r

The last button shows, well, the weather! You can indeed check the weather on the weather station. This screen was developed in the very, very, very early days of the weather station where there was no website, no receiver, and it was going to the roof to check on the station.

But, in the spirit of this project, I kept it around. You can get the temperature, humidity, wind speed, wind gust, wind direction, daily rainfall, rainfall rate, pressure, and lux level right on the station! It’s an impressive amount of data to fit on a 128×32 screen!

 In fact, here’s a photo from June 2024 when the station was under development showing that data screen - largely similar to what it was today.  You can notice how wildly different the station internals looked at the time - one battery, different sol

In fact, here’s a photo from June 2024 when the station was under development showing that data screen - largely similar to what it was today.

You can notice how wildly different the station internals looked at the time - one battery, different solar manager, Adafruit PowerBoost at the top. It was also crazy hot that day - but the temperature sensor was likely overdoing it since it wasn’t in a radiation shield.

For those careful-eyed folks - you’ll notice there was a full-sized Pi onboard the station at that time. I was originally using a Pi 3B+ that I had lying around - but discovered that full-sized Pis idle at almost 2 watts of power! It turns out, the Pi Zero 2 W is the most efficient Pi in terms of idling power (and overall power consumption), so I quickly switched to the Zero 2 W after discovering this information.

While I could’ve (and should’ve) used a low-power SoC (i.e. an ESP32, possibly an Arduino) for this project, I decided to play it safe and use a Pi while sucking up the extra costs of beefing up the power subsystem on the station to handle a constant ~0.8-1.2 W draw. It allowed for much faster prototyping of the station, in addition to all the creature comforts that come with running a full Linux OS.

 Enough of the station on the roof, let’s move down into my apartment where the power is plentiful and the Wi-Fi is much better than on the roof. Introducing, the Beacon Hill Weather Receiver.   This is a Raspberry Pi 3B sitting very close to my ceil

Enough of the station on the roof, let’s move down into my apartment where the power is plentiful and the Wi-Fi is much better than on the roof. Introducing, the Beacon Hill Weather Receiver.

This is a Raspberry Pi 3B sitting very close to my ceiling (for optimal reception, there’s a long micro USB cable powering this thing), also with a RFM69 bonnet onboard to get data from the station.

The receiver runs a separate software stack that takes care of receiving data from the station (which comes in as 3-4 packets of comma deliminated data) and translating that to the appropriate Pydantic models that the Beacon Hill Weather API can handle.

 The screen & buttons on the receiver are also used - but just for a different purpose. Hitting the leftmost button brings up some statistics about the last RX time, last upload time, local database size, and the last packet’s RSSI.  The other tw

The screen & buttons on the receiver are also used - but just for a different purpose. Hitting the leftmost button brings up some statistics about the last RX time, last upload time, local database size, and the last packet’s RSSI.

The other two buttons use to show details about the last packet transmitted from the station (battery life and the actual weather) - but since this receiver is 10 feet off the ground, it doesn’t make sense to have this functionality.

 Whenever the weather station is receiving or uploading data, it’ll flash text on the screen. During the receiving of packets, it’ll show “RX 0”, “RX 1”, etc etc.  Packets are transmitted as 60-byte strings (which is what the RFM69 can handle), delim

Whenever the weather station is receiving or uploading data, it’ll flash text on the screen. During the receiving of packets, it’ll show “RX 0”, “RX 1”, etc etc.

Packets are transmitted as 60-byte strings (which is what the RFM69 can handle), deliminated by commas. The first packet sent from the station is 0,<length of packets>, which tells the receiver how many packets to expect.

From there, the remaining packets are sent with all the weather data in a specific order. There’s code on the station to automatically squeeze as much data out of the packets as possible. Usually the RX number goes up to 2 or 3, but occasionally it can hit 4.

In reality, that means the station is transmitting about 140-160 bytes of data for its latest weather report. This data is transmitted in about 0.3 seconds with acknowledgements on either end.

But, enough with the hardware, let’s move on to the website!

 This is the main homepage of Beacon Hill Weather. The frontend uses React + MUI (a common combo), but with the Toolpad Core which helps with setting up this dashboard-style React app. Routing is done via React Router.  The homepage contains all the

This is the main homepage of Beacon Hill Weather. The frontend uses React + MUI (a common combo), but with the Toolpad Core which helps with setting up this dashboard-style React app. Routing is done via React Router.

The homepage contains all the data of Beacon Hill Weather at a glance. The current condition (although when it’s raining, I populate the current condition based on rainfall rates), sunrise, and sunset times are fetched from Apple WeatherKit.

Below that is the feels like, humidity, dew point, wind speed, wind gust, wind direction, rainfall today (and rainfall rate when it’s raining), UV index, Air Quality Index, PM2.5 Concentration (averaged over the hour), pressure, pressure trend over the last 6 hours, calculated solar irradiance, and light level.

Beacon Hill Weather spits out an impressive amount of data - the entire system has almost 20 data points getting logged every minute. And below that are some refresh indicators telling you when new data will be fetched.

On the right is the daily summary, basically an almanac showing the daily high, averages, and minimums up to the current time. This includes…get ready for it…

Temperature, Feels Like, Humidity, Dew Point, Wind Speed, Wind Gust, UV Index, Air Quality Index, Pressure, Solar Irradiance, Light Level, and Internal Temperature.

 Below all of that is the system status box (which appears under current conditions on desktop, or the daily summary on mobile). It basically is to indicate the system health - showing battery levels, the signal strength from the receiver, and the in

Below all of that is the system status box (which appears under current conditions on desktop, or the daily summary on mobile). It basically is to indicate the system health - showing battery levels, the signal strength from the receiver, and the internal temperature of the junction box (the WeatherHAT has a BME280 on it that does these readings).

The battery gauge in Beacon Hill Weather likes to be dramatic and say the battery is a lot more drained than it is, so I also show the voltage readings coming back too. The battery can safely go down to 3.3-3.4 volts without much of an issue.

 And below all of this is the graph! It just wouldn’t be one of my projects without some graphs.  These graphs are powered by the MUI X library. The graph shows all the daily data up to the current time, and hovering over the data will show you the v

And below all of this is the graph! It just wouldn’t be one of my projects without some graphs.

These graphs are powered by the MUI X library. The graph shows all the daily data up to the current time, and hovering over the data will show you the value reported for that time. There’s also optimizations on mobile so this tooltip goes above your finger so you can actually read the data in the tooltip.

 And here’s that graph selector…again, truly a ridiculous amount of data you can see on this weather station.  And just note that rainfall rate hides itself if it hasn’t rained so…yeah. Big data.

And here’s that graph selector…again, truly a ridiculous amount of data you can see on this weather station.

And just note that rainfall rate hides itself if it hasn’t rained so…yeah. Big data.

 Next up on our big tour of Beacon Hill Weather is the history page! Oh, and you can open the sidebar to get a full description of each page, along with version information.  The history page is meant to show a day-by-day summary of what Beacon Hill

Next up on our big tour of Beacon Hill Weather is the history page! Oh, and you can open the sidebar to get a full description of each page, along with version information.

The history page is meant to show a day-by-day summary of what Beacon Hill Weather recorded. It’ll conveniently show the high and low temperatures (along with what time they were recorded), sunrise and sunset times, along with a shortened almanac for each day.

Each page has 10 days, and there’s pagination at the top and bottom of each page to help you navigate.

 Before we hop into the history page, one more mention. If you hover over any sunrise or sunset time, you’ll see the astronomical, nautical, and civil sunrise times displayed in a tooltip. Very nifty!

Before we hop into the history page, one more mention. If you hover over any sunrise or sunset time, you’ll see the astronomical, nautical, and civil sunrise times displayed in a tooltip. Very nifty!

 Diving into the history page - it’s a pretty simple page with not much going on. At the top, you’ve got navigation to flick between the previous and next day. Below that is just a repeat of what’s seen on the history page itself.  Below that box is

Diving into the history page - it’s a pretty simple page with not much going on. At the top, you’ve got navigation to flick between the previous and next day. Below that is just a repeat of what’s seen on the history page itself.

Below that box is the graph for viewing all the data for the day from 12:00 AM to 11:59 PM. There’s a lot of graphs on this website.

 And below that is just the daily summary (like on the homepage), but for the entire day.

And below that is just the daily summary (like on the homepage), but for the entire day.

 Next up is the climatology page! This page draws inspiration from How Hot Is It In My Dorm Room’s climatology page, which was intended to show the min/avg/max data for a day.  When you load the page, you’re greeted to a graph showing the min/avg/max

Next up is the climatology page! This page draws inspiration from How Hot Is It In My Dorm Room’s climatology page, which was intended to show the min/avg/max data for a day.

When you load the page, you’re greeted to a graph showing the min/avg/max highs of the current year, with a dropdown to switch to older years (since its early January, I switched it to 2024). Hovering over any point will show you the precise values for any data point. Seeing the temperature graph at the end of 2025 is going to be incredibly cool, and I cannot wait.

Similarly to all other graphs, you can dial in and see values for lots of data types to see how they’ve trended throughout the year or day-by-day.

 Below the graphs is the monthly summaries table, which allows you to see the almanac for every month as captured by Beacon Hill Weather. Click the dropdown at the top and away you go!  Just like all the other almanacs, you can see the min/avg/maximu

Below the graphs is the monthly summaries table, which allows you to see the almanac for every month as captured by Beacon Hill Weather. Click the dropdown at the top and away you go!

Just like all the other almanacs, you can see the min/avg/maximum data points with the time they occurred.

 Next up is the data explorer page! I hope you still like graphs because we’re not done with the graphs just yet.  The data explorer page is made to get into the weeds with Beacon Hill Weather’s data, allowing any user to query up to 60 days of data

Next up is the data explorer page! I hope you still like graphs because we’re not done with the graphs just yet.

The data explorer page is made to get into the weeds with Beacon Hill Weather’s data, allowing any user to query up to 60 days of data within the station’s data range (which currently starts on September 4, 2024).

Two options are provided to the user - you can have rainfall totals go into a cumulative mode (rather than resetting each day, which is how it is in the raw data), and also download data to a JSON file (there’s some work to be done with showing users how keys are translated, since shortened keys are used to save data over the wire).

After that, hit the submit button and…

 Boom, look at that graph.  On the frontend, I do some trickery to ensure the number of points doesn’t exceed 5,000(ish) by only showing every nth point to hit this limit. This was done for performance reasons, as past 5k points the MUI X library can

Boom, look at that graph.

On the frontend, I do some trickery to ensure the number of points doesn’t exceed 5,000(ish) by only showing every nth point to hit this limit. This was done for performance reasons, as past 5k points the MUI X library can’t really render a graph efficiently.

The graph page will tell you the number of points on the graph and if it’s doing this point skipping business.

 And here’s that cumulative rainfall option coming into play, showing you all the rainfall that occurred in this 31 day period I selected.

And here’s that cumulative rainfall option coming into play, showing you all the rainfall that occurred in this 31 day period I selected.

 The next three pages on the sidebar (below the divider) are basically support pages for the entire website.  The about page does exactly what it says - it tells you about Beacon Hill Weather in excruciating technical detail. I’ll spare you that on m

The next three pages on the sidebar (below the divider) are basically support pages for the entire website.

The about page does exactly what it says - it tells you about Beacon Hill Weather in excruciating technical detail. I’ll spare you that on my portfolio entry though.

 Next up is the changelog page which, well, tells you what changes in each version of Beacon Hill Weather! It’s an accordion setup within MUI that shows each version, when it was released, and then a changelog that I type up for each version.

Next up is the changelog page which, well, tells you what changes in each version of Beacon Hill Weather! It’s an accordion setup within MUI that shows each version, when it was released, and then a changelog that I type up for each version.

 Lastly is the public API page, which is basically a fancy redirector to the API for Beacon Hill Weather.  In the spirit of weather data being publicly accessible for anyone - I’ve done exactly the same for Beacon Hill Weather and opened up the API f

Lastly is the public API page, which is basically a fancy redirector to the API for Beacon Hill Weather.

In the spirit of weather data being publicly accessible for anyone - I’ve done exactly the same for Beacon Hill Weather and opened up the API for anyone to use without a key.

 The link takes you to a Swagger page generated by FastAPI (the library being used for the API), with interactive elements and all the routes in one convenient place!  Hopefully in the future, I can hook the station into Wunderground and the NWS CWOP

The link takes you to a Swagger page generated by FastAPI (the library being used for the API), with interactive elements and all the routes in one convenient place!

Hopefully in the future, I can hook the station into Wunderground and the NWS CWOP (Citizens Weather Observer Program).

 Two more things - the homepage can (and will) show system alerts whenever I deem necessary. These are usually to announce outages relating to the station whenever I need to do maintenance, or something happened (like the AQI sensor going down on Chr

Two more things - the homepage can (and will) show system alerts whenever I deem necessary. These are usually to announce outages relating to the station whenever I need to do maintenance, or something happened (like the AQI sensor going down on Christmas Eve!).

And below that, you’ll see that Beacon Hill Weather will also report on any weather alerts that affect Beacon Hill! At a glance, it shows the alert name, when it starts (or expires), and a button to show more info.

 Click on the more info button, and you’re greeted with a modal showing you all the information you can get your hands on with the alert.  A lot of work went into reading the NWS API and getting this formatted in a way that looks like what you’d see

Click on the more info button, and you’re greeted with a modal showing you all the information you can get your hands on with the alert.

A lot of work went into reading the NWS API and getting this formatted in a way that looks like what you’d see when visiting the official NWS website.

 Oh, and did I mention there’s also dark mode? By default, Beacon Hill Weather will load into whatever your system appearance is, with options to change into manual light/dark mode. Your setting is saved to local storage.

Oh, and did I mention there’s also dark mode? By default, Beacon Hill Weather will load into whatever your system appearance is, with options to change into manual light/dark mode. Your setting is saved to local storage.

 To round up the article, here’s Beacon Hill Weather out in a very, very snowy Boston in December. Of course, the station kept on going as if nothing was happening. Plus, it’s very cool to see it in the snow! The snowstorm did inspire a possible snow

To round up the article, here’s Beacon Hill Weather out in a very, very snowy Boston in December. Of course, the station kept on going as if nothing was happening. Plus, it’s very cool to see it in the snow! The snowstorm did inspire a possible snow depth sensor purchase but…that’ll be for later.

Beacon Hill Weather has been an absolute joy to build and the most fun I’ve had with a project to date. It’s crazy to say I made a weather station, it sits on my roof, and it sends down accurate weather data every single minute of every single day.

This has been an incredible project, a lifelong dream of mine, and such a marvelous learning experience - plus, this project isn’t done just yet!

In short, Beacon Hill Weather rules.