Wireless relay & sensor with one ESP32

The pieces

You can have a node with only one ESP32 for the sensor and the relay. This is the less expensive setup, because you need only one ESP32 board. The fritzing diagram for this node is the following:

 

An ESP32 with a DHT sensor and a relay

 

Esp32 relay and dht sensor
Esp32 relay and dht sensor

The Sketch.

After uploading the sketch with the Arduino IDE to the ESP32 board, you can trigger the relay or you can read the relay status and the temperature sensor values with a http request . For example, if the ip address given by the router to the board is the 192.168.2.15, then following http request are available.

  • http://192.168.2.15: returns a json object with the current status of the relay, and the temperature and humidity values.
  • http://192.168.2.15/H: sets the state of the relay to High and returns the same json object as before.
  • http://192.168.2.15/L: sets the state of the relay to Low and returns the same json object as before.

To know the Ip address of the ESP32 board, take a look with the serial console from the Arduino IDE after uploading the sketch to the board.

Important: this sketch uses  the alternative “DHTStable” library from Rob Tillaart, that works better than the default one. Please download the library and add it to your arduino ide before building this sketch.

/*
   Smart Pi Thermostat by Roque Campos
   Sketch to read temperatures with an ESP32 board and a DHTxx sensor, and to control a Relay connected to the Pin 21
   Complete Project Details https://www.smart-thermostat.eu
*/

#include 
#include 


// Uncomment one of the lines below for whatever DHT sensor type you're using!
#define DHTTYPE 11   // DHT 11
//#define DHTTYPE 22   // DHT 22  (AM2302), AM2321

// Replace with your network credentials
const char* ssid     = "SSID";
const char* password = "Password";
const String nodeName = "nodeName";


//Please don't touch anything below this point unless you know what you are doing.
const String sketchVersion = "2";
const String nodeType = "TH&Relay";
unsigned long lastReceivedRelayCommandMilis;
const unsigned int TIMEOUT_REICEIVED_COMMANDS_MILIS = 1000 * 60 * 2; //Two minutes
String relayError = "";
String thError = "";
WiFiServer server(80);

//The pin for the relay
const int relayPin = 21;

//Onboard led
const int ONBOARD_LED_PIN = 2;

// DHT Sensor
const int DHTPin = 18;


dht DHT;

// Client variables
char linebuf[80];
int charcount = 0;

void setup() {
  Serial.begin(115200);



  pinMode(ONBOARD_LED_PIN, OUTPUT);

  //Initialize serial and wait for port to open:
  pinMode(relayPin, OUTPUT);      // set the Relay pin mode

  // We start by connecting to a WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  setUpWifi();
  lastReceivedRelayCommandMilis = millis();
}

void setUpWifi() {
  //WiFi.config(ip,dns,gateway,subnet);

  // attempt to connect to Wifi network:
  int counter = 0;
  while (WiFi.status() != WL_CONNECTED) {
    WiFi.disconnect();
    WiFi.begin(ssid, password);
    int counter = 0;
    while (WiFi.status() != WL_CONNECTED) {
      delay(1000);
      Serial.print(".");
      counter++;
      if (counter > 10) {
        break;
      }
    }
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.print("MAC: ");
  Serial.println(WiFi.macAddress());

  server.begin();
}

double celsius2Fahrenheit(double celsius)
{
  return celsius * 9 / 5 + 32;
}

void turnRelayOffIfTimeout() {
  unsigned long now = millis();
  long elapsed = now - lastReceivedRelayCommandMilis;
  if (elapsed > TIMEOUT_REICEIVED_COMMANDS_MILIS) {
    digitalWrite(relayPin, LOW);
    relayError = "Thermostat command timeout...";
  }
}

void loop() {

 
   turnRelayOffIfTimeout();
  if (WiFi.status() != WL_CONNECTED) {
    setUpWifi();
  }
  // listen for incoming clients


  WiFiClient client = server.available();
  if (client) {
    digitalWrite(ONBOARD_LED_PIN, HIGH);
    Serial.println("New client");
    memset(linebuf, 0, sizeof(linebuf));
    charcount = 0;
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    String currentLine = "";
    while (client.connected()) {

      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        //read char by char HTTP request

        linebuf[charcount] = c;

        if (charcount < sizeof(linebuf) - 1) charcount++;
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply

        if (c == '\n' && currentLineIsBlank) {



          int chk = DHTLIB_OK;
          double humidity = -10000;
          double celsiusTemp = -10000;
          double fahrenheitTemp = -10000;

          if (DHTTYPE == 22) {
            chk = DHT.read22(DHTPin);
          } else {
            chk = DHT.read11(DHTPin);
          }

          if (chk == DHTLIB_OK) {
            thError = "";
            Serial.print("DHT OK,\t");
            celsiusTemp = DHT.temperature;
            fahrenheitTemp = celsius2Fahrenheit(celsiusTemp);
            humidity = DHT.humidity;


          } else {
            switch (chk)
            {
              case DHTLIB_ERROR_CHECKSUM:
                thError = "Checksum error";
                break;
              case DHTLIB_ERROR_TIMEOUT:
                thError = "Timeout error";
                break;

              default:
                thError = "Unknown error";
                break;
            }
            Serial.print(thError);
          }

          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: application/json");
          client.println();
          client.println("{");
          client.println();
          client.println("\"nodeType\":\"" + nodeType + "\",");
          client.println("\"name\":\"" + nodeName + "\",");
          client.println("\"version\":\"" + sketchVersion + "\",");
          client.println("\"relayError\":\"" + relayError + "\",");
          client.println("\"thError\":\"" + thError + "\",");
          client.println("\"mac\":\"" + WiFi.macAddress() + "\",");

          int currentStatus = digitalRead(relayPin);

          String statusAsString = (currentStatus == 1) ? "true" : "false";
          client.print("\"status\":\"" + statusAsString);
          client.println("\",");


          String cc = String(celsiusTemp);
          cc.trim();
          client.print("\"celsius\":\"" + cc);
          client.println("\",");



          String ff = String(fahrenheitTemp);
          ff.trim();
          client.print("\"fahrenheit\":\"" + ff);
          client.println("\",");

          String hh = String(humidity);
          hh.trim();
          client.print("\"humidity\":\"" + hh);
          client.println("\"");

          client.println();
          client.println("}");
          client.println();

          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
          currentLine = "";
          memset(linebuf, 0, sizeof(linebuf));
          charcount = 0;
        } else if (c != '\r') {

          // you've gotten a character on the current line
          currentLineIsBlank = false;
          currentLine += c;      // add it to the end of the currentLine

        }

        // Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /H")) {
          lastReceivedRelayCommandMilis = millis();
          digitalWrite(relayPin, HIGH);
          relayError = "";
        }
        if (currentLine.endsWith("GET /L")) {
          lastReceivedRelayCommandMilis = millis();
          digitalWrite(relayPin, LOW);
          relayError = "";
        }




      }
    }
    // give the web browser time to receive the data
    delay(250);

    // close the connection:
    client.stop();
    Serial.println("client disconnected");
    digitalWrite(ONBOARD_LED_PIN, LOW);
  }






}