Introduction: An ESP-Now Home Weather Station
I wanted to have a home weather station for quite some time and one that everyone in the family could easily check on for temperature and humidity. In addition to monitor the outside conditions I wanted to monitor specific rooms in the house as well and my garage workshop. That would let us know when it is a good time to air out the house or run the dehumidifier (it rains a lot here during the winter). What I created is an ESP-Now based sensor system that reports to a local web-server that anyone can check from their computer or phone. For the phone I wrote as simple Android app to make that even easier.
Step 1: Design Details
I wanted to have various sensor stations I could place in different locations and have them report back to one main station (or hub) that would save the information. After trying various ideas, I decided to use Espressif's ESP-Now protocol, since it allowed for rapid communication directly between devices. You can read a bit about ESP-Now here and this GitHub repo was a great part of my inspiration.
The first picture shows the layout of the system. Each sensor reports its measurements to a gateway device which forwards the data to the main server by hard wired serial connection. The reason for this is that the ESP-Now protocol cannot be active at the same time as the WIFI connection. For a user to access the web page, the WIFI would have to be on at all times and that then makes it impossible to use the ESP-Now communications on the same device. While the gateway device must be an Espressif based device (capable of ESP-Now), the main server could be any device capable of running a web page.
Some sensor stations would run off batteries (or solar charged batteries) and others would simply have mains power. However, I wanted all to use as little power as possible and that is where the "deepsleep" feature available to ESP8266 and ESP32 devices is extremely helpful. The sensor stations would periodically wake up, take measurements and send them to the gateway device and go back to sleep for some preprogrammed period of time. Their wake period of only about 300ms every 5 minutes (in my case) reduces their power consumption significantly.
Step 2: Sensors
There are various sensors to chose from for measuring environmental parameters. I decided to stick with I2C communications capable sensors only, as it allowed rapid measurements and would work on any of the devices I had. Rather than working with ICs directly, I searched for ready to use modules that had the same pin-outs to simplify my designs. I started with only wanting to measure temperature and humidity and therefore chose a SI7021 based module. Later I wanted a sensor that could measure pressure as well and decided to try the BME280 based sensor modules. For some locations I even wanted to monitor the light levels and the BH1750 module was ideal for this as a separate sensor module. I bought my sensor modules off ebay and these are the modules I received:
- BME280 (GY-BMP/E280), measures temperature, humidity and pressure
- SI7021 (GY-21), measures temperature and humidity
- BH1750 (GY-302), measures light
There are two styles of the GY-BMP/E280 PCB modules to be found. Both share the same pin out for pins 1 to 4. One module has two additional pins, CSB and SDO. Those two pins are pre-connected on the 4-pin version of the module. The level of the SDO pin determines the I2C address (Ground = default of 0x76, VCC = 0x77). The CSB pin must be connected to VCC to select the I2C interface. I prefer the 4 pin module, since it is ready to use as is for my purpose.
In general, these modules are very convenient to use as they already have pull-up resistors installed for the communications lines and all run on 3.3V so are compatible with ESP8266 based boards. Note, that the pins on these sensor ICs are generally not 5V tolerant, so interfacing them directly with something like an Arduino Uno may damage them permanently.
Step 3: Sensor Stations
As mentioned, the sensor stations would all be Espressif devices using the ESP-Now communications protocol. From previous projects and experimentation, I had several different devices available to me to conduct my initial tests and incorporate them into the final design. I had the following devices on hand:
- two ESP-01 modules
- two Wemos D1 mini development boards
- one Lolin ESP8266 development boards
- one ESP12E serial WIFI kit board
- one GOOUUU ESP32 board (a 38 pin development board)
I also had a Wemos D1 R2 development board, but there were issues with it that did not allow it to wake up from deep sleep and as a gate way device it would crash and not properly restart. I repaired it later on and it became part of the Garage Door opener project. In order for "deepsleep" to work, the RST pin of the ESP8266 must be connected to the GPIO16 pin, so the sleep timer can wake up the device. Ideally this connection should be made with a Schottky diode (cathode to GPIO16) so that the manual reset through the USB-TLL connection during programming still works. However, a low value (300-ish Ohm) resistor or even direct wire connection can still be successful.
ESP-01 modules do not allow for easy access to the GPIO16 pin and one must solder directly to the IC. This is not a simple task and I would not recommend this for everyone. The ESP12E serial WIFI kit board was a bit of a novelty item and required quite a few changes for it to be useful for my purpose. The easiest boards to use were the Wemos D1 mini type boards and the Lolin board. ESP32 devices do not require any modifications for deepsleep to work. Andreas Spiess has a nice Instructable on this.
Step 4: ESP-01 Sensor Station
On all sensor stations the sensor modules are mounted vertically to reduce the amount of dust that can collect on them. Not all are in enclosures and I may not mount them in enclosures. The reason for this is that the devices may warm up and affect the temperature and humidity readings in not sufficiently ventilated.
ESP-01 boards are very compact and have few digital IO pins to work with, but it is enough for the I2C interface. The boards do however require a tricky modification to allow "deepsleep" to work. In the photo shown, a wire was soldered from the corner pin (GPIO16) to the RST pin on the header. The wire I used is 0.1mm diameter insulated "repair" wire. The insulation coating melts away upon heating, so it can be soldered to repair traces, etc in PCBs and still not worry about creating shorts where the wire contacts other components. Its size makes it difficult to work with and I soldered this wire in place under a (hobbyist/stamp collectors’ style) microscope. Keep in mind that the header on the right side has a 0.1" (2.54mm) pin spacing. Installing a Schottky diode here would not be easy at all, so I decided to just try the wire alone and both units have been running for over a month without any issues.
The modules were installed on two prototype boards I created. One (#1) is a programmer board that also allows I2C modules to be installed and tested, while the other (#2) is a development/test board for I2C devices. For the first board I soldered together an old USB male connector and a small PCB to power the unit directly from a USB wall adapter. The other unit has a regular DC jack modified to fit into the screw terminal header and is powered via a wall adapter as well.
The schematic shows how they are connected and how the programmer works. I do not have any other ESP-01 modules, so I haven't had any immediate need for the programmer. In the future I will likely make a PCB for them. Both of these boards have the SI7021 sensor module installed as I was not as interested in pressure measurements on those locations.
Step 5: ESP 12E Serial WIFI Kit Sensor Station
The ESP12E Serial WIFI Kit board was not intended for development as much as it was for showcasing what could be done with this device. I bought it long ago to learn a bit about ESP8266 programming and finally decided to give it some new use. I removed all the LEDs that were installed for demonstrations and added a USB programming header as well as a I2C header suitable for the modules I use. It had a CdS photo resistor connected to its analog input pin and I decided to leave it there. This particular unit was going to monitor my garage workshop and the photo-sensor it had was sufficient to let me know if the lights had been accidentally left on. For the light measurement I normalized the readings to give me a percent output and anything over “5” at night meant the lights were left on or a door to the house was not properly closed. The RST and GPIO16 pins are clearly labeled on the PCB and the Schottky diode connecting them was installed on the underside of the PCB. It is powered through a USB-serial board that is directly plugged into a USB wall charger. I have extras of these USB-serial boards and don't need this one right now.
I did not make a schematic for this board and generally do not recommend buying one to use for this purpose. The Wemos D1 Mini boards are much more suitable and will be discussed next. Although, if you do have one of these and need some advice, I'd be happy to help.
Step 6: D1 Mini Sensor Stations
The Wemos D1 Mini type of ESP8266 development boards are my preferred ones to use and if I had to do it over, I would just use these. They have a large number of accessible IO pins, can be directly programmed via the Arduino IDE and are still fairly compact. The D0 pin is GPIO16 on these boards and connecting a Schottky diode is rather easy to do. The schematic shows how I have these boards wired up and both of them use the BME2808 sensor module.
One of the two boards is used to monitor the outside weather and runs from a solar power battery. A 165mm x 135mm (6V, 3.5W) solar panel is connected to a TP4056 Li-ion battery charging module (see the Solar Powered Battery Sensor Station Setup Diagram). This particular charging module (03962A) features a battery protection circuit which is necessary if the battery (pack) does not contain one. The Li-ion battery was recycled from an old laptop battery pack and it still can hold sufficient charge to run the D1 Mini board, especially with deep sleep enabled. The board was placed in a plastic enclosure to keep it somewhat safe from the elements. However, in order for the interior to be exposed to the outside temperature and humidity, two 25mm diameter holes were drilled on opposite sides and covered (from the inside) with black landscape cloth. The cloth is designed to allow moisture to penetrate and therefor the humidity can be measured. At one end of the enclosure a small hole was drill and a clear plastic window installed. This is where the BH1750 light sensor module was placed. The entire unit is placed outdoors in the shade (not direct sun) with the light sensor point out into the open. It has been running from the solar powered battery for almost 4 weeks in our rainy/cloudy winter weather here.
Step 7: Gateway and Webserver
A Lolin NodeMCU V3 (ESP8266) board was used for the ESP-Now Gateway device and an ESP32 (GOOUUU board) was used for the Webserver. Almost any ESP8266 or even ESP32 board could have served as the gateway device, this was simply the board I had "left over" after I used all the other boards I had.
I used the ESP32 board since I need a board with a bit more computing power to collect the data, sort it, save it to storage and run the web server. In the future it may also have its own sensor and a local (OLED) display. For storage an SD card was used with a customized adapter. I used a common microSD to SD card adapter and soldered a 7 pin male (0.1" pitch) header to the plated contacts. I followed the advice from this GitHub to make the connections.
The prototyping setup (with Dupont wires) does not include a sensor module, but the finalized PCB that I designed does allow for one as well as a small OLED display. Details on how I designed that PCB are part of a different Instructable.
Step 8: Software
ESP8266 (ESP-NOW) Devices
The software for all devices was written using the Arduino IDE (v1.87). Each sensor station runs essentially the identical code. They only differ by which pins are used for the I2C communications and which sensor module they are connected to. Most importantly they send the identical measurement data packet to the ESP-Now Gateway station, regardless whether they have the same sensor. What this means is that some sensor stations will fill in dummy values for the pressure and light level measurements if they do not have sensors to provide real values. The code for each station and the gateway was adapted from Anthony Elder's examples on this GitHub.
The gateway device code used SoftwareSerial to communicate with the web server, since ESP8266 has only one fully functioning hardware UART. Running at maximum baud rate of 9600 it seems quite reliable and is more than sufficient for sending these relatively small data packets. The gateway device is also programmed with a private MAC address. The reason for this is so if it needs replacing, then the sensor stations do not all have to be re-programmed with the new recipient MAC address.
ESP32 (Web Server)
Each sensor station sends its data packet to the gateway device which forwards it to the web server. Along with the data packet the sensor station MAC address is also sent to identify each station. The web server has a "look-up" table to determine the location of each sensor and sorts the data accordingly. The time interval between measurements was set to 5 min plus a random factor to avoid having sensors "collide" with one another when sending to the gate way device.
The home WIFI router was set to allot a fixed IP address to the web server when it connects to the WIFI. For mine it was 192.168.1.111. Typing that address in any browser will connect to the weather station web server as long as the user is within WIFI range of (and connect to) the home network. When user connects to the web page, the web server responds with a table of the measurements, and includes the time of the last measurement of each sensor. This way if a sensor station becomes non-responsive, one can see that from the table if a reading is more than 5-6 min old.
The data is saved in individual text files on an SD card and they can also be downloaded from the web page as well. It can be imported into Excel or any other application for plotting data
Android App
To make it easier to view the local weather information on a smartphone, I created a relatively Android App using Android Studio. It is available on my GitHub page here. It uses the webview class to load the web page from the server and as such as limited functionality. It is not capable of downloading the data files and I had no need for those on my phone anyway.
Step 9: Results
Finally, here are some results for from my home weather station. The data was downloaded on a laptop and plotted in Matlab. I attached my Matlab scripts and you can also run them in GNU Octave. The outdoor sensor has been running on its solar charged battery for almost 4 weeks and we have rarely any sun at this time of the year. So far everything is working well and everyone in the family can look up the weather themselves rather than asking me now!
Attachments

Participated in the
Epilog X Contest
16 Comments
2 years ago
Hi, thank you for this great project.I have reached a stage where I have a working sensor that transmits the readings to gateway and I can see them on serial monitor. The problem is that this readings are from hardware serial pins not from software serial pins which are silent. I lookup your code but to be honest I don't have much knowledge so far to debug. Would you direct me where to look?
Greetings,
Milen
Reply 2 years ago
Hi Milen,
What kind of device are you using for the gateway? In my project I used an ESP8266 device and it was set up to use Software serial. Did you use the same type of device and the software I included above?
Reply 2 years ago
Yes, I use NodeMCU and code you published here
Reply 2 years ago
Double check you have the software serial pins connected correctly. It should work if connected as per diagram above.
Reply 2 years ago
Hi, everything is fine now, I was written mac address of the sensor wrong and obviously that was the problem. Thanks again for your responsiveness.
Reply 2 years ago
Good to hear you found the problem! You're welcome :)
3 years ago
Hi Marcell
So I'm back this time equipped with ESP8266, I have built 3 transmitters, and according to the serial printout, they are collecting temperatures and the Sara is being sent.
On the receiver side, I do a reboot serial printout is all good and awaiting esp connection, nothing ever arrives.
Has something changed in the code since you did this project as I just can't it to w3.
Cheers Alan
Reply 3 years ago
Hi Alan, I've changed nothing really. My system has been up and running for a over year unattended now. I've added a couple more sensor stations last summer and that is all. My suggestion for debugging is to first run them near each other, so distance/obstacles do not interfere with the connection. Verify that the private MAC address has been set correctly and that is indeed the MAC address the sensor stations are sending the data to. Is the serial gateway receiving correctly? Check that before worrying about the web server part. You can monitor the serial gateway output using the USB-to-serial adapter and any serial terminal app.
3 years ago
This model that I want, I'll try when my Esp32 arrive from ae, Esp32 as server and 4 wemos D1 Mini Pro as clients with sht30 sensor
Reply 3 years ago
Sounds good and it should work fine. I have 7 sensor stations now and one of them runs off a solar panel (charging a 18650 battery) for 6 months now already. Works very nice for me.
4 years ago
Hi Marcell
Great project this is exactly what I was looking for with a little mod, I only actually need the BME280 sensor in the garden sending data to a receiver, I don`t need the web-server part.
The problem I`m running into is the fact that you are using ESP2866 boards and I have ESP32, I chose them specifically as they have an even lower standby current drain.
So I have played around with my boards, all test sketches work, ESP-NOW, Deep Sleep etc.
So I thought it would be easy to implement your sensor code to work with the ESP32, nope problems after problems, just cant get it to work.
Any assistance you can give on sorting out these errors so I can use the ESP32 would be most appreciated
Lines of code where there are issues are
C:\Users\Gamma\Documents\Arduino\sketch_apr02s\sketch_apr02s.ino: In function 'void setup()':
sketch_apr02s:80:8: error: 'class WiFiClass' has no member named 'setOutputPower'
WiFi.setOutputPower(20.5);
^
sketch_apr02s:82:25: error: 'ESP_NOW_ROLE_CONTROLLER' was not declared in this scope
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
^
sketch_apr02s:82:48: error: 'esp_now_set_self_role' was not declared in this scope
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
^
sketch_apr02s:83:31: error: 'ESP_NOW_ROLE_SLAVE' was not declared in this scope
esp_now_add_peer(remoteMac, ESP_NOW_ROLE_SLAVE, WIFI_CHANNEL, NULL, 0);
^
sketch_apr02s:88:4: error: invalid user-defined conversion from 'setup()::<lambda(uint8_t*, uint8_t)>' to 'esp_now_send_cb_t {aka void (*)(const unsigned char*, esp_now_send_status_t)}' [-fpermissive]
});
^
C:\Users\Gamma\Documents\Arduino\sketch_apr02s\sketch_apr02s.ino:85:63: note: candidate is: setup()::<lambda(uint8_t*, uint8_t)>::operator void (*)(uint8_t*, uint8_t)() const <near match>
esp_now_register_send_cb([](uint8_t* mac, uint8_t sendStatus) {
^
C:\Users\Gamma\Documents\Arduino\sketch_apr02s\sketch_apr02s.ino:85:63: note: no known conversion from 'void (*)(uint8_t*, uint8_t) {aka void (*)(unsigned char*, unsigned char)}' to 'esp_now_send_cb_t {aka void (*)(const unsigned char*, esp_now_send_status_t)}'
In file included from C:\Users\Gamma\Documents\Arduino\sketch_apr02s\sketch_apr02s.ino:34:0:
C:\Users\Gamma\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.0/tools/sdk/include/esp32/esp_now.h:165:11: note: initializing argument 1 of 'esp_err_t esp_now_register_send_cb(esp_now_send_cb_t)'
esp_err_t esp_now_register_send_cb(esp_now_send_cb_t cb);
^
C:\Users\Gamma\Documents\Arduino\sketch_apr02s\sketch_apr02s.ino: In function 'void gotoSleep()':
sketch_apr02s:132:42: error: 'RANDOM_REG32' was not declared in this scope
int sleepSecs = SLEEP_SECS + ((uint8_t)RANDOM_REG32/8);
^
sketch_apr02s:136:38: error: 'RF_NO_CAL' was not declared in this scope
ESP.deepSleep(sleepSecs * 1000000, RF_NO_CAL);
Reply 4 years ago
Hi there!
The ESP32 has some different libraries & include files compared to the ESP8266, so you have to make the appropriate changes for them. It should work fine on ESP32 devices once you've made those changes. For the first error you get (setting the transmit power) you can exclude that line if you want. I only used it to boost transmitting power for devices that were further away from the receiver and you may not need that at all (not all my devices need it).
For ESP-Now functions, check out this page: https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/network/esp_now.html
For ESP32 devices you have to include the appropriate header file:
esp32/include/esp_now.h
That should fix those problems as long you check the function calls are the ones that match the ESP32.
The deep sleep function calls for the ESP32 are not the same as for the ESP8266. If you check the ESP32 core on github, you can find examples of the calls and how they are used. The ESP32 library uses separate function calls to initialize the deep sleep mode and to start it. There is an example here:
https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/ExternalWakeUp.ino
Let me know how it works out.
4 years ago
It seems to me that there is an inherent problem with your design...
Using a random generator so as to avoid packet interference is all well and good, but it does not help to identify the sending sensor if THE SENSORS ALL HAVE THE SAME MAC. Without a unique MAC assigned to each sensor, you have no way of knowing which sensor sent the data packet.
So... your only option is to pool all data received into 1 file as if it were being sent by 1 Sensor and call it a day.
However, you could increase your sample size by cataloging each sensor for a unique MAC address and pairing all sensors in the Receiver. Then you would know which sensor sent the last packet and be able to sort the incoming data without having to fudge missing data. Finally, the Receiver would be able to isolate a failed sensor or one that is not sending good data.
Reply 4 years ago
Each sensor comes with a unique MAC and that is how they are identified. That is shown in the code and stated above. Under the section "ESP32 Webserver" it states : "Along with the data packet the sensor station MAC address is also sent to identify each station." The slight randomization for the sleep time is just to avoid collisions when sending the data so not too much is missed. They have been running for over 2 months without any problems, sending date roughly every 5-6 min.
Tip 4 years ago
Maybe Add more sensors?
Reply 4 years ago
Personally I am just mostly interested in temperature and humidity at certain locations around the house. Some stations have (or will have) pressure and light measurements as well. The main webserver will get a sensors. The socket for it is already there, so it won't be difficult. There is almost no limit to the number of sensor stations of course or the types of measurements you can do. I tested one sensor station at the back of my yard and it is able to send to my WIFI server sitting in my basement (almost 60 ft/18m away through several walls).