fbpixel
Control 8 relays using ESP32 and a web interface

Control 8 relays using ESP32 and a web interface

In this tutorial, we will create a web interface to control 8 relays individually. This tutorial is a continuation of the project Pilot 8 relays using an ESP32 and the serial monitor.

This tutorial can be applied to any microcontroller with a Wifi or Ethernet connection. You will have to be careful to modify the connection scheme and code to suit your use.

Material

  • NodeMCU 32S
  • Breadboard
  • Jumper cable
  • 8 relay module
  • Shift register 74hc595

Principle

In the previous tutorial, we saw how to drive 8 relays independently using the Arduino IDE serial monitor. When an internet connection is available, as on the ESP32 NodeMCU, it is possible to turn your microcontroller into a server and host a web page. This web page can be used as a graphical interface to drive your project. We will create a web page, accessible via the local network, with buttons to activate the relays.

Code

We will take the code from the previous tutorial and combine it with the code to create a Web Interface for the ESP32 NodeMCU. On the web page we will create a table with 16 buttons corresponding to the “Activate” and “Reset” actions of the 8 relays. In order to visualize some of the actions, we add an insert to display messages from the microcontroller.

void webpage(WiFiClient client) { //Send webpage to browser
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.println("<head>");
  client.println("<title> AranaCorp </title>");
  client.println("<meta name='apple-mobile-web-app-capable' content='yes' />");
  client.println("<meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />");
  client.println("<meta charset='UTF-8'>");
  client.println("");
  client.println("");
  client.println("");
  client.println("</head>");
  client.println("<body> ");
  client.println("<div id='page'>");
  client.println("<div id='content'>");
  client.println("<hr/><hr>");
  client.println("<h1><center> AranaCorp - Relay Controller Web Interface </center></h1>");
  client.println("<hr/><hr>");
  client.println("<br><br><div id='m' class='box'><center><table>");
  client.println("<tr><td>Console </td><td><input id='senM1' class='sensor'  value='" + String(console) + "' readonly></input></td></tr> </table>");

  client.println("  <table><tr><td>Relay 0</td>");
  client.println("   <td><a href='/light0on' class='button activate'> Activate </a>");
  client.println("  <a href='/light0off' class='button reset'> </a></td><td>Relay 1</td>");
  client.println("   <td><a href='/light1on' class='button activate'> Activate </a>");
  client.println("  <a href='/light1off' class='button reset'> Reset </a></td><td>Relay 2</td>");
  client.println("   <td><a href='/light2on' class='button activate'> Activate </a>");
  client.println("  <a href='/light2off' class='button reset'> Reset </a></td><td>Relay 3</td>");
  client.println("   <td><a href='/light3on' class='button activate'> Activate </a>");
  client.println("  <a href='/light3off' class='button reset'> Reset </a></td></tr><tr><td>Relay 4</td>");
  client.println("   <td><a href='/light4on' class='button activate'> Activate </a>");
  client.println("  <a href='/light4off' class='button reset'> Reset </a></td><td>Relay 5</td>");
  client.println("   <td><a href='/light5on' class='button activate'> Activate </a>");
  client.println("  <a href='/light5off' class='button reset'> Reset </a></td><td>Relay 6</td>");
  client.println("   <td><a href='/light6on' class='button activate'> Activate </a>");
  client.println("  <a href='/light6off' class='button reset'> Reset </a></td><td>Relay 7</td>");
  client.println("   <td><a href='/light7on' class='button activate'> Activate </a>");
  client.println("  <a href='/light7off' class='button reset'> Reset </a></td></tr>");
  client.println("</table></center></div>");

  client.println("</div><footer><div><p style='text-align:left;float:left;padding:0px;margin:0px;'>&copy; Copyright 2020 AranaCorp. All rights reserved</p><p style='float:right;padding:0px;margin:0px;'><a style='color:#3aaa35;' href='https://www.aranacorp.com/fr/evidence'>www.aranacorp.com</a><p></div></footer></div></body></html>");
  delay(1);
  client.stop();
}

Once the web page is up and running, all we have to do is handle the browser requests in the loop() function.

void loop() {
  WiFiClient client = server.available();
  if (client) {
    if (client.connected()) {
      String request = "";
      if (client.available()) {
        request = client.readStringUntil('\r');
        if (request != "") {
          client.print( header );
          handleRequest(request);
          webpage(client);//Return webpage
        }
      }
    }
  }
}

void handleRequest(String request) { /* function handleRequest */
  ////Handle web client request
  String pwmCmd;
  //Digital Ouputs
  for (int i = 0; i < 16; i++) {
    if (request.indexOf("/light" + String(i) + "on") > 0) {
      Serial.print("Relay n° "); Serial.print(i); +Serial.println(" ON ");
      setRegisterPin(i, 0);
      writeRegisters();
      console = String("Relay n°" + String(i) + " ON");
    }
    if (request.indexOf("/light" + String(i) + "off") > 0) {
      Serial.print("Relay n° "); Serial.print(i); +Serial.println(" OFF ");
      setRegisterPin(i, 1);
      writeRegisters();
      console = String("Relay n°" + String(i) + " OFF");
    }
  }
}

