Skip to content

Final Project

Weather Report (Art Installation)

“Weather Report” is an installation that changes its behavior according the city that you choose. The object gets your input through an online form and uses an open API to know how is the weather in that place. With the result it make a visual output mimicking the weather in the place you chose. It works with pumps, neopixels and a fog generator to simulate the weather conditions (sunny, cloudy, rainy, rainy and foggy).


Part Provider Quantity Price Total
Plywood Sheet 2495x1245x15mm Fab Lab BCN 1 € 0,01 € 0,01
Acrylic Sheet 297x420x4mm Servei Estació 2 € 12,00 € 24,00
PLA Filament (grams) Fab Lab BCN 84 € 14,85 € 1,27
Water pump 12v Amazon 1 € 13,95 € 13,95
120mm Fan 12v Fab Lab BCN 1 € 0,01 € 0,01
Water tank Leroy Merlin 1 € 5,99 € 5,99
LED strip (meters) Fab Lab BCN 2 € 36,40 € 14,40
Mist maker Amazon 1 € 12,35 € 12,35
Power supply 12v Amazon 1 € 15,85 € 15,85
Power supply 5v Amazon 1 € 12,35 € 12,35
PCB - R10k SMD DigiKey 4 € 0,06 € 0,24
PCB - R1k SMD DigiKey 1 € 0,06 € 0,06
PCB - R100 SMD DigiKey 2 € 0,06 € 0,12
PCB - R0 SMD DigiKey 4 € 0,06 € 0,24
PCB - C0.1uF SMD DigiKey 1 € 0,27 € 0,27
PCB - Switch 6mm SMD DigiKey 2 € 0,91 € 1,82
PCB - N mosfet SMD DigiKey 2 € 0,89 € 1,78
PCB - Led SMD DigiKey 2 € 0,18 € 0,36
PCB - Relay DigiKey 2 € 1,33 € 2,66
PCB - Voltage Regulator 5v SMD DigiKey 1 € 0,68 € 0,68
PCB - Voltage Regulator 3.3v SMD DigiKey 1 € 0,63 € 0,63
PCB - Power Jack SMD DigiKey 1 € 0,64 € 0,64
PCB - ESP8266 12F Amazon 1 € 5,59 € 5,59
PCB - 2 way Born Screw DigiKey 2 € 0,32 € 0,64
PCB - 3 way Born Screw DigiKey 1 € 0,35 € 0,35
Total € 116,25

For the plywood I used only scraps from the lab, mainly from the CNC week, the PLA filament is according a 1kg (€14,85) and the LED strip is according 5m (€36,40) but I also used some scraps from the lab. The 120mm fan was lent by Edu. I used the Tables Generator to pass the BOM to Markdown language.

Design progress

Talking with the instructors we agreed that this may be the most academic-friendly project so I’m working on it for the Fab Academy Final Project. We talked about not using a Raspberry Pi with a GPS antenna but using an ESP that extracts it’s location data from the internet. I’ll have to test if the pumps can send water high enough and if the flow will be sufficient.

I redesigned (over and over) it on fusion:

Update 12/03: I made a small scale model to see how the design is going:

I tried this round model but I didn’t like it so I went back to the cube:

Final Object

For the final installation I’m using this signal flow:

It works like this:

1) You go to a web interface (from your favorite browser) that is only accessible in the local network (the address will always be informed physically in the installation), in the case of the tests I used a fixed address of The web interface is generated by the ESP8266.

2) The web interface has only a form with the question “Where in the World?”. You have to type the name of the city in the form, the API accepts different languages with no problem, so London and Londres (in portuguese, for example) will have the same result.

3) Then the ESP gets the results in a JSON format and extracts the main weather to decide the output.

4) The object outputs lights and/or water as a visual representation of the weather from the city you chose.

For example, if you type “Barcelona” and it’s a thunderstorm in the city in that moment the object will do a light animation imitating a thunder and turn on the pumps to activate the “rain” of the object.

After some tests and (re)designs I finally found the final form for my installation:

I decided to use a pure cube as a neutral background for the effects that I’m looking for. Using plywood is also a way to try to maintain the nature-focused look.



The code works by basically gathering data from an open weather API and using the info to decide which output is appropriate. I’ll try to explain the code in the order of appearance:

Web Interface (Input)

When uploading the sketch to the ESP8266 I’m also including a index.h that will hold all the HTML code that the web interface is based on. After the WiFi is set we can reset the ESP and it will connect automatically to the SSID you specified. We can use a fixed IP code to always know where we can find the page.

