Esp8266 + Rotary Encoder + 2004 LCD + DHT11 with a Menu System

In this comprehensive guide, we will learn how connect a WeMos D1 Mini to a rotary encoder, a 2004 LCD display, and a DHT11 temperature and humidity sensor to create a menu system. The WeMos D1 Mini is a compact ESP8266-based development board that is perfect for IoT projects. The rotary encoder will be used for navigating through the menu, the 2004 LCD will display the menu options, and the DHT11 sensor will provide temperature and humidity readings. This tutorial will cover the hardware connections, required libraries, and a detailed explanation of the code.

Requirements:

  1. ESP8266 development board (e.g., NodeMCU or Wemos D1 Mini) (Affiliate) – https://s.click.aliexpress.com/e/_DD3JQhj
  2. Rotary Encoder (Affiliate) – https://s.click.aliexpress.com/e/_Dl7iO57
  3. 2004 LCD module (with I2C interface) – (Affiliate) – https://s.click.aliexpress.com/e/_DE4GaZb
  4. DHT11 temperature and humidity sensor (Affiliate) – https://s.click.aliexpress.com/e/_DFb2JzR
  5. Breadboard and jumper wires (Affiliate) – https://s.click.aliexpress.com/e/_Dl5kuk1

Step 1: Connecting the Hardware (External regulated power source)

First, follow the steps from the previous tutorial to connect the rotary encoder and the 2004 LCD display to the WeMos D1 Mini -> https://www.edgemicrotech.com/wemos-d1-mini-rotary-encoder-2004-lcd-with-a-menu/

Next, connect the DHT11 sensor to the WeMos D1 Mini as follows:

– VCC to 3.3V: pin provides power to the DHT11 sensor.
– GND to GND: This pin connects the DHT11 sensor to the ground.
– DATA to D4 : This pin is responsible for transmitting data from the DHT11 sensor to the WeMos D1 Mini.

 

 

Step 2: Installing the Required Libraries

Before we start coding, we need to install the required libraries for the rotary encoder, the 2004 LCD display, and the DHT11 sensor. You can find the libraries in the Arduino IDE Library Manager:

– RotaryEncoder by Matthias Hertel: This library provides an easy way to read the rotary encoder’s position and direction.

 

 

 

 

– LiquidCrystal_I2C by Frank de Brabander: This library allows you to control the 2004 LCD display using the I2C protocol.

 

 

 

 

– DHT sensor library by Adafruit: This library provides an easy way to read temperature and humidity data from the DHT11 sensor.

 

 

 

 

 

Step 3: Coding the Menu System with DHT11 Sensor Integration

Now that we have connected the hardware and installed the required libraries, let’s write the code for the menu system with DHT11 sensor integration. Open the Arduino IDE and create a new sketch. Copy and paste the following code:

 

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RotaryEncoder.h>
#include <DHT.h>

// Initialize the LCD display
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Initialize the rotary encoder
RotaryEncoder encoder(D5, D6);


// Initialize the DHT11 sensor#define DHTPIN D4
#define DHTTYPE DHT11
DHT dht(D4, DHTTYPE);

// Define the menu items
const char* menuItems[] = { "Option 1", "Option 2", "Option 3", "Temp & Humidity" };

// Variables to store the current menu position and previous position
int menuPosition = 0;
int prevMenuPosition = 0;

void setup() {
  // Initialize the LCD display
  lcd.init();
  lcd.backlight();

  // Initialize the rotary encoder
  pinMode(D7, INPUT_PULLUP);
  encoder.setPosition(0);

  // Initialize the DHT11 sensor
  dht.begin();

  // Display the menu
  displayMenu();
}

void loop() {
  // Read the rotary encoder
  encoder.tick();

  // Update the menu position
  menuPosition = encoder.getPosition() % 4;
  if (menuPosition < 0) {
    menuPosition += 4;
  }
  
  // Check if the menu position has changed
  if (menuPosition != prevMenuPosition) {
    displayMenu();
    prevMenuPosition = menuPosition;
  }

  // Check if the rotary encoder button is pressed
  if (digitalRead(D7) == LOW) {
    // Perform an action based on the selected menu item
    switch (menuPosition) {
      case 0:
        // Action for Option 1
        break;
      case 1:
        // Action for Option 2
        break;
      case 2:
        // Action for Option 3
        break;
      case 3:
        // Action for displaying temperature and humidity
        displayTemperatureAndHumidity();
        break;
    }
  }
}