You will find below, the complete code integrating the management of the web page as well as the shift register seen in the previous articles. Don’t forget to update the ssid and password variables with the values of your network.

//Libraries
#include <WiFi.h>//https://www.arduino.cc/en/Reference/WiFi

//Constants
#define number_of_74hc595s 2
#define numOfRegisterPins number_of_74hc595s * 8
#define SER_Pin 25
#define RCLK_Pin 33
#define SRCLK_Pin 32

//Variables
boolean registers[numOfRegisterPins];

char* ssid  = "*****";
char* password  = "*****";


String nom  = "ESP32";
//Objects
WiFiServer server(80);
WiFiClient client;

String header = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
String console = "System initialized";

void setup() {
  //Init Serial USB
  Serial.begin(115200);
  Serial.println(F("Initialize System"));
  //Init ESP32Wifi
  Serial.print("Connecting to "); Serial.println(ssid);
  WiFi.begin(ssid, password);
  // Connect to Wifi network.
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500); Serial.print(F("."));
  }
  server.begin();
  Serial.println();
  Serial.println(F("ESP32Wifi initialized"));
  Serial.print(F("IP Address: "));
  Serial.println(WiFi.localIP());

  //Init register
  pinMode(SER_Pin, OUTPUT);
  pinMode(RCLK_Pin, OUTPUT);
  pinMode(SRCLK_Pin, OUTPUT);
  clearRegisters();
  writeRegisters();
  delay(500);
}

void loop() {
  WiFiClient client = server.available();
  if (client) {
    if (client.connected()) {
      String request = "";
      if (client.available()) {
        request = client.readStringUntil('\r');
        if (request != "") {
          client.print( header );
          handleRequest(request);
          webpage(client);//Return webpage
        }
      }
    }
  }
}


void handleRequest(String request) { /* function handleRequest */
  ////Handle web client request
  String pwmCmd;
  //Digital Ouputs
  for (int i = 0; i < 16; i++) {
    if (request.indexOf("/light" + String(i) + "on") > 0) {
      Serial.print("Relay n° "); Serial.print(i); +Serial.println(" ON ");
      setRegisterPin(i, 0);
      writeRegisters();
      console = String("Relay n°" + String(i) + " ON");
    }
    if (request.indexOf("/light" + String(i) + "off") > 0) {
      Serial.print("Relay n° "); Serial.print(i); +Serial.println(" OFF ");
      setRegisterPin(i, 1);
      writeRegisters();
      console = String("Relay n°" + String(i) + " OFF");
    }
  }
}