I made it very quickly on Atom, only a few HTML lines and that’s it. As I’m using a specific font I’m calling it from the Google API and defining the sizes of the text styles:

  <title>Weather Report V0.2</title>
  <link href="" rel="stylesheet">

    body {
    background: url("");

    background-repeat: no-repeat; /* do not repeat the image */
    background-size: cover;
    font-family: 'Montserrat', sans-serif;
    font-size: 14px;
    line-height: 1.5;
    margin: 0 auto;
    max-width: 800px;
    padding: 2em 2em 4em;
    text-align: center;
    content: center;
    align-items: center;


h1, h2, h3, h4, h5, h6 {
    line-height: 1.3;
    margin: auto;
    text-align: center;
    text-decoration-line: none;

 h1 {
    font-weight: 100;
     color: #00000;
     font-family: 'Montserrat', sans-serif;
     margin-top: 3.7em;
     font-size: 28px;

h2 {
    color: #00000;
    font-weight: 300;
    margin-top: 1.3em;
    font-size: 14px;

h3 {
    margin-top: 1.3em;
    font-size: 18px;


          <h1>Weather Report</h1>
          <form action="/action_page">
          Where in the world?<br>
          <input type="text" name="city" value="">
          <input type="submit" value="Submit">



It sends the input to the “action page” that is actually the Arduino code so it can manage the output. After this the page reloads itself as a clean interface.

WiFI Manager

I’m using the ESP8266 as a microcontroller for the WiFi connection. I’d like to be a easy setup for anyone so I’m using the WiFiManager library to control the WiFi SSIDs and passwords. This library permits that we configure the WiFi on the go, whenever it can’t find a known network the ESP becomes an Access Point so you can enter the SSID and the password.

You have to call it on the setup:

WiFiManager wifiManager;
wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(255,255,255,0), IPAddress(192,168,1,1));
wifiManager.autoConnect("Weather Report AP");

After this the settings will be saved in the ESP8266 memory and you won’t have to set it again unless you change the network you’re trying to connect.


For the weather reference I’m using the OpenWeather API, a free and easy API to have weather reports in real time from all around the world. The function that is calling the API works like this:

void getWeatherData(String CityName)
String result;

  if (client.connect(servername, 80))   
          {                                         //starts client connection, checks for connection
          client.println("GET /data/2.5/weather?q="+CityName+"&units=metric&APPID="+APIKEY);
          client.println("User-Agent: ArduinoWiFi/1.1");
          client.println("Connection: close");
  else {
         Serial.println("connection failed");        //error message if no client connect

  while(client.connected() && !client.available())
  delay(500);                                          //waits for data
  while (client.connected() || client.available())    
       {                                             //connected or data available
         char c =;                     //gets byte from ethernet buffer
         result = result+c;


It basically calls for the API with a variable that is the City Name, which we get from the web interface input. It’s done by the JSON library.

A good explanation of what is a JSON can be found here but in a nutshell:

“JSON stands for JavaScript Object Notation. It is a lightweight format for storing and transporting data. JSON is often used when data is sent from a server to a web page.”

So what this part of the code is doing is asking for the JSON file of how is the weather on the asked city. When it comes back it is stored on the JSON buffer so we can use it on other function. In this case I’m calling for the “main weather” like this:

String weather = root["weather"]["main"];

After the JSON file of the city is stored the code starts to check if the file has a folder called “weather” and inside it a “main” value (because I’m using only the main weather information). To take a better look on how a JSON file works you can get the response code, copy and paste on this Online JSON viewer:

So in this case the weather is “clear”:

char jsonArray [result.length()+1];
jsonArray[result.length() + 1] = '\0';
StaticJsonBuffer<1600> json_buf;
JsonObject &root = json_buf.parseObject(jsonArray);

The StaticJsonBuffer is the space left for dealing with the information sent by the API, the bigger the space more info you can receive but it also takes longer to load. In this case I used the Arduino JSON assistant to calculate the right size of the buffer for the best performance:

So the total size should be 429 (additional bytes for input duplication) + 1169 (for the ESP8266 platform) = 1598 bytes. I rounded to 1600.


I made different functions for all the effects that I would like to have as an output and gathered all in another function so I could call it from the web interface. I had to firstly check out the API documentation for the weather conditions, so I gathered the possible results into categories which I could play the same animation:

  • Clear;
  • Clouds;
  • Drizzle;
  • Rain;
  • Snow; Thunderstorm; Tornado;
  • Mist; Smoke; Haze; Dust; Fog; Sand;

When the ESP gets the result from the API it runs a function/animation according to the weather:

void climateConditions()
if (realweather =="Clear")
if (realweather =="Clouds")
if (realweather =="Drizzle")
if (realweather =="Rain")
if (realweather =="Thunderstorm")
if (realweather == "Mist")

And each of this functions have a different output, for example the rain03(); can be described like this:

void rain03()
          theaterChase(strip_0.strip.Color(255, 127, 0), 40); //it is an animation from the Adafruit library where it simulates a theater chase light, you can control the color and the speed
          colorWipe(0,0); //this is also from the library, it turns the lights off
          digitalWrite(relay1, HIGH); //turns the pump on
          theaterChase(strip_0.strip.Color(255, 127, 0), 80);
          digitalWrite(relay1, LOW); //turns the pump off
          theaterChase(strip_0.strip.Color(255, 127, 0), 120);

I made the animations with the help of the Neopixel Effect Generator from Adriano Tiger. It is a “online editor to generate Arduino code for neopixel ledstrips without programming knowledge” (words from Adriano) which is really easy to use, has a graphic feedback system and generates the code based on what you input:

In this website you can input the number of LEDs of your strip and the pin that you’re using in the Arduino. You can also make the animations by combining the effects and changing the colors, speed, steps, direction and length. It also gives you an estimation of the current draw.

After you finish creating the animation you can go to the “Generate Arduino Code” button on the corner, copy and paste the code. In my case I copied only the strip_loop functions to call it whenever I want.

Enclosure (CNC cutting)


The cube itself is made from 15mm plywood. I started by getting some components from the 3D Warehouse, a repository for Sketchup 3D models made by it’s community. I measured all the real life components with a caliper and scaled the 3D models to match:

Then I started to accommodate all the components into the cube:

After this I started designing the junctions, fittings and other types of details, like this joint between the horizontal and the vertical plates that fits in the 45 degree joint. The joints are simple pockets:

Laying down the pieces to check how many plywood sheets I would need:

CNC cutting

In Sketchup you can export directly into .dxf so I took it to Rhino to configure the strategies for cutting. When you’re exporting from Sketchup is a good idea to polish the 2D model in Rhino joining the lines, checking for errors and remaking circles (Sketchup uses few sides to make it lighter but it decreases the “resolution” of the circle).

In Rhino I also make some small corrections like the tolerance offset in the pocket joints, 0.2mm in this case. To make square corners inside pockets that can’t be made by the mill I had to modify the drawing by doing holes in the corners, usually called “dog bones”. With a script for Grasshopper called Dog Bone Corner Generator.

You just have to link the polyline that you’d like to use as a Graphic and set some parameters as you wish. The output is a new polyline with the dog bones inserted.

After this is time to prepare the cutting strategies on RhinoCam. I divided into Screws, Pockets, Profile Inside, Profile Outside and Profile 45. I also simulated all the strategies to be sure that everything would go fine.

The machine parameters and the milling bit for the Screws, Pocketing and Profiles were all the same:

  • 6mm 1 flute downcut flat end milling bit: I measured this milling bit that we had in the lab to input all the necessary parameters.

Screws, Pocketing and Profiling:
  Speed: 18.000 RPM
  Plunge: 5.000 mm/min
  Approach: 5.000 mm/min
  Engage: 5.000 mm/min
  Cut: 7.000 mm/min
  Retract: 10.000 mm/min
  Departure: 10.000 mm/min
  Transfer: 15.000 mm/min
  • Screws: I used the Engrave strategy with 3mm depth only to mark the places of the screws that secure the board into the machine.

  • Pockets: This was made with the Pocketing strategy set to do 2 passes of 3mm (rough cut) and 1 passes of 1.8mm (finish cut) to get a smoother finish. It’s also set to follow the polyline from inside to match the drawing sizes and in Climb as I’m using a downcut bit.

A lot of pockets in each board:

Selecting the flat mill profile that I created:

Checking the cut speeds and feeds:

Entering along the path helps to avoid chipping the board, while exiting in this case is better if you do it along the axis because of the hardness of the plywood.

  • Profiles: This was used only to make the circular hole to pass cables inside the cube and follows the same rules from the pockets but with 2 passes of 6mm and 2 passes of 1.4mm to cut through.

To avoid having my pieces flying away while they were cutting I’m using triangular Bridges/Tabs.

The Profile 45 was different because it used a Vee milling bit in 45 degrees. It was important for me to use this so I could hide the joints of the cube.

In this picture you can see the Vee 45 and the Vee 30:

  • 32mm 2 flutes 45 degrees Vee milling bit: I also had to measure the tool to input the parameters.

Profile 45:
  Speed: 20.000 RPM
  Plunge: 2.500 mm/min
  Approach: 5.000 mm/min
  Engage: 2.500 mm/min
  Cut: 2.500 mm/min
  Retract: 5.000 mm/min
  Departure: 10.000 mm/min
  Transfer: 15.000 mm/min

I used this settings after making several tests with Mikel to avoid breaking the tool (as we only had one), burning the wood or making too much noise (normally it means bad things).

I didn’t use tabs on this strategy because all the pieces had a side that was made with the Profile strategy so it already had tabs.

Main Board (PCB Making)

I designed this board in EAGLE from scratch following some guide lines from the Arduino ESP8266 Docs, mainly the Improved stability part. Some buttons and resistors are required to program and to run codes in the ESP8266.

After this was only a matter of placing two relays circuits (mosfets, LEDs, resistors and relays) and an output for the LED strip.

The ESP8266 runs on 3.3v but the relays and the LED strip runs on 5v so I used two voltage regulators: one to 3.3v and other to 5v so the board could take also 12v if needed.

Part Provider Quantity Price Total Reference
PCB - R10k SMD DigiKey 4 € 0,06 € 0,24 RES 10.0K OHM 1/4W 1% 1206 SMD
PCB - R1k SMD DigiKey 1 € 0,06 € 0,06 RES 1.00K OHM 1/4W 1% 1206 SMD
PCB - R100 SMD DigiKey 2 € 0,06 € 0,12 RES 100 OHM 1/4W 1% 1206 SMD
PCB - R0 SMD DigiKey 4 € 0,06 € 0,24 RES 0.0 OHM 1/4W 5% 1206 SMD
PCB - C0.1uF SMD DigiKey 1 € 0,27 € 0,27 CAP CERAMIC .1UF 250V X7R 1206
PCB - Switch 6mm SMD DigiKey 2 € 0,91 € 1,82 SWITCH TACT SMD W-GND 160GF
PCB - N mosfet SMD DigiKey 2 € 0,89 € 1,78 MOSFET N-CH 30V 1.7A SSOT3
PCB - Led SMD DigiKey 2 € 0,18 € 0,36 LED GREEN CLEAR 1206 SMD
PCB - Relay Amazon 2 € 0,89 € 1,78 SRD-12VDC-SL-C
PCB - Voltage Regulator 5v SMD DigiKey 1 € 0,68 € 0,68 IC 5.0 100MA LDO VREG SOT23
PCB - Voltage Regulator 3.3v SMD DigiKey 1 € 0,63 € 0,63 IC 3.3V100MA LDO VREG SOT23
PCB - Power Jack SMD DigiKey 1 € 0,64 € 0,64 CONN PWR JACK DC 0.65X2.75MM SMD
PCB - ESP8266 12F Amazon 1 € 5,59 € 5,59 ESP8266 Wifi Module ESP-12E
PCB - 2 way Born Screw Amazon 2 € 0,32 € 0,64 AC 300V 16A 3 Ways 5mm Pitch
PCB - 3 way Born Screw Amazon 1 € 0,35 € 0,35 AC 300V 16A 2 Ways 5mm Pitch
Total € 15,20

I was trying to make the smallest board possible so I had to use a lot of 0Ω resistors as jumpers:

To make it a little more customized I brought the export to Illustrator and added some vectors:

I took it to mods to make the Roland mill file as usual and milled the board:

Final board

Actually I had to do it two times because in the first try I did not connected the ESP as the documentation said so it was too much unstable.

As you can see in this picture the board has the ESP8266 as a microcontroller, two buttons for flashing and resetting, one power jack that can take up to 12v, 2 power regulators (3.3v and 5v), a 3 way borne connector to the led strip and two relays for the pump and the mist machine.

I can program it by the FTDI connector in the Arduino IDE using the settings for “Generic ESP8266”. As I had some troubles with the traces I had to make some jumpers but it didn’t affected the board.

To protect it from humidity I used the this box that I already had.

Rain Effect (Laser Cutting)

The “rain” part of the installation is basically a shower plate made in acrylic but with really specific hole sizes to make it drip more like rain.

When I made a research about it I found this Real Rain shower plate from Kohler.

It uses 3 different hole sizes to achieve the “rain effect” by dripping in different rates:


I tried to do my own version, beginning with a little project of how it should work:

To check the effect I did some tests with a model first. I used Grasshopper to make different sizes of circles scattered in the plate to simulate the rain:

But the dripping rate was too low, so I went back to Grasshopper to fix it.

Shower plate

The Grasshopper script is really simple: It draws a square of 360x360mm and offsets it by 9mm. Then it scatters 900 points inside this square and turn then into circles varying size from 0.15 to 0.50 (in the second version).

To generate the rest of the shower plate I used the, having a .dxf file so I could easily cut the pieces in the laser cutter and fit it really nice.

Laser cutter settings for a 4mm acrylic:

  • Power: 85 / Speed: 0.6 / Hz: 20k

The fitting was perfect with no leaks but the volume of the tank was too big so I added a piece of foam to make the plate fill quicker:

I screwed some magnets to the top of the plate to make it “snap fit” the box:

Rails (3D Printing)

Also in SketchUp I designed a rail to direct the led strip into a 45 degree angle:

I exported the model into .STL, sliced in Cura using the preset settings for draft (0.2mm layer height) and 3D printed in PLA using the Anycubic that we have in the lab.

I used a tolerance of 0.2mm in the fitting and it worked fine:

I glued the pieces to make sure that would hold the weight of the led strip.

And then finally attached the rail into the showerplate:

Mist Effect

The mist effect comes from a mist machine we had on the lab. It is composed by 3 ceramic diaphragms that vibrate in an ultrasonic frequency to create the water mist.

You just have to throw it on the water tank (will not work with distilled water).

I am forcing the mist out with a 12v fan that is connect together to the mist machine in the relay.

I placed the fan in the top piece of the top part so whenever the mist machine comes into action the fan will blow the mist out.

Identification (Vinyl Cutting)

I made a simple identification design in Illustrator for the object as a vector so I could cut it on the vinyl cutter, nothing more than the pen and the text tool:

I cut it on the vinyl cutter in black vinyl using the Roland GX-24 with the following settings:

  • Speed: 5cm/s / Force: 120gf / Pen foce: 0 / Thickness: 0.250mm

Then transfered the vinyl with a masking tape:

Power supplies

I used a 5v 10a power supply to power the LED strip and a 12v 8.5a to power the pump, the fan and the mist maker. They are daisy chained in the AC lines to use only one power cable.

As i’m using power regulators on my board it also powers the ESP8266 (3.3v) and the relays (5v).


I decided to leave all the electronics outside for the first tests so I just had to connect the shower plate into the wooden cube and pass some cables through.

Firstly I assembled the LED strip into the rail and into the shower plate:

Then I assembled the wooden box, It was a perfect fit but I used glue to be sure.

As I was already glueing I took some extra time to make a wood filler with some glue and sawdust to cover some holes after mounting everything.

I sanded everything in 3 passes: 80, 120 and 180 grit and finished with linseed oil. You have to apply it directly to the surface with a cloth and let it dry for 24h.

I used magnets to easily snap mount the plate into the cube:

The original idea was to hang it to the ceiling but to make it more easily presentable Edu, one of our instructors, suggested to use transparent acrylic as a holder:

And it worked very well!

Inside was a little messy because the first tests were with the electronics out so the cables had to be long. I decided to leave the long cables in the case I need to do some maintenance.

You can see the water tank with the mist maker, the water pump protected by a latex glove to avoid the humidity and the box that holds all the electronics.

Final tests


This project is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

This means that you are free to:

  • Share — copy and redistribute the material in any medium or format;
  • Adapt — remix, transform, and build upon the material.

Under the following terms:

  • Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use;
  • NonCommercial — You may not use the material for commercial purposes;
  • ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.


I’d like to thank all the instructors and my classmates for all the help during this project. I’ll try to name them all but sorry if I forgot someone:

Eduardo Chamorro, Esteban Giménez, Santiago Fuentemilla, Xavi Domínguez, Óscar González, Guillem Camprodon, Victor Barberan, Mikel Guelbenzu, Yiannis Vogdanis, Diar Amin, Josep Marti, Gustavo de Abreu, Alberto Martínez, Eva Blsakova and Juan Carlos Rincon.

Besides people who helped in the project I’d like to thank people from the lab: friends from the MDEF who also where a really good company inside and outside the classes. People from the Fab Lab Barcelona administration and other employees who made my staying here a really good time.

The open-source community is made by everyone so I’d also like to thank all the people that made their project open-source. It helped me as inspiration, reference, guidance or some other way in this project. I’ll keep sharing all the work related to this project too.