void displayMenu() {
  lcd.clear();
  for (int i = 0; i < 4; i++) {
    if (i == menuPosition) {
      lcd.print("> ");
    } else {
      lcd.print("  ");
    }
    lcd.print(menuItems[i]);
    lcd.setCursor(0, i + 1);
  }
}

void displayTemperatureAndHumidity() {
  
  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature();

  lcd.clear();
  lcd.print("Temp: ");
  lcd.print(temperature);
  lcd.print(" C");
  lcd.setCursor(0, 1);
  lcd.print("Humidity: ");
  lcd.print(humidity);
  lcd.print(" %");

  delay(2000);    // Display the readings for 2 seconds
  displayMenu();  // Return to the menu
}

 

  • In this code, we first include the necessary libraries and initialize the LCD display, rotary encoder, and DHT11 sensor. We define an array of menu items and two variables to store the current and previous menu positions.
  • In the setup() function, we initialize the LCD display, rotary encoder, DHT11 sensor, and display the menu. In the loop() function, we read the rotary encoder’s position and update the menu position accordingly. We also check if the menu position has changed and update the display if necessary. Finally, we check if the rotary encoder button is pressed and perform an action based on the selected menu item, including displaying temperature and humidity readings.
  • The displayMenu() function is responsible for displaying the menu on the LCD screen. It clears the screen, iterates through the menu items, and prints them with a “>” symbol indicating the current selection.
  • The displayTemperatureAndHumidity() function reads the temperature and humidity data from the DHT11 sensor and displays the readings on the LCD screen. It then returns to the menu after a 2-second delay.

 

Step 4: Uploading the Code

Connect the WeMos D1 Mini to your computer using a micro USB cable. In the Arduino IDE, select the correct board (WeMos D1 R2 & Mini) and the correct COM port. Click the Upload button to upload the code to the WeMos D1 Mini.

 

 

Expanding the code: Multi-level menu and back Button

  • We will expand the menu system from the previous guide to create a multi-level menu system using a WeMos D1 Mini, rotary encoder, 2004 LCD display, and DHT11 temperature and humidity sensor. This multi-level menu system will allow users to navigate through different levels of options and perform various actions.
  • We also modify the code to only go back in the menu when a button is pressed, we will add a separate button for this purpose. Connect the button to the WeMos D1 Mini as follows:

 

  1. Button’s one end to D3 (GPIO0)
  2. Button’s other end to GND

 

 

Upload the Code

 

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RotaryEncoder.h>
#include <DHT.h>

// Initialize the LCD display
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Initialize the rotary encoder
RotaryEncoder encoder(D5, D6);

// Initialize the DHT11 sensor#define DHTPIN D4
#define DHTTYPE DHT11
DHT dht(D4, DHTTYPE);
const int buttonPin = D3;

// Define the menu items
const char* mainMenuItems[] = { "Option 1", "Option 2", "Sensors", "Option 4" };
const char* sensorsMenuItems[] = { "Temperature", "Humidity" };

// Variables to store the current menu position, previous position, and menu level
int menuPosition = 0;
int prevMenuPosition = 0;
int menuLevel = 0;

void setup() {
  // Initialize the LCD display
  lcd.init();
  lcd.backlight();
  Serial.begin(115200);

  // Initialize the rotary encoder
  pinMode(D7, INPUT_PULLUP);

  // Initialize the back button

  pinMode(buttonPin, INPUT);

  encoder.setPosition(0);

  // Initialize the DHT11 sensor
  dht.begin();

  // Display the menu
  displayMenu();
}

void loop() {

  Serial.println(digitalRead(buttonPin));

  // Read the rotary encoder
  encoder.tick();

  // Update the menu position
  menuPosition = encoder.getPosition() % 4;  // Change the modulo value based on the number of menu items
  if (menuPosition < 0) {
    menuPosition += 4;
  }

  // Return to the main menu
  // Check if the back button is pressed
  
  if (digitalRead(buttonPin) == LOW) {
    // Go back to the previous menu level
    if (menuLevel > 0) {
      menuLevel--;
      menuPosition = 0;
      prevMenuPosition = -1;
      displayMenu();
    }
  }
  // Check if the menu position has changed
  if (menuPosition != prevMenuPosition) {
    displayMenu();
    prevMenuPosition = menuPosition;
  }

  // Check if the rotary encoder button is pressed
  if (digitalRead(D7) == LOW) {
    // Perform an action based on the selected menu item and menu level
    switch (menuLevel) {
      case 0:  // Main menu
        switch (menuPosition) {
          case 0:
            // Action for Option 1
            break;
          case 1:
            // Action for Option 2
            break;
          case 2:
            // Enter the Sensors menu
            menuLevel = 1;
            menuPosition = 0;
            prevMenuPosition = -1;
            break;
          case 3:
            // Action for Option 4
            break;
        }
        break;
      case 1:  // Sensors menu
        switch (menuPosition) {
          case 0:
            // Action for displaying temperature
            displayTemperature();
            break;
          case 1:
            // Action for displaying humidity
            displayHumidity();
            break;
        }
    }
  }

}