void webpage(WiFiClient client) { //Send webpage to browser
  /* client.println("HTTP/1.1 200 OK");
    client.println("Content-Type: text/html");
    client.println("");*/
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.println("<head>");
  client.println("<title> AranaCorp </title>");
  client.println("<meta name='apple-mobile-web-app-capable' content='yes' />");
  client.println("<meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />");
  client.println("<meta charset='UTF-8'>");
  //client.println("<meta http-equiv='refresh' content='1'>");
  client.println("");
  client.println("<style>");
  client.println("");
  client.println("   body {");
  client.println("   font-size:100%;");
  client.println("   color:white;");
  client.println("   background-color: #111111;");
  client.println("   margin:0px;");
  client.println("   } ");
  client.println("  ");
  client.println("  #page {");
  client.println("width:100%;");
  client.println("  position: relative;");
  client.println("  min-height: 99vh;");
  client.println("}");
  client.println("");
  client.println("#content {");
  client.println("  padding-bottom: 2.5rem;    /* Footer height */");
  client.println("}");
  client.println("");
  client.println("footer {");
  client.println("  background-color:black;");
  client.println("  position: absolute;");
  client.println("  bottom: 0;");
  client.println("  width: 100%;");
  client.println("  height: 2.5rem;            /* Footer height */");
  client.println("}");
  client.println("   ");
  client.println("   h1 {color: #3AAA35;}");
  client.println("   p { text-align:center; }");
  client.println("");
  client.println("   table {");
  client.println("   width=80%;");
  client.println("margin: 40px 40px 40px 40px;");
  client.println("   }");
  client.println("   tr{");
  client.println("border: 1px solid black;");
  client.println("padding: 20px 20px 20px 20px;");
  client.println("   }");
  client.println("   td{");
  client.println("padding: 10px 10px 10px 10px;");
  client.println("   }");
  client.println("   .wrapper {");
  client.println("display: grid;");
  client.println("/*grid-template-columns: 1fr 1fr 1fr;*/");
  client.println("");
  client.println("margin: 60px 20px 60px 20px;");
  client.println("}");
  client.println(".box {");
  client.println("  border-radius: 10px;");
  client.println("  border: 2px solid white;");
  client.println("  font-size: 150%;");
  client.println("  /*height: 120px;*/");
  client.println("  margin: 5px 5px 5px 5px;");
  client.println("}");
  client.println("");
  client.println(".button {");
  client.println("  background-color: #111111; /* Green */");
  client.println("  border: none;");
  client.println("  color: white;");
  client.println("  padding: 16px 32px;");
  client.println("  text-align: center;");
  client.println("  text-decoration: none;");
  client.println("  display: inline-block;");
  client.println("  font-size: 16px;");
  client.println("  margin: 4px 2px;");
  client.println("  transition-duration: 0.4s;");
  client.println("  cursor: pointer;");
  client.println("  border-radius: 12px;");
  client.println("}");
  client.println("");
  client.println(".activate {");
  client.println("  color: white; ");
  client.println("  border: 2px solid #3AAA35;");
  client.println("}");
  client.println("");
  client.println(".activate:hover {");
  client.println("  background-color: #3AAA35;");
  client.println("  color: white;");
  client.println("}");
  client.println("");
  client.println(".reset { ");
  client.println("  color: white; ");
  client.println("  border: 2px solid #f44336;");
  client.println("}");
  client.println("");
  client.println(".reset:hover {");
  client.println("  background-color: #f44336;");
  client.println("  color: white;");
  client.println("}");
  client.println("");
  client.println("    .sensor {");
  client.println("  background-color: #ffffff;");
  client.println("  border: none;");
  client.println("  color: black;");
  client.println("  padding: 16px 32px;");
  client.println("  text-align: center;");
  client.println("  text-decoration: none;");
  client.println("  display: inline-block;");
  client.println("  font-size: 16px;");
  client.println("  margin: 4px 2px;");
  client.println("  transition-duration: 0.4s;");
  client.println("  cursor: pointer;");
  client.println("  border-radius: 2px;");
  client.println("}");
  client.println("");
  client.println(".status {");
  client.println("  color: white; ");
  client.println("  border: 5px solid #3AAA35;");
  client.println("  border-radius: 12px;");
  client.println("}");
  client.println("");
  client.println("");
  client.println("@media (min-width: 1050px){ /*screen and*/");
  client.println("  .wrapper {");
  client.println("grid-template-columns: repeat(2, 1fr);");
  client.println("  }");
  client.println("  ");
  client.println("@media (min-width: 1500px){");
  client.println("  .wrapper {");
  client.println("grid-template-columns: repeat(3, 1fr);");
  client.println("  }");
  client.println("}");
  client.println("");
  client.println(" </style>");
  client.println("");
  client.println("");
  client.println("</head>");
  client.println("<body> ");
  client.println("<div id='page'>");
  client.println("<div id='content'>");
  client.println("<hr/><hr>");
  client.println("<h1><center> AranaCorp - Relay Controller Web Interface </center></h1>");
  client.println("<hr/><hr>");
  client.println("<br><br><div id='m' class='box'><center><table>");
  client.println("<tr><td>Console </td><td><input id='senM1' class='sensor'  value='" + String(console) + "' readonly></input></td></tr> </table>");

  client.println("  <table><tr><td>Relay 0</td>");
  client.println("   <td><a href='/light0on' class='button activate'> Activate </a>");
  client.println("  <a href='/light0off' class='button reset'> Reset </a></td><td>Relay 1</td>");
  client.println("   <td><a href='/light1on' class='button activate'> Activate </a>");
  client.println("  <a href='/light1off' class='button reset'> Reset </a></td><td>Relay 2</td>");
  client.println("   <td><a href='/light2on' class='button activate'> Activate </a>");
  client.println("  <a href='/light2off' class='button reset'> Reset </a></td><td>Relay 3</td>");
  client.println("   <td><a href='/light3on' class='button activate'> Activate </a>");
  client.println("  <a href='/light3off' class='button reset'> Reset </a></td></tr><tr><td>Relay 4</td>");
  client.println("   <td><a href='/light4on' class='button activate'> Activate </a>");
  client.println("  <a href='/light4off' class='button reset'> Reset </a></td><td>Relay 5</td>");
  client.println("   <td><a href='/light5on' class='button activate'> Activate </a>");
  client.println("  <a href='/light5off' class='button reset'> Reset </a></td><td>Relay 6</td>");
  client.println("   <td><a href='/light6on' class='button activate'> Activate </a>");
  client.println("  <a href='/light6off' class='button reset'> Reset </a></td><td>Relay 7</td>");
  client.println("   <td><a href='/light7on' class='button activate'> Activate </a>");
  client.println("  <a href='/light7off' class='button reset'> Reset </a></td></tr>");
  client.println("</table></center></div>");

  client.println("</div><footer><div><p style='text-align:left;float:left;padding:0px;margin:0px;'>&copy; Copyright 2020 AranaCorp. All rights reserved</p><p style='float:right;padding:0px;margin:0px;'><a style='color:#3aaa35;' href='https://www.aranacorp.com/fr/evidence'>www.aranacorp.com</a><p></div></footer></div></body></html>");
  delay(1);
  client.stop();
}

