BMP180 is a Digital pressure sensor. In this tutorial we are interfacing BMP180 with ESP8266. Sensor have pressure range of 300 to 1100hPa and operate at 1.8V to 3.6V. It’s common application is Weather forecast.
How BMP180 used for weather forecast?
In order to understand the types of weather conditions generally associated with high and low pressure systems, we must think “vertically.” The motion of air in the atmosphere above our heads plays a large part in the weather we experience here at earth’s surface. Basically, air cools as it rises, which can cause water vapor in the air to condense into liquid water droplets, sometimes forming clouds and precipitation. On the other hand, sinking air is associated with warming and drying conditions. So the first important point to keep in mind is rising air = moistening, sinking air = drying.
So what does this have to do with high and low pressure? Well, high pressure is associated with sinking air, and low pressure is associated with rising air. But why? The answer has to do with the typical air flow around high and low pressure. Physically, it seems to make sense to have air flow from high pressure to low pressure. For reasons I won’t get into in this post, the airflow (due to the Earth’s rotation and friction) is directed slightly inward toward the low pressure center, and slightly outward away from the high pressure center:
The slightly inward moving air in low pressure causes air to converge and since it can’t move downward due to the surface, the air is forced upward, leading to condensation and precipitation as discussed earlier. The opposite occurs with high pressure. Air is moving away from the high pressure center at the surface (or “diverging”) so as a result, air from above must sink to take its place. The surface flow is accompanied by the opposite behavior at upper levels of the atmosphere, as depicted in this schematic diagram:
Components required
- BMP180
- NodeMCU (ESP8266)
BMP180 Pin out
ESP8266 (NodeMCU) connections with BMP180
Note: Do not connect Sensor directly to +5V or VIN marked on NodeMCU. it will damage the sensor permanently.
Connect sensor VIN to NodeMCY 3.3V, Connect GND pin to GND, SCL to D1 and SDA to D2 of NodeMCU as shown in below circuit.
ESP8266 Code for BMP180 Sensor
Before programming Download Required Library from Here
First we see simple program which will read sensor data on serial monitor.
/* * BMP180 Interface with ESP8266 Code Example * https://circuits4you.com * March 2019 * Hardware connections: NodeMCU BMP180 3.3V VIN GND GND D1 SCL D2 SDA (WARNING: do not connect + to 5V or the sensor will be damaged!) */ #include <SFE_BMP180.h> #include <Wire.h> // You will need to create an SFE_BMP180 object, here called "pressure": SFE_BMP180 pressure; #define ALTITUDE 1655.0 // Altitude in meters void setup() { Serial.begin(115200); Serial.println("REBOOT: circuits4you.com"); // Initialize the sensor (it is important to get calibration values stored on the device). if (pressure.begin()) Serial.println("BMP180 init success"); else { Serial.println("BMP180 init fail\n\n"); while(1); // Pause forever. } } void loop() { char status; double T,P,p0,a; // Loop here getting pressure readings every 10 seconds. // If you want sea-level-compensated pressure, as used in weather reports, // you will need to know the altitude at which your measurements are taken. // We're using a constant called ALTITUDE in this sketch: Serial.println(); Serial.print("provided altitude: "); Serial.print(ALTITUDE,0); Serial.print(" meters, "); Serial.print(ALTITUDE*3.28084,0); Serial.println(" feet"); // If you want to measure altitude, and not pressure, you will instead need // to provide a known baseline pressure. This is shown at the end of the sketch. // You must first get a temperature measurement to perform a pressure reading. // Start a temperature measurement: // If request is successful, the number of ms to wait is returned. // If request is unsuccessful, 0 is returned. status = pressure.startTemperature(); if (status != 0) { // Wait for the measurement to complete: delay(status); // Retrieve the completed temperature measurement: // Note that the measurement is stored in the variable T. // Function returns 1 if successful, 0 if failure. status = pressure.getTemperature(T); if (status != 0) { // Print out the measurement: Serial.print("temperature: "); Serial.print(T,2); Serial.print(" deg C, "); Serial.print((9.0/5.0)*T+32.0,2); Serial.println(" deg F"); // Start a pressure measurement: // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait). // If request is successful, the number of ms to wait is returned. // If request is unsuccessful, 0 is returned. status = pressure.startPressure(3); if (status != 0) { // Wait for the measurement to complete: delay(status); // Retrieve the completed pressure measurement: // Note that the measurement is stored in the variable P. // Note also that the function requires the previous temperature measurement (T). // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.) // Function returns 1 if successful, 0 if failure. status = pressure.getPressure(P,T); if (status != 0) { // Print out the measurement: Serial.print("absolute pressure: "); Serial.print(P,2); Serial.print(" mb, "); Serial.print(P*0.0295333727,2); Serial.println(" inHg"); // The pressure sensor returns absolute pressure, which varies with altitude. // To remove the effects of altitude, use the sea level function and your current altitude. // This number is commonly used in weather reports. // Parameters: P = absolute pressure in mb, ALTITUDE = current altitude in m. // Result: p0 = sea-level compensated pressure in mb p0 = pressure.sealevel(P,ALTITUDE); // we're at 1655 meters (Boulder, CO) Serial.print("relative (sea-level) pressure: "); Serial.print(p0,2); Serial.print(" mb, "); Serial.print(p0*0.0295333727,2); Serial.println(" inHg"); // On the other hand, if you want to determine your altitude from the pressure reading, // use the altitude function along with a baseline pressure (sea-level or other). // Parameters: P = absolute pressure in mb, p0 = baseline pressure in mb. // Result: a = altitude in m. a = pressure.altitude(P,p0); Serial.print("computed altitude: "); Serial.print(a,0); Serial.print(" meters, "); Serial.print(a*3.28084,0); Serial.println(" feet"); } else Serial.println("error retrieving pressure measurement\n"); } else Serial.println("error starting pressure measurement\n"); } else Serial.println("error retrieving temperature measurement\n"); } else Serial.println("error starting temperature measurement\n"); delay(5000); // Pause for 5 seconds. }
Results and Testing
After uploading code open serial monitor at 115200 baud rate and You will find all sensor readings are coming. in case of any error check your connections.
Complete Weather Station
This is complete weather station project which measures, Temperature, Humidity, Pressure and Rain.
If you are looking for simple weather station using only DHT11, refer this.
Circuit Connections
Now we make complete weather station with BMP180, DHT11 and Rain Sensor. Make connections as shown below.
ESP8266 Weather Station Arduino IDE Code
Program is divided in two parts. main arduino code and index.h i.e. HTML file. before uploading code enter your SSID and Password. If you have not installed BMP180 Library, Download it from here.
/* * ESP8266 NodeMCU DHT11, BMP180 and Rain Sensor - Weather Station Example * https://circuits4you.com * * Referances * https://circuits4you.com/2017/12/31/nodemcu-pinout/ * https://circuits4you.com/2019/01/25/esp8266-dht11-humidity-temperature-data-logging/ * */ #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <SFE_BMP180.h> #include <Wire.h> #include "index.h" //Our HTML webpage contents with javascripts #include "DHTesp.h" //DHT11 Library for ESP #define LED 2 //On board LED #define DHTpin 14 //D5 of NodeMCU is GPIO14 // You will need to create an SFE_BMP180 object, here called "pressure": SFE_BMP180 pressure; #define ALTITUDE 1655.0 // Altitude in meters DHTesp dht; //SSID and Password of your WiFi router const char* ssid = "Your SSID"; const char* password = "Your Password"; ESP8266WebServer server(80); //Server on port 80 //=============================================================== // This routine is executed when you open its IP in browser //=============================================================== void handleRoot() { String s = MAIN_page; //Read HTML contents server.send(200, "text/html", s); //Send web page } float humidity, temperature; void handleADC() { char status; double T,P,p0,a; double Tdeg, Tfar, phg, pmb; status = pressure.startTemperature(); if (status != 0) { // Wait for the measurement to complete: delay(status); status = pressure.getTemperature(T); if (status != 0) { // Print out the measurement: Serial.print("temperature: "); Serial.print(T,2); Tdeg = T; Serial.print(" deg C, "); Tfar = (9.0/5.0)*T+32.0; Serial.print((9.0/5.0)*T+32.0,2); Serial.println(" deg F"); status = pressure.startPressure(3); if (status != 0) { // Wait for the measurement to complete: delay(status); status = pressure.getPressure(P,T); if (status != 0) { // Print out the measurement: Serial.print("absolute pressure: "); Serial.print(P,2); pmb = P; Serial.print(" mb, "); phg = P*0.0295333727; Serial.print(P*0.0295333727,2); Serial.println(" inHg"); p0 = pressure.sealevel(P,ALTITUDE); // we're at 1655 meters (Boulder, CO) Serial.print("relative (sea-level) pressure: "); Serial.print(p0,2); Serial.print(" mb, "); Serial.print(p0*0.0295333727,2); Serial.println(" inHg"); a = pressure.altitude(P,p0); Serial.print("computed altitude: "); Serial.print(a,0); Serial.print(" meters, "); Serial.print(a*3.28084,0); Serial.println(" feet"); } else Serial.println("error retrieving pressure measurement\n"); } else Serial.println("error starting pressure measurement\n"); } else Serial.println("error retrieving temperature measurement\n"); } else Serial.println("error starting temperature measurement\n"); int rain = analogRead(A0); //Ref 1: https://circuits4you.com/2019/01/11/nodemcu-esp8266-arduino-json-parsing-example/ //Ref 2: https://circuits4you.com/2019/01/25/arduino-how-to-put-quotation-marks-in-a-string/ //Create JSON data String data = "{\"Rain\":\""+String(rain)+"\",\"Pressuremb\":\""+String(pmb)+"\",\"Pressurehg\":\""+String(phg)+"\", \"Temperature\":\""+ String(temperature) +"\", \"Humidity\":\""+ String(humidity) +"\"}"; digitalWrite(LED,!digitalRead(LED)); //Toggle LED on data request ajax server.send(200, "text/plane", data); //Send ADC value, temperature and humidity JSON to client ajax request //Get Humidity temperatue data after request is complete //Give enough time to handle client to avoid problems delay(dht.getMinimumSamplingPeriod()); humidity = dht.getHumidity(); temperature = dht.getTemperature(); Serial.print("H:"); Serial.println(humidity); Serial.print("T:"); Serial.println(temperature); //dht.toFahrenheit(temperature)); Serial.print("R:"); Serial.println(rain); } //============================================================== // SETUP //============================================================== void setup() { Serial.begin(115200); Serial.println(); //Ref 3: https://circuits4you.com/2019/01/25/interfacing-dht11-with-nodemcu-example/ // Autodetect is not working reliable, don't use the following line // dht.setup(17); // use this instead: dht.setup(DHTpin, DHTesp::DHT11); //for DHT11 Connect DHT sensor to GPIO 17 //dht.setup(DHTpin, DHTesp::DHT22); //for DHT22 Connect DHT sensor to GPIO 17 //Onboard LED port Direction output pinMode(LED,OUTPUT); //BMP180 Sensor if (pressure.begin()) Serial.println("BMP180 init success"); else { Serial.println("BMP180 init fail\n\n"); while(1); // Pause forever. } WiFi.begin(ssid, password); //Connect to your WiFi router Serial.println(""); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } //If connection successful show IP address in serial monitor Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); //IP address assigned to your ESP server.on("/", handleRoot); //Which routine to handle at root location. This is display page server.on("/readADC", handleADC); //This page is called by java Script AJAX server.begin(); //Start server Serial.println("HTTP server started"); } //============================================================== // LOOP //============================================================== void loop() { server.handleClient(); //Handle client requests }
For more details and working of code refer read more NodeMCU Weather Station.
index.h
const char MAIN_page[] PROGMEM = R"=====( <!DOCTYPE html> <html> <head> <title>circuits4you.com</title> </head> <style> @import url(https://fonts.googleapis.com/css?family=Montserrat); @import url(https://fonts.googleapis.com/css?family=Advent+Pro:400,200); *{margin: 0;padding: 0;} body{ background:#544947; font-family:Montserrat,Arial,sans-serif; } h2{ font-size:14px; } .widget{ box-shadow:0 40px 10px 5px rgba(0,0,0,0.4); margin:100px auto; height: 330px; position: relative; width: 500px; } .upper{ border-radius:5px 5px 0 0; background:#f5f5f5; height:200px; padding:20px; } .date{ font-size:40px; } .year{ font-size:30px; color:#c1c1c1; } .place{ color:#222; font-size:40px; } .lower{ background:#00A8A9; border-radius:0 0 5px 5px; font-family:'Advent Pro'; font-weight:200; height:130px; width:100%; } .clock{ background:#00A8A9; border-radius:100%; box-shadow:0 0 0 15px #f5f5f5,0 10px 10px 5px rgba(0,0,0,0.3); height:150px; position:absolute; right:25px; top:-35px; width:150px; } .hour{ background:#f5f5f5; height:50px; left:50%; position: absolute; top:25px; width:4px; } .min{ background:#f5f5f5; height:65px; left:50%; position: absolute; top:10px; transform:rotate(100deg); width:4px; } .min,.hour{ border-radius:5px; transform-origin:bottom center; transition:all .5s linear; } .infos{ list-style:none; } .info{ color:#fff; float:left; height:100%; padding-top:10px; text-align:center; width:25%; } .info span{ display: inline-block; font-size:40px; margin-top:20px; } .weather p { font-size:20px;padding:10px 0; } .anim{animation:fade .8s linear;} @keyframes fade{ 0%{opacity:0;} 100%{opacity:1;} } a{ text-align: center; text-decoration: none; color: white; font-size: 15px; font-weight: 500; } </style> <body> <div class="widget"> <div class="clock"> <div class="min" id="min"></div> <div class="hour" id="hour"></div> </div> <div class="upper"> <div class="date" id="date">21 March</div> <div class="year">Temperature</div> <div class="place update" id="temperature">23 °C</div> </div> <div style="text-align: center;"><a href="https://circuits4you.com" style="align:center">circuits4you.com</a></div> <div class="lower"> <ul class="infos"> <li class="info temp"> <h2 class="title">TEMPERATURE</h2> <span class='update' id="temp">21 °C</span> </li> <li class="info weather"> <h2 class="title">PRESSURE</h2> <span class="update" id="pressure">0 mb</span> </li> <li class="info wind"> <h2 class="title">RAIN</h2> <span class='update' id="rain">0%</span> </li> <li class="info humidity"> <h2 class="title">HUMIDITY</h2> <span class='update' id="humidity">23%</span> </li> </ul> </div> </div> <script> setInterval(drawClock, 2000); function drawClock(){ var now = new Date(); var hour = now.getHours(); var minute = now.getMinutes(); var second = now.getSeconds(); //Date var options = {year: 'numeric', month: 'long', day: 'numeric' }; var today = new Date(); document.getElementById("date").innerHTML = today.toLocaleDateString("en-US", options); //hour var hourAngle = (360*(hour/12))+((360/12)*(minute/60)); var minAngle = 360*(minute/60); document.getElementById("hour").style.transform = "rotate("+(hourAngle)+"deg)"; //minute document.getElementById("min").style.transform = "rotate("+(minAngle)+"deg)"; //Get Humidity Temperature and Rain Data var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var txt = this.responseText; var obj = JSON.parse(txt); //Ref: https://www.w3schools.com/js/js_json_parse.asp document.getElementById("rain").innerHTML = obj.Rain + "%"; document.getElementById("temperature").innerHTML = Math.round(obj.Temperature) + "°C"; document.getElementById("temp").innerHTML = Math.round(obj.Temperature) + "°C"; document.getElementById("humidity").innerHTML = Math.round(obj.Humidity) + "%"; document.getElementById("pressure").innerHTML = Math.round(obj.Pressuremb) + " mb"; } }; xhttp.open("GET", "readADC", true); //Handle readADC server on ESP8266 xhttp.send(); } </script> </body> </html> )=====";
Results and Testing
Once code is uploaded get ESP8266 IP address from serial monitor. and open it in web browser.