WeatherCube, an Edge-lit 6 Day Weather Forecast

by marzsman in Circuits > LEDs

1744 Views, 35 Favorites, 0 Comments

WeatherCube, an Edge-lit 6 Day Weather Forecast

IMG_20230310_173311.jpg
WeatherCube
WeatherCube.jpg

WeatherCube shows a 6 day forecast with multiple edge-lit acrylic panels.

I use the OpenWeatherMap API to request the weather forecast, I simplify the data into a weather type, then break it down into separate weather elements, and finally light up the appropriate panels.

Each weather element is a different panel: one for the sun in yellow, one for the cloud in white, two or three types of rain drops in blue, and so on.

After a couple of seconds the icon changes to the next days weather.

Supplies

Material


  • Some acrylic plates, 1 for each weather element (Sun, cloud, rain, snow, ...) and 1 for the front
  • A RGB LED strip which can be cut in smaller parts, I love those 4mm strips because they line up perfectly with the acrylic
  • Electrical wires
  • A microcontroller with Wifi connection, I used the Pico
  • Some scraps of wood to make the case


Tools


  • Soldering iron
  • Cable stripper
  • 3D printer
  • Laser cutter
  • Some wood working tools
  • Table saw or router
  • Woodglue
  • Some tape


Software


  • Thonny or Arduino IDE or another IDE you use to program your microcontroller
  • An API key at openweathermap.org

The Pre-prototype

IMG_20141008_004119.jpg
IMG_20210306_154736603.jpg
IMG_20140810_002606.jpg

I got this idea a long time ago. I had the chance to play around with a laser cutter at our local makerspace and I was blown away by it. In some way, I discovered the magic of edge-lit panels, and I really wanted to make a project with this.

The easy part was using the laser cutter to cut out the acrylic and the panels for the frame. But back then, LED strips weren't as popular and accessible as they are these days, so I tried to solder my own. That took me ages, and they were chunky and not very reliable.

When I put it all together, I was happy with the acrylic light effect, but the overall look of the product wasn't the result I had hoped for, so the project ended up in a box.

Now, fast-forwarding almost a decade later, with a couple of unsuccesfull retries, to a time when we have a huge range of Wifi connected microcontrollers, 3D printers, laser cutters, and LED strips that are cheap and easy to use, available. It was the perfect time to pick up this project again and try a full rebuild.

The Inside

IMG_20210306_155931332.jpg
WeatherCube - acrylic holder.png

The acrylic plates


For this version I decided to use 6 acrylic plates.

  • A sun
  • A partial sun
  • A cloud
  • A drop of rain (drizzle)
  • Rain (which I also use as snow)
  • Heavy rain

I know there are more options but I wanted it to be less chunky than the old version. And these where the most common weather types where I live.

I reused the plates from the old project and that's why I have no idea where the original vector files are so I can't share these. But I used some weather icon font or vector. I selected a simple outlined icon set to give it a clean look without too much detail.


The 3D printed plate holder


To keep the acrylics and the LED strips in place I designed a body in Tinkercad.

Along the way, I also decided to only use strips on the top or bottom to reduce the amount of LEDs. So only in these parts there are slots.

The slots are also a little bit deeper so there is less light bleeding onto the other panels. And this way the panels are also better held into place.

At first, I designed the box as a whole, but quickly came to the conclusion that it wasn't easy to insert the plates and the LED strips. So I exported it as 4 separate parts.

https://www.tinkercad.com/things/2oMrll1SZdt

I added the separated parts as STLs to download

I also printed a front passe-partout and a backplate

Front: https://www.tinkercad.com/things/jn3ZKdJRoRS

Back: https://www.tinkercad.com/things/3eqcjnnVOIm

The Electronics

IMG_20210307_204833324.jpg
Screenshot 2023-02-27 at 08.56.43.png
IMG_20210319_075328155.jpg
IMG_20230225_102828.jpg
IMG_20230225_103031.jpg
IMG_20230225_103928.jpg

I wanted to keep the amount of active LEDs per weather type as low as possible, so I could power them from the microcontroller. That's why I decided to only add 1 LED strip per plate and at the side where the weather element was closest to. So the raindrops and cloud are illuminated from the bottom and the suns from above.

Most strips are 6 LED's but some needed less, like the raindrops.

