Introduction: Another IoT Weather Station
The following was a birthday gift for my Dad; inspired by another Instructable that I saw and initially intended to be proved to him as a self-build kit. However on starting to work on this project with him I very quickly realised that the initial tutorial that inspired the gift was out of date and that many of the other online tutorials had significant gaps in their explanations. I therefore decided to publish yet another IoT Weather Station which hopefully would be easy to follow form start to finish.
Further this instructable shows you how to use Blynk, Google Sheets or both to monitor and record sensor readings. What is more, the Google Sheets entries are written directly to the sheet (without having to go via a 3rd party service).
A Stevenson Screen is an "instrument shelter is a shelter or an enclosure to meteorological instruments against precipitation and direct heat radiation from outside sources, while still allowing air to circulate freely around them." (Wikipedia).
- Wemos LolIn - NodeMCU v3 (USD 1.43)
- BME280 (Temperature, Pressure & Humidity sensor) (USD 2.40)
- 6V 1000mA Solar Panel (USD 9.96)
- 5V 1A Micro USB 18650 Lithium Battery Charging Board Charger Module+Protection Dual Functions TP4056 (USD 0.99)
- 4x 1.2V NiMH rechargeable batteries
- Battery Holder (4x AA, side by side & end to end)
- Micro USB Male connector plug
- Cable Ties
- 3x Wing Nuts
- Pole or broom-stick
- Epoxy and/or super-glue (in hindsight, silicon might have worked better)
- Blynk App
- Google Sheets (if you are wanting to have access to the historical data)
- EasyEDA (for drawing schematic)
- Arduino IDE
- Soldering Iron
- Heat Shrink Tubing
- 3D Printer
- Glue Gun
Step 1: 3D Printing - Stevenson Screen
As already mentioned, download the files from https://www.thingiverse.com/thing:1718334 and print the required bits. Assembly instructions are also found in the above link. I did make some modifications (see notes below).
Parts printed are:
- Middle_Ring.stl (x5)
- Middle_Ring_bottom.stl (x1, STL attached above)
- Solid_Plate.stl (x1)
- Solid_Plate_Base.stl (x1)
- My_Solar_Cell_Mount.stl (x2, STL attached above)
The assembly order is:
- Thread the holes
- Screw the M3 bars into the threaded sockets
- Slide in the Sensor_Grid
- The My_Solar_Cell_Mounts are epoxied to the top of the Top_Cover
I drilled holes in the Solid plates to allow the charging cable from the Solar Panel to connect to the charger and then one to allow the cable to run from the controller to the sensor on the Sensor_Grid.
Once completed, the sensor was programmed to take the following readings every 60 minutes:
- I customised the solar cell mounts to be better suited to hold my solar cell.
- I installed the electronics in between the Pole_Mount and Solid_Plate. This did not appear to provide good protection for the electronics. I therefore modified on Solid_Plate so that it had a skirt which would then close the gap and thereby provide better protection for the electronics. Some of the above photos were taken before I made this change.
- My epoxy landed up not holding the solar panel which I then re-attached with super glue. I think I will land up having to use silicon.
Step 2: The Circuit
Connect the circuit as shown in the schematic, mounting the LoLin and BME280 on the 3D-printed mesh as shown in the photo.
BME280 -> LiLon
- VCC -> 3.3V
- GND -> GND
- SCL -> D1
- SDA -> D2
LiLon -> LiLon
- D0 -> RST (this is needed in order to wake the controller up from deep sleep but must only be connected after the code has been uploaded to the controller)
I had challenges getting a suitable LiLon battery. Also for some reason I had no success powering via VIN. I therefore powered as follows:
- Output from the TP4056 was wired to the Male USB connector which then was plugged into the board's USB socket in order to power it.
- B- and B+ on the TP4056 was connected to the AA battery holder which held the NiMH batteries.
Step 3: IoT - Blynk
"Blynk is a hardware-agnostic IoT platform with customizable mobile apps, private cloud, rules engine, and device management analytics dashboard". Basically it allows you to securely manage and monitor remote sensors from anywhere in the world via the Internet. While a commercial service, each account comes with 2000 free credits. Credits enable you to associate different gauges, displays, notifications etc with your sensor or sensors. While the subscription pricing is out of the range of a hobbyist's budget, the free credits are enough for a simple project like this one.
To start using the service you will need to first download the Blynk App to your phone/device, create and account (or log on with existing account) and then create a new project as follows:
- Choose your hardware
- Give your project a name (in this case I used "Weather Station".
- Click "Create"
- You with then get an Auth Code e-mailed to you.
You will not need to add the required widgets. With my 2000 free credits I added the following:
- 3 Gauges
- 1 Super Chart
The gauges and charts were set up as per the attached photos, each being assigned its own virtual pin that would be used latter in the code.
Once done with the settings, the play button on the top right can be pressed to start collecting date.
For more information see
Step 4: Code - Preparing the Arduino IDE
The following libraries will need to be added to the Arduino IDE in order to complete this project:
- https://github.com/adafruit/Adafruit_BME280_Library (need for the temperature, pressure and humidity sensor )
- https://github.com/esp8266/Arduino (this gives you access to the ESP8266 board)
- https://github.com/blynkkk/blynk-library/releases/tag/v0.6.1 (the Blynk library)
- https://github.com/electronicsguy/ESP8266/tree/master/HTTPSRedirect (HTTPSRedicect needed for connecting to Google Sheets)
For instructions on installing libraries for the Arduino IDE, visit https://www.arduino.cc/en/guide/libraries.
My hardware settings where as follows:
- Board: NodeMCU 1.0 (ESP-12E Module)
- Upload Speed: 115200
When using the attached code in the following steps, please always refer to the comments in the code with respect to adding the following:
- Wifi SID
- Wifi Password
- Blynk authorisation key
- Google Script ID
- Google Sheet sharing key
Step 5: Code - Blynk
I battled for ages to get my BME280 sensor to work until I found an example that contained the following line.
- status = bme.begin(0x76); //The I2C address of the sensor I use is 0x76
It appears that I needed to set the sensor address. Once I had done this it all worked just fine.
Blynk has a really nice mobile user-interface it does however have the following limitations:
- Only 2000 free credits, projects requiring more than that require an expensive monthly subscription (unless you host and maintain your own Blynk server).
- Unless you host your own Blynk server, you cannot export historical data.
For the above reasons I looked at how I could integrate my data collecting process into a Google Sheet. This is covered in the next section.
Step 6: Code - Google Sheets
In order to record your readings so that you can analyse historical data at a later date you need to write it to some sort of database. The HTTPSRedirect library lets us do this by writing our data to a Google Sheet.
The main limitations with this approach are as follows:
- No nice mobile user-interface
- A Google Sheet can have a maximum of 400 000 cells. For this project this is not a big issue as it will take just over 11 years before this limit is reached.
The Google Sheet is set-up as follows.
Create a Google Sheet with two sheets.
Sheet 1: Data
The Data sheet needs 4 columns i.e. Date/Time, Temperature, Humidity, Pressure (columns A to D). Format the columns appropriately e.g. Column A to be "Date Time" so that the date and time is shown in the cells.
Sheet 2: Dashboard
Create the Dashboard sheet as per the attached photos, entering the formulae as listed below:
- B2: =counta(Data!B:B)-1
- B3: =B1+TIMEVALUE(CONCATENATE("00:",Text(G7,"0")))
- B6: =query(Data!A2:D,"Select B order by A desc limit 1")
- C6: =query(Data!A2:D,"Select C order by A desc limit 1")
- D6: =query(Data!A2:D,"Select D order by A desc limit 1")
- B8: =query(Data!A2:D,"Select A order by B desc limit 1")
- C8: =query(Data!A2:D,"Select A order by C desc limit 1")
- D8: =query(Data!A2:D,"Select A order by D desc limit 1")
- B9: =query(Data!A2:D,"Select B order by B desc limit 1")
- C9: =query(Data!A2:D,"Select C order by C desc limit 1")
- D9: =query(Data!A2:D,"Select D order by D desc limit 1")
- B11: =query(Data!A2:D,"Select A where B is not null order by B asc limit 1")
- C11: =query(Data!A2:D,"Select A where C is not null order by C asc limit 1")
- D11: =query(Data!A2:D,"Select A where D is not null order by D asc limit 1")
- B12: =query(Data!A2:D,"Select B where B is not null order by B asc limit 1")
- C12: =query(Data!A2:D,"Select C where C is not null order by C asc limit 1")
- D12: =query(Data!A2:D,"Select D where D is not null order by D asc limit 1")
- G3: =4+B2*4+29+17
- G4: =(G2-G3)/G2
- G6: =G2/4 G8: =G7*G6
- G9: =(G8/60)/24
- G10: =G9/365
- G11: =(((((G2-G3)/4)*G7)/60)/24/365)
Google Sheets can have a maximum of 400,000 cells. This is used, together with the fact that each reading uses 4 cells, to calculate how much space is left and when it will run out.
It may be possible to improve on these formulae. I was doing two things here i.e. learning about the query formula and then also writing some formula in such a way as to help me remember the logic behind them.
The "Chart Editor" screenshot show the basic set-up for the the Temperature graph. The other graphs where created using the same set-up. The only difference between the graphs was the minimum vertical axis values (found under the customise tab). The customise tab also has the other settings like access names, graph titles, etc.
We now need a Google Script that will enable us to write our data by calling a URL.
Creating the script
In the Google Sheet URL, note down the key between the "d/" and "/edit". This is your —Your-Google-Sheet-Sharing-Key– and will be needed in the code below.
Next go to Tools > Script Editor and create the Google App Script, pasting the code in the attached GS file. Update the var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/—Your-Google-Sheet-Sharing-Key–/edit"); to reflect your sharing key.
Now publish the script by going to Publish > Deploy as Web App.
Copy the Current web app URL and save it somewhere as you will need it for extracting the GScriptID (—Your-Google-Script-ID–). The GScriptID is the string between "s/" and "/exec?". Ensure that "Anyone, even anonymous" has access to the app. During this process you will be asked to grant some permissions. It is important that you grant these.
Note: Whenever you modify your code, you have to create a “New” Project version and publish it otherwise you will still be hitting the same old code.
You can now test the script by browsing tohttps://script.google.com/macros/s/—Your-Google-Script-ID–/exec?Temperature=10&Humidity=11&Pressure=12. Each time that you refresh this link, a new entry should be added to the Google Sheet.
This above was taken from the following tutorial: http://embedded-lab.com/blog/post-data-google-sheets-using-esp8266/. This tutorial is however out of date and so the associated Arduino code in the next section has been changed to accommodate the latest HTTPSRedirect libraries.
The Arduino Code
See attached code.
Step 7: Code - Blynk & Google Sheets
In order to get the best out of both worlds, one can combine the code for both Blynk and Google Sheets.
See attached code.
Step 8: Final Comments
None of the above are my ideas but rather this a project built on the ideas and work of others. I have enjoyed pulling it altogether into one place. using different technologies and tools to great a fun and practical project. I especially enjoyed learning how to store my readings in a Google Sheet. For this I wish to thank the ElectronicsGuy (Sujay Phadke).
After completing this project I needed to change my wireless settings. I was now working on a different computer. After uploading the changes, the project stopped working. After some troubleshooting I concluded that the deepsleep function was failing. I took the project back home and uploaded it there (using the same code) and it worked. I have therefore concluded that something must have changed in the libraries that I added. I have therefore attached the libraries that are currently on my home computer to this section; just in case somebody else comes across this issue.