//SR
void clearRegisters() { /* function clearRegisters */
  //// Clear registers variables
  for (int i = numOfRegisterPins - 1; i >=  0; i--) {
    registers[i] = HIGH;
  }
}

void writeRegisters() { /* function writeRegisters */
  //// Write register after being set
  digitalWrite(RCLK_Pin, LOW);
  for (int i = numOfRegisterPins - 1; i >=  0; i--) {
    digitalWrite(SRCLK_Pin, LOW);
    digitalWrite(SER_Pin, registers[i]);
    digitalWrite(SRCLK_Pin, HIGH);
  }
  digitalWrite(RCLK_Pin, HIGH);
}

void setRegisterPin(int index, int value) { /* function setRegisterPin */
  ////Set register variable to HIGH or LOW
  registers[index] = value;
}

void printRegisters() { /* function clearRegisters */
  //// Clear registers variables
  for (int i = 0; i < numOfRegisterPins; i++) {
    Serial.print(registers[i]); Serial.print(F(" ,"));
  }
  Serial.println();
}

Result

Once the code has been loaded into the microcontroller, enter the IP address displayed in the serial monitor (here 192.168.1.64) into your web browser. The following page should be displayed.

You can then close the relays with the “Activate” buttons and open them with the corresponding “Reset” buttons.

Don’t hesitate to leave us a comment to give us your opinion, feedback and ideas for improvement for this tutorial.

Sources

Control 8 relays using ESP32 and serial monitor

Control 8 relays using ESP32 and serial monitor

In this tutorial we will see how to address each relay individually with a NodeMCU32S microcontroller and 74HC595 shift registers. At the end of this tutorial you will also be able to control each relay using the serial monitor. This tutorial follows on from the project Pilot 8 relays using an ESP32 and a shift register.

Ce tutoriel peut être appliqué à n’importe quel microcontrôleur. Il faudra faire attention à modifier le schéma de connexion et le code pour qu’ils correspondent à votre usage.

Material

  • NodeMCU 32S
  • Breadboard
  • Jumper cable
  • 8 relay module
  • Shift register 74hc595

Principle

In the previous tutorial, we saw how to manage 8 relays using a shift register. We will now come to address each relay independently using the Arduino IDE’s serial monitor. It is possible to communicate with the microcontroller via the USB port using the serial port. We will therefore define a message structure to tell the microcontroller which relay to switch on.

Schematic

As a reminder, here is the connection diagram of the project

  • GND integrated circuit ground
  • Vcc power supply pin. Usually connected to 5V
  • SH_CP or RCLK connected to pin 33
  • ST_CP or SRCLK connected to pin 32
  • DS or SER connected to pin 25
NodeMCU32S ESP32, shift register 74HC595 and 8 relays module schematics

Code

We are going to take the code from the previous tutorial and add the functions to receive messages from the serial monitor and recover the relay control commands. For the command messages, we choose the form “YYxZ”, with YY, the relay identifier, a number from 0 to 7; and Z, the relay status 0-open, 1-close.

The readSerialPort function, retrieves the characters sent by the serial monitor in the character string “msg”.

the convertMsgToCmd function will translate the string into a relayId identification number and the status of the relayState.

void readSerialPort() {
  while (Serial.available()) {
    delay(10);
    if (Serial.available() > 0) {
      char c = Serial.read();  //gets one byte from serial buffer
      msg += c;
    }
  }
}

void convertMsgToCmd() {
  relayId = -1;
  relayState = -1;
  if (msg.length() > 0) {
    Serial.println(msg);
    sep = msg.indexOf('x');
    if (sep > 0) {
      m1 = msg.substring(0, sep); //get servo id
      m2 = msg.substring(sep + 1, msg.length()); //get servo pos

      char carray1[6]; //magic needed to convert string to a number
      m1.toCharArray(carray1, sizeof(carray1));
      relayId = atoi(carray1);

      char carray2[6];
      m2.toCharArray(carray2, sizeof(carray2));
      relayState = atoi(carray2);

      relayState = 1 - relayState;
      Serial.print(F("Set relay n° ")); Serial.print(relayId); Serial.print(F(" to ")); Serial.println(!relayState ? "HIGH" : "LOW");
    }

    sep = msg.indexOf("reset");
    if (sep == 0) {
      m1 = "reset";
    }

    sep = msg.indexOf("states");
    if (sep == 0) {
      m1 = "states";
    }
    msg = "";
  }
}