void displayMenu() {
  lcd.clear();
  const char** currentMenuItems;
  int numItems;

  // Determine the current menu items and number of items based on the menu level
  switch (menuLevel) {
    case 0:
      currentMenuItems = mainMenuItems;
      numItems = 4;
      break;
    case 1:
      currentMenuItems = sensorsMenuItems;
      numItems = 2;
      break;
  }

  // Display the menu items
  for (int i = 0; i < numItems; i++) {
    if (i == menuPosition) {
      lcd.print("> ");
    } else {
      lcd.print("  ");
    }
    lcd.print(currentMenuItems[i]);
    lcd.setCursor(0, i + 1);
  }
}


void displayTemperature() {
  float temperature = dht.readTemperature();

  lcd.clear();
  lcd.print("Temperature: ");
  lcd.print(temperature);
  lcd.print(" C");

  delay(2000);    // Display the reading for 2 seconds
  displayMenu();  // Return to the menu
}

void displayHumidity() {
  float humidity = dht.readHumidity();

  lcd.clear();
  lcd.print("Humidity: ");
  lcd.print(humidity);
  lcd.print(" %");

  delay(2000);    // Display the reading for 2 seconds
  displayMenu();  // Return to the menu
}

 

 

Troubleshooting the Multi-Level Menu System with WeMos D1 Mini, Rotary Encoder, 2004 LCD, and DHT11 Sensor

 

In this section, we will discuss some common issues that you may encounter while the multi-level menu system with the WeMos D1 Mini, rotary encoder, 2004 LCD display, and DHT11 sensor, and provide solutions to resolve them.

 

  1. The LCD display is not showing any text or showing garbled text.
    Solution: Check the I2C address of your LCD display. The default address in the code is 0x27, but it may be different for your specific display. You can use an I2C scanner sketch to find the correct address and update the code accordingly. Check this post for more info: https://www.edgemicrotech.com/connecting-an-esp8266-to-a-2004-lcd-a-comprehensive-guide/
  2. The rotary encoder is not responding or behaving erratically.
    Solution: Ensure that the rotary encoder is properly connected to the WeMos D1 Mini. Check the connections for the CLK, DT, and SW pins. Also, make sure that the rotary encoder library is correctly installed in the Arduino IDE.
  3. The DHT11 sensor is not providing accurate temperature and humidity readings.
    Solution: Check the connections between the DHT11 sensor and the WeMos D1 Mini. Ensure that the VCC, GND, and DATA pins are connected correctly. Also, make sure that the DHT sensor library is correctly installed in the Arduino IDE. Check this post: https://www.edgemicrotech.com/connecting-an-esp8266-to-a-dht11-sensor/
  4. The back button is not working.
    Solution: Check the connections between the back button and the WeMos D1 Mini. Ensure that one end of the button is connected to D3 (GPIO0) and the other end is connected to GND.
  5. The menu system is not updating or behaving as expected.
    Solution: Review the code to ensure that the menu structure, menu level handling, and button press handling are implemented correctly. Make sure that the menu items and actions are defined properly in the code.
  6. The code is not uploading to the WeMos D1 Mini.
    Solution: Check the board selection and COM port in the Arduino IDE. Ensure that the correct board (WeMos D1 R2 & Mini) and COM port are selected. Also, make sure that the WeMos D1 Mini is connected to your computer using a micro USB cable.
If you still encounter issues after trying these troubleshooting steps, double-check all connections and review the code to ensure that everything is set up correctly. If necessary, consult the documentation for the WeMos D1 Mini, rotary encoder, 2004 LCD display, and DHT11 sensor for additional information and guidance.

 

Conclusion

You have now successfully connected a WeMos D1 Mini to a rotary encoder, a 2004 LCD display, and a DHT11 temperature and humidity sensor to create a menu system. This comprehensive guide demonstrates how to expand the menu system to include sensor readings, such as temperature and humidity. You can customize the menu items and actions in the code to suit your specific project requirements. This setup can be used in various applications, such as home automation systems, IoT devices, or any project that requires user interaction through a menu and sensor data display. Happy coding!