So eventually this is what I needed:

  • Sun: From top side = 6 LEDs
  • Partial sun: From top side = 6 LEDs
  • Cloud: From bottom: 6 LEDs
  • Heavy rain: From bottom: 4 LEDs
  • Soft rain: From bottom: 4 LEDs
  • Drizzle: From bottom: 3 LEDs

I added 1 extra strip of 6 LEDs in the front to indicate which day of the week we are, so I could have a 6 day forecast. The first LED always shows the next day and every next day in the cycle lights up the next LED. To make it easier I gave weekend days a different colour.

Now I had to solder all the strips into 1 long string and install them into 3D printed parts. I started with the LED strip the closest to the microcontroller and each time I soldered a new one to it I tested if everything was still working. Believe me, those 4mm strips aren't easy to solder :)

When the strips where connected, I installed them and did some last tests and used some tape and hotglue to keep it all together.

And now time for some basic wood working.

The Outside

IMG_20230225_104316.jpg
IMG_20230225_155519.jpg
IMG_0042.PNG
IMG_20210317_231124468.jpg
IMG_20230225_104114.jpg
IMG_20230225_104138.jpg

The first plan was to 3D print a case but then I got the idea to make one with wood, to give it an overall nicer finish.

I salvaged some wood from pallets and sanded it until I got the beautiful colour of the wood visible again.

For the joints, I didn't want to use any screws or nails and just glue it together, so I used rabbet joints, these are very strong and easy to make using a table saw or router, or even with hand tools.