Once the values relayId and relayState have been retrieved, they can be set as the input for the setRegisterPin function (relayId, relayState); in order to activate or deactivate the relay. It is possible to create as many messages as you wish. Here, for example, I have added the “reset” command to open all the relays and the “states” command to display the states of each relay.

//Constants
#define number_of_74hc595s 1
#define numOfRegisterPins number_of_74hc595s * 8
#define SER_Pin 25
#define RCLK_Pin 33
#define SRCLK_Pin 32

//Variables
boolean registers[numOfRegisterPins];
String msg, m1, m2;
int sep, relayId, relayState;

void setup() {
  delay(100);
  //Init Serial USB
  Serial.begin(115200);
  Serial.println(F("Initialize System"));
  //Init register
  pinMode(SER_Pin, OUTPUT);
  pinMode(RCLK_Pin, OUTPUT);
  pinMode(SRCLK_Pin, OUTPUT);
  clearRegisters();
  writeRegisters();
  delay(500);
  Serial.println(F("Enter Relay ID ans state (IDxSTATE):"));
}

void loop() {
  readSerialPort();
  convertMsgToCmd();
  if (relayId >= 0 and relayState >= 0) {
    setRegisterPin(relayId, relayState);
    writeRegisters();
  }
  if (m1 == "reset") {
    Serial.println(F("Reset all relays"));
    clearRegisters();
    writeRegisters();
  }
  if (m1 == "states") {
    Serial.println(F("print relays states"));
    printRegisters();
  }
  m1 = "";
}

void clearRegisters() { /* function clearRegisters */
  //// Clear registers variables
  for (int i = numOfRegisterPins - 1; i >=  0; i--) {
    registers[i] = HIGH;
  }
  printRegisters();
}

void writeRegisters() { /* function writeRegisters */
  //// Write register after being set
  digitalWrite(RCLK_Pin, LOW);
  for (int i = numOfRegisterPins - 1; i >=  0; i--) {
    digitalWrite(SRCLK_Pin, LOW);
    digitalWrite(SER_Pin, registers[i]);
    digitalWrite(SRCLK_Pin, HIGH);
  }
  digitalWrite(RCLK_Pin, HIGH);
}

void setRegisterPin(int index, int value) { /* function setRegisterPin */
  ////Set register variable to HIGH or LOW
  registers[index] = value;
}

void printRegisters() { /* function clearRegisters */
  //// Clear registers variables
  for (int i = 0; i < numOfRegisterPins; i++) {
    Serial.print(registers[i]); Serial.print(F(" ,"));
  }
  Serial.println();
}

void readSerialPort() {
  while (Serial.available()) {
    delay(10);
    if (Serial.available() > 0) {
      char c = Serial.read();  //gets one byte from serial buffer
      msg += c;
    }
  }
}

void convertMsgToCmd() {
  relayId = -1;
  relayState = -1;
  if (msg.length() > 0) {
    Serial.println(msg);
    sep = msg.indexOf('x');
    if (sep > 0) {
      m1 = msg.substring(0, sep); //get servo id
      m2 = msg.substring(sep + 1, msg.length()); //get servo pos

      char carray1[6]; //magic needed to convert string to a number
      m1.toCharArray(carray1, sizeof(carray1));
      relayId = atoi(carray1);

      char carray2[6];
      m2.toCharArray(carray2, sizeof(carray2));
      relayState = atoi(carray2);

      relayState = 1 - relayState;
      Serial.print(F("Set relay n° ")); Serial.print(relayId); Serial.print(F(" to ")); Serial.println(!relayState ? "HIGH" : "LOW");
    }

    sep = msg.indexOf("reset");
    if (sep == 0) {
      m1 = "reset";
    }

    sep = msg.indexOf("states");
    if (sep == 0) {
      m1 = "states";
    }
    msg = "";
  }
}

Result

Once the code has been loaded into the microcontroller, open the serial monitor. You can enter the relay ID (0 – 7) and the desired state (0-open, 1-closed). For example, to close relay 2, type 2×1 and then “enter” or “send”.

Next Steps

Sources

Controlling 8 relays with ESP32 and shift register

Controlling 8 relays with ESP32 and shift register

In this series of tutorials, we will see how to drive a multitude of relays with a NodeMCU32S microcontroller and 74HC595 shift registers. We will then see how to address each relay individually. Finally, we will create a web interface to control each relay via the internet. This project is a good basis to develop a home automation system for your home.

This tutorial can be applied to any microcontroller. You will need to be careful to modify the connection diagram and code to suit your use.

Material

  • NodeMCU 32S
  • Breadboard
  • Jumper cable
  • 8 relay module
  • Shift register 74hc595

Principle

To control the 8 relay module, 8 digital outputs of the microcontroller must be reserved. In order to save the number of inputs/outputs of the microcontroller, different integrated circuits can be used. In particular, the shift register. The shift register 74HC595 has 8 programmable outputs, which can be set to 0 or 5V and only requires 3 digital inputs. This solution is therefore ideal to allow us to control the relays and keep the microcontroller outputs for other functions.

