# ESP8266-based temperature and humidity station Tutorial on how to build a temperature and humidity sensor By Abraham Kamel Hussein - ak225ce **Overview** This is a simple temperature and humidity station that collects data from a DHT-11 temperature and humidity sensor and sends it over WiFi to a cloud-based service (Ubidots) to be stored in a database and visualized. It is based on the incredibly cheap and ubiquitous ESP8266 series of sensors, more specifically the NodeMCU development board, which has built in WiFi. To develop it from scratch took weeks. To make it once you have all the materials should only take you about an hour or two, depending on your skill level. **Objective** A long time ago when I first was introduced to Arduino and IoT, my first real project was to make a small temperature measurement station using an arduino connected directly to my computer. It used a simple IC temperature sensor that was quite hard to get a reliable read on, only worked when connected directly to a java program on my desktop and dumped values into a text file that I had to read manually rather than a dashboard or more powerful database. A few years later, I have spent a while studying computer science, and decided to begin a large project to create my own home automation software suite with all kinds of sensors and actuators all around the home. Having looked around at all the possible options however, I quickly realized that it would be quite expensive to get a bunch of raspberry pi's or other wi-fi enabled development boards/ arduinos+wifi shields. That's when I ran into the ESP8266 boards. ESP8266 boards like the D1 mini or NodeMCU are quite cheap compared to more powerful devices like raspberry pi's and offer the combination of an arduino-IDE compatible microprocessor that allows you to read sensors, make calculations and send output to actuators, together with simple wi-fi functionality that can be extended a lot with libraries (also through the arduino-IDE) for incredibly cheap prices, with a D1 mini costing as little as 30 SEK in some places and nodeMCUs costing around 50-100 if you go to the right place. The purpose of this particular project is to create a proof of concept where an ESP8266 is connected to a DHT-11 combined thermometer/humidity sensor and publishes the data over the internet to be collected in a database and displayed. By doing the proof of concept, more advanced projects can be attempted later with a better idea of how the ESP8266 works and what its limitations are. I also just generally have always wanted to have a history of the temperature/humidity in my apartment accessible from anywhere, to see interesting patterns and test the effects of different things, like cooking or different ways to try to cool and dehumidify the room. **Material** List of materials: -DHT 11 temperature and humidity sensor The DHT-11 is a popular temperature and humidity sensor that has many libraries and tutorials available online, since it's very often used for beginner IoT projects in arduino/raspberry pi. Can be bought from Kjell & Company in person (you pay a premium for them to have a physical store) or online. I bought mine at [Kjell](https://www.kjell.com/se/produkter/el-verktyg/arduino/moduler/temperatur-och-luftfuktighetssensor-for-arduino-p87086) for 100 SEK. ![](https://i.imgur.com/K3MseDj.png) -NodeMCU ESP8266 A powerful development board for the ESP8266. More expensive than boards like the D1 mini but also a little easier to handle since it comes with pins preinstalled, allowing to be attached to a breadboard or jumper cables. It is built around the ESP8266 chip, which is built with wifi functionality. I got mine at a local makerspace for about 40 SEK, but you can get one at [Lawicel](https://lawicel-shop.se/embedded/mikrokontroller/esp8266/nodemcu-v3-with-esp-12e-ch340/) for 50 SEK, or most other online suppliers of electronics. ![](https://i.imgur.com/viIbnLV.png) **Computer setup** Development on the NodeMCU can be done in the Arduino IDE, providing a familiar context for anyone who's already worked with Arduino and a bunch of powerful development tools. ESP-8266 support doesn't come with the arduino IDE. You have to add it by going to https://github.com/esp8266/Arduino and following the instructions there to add ESP8266 support through the board manager. Following this, you go into the "tools" dropdown menu, hover over "board" and choose your board (the NodeMCU) out of the menu that folds out. There, you're done and ready to program! Now we need 2 libraries to read the DHT-11. "Adafruit Unified Sensor" and "DHT-11 sensor library" by Adafruit. These can be installed by going into the library manager (in the "sketch" dropdown) and searching for them by name in the search text field and then clicking "install". Make sure you take the one published by Adafruit if you see several similar ones. Finally, do the same thing to download the "Arduino JSON" library published by Benoit Blanchon. The benefit of the arduino IDE is that once you have everything set up, getting your program onto the board is very easy. You simply click the "upload" button (the arrow pointing right) and your program is uploaded to the connected port. Note that you may have to change which COM port the arduino IDE operates with to interact with the board. In my case the NodeMCU usually showed up on COM 11. You can do this through the "Tools" dropdown. **Putting everything together** A wonderful thing about this project is how simple it is to set up. No resistors or other circuitry is needed, you simply connect the S pin on the DHT-11, which sends the signals indicating humidity and temperature, to GPIO2 (D4) on the NodeMCU. The 3.3V pin on the NodeMCU gets connected to the middle pin on the DHT-11 and the GND pin is connected to the final, third pin marked -. ![](https://i.imgur.com/apLOieB.png) **Platform** At the start, I wasn't really sure which platform to choose. However, I quickly realized that testing how an ESP8266 works together with a REST API could be very valuable, since they are a very versatile way of communicating between services and devices, especially when you involve the JSON format, allowing you to send over values and commands over HTTP. At first I considered programming my own REST API in the cloud using something like Node JS, Express and AWS, but I quickly realized that many complications could arise from having both an untested, brand new API and a somewhat low level device I have never programmed on before. Therefore, I decided it would be much better to use a service ready out of the box, so I can know that the API is fully reliable and more easily locate issues with the ESP8266. Ubidots just so happens to check all these boxes. It's a cloud service where you can send HTTP requests to a REST API allowing you to address individual devices with minimal setup. It also happens to have a free version, which is great because I don't really want to pay a subscription for a proof of concept. The downside however is limited data retention (about a month) and a (very generous) bandwidth cap. My plan for the future after this project however is to create my own REST API and put it on a central server in my home, maybe on a Raspberry Pi or an old unused computer in a closet. This should allow me unlimited bandwidth and a relatively large amount of processing power and memory, meaning many more devices will be able to send much more frequent updates. **The code** And now for the coding part. First, we have to include the libraries responsible for handling the WiFi functionality on the ESP8266 (ESP8266WiFi.h, ESP8266WiFiMulti.h). Then the HTTP client for the ESP8266 to allow us to send POST requests to the Ubidots API (ESP8266HTTPClient.h). Then we need a library that allows us to easily make JSON documents to send the sensor readings with (ArduinoJson.h). Finally, import DHT.h, the DHT-11 sensor library. ``` #include <ESP8266WiFi.h> #include <ESP8266WiFiMulti.h> #include <ESP8266HTTPClient.h> #include <ArduinoJson.h> #include "DHT.h" ``` Now for some definitions. We connected the signal pin of the DHT-11 to GIPO2, so we define 2 as the DHTPIN. We define the type of DHT sensor (the library can read several), which in our case is the DHT-11. ``` #define DHTPIN 2 #define DHTTYPE DHT11 ``` Finally we set some global variables, that will be available for the whole program. This is the initialized DHT object and the WifiMulti object that allows us to connect to wifi easily. ``` DHT dht(DHTPIN, DHTTYPE); ESP8266WiFiMulti WiFiMulti; ``` Now for the setup. We set up the serial connection, with a 9600 baud rate (the default on the arduino serial monitor). There is a 4 second wait loop to allow the card to enter a state where it can accept wifi commands (it has a sort of initialization time to get ready). Once that is done, we set the wifi mode to station (basically a client), log in to the local wifi network and start the DHT-11 object that will be responsible for getting readings from the sensor. ``` void setup() { Serial.begin(9600); for (uint8_t t = 4; t > 0; t--) { Serial.printf("[SETUP] WAIT %d...\n", t); Serial.flush(); delay(1000); } WiFi.mode(WIFI_STA); WiFiMulti.addAP("yourNetwork", "yourNetworkPassword"); dht.begin(); } ``` Setup is done, and we now enter the main loop, which is responsible for sending the **Transmitting the data / connectivity** Now for the main part of this program, which is an infinite loop where the sensor data is collected, packeted and sent out on a 60 second basis. All of this is in the default Arduino void loop(){} function. First we retrieve the sensor readings through the dht objects. ``` float h = dht.readHumidity(); float t = dht.readTemperature(); ``` These are then packeted into a JSON format object, which allows us to send both readings in a single POST request with a label for what each value represents (temperature and humidity in this case). This data is finally serialized so it can be sent as a single string over HTTP. ``` //Ubidots takes data in the JSON format, allowing multiple variables to be handled in a single HTTP POST request. DynamicJsonDocument doc(2048); //Creates temperature and humidity posts in the JSON documents with the values from the DHT-11 doc["Temperature"] = String(t); doc["Humidity"] = String(h); //The JSON document has to be serialized into a string to be sent as the payload in the POST request. String json; serializeJson(doc,json); ``` Finally we check that the WiFi network is connected. If it is, we set a WiFi client object to insecure in order to not have to deal with the whole SSL verification process. This is a limitation on my part, since I don't really know the process well enough to make sure the program consistently has the correct SSL footprint, but it shouldn't be a problem for a device this simple unless someone really wants to know what the temperature in your flat is like and does a man in the middle on you. Still, something that needs to be figured out before more serious projects can be done. After that, a POST request is sent and either the return payload or the error is handled. The return payload just gets printed to serial, and if there's an error you just print that to serial as well for debugging. The POST request also gets a header added to it, which includes your Ubidots authentication token. This is repeated every 60 seconds. ``` if ((WiFiMulti.run() == WL_CONNECTED)) { std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure); client->setInsecure(); HTTPClient https; Serial.print("Beginning HTTPS sequence"); if (https.begin(*client, "https://industrial.api.ubidots.com/api/v1.6/devices/HumidF")) { // HTTPS https.addHeader("X-Auth-Token","yourUbidotsToken"); Serial.print("EXECUTING POST \n"); // start connection and send HTTP header int httpCode = https.POST(json); // httpCode will be negative on error if (httpCode > 0) { // Handles the return part, request has already been sent by this point Serial.printf("RETURN CODE: %d\n", httpCode); //The post request succeeded if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { String payload = https.getString(); Serial.println(payload); } } else { Serial.printf("POST ATTEMPT FAILURE", https.errorToString(httpCode).c_str()); } https.end(); } else { Serial.printf("UNABLE TO CONNECT"); } } delay(60000) ``` WiFi is of course not the most energy efficient choice, but it is a very cheap way to communicate that should be available for basically everyone everywhere without any unusual equipment or services needed. Pretty much everyone has a wifi hotspot at this point. **Presenting the data** Ubidots will be used to gather and display the data. You can follow [this](https://hackmd.io/@lnu-iot/Hkpudaxq9) tutorial to make yourself a virtual device and a dashboard for it. The Ubidots dashboard I built consists of 2 gauges for the latest temperature and humidity measurement, and 3 line diagrams - one with humidity and temperature together over time (good for seeing how they interact) and a chart each for temperature over time and humidity over time. Data for both humidity and temperature is uploaded once a minute, to provide an acceptable resolution that allows you to look at how temperature and humidity goes over minutes, hours, days or even longer. This way Ubidots bandwidth, electricity and bandwidth are all saved without any real sacrifice in usefulness, since it's extremely unlikely I'll ever be interested in knowing how temperature and humidity change over seconds for example. ![](https://i.imgur.com/dhGSgOm.png) The data is retained for only a month, as per Ubidots [data retention policy](https://help.ubidots.com/en/articles/636669-how-long-is-my-data-stored-for). This is a huge downside, and a good reason to start working on my own hosting, processing and visualization solution. Knowing temperature data by year would be a pretty cool curiosity, and might even have some use when integrated with potential future other smart home systems that use their own models built on past data. **Finalizing the design** The results were in my opinion very satisfactory. There is as previously stated an issue with secure communication, since the whole SSL process is very difficult to do and not at all automated or simplified when programming with the ESP8266 (you literally have to figure out the SSL footprint of the site and paste it in as plaintext). This requires further investigation. Ubidots itself is also kind of a problem, as it limits how many requests can be sent in per day and only stores the data for a month. This in my opinion can be best solved by making a self hosted solution with something either similar to Ubidots that is premade or something you program yourself. This will probably be the next project I embark on. I also need to figure out how to power this device and future devices like it with a battery, since it's still reliant on USB power from a computer at the moment. This will also be part of the next project I embark on in IoT. Still, given the time limit for the project and the available skills and resources, this turned out very well. It cost very little (about 150 SEK total, could be brought down to 100 SEK total if I had bought the DHT-11 somewhere cheaper) and does exactly what I wanted it to do; display the temperature and humidity and provide historical data. ![](https://i.imgur.com/mUDnI8t.jpg)