Table of Contents
Toggle
In this tutorial, we will learn how to make a Solar powered WiFi weather station by using an ESP32 Wifi Module and few common weather sensors available in the market. The weather station is fully solar-powered, so no need to worry about the external power supply. You can install it in a remote place without laying long cables to provide power.
I have earlier posted two articles on Weather Stations ( Version -1.0 and Version-2.0) that were based on Wemos ( ESP8266) and are very popular on the internet. Based on the user’s feedback, I tried my best to make a more powerful weather station by including some new features.
The Solar powered WiFi weather station V3.0 is such compact weather station that consists of several meteorological sensors that measure the following parameters:
1. Internal Temperature (BME280)
2.Humidity (BME280)
3. Barometric Pressure (BME280)
4.External Temperature (DS18B20)
5. Wind Speed ( Sparkfun Weather Meter )
6. Wind Direction ( Sparkfun Weather Meter )
7. Rain Gauge ( Sparkfun Weather Meter )
8. UV Index ( SI1145)
9. Lux Level ( BH1750 )
I have designed a customized PCB for this project. It is designed in such a way that you can conveniently integrate different combinations of sensors according to your actual application needs.
Why a Weather Station?
Imagine you are residing at a place that is far away from the meteorological department. In such a case, the weather predictions you get may not be the most precise. This is where home weather stations become more advantageous. This small weather station can provide accurate data regarding the weather parameters of where you live.
Today, data on localized weather, known as microclimates, is the new frontier for more precise and accurate weather forecasting. As a result, the collection of weather data is becoming increasingly smaller and gridded.
Applications:
The applications of this type of small portable weather station are vast in the area of smart agriculture, smart city, solar power plants, construction site, etc.
Supplies:
Components Used:
1. ESP32 Dev Kit V1- 30 Pins ( Aliexpress / Banggood )
2. TP4056 ( Aliexpress / Banggood )
3. Barometric Pressure sensor BME280 ( Amazon / Banggood )
4. Temperature Sensor – DS18B20 ( Amazon / Banggood )
5. UV Index Sensor – GY1145 ( Amazon / Banggood )
6. Lux Level Sensor – BH1750 ( Amazon / Banggood )
7. Wind & Rain Sensor ( Amazon / Sparkfun )
8. MCP1700-3.3V ( Amazon)
9. Resistors – 2 x 1K, 1 x 10K, 3 x 4.7K, 1 x 27K, 1 x 100K ( Amazon / Banggood )
10. Electrolytic Capacitor – 1 x 100uF ( Amazon / Banggood )
11. Ceramic Capacitors – 4 x 0.1uF ( Amazon / Banggood )
12. TVS Diode – DT1042-04SO ( Amazon ) – Optional
13. RJ11 Connector ( Aliexpress )
14. Male / Female Headers ( Amazon / Banggood )
15. Jumper Cap ( Amazon / Banggood )
16. Screw Terminal-2P – 5.08mm pitch ( Amazon / Banggood )
17. Screw Terminal -3P -3.5mm pitch ( Sparkfun )
18. Solar Panel – 5V / 1.2Watt ( 110 x 69 mm ) – ( Amazon / Aliexpress / Banggood )
19. 18650 Battery ( Banggood )
20. 8650 Battery Holder ( Amazon / Banggood )
21. 22 AWG Wires ( Amazon / Banggood )
22. Jumper Wires M-F( Amazon / Banggood )
23. Slide Switch ( Amazon / Banggood )
24. PCB ( PCBWay )
Tools Used:
1. Soldering Iron ( Amazon / Banggood )
2. Nipper ( Amazon / Banggood)
3. Wire Stripper ( Amazon / Banggood)
4. 3D Printer ( Amazon / Banggood)
Selecting the Power Supply
If you are planning to install the weather station at a remote location like your farmhouse, you may not get access to the power grid to run the weather station. To run the station continuously, there must be a continuous power supply otherwise the system will not work. The best way to provide continuous power to the circuit is by using a battery. But in the case of the battery, after some days of run, its juice will run out, and it is a really difficult job to go there and charge it. So a solar charging circuit was proposed to use free energy from the sun to charge the battery and to power the ESP32 board.
Here, I have used a 18650 Li-Ion battery. The battery is charged from a Solar panel through a TP4056 charging module. The TP4056 module comes with a battery protection chip or without the protection chip. I will recommend buying a module that has a battery protection chip included.
The 18650 battery outputs 4.2V when fully charged. The battery voltage is further step down to 3.3V by using a low dropout voltage regulator(MCP1700-3302E). The output from the voltage regulator will power the ESP32 through the 3.3V pin.
Power Supply Circuit
The operating voltage of the ESP32 is 3.3V whereas the fully charged battery voltage is 4.2V. So we have to step down the battery voltage from 4.2V to 3.3V, which can easily be done by a linear voltage regulator but unfortunately, it is not at all recommended for this project. Because all the linear regulators require an input voltage at least some minimum amount higher than the desired output voltage. That minimum amount is called the dropout voltage. Due to this reason when battery voltage drops to around 3.7V, the linear voltage regulator will not able to maintain the voltage required voltage ( 3.3V ).
The solution to the above problem is to use a low-dropout or LDO regulator. A low-dropout or LDO regulator is a DC linear regulator which can regulate the output voltage even when the supply voltage is very close to the output voltage. Here we will use an MCP1700 LDO for efficiently powering the Circuit.
A ceramic capacitor ( 0.1uF) and an electrolytic capacitor (100uF) are connected in parallel to the GND and Vout pin of the LDO ( MCP1700 -3.3V ) to smooth the voltage peaks.
The output of the MCP1700 is connected to the ESP32 3.3V pin through a slide switch.
MCP1700 Data Sheet: Download
Wind Vane ( Wind Direction Sensor)
The wind vane indicates the direction that the wind is blowing. It is the most complex of the sensors in the Sparkfun Weather Sensor Kit. It has eight reed switches, each connected to a different resistor. As the wind vane rotates, a magnet closes the reed switches and may close two at a time due to their proximity to each other, allowing up to 16 different positions to be indicated. However, in testing the unit, I never could make the device close two switches at once, so although it might be possible theoretically to measure 16 directions, I only get eight. The software takes 16 directions into account, just in case.
An external resistor can be used to form a voltage divider, producing a voltage output that can be measured with an analog to digital converter, on your the microcontroller allows you to determine the direction of the wind vane pointer.
To measure voltage output, I have used a 10kohm external resistor to form a voltage divider with the wind vane resistor ( Rvane). The 10K resistor is connected to 3.3V as shown in the above figure. Then, I connect the middle of the divider to the ESP32 ADC pin (GPIO 35), measure the voltage, and by referring to the table shown above, convert to the wind direction.
The reed switches and resistors arrangement are shown in the above picture. Resistance values for all 16 possible positions are given in the table.
When the wind vane pointer falls in between two switches, the resistance value is considered as the equivalent resistance between the two adjacent resistances. In this situation, the vane’s magnet activates two switches simultaneously, as result they are connected in parallel.
Example:
When the wind vane pointer falls in between the Switches S1 and S2, the equivalent resistance is determined by the following formula:
Rvane = R1x R2 / ( R1+R2 ) = 33 x 8.2 / ( 33 +8.2 ) = 6.57K
Since the values outputted by the wind vane are based on degrees, you can, in theory, have any value represent any direction. However, it is recommend having the value at degree 0 represent North for ease of use.
Anemometer ( Wind Speed Sensor)
The wind speed sensor is a cup-type anemometer measures wind speed by closing a contact as a magnet moves past a reed switch. As per the datasheet, a wind speed of 2.4km/h (1.4912 mph) causes the switch to close once per second. The anemometer switch is connected to the inner two conductors of the RJ 11 cable shared by the anemometer and wind vane (pins 2 and 3). The Anemometer is connected to the ESP32 GPIO pin 14 and GND. After that, all we need to do then is to monitor for button presses which are pretty straightforward. We can use the pin interrupts method to monitor the button press ( tips). When the reed switch closes the circuit (pressing the button), it triggers a software event.
If you want to make your own wind sensor, then read this nice article
These are few more 3D printed Wind Sensors:
1. Anemometer
2. Wind Speed Gauge
Rain Gauge ( Rain Fall Sensor )
Here I have used a most common type of Rain Sensor which is called a Tipping Bucket rain gauge. Basically, there’s a little see-saw shape tipper bucket inside the sensor ( see the above picture ). The rain fills up a bucket on one end and it tips over so that it empties and the bucket on the other side starts to fill. Each time the bucket tips it passes a magnet over a reed switch making a momentary electrical connection. The buckets are calibrated to a volume of water, which means if we can count how many times the switch closes we can calculate how much rainfall there’s been.
Much like the wind speed gauge, the rainfall gauge generates ticks to tally the amount of rain that has fallen. Count ticks to determine how much rain has fallen recently. Each tick represents 0.011″ ( 0.28mm ) of rainfall. This sensor is connected to pin 25 of the ESP32.
The rain gauge that I have used here is from Sparkfun. It has an RJ-11 plug on the end, you can directly plug it into the Weather Station V3.0 PCB.
You can make your 3D printed Rain Gauge by following this article
Measuring the Rainfall
In the previous step, we have discussed that each time the bucket tips, it passes a magnet over a reed switch making a momentary electrical connection. Here each tip of the bucket in the rain gauge can be assumed as a button press. We can easily then connect the gauge as if it were a button.
The rain gauge is connected to the ESP GPIO pin 25 and GND. After that, all we need to do then is to monitor for button presses which are pretty straightforward. We can use the pin interrupts method to monitor the button press ( tips). When the reed switch closes the circuit (pressing the button, the bucket tipping), it triggers a software event.
Here I am using attachInterrupt()to monitor the number of tips. You can find the details from Arduino Page.
Monitoring Pressure, Temperature and Humidity by BME280
In the earlier days, weather parameters like ambient temperature, humidity, and barometric pressure were measured with separate analog instruments: thermometer, hygrometer, and barometer. But today the market is flooded with cheap and efficient digital sensors that can be used to measure a variety of environmental parameters. The best examples are sensors like DHT11, DHT 22, BMP180, BMP/E280, etc.
In this project, we will use BMP280 / BME280 sensor.
BMP280: BMP280 is a sophisticated sensor that very accurately measures barometric pressure and temperature with reasonable accuracy. The BME280 is the next-generation of sensors from Bosch and is the upgrade to the BMP085/BMP180/BMP183 – with a low altitude noise of 0.25m and the same fast conversion time. The advantage of this sensor is that it can use either I2C or SPI for communication with the microcontroller. For simple easy wiring, I will suggest buying the I2C version board.
BME280: The new BME280 sensor, an environmental sensor with temperature, barometric pressure, and humidity. The BME280 is the next generation of sensors from Bosch and is the upgrade to the BMP280. This precision sensor from Bosch is the best low-cost sensing solution for measuring humidity with ±3% accuracy, barometric pressure with ±1 hPa absolute accuracy, and temperature with ±1.0°C accuracy. It can be used in both I2C and SPI.
Note: BME280 can measure humidity but BMP280 can’t. In the market, BMP280 is also available by the name of BME280. So be sure whether it is a BMP280 or BME280.
You can read this nice article on BME280 for a better understanding.
Monitoring UV Index – SI1145 Sensor
The Si1145 is a sensor with a calibrated UV sensing element that can calculate the UV Index. It can communicate via I2C communication (address 0x60). You can hook up this sensor with I2C port in the PCB which is located at the bottom left of the ESP board.
The SI1145 sensor really doesn’t have an actual UV sensor! Instead, it looks at the amount of visible and IR light it receives from the Sun and uses a formula to calculate the UV index, right down to two decimal points.
You can read this article to know more about the UV sensor.
If you need a more accurate measurement of UV Index, you may use the VEML6070 sensor. Unlike the Si1145, this sensor will not give you UV Index readings. However, the Si1145 does UV Index approximations based on light level, not true UV sensing. The VEML6070 in contrast does have a real light sensor in the UV spectrum.
You can read this tutorial for writing the code and using its library.
Monitoring Lux Level – BH1750 Sensor
The BH1750 Ambient Light Sensor Module is based on the digital Ambient Light Sensor IC BH1750FVI developed by ROHM Semiconductor. It is a digital IC with built-in 16-bit illuminance to a digital converter.
The output of this sensor is in LUX (lx), so it does not require any further calculations. Lux is the unit to measure Light intensity. It measures the intensity according to the amount of light hitting on a particular area. One lux is equal to one lumen per square meter.
For communication with external devices like ESP32, the BH1750 Ambient Light Sensor IC uses I2C Bus Interface.
Pin Description
VCC – 3.3V to 3.3V
GND – VCC
SCL – SCL
SDA – SCL
ADD – I2C Device Address ( Kept Open )
You can read this article for information on BH1750 light sensor
External Temperature Sensor
If you need, you can connect an external temperature sensor like DS18B20 to monitor the ambient temperature. DS18B20 is One Wire interface Temperature sensor manufactured by Dallas Semiconductor Corp. It requires only one digital pin for two-way communication with a microcontroller. I have hooked up this sensor with ESP32 GPIO pin4.
The DS18B20 comes usually in two form factors. One that comes in the TO-92 package looks exactly like an ordinary transistor and another one in a waterproof probe with an extension cable. I have used DS18B20 probe for measuring the temperature. It uses a one-wire protocol to communicate with the ESP32. It can be hooked up to the 3 pin screw terminal on the PCB.
To interface with the DS18B20 temperature sensor, you need to install the One Wire library and the Dallas Temperature library. You can read this article for more details on the DS18B20 sensor.
Monitoring Battery Voltage
The weather station is run by a 18650 Li-Ion battery, so it is essential to monitor the battery status. The max voltage input to the ESP32 board is around 3.2~3.3V but a fully charged 18650 battery voltage is 4.2V. So to measure this voltage we have to step down the voltage by using a voltage divider network.
The voltage divider is made up of 27k (R1) and 100k (R2).
When you have your ESP32 powered with batteries or solar-powered as in this case, it can be very useful to monitor the battery level. One way to do that is to read the output voltage of the battery using an analog pin of the ESP32.
However, the battery we’re using here outputs a maximum of 4.2V when fully charged, but the ESP32 GPIOs work at 3.3V. So, we need to add a voltage divider so that we’re able to read the voltage from the battery.
The voltage divider formula is as follows:
Vout = (Vbat*R2)/(R1+R2)
So, if we use R1=27k Ohm, and R2=100k Ohm,
We get: 1 Vout = (4.2*100k)/(27k + 100k) = 3.307V
So, when the battery is fully charged, the Vout outputs 3.307V that we can read with an ESP32 GPIO pin. To select the voltage divider resistance values, you can use this online calculator.
ESP32 – Thingspeak-Deep-Sleep
The heart of our Weather Station is an ESP8266 SOC which is a power-hungry chip. When your project is powered by a plug-in the wall, you tend not to care too much about power consumption. But if you are going to power your project with batteries, every mA counts.
Our objective is to run the device by using a 18650 Li-Ion battery. To run the ESP32 by using a battery, we have to lower the power consumption. To do that, we’ll use the Deep Sleep Mode which is the most power-efficient option for the ESP chip. It allows to put the ESP32 into hibernation and saves the battery. You can wake up the ESP at regular intervals to make measurements and publish them.
Calculating Battery Life:
The ESP32 consumes around 75mA in normal operation and hits about 150mA while transmitting data over WiFi. and in Deep Sleep about 10uA. The ESP32 takes ~ 30secs to upload data.
Battery Life calculations:
Battery Used: 3400mAh / 3.7V 18650 Li-Ion
Publish Interval = 10mins ( ON Time: 30 sec and Sleep Time: 9 mins 30 sec )
Total number of Readings / Hour = 60/10 = 6
Power consumption per hour (ON time) = 6 x 150 mA * 30 / 3600 = 7.5mA
Sleep time = 6 x 10uA * 570 / 3600 = 0.0095 mA
Total time in hours on battery = 3400 / (7.5+0.0095) = 452.76Hrs
Total days on battery = 452.76/24 = 18.86 Days
I have prepared an excel sheet for calculating the battery life. It is attached below, you can use it.
Solar Panel Selection
The amount of solar insolation varies according to which part of the globe you are located at. To find out the amount of solar insolation in your area, you can use the Global Solar Atlas. By taking consideration into a minimum of 1 hour of full sunlight, we are going to select the solar panel.
From the previous step, it is concluded that the average current consumption is 7.5 mA
Charge required for running the device for the whole day = 7.5 mA x 24 Hours = 180 mAh
So, our target is to generate 180 mAh in 1 hour.
To charge a 3.7V Li-Ion battery, a solar panel of voltage 5 to 6V is adequate.
Required Solar Panel rating = 180 mA at a voltage of around 5 to 6 volts.
Solar panel rating = 180 mA x 5V = 0.9 Watt, by considering some losses, I have selected a higher rating solar panel.
Solar Panel Selected: I have used a 5V,250mA Solar Panel ( 110 x 69 mm)
PCB Design
I have drawn the schematic by using EasyEDA online software after that switched to PCB layout.
All of the components you added in the schematic should be there, stacked on top of each other, ready to be placed and routed. Drag the components by grabbing on its pads. Then place it inside the rectangular borderline.
Arrange all the components in such a way that the board occupies minimum space. The smaller the board size, the cheaper will be the PCB manufacturing cost. It will be useful if this board has some mounting holes on it so that it can be mounted in an enclosure.
Now you have to route. Routing is the most fun part of this entire process. It’s like solving a puzzle! Using the tracking tool we need to connect all the components. You can use both the top and the bottom layer for avoiding overlap between two different tracks and making the tracks shorter.
You can use the Silk layer to add text to the board. Also, we are able to insert an image file, so I add an image of my website logo to be printed on the board. In the end, using the copper area tool, we need to create the ground area of the PCB. Now the PCB is ready for manufacturing.
You can order it from PCBWay
Note: When you place an order, I will get 10% donation from PCBWay for contribution to my work. Your little help may encourage me to do more awesome work in the future. Thank you for your cooperation.
PCB Fabrication
Once we are completed the PCB design we just need to click the “Gerber Output” button, save the project and we will be able to download the Gerber files which are used to manufacturing the PCB.
Assembling the PCB
After receiving the board from the PCB fab house, you have to solder the components. For Soldering, you will need a decent Soldering Iron, Solder, Nipper.
First I cut the straight male and female headers pin for ESP32 Board, TP4056, BME280, and jumper JP1. Following are the details about the headers :
1. ESP Board – 2 x 15pins ( Female )
2. BME280 – 1 x 4pins ( Female )
3. UV Sensor – 1 x 4pins ( Female )
4. Lux Level Sensor – 1 x 4pins ( Female )
5. Spare I2C Port – 1 x 4pins ( Female )
4. Jumper JP1- 1 x 2pins ( Male )
It is good practice to solder the components according to their height. Solder the lesser height components first. I have started by soldering the resistors, switch and then moved towards the bigger components like headers pin, screw terminal, and battery holder.
Download the Schematic attached below.
Schematic_Weather+Station_V3.0
Soldering the TVS Diode
In the entire PCB, the lesser height component is the TVS diode which is the only SMD component used in this project. You can see the datasheet.
First, apply soldering flux on all 6 pads and then apply a small amount of solder to the corner pads. Place and align the diode chip using tweezers. Hold the chip in place while touching the pads with the tip of the soldering iron so that the solder melts the pin and the pad together.
Be sure the dot symbol on the PCB and the TVS diode is matching together. The dot symbol represents pin number -1.
Now apply solder to all the pads, and you are done. If you mess up during the soldering, you can remove the extra solder by using a desoldering wick.
You can read this tutorial if you are new to soldering SMD components by using a soldering iron. By the way, I am also learning.
Note: Without the use of this TVS diode not affect the functionality of the weather station, it provides additional protection to the circuit.
Soldering the Resistors and Ceramic Capacitor
By considering the component height, after the TVS diode, the next component is the resistor and then ceramic capacitors. Bend the resistor legs and insert them into the PCB holes. Solder the legs and trim the extra legs by using a nipper.
During soldering always refer to the schematic diagram to avoid any mistakes. The schematic diagram is attached below. You should take a printout and keep it side when soldering.
Similarly, solder the ceramic capacitors. Note that ceramic capacitors do not have any polarity, so you can solder in any way, it will work.
Soldering the LDO MCP1700
The LDO MCP1700 used in this project comes in the TO92 package in which the pin-to-pin distance is only 1.26mm. So if you are a beginner, you may short the pads during the soldering, to avoid this I have not used the TO92 package footprint on the PCB. I intentionally provided some gaps in between the soldering pads.
Stretch the 3 legs of MCP1700 as shown in the above picture, then insert it into the PCB holes where it is labeled as MCP1700.
The pinout diagram is shown above, each pin name is also labeled on PCB so that you will not confuse during the soldering.
Trim the Headers
The best way to trim the female header pieces is to count out 15 pins, pull the 16th pin, then use a nipper to cut the gap between the 15th and 17th pin.
You must be careful when cutting the header to center your snip. An off-center cut may result in the mechanical portion of the header escaping or losing some of its retention force.
Optionally, you may take a file, piece of sandpaper to sand down the end of the header so that it will look very smooth.
I followed the above principle to prepare all the female headers.
Soldering the Headers
Plug all four headers into the PCB. The PCB is labeled to identify which header goes to which place. The male pins of the header should enter the top side of the PCB and extend out the bottom. I always solder two end pins first, then solder the remaining pins.
It’s important that each of the headers is at a nice, 90° angle to the PCB. This will ensure that the ESP32 board/ sensor modules will slide straight onto the headers, and you won’t have to bend any pins in doing so.
To mount the TP4056, here I have used 6 x 1 female pin, you may use male pins too.
Trim the extra legs by using a nipper.
Soldering the Bigger Components
The bigger components on the PCB are the terminal connectors ( two screw terminals and two RJ11 connectors) and the 18650 battery holder. First solder the two screw terminals then solder the RJ11 connector. The RJ11 connector has some locking arrangement, you have to insert it into the two side holes on the PCB.
Adding the Modules and Battery
After assembling the header pins, switch, Connectors, and screw terminal, it is time to insert the boards into their respective headers. The headers are clearly labeled on the PCB, so there is no chance of confusion.
First I place the TP4056 board and solder all the pads.
Then I added the ESP32 Board and BME280 Sensor.
Finally, I inserted the 18650 battery into the battery holder.
3D Printed Enclosure
The ideal enclosure for keeping the weather sensors is the Stevenson Screen. A Stevenson screen is an enclosure to shield meteorological sensors against precipitation and direct heat radiation from outside sources, while still allowing air to circulate freely around them.
My friend Glen from New Zealand helped me to make this professional-grade Stevenson Screen. I really appreciate his help in making this project successful.
This has a simple wall mount and a 2 part cover to isolate the heat transfer from the solar panel. The V3.0 design has a provision for mounting a UV Index sensor on the top. Apart from this, the top cover for mounting solar panel is kept away from the main enclosure to avoid heat transfer from the solar panel to the interior part of the enclosure.
The Stevenson Screen has 6 parts:
1. PCB Mount Frame
2. Bottom Plate
3. Bottom Mount
4. Middle Rings x 12 Nos
5. Screen Top Cover
6.Top Cover for Solar Panel Mount ( Solar Panel Size: 110 x 69 mm )
7. M6 Rod x 4 Nos
I used my Creality 3D printer and 1.75 mm white PLA filament to print the parts. I will recommend using ABS or PTEG filament instead of using PLA.
You can refer to the above explosion diagram to assemble the 3D printed parts.
You can download the .STL files from Thingiverse
You can download the STEP files from GRABCAD for any modification.
Assemble the 3D Printed Parts
The assembly process is clearly indicated in the explosion diagram shown above. It is broadly as below:
1. Stacking 12 numbers of middle rings one above the others
2. Mounting the PCB
3. Mounting Solar Panel and UV Sensor on Top Cover
4. Joining the Bottom plate, Middle ring, and Top Cover
Assemble the Middle Rings
The assembling process is very simple, just stack one above the others. After stacking all the middle rings, insert the 4 x M6 rods at the corners. The M6 rods can be a metal one or 3D printed one, here I have used the 3D printed rods.
If you are using 3D printed rods, then I will suggest inserting the M3 rods at the early stage, i.e. after stacking 2 or 3 rings is perfect. Then insert the remaining middle rings one by one. I have broken 2 rods during the assembling because I did one mistake that stacked all the rings first and then tried to push the rods at the corner holes.
Mount the PCB
The PCB Mount Frame is designed to mount the V3.0 PCB ( 100 x 86 mm). The PCB mount has text on it to show orientation and the battery goes to the top of the assembly.
Align the PCB in such a way that the battery holder on the PCB and the mounting plate match each other. Once it is matched the other sides will automatically be matched. Now you have to align the PCB holes with the PCB mounting holes ( looks like 4 standoffs ). Then secure the PCB with 4xM3 Nuts.
After installing the PCB, slide the PCB mount into the middle ring assembly as shown in the above picture.
Connect the Wind and Rain Sensors
First, insert the two cables from the wind and rain sensor through the round hole in the Bottom Mount. Connect the two cables to RJ11 connectors ( wind and rain sensor) on the PCB. The connector is labeled as ” Wind Sensor ” and ” Rain Sensor “.
Install the bottom plate and secure it with 4 M3 nuts as shown in the above picture.
Now you can install the bottom mount into the bottom plate and then secure it with a locking nut ( M4).
Note: For a neat and cleaner look, keep the sensor cables toward the bottom mount ( backside ).
Mount the Solar Panel
The Solar panel slot in the top cover is designed to hold a 110 x 69 mm solar panel. Here, I have used a 1.25W solar panel.
Apply a small amount of flux to the soldering pads on the solar panel. Then, solder a 22 AWG red wire to the positive terminal and a black wire to the negative terminal of the Solar Panel.
Insert the two wires into the holes in the top cover as shown above. Use silicon glue to fix the Solar Panel and press it some time for proper bonding. Seal the holes from the inside by using a waterproof sealant or silicone glue. I will recommend not to use hot glue, I have used it in my earlier version, it got melt when exposed to bright sunlight during the hot summer.
Here I have used T-8000 glue for mounting the solar panel as well as sealing the cable holes. It is a transparent glue, so it’s hardly visible where the glue is used. The main problem with this glue is that it takes a lot of time to dry out.
Mount the UV Sensor
The UV sensor module is comprised of UV sensors along with other electronic components to work it properly. Only the sensor part is responsible for sensing the UV light, so it should be exposed to the light.
The top cover is designed to hold the UV Sensor module ( GY1145 ) on a peg and a small clearance is given in the slot for the soldering pins on the module.
First, cover the UV sensor ( marked in the yellow border – see the image ) by using masking tape, then mount it on the top cover. You may need small alignment to expose the sensor through the square hole on the enclosure.
Now apply some silicone sealant to stop any water from entering through the opening. After drying the sealant, remove the masking tape by using tweezers. After removal of the tape, you will reveal a clean sensor surface
Note: No window is provided over the UV sensor because it will give a wrong reading.
Connect the Solar Panel and UV Sensor
Solder 4 jumper wires to the module pins ( VIN, GND, SDA, and SCL).
There are 3 holes in the top cover, 2 central ones for where the solar panel wires are soldered onto the panel and there is a single hole at the front, this is for the wire from the UV sensor board.
Assemble these wires in place using silicone to seal up the holes.
Now connect the solar panel red wire to the positive and black wire to the negative terminal of the Solar In screw terminal on the PCB.
Then connect the wires coming from the UV sensor to the UV sensor header ( P2 ) on the PCB.
Software and Libraries
To use the ESP32 board with the Arduino library, you’ll have to use the Arduino IDE with ESP32 board support. If you haven’t already done that yet, you can easily install ESP32 Board support to your Arduino IDE by following this tutorial by Sparkfun.
Install Libraries:
Before uploading the code install the following libraries :
1. ESP32
2. Blynk
3. BME280
4. Adafruit_SI1145_Library
5. BH1750
6. One Wire
7. Dallas Temperature
How to Install the Libraries?
You can read this tutorial by Sparkfun to install the Arduino libraries.
In my earlier version, there are two separate codes for Blynk and Thinspeak but in this version, we have written a single piece of code. The user has to only comment out a single line of code for Blynk or Thingspeak.
Download the Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
//======================================================================================// // // // Solar WiFi Weather Station V3.0 Firmware // // // // Developed by Debasish Dutta, Last Update: 30.03.2021 // // // //======================================================================================// #include <BME280I2C.h> #include "Adafruit_SI1145.h" #include <BH1750.h> #include <DallasTemperature.h> #include <OneWire.h> #include "Wire.h" #include <WiFi.h> #include <BlynkSimpleEsp32.h> #include "esp_deep_sleep.h" //Library needed for ESP32 Sleep Functions //=================== Pin assignment definitions ========================================== #define WIND_SPD_PIN 14 #define RAIN_PIN 25 #define WIND_DIR_PIN 35 #define VOLT_PIN 33 #define TEMP_PIN 4 // DS18B20 hooked up to GPIO pin 4 //======================================================================================= WiFiClient client; BME280I2C bme; Adafruit_SI1145 uv = Adafruit_SI1145(); BH1750 lightMeter(0x23); OneWire oneWire(TEMP_PIN); DallasTemperature sensors(&oneWire); //=========================Declaring Variables and Constants ================================== // Variables used in reading temp,pressure and humidity (BME280) float temperature, humidity, pressure; // Variables used in reading UV Index (Si1145) float UVindex; // Variables used in reading Lux Level( BH1750 ) float lux; // Variables used in calculating the windspeed volatile unsigned long timeSinceLastTick = 0; volatile unsigned long lastTick = 0; float windSpeed; // Variables used in calculating the wind direction int vin; String windDir = ""; // Variables and constants used in tracking rainfall #define S_IN_DAY 86400 #define S_IN_HR 3600 #define NO_RAIN_SAMPLES 2000 volatile long rainTickList[NO_RAIN_SAMPLES]; volatile int rainTickIndex = 0; volatile int rainTicks = 0; int rainLastDay = 0; int rainLastHour = 0; int rainLastHourStart = 0; int rainLastDayStart = 0; long secsClock = 0; // Variables used in calculating the battery voltage float batteryVolt; float Vout = 0.00; float Vin = 0.00; float R1 = 27000.00; // resistance of R1 (27K) // You can also use 33K float R2 = 100000.00; // resistance of R2 (100K) int val = 0; //=========================Deep Sleep Time ================================================ //const int UpdateInterval = 1 * 60 * 1000000; // e.g. 0.33 * 60 * 1000000; // Sleep time //const int UpdateInterval = 15 * 60 * 1000000; // e.g. 15 * 60 * 1000000; // // Example for a 15-Min update interval 15-mins x 60-secs * 10000 //========================= Enable Blynk or Thingspeak =================================== // configuration control constant for use of either Blynk or Thingspeak //const String App = "BLYNK"; // alternative is line below const String App = "Thingspeak"; // alternative is line above //========================= Variables for wifi server setup ============================= // Your WiFi credentials. // Set password to "" for open networks. char ssid[] = "XXXX"; // WiFi Router ssid char pass[] = "XXXX"; // WiFi Router password // copy it from the mail received from Blynk char auth[] = "XXXX"; // Thingspeak Write API const char* server = "api.thingspeak.com"; const char* api_key = "XXXX"; // API write key //========================= Setup Function ================================================ void setup() { Serial.begin(115200); delay(25); Serial.println("nWeather station powered on.n"); Wire.begin(); sensors.begin(); // Wire.begin(22, 21); // for BH1750 bme.begin(); // 0x76 is the address of the BME280 module uv.begin(0x60); // 0x60 is the address of the GY1145 module wifi_connect(); // Wind speed sensor setup. The windspeed is calculated according to the number // of ticks per second. Timestamps are captured in the interrupt, and then converted // into mph. pinMode(WIND_SPD_PIN, INPUT); // Wind speed sensor attachInterrupt(digitalPinToInterrupt(WIND_SPD_PIN), windTick, FALLING); // Rain sesnor setup. Rainfall is tracked by ticks per second, and timestamps of // ticks are tracked so rainfall can be "aged" (i.e., rain per hour, per day, etc) pinMode(RAIN_PIN, INPUT); // Rain sensor attachInterrupt(digitalPinToInterrupt(RAIN_PIN), rainTick, FALLING); // Zero out the timestamp array. for (int i = 0; i < NO_RAIN_SAMPLES; i++) rainTickList[i] = 0; // ESP32 Deep SLeep Mode // esp_deep_sleep_enable_timer_wakeup(UpdateInterval); // Serial.println("Going to sleep now..."); // esp_deep_sleep_start(); } //================================ Loop Function ============================================== void loop() { Read_Sensors_Data(); // Read all the Sensors // printdata(); // Print all the sensors data on the serial monitor Send_Data(); // Upload all the sensors data on the Internet ( Blynk App or Thingspeak ) } //============================ Connect to WiFi Network ========================================= void wifi_connect() { if (App == "BLYNK") // for posting datas to Blynk App { Blynk.begin(auth, ssid, pass); } else if (App == "Thingspeak") // for posting datas to Thingspeak website { WiFi.begin(ssid, pass); while (WiFi.status() != WL_CONNECTED) { delay(500); // Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); } else { WiFi.begin(ssid, pass); Serial.print(App); Serial.println(" is not a valid application"); } } //=================================================================================================== // Read Sensors Data ( BME280, Si1145,BH1750, Bat. Voltage, Wind Sensors, Rain Gauge ) //================================================================================================== void Read_Sensors_Data() { // Reading BME280 sensor bme.read(pressure, temperature, humidity, BME280::TempUnit_Celsius, BME280::PresUnit_Pa); //*************************************************************************** // Reading DS18B20 sensor sensors.requestTemperatures(); //*************************************************************************** // Reading GY1145 UV sensor UVindex = uv.readUV(); // the index is multiplied by 100 so to get the // integer index, divide by 100! UVindex /= 100.0; //********************************************************************************** /*// Reading BH1750 sensor lux = lightMeter.readLightLevel(); */ //********************************************************************************** // Reading Battery Level in % val = analogRead(VOLT_PIN);//reads the analog input Vout = (val * 3.3 ) / 4095.0; // formula for calculating voltage out batteryVolt = Vout * ( R2+R1) / R2 ; // formula for calculating voltage in //********************************************************************************** // Read Weather Meters Datas ( Wind Speed, Rain Fall and Wind Direction ) static unsigned long outLoopTimer = 0; static unsigned long wundergroundUpdateTimer = 0; static unsigned long clockTimer = 0; static unsigned long tempMSClock = 0; // Create a seconds clock based on the millis() count. We use this // to track rainfall by the second. We've done this because the millis() // count overflows eventually, in a way that makes tracking time stamps // very difficult. tempMSClock += millis() - clockTimer; clockTimer = millis(); while (tempMSClock >= 1000) { secsClock++; tempMSClock -= 1000; } // This is a once-per-second timer that calculates and prints off various // values from the sensors attached to the system. if (millis() - outLoopTimer >= 2000) { outLoopTimer = millis(); // Windspeed calculation, in mph. timeSinceLastTick gets updated by an // interrupt when ticks come in from the wind speed sensor. if (timeSinceLastTick != 0) windSpeed = 1000.0/timeSinceLastTick; // Calculate the wind direction and display it as a string. windDirCalc(); rainLastHour = 0; rainLastDay = 0; // If there are any captured rain sensor ticks... if (rainTicks > 0) { // Start at the end of the list. rainTickIndex will always be one greater // than the number of captured samples. int i = rainTickIndex-1; // Iterate over the list and count up the number of samples that have been // captured with time stamps in the last hour. while ((rainTickList[i] >= secsClock - S_IN_HR) && rainTickList[i] != 0) { i--; if (i < 0) i = NO_RAIN_SAMPLES-1; rainLastHour++; } // Repeat the process, this time over days. i = rainTickIndex-1; while ((rainTickList[i] >= secsClock - S_IN_DAY) && rainTickList[i] != 0) { i--; if (i < 0) i = NO_RAIN_SAMPLES-1; rainLastDay++; } rainLastDayStart = i; } } } // Keep track of when the last tick came in on the wind sensor. void windTick(void) { timeSinceLastTick = millis() - lastTick; lastTick = millis(); } // Capture timestamp of when the rain sensor got tripped. void rainTick(void) { rainTickList[rainTickIndex++] = secsClock; if (rainTickIndex == NO_RAIN_SAMPLES) rainTickIndex = 0; rainTicks++; } // reading wind direction void windDirCalc() { vin = analogRead(WIND_DIR_PIN); if (vin < 150) windDir="202.5"; else if (vin < 300) windDir = "180"; else if (vin < 400) windDir = "247.5"; else if (vin < 600) windDir = "225"; else if (vin < 900) windDir = "292.5"; else if (vin < 1100) windDir = "270"; else if (vin < 1500) windDir = "112.5"; else if (vin < 1700) windDir = "135"; else if (vin < 2250) windDir = "337.5"; else if (vin < 2350) windDir = "315"; else if (vin < 2700) windDir = "67.5"; else if (vin < 3000) windDir = "90"; else if (vin < 3200) windDir = "22.5"; else if (vin < 3400) windDir = "45"; else if (vin < 4000) windDir = "0"; else windDir = "0"; } //====================== Print Data on Serial Monitor =============================================== void printdata(){ Serial.print("Air temperature [°C]: "); Serial.println(temperature); Serial.print("Humidity [%]: "); Serial.println(int(humidity)); Serial.print("Barometric pressure [hPa]: "); Serial.println(pressure / 100); Serial.print("UV: "); Serial.println(UVindex); // Serial.print("Light: "); Serial.print(lux); Serial.println(" lx"); Serial.print("Windspeed: "); Serial.print(windSpeed*2.4); Serial.println(" mph"); Serial.print("Wind dir: "); Serial.print(" "); Serial.println(windDir); Serial.print("Rainfall last hour: "); Serial.println(float(rainLastHour)*0.011, 3); // Serial.print("Rainfall last day: "); Serial.println(float(rainLastDay)*0.011, 3); // Serial.print("Rainfall to date: "); Serial.println(float(rainTicks)*0.011, 3); Serial.print("Battery Level: "); Serial.println(batteryVolt); Serial.print("Temperature in C: "); Serial.println(sensors.getTempCByIndex(0)); //print the temperature in Celsius Serial.print("Temperature in F: "); Serial.println((sensors.getTempCByIndex(0) * 9.0) / 5.0 + 32.0); //print the temperature in Fahrenheit } //======================Upload Sensors data to Blynk App or Thingspeak ================================= void Send_Data() { // code block for uploading data to BLYNK App if (App == "BLYNK") { // choose application Blynk.virtualWrite(0,temperature ); // virtual pin 0 Blynk.virtualWrite(1, humidity ); // virtual pin 1 Blynk.virtualWrite(2, pressure/100 ); // virtual pin 2 Blynk.virtualWrite(3, UVindex); // virtual pin 3 // Blynk.virtualWrite(4, windSpeed*1.492 ); // virtual pin 4 Blynk.virtualWrite(4, windSpeed*2.4*4.5 ); // virtual pin 4 Blynk.virtualWrite(5, windDir); // virtual pin 5 Blynk.virtualWrite(6, rainLastHour); // virtual pin 6 Blynk.virtualWrite(7, batteryVolt); // virtual pin 7 Blynk.virtualWrite(8, sensors.getTempCByIndex(0)); // virtual pin 8 delay(12*5000); } // code block for uploading data to Thingspeak website else if (App == "Thingspeak") { // Send data to ThingSpeak WiFiClient client; if (client.connect(server,80)) { Serial.println("Connect to ThingSpeak - OK"); Serial.println(""); Serial.println("********************************************"); String postStr = ""; postStr+="GET /update?api_key="; postStr+=api_key; postStr+="&field1="; postStr+=String(temperature); postStr+="&field2="; postStr+=String(humidity); postStr+="&field3="; postStr+=String(pressure/100); postStr+="&field4="; postStr+=String(UVindex); postStr+="&field5="; //postStr+=String(windSpeed*1.492); //speed in mph postStr+=String(windSpeed*2.4*4.5); //speed in Km/h postStr+="&field6="; postStr+=String(windDir); postStr+="&field7="; postStr+=String(float(rainTicks)*0.011, 3); postStr+="&field8="; postStr+=String(batteryVolt); postStr+="&field9="; postStr+=String(sensors.getTempCByIndex(0)); postStr+=" HTTP/1.1rnHost: a.c.drnConnection: closernrn"; postStr+=""; client.print(postStr); delay(5000); //******************************************************************************* } while(client.available()){ String line = client.readStringUntil('r'); // Serial.print(line); } } } //=============================End of the Program ================================= |
Uploading Sensor Data to ThingSpeak
First, create an account on ThingSpeak.
Then create a new Channel on your ThingSpeak account.
Find How to Create a New Channel Fill Field 1 as Temperature, Field 2 as Humidity, Field 3 Pressure, Field 4 as UV Index, Field 5 as Wind Speed, Field 6 as Wind Direction, Field 7 as Rain Fall, and Field 8 as Battery Voltage
In your ThingSpeak account select “Channel” and then “My Channel”.
Click on your channel name.
Click on “API Keys” tab and copy the “Write API Key”
Open the Solar_Weather_Station_ThingSpeak code.
Replace the “WRITE API ”with the copied “Write API Key”.
Interfacing With Blynk App
Blynk is the most popular Internet of Things platform for connecting any hardware to the cloud, designing apps to control them, and managing your deployed products at scale. With Blynk Library you can connect over 400 hardware models including ESP8266, ESP32, NodeMCU & Arduino to the Blynk Cloud.
Step-1: Download the Blynk app
1. For Android
2. For iPhone
Step-2: Get the Auth Token
In order to connect the Blynk App and your hardware, you need an Auth Token.
1. Create a new account in the Blynk App.
2. Press the QR icon on the top menu bar. Create a clone of this Project by scanning the QR code shown above. Once it detected successfully, the whole project will be on your phone immediately.
I’ve made the Sol Weather Station app. You are welcome to try it out!
To start using it:
1. Download Blynk App: http://j.mp/blynk_Android or http://j.mp/blynk_Android
2. Touch the QR-code icon and point the camera to the code below 3. Enjoy my app!
3. After the project was created, we will send you Auth Token over email.
4. Check your email inbox and find the Auth Token.
Step-3: Preparing Arduino IDE for Wemos Board
To upload the Arduino code to Wemos board, you have to follow this Instructables
Step-4: Arduino Sketch
After installing the above libraries, paste the Arduino code given below. Enter the auth code from step-1, SSID, and password of your router. Then upload the code.
Weather Station Installation
Once you have confirmed that your weather station PCB along with all the sensors, working perfectly, you need to design and make a mount for it. I have used a wooden pole ( 4cm x 8cm x 300 cm ) to mount the sensors and the 3D-printed Stevenson Screen.
If you purchase the entire Weather Meters Kit, then you don’t have to worry about mounting the wind and rain sensor. But if you purchase the independent sensor, you may need some mounting arrangement. I found a nice wind sensor holder from Thingiverse.
First I mount the wind sensors ( Wind Vane and Anemometer ) by using the 3D printed wall mounts. I have installed the wind vane and anemometers by using cable ties. After that, mounted them on the wooden pole by using two screws. You can see the above picture for better understanding.
Similarly, I have mounted the rain sensor on the wooden pole. But the holder used for it is a ready-made one. In the future, I will make a 3D printed holder for it so you don’t have to buy it.
At last, mount the external temperature sensor ( DS18B20 ) on the pole by using cable ties. After installing all the sensors, you have to route all the cables from the sensors to the Stevenson Screen.
Note: Always use good quality cable ties that are specially made for outdoor use ( UV-resistant ).
Now it is time to install the Stevenson Screen which we have made earlier. Install the Bottom Mount on the wooden pole by using 4 screws.
Suitable Location for Installation:
The location of your weather station is the most important part of the installation. If your weather station is located under a tree or an overhang, the rainfall data measured by the station will not be correct. If you place your weather station in an alley, you could very well get a wind tunnel effect on the anemometer, resulting in erroneous wind data. If you want to measure sunlight you cannot have the sensor in a shadow. So make sure that there is sufficient clearance around and above the weather station.
You can read this nice article on Weather Station Installation.
Conclusion and Future Goal
It took me a lot of time to make the circuit, making the PCB prototype, rectifying the errors in the PCB prototype, testing the PCB, making the enclosure, and then assembling and installing them. So I had not enough time left to concentrate on the software part. I am entering this project in Microcontroller Contest, the deadline is 29.03.2021. So I have no options to wait and complete the full software. The software attached here is a basic building block of the project, I will update it regularly with new features.
My future goals are :
1. Software for Implementing ESPHome and Home Assistant
2. Software for implementing MQTT
3. Optimizing the Power Consumption
4. Implementing LORA communication ( Probably in V4.0 )
Thanks for reading my Instructable. If you like my project, don’t forget to share it.
Comments and feedback are always welcome.