Have you ever left your home only to find yourself standing in the rain on the street? This project ensures that doesn’t happen again.
Using an ESP8266, you’ll retrieve the current weather conditions via an API and display on an OLED screen whether it’s raining, snowing, or the sun is shining. If you need an umbrella outside, the display and an LED will remind you to take your umbrella with you.
Oh, and to prevent your ESP8266 from spending the whole day on the internet constantly retrieving weather data, you’ll also integrate a radar module. This way, you can place your project near your apartment door, for example, and only activate it when you approach. So you’ll be reminded at just the right time. 🙂
For this project you’ll need:
- NodeMCU ESP8266
- OLED Display 128×64 pixels
- Microwave radar sensor RCWL-0516
- LED
The Setup
This is roughly how the completed project should look:
First, place your ESP8266 on your breadboard. I recommend using a NodeMCU Lua Amica for this, as it’s narrow enough that you can still plug cables into the pinouts. The newer version called Lolin is at a disadvantage here and therefore less suitable for breadboard projects. Then connect your microcontroller to these 3 components:
OLED Display
In this project, you’ll use a small OLED display with I²C connection. Place your display on the breadboard and first connect it to one of the GND pins and a 3.3V output on the microcontroller. Then connect the display pin SCL to D1 and the SDA pin to D2. You can communicate with your display via I²C using these two pins D1 and D2.
Radar Module RCWL-0516
This sensor is an excellent motion sensor with a range of 5 to 7 meters. The great thing about this module is that it can even detect movements through an obstacle (for example, a box).
The connection is child’s play: In addition to the usual connection of GND and 3.3V, you connect the OUT pin to pin D7 on your ESP8266.
The LED
Now for the easiest exercise, the LED. Connect the anode (long leg) to pin D6 and the cathode (short leg) to ground. Don’t forget to add a resistor (e.g. 220Ω) in between!
The Code for Your Project
Are you new to the ESP8266? Then find out how to program the ESP8266 with the Arduino IDE.
___STEADY_PAYWALL___
The Openweather API
It gets a bit more complex now, because first you need to register for a free API from which you can retrieve the current weather conditions at your location (or any other place on Earth).
First, register at https://openweathermap.org. For an account, you only need a username, an email address, and a password. In your personal area, you now have the option to create an API key under the menu item API keys. You’ll need this later in your Arduino sketch for the API query of the weather data. Once you’ve done that, you can continue with the code.
The Required Libraries
For this project, you need 7 libraries. You may need to install 3 of these first to be able to use them: Adafruit GFX, Adafruit 1306, and ArduinoJSON. If you haven’t installed them in your Arduino IDE yet, it’s best to do that now. To do this, click on the Tools menu item and then on Manage Libraries. Then the Library Manager opens, where you can search for the respective libraries. Install the latest version of each.
When you’re done with that, include them at the beginning of your sketch before the void setup() function:
#include <Wire.h> //I2C connection
#include <Adafruit_GFX.h> //OLED display
#include <Adafruit_SSD1306.h> //OLED display
#include <ESP8266WiFi.h> //WiFI
#include <ArduinoJson.h> //JSON
#include <ESP8266HTTPClient.h> //API query
#include <WiFiClient.h> //API query
Internet Access Data and OLED Display
To allow your ESP8266 to connect to the internet, you need to provide your access data. Right after that follows some code for communication with your display:
// WiFi credentials
const char* ssid = "Your network name";
const char* password = "Your password";
//OLED display
#define SCREEN_WIDTH 128 // Display width in pixels
#define SCREEN_HEIGHT 64 // Display height in pixels
//Information about the OLED display and I2C communication
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
Icons for All (Important) Weather Conditions
Icons should appear on your display later to symbolize the current weather: clear sky, clouds, snow, fog – and an umbrella for rain and thunderstorms. The declarations of these icons in the code are very long. Therefore, you won’t find them here, but in the complete Arduino sketch that you can find below.
The Setup Function
In the setup() function, you define the two pins for the LED and the radar sensor, prepare the connection to the Serial Monitor, specify the address of your display, and set the font size and color. 🙂
void setup() {
pinMode (12, OUTPUT); //LED Pin (D6 on ESP8266)
pinMode (13, INPUT); //Radar Pin (D7 on ESP8266)
Serial.begin(115200); //Connection to Serial Monitor
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Display address: 0x3C
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.setTextSize(1); //Font size
display.setTextColor(SSD1306_WHITE); //Color
display.clearDisplay();
}
The Loop
In the loop() function, your radar module works. Every 100 milliseconds it checks if something is moving nearby. If so, your ESP8266 connects to the internet and starts querying the weather data from Openweather. As long as this is not the case, the loop keeps running and the OLED display remains dark.
void loop() {
delay(100);
if (digitalRead(13) == HIGH) { //Movement detected?
Serial.println("Movement detected.");
if (WiFi.status() != WL_CONNECTED) { //Not connected -> Establish connection
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
display.clearDisplay();
display.setCursor(0, 10);
display.println("Connecting to WiFi..."); //Show connection status
display.display();
}
display.clearDisplay();
display.setCursor(0, 10);
display.println("Connected to WiFi!"); //Show connection status
display.display();
delay(1000);
}
apiCall(); //Call apiCall() function
} else { //No movement detected?
if (WiFi.status() == WL_CONNECTED) { //then terminate the existing connection
WiFi.disconnect();
Serial.println("Disconnected from WiFi");
}
digitalWrite(12, LOW);
}
}
The apiCall() Function
This function is the heart of your code! Here you start the query to the API (a so-called API Call), process the data arriving in your ESP8266, and display an appropriate icon on your display depending on the weather. Additionally, you output the current temperature and make the LED light up when it rains.
This code is not quite simple. So let’s look at it step by step:
First of all, you define the function itself and write an If query, within which all the following code takes place. With this query, you ensure that this is only executed when the connection to the internet is established. Because without internet, no weather data. 🙂
void apiCall() {
if ((WiFi.status() == WL_CONNECTED)) { //Check network status
Retrieving and Processing Weather Data
Now comes the query to Openweather. For this, you use a URL that defines the type of query (current weather) and the desired location. At the end of the URL is your API key, which you created at the beginning.
A possible URL for querying Berlin’s weather could look like this:
http://api.openweathermap.org/data/2.5/weather?q=Berlin,de&units=metric&appid=YOUR API KEY"
Enter the city whose weather you want after q=. Alternatively, you can also use the coordinates of your location. To find these, the website latlong.net is suitable – there you can enter any location and find out its coordinates. For Berlin, the URL would then look like this:
http://api.openweathermap.org/data/2.5/weather?lat=52.51&lon=13.39&units=metric&appid=YOUR API KEY"
Now follows a check if the query worked. In this case, you get the answer 200 from the server. So you write an If query that only executes all following code if the server response was positive and you received the desired data.
Then you save this data in the variable payload and process it using the ArduinoJson library.
if (httpCode == HTTP_CODE_OK) { //Is the server response 200?
String payload = http.getString(); //Save data in a variable
DynamicJsonDocument doc(1024);
DeserializationError error = deserializeJson(doc, payload); //Parse JSON
if (error) { //Error message for faulty processing
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
return;
}
The payload variable now contains the weather data in JSON format. You can see what this looks like if you call the URL for the query from your sketch in your browser. Here’s an example for Berlin on the evening of January 13, 2020:
{"coord":{"lon":13.41,"lat":52.52},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03n"}],"base":"stations","main":{"temp":3.2,"feels_like":-1.49,"temp_min":1.11,"temp_max":5,"pressure":1017,"humidity":86},"visibility":10000,"wind":{"speed":4.1,"deg":180},"clouds":{"all":40},"dt":1578947701,"sys":{"type":1,"id":1275,"country":"DE","sunrise":1578899517,"sunset":1578928632},"timezone":3600,"id":2950159,"name":"Berlin","cod":200}
A bit hard to read, isn’t it? However, this is no problem for your ESP8266. The ArduinoJson library provides you with everything for this. In short, you can fish out exactly the data you need with a few lines of code. Above all is a For loop that ensures that the upcoming displays and animations are shown three times until the display goes dark again:
//Output weather condition and temperature
for (int j = 0; j < 3; j++) { // Run animation 3 times until next measurement
//Read weather data based on ID
JsonObject weather_0 = doc["weather"][0];
int weather_0_id = weather_0["id"]; // Weather ID
Serial.println(weather_0_id);
You have now extracted the ID of the current weather from the data. Openweather assigns each weather condition its own three-digit ID. For example, light rain has the ID 500. Falling volcanic ash, on the other hand, has the ID 762! You can find all IDs here.
Showing Weather Data on the Display
Now follow a series of If queries that show and animate the icon appropriate to the weather on your display. Here’s an example of the ID range “Clouds” – these are all IDs between 801 and 804. You can find more detailed explanations in the comments in the code. The For loop is interesting: Here you move the icon to the left by displaying it 128 times (the width of the icon) one pixel further left each time. This creates the impression of an animation.
if (weather_0_id > 800 && weather_0_id < 900) {
//Show and move cloud away
display.clearDisplay(); //Clear display
display.drawBitmap(0, 0, clouds, 128, 64, WHITE); //Draw icon...
display.display(); //...and show
digitalWrite(12, LOW); //Turn off LED as no rain
delay(2000);
for (int i = 0; i > -128; i--) { //"Push" the icon out of the display
display.clearDisplay();
display.drawBitmap(i, 0, clouds, 128, 64, WHITE);
display.display();
delay(1);
}
This is followed by more queries via else if{} for the other weather conditions, which you can find below in the complete sketch.
Now all that’s missing is the display of the temperature. You also read this from the JSON data and bring it to your display in an animated way:
//Show and animate temperature
JsonObject main = doc["main"];
int main_temp = (int)main["temp"]; // Convert data to INT and save in variable
String temp = String(main_temp) + " C"; //Append C for Celsius
display.setTextSize(3); //Increase font size
display.setCursor(25, 20);
display.println(temp);
display.display();
delay(2000);
for (int i = 25; i > -144; i--) { //Animation
display.clearDisplay();
display.setCursor(i, 20);
display.println(temp);
display.display();
delay(1);
}
Finally, you set the font size back to 1 and close all open brackets. The very last else refers to the query whether the server’s response was positive (i.e. 200) and returns an error message if it wasn’t.
Here now is the complete sketch. When you copy and use it, be sure to enter your own WiFi data and your Openweather API key in the marked places.