Schematic

To control the shift register, the NodeMCU is connected as follows:

  • GND integrated circuit ground
  • Vcc power supply pin. Usually connected to 5V
  • SH_CP or RCLK connected to pin 33
  • ST_CP or SRCLK connected to pin 32
  • DS or SER connected to pin 25

The outputs of the integrated circuit 74HC595 (Q0-Q7) are directly connected to the inputs of the 8 relay module. In this tutorial we do not use the Enable (OE) and Reset (MR) pins.

  • OE Output enable, activates LOW. Pin connected to GND to activate the outputs.
  • MR Master reset, active LOW. Reset pin. Connected to 5V

Attention: The outputs of a microcontroller are current limited. To drive so many relays, it is strongly recommended to use an external voltage source.

NodeMCU32S ESP32, shift register 74HC595 and 8 relays module schematics

Code

In the following code, we will first define the basic functions to manage the shift register. Then we will operate the relays one by one using a for loop.

//Constants
#define number_of_74hc595s 1
#define numOfRegisterPins number_of_74hc595s * 8
#define SER_Pin 25
#define RCLK_Pin 33
#define SRCLK_Pin 32

//Variables
boolean registers [numOfRegisterPins];

void setup(){
//Init Serial USB
Serial.begin(115200);
Serial.println(F("Initialize System"));
//Init register
pinMode(SER_Pin, OUTPUT);
pinMode(RCLK_Pin, OUTPUT);
pinMode(SRCLK_Pin, OUTPUT);
clearRegisters();
writeRegisters();
delay(500);
}

void loop(){
writeGrpRelay();
}

void clearRegisters(){/* function clearRegisters */ 
//// Clear registers variables 
for(int i = numOfRegisterPins-1; i >=  0; i--){
  registers[i] = HIGH;//LOW;
}}

void writeRegisters(){/* function writeRegisters */ 
//// Write register after being set 
digitalWrite(RCLK_Pin, LOW);
 for(int i = numOfRegisterPins-1; i >=  0; i--){
  digitalWrite(SRCLK_Pin, LOW); int val = registers[i];
  digitalWrite(SER_Pin, val);
  digitalWrite(SRCLK_Pin, HIGH);
}
  digitalWrite(RCLK_Pin, HIGH);
}

void setRegisterPin(int index,int value){/* function setRegisterPin */ 
////Set register variable to HIGH or LOW
registers[index] = value;
}

void writeGrpRelay(){/* function writeGrpRelay */ 
for(int i = numOfRegisterPins-1; i >=  0; i--){
   Serial.print(F("Relay "));Serial.print(i);Serial.println(F(" HIGH"));
   setRegisterPin(i, LOW);
   writeRegisters();
   delay(200); 
   Serial.print(F("Relay "));Serial.print(i);Serial.println(F(" LOW"));
   setRegisterPin(i, HIGH);
   writeRegisters();
  delay(500); 
      
}
}

Results

Once the components have been correctly connected and the code loaded into the microcontroller, the relays should activate one after the other.

Bonus: Control 16 relays with two shift registers.

Schematic

NodeMCU32S ESP32, shift registers 74HC595 and 16 relays module schematics

Code

The beauty of this code is that to make it work with a second shift register you only need to change the parameter:

#define number_of_74hc595s 2

Results

Next Steps

Sources

Power measurement with Arduino and INA219

Power measurement with Arduino and INA219

The INA219 Sensor is a current and voltage sensor for easy measurement of power. In some applications, it is interesting to measure the electrical power exchanged between devices. For example, measuring the power recovered by a solar panel. We will see in this tutorial how to measure the power values ​​with the INA219 sensor.

Prerequisite: Give senses to your robot

Equipment

  • Computer
  • Arduino board
  • USB cable
  • 1x INA219 sensor

Diagram

The INA219 sensor is a current and voltage sensor communicating via I2C. It is enough to supply it with the 5V output of the Arduino and to connect the SDA and SLC terminals of the I2C communication.

Schéma de connexion entre Arduino, INA219, moteur et source d'énergie

Code

To display the INA219 measurements, we will use the Adafruit library Adafruit_INA219.h which you can download or install directly from the Arduino IDE.

The electrical power exchanged by two devices is calculated by multiplying the voltage and the current on the bus connecting them:

P = UxI with P the power (W), U the voltage (V) and I the current (A).

Energy is the power consumed by the device over time

E = Pxt with E energy (Wh), P power (W) and t time (h)

Functions to know:

  • begin () to initialize communication with the sensor
  • getBusVoltage_V () to retrieve the voltage value on the Vin- / Vin + bus
  • shuntVoltage_mV () to recover the voltage across the shunt resistor
  • getCurrent_mA () to retrieve the current value from the shunt resistor
#include <Wire.h>
#include <Adafruit_INA219.h>