I also milled some grooves in the corners so I had room to guide the wires (which I didn't use), and also on the back so I could fit in a back plate.

When everything was glued together, I did some more sanding and used a clear varnish to keep the wood colour.

The end result was exactly what I was hoping for.

I did make a little calculation error and I had to remove some layers from the top and bottom of the 3D printed acrylic plate holder.

The Code

I wrote the code in MicroPython. I'm not going into detail on how to start programming a Raspberry Pico, there are already plenty good tutorials available.

The full code of this project is available on my Gitlab repo, you can download it and copy all the files to your pico to get started. I'm not 100% sure but I guess that you can use this code on other MicroPython compatible boards.

https://gitlab.com/sometimes-i-make/weathercube


1. Get the weather data


The first requirement is to create an account at https://openweathermap.org

After you create an account you go to https://home.openweathermap.org/api_keys and generate a new API key.

Write down this key, we will use it to request the forecast.

To make the request I use the One Call API 2.5 request. It looks like they don't offer a link to the docs of the 2.5 version anymore. The API still works so you can just follow this link https://openweathermap.org/api/one-call-api

You can also use the 3.0 API but then you have to give your credit card, it's still free for up to 1000 requests a day, so that should be more then enough.

Anyway I'll keep working with the 2.5 version for now.

Next you should find your Latitude Longitude location. This is your position on the planet which is needed for the API request so the API can send you your local weather forecast.

If you go to this site https://www.latlong.net/ you can find your location by typing in your location. Then you copy the latitude and longitude.

Now we have everything we need to make the request.

For the request we use the API key we created and the latitude / longitude of our location. Because we don't need all the data returned from the request, only the daily part, we replace {part} with "current,minutely,hourly,alerts"

You can add your own credentials in the file config.py in the root of the project for easy configuration.

https://api.openweathermap.org/data/2.5/onecall?lat={lat}&lon={lon}&exclude={part}&appid={API key}


To request the data with MicroPython I use the http library. I convert the response to json and then I loop through the daily data and add the weather forecasts for each day to an Array

def get_weather():
global forecast
print('get the weather from openweathermap.org')

url = f"https://api.openweathermap.org/data/2.5/onecall?lat={lat}&lon={lon}&appid={owm_api_key}&exclude=current,minutely,hourly,alerts"
response = http.get(url)

# parse the response to json
weather_data = response.json()

# store the forecasts in an array
forecast = []

# get the daily forecasts
if weather_data.get('daily') and len(weather_data['daily']) > 0:
# skip today's weather
weather_data['daily'].pop(0)
for day in weather_data['daily']:
forecast.append(getIcon(day['weather'][0]['icon'], day['weather'][0]['id']))

print('The forecast for the next days', forecast)



To convert the weather type I receive from openweathermap I used the key of the weather icon they return.

I then grouped and map these icon to my own, easy to read, weather type keys.

def getIcon(code, id):
if code in ['01d', '01n']:
# Sunny
icon = 'sun'
elif code in ['02d', '02n']:
# Few clouds
icon = 'cloudy'
elif code in ['03d', '03n', '04d', '04n']:
# Cloudy
icon = 'clouds'
elif code in ['09d', '09n']:
# Showers
icon = 'showers'
elif code in ['10d', '10n', '11d', '11n']:
if id == 500:
icon = 'drizzle'
elif id == 501:
icon = 'rain'
elif id in [502, 503, 504]:
icon = 'showers'
else:
icon = 'showers'
elif code in ['13d', '13n']:
icon = 'snow'
else:
icon = code
return icon


2. Control the LEDs


First I defined all the colours I need with their RGB values.

Next I defined their position on the LED strip.

Example: the sun, starts at LED 0 and is 6 LEDs long and uses the color yellow

After that I defined all the panels with their strips.

Example: Drizzle has a bit of sun, a cloud and the drizzle icon compined


# colors
white = (255, 255, 255)
orange = (255, 165, 0)
yellow = (255, 255, 0)
blue = (0, 0, 255)
purple = (128, 0, 128)

# weather elements with the start index + the amount of leds + the color
sun = [0, 6, yellow]
halfSun = [6, 6, yellow]
cloud = [12, 6, white]
heavyRain = [24, 4, blue]
lightRain = [28, 4, blue]
drizzle = [32, 3, blue]
snow = [28, 4, white]

days = [35, 6, white]

# weather types, some weather elements are combined into one type
weather_icons = {
"sun": [sun],
"cloudy": [halfSun, cloud],
"clouds": [cloud],
"drizzle": [halfSun, drizzle, cloud],
"rainy": [halfSun, lightRain, cloud],
"rain": [lightRain, cloud],
"showers": [heavyRain, cloud],
"snow": [snow, cloud]
}


Now we can start looping over the forecast array and light up the LEDs.

To control the LEDs I used the following library that makes it A LOT easier, so don't forget to give him a star ;)

https://github.com/blaz-r/pi_pico_neopixel

The loop starts at day 0, so that's the first weather in the forecast array, after every loop we increase the day variable with 1

This way we can get the correct weather key from the forecast array and use this to return the correct weather type

set_leds(weather_icons[forecast[day]])


def set_leds(weather):
print('set the weather')

# set the current day and check if it's a weekend day
day_color = purple if is_weekend(day) else orange
strip.set_pixel(days[0], day_color)

for icon in weather:
for i in range(icon[0], icon[0] + icon[1]):
strip.set_pixel(i, icon[2])

time.sleep(0.01)

strip.show()


I also check if the day index is a week day or a weekend day to make it a little easier to see at which day we are in the cycle.


3. Some extra notes and wrapup


If you pull the repo, make a copy of config_example.py and rename it to config.py. You can add your own settings in this file.

The full program is in the file main.py. This is the file that will run when starting the Pico.

I added some extra configurations in the file main.py, see the comments for more info.

There's also a file boot.py which is responsible for connecting to the Wifi and setting the local time, but I'm not 100% sure is correctly working, this will need some extra debugging.


And that's it. When you start the code you should see the LEDs light up with each different weather.

In the repo there's a script, weather_test.py, which loops over all the weather types which makes it a bit easier to debug.

Extra Note: My strip uses the RGB notation but some use GRB, so if you see weird colors check if this value is correct. You can find all the info about this in the pi_pico_neopixel repo I shared above.

Putting It All Together

IMG_20210319_230329115.jpg
IMG_20210319_225151892.jpg
IMG_20210319_223150816.jpg

Now that everything is up and running it's time to assemble

I installed all parts into the frame in the following order.

  1. The clear acrylic with the days LED strip, I used some black tape to keep it in place
  2. A black passe-partout to give it a nice bezel
  3. The plate holder
  4. A black plate to close it

When I was testing the day cycle it annoyed me that the days weren't very visible.

To fix this I cut out some spacers for the LEDs, and lasered a small line just above the spacer and a small one to the side of it from the front panel.

Than I cut out a piece of black paper and, with a lot of patience and trail and error, I pushed the paper into the slots. After that I taped some blurry tape over it to give the light a diffused effect.

And that was exactly the effect I was looking for. Sorry I don't have more pictures of those steps, see the notes I added on the pictures

Wrapping Up

This project went through many iterations over many years, but I quite like this end result. This idea remained alive somewhere in the back of my head and during these years I tried to improve it from time to time and in the end, I really enjoy the finished product. It's amazing how much technology has advanced over the years and made it much easier to improve on each iteration.

I hope you like the project too, or you can use it as an inspiration to create something totally different.