ESP32 PS4 controller: controlling a relay

In this tutorial we will check how to connect a PS4 controller to the ESP32 and control a relay by using the controller buttons. The tests from this tutorial were done using a DFRobot’s ESP32 module integrated in a ESP32 development board.

Introduction

In this tutorial we will check how to connect a PS4 controller to the ESP32 and control a relay by using the controller buttons. The tests from this tutorial were done using this relay board from DFRobot.

We will be using the Arduino core and this library, already introduced on this tutorial.

Figure 1 illustrates the wiring diagram between the ESP32 and the relay board. As can be seen, we can control the relay by connecting a digital pin of the ESP32 to the relay board input pin, labeled in the image as IN.

Note that the board doesn’t have any label but, in my version of the board, this pin is attached to the green wire. The additional wires correspond to GND (black) and VCC (red).

The relay board is already prepared to be controlled using the digital voltage level of a microcontroller such as the ESP32.

Electric diagram with the connection between the ESP32 and the relay board.
Figure 1 – Electric diagram with the connection between the ESP32 and the relay board.

Important: This tutorial will focus only on the control of the relay. Thus we will only work with low currents and voltages. Nonetheless, a relay can be used to control circuits operating with the mains, which is dangerous if you don’t know what you are doing. Please stay safe and don’t work with the mains if you don’t have experience with it.

The tests from this tutorial were done using a DFRobot’s ESP32 module integrated in a ESP32 development board.

The code

We will start by importing the PS4Controller.h library, to get access to the functionalities we need to allow the connection of a PS4 controller. These will be exposed by the PS4 extern variable that becomes available from the library include.

#include <PS4Controller.h>

Then we will define a global variable called relayPin that will contain the number of the pin that will be connected to the relay. I’ll be using pin 13, but you can use other if you prefer.

int relayPin = 13;

Moving on to the Arduino setup, we will start by initializing a serial connection, to output some messages from the program.

Serial.begin(115200);

Then we will configure the pin connected to the relay to work as output, by calling the pinMode function. As first input we pass the number of the pin (stored in the global variable) and as second input the constant OUTPUT.

pinMode(relayPin, OUTPUT);

After this we will initialize the Bluetooth layer of the ESP32, so it is ready to receive an incoming controller connection. This is done with a call to the begin method on the PS4 extern variable, passing as input a string with the Bluetooth address stored in the controller (you can learn how to obtain the address here).

if(!PS4.begin("01:01:01:01:01:01")){
      Serial.println("Initializetion failed");
      return;
}

To finalize the Arduino setup function we will set a callback function to handle the controller connection event and another function to handle button presses.

You can learn more about the controller connection event here. For a tutorial on how to handle button presses on the controller you can check here.

The complete setup function, already with the registering of the callback functions, can be seen below. Note that we are going to analyze the implementation in detail later.

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

  pinMode(relayPin, OUTPUT);

  if(!PS4.begin("01:01:01:01:01:01")){
      Serial.println("Initializetion failed");
      return;
  }
  
  Serial.println("Initialization finished.");
 
  PS4.attach(onEvent);
  PS4.attachOnConnect(onConnection);
}

Since we are working with events, we don’t need to do any periodic polling to the PS4 extern variable. Thus, we can delete the main loop FreeRTOS task.

void loop()
{
  vTaskDelete(NULL);
}

Now we are going to analyze the implementation of the onConnection function, which we will use to handle an incoming controller connection. We will simply confirm the controller is connected by calling the isConnected method and print a message to the user indicating it has been connected.

void onConnection() {
  
  if (PS4.isConnected()) {
    Serial.println("Controller connected.");
  }
}

To finalize, we will check the implementation of the onEvent function, which will set the state of the relay. We will assume that pressing the cross button will turn the relay on and pressing the square button will turn it off.

In both cases, we will detect the button pressed event, accordingly to what was analyzed in this tutorial.

In either cases, we access the event attribute of the PS4 extern variable, which is a struct. Then we access the button_down field, which is also another struct. To finalize, we access the cross and square fields to check if the cross or the square buttons were pressed, respectively.

In case the cross was pressed, we set the state of the pin connected to the relay to a high digital level, turning on the relay. We set the state of the pin with a call to the digitalWrite function, passing as first input the number of the pin and as second the constant HIGH.

if(PS4.event.button_down.cross){
    digitalWrite(relayPin, HIGH);
}

We will do something similar for the square button, but instead we pass as second argument of the digitalWrite function the value LOW. This will set the pin to a low digital level, turning off the relay.

if(PS4.event.button_down.square){
     digitalWrite(relayPin, LOW);
}

The complete callback function is shown below.

void onEvent(){

  if(PS4.event.button_down.cross){
    digitalWrite(relayPin, HIGH);
  }
  
  if(PS4.event.button_down.square){
     digitalWrite(relayPin, LOW);
  }
  
}

The complete code can be seen below.

#include <PS4Controller.h>

int relayPin = 13;

void onEvent(){

  if(PS4.event.button_down.cross){
    digitalWrite(relayPin, HIGH);
  }
  
  if(PS4.event.button_down.square){
     digitalWrite(relayPin, LOW);
  }
  
}

void onConnection() {
  
  if (PS4.isConnected()) {
    Serial.println("Controller connected.");
  }
}

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

  pinMode(relayPin, OUTPUT);

  if(!PS4.begin("01:01:01:01:01:01")){
      Serial.println("Initializetion failed");
      return;
  }
  
  Serial.println("Initialization finished.");
 
  PS4.attach(onEvent);
  PS4.attachOnConnect(onConnection);
}

void loop()
{
  vTaskDelete(NULL);
}

Testing the code

First make sure to wire the ESP32 and the relay accordingly to the schematic from figure 1.

After that, compile and upload the code to the ESP32 using the Arduino IDE. When the procedure finishes, open the serial monitor and wait for the “Initialization finished” message to get printed.

Then connect the controller by pressing the PS button. You should obtain a “Controller connected” message in the monitor, which is printed from the callback function.

To finalize the test, press the cross button on the controller. The relay should turn on. Then click the square button. The relay should turn off. You can check in the video below how the system should behave.

One Reply to “ESP32 PS4 controller: controlling a relay”

  1. Shouldn’t there be a way to connect the controller directly without messing with the MAC? Android/Linux can do it

Leave a Reply