Adafruit_INA219 ina219;

  float voltage_V = 0,shuntVoltage_mV,busVoltage_V;
  float current_mA = 0;
  float power_mW = 0;
  float energy_Wh=0;
  long time_s=0;

void setup(void) 
{
  Serial.begin(9600);
  uint32_t currentFrequency;
  ina219.begin();
  Serial.println("Measuring voltage and current with INA219");
}

void loop(void) 
{
  getData();
  delay(2000);
}

void getData(){
  
 time_s=millis()/(1000); // convert time to sec
 busVoltage_V = ina219.getBusVoltage_V();
 shuntVoltage_mV = ina219.getShuntVoltage_mV();
 voltage_V = busVoltage_V + (shuntVoltage_mV / 1000);
 current_mA = ina219.getCurrent_mA();
 //power_mW = ina219.getPower_mW(); 
 power_mW=current_mA*voltage_V; 
 energy_Wh=(power_mW*time_s)/3600;   //energy in watt hour
   
  
  Serial.print("Bus Voltage:   "); Serial.print(busVoltage_V); Serial.println(" V");
  Serial.print("Shunt Voltage: "); Serial.print(shuntVoltage_mV); Serial.println(" mV");
  Serial.print("Load Voltage:  "); Serial.print(voltage_V); Serial.println(" V");
  Serial.print("Current:       "); Serial.print(current_mA); Serial.println(" mA");
  Serial.print("Power:         "); Serial.print(power_mW); Serial.println(" mW");  
  Serial.print("Energy:        "); Serial.print(energy_Wh); Serial.println(" mWh");
  Serial.println("----------------------------------------------------------------------------");
}


Application

One possible application with an INA219 sensor is to create an energy meter to measure the electrical power absorbed by a solar panel, for example. This allows you to check the correct functioning of the photovoltaic cells, on the one hand, and to measure its performance over time.

Schéma de connexion entre batterie LiPo Arduino, capteur INA219 et panneau solaire

Sources

Find other examples and tutorials in our Automatic code generator
Code Architect

Control your project using an IR remote

Control your project using an IR remote

There are different ways to communicate with a system. One of the most used, especially with television, is the infrared remote control. We will see how to drive an Arduino using a receiver and an IR remote control.

In this tutorial, we use an IR remote control commonly sold in Arduino kits

Prerequisite: Give senses to your robot

Equipment

  • Computer
  • Arduino board
  • USB cable or serial / USB adapter to connect the Arduino board to the PC
  • 1x IR remote control
  • 1x IR receiver
  • 3x Dupont cables

Principle of operation

An infrared remote control, as the name suggests, uses light to send commands between the transmitter and the receiver. The transmitter consisting of a diode emits infrared rays which travel in the air. These signals are then received by a photodiode, which is capable of transforming the light signal it receives into an electrical signal.

Communication by infrared is limited in distance to a few meters and must be direct, i.e. no object must be in the path of the light signal. It can also be disturbed by neon lights or the sun’s rays.

Diagram

The IR receiver is a sensor capable of receiving infrared waves. To read the sensor, it must be supplied with the 5V output from the Arduino and read the signal obtained using a digital input. Here, pin 9.

Code

To decode, the information coming from the remote control we will use the IRremote.h library. It will allow us to detect which button is pressed. Each button corresponds to a hexadecimal code which must be identified for each IR remote control. The following code displays the hexadecimal value when a button is pressed, allowing you to configure your code according to the remote control.

//Library
#include "IRremote.h"

//Variable
int receiverPin = 9;
IRrecv irrecv(receiverPin);     
decode_results results;      

void setup(){
  Serial.begin(9600);
  Serial.println(F("IR Receiver Decoder")); 
  irrecv.enableIRIn(); // Start the receiver
}

void loop() {
  if (irrecv.decode(&results)){ // IR signal received?
    convertIR(); 
    irrecv.resume(); // receive the next value
  }  
}


void convertIR() // convert IR code
{
 Serial.print(results.value);
 Serial.print(F(" -> "));
  switch(results.value)
  {
  case 0xFFA25D: Serial.println(F("POWER")); break;
  case 0xFFE21D: Serial.println(F("FUNC/STOP")); break;
  case 0xFF629D: Serial.println(F("VOL+")); break;
  case 0xFF22DD: Serial.println(F("FAST BACK"));    break;
  case 0xFF02FD: Serial.println(F("PAUSE"));    break;
  case 0xFFC23D: Serial.println(F("FAST FORWARD"));   break;
  case 0xFFE01F: Serial.println(F("DOWN"));    break;
  case 0xFFA857: Serial.println(F("VOL-"));    break;
  case 0xFF906F: Serial.println(F("UP"));    break;
  case 0xFF9867: Serial.println(F("EQ"));    break;
  case 0xFFB04F: Serial.println(F("ST/REPT"));    break;
  case 0xFF6897: Serial.println(F("0"));    break;
  case 0xFF30CF: Serial.println(F("1"));    break;
  case 0xFF18E7: Serial.println(F("2"));    break;
  case 0xFF7A85: Serial.println(F("3"));    break;
  case 0xFF10EF: Serial.println(F("4"));    break;
  case 0xFF38C7: Serial.println(F("5"));    break;
  case 0xFF5AA5: Serial.println(F("6"));    break;
  case 0xFF42BD: Serial.println(F("7"));    break;
  case 0xFF4AB5: Serial.println(F("8"));    break;
  case 0xFF52AD: Serial.println(F("9"));    break;
  case 0xFFFFFFFF: Serial.println(F(" REPEAT"));break;  
  default: 
    Serial.println(F(" unknown  "));

  }
  delay(500);
}

Application

One of the best known applications is to control the color of an RGB LED using a remote control. For each button on the remote control we will match a color. It is possible to use the other buttons to perform another action such as lowering / increasing the brightness or flashing the LED.

//Library
#include "IRremote.h"

//Constant
const int receiverPin = 9;
#define ledRPin 11
#define ledGPin 5
#define ledBPin 6

//Variable
int power=50;
bool ledState=0;
IRrecv irrecv(receiverPin);     
decode_results results;      

void setup(){
  Serial.begin(9600);
  Serial.println(F("IR Receiver Decoder")); 
  irrecv.enableIRIn(); // Start the receiver
  pinMode(ledRPin,OUTPUT);
  pinMode(ledGPin,OUTPUT);
  pinMode(ledBPin,OUTPUT);
  lightRGB(255,0,0);
}

void loop()   /*----( LOOP: RUNS CONSTANTLY )----*/
{
  if (irrecv.decode(&results)){ // IR signal received?
    convertIR(); 
    irrecv.resume(); // receive the next value
  }  
}


void convertIR() // convert IR code
{
 Serial.print(results.value);
 Serial.print(F(" -> "));
  switch(results.value)
  {
  case 0xFFA25D: 
    Serial.print(F("POWER "));
    ledState=!ledState; 
    Serial.print(ledState);
    if(!ledState) lightRGB(0,0,0);
    break;
  case 0xFFE21D: Serial.print(F("FUNC/STOP")); break;
  case 0xFF629D: 
    Serial.print(F("VOL+ power:")); 
    power=power+10;
    power=min(power,100);
    Serial.print(power);
    break;
  
  case 0xFFA857: 
    Serial.print(F("VOL- power:")); 
    power=power-10;
    power=max(power,0);
    Serial.print(power);
    break;
  
  case 0xFF22DD: Serial.print(F("FAST BACK"));    break;
  case 0xFF02FD: Serial.print(F("PAUSE"));    break;
  case 0xFFC23D: Serial.print(F("FAST FORWARD"));   break;
  case 0xFFE01F: Serial.print(F("DOWN"));    break;
  case 0xFF906F: Serial.print(F("UP"));    break;
  case 0xFF9867: Serial.print(F("EQ"));    break;
  case 0xFFB04F: Serial.print(F("ST/REPT"));    break;
  case 0xFF6897: 
    Serial.print(F("0")); 
    if(ledState) lightRGB(255,255,255);   
    break;
  case 0xFF30CF: 
    Serial.print(F("1"));    
    if(ledState) lightRGB(255,0,0);
    break;
  case 0xFF18E7: Serial.print(F("2"));    
    if(ledState) lightRGB(0,255,0);
    break;
  case 0xFF7A85: Serial.print(F("3"));    
    if(ledState) lightRGB(0,0,255);
    break;
  case 0xFF10EF: Serial.print(F("4"));    
    if(ledState) lightRGB(255,55,55);
    break;
  case 0xFF38C7: Serial.print(F("5"));    
    if(ledState) lightRGB(55,255,55);
    break;
  case 0xFF5AA5: Serial.print(F("6"));    
    if(ledState) lightRGB(55,55,255);
    break;
  case 0xFF42BD: Serial.print(F("7"));    
    if(ledState) lightRGB(255,255,55);
    break;
  case 0xFF4AB5: Serial.print(F("8"));    
    if(ledState) lightRGB(255,55,255);
    break;
  case 0xFF52AD: Serial.print(F("9"));    
    if(ledState) lightRGB(55,255,255);
    break;
  case 0xFFFFFFFF: Serial.print(F(" REPEAT"));break;  
  default: 
    Serial.print(F(" unknown  "));
    lightRGB(0,0,0);
  }
  Serial.println();
  delay(500);
}

void lightRGB(int r, int g, int b){
  if(0){
    r=255-r;
    g=255-g;
    b=255-b;
  }
  analogWrite(ledRPin, r*power/100);
  analogWrite(ledGPin, g*power/100);
  analogWrite(ledBPin, b*power/100);
}

Sources

Find other examples and tutorials in our Automatic code generator
Code Architect