Arduino MEGA 2560 + ESP8266 (ESP-01) Home Automation

You can watch DHT11 data (Humidity and Temperature), IR Flame Sensor, MQ-4 Natural Gas Sensor, HC-SR501 PIR Motion Dedector and control 4 Channel Relay Module over internet/network with Android App. We use ESP8266-01 WiFi module for wireless comminication.

Required Main Parts

  • Arduino MEGA 2560 (Rev3)
  • ESP8266-01 WiFi module (If you need update your ESP8266 Firmware please check ESP8266 Firmware update page)
  • DHT11 Humidity and Temperature sensor
  • IR Flame Sensor
  • MQ-4 Natural Gas Sensor
  • HC-SR501 PIR Motion Dedector
  • 4 Channel Relay Module
  • Any Android device

Project Details

We use ESP8266-01 WiFi module for wireless comminication.
We need two libraries for read DHT11:
DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library
Adafruit Unified Sensor Lib: https://github.com/adafruit/Adafruit_Sensor
We need WiFiEspAT library for ESP-01 module:
WiFiEspAT: https://github.com/jandrassy/WiFiEspAT
We need ArduinoJson library for serialize Json data:
ArduinoJson: https://arduinojson.org/

You can install all these libraries from Library Manager in your Arduino IDE

We use external DC power adaptor for Arduino and power circuit for sensors, 4 Channel Relay Module and ESP-01 module. We use Arduino mega 2560 r3 proto shield for power circuit and ESP-01 module.

Arduino Home Automation Shield

Shopping List

Amount Part Type
2 100nF/16V Ceramic Capacitor
1 1000μF/16V Electrolytic Capacitor
1 100μF/16V Electrolytic Capacitor
1 7805 5V Voltage Regulator
1 LD1117 3.3V Voltage Regulator
1 Female Header

Power Circuit

Arduino Home Automation power supply circuit schema

Shopping List

Amount Part Type
1 Arduino Mega 2560 (Rev3)
1 4 Channel Relay Module
1 1N4148 Diode
1 DHT11 Temperature & Humidity Sensor Module
1 HC-SR501 Motion Sensor Module
1 IR Flame Sensor Module
1 MQ-4 Natural Gas Sensor Module
1 ESP8266 (ESP-01) WiFi Module
1 10kΩ Resistor
1 Pushbutton

Circuit

Arduino home automation schema

Android APP

Android Home Automation APP

Code (arduino_secrets.h)

#define SECRET_SSID "SSID" // Your SSID
#define SECRET_PASS "SSIDPASS" // Your SSID Password

Code (HomeAutomation.ino)

/**********************************************************************
 *  For projects details and circuit scheme please visit:             *
 *  https://www.arduinoclub.net/arduinomega-2560-home-automation.html *
 *********************************************************************/
// Include WiFiEspAT library
#include <WiFiEspAT.h>
// Include EEPROM library
#include <EEPROM.h>
// Include SSID  information (arduino_secrets.h) file
#include "arduino_secrets.h"

// Include Adafruit DHT11 Sensor Library
#include "DHT.h"
// DHT11 pin
#define DHTPIN 6
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

// ArduinoJson
#include <ArduinoJson.h>
StaticJsonDocument<150> doc;

// Don't change from here. Please edit from arduino_secrets.h file
const char ssid[] = SECRET_SSID;    // Your SSID (use arduino_secrets.h for change)
const char pass[] = SECRET_PASS;    // Your SSID Password (use arduino_secrets.h for change)

// Password for connection requests. You can change your connection password from this variable.
char* password = "1234";

// Relay pins
int relays[] = {NULL, 2, 3, 4, 5};

// HC-SR501 PIR Sensor pin
int hcSr501 = 7;
int motionState = 0;
int EepromMotionState;

// Flame sensor pin
int flameSensor = A0;
int flameState = 0;
int EepromFlameState;
// The limit value that the FLAME sensor will define as flame (max value: 1023)
int flamethreshold = 200;

// MQ-4 gas sensor pin
int gasSensor = A1;
int gasValue = 0;
int EepromGasState;
// Limit value that the MQ-4 gas sensor will define as a gas leak (max value: 1023)
int gasthreshold = 390;

String answer = "";
int bodyFinder = 0;
char requestBody[100];
int count;
int rState;
boolean rlrequest = false;
boolean getallrequest = false;

#if defined(ARDUINO_ARCH_AVR) && !defined(HAVE_HWSERIAL1)
#include 
SoftwareSerial Serial1(12, 13); // RX, TX
#define AT_BAUD_RATE 9600
#else
#define AT_BAUD_RATE 115200
#endif

WiFiServer server(80);

void setup() {

  // The final position of the relays is adjusted by reading from the EEPROM.
  for (count = 1; count <= 4; count++) {
    rState = EEPROM.read(count);
    pinMode(count+1, OUTPUT);
    if (rState == 1) {
      onOff(count, "ON", false);
    } else {
      onOff(count, "OFF", false);
    }
  }

  pinMode(hcSr501, INPUT);
  pinMode(flameSensor, INPUT);
  pinMode(gasSensor, INPUT);

  Serial.begin(115200);
  while (!Serial);

  // Serial for ESP8266 initializing
  setEspBaudRate(AT_BAUD_RATE);

  WiFi.init(Serial1);

  dht.begin();

  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println(F("ESP8266 not found"));
    // Operation discontinued because ESP8266 could not be found
    while (true);
  }

  // Connect / reconnect to WiFi network
  int status = WiFi.begin(ssid, pass);

  Serial.println(F("Trying to connect to SSID: "));
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
    Serial.print('.');
  }
  Serial.println();

  // ESP8266 server starting
  server.begin();

  IPAddress ip = WiFi.localIP();
  Serial.println();
  Serial.println(F("WiFi network connected."));
  Serial.print(F("To send a request to the server use \"http://"));
  Serial.print(ip);
  Serial.println(F("/\" Link."));
}

void loop() {

  // Checking for an HTTP request
  WiFiClient client = server.available();
  if (client) {
    IPAddress ip = client.remoteIP();
    Serial.print(F("New client: "));
    Serial.println(ip);

    Serial.println(F("--> Request data"));
    while (client.connected()) {
      if (client.available()) {
        // Set variables values to 0
        memset(requestBody, 0, sizeof requestBody);
        bodyFinder = 0;

        while (client.available()) {
          char c = client.read();
          Serial.write(c);
          if (bodyFinder != 4) {
            if (c == '\r' || c == '\n') { // r or n
              bodyFinder ++;
            } else {
              bodyFinder = 0;
            }
          }
          if (bodyFinder == 4 && c != '\n') {
            strncat(requestBody, &c, 1);
          }
        }
        Serial.println();
        Serial.println(F("--> POST data received:"));
        Serial.println(requestBody);
        // We divide our POST data received with the strtok() function from the first & character and load it into our token variable
        char* token = strtok(requestBody, "&");
        // Checking whether the first 5 characters are equal to the pass = expression (Parameter) in the received POST request.
        if (strncmp(token, "pass=", 5) == 0) {
          // It is the password in the POST request received after the first 5 characters in the token variable (ie after pass =) This password is transferred to the PWD variable
          char* PWD = token + 5;
          // Checking the correctness of the password received with the pass parameter in the request.
          if (strcmp(PWD, password) == 0) {
            Serial.println(F("--> PASSWORD CORRECT"));

            while (token != NULL) {
              token = strtok(NULL, "&");
              // Röle
              if (strncmp(token, "rl=", 3) == 0) {
                rlrequest = true;
                if (getallrequest == false) {
                  Serial.print(F("--> rl REQUEST Relay number: "));
                  int rlNumber = atol(token + 3);
                  Serial.print(rlNumber);
                  Serial.print(F(" Command: "));
                  char* rlCommand = token + 4;
                  Serial.println(rlCommand);
                  onOff(rlNumber, rlCommand, true);
                  answer = "";
                  doc["status"] = F("OK");
                  doc["rl"] = (String)rlNumber;
                  doc["rlcommand"] = (String)rlCommand;
                  serializeJson(doc, answer);
                }
              }
              // getall
              if (strncmp(token, "getall", 6) == 0) {
                getallrequest == true;
                if (rlrequest == false) {
                  Serial.println(F("--> getall REQUEST"));
                  answer = "";
                  // DHT11 sensor data reading
                  // Temperature in Celsius
                  float t = dht.readTemperature();
                  char str_t[6];
                  dtostrf(t, 4, 2, str_t);
                  // Nem
                  float h = dht.readHumidity();
                  char str_h[6];
                  dtostrf(h, 4, 2, str_h);
                  // HC-SR501 PIR sensor data is read from address 7 of EEPROM:
                  EepromMotionState = EEPROM.read(7);
                  // FLAME sensor data read from address 8 of EEPROM:
                  EepromFlameState = EEPROM.read(8);
                  // GAS sensor data is read from EEPROM at address 9:
                  EepromGasState = EEPROM.read(9);
                  doc["status"] = F("OK");
                  doc["temperature"] = (String)t;
                  doc["humidity"] = (String)h;
                  doc["gas"] = EepromGasState;
                  doc["flame"] = EepromFlameState;
                  doc["motion"] = EepromMotionState;
                  // Relays location 1.2.3.4 of the EEPROM. Reading from addresses:
                  // Creating Json array named relays
                  JsonArray relays = doc.createNestedArray("relays");
                  for (count = 1; count <= 4; count++) {
                    rState = EEPROM.read(count);
                    relays.add(rState);
                  }
                  serializeJson(doc, answer);
                  // If the last recorded MQ-4 gas sensor data at the 9th address of the EEPROM is 1, that is, gas is detected, this data is now converted to 0 because it is transmitted to the client..
                  if (EepromGasState == 1) {
                    EEPROM.update(9, 0);
                  }
                  // If the last recorded PIR sensor data to the 7th address of EEPROM is 1, that is, motion is detected, this data is converted to 0 because it is transmitted to the client.
                  if (EepromMotionState == 1) {
                    EEPROM.update(7, 0);
                  }
                  // If the last recorded FLAME sensor data at the 8th address of EEPROM is 1, that is, flame is detected, this data is converted to 0 because it is transmitted to the client.
                  if (EepromFlameState == 1) {
                    EEPROM.update(8, 0);
                  }
                }
              }
            }
          } else {
            Serial.println(F("--> PASSWORD INCORRECT"));
            answer = "";
            doc["status"] = F("ERROR");
            doc["message"] = F("Password Incorrect");
            serializeJson(doc, answer);
          }
        } else {
          Serial.println(F("--> pass parameter not sent"));
          answer = "";
          doc["status"] = F("ERROR");
          doc["message"] = F("pass parameter not sent");
          serializeJson(doc, answer);
        }

        // When the end of the HTTP header is reached (a blank line),
        // It means that the HTTP request has reached the end, a response is sent to the request at this stage

        Serial.println(F("--> Forwarded reply"));
        Serial.println(answer);

        // http answer headers
        client.println(F("HTTP/1.1 200 OK"));
        client.println(F("Content-Type: application/json; charset=UTF-8"));
        client.println(F("Connection: close"));  // Client is notified that the connection will be closed after the completion of the response
        client.println();
        client.print(answer);
        client.flush();
        rlrequest = false;
        getallrequest == false;
        doc.clear();
        break;
      }
    }

    // close connection:
    client.stop();
    Serial.println(F("--> Client connection closed"));
  }

  // HC-SR501 PIR sensor data reading
  motionState = digitalRead(hcSr501);
  // Reading the last record at address 7 of the EEPROM
  EepromMotionState = EEPROM.read(7);
  // If the sensor has not detected a motion
  if (motionState == 0) {
    // If the last record at the 7th address of the EEPROM is 1, the data in the EEPROM is not converted to 0 because this data has not yet been received by the client.
    if (EepromMotionState != 1) {
      EEPROM.update(7, motionState);
    }
  } else {
    if (EepromMotionState != 1) {
      EEPROM.update(7, motionState);
    }
  }

  // FLAME sensor data reading
  flameState = analogRead(flameSensor);
  // Reading the last record at address 8 of the EEPROM
  EepromFlameState = EEPROM.read(8);
  // If the sensor did not detect a flame
  if (flameState > flamethreshold) {
    // If the last record in the 8th address of the EEPROM is 1, the data in the EEPROM is not converted to 0 because this data has not yet been received by the client.
    if (EepromFlameState != 1) {
      EEPROM.update(8, 0);
    }
  } else {
    if (EepromFlameState != 1) {
      EEPROM.update(8, 1);
    }
  }

  // MQ-4 Gas sensor data reading
  gasValue = analogRead(gasSensor);
  // Reading the last record at address 9 of the EEPROM
  EepromGasState = EEPROM.read(9);
  // If the value read from the sensor is equal to or higher than the limit value
  if (gasValue >= gasthreshold) {
    if (EepromGasState != 1) {
      EEPROM.update(9, 1);
    }
  } else { // If the reading is below the limit value
    // If the last record at the 9th address of the EEPROM is 1, the data in the EEPROM is not converted to 0 because this data has not yet been received by the client.
    if (EepromGasState != 1) {
      EEPROM.update(9, 0);
    }
  }
}

// This function sets the Baudrate of ESP8266
// Serial1 is set to 115200 if available, and 9600 with SoftwareSerial if not available.
void setEspBaudRate(unsigned long baudrate) {
  long rates[6] = {115200, 74880, 57600, 38400, 19200, 9600};

  Serial.print(F("Set ESP8266 baudrate to: "));
  Serial.print(baudrate);
  Serial.println(F("..."));

  for (int i = 0; i < 6; i++) {
    Serial1.begin(rates[i]);
    delay(100);
    Serial1.print(F("AT+UART_DEF="));
    Serial1.print(baudrate);
    Serial1.print(F(",8,1,0,0\r\n"));
    delay(100);
  }

  Serial1.begin(baudrate);
}

// Relay ON/OFF function
void onOff(int relayNumber, String position, boolean updateEeprom) {
  if (position == "ON") {
    digitalWrite(relays[relayNumber], LOW);
    if (updateEeprom == true) {
      EEPROM.update(relayNumber, 1);
    }
  }
  if (position == "OFF") {
    digitalWrite(relays[relayNumber], HIGH);
    if (updateEeprom == true) {
      EEPROM.update(relayNumber, 0);
    }
  }
}

Download Project

Include Circuit scheme, Arduino code.

Download