Hello readers, hope you all are doing great. In this tutorial, we will discuss low power modes in ESP32, their purpose and their implementation to increase the battery life by reducing power consumption.
Along with multiple wireless and processing features, ESP32 also provides us with a power-saving feature by offering sleep modes. When you are powering the ESP32 module from the live supply using an adaptor or a USB cable, there is nothing to worry about power consumption. But when you are using a battery, as a power source to ESP32, you need to manage the power consumption for longer battery life.
Low Power Modes in ESP32
When ESP32 is in sleep mode, a small amount of power is required to maintain the state of ESP32 in RAM (random access memory) and retain necessary data. Meanwhile, the power supply won’t be consumed by any unnecessary peripheral or inbuilt modules like Wi-Fi and Bluetooth.
ESP32 offers 5 power modes. Each mode is configurable and offers different power-saving capabilities:
Active Mode
Modem Sleep Mode
Light Sleep Mode
Deep Sleep Mode
Hibernation Mode
Fig. 2
Active Mode:
In active mode, all the modules and features of ESP32, like processing cores, Wi-Fi, Bluetooth, radio etc. remain active all the time.
Most of the power consumption occurs in this power mode which can vary between 160 -240mA and sometimes the maximum consumption could reach up to 790mA (when both Wi-Fi and Bluetooth are enabled or active at the same time).
Modem Sleep Mode:
In this mode, radio, Wi-Fi, Bluetooth will be disabled and everything else will remain active. Power consumption in this mode varies from 3 to 20mA.
Sleep modes can switch between modem and active modes as per the predefined intervals, by following the associated sleep pattern.
Light Sleep Mode:
During this mode, the central processing unit is paused by turning/powering off its clock.
ULP- coprocessor and RTC (real-time clock) remain active during light sleep mode and power consumption is 0.8mA.
Deep Sleep mode:
In this mode, the Ultra Low Power (ULP) coprocessor remains active while the ESP32 core and other digital peripherals remain inactive.
The ULP coprocessor wakes up the core processor when required.
The amount of power consumed in this mode is 10uA.
Fig 3
Hibernation Mode:
In this mode, the ULP coprocessor and internal oscillator both are disabled.
Only a real-time clock (RTC) remains active to wake up the processor and other required modules from hibernation mode and the power consumption in this mode is extremely low that is approximately 2.5uA.
For a better understanding of low power modes in ESP32, we are going to implement deep sleep mode in esp32 and will also discuss how to wake up the device from deep sleep mode.
Deep Sleep mode and Wakeup Using Capacitive Touch-sensitive pins
To implement deep sleep modes we are going to use another ESP32 feature that is Capacitive Touch Sensing pins. These pins can sense the presence of a body that holds an electric charge.
So we are going to use these touch-sensitive pins for waking up ESP32 from deep sleep mode using the Arduino IDE compiler.
In Arduino IDE examples are given for deep sleep mode with various wake-up methods.
Follow the image attached below to open the example code:
Fig. 4 Example code.
Arduino IDE Code
#define Threshold 40 /* Greater the value, more the sensitivity */RTC_DATA_ATTR int bootCount = 0;touch_pad_t touchPin;/*Method to print the reason by which ESP32has been awaken from sleep*/void print_wakeup_reason(){ esp_sleep_wakeup_cause_t wakeup_reason; wakeup_reason = esp_sleep_get_wakeup_cause(); switch(wakeup_reason) { case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break; case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break; case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break; case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break; case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break; default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break; }}/*Method to print the touchpad by which ESP32has been awaken from sleep*/void print_wakeup_touchpad(){ touchPin = esp_sleep_get_touchpad_wakeup_status(); switch(touchPin) { case 0 : Serial.println("Touch detected on GPIO 4"); break; case 1 : Serial.println("Touch detected on GPIO 0"); break; case 2 : Serial.println("Touch detected on GPIO 2"); break; case 3 : Serial.println("Touch detected on GPIO 15"); break; case 4 : Serial.println("Touch detected on GPIO 13"); break; case 5 : Serial.println("Touch detected on GPIO 12"); break; case 6 : Serial.println("Touch detected on GPIO 14"); break; case 7 : Serial.println("Touch detected on GPIO 27"); break; case 8 : Serial.println("Touch detected on GPIO 33"); break; case 9 : Serial.println("Touch detected on GPIO 32"); break; default : Serial.println("Wakeup not by touchpad"); break; }}void callback(){ //placeholder callback function}void setup(){ Serial.begin(115200); delay(1000); //Take some time to open up the Serial Monitor //Increment boot number and print it every reboot ++bootCount; Serial.println("Boot number: " + String(bootCount)); //Print the wakeup reason for ESP32 and touchpad too print_wakeup_reason(); print_wakeup_touchpad(); //Setup interrupt on Touch Pad 3 (GPIO15) touchAttachInterrupt(T3, callback, Threshold); //Configure Touchpad as wakeup source esp_sleep_enable_touchpad_wakeup(); //Go to sleep now Serial.println("Going to sleep now"); esp_deep_sleep_start(); Serial.println("This will never be printed");}void loop(){ //This will never be reached}
Code Description
The first step is to set the threshold value for touch-sensitive pins.
When a body, containing an electric charge touches a touch-sensitive pin, the threshold value decreases below 40, that decrease in the threshold value will make ESP32 wake up from deep sleep mode. In the example code threshold value is 40.
The next task is to store the data into RTC memory (using RTC_DATA_ATTR ) because in deep sleep mode only RTC remains active and all other peripherals, processors, wireless modules will be disabled.
ESP32 offers 8kB SRAM on RTC to store the data.
But when you press EN/reset button the data stored in RTC memory will also be erased.
bootCount an integer type variable is used to count the number of times ESP32 has woken up during sleep mode. The value of bootCount variable is stored in RTC memory.
The print_wakeup_reason() function is used to print the reason for ESP32 wakeup from deep sleep whether it is due to an external interrupt, timer, or touch-sensitive pins.
The ESP32 has multiple capacitive touch-sensitive GPIO pins which can be used to wake up esp32 from deep sleep mode.
Print_wakeup_touchpad() function is used to print the GPIO pin which made ESP32 wake up from sleep mode.
When you hold a capacitive sensitive pin for a longer duration the threshold value (initialized globally) decreases from its predefines value i.e., 40 which will cause ESP32 to wake up, at that time the callback() function comes into action.
This function will be used as an argument inside the touchAttachInterrupt() function.
Setup()
Inside the setup() function the first task is to start the serial monitor with a baud rate of 115200.
Next, if there is any increment in boot count due to wake up calls, then print that count on the serial monitor.
Call the respective functions to print the wake-up reason:
Print_wakeup_reason() is used to print whether the ESP32 wake-up is caused by an external interrupt, timer or a capacitive sensitive pin.
If the wake up is due to a capacitive sensitive pin then the print_wakeup_touchpad() function will print the GPIO pin number which caused the wake-up.
The next task is to attach the interrupt using touchAttachInterrupt() function, to capacitive sensitive GPIO pin which you will use to wake up ESP32.
In this example we are using GPIO 15 capacitive sensitive pin as a wakeup interrupt pin.
esp_sleep_enable_touchpad_wakeup() is used to enable touch sensor feature.
esp_deep_sleep_start() function is used to make ESP32 enter to deep sleep mode.
Once ESP32 enters the sleep mode no other operation or data communication is possible until it receives a wakeup call.
Fig 12
Loop()
In this example code, there is nothing, written inside the loop function. But you can change the code as per your requirements.
Code Testing
To test the code, use a connecting wire (male to female) and connect one side to ESP32’s touch-sensitive pin (which you have mentioned in the code as an interrupt).
When you touch that pin an interrupt will be generated to wake ESP32 from sleep.
You can see the results on a serial monitor or can check the current consumption or can run other functions once it is awake like blinking LED.
In this code, we are using GPIO_15 touch-sensitive pin.
Fig. 13 waking up esp32 using capacitive sensitive GPIO pin
We have attached a screenshot from the serial monitor for reference.
Fig. 14
Deep Sleep mode and Wakeup Using Interrupt method
Arduino IDE Code
#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */#define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in seconds) */RTC_DATA_ATTR int bootCount = 0;/*Method to print the reason by which ESP32has been awaken from sleep*/void print_wakeup_reason(){ esp_sleep_wakeup_cause_t wakeup_reason; wakeup_reason = esp_sleep_get_wakeup_cause(); switch(wakeup_reason) { case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break; case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break; case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break; case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break; case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break; default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break; }}void setup(){ Serial.begin(115200); delay(1000); //Take some time to open up the Serial Monitor //Increment boot number and print it every reboot ++bootCount; Serial.println("Boot number: " + String(bootCount)); //Print the wakeup reason for ESP32 print_wakeup_reason(); /* First we configure the wake up source We set our ESP32 to wake up every 5 seconds */ esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds"); /* Next we decide what all peripherals to shut down/keep on By default, ESP32 will automatically power down the peripherals not needed by the wakeup source, but if you want to be a poweruser this is for you. Read in detail at the API docs http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html Left the line commented as an example of how to configure peripherals. The line below turns off all RTC peripherals in deep sleep. */ //esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF); //Serial.println("Configured all RTC Peripherals to be powered down in sleep"); /* Now that we have setup a wake cause and if needed setup the peripherals state in deep sleep, we can now start going to deep sleep. In the case that no wake up sources were provided but deep sleep was started, it will sleep forever unless hardware reset occurs. */ Serial.println("Going to sleep now"); Serial.flush(); esp_deep_sleep_start(); Serial.println("This will never be printed");}void loop(){ //This is not going to be called}
Code Description
The first task is, to define the timer period for which ESP32 will be in deep sleep mode.
As we know that ESP32 operates at the MHz frequency range so the timer will be in microseconds. So, it is required to convert the time into seconds.
To add a timer of 5sec we need to multiply 5*1000000.
bootCount an integer type variable is used to count the number of times ESP32 has woken up during sleep mode. The value of bootCount variable is stored in RTC memory.
Fig 15
The print_wakeup_reason() function is used to print the reason for ESP32 wakeup from deep sleep whether it is due to an external interrupt, timer or touch-sensitive pins.
Fig. 16
Setup()
As discussed earlier, inside the setup function first we need to initialize the serial monitor at 115200 baud rate and then print the value of bootCount variable which is incrementing every time a wakeup interrupt occurs.
Fig. 17
The esp_sleep_enable_wakeup() function is used to enable the timer to generate a timer interrupt by passing time in microsecond as an argument.
In the beginning of code we have defined some global variable to add 5 sec timer (or 5000000us) and after every 5 sec ESP32 should wake up from deep sleep till 5 sec.
Fig. 18
esp_deep_sleep_start() function is used to make ESP32 enter the deep sleep mode.
Fig. 19
Testing
You can see the results of above code on serial monitor as shown is the image attached below.
Fig 20
This concludes the tutorial. I hope you found this useful, and I hope to see you soon for the new ESP32 tutorial.
Hello readers, I hope you all are doing great. Welcome to the 3rd Lecture of Section 2 in the ESP32 Programming Series. In this tutorial, we are going to discuss another important feature of ESP32 i.e. PWM(Pulse Width Modulation).
Pulse Width Modulation is a technique to reduce the voltage by pulsating it. In today's lecture, we will first understand the basic concept of PWM, and after that will design two projects to fully grasp it. In the first project, we will control the brightness of an LED, while in the second one, we will control the speed of a DC Motor.
Here's the video demonstration of PWM Control in ESP32:
Before going forward, let's first have a look at the PWM working:
PWM is used to control the power delivered to the load by pulsating the ON-Time of the voltage pulse, without causing any power loss. Let's understand the PWM concept with the help of below image:
As you can see in the above image, Figure A shows a simple 5V DC signal.
Figure D shows a simple circuit with a manual switch, now if we turn the switch ON & OFF manually, the Load will also behave in the same way. Its waveform is shown in Figure B, when the switch is ON, we are getting +5V and when it's OFF, output is 0V.
Instead of manual switching, if we place a fast automatic switching circuit (FETs, MOSFETs etc.), the output pulse won't show fluctuations, instead, it will get steady but its overall power will be reduced.
Let's understand the working of PWM with an example:
Suppose a DC Motor runs at 200RPM over 5V. Now, if we want to reduce its speed to 100 RPM, we need to reduce its input voltage to 2.5V(approx). So, either we can replace the 5V battery with a 2.5V Battery or use a PWM circuit to reduce the voltage level from 5V to 2.5V. In this specific case, the PWM pulse will be ON for 50% of the time and get OFF for the remaining 50% of the time.
The behavior of the PWM signal is determined by the following factors:
Frequency
Duty Cycle
Resolution
PWM Frequency:
The Frequency of a signal is defined as the number of cycles per second, denoted by "f" and the measuring unit is hertz(Hz).
The Frequency (f) of a signal is inversely proportional to its time period(t).
Let's understand the signal Frequency with the help of below image:
As you can see in the below figure, we have taken two signals for a duration of 1 second. The first signal completes 10 Cycles in 1 second, so we can say it has a frequency of 10Hz, while the second one has a frequency of 5Hz as it completes 5 cycles in 1 second. So, I hope now it's clear that the number of cycles per second is the frequency of a signal.
The frequency of a PWM signal depends on the provided clock source.
In the case of microcontrollers, the clock source is provided by the crystal oscillator. So, a 40MHz Crystal Oscillator can produce high-frequency PWM signals as compared to a 20MHz oscillator.
PWM Duty Cycle:
Duty Cycle is the ratio of ON time(when the signal is high) to the total time taken to complete the cycle. The duty cycle is represented in the form of a percentage (%) or ratio. Let's understand the PWM Duty Cycle with the help of below image:
The 1st graph shows no signal, so we can say it has a 0% Duty Cycle because there's no ON-Time.
The 2nd graph shows 5 cycles of a signal and in each cycle, the signal is ON only for 25% of the total time. So, its Duty Cycle is 25%.
In the 3rd graph, the signal has a duty cycle of 50% because it's HIGH for 50% of the cycle.
You can calculate the 4th graph, its duty cycle is 75% as it is HIGH for 75% of the total duration.
The last graph shows a pure DC Signal of 5V, and as it is HIGH for the whole cycle, its duty cycle will be 100%.
Resolution:
The resolution of a PWM signal defines the number of steps it can have from zero power to full power. The resolution of the PWM signal is configurable for example, the ESP32 module has a 1-16 bit resolution, which means we can configure maximum a of 65536 (2^16) steps from zero to full power.
Implementing PWM using ESP32
In the ESP WROOM-32 module, there are 16 PWM channels. All the channels are divided into two groups containing 8 channels in each group. The resolution can be programmed between 1 to 16 bits and frequency also depends upon the programmed resolution of the PWM signal.
Now
For the demonstration of PWM in ESP32 we are going to explain two examples:
Controlling LED brightness using PWM
Controlling DC motor speed using PWM
ESP32 Code for Controlling LED brightness using PWM
We are using Arduino IDE to compile and upload the code into the ESP WROOM-32 board.
ESP32’s inbuilt LED is used in this code. You can also connect an external LED as per your requirements.
Arduino IDE Code:
// Global variable declaration to set PWM properties
const int ledChannel = 0; // select channel 0
const int resolution = 8; //8-bit resolutin i.e., 0-255
const int frequency = 5000; // set frequency in Hz
int dutyCycle = 0;
void setup()
{
Serial.begin(115200);
ledcSetup(ledChannel, frequency, resolution); // configure LED PWM functionalities
ledcAttachPin(LED_BUILTIN, ledChannel); // attach the channel to the GPIO to be controlled
}
void loop()
{
while(dutyCycle <200)
{
ledcWrite(ledChannel, dutyCycle++); // changing the LED brightness with PWM
Serial.print(" duty Cycle ++ :");
Serial.println(dutyCycle); // display the duty cycle on serial monitor
delay(5);
}
while(dutyCycle>0)
{
ledcWrite(ledChannel, dutyCycle--); // changing the LED brightness with PWM
Serial.print(" duty Cycle -- :");
Serial.println(dutyCycle); // display the duty cycle on serial monitor
delay(5);
}
}
Code Description
Global Variable declaration:
The first step is to declare variables for setting PWM properties.
As we have already mentioned that ESP WROOM-32 has 16 PWM channels (0 to 15). So, the first step will be to select a PWM channel between 0-15. In the Arduino IDE code, we are using PWM channel_0 to generate a PWM signal.
The next step will be to choose the resolution. The maximum resolution for ESP32 is 16-bit. You can choose any value between 1-16. PWM resolution is the factor that decides the maximum duty cycle.
For example, if we choose 10-bit resolution then the maximum duty cycle of the output signal will be 2^10 that is 1024 (0-1023) and similarly, for 8-bit resolution the duty cycle will be 2^8=256 (0- 255).
5KHz or 5000Hz is the PWM signal frequency.
We also need to initialize a variable to store the duty cycle value.
// Global variable declaration to set PWM properties
const int ledChannel = 0; // select channel 0
const int resolution = 8; //8-bit resolutin i.e., 0-255
const int frequency = 5000; // set frequency in Hz
int dutyCycle = 0;
Arduino Setup() Function
Inside setup() function we are going to start serial monitor at 115200 baud rate.
Serial.begin(115200);
To configure PWM properties we are calling the ledcSetup() function which uses PWM properties (like PWM channel, frequency and PWM resolution) as arguments.
ledcSetup(ledChannel, frequency, resolution); // configure LED PWM functionalities
ledcAttachPin() function is used to assign the LED_BUILTIN pin to the PWM channel.
ledcAttachPin(LED_BUILTIN, ledChannel); // attach the channel to the GPIO to be controlled
Arduino Loop() Function
Inside the loop function, we going to run a conditional control loop (while loop) to change the LED brightness along with the change in duty cycle.
At first, the value of the duty cycle is going to increase continuously until it reaches max 8-bit resolution ( that is 255).
The serial monitor will print the duty cycle value with some delay.
while(dutyCycle <200)
{
ledcWrite(ledChannel, dutyCycle++); // changing the LED brightness with PWM
Serial.print(" duty Cycle ++ :");
Serial.println(dutyCycle); // display the duty cycle on serial monitor
delay(5);
}
After increasing the duty cycle to maximum resolution another while loop is used to decrease the duty cycle to value 0 from 255 and proportionally the LED brightness and the PWM output will be printed on the serial monitor.
while(dutyCycle>0)
{
ledcWrite(ledChannel, dutyCycle--); // changing the LED brightness with PWM
Serial.print(" duty Cycle -- :");
Serial.println(dutyCycle); // display the duty cycle on serial monitor
delay(5);
}
Code Testing
You can see the change in the value of the duty cycle on the serial monitor. We have attached a screenshot below from the Arduino IDE serial monitor for reference.
For a better understanding of PWM output you can use an oscilloscope (either CRO or DSO) by connecting the PWM output pint and GND pint to the oscilloscope probe, if available.
You can also use a serial plotter to see the PWM output if you do not have an oscilloscope.
To access the serial plotter, use sort-cut key shift+ctrl+L or follow the image attached below:
Fig. 8 Arduino IDE Serial Plotter
We have attached a screenshot of the PWM output waveform from the serial plotter for better understanding.
You can vary the value of duty cycle anywhere between 0-8 bit resolution.
For example in the image attached below the duty cycle is 200.
Fig. 9 Serial plotter PWM output
ESP32 Code for Controlling DC motor speed using PWM
Fig. 10
In this example, we are going to implement PWM using ESP WROOM-32 to control the speed of a DC motor.
The speed of the DC motor depends upon the input power supply. So, by varying the power input we can also vary (increase or decrease) the speed of DC motor.
Hardware components required:
ESP WROOM-32 board
DC motor
L298N motor driver
Connecting wires
Data cable
L298N motor driver: A motor driver is used between the ESP32 board and DC motor to resolve the power compatibility issues.
Both the ESP32 board and DC motor operate at different power ratings due to which you can not connect the two devices directly. So a motor driver is used to receive a low power input from the ESP32 board and drive/run DC motor at slightly high power.
L298N can drive a DC motor that operated between 5 to 35 voltage range and maximum current of 2A.
There are various DC motor drivers available in the market for example L293D, DRV8833, MAX14870 single brushed motor driver etc. You can choose the driver of your choice depending upon the application and power ratings.
Fig. 11
FIG. 12 IC L298N pin-out
You can also change the direction of rotation by connecting the input as per the table drawn below:
IN_1
IN_2
Rotation
HIGH
LOW
DC motor rotates in a clockwise direction
LOW
HIGH
The motor rotates in an anti-clockwise direction
LOW
LOW
Motor STOP
HIGH
HIGH
Motor STOP
Table 1
Arduino Code
//configure GPIO pins to connect motor driver
int enable1Pin = 14;
int M_Pin1 = 26;
int M_Pin2 = 27;
// Setting PWM properties
const int freq = 10000;
const int pwmChannel = 0;
const int resolution = 8;
int dutyCycle = 150;
void setup()
{
Serial.begin(115200);
// sets the pins as outputs:
pinMode(M_Pin1, OUTPUT);
pinMode(M_Pin2, OUTPUT);
pinMode(enable1Pin, OUTPUT);
//Configure LED PWM functionalities
ledcSetup(pwmChannel, freq, resolution);
// attach the channel to the GPIO to be controlled
ledcAttachPin(enable1Pin, pwmChannel);
Serial.print("Testing DC Motor...");
}
void loop()
{
// Move the DC motor in anti-clockwise direction at maximum speed
Serial.println("Moving reverse");
digitalWrite(M_Pin1, LOW);
digitalWrite(M_Pin2, HIGH);
delay(500);
// Move DC motor forward with increasing speed
Serial.println("Moving Forward");
digitalWrite(M_Pin1, HIGH);
digitalWrite(M_Pin2, LOW);
//----while loop----
while (dutyCycle <= 255)
{
ledcWrite(pwmChannel, dutyCycle);
Serial.print("Speed increasing with duty cycle: ");
Serial.println(dutyCycle);
dutyCycle = dutyCycle +5;
delay(100);
}
while (dutyCycle >150)
{
ledcWrite(pwmChannel, dutyCycle);
Serial.print("Speed decreasing with duty cycle: ");
Serial.println(dutyCycle);
dutyCycle = dutyCycle -5;
delay(100);
}
// _____Stop the DC motor
Serial.println("STOP DC motor");
digitalWrite(M_Pin1, LOW);
digitalWrite(M_Pin2, LOW);
delay(500);
}
Code Description
The first step is to configure GPIOs which are to be connected with the DC motor driver (L298N).
Here we are using three GPIOs, the first one is connected with the Enable_A pin and the rest of the two are connected with motor inputs.
You can also control 2 motors with the same driver using Enable_2 and its respective input pins.
//configure GPIO pins to connect motor driver
int enable1Pin = 14;
int M_Pin1 = 26;
int M_Pin2 = 27;
The next step is to define variables to store PWM properties as discussed in the previous example.
You can vary the frequency and duty cycle of the PWM signal as per your requirements but, within the desired range.
Here we are assigning 10000Hz or 10KHz frequency with 8-bit resolution (0-255 duty cycle) and the initial duty cycle value is 150 for PWM channel 0.
// Setting PWM properties
const int freq = 10000;
const int pwmChannel = 0;
const int resolution = 8;
int dutyCycle = 150;
Arduino Setup() Function
Inside the setup function, the first task is to initialize the serial monitor with a 115200 baud rate.
Serial.begin(115200);
Set the operating mode of three GPIO pins (which are to be connected with motor driver board) as output.
// sets the pins as outputs:
pinMode(M_Pin1, OUTPUT);
pinMode(M_Pin2, OUTPUT);
pinMode(enable1Pin, OUTPUT);
Call the function ledcSetup() to configure PWM properties by passing PWM properties as arguments.
//Configure LED PWM functionalities
ledcSetup(pwmChannel, freq, resolution);
Next, you need to select the GPIO pin which will provide the PWM output from ESP32 to the motor driver using ledcAttachPin() function which uses the PWM output pin and PWM channel as two arguments.
// attach the channel to the GPIO to be controlled
ledcAttachPin(enable1Pin, pwmChannel);
Arduino Loop() Function
Start rotating the motor in the anti-clockwise direction. Follow Table 1 for more details regarding the direction of rotation.
Add the delay of 0.5 sec or as per your requirements.
Fig. 19
Rotate the DC motor in a clockwise direction by setting M_PIN1 as high ND m_Pin2 as low.
Fig. 20
As we have initialized the duty cycle variable with a value of 150. Now, increase the motor speed by increasing the value of the Duty cycle from 150 by increasing 5 steps continuously until it reaches the maximum value that is 255.
Fig. 21 Increasing speed
After reaching the maximum speed at 255 duty cycle, now let's decrease the speed of DC motor till 150 duty cycle with the decrease of 5 steps every time.
Fig. 22 Reducing speed
Stop duty cycle by either writing both the motor pins(M_Pin1, M_Pin2) to LOW or HIGH (like XOR gate).
Fig. 23 STOP DC motor
Code Testing
For a better understanding, open the serial monitor using shortcut keys ctrl+shift+M.
On the serial monitor, you can see the increase and decrease in duty cycle and can compare it with DC motor speed.
Fig. 24 PWM output on serial monitor
You can also check the PWM output on the Serial plotter by pressing the ctrl+shift+L keys.
It is visible through the waveform that the duty cycle is varying from 150 to 255 and reverse and proportionally the seed of the DC motor.
Fig. 25 PWM output on Serial Plotter
This concludes the tutorial. I hope you found this useful, and I hope to see you soon for the new ESP32 tutorial.
Hello readers, hope you all are doing great. In this tutorial, we will discuss another ESP32 protocol that is Web Socket and we will also explain how to create a web server using web socket protocol with ESP32. So, we will have a look at What is a web socket server, How web socket protocol is different from HTTP protocol, What is handshaking in networking, Three-way handshaking, Web socket application, Creating web socket server using ESP32 module etc. Let's get started:
A Web Socket is a full-duplex (both the server and the client can send and receive data at the same time) computer communication protocol. Web socket protocol, like HTTP (hypertext transfer protocol), also works in server and client communication format. A web socket uses a process known as handshaking to establish communication between the server and client. This protocol is also known as the stateful protocol. When a client device requests communication with the server, a connection is established between the server and the client, and the connection remains in place until either the server or the client terminates it.
How web socket protocol is different from HTTP protocol?
Both, web socket and HTTP protocols are computer communication protocols and both the protocols work on the 4th layer of TCP (transmission control protocol). But still, there are multiple specifications that make them stand apart from each other.
Unlike web socket protocol, HTTP is a half-duplex protocol (half-duplex protocol means that the client and server can either transmit or receive data at a time). It is a connection-oriented protocol.
Fig. 2 HTTP protocol
When we need to update a web page over HTTP, we have to update the complete web page before updating any data. To overcome this drawback, the most efficient solution is using a web socket protocol to receive updated data in real time. Along with that web socket protocol also saves a significant number of clock cycles for resource-intensive applications.
Fig. 3 web socket protocol
Whenever a client sends an HTTP request to a server, a TCP connection will be open between the server and client and when the server responds to that request the TCP connection between server and client will be terminated immediately.
HTTP protocol uses three-way handshaking which guarantees the transmission of the data packet and re-transmit the lost data packet.
Web socket starts with ws:// (web socket) or wss:// (web socket secure) whereas, HTTP starts with http://.
What is Handshaking in networking?
It is the process of establishing a connection between server and client. Handshaking determines the protocol, error correction scheme and speed etc. to be used for communication.
Fig. 4 Handshaking
Handshaking is necessary at the start of each communication session to ensure successful server and client communication despite some hardware or software configuration differences.
Three-way handshaking
In TCP/IP (transmission control protocol/ internet protocol) network, three-way handshaking is used to create a communication channel between server and client.
Three-way handshaking steps are:
Establishing a connection between server and client.
Server receives an SYN (synchronize sequence packet) packet from the client device.
Client device receives the ACK (acknowledgment sequence number) signal from the server and responds with an ACK packet.
Fig. 5 Three-way handshaking
Web socket Application
Web socket is used in real-time applications where a client is required to respond quickly to a change or update. The various web socket applications are:
Chat application
Online education
Sports update
Location-based applications
Financial Tickers
Creating Web Socket Server Using ESP32 Module
To create a web socket server using ESP32 we are using Arduino IDE as a compiler. Arduino IDE will compile the code and will also upload the compiled code into the ESP32 hardware module.
If you are not familiar with using the Arduino IDE compiler for ESP32 programming then follow our #1 tutorial that is about Introduction to ESP32 programming series.
Code
Code description
Download the required libraries (AsyncTCP and ESP32 WebServer) from the given link:
Follow our tutorial Introduction to ESP32 programming series to learn about adding a library in Arduino IDE.
Import the required libraries.
We are using three libraries to create a web socket server:
WiFi.h: This library is used to connect ESP32’s wifi module with the internet. It makes a wi-fi device to serve either as a client or a server.
AsyncTCP.h: This library is an asynchronous TCP library, used to enable a multi-connection, trouble-free network environment.
ESPAsyncWebServer.h: This library is used to create an asynchronous web server.
Fig. 6 Libraries
Initialize a variable “LED_Status” to store the status of inbuilt LED (internally connected to GPIO 2.
Enter the SSID and password as per your network credentials.
To create a web server we need to assign a port and port 80 is used for a local server.
Here we are creating an AsyncWebserver object with port 80 and another object AsynchWebsocket to handle connection at /ws path.
After assigning the port and path for the webserver and web socket respectively, the next step will be to create and design a web page.
We are using HTML (hypertext markup language) to create a web page to display LED status and change the state of the LED.
The complete HTML code is stored inside a variable “index_html”, which is used to display and style web page content.
Inside the index_html variable, the Style tag consists of all the instructions regarding styling the web page like the text color, font size, background color, font face etc. You can those instructions as per your requirements.
Fig. 10 <style> tag
Fig: 11 Styling the button
Inside the body tag, all the instructions required to display the content like text, heading etc is defined.
Fig. 12 <body> tag
<h1>ESP32 Web-Socket Server</h1> is the heading to be displayed on the top of the webpage.
<h2>LED1</h2> is the second heading for LED.
A button with text written to change the status of LED from LOW to HIGH and vice- versa.
Java-Script: When the webserver interface is fully loaded in the browser, it is used to set up a web socket connection with the server and handle data exchange via web socket. It is written inside <script> tag.
Fig. 13 script tag
window.addEventListener('load', onLoad) Here the onload() function calls the initWebSocket() function and initButton() function to initialize the websocket connection with the server and add event listener to the button respectively.
Gateway is the entry point for the web socket which gets the IP address.
initWebSocket() initialize the web socket connection at the obtained IP address.
When a connection is established between the server and client, the client will send a message to the ESP32 server to ensure the connection.
initWebSocket() will be called again after 2 sec if somehow the connection is closed.
Fig 14 initWebSocket()
The next step will be to update the status of LED on the web page.
When the server receives the changes in the state of LED which are requested/made by the client, the ESP32 will update the status of the LED on hardware and then acknowledge to the client.
Fig. 15 Update LED status on the web page
The function notifyClients() is used to update the current status of LED to the client device.
Fig. 16 Notify clients
handlWebSocketMessage() is a callback function that will run when the server receives a new message from the client through a web Socket.
Fig. 17 handles web (client) socket message
To configure the web socket server a function onEvent() is defined, to handle different asynchronous steps for the web socket.
The function initWebSocket() is used to initialize web socket protocol.
Fig. 18 Initialize web socket
The processor() is used to search for a placeholder on the web page.
The %STATE% placeholder will be replaced with the current LED state i.e. HIGHT for ‘1’ and LOW for ‘0’.
Fig. 19 Placeholder
Setup()
Inside the setup(), first of all we will initialize the serial monitor with 115200 baud rate.
Then, set the LED as output and write the LOW or ‘0’ state for LED.
Fig. 20
Call the WiFI.begin() function, which is having arguments ssid and password.
Continuously check the Wi-Fi status and print on the serial monitor once connected.
Fig. 21 Wifi status
If the ESP32 is connected with wi-fi then fetch the IP address and print it on serial monitor.
Iinitialize the web socket by calling initWebSocket() function.
Fig. 22
Pass the index_html variable as an argument to serve the text stored, when you receive a request on the URL.
Pass the processor() as an argument to replace the placeholder.
Fig. 23
Start the server.
Fig. 24
Loop()
The cleanupClients() function is called continuously in the loop function to close the previous client connection when the maximum client-connection limit is reached. Sometimes evening after calling the close function, the browser does not properly terminate the connection which can crash the server.
To avoid the server crash, cleanupClients() function is used.
Keep updating the status of the LED to LED_Status variable.
Print the LED status on the serial monitor using serial.println(“ ”).
Testing/Results
For testing purposes, we are using the inbuilt LED which is connected to GPIO 2.
You can see the updated status of the LED on the web page with an IP address of (192.168.43.233 in our project).
In this code, ESP32 is acting as a server both the ESP32 module and laptop/ mobile phone should be connected to the same wi-fi network.
Compile and upload the code into ESP32 using Arduino IDE.
Open the serial monitor and copy the IP address.
Enter the IP address in the browser.
A web page will be displayed on the screen.
Now you can change the status of ESP32’s inbuilt LED by clicking on the “change LED status” button.
Screenshots of the Serial monitor and web page are attached below for better understanding.
In the first image, you can see the IP address and status of the LED is printed on the serial monitor.
Fig 26 Arduino IDE Serial monitor
Fig. 27 Web page displaying LED status HIGH
Fig 28 Web page displaying LED status LOW
Fig. 29 ESP32 LED HIGH
This concludes the tutorial. I hope you find it helpful. In our next tutorial, we will discuss PWM (pulse width modulation) using ESP32.
Hello readers, hope you all are doing great. Today, we will discuss interrupts and timers in ESP32 and how to handle internal as well as external interrupts. So, we will discuss What is interrupt, Polling, ESP32 interrupt, Software interrupts, Hardware Interrupts, IRS (Interrupt Service routine), Steps to execute an interrupt or how is an interrupt handled in the microcontroller, Code description for ESP32 interrupts with Arduino IDE, Code description for hardware interrupts, Why is it preferred to use timer to add delay instead of using delay() function. So, let's get started:
Interrupts are used when a micro-controller needs to continuously monitor for an event while the same micro-controller is executing a particular task.
Fig 1 Interrupt
Each interrupts has a priority level and each interrupt is executed as per their priority level.
You can mask or unmask a particular interrupt depending upon their properties and your requirements.
Polling
Polling is a process that performs continuous monitoring. Basically, the processor continuously monitors the state of a specific device or a peripheral, and when the status of the device satisfies the condition, the device executes the task that was required. Then it moves on to the next device to monitor until each one has been served. The processor performs no other operations and devotes all of its processing time to monitoring, and all other tasks are suspended until the current one is completed.
Fig 2 polling vs Interrupt
So, to overcome the disadvantage of the polling method, we chose the Interrupt method.
ESP32 Interrupt
ESP32 module has a dual-core processor and each core consists of 32 interrupts. Basically interrupts are of two types:
Software Interrupts:
Fig 3 ESP32 software interrupt
Software interrupts are internal which occur in response to the execution of a software instruction. For example, a timer can be used to generate a software interrupt.
Hardware Interrupts:
Fig 4 ESP32 software interrupt
Hardware interrupts are the external interrupts that are caused by an external event. For example, an external push button connected to ESP32’s GPIO or a motion sensor will generate an interrupt (event) if a motion is detected.
ISR (Interrupt Service routine)
When an interrupt occurs during normal program execution, an ISR (interrupt service routine) or an interrupt handler is called into action. The normal program execution will be halted, and the interrupt will be executed based on the priority level of the interrupt.
Fig. 5 Interrupt service routing
Every interrupt has a fixed memory location where the address of the ISR is stored.
Interrupt Vector Table refers to a memory table or memory table that is used to store the location of an interrupt service routine.
Note: IRAM_ATTR attribute should be defined for interrupt handling. As per the ESP32 datasheet interrupt service routine should run inside the RAM. Because inside the RAM it is fast to execute a code than in flash memory and when an interrupt occurs all the other tasks will be blocked or halted till the time interrupt request is served.
Steps to execute an interrupt in ESP32
When an interrupt occurs, the microcontroller will go through the following steps:
The microcontroller will halt the current task and will store the address of the next instruction (Program Counter or PC) on the stack (lower byte first).
The microcontroller will execute the higher priority interrupt first and will block the lower priority interrupts.
It jumps to the interrupt vector table memory location that contains the address of the interrupt service routine (ISR).
The microcontroller reads the interrupt vector table and jumps to the address of the ISR. It begins executing the interrupt service subroutine.
The microcontroller returns to the location where it was interrupted after executing the RETI instruction. First, it obtains the program counter (PC) address from the stack by inserting the stack's top bytes into the PC. The execution will then begin at that address.
Fig. 6 ESP32 Interrupt Program flow
ESP32 Interrupt Code
We are using Arduino IDE to compile the code and then upload into the ESP32 board.
If you are not familiar with the procedure of getting started with Arduino IDE and hoe to compile a code in Arduino IDE then follow our previous tutorial that is Introduction to ESP32 programming series.
// Set GPIOs for LED and Push buttonconst int led = 2;const int button = 0;// Timer: Auxiliary variables#define timeSeconds 10unsigned long now = millis();unsigned long lastTrigger = 0;boolean startTimer = false;// Checks if button input was detected, sets LED HIGH and starts a timervoid IRAM_ATTR buttonInput() { Serial.println("input is available !!!"); digitalWrite(led, HIGH); startTimer = true; lastTrigger = millis();}void setup() { // Serial port for debugging purposes Serial.begin(115200); pinMode(button, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(button), buttonInput, RISING); // Set LED to LOW pinMode(led, OUTPUT); digitalWrite(led, LOW);}void loop() { now = millis(); // Turn off the LED after the number of seconds defined in the timeSeconds variable if(startTimer && (now - lastTrigger > (timeSeconds*500))) { digitalWrite(led, LOW); startTimer = false; }}
Code for ESP32 Interrupts with Arduino IDE
As we have already discussed that the interrupt could be software generated (internal interrupt) or due to hardware (external interrupt). This tutorial we are using hardware or external interrupt for demonstration. You can also use software interrupts or both in a single code, as per your requirements.
Code Description for Hardware interrupt
For the demonstration of hardware interrupt we are using a push button which is connected to the interrupt pin and a LED for the show output.
First of all, let us assign two GPIOs, one is for push button (input) and another is LED. We are using the built-in LED that is GPIO_2 and a built-in push button (named as BOOT on ESP32 board) connected to GPIO_0.
Fig. 7
In this code, we are using timer to add delay instead of using delay() function.(I will also explain that why it is preferred to use timer in order to create delay instead of using delay() function after the code demonstration).
Next, we are defining variables which are used to set the timer for adding delay after the interrupt is being detected.
The variable now is defining the current time
The variable lastTrigger is defining the time when the interrupt is detected.
The variable startTimer is used to start the time when an interrupt is detected.
IRAM_ATTR
It is required that the interrupt service routine should have the minimum possible execution time because it halts or blocks the normal program execution.
The attribute IRAM_ATTR is used to run the code (interrupt code) inside the internal RAM when an interrupt occurs because RAM (random access memory) is much faster than flash memory.
After the execution of the interrupt code or ISR the normal code will be stored or executed inside the flash memory.
Arduino Setup() Function
Inside the setup() function we are initializing the serial communication with a baud rate of 115200.
Set the push button GPIO pin a pulled up input pin.
attachInterrupt() function is used to set the button pin (GPIO_0) as an interrupt pin and it will button input (interrupt) during the falling edge.
A function called detachInterrupt() can be used if you no longer want to use a GPIO pin as an interrupt.
Change the state of the LED when an interrupt is detected for
Arduino Loop() Function
Inside the loop function which is continuously running, the buttonInput function will be called every time when an interrupt occurs , which we have defined previously inside the setup() function.
LED will turned off after the delay of 5sec once an interrupt is detected.
The variable “now” will be updated every time with the current time.
We can check the interrupt details on serial monitor as shown in the image below:
Fig 14 Serial monitor
Why it is preferred to use Timer instead of delay()?
Delay() function is a complete software process and it is mostly used because it is easier to implement delay using only software. On the other hand, when we switch to hardware delay or use a timer to add delay the process is a bit complicated to implement.
But, when we think of a practical perspective we prefer hardware delay over software delay. Because a software delay keeps the processor busy in a continuous loop and the processor need to keep all other tasks on halt.
On the other hand, if we use a timer to add delay the processor can complete some other task while the timer is playing its own part.
This concludes the tutorial. Hope you find it helpful. In our next tutorial, we will discuss the ESP32 Web Socket server.
Hello readers, hope you all are doing great. This is our 3rd tutorial in the ESP32 programming series. In our previous tutorial, we discussed the ESP32 Web server, where we created the ESP32 web server in STA mode.
ESP32 can be operated as an access point (AP) or a Wi-Fi station (STA mode). So, in this tutorial, we will create an ESP32 web server in access point (AP) mode. Here's the video demonstration of ESP32 WebServer in Access Point Mode:
As I mentioned above, in our 2nd tutorial, we already discussed the basics of the ESP32 web server. So, in this tutorial, we will only discuss how to create the ESP32 in access point mode.
For detailed information about the basics of the ESP32 web server and how client-server communication takes place, follow our previous tutorial (i.e., Create a Web Server with ESP32).
In Access Point Mode the ESP32 creates its own wireless Wi-Fi network in this mode, similar to the one provided by your existing router. In access point mode, we don't need to connect the ESP2 to a Wi-Fi network. In the Wi-Fi network it creates, the ESP32 Wi-Fi board can connect up to 5 devices.
Fig 1 ESP32 as an Access Point
So, in access point mode, nearby Wi-Fi devices such as mobile phones, laptops, or a secondary ESP32 module acting as a station can connect directly to the AP (ESP32 module) without the need for an external Wi-Fi router.
On the other hand, in Stationmode, the ESP32 wi-fi module connects to your Wi-Fi network through a router. The router acts as a conduit for communication between the web client and the ESP32. The Wi-Fi router provides the IP address. This IP address can be used by web clients to connect to the Web server on a local network.
To know about how to set up/operate Arduino IDE for ESP32 compilation, follow our first tutorial i.e., Introduction to ESP32 programming series.
ESP32 Web Server in Access Point (AP) Mode
Here we are using an inbuilt example from Arduino IDE(ESP32). You can modify the example code as per your requirements or can write your own code.
To find the Wi-Fi Access Point example in Arduino IDE :
Click on File from the top menu bar.
Place the mouse cursor on the example option from the list.
Look for the WiFi option.
There you will find the WiFiAccessPoint option, click on that and compile the program.
A screenshot is attached below to help you find the example code in Arduino IDE.
Fig 2 Wi-Fi access point example
The first task while writing the WiFi code is to add the required wifi header files or libraries in the code.
Here we are adding three libraries.
WiFi.h: This header file contains all the functions related to Wi-Fi activities like enabling the Wi_Fi, connecting to a wi-fi network etc.
WiFiClient.h: This header file is used to create a client that can connect with a specific IP address.
WiFiAP.h: This header file is used to configure and manage ESP32’s wifi module in Access Point (AP) mode.
Fig 3: Libraries
Define the LED pin or a GPIO (for peripheral interface) which we going to control through web server. Here we are using the inbuilt LED which is internally connected with GPIO2
Give a name (SSID) to the ESP32 Access Point and set the password for security purpose ( if you wish to).
While creating a web server we also need to assign a port and usually port 80 is used for local web server.
Arduino Setup() function
Inside the setup function, the LED pin is initialized as an output one and then initialized the serial monitor with a baud rate of 115200.
The next task is to configure the ESP32 Wi-Fi module in access point mode. For that, here we are calling a function called WiFi.softAP. Where we are passing two parameters, ssid and password, respectively.
After configuring the AP mode, we need to fetch the IP address of the access point by calling the WiFi.softAPIP() function and printing it on the serial monitor.
Then, after fetching the IP address, we will start the server using the server. perform.
Arduino Loop() function
After configuring the Access Point mode and initializing the server, the server will next wait for the station or client connection, which can be a mobile phone, a laptop, or another ESP32 board configured in STA mode.
Once the connection is established between the access point and the client device, the access point will wait for the data input.
A string type variable called currentLine has been defined to hold the incoming data from the client.
If there is a byte to be read from the client, then it will be stored inside the char type variable c.
HTTP header always starts with a response code e.g.: HTTP/1.1 200 ok
An HTML page will be created on the client’s browser, from where the client device can control (ON/OFF) the LED.
Different URLs will be created to turn ON and OFF the LED depending upon the HTML input received from the client device i.e., H (to turn ON the LED) and L ( to turn OFF the LED).
Client.stop() function is responsible for closing the connection between Access Point and client or station device.
Note: If you need any guidance regarding how to upload or compile a code for the ESP32 module in Arduino IDE, follow our first tutorial on the ESP32 programming series.
Testing ESP32 web server with hardware in Access Point with Arduino IDE
Here we are going to control the ESP32’s inbuilt LED through an ESP32 web server (AP mode).
We will connect our station or client device through Wi-Fi to the ESP32 module, which (ESP32) is currently acting as an access point (AP).
To establish the connection go to your mobile phone’s Wi-Fi setting.
The Access Point is advertising itself with a pre-defined SSID so that the station devices or clients can find the AP device and can communicate with each other.
If you find a wi-fi device (AP) named ESP32_AP (or as per your SSID) connect to that after entering the assigned password.
Fig. Scanning for available Wi-Fi devices in mobile phone
Fig. Connected with ESP32 AP
As we are using the inbuilt LED, no external components are required.
After connecting to the access point, you can find the IP address of the AP device printed on the Serial Monitor. As shown in the image below:
Fig.: Serial Monitor
Enter the IP address in the browser. Now you can turn the LED ON or OFF using the web page as shown in the images below.
A web page with URL 192.168.4.1/H will be displayed on the browser when LED is turned ON
Fig.: URL when LED is turned ON
LED is blue color represents the inbuilt LED which is connected to GPIO_2.
Fig.: ESP32 LED ON
Another web page with URL 192.168.4.1/L will be created when the AP will receive the input to turn OFF the inbuilt LED. As shown in the image below:
Fig.: Web page displaying the LED off state.
This concludes today’s tutorial. We hope you find it helpful.
In our next tutorial, we will discuss another ESP32 feature that is BLE (Bluetooth low energy).
Hello readers, I hope you all are doing well. Welcome to the Section 2 (ESP32 Features) of the ESP32 Programming Series. ESP32 is equipped with numerous built-in features and in each chapter of this Section 2, we will explore one of these ESP32 features in detail.
In the previous Section(Section 1: ESP32 IDEs), we installed different software IDEs to program ESP32 boards. Among these IDEs, we are going to use Arduino IDE for programming ESP32. So, I hope all of your tools are configured properly and you are ready to explore the built-in features of ESP32.
Today's the 1st Chapter of Section 2, and here we will discuss How to communicate with ESP32 Bluetooth Classic from a smartphone using Arduino IDE.
Here's the video tutorial for ESP32 Bluetooth Classic:
ESP32 is equipped with 3 wireless communication protocols:
Bluetooth Classic
Bluetooth Low Energy(BLE)
Wi-Fi
Before going forward, let's first have a look at the basic features of BT Classic:
What is Bluetooth Classic?
Bluetooth is a short-range communication(wireless) technology, used in electronic devices(i.e. mobile phones, computers, LED, headphones, speakers etc.) for wireless communication over a short distance, approximately 15m. Bluetooth operates at a 2.4GHz ISM band. Bluetooth uses low-energy radio waves for data communication between Bluetooth-enabled devices.
Now, let's design the code to communicate over ESP32 Classic BT:
ESP32 Bluetooth Classic
We are using Arduino IDE for code compiling and uploading to the ESP32 module. I hope you have already installed ESP32 Boards in Arduino IDE. So, let's design a simple project to understand the working of ESP32 Bluetooth Classic:
Project Description
First of all, we will install a "Serial BluetoothTerminal" App from the Google Play Store to communicate with the ESP32 Classic BT.
In this project, we will first enable the ESP32 Classic Bluetooth, so that we can connect it to our smartphone. After a successful connection, we will send data from our smartphone(Serial Bluetooth Terminal App) to the ESP32 Serial Terminal and vice versa.
So, let's first understand the ESP32 BT Code and then will install the Serial Bluetooth App from the Google Play Store:
Code for ESP32 Classic BT
Open Arduino IDE and navigate to "File > Examples > BluetoothSerial > SerialtoSerialBT".
This code utilizes BluetoothSerial Library, it's pre-installed with Arduino IDE but if you can't find it in the Examples, you can manually Download Bluetooth Serial Library and add it from Library Manager in Arduino IDE.
Upload this code to your ESP32 Microcontroller Board.
Here's the complete code:
#include "BluetoothSerial.h"
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to enable it
#endif
BluetoothSerial SerialBT;
void setup() {
Serial.begin(115200);
SerialBT.begin("TEP_ESP32_BT"); //Bluetooth device name
Serial.println("The device started, now you can pair it with bluetooth!");
}
void loop() {
if (Serial.available()) {
SerialBT.write(Serial.read());
}
if (SerialBT.available()) {
Serial.write(SerialBT.read());
}
delay(20);
}
Let's understand the code working:
How the Code Works
First of all, we added the Classic Bluetooth Library named "BluetoothSerial", it has all the routines/functions required to enable Bluetooth and to communicate with other devices.
#include "BluetoothSerial.h"
Next, we placed a check to ensure that Classic Bluetooth is configured properly and is discoverable to other devices:
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to enable it
#endif
Next, we created a Bluetooth object "SerialBT" of class BluetoothSerial to initialize the Bluetooth stack and communicate serially with ESP32 Classic Bluetooth:
BluetoothSerial SerialBT;
Setup() Function
Initial Configurations of the project are added in the Setup() function. In our code:
First, we initialized the Serial Port at a baud rate of 115200.
Next, we initialized the SerialBT object and assigned a unique name "TEP_ES32_BT" to our Bluetooth device, this name will appear in the Bluetooth Search List.
Finally, printed a welcome message on the Serial Monitor.
void setup() {
Serial.begin(115200);
SerialBT.begin("TEP_ESP32_BT"); //Bluetooth device name
Serial.println("The device started, now you can pair it with bluetooth!");
}
Loop() Function
The Loop() Function is an infinite loop and is equivalent to while(1) in normal C Language. In our code, we have placed two if checks:
The first "IF Check" is monitoring the ESP32 Serial Terminal.
If we send any data from the Serial Terminal, this data will be transmitted to the SerialBT.
The second "IF Check" is monitoring the SerialBT.
If we receive any data via ESP32 Classic Bluetooth, we will print it on the Serial Terminal.
void loop() {
if (Serial.available()) {
SerialBT.write(Serial.read());
}
if (SerialBT.available()) {
Serial.write(SerialBT.read());
}
delay(20);
}
So, I hope you have understood the working of this ESP32 Classic Bluetooth code. Now, let's install the Serial Bluetooth Terminal App from the Google Play Store:
Serial Bluetooth Terminal App
Make sure your mobile's Bluetooth is enabled.
Open the Google Play Store on your Smartphone and make a search for "Serial Bluetooth Terminal" and install it.
If we are connecting with the ESP32 BT for the first time, we need to pair it first.
Open the Serial Bluetooth Terminal app and click on the "Devices" tab.
It will scan the list of all the available Bluetooth devices:
[Image]
Now, Pair with the ESP32 Classic BT device named "TEP_ESP32_BT".
Click on Pair.
We have successfully paired the ESP32 BT with the smartphone's Bluetooth.
ESP32 BT to Smartphone - Data Testing
Open the Bluetooth Terminal App and click on the Connect Button at the top:
[Image]
Open the Serial Monitor in the Arduino IDE and set the baud rate to 115200:
[Image]
As shown in the below figure, when we send data from the Serial Monitor, it communicates over Classic Bluetooth and appears in the BT Terminal App.
Similarly, when we send data from the BT Terminal App, it appears on the Serial Monitor of Arduino IDE.
So, that's how we can communicate between ESP32 and smartphones over Classic Bluetooth. In today's lecture, we communicated simple text data to understand the working principle. In the upcoming lectures, we will send complex data(i.e. commands & sensor values) via Classic Bluetooth.
Now, let's have a look at some theoretical knowledge about Classic Bluetooth:
BLE vs Bluetooth Classic
Fig: BLE vs Classic Bluetooth
Bandwidth: Bluetooth can send a large amount of data, while BLE sends small chunks of data.
Compatibility: Classic Bluetooth and BLE are not compatible with each other. A Bluetooth-supported device can’t communicate with BLE supported device.
But, a device having BT V4 (Bluetooth version 4) can discover both BLE and Classic Bluetooth devices.
Power consumption: The classic Bluetooth consumes more power than BLE.
Pairing: In Bluetooth classic pairing is necessary before sharing data between Bluetooth devices for security purposes. On the other hand, BLE technology doesn't ask for pairing before data transmission.
Number of active devices: In traditional Bluetooth, a maximum of 7 slave devices can be connected with the master Bluetooth at a time. Though classic Bluetooth can connect with multiple nodes/slave devices at a time but it can exchange data with only a single node at a time.
Bluetooth Evolution
The initial Bluetooth version (V1.0) was riddled with bugs and limitations.
Bluetooth 2.0 was created as a result of various modifications and improvements to the basic version 1.0.
Bluetooth 2.0's most notable feature was the enhanced data rate (EDR).
Fast modulation technology and a data rate of up to 3Mbps are used in Enhanced Data Rate mode.
Despite improvements in the basic version, Bluetooth 2.0 lacks a security feature.
Bluetooth 2.1 added a security feature called "Pairing" as well as a faster data rate.
Another updated version, Bluetooth 3.0, included a Wi-Fi feature, but it was rarely used, and when it was, the features were similar to the Bluetooth 2.1 version.
Bluetooth 4.0 was the first version to include the Bluetooth low energy feature (BLE).
The most recent Bluetooth version is v5.2, which supports both Classic Bluetooth and BLE and consists of the following features:
EATT (enhanced attribute protocol)
LE (Low Energy) power control feature (LEPCF)
LE Audio
Bluetooth Network topology
Classic Bluetooth forms a piconet. A piconet has a single master and multiple(max 7) slaves. Each piconet has its own hopping sequence.
Fig: Classic Bluetooth Network topology
Classic Bluetooth can operate on both point-to-point and point-to-multi-point network topology. In traditional Bluetooth, a maximum of 7 slave devices can be connected with the master Bluetooth at a time. Though, classic Bluetooth can connect with multiple nodes/slave devices at a time, but it can exchange data with only a single node at a time.
Bluetooth Clock
In classic Bluetooth, the piconets are not synchronized.
The clock is one of the most important aspects of Bluetooth. In a Bluetooth connection, the master device has a clock that is used to split the time on each physical channel. Clocks on all slaves in a connection are synchronized to the master clock.
Bluetooth clock synchronization is essential because the radios must agree on when to transmit. Because Bluetooth uses precise timeslots for transmissions with devices alternating, if the clocks are not synchronized, there may be issues with devices transmitting at the incorrect time.
Classic Bluetooth transmitting power
It is defined in multiple classes:
Class 1: +20dBm maximum.
Class 2: Up to +4dBm.
Class 3: Up to +0dBm.
Classic Bluetooth Data transmission modes
Generally, there are two data transmission modes:
Basic Rate (BR): BR is the first Bluetooth protocol which is implemented in Bluetooth v1.0. It uses one of the FSK (frequency shift keying) modulation techniques known as Gaussian frequency-shift keying (GFSK) and communicates data at the 2.4 GHz ISM band.
Enhanced Data Rate (EDR): It's a Bluetooth specification that allows for a higher data rate or speed. It is not available in all Bluetooth versions, and its availability is dependent on the Bluetooth version and profile. EDR uses pi/4-DQPSK (differential quadrature phase-shift keying) and 8DPSK (differential phase-shift keying) modulation techniques with data rates of 2Mbps and 3Mbps respectively.
Bluetooth packet format
When two devices communicate data over Classic Bluetooth, they use SPP (Serial Port Profile)
Fig. Bluetooth packet format
Enhanced data rate packet sends the Access code and header using the basic rate and this process uses GFSK (Gaussian Frequency Shift Keying). The guard gives the time to change the modulation to EDR modulation and then the synch word (64 bits), payload, and Trailer (4 bits) bits are sent using EDR (enhanced data rate) modulation.
So, that was all for today. In the next lecture, we will communicate between ESP32 and smartphones via BLE(Bluetooth Low Energy). Till then take care. Have a good day!!!
Hello geeks, Welcome to our new project. As most readers have already seen the coffee vending machine or maybe you are drinking coffee while reading this article and if you are a tinker or a geek, it must have come to your mind how to make a coffee vending machine on your own. In today's tutorial, we are going to learn how to make a Smart Coffee Vending Machine using Arduino with Proteus Simulation for the same.
We can use this project for an engineering project’s showcase for electronics, electrical engineering students, and can be used in offices as well.
Coffee is the second most popular drink in the world and it is one of the oldest beverages of the world. According to Wikipedia, more than 2 billion cups of coffee are consumed every day in the whole world. As engineers or working professionals, we all know how coffee is very important for us. Having a good coffee makes our day better and refreshes the mood. Research shows coffee drinkers tend to live longer but when keeping it in moderate consumption. And making a good coffee is one of the most skillful jobs and time-consuming processes as we want our coffee in minutes. Now here our project comes to the picture, this smart coffee vending machine can make a good coffee in a couple of minutes. There are various flavors of coffee and our smart coffee vending machine can provide us with 4 different flavors which are the most commonly loved such as Latte, Cappuccino, Espresso, and Cafe Mocha. Here's the video demonstration of this project:
As we are going to design this project using Proteus Simulation, instead of using real components. As in the simulation, we can figure out the issue which may occur while working on real components and that can damage our components.
Proteus is the software for simulation and designing electronics circuits. As Proteus software has a big database of electronics components but still it does not have few modules in it like Arduino boards or LCD modules etc.
So we have to install the libraries, which we are going to use in this project:
Arduino Library for Proteus: We have to add the Arduino boards to the Proteus components list.
LCD Library for Proteus: We have to add the LCD module to Proteus Suite.
You can download this whole project for example Proteus Simulation and Arduino Code, by tapping the below button
Smart Coffee Vending Machine using Arduino
These are required components for Smart Coffee Vending Machine, as follows:
20X4 LCD display: It is used to display user-related messages like the state of the vending machine.
Arduino UNO: It is used as the brain of our project. All operations and decision-making will be done using this microcontroller.
DC motor: It is used for dispensing the ingredients of coffee and the mixer.
Buttons: It is used as a user interaction option.
As a suggestion, whenever we make a project, it should be like a product, as it should be user friendly and interactive, so considering that we have used an LCD module to display the messages related to available coffee flavors and their individual prices so that users can easily select them using buttons and DC motors to pour the ingredients related to coffee like water, sugar, coffee powder, and milk, and a mixer for blending the coffee.
We have connected the LCD using an I2C GPIO expander as we have limited GPIO pins to connect other peripherals with Arduino UNO. I2C Gpio expander requires only two pins as we know that I2C uses SCL(Serial Clock) and SDA(Serial Data) pins for communication.
Components Needed:
Arduino UNO
LCD display
4 Buttons
8 Motors
PCF8574
Components Details
Arduino UNO:
We can use any Arduino development board but here in this project, we have used an Arduino UNO board.
Arduino UNO is one of the programmable, open-source microcontroller boards of the Arduino family.
It contains an Atmel’s Microchip ATMega328 or ATMega328P microcontroller which has Harvard architecture 8-bit RISC processor core and 32 KB flash memory.
Arduino UNO comprises 14 digital I/O pins out of which 6 are PWM pins as well and 6 Analog I/O pins with 10 bits resolution(0-1024).
Arduino UNO has only 1 hardware UART pin(but we can use other pins also for UART communication using SoftwareSerial library in Arduino), 1 I2C, and 1 SPI.
PCF8574:
We have used this IC as a GPIO expander for our project as we have restrictions on the availability of GPIO pins in Arduino UNO.
It is an 8-bit I/O, silicon-based CMOS GPIO expander.
It can be used to write data on the pins and also can read data on those pins.
It uses the I2C protocol for communication with the master device.
As we know that I2C protocol uses the slave address to send or receive data from slaves, so for that it has 3 pins A0, A1, A2 for setting the slave address.
Slave address for PCF8574 starts from 0x20 to 0x27. That means we can add only 8 PCF8574 IC directly to a master controller.
The following image explains the logic of the slave address of PCF8574.
It is used for connection for the LCD module with Arduino UNO in our project.
If you want to learn more about IC PCF8574, you can refer to the datasheet using the following URL: PCF8574 Datasheet
LCD display
The LCD display is used to show the user-related messages in this project.
LCD is a short form of Liquid Crystal Display which is basically built using Liquid Crystal technology.
There are different sizes of LCDs available, in this project we have used 20X4 size.
Here 20X4 signifies that it can display 80 ASCII characters at a time.
There are 16 pins in the LCD. We will not use every pin of LCD in this project.
It has 8 data pins, 1 Read/ Write select pin, 1 Register mode pin, 1 Enable pin, 2 pins for backlight, and 2 pins for power supply, 1 contrast control pin.
There are mainly two types of register in the LCD: Command Register and Data Register.
When we set the RS(Register Select) pin to logic High then it will select the data register mode and in logic Low, it will select the command register.
To display the data on LCD we will set the RS pin to logic High.
Proteus Simulation of Smart Coffee Vending Machine :
Now, it's time to start designing the Proteus Simulation of our Smart Coffee Vending Machine.
Most importantly, ensure that Proteus is installed on your PC and download all the required libraries for Proteus ahead.
For this project, we are going to need libraries of Arduino and LCD modules.
Make sure that you have read about how to use libraries in Proteus software.
Let’s create a new project, open the new project in Proteus and import all the required components which we are going to use, and place them within the working area.
We need the following components, so select all of them from the Proteus component library.
Circuit Diagram and Working:
Now let’s design our circuit, first place all the selected components in the Proteus Workplace, as shown in the image below:
We will start connecting the LCD module and PCF8574, as we are using only 4-data pin-mode of LCD.
After that, we will start the GPIO expander PCF8574 I2C connections, connect the SDA, SCL pins of PCF8574 to Arduino UNO’s SDA, SCL pins which are A4, A5 pins of the development board.
As we know, we have to set the slave address of PCF8574 using A0, A1, A2 pins. And in this project we are going to use the slave address 0x20, therefore for that, we have to connect all pins to the ground. (As we have already seen in the above PCF8574 addressing image)
In the next step, we are going to connect the buttons to Arduino digital pins D2, D3, D4, D5 as "Latte", "Cappuccino", "Espresso", "Cafe Mocha" flavors respectively and another terminal of the buttons is connected to ground. As we are going to use the buttons inactive low condition which means, when we press the button it will give us a logical LOW state.
There may be a doubt in your mind why we have not used any PULL-UP resistors with buttons because we will handle that in our code. Arduino UNO comes with an internal PULL-UP resistor of 20-50 KOhms.
Now connect the dc motors for each container, Water, Coffee, and Sugar container’s motors are connected with Arduino’s digital pins D10, D12, D11 respectively. Connect the coffee outlet motors for each type of Latte, Cappuccino, Espresso, Cafe Mocha with digital pins D6, D7, D8, D9 respectively. And at last, connect the mixer with the D13 pin.
As we have mostly completed the wiring part, the first thing which we must make sure of before going to start our simulation is that all components should have adequate power supply and ground. And ground must be common in the whole circuit.
Now we hope you have understood the connections and you have already done it, so it is time to move to the coding part of our project.
Arduino Code for Smart Coffee Vending Machine
If you already know about the syntax and structure of Arduino sketch, it's a good thing, but if you have not been familiarized yet, no need to worry, we will explain it to you step-by-step.
Arduino coding language mostly follow the syntax and structure of C++ programming language, so if you are familiar with C++, then it would be like a cup of cake for you to understand the code but still if you don’t have any background knowledge, you don’t have to worry again, we have your back.
Arduino Coding follows a strict structure, it has mainly two sections. we have to write our code in those two functions.
void setup()
void loop()
As we are going to explain the Arduino code, it would be easy to understand if you have opened the code in the Arduino IDE already.
Declaration code:
When we start our code, we will first include all the required libraries which we are going to use in this project.
So our first step would be to download the required libraries if they are already not pre-installed in the Arduino IDE.
Mainly we will use only two libraries, one for LCD display and the other for I2C communication.
And I2C related functions come in the Wire library which will be pre-installed in Arduino ID, we don't have to install it explicitly.
For the LCD module, we will use the Liquid Crystal_I2C library that we have to install.
We can install libraries related to Arduino from the Arduino IDE by going to ‘Sketch > Include Library > Manage Library’. Now in the library manager, we can search for our required libraries. We can install the libraries using zip files also.
>> Now, as we have installed all the required libraries. Let’s include them in our sketch.
After that, we will define the pins which we are going to use in our project.
We have to define them globally so that we can use them in all functions.
You must be having a doubt why we have not defined pins for I2C.
Because those pins are pre-defined in the Wire library, we can not assign any other pins for I2C communication.
Now we will define and declare all the variables which are required in our project.
There is an array for the price of a coffee with the size of 4, as we will only provide only 4 types of coffees and a string type variable for storing the name of flavors of coffee.
Arduino Setup() Function:
In this Arduino Setup() function, we will write a section of code that will only run once.
So mostly we will write the declarations, define the type of pins and initialize the peripherals such as the LCD module.
We want to take user input from the buttons therefore we will declare them as INPUT type.
We have not connected PULL UP resistors in buttons as you have read above, we will handle that in the code therefore we have declared it as INPUT_PULLUP mode.
We have declared motor pins as OUTPUT mode because we want to control the motors.
After that we will initialize the LCD module then we will turn on the backlight of LCD, set the cursor to 0,0 index and using ‘lcd.print()’, we will print the welcome message on the LCD module.
In the setCursor function, the first argument is used for X-Axis and the second argument is for Y-Axis.
It will display the welcome message for 1 sec as we have given a delay for 1000 milliseconds after we clear the display.
Arduino Loop() Function:
Arduino Loop function runs after the the ‘void setup()’ function.
In this section, we will write the code which is required to run in a continuous loop. So we will write our main application code here.
So when the code reaches the void loop section, first we will display the flavor and the price of the coffee on LCD display as we want to show the user what type of coffee our vending machine makes and the price of those individually.
>> Now we will write the section for reading the user input from the buttons. As we have set that the condition will be true when the button will be logic LOW state.
>> Now when the user will press the button, the state of the button’s pin state will be changed to logic LOW state and then our ‘if condition’ will be true and code and our operation will enter in the ‘if condition’ section.
>> Here we will display to the user the current process stage of the coffee making. So we will clear the LCD display and then set the cursor to 0,0 index. After that we will display the message for collecting the ingredients.
As we have not cleared the display, it will display the same message.
After 1 second delay, we will start the water container motor for pouring the water for 2 seconds.
Thereafter we will set the water’s container pin to LOW and Sugar’s container motor pin to HIGH for 2 seconds, similarly for the coffee’s container pin.
Now we will start the motor for the selected flavor of coffee for 2 seconds and then stop it.
As now our selected coffee is getting ready so we will display the message for the same.
To display any new message, we have to clear our display with pre-occupied text.
Now we will start the mixer motor for 10 seconds to mix all the poured ingredients.
>> Now our selected coffee is ready. So we will clear the LCD display and set the cursor, and will print the message regarding the prepared coffee with the price of it.
Results/Working:
Below is the Flow diagram of coffee vending machine:
Let’s understand the code with an example, we will go with the starting step.
Power ON the device, the machine will display the welcome message that you can change from that code as per your choice.
That message will be shown for 1 second thereafter it will clear the display.
Now it will display the type of coffee as "Latte", "Cappuccino", "Espresso", "Cafe Mocha" and their respective prices.
Let’s suppose, the user wants to have a Latte today, so he/she will press the button for the same, thereafter our coffee-making process will start.
The first LCD display will show the message “Wait a Moment Collecting Ingredients” and it waits for 1 second.
Thereafter it will start pouring the water for 2 seconds, then it will stop that motor.
After that, it will start to pour sugar for 2 seconds, then stop that motor.
At last, it will start to pour the coffee for 2 seconds, then stop that motor.
It will start the motor of the selected type of coffee to dispense the coffee to the container and then it will wait for 1 second.
Now LCD will display the message for coffee getting ready as "Wait a Moment Your’s Rich Latte is getting ready…” as the user has selected Latte that’s why it shows “Latte is getting ready… “.
Now we will start the mixer to mix all the ingredients for 10 seconds.
Again we will clear the LCD display to show the message for prepared coffee as “ Your's Rich Latte is ready. Please Collect it Your's Amount - 5/-”.
Then it waits for 5 seconds and clears the display and again shows the price and the available types of coffee.
As Proteus requires the hex file of the code to run the simulation.
So for that, open the Arduino IDE and please verify your code before making a hex file by clicking on the ‘Verify’ button to remedy any errors.
To get the hex file from the Arduino IDE click on “Sketch > Export Compiled Binary”.
Your hex file will be generated successfully now put that hex file to the Arduino UNO board in the Proteus software.
Everything is now in place, it's time to run the simulation and get a nice virtual coffee.
I hope you have understood the whole working of our smart vending machine project and enjoyed it as well. I think we have explained pretty much everything but still if you have any doubts or improvements please let us know in the comment section.
Thanks for giving your valuable time for reading it.
Hello readers, today we will learn about the messaging protocol supported by ESP32(called MQTT protocol), which is used for IoT applications. The communication protocol to be used for data transmission and connectivity in web-enabled devices depends upon the type of IoT application.
The Internet of Things (IoT) is a network of interconnected computing devices like digital machines, automobiles with inbuilt sensors, having unique identifiers and the ability to communicate data over a network without the need for human intervention.
Before implementation, let's first have a look at what is MQTT Protocol?
MQTT stands for Message Queuing Telemetry Protocol and is a messaging or communication protocol used for IoT applications.
In MQTT protocol, a publisher sends a message to the broker with a specific topic tag, and the broker forwards this message to all the Subscribers of that mentioned topic.
So, in order to understand MQTT Protocol, we need to discuss these 4 terms:
MQTT Topic
MQTT Publisher
MQTT Broker
MQTT Subscriber
Note:
The OASIS technical committee is the in-charge of MQTT specifications. The OASIS or the Organization for the Advancement of Structured Information Standards is a non-profit organization dedicated to the development, convergence, and implementation of electronic business standards.
Fig 1: ESP32 MQTT Protocol
MQTT Topic
In MQTT protocol, a Topic is simply a UTF-8 string i.e. "Arduino", "ESP32", "Beginner Tutorials" etc.
MQTT Clients can subscribe to these Topics and are called Subscribers to that Topic.
MQTT Broker sends messages to the Clients based on their Topic subscription.
A topic may have multiple levels, separated by a forward slash.
MQTT Publisher
MQTT Publisher(also called MQTT client), as the name suggests, publishes the message on a specific topic and sends it to the broker.
In simple words, a publisher sends a message(normally a string) to the MQTT Broker, and this message also contains the Topic information.
MQTT Broker
MQTT Broker(also called MQTT server) acts as a coordinator between the subscriber and the publisher in order to create communication.
The broker's job description is as follows:
Receiving messages from the publisher
Filtering received messages based on assigned Topics from the publisher.
Determining the interested subscriber in each message based on the assigned Topic
Finally forwarding the messages to subscribers
MQTT Subscriber
MQTT Subscriber(also called MQTT client), subscribes to the MQTT Topics and receives the messages from the MQTT broker, sent by the Publisher.
How does MQTT Work
This messaging protocol follows the Publish and Subscribe model. The Publisher and Subscribers of the message, communicate via Topics and are separated from one another. The broker is in charge of their communication. The broker's job is to filter all incoming messages and distribute them to the subscribers in the most efficient way possible. The broker pushes the information to the client whenever something new becomes available, so the client doesn't have to pull the information.
Because there are so many ready-to-use brokers and client applications, getting started with MQTT is a breeze.
Fig 2: MQTT Publish and Subscribe architecture
MQTT Features
Light Weight
It is a lightweight and versatile IoT communication and data transfer protocol aimed at IoT developers who want to strike a compromise between flexibility and network resources.
All the MQTT messages have a small footprint which adds a lightweight feature to this protocol.
In MQTT every message has:
2-byte header (fixed)
A 256 MB message payload
A 2-byte variable header (optional)
Security
MQTT protocol implementation will allow you to use your User name and password for security purposes. If you added the authentication feature while creating the MQTT server then stranger clients can’t communicate to your MQTT server.
Bidirectional communication
There is no direct link between clients in MQTT.
A broker connects the subscriber and the publisher in this messaging protocol. As a result, the subscriber and publisher can converse about any issue that the broker handles.
Eliminate polling
Polling is a procedure in which the controlling devices wait for input from an external device to determine whether the device is ready to broadcast data. MQTT protocol follows instantaneous push-based delivery. So there is no need to continuously check or poll before sending data which results in reduced network traffic.
Storage and forwarding
MQTT supports the storage and forwarding of persistent messages on the broker. Clients can ask for the broker to keep messages after they've been published. When this feature is used, any persisted message will be broadcast to a client who has subscribed to a topic. The most recent persistent message is the only one that gets saved. Unlike typical messaging queues, however, the MQTT broker prevents these persisted messages from being backed up inside the server.
Decouple and scale
It enables changes in communication patterns and functionality without causing a system-wide ripple effect.
Simplifies communication
As we have already discussed that MQTT follows Subscriber and Publisher architecture where the broker acts as an interface between the clients. So there is no need of computer to computer interface hence providing simplified communication.
Dynamic targeting
It also supports authentication, publishing, subscribing, keep-alive pings.
It runs on top of Internet protocol and TCP.
Quality of service
Quality of service is a kind of indicator which ensures that messages are exchanged between the sender and the receiver. There are three levels of QoS:
just once - this level is not reliable but is the fastest one
at least once - this level is the default mode
just once - this level is the most reliable, but slowest
MQTT Applications
MQTT protocol is mostly used in IoT(internet of things) applications for data transmission. The data can be read from some sensors or some temperature value.
Fig 3: MQTT Applications
Some other applications where you can use it are :
Security and surveillance
Industries & energy
Logistics
Medical & healthcare
How to Publish a message using ESP32 MQTT?
The MQTT protocol is another functionality supported by the ESP32 module. To implement MQTT, we're utilizing the Arduino IDE.
If you're not sure where to begin coding with the ESP32, check out our prior tutorial, Introduction to the ESP32 Microcontroller Series.
Code Description
Global Declarations
Adding libraries will be the initial stage.
To use ESP32 MQTT to send a message, you'll need two libraries.
#include <WiFi.h>#include <PubSubClient.h>
PubSubClient library is not available in ESP32’s library list. You need to download the library first and add the library into Arduino IDE.
Fig 4: Adding library to Arduino IDE.
Click on Add. Zip Library.
Browse for the downloaded library file and add.
PubSubClient library and Wi-Fi library
We covered Wi-Fi in detail in our previous tutorial, ESP32 web server.
PubSubClient is a client library that may be used with MQTT applications.
Add your SSID and Password to create a wi-fi connection. Follow our previous tutorial, ESP32 web server, to learn more about ESP32 Wi-Fi.
const char* ssid = "public"; //add your SSIDconst char* password = "ESP32@123";// add your password
Initialize the Wi-Fi. (follow the previous tutorial for more details about (ESP32 Wi-Fi)
Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi.."); }
Print Wi-Fi status on serial monitor
Serial.println("Connected to the Wi-Fi network");
Define the MQTT server's address and port address.
To do so, we use the PubSubClient object's setServer function.
The address and port, both defined early in global variables declaration, will be passed to this procedure as the first and second arguments, respectively.
setCallback method to define a handling function.
When a MQTT message is received on a subscribed topic, this handling function is called. This function's code will be saved for later.
client.setServer(mqttServer, mqttPort); while (!client.connected()) { Serial.println("Connecting to MQTT..."); if (client.connect("ESP32Client", mqttUser, mqttPassword )) { Serial.println("connected to MQTT"); } else { Serial.print("failed to connect "); Serial.print(client.state()); delay(2000); } }
Publish a topic
client.publish("esp/test", "ESP32");
Subscribe for the topic you want to.
client.subscribe("esp/test");
Finally, we'll subscribe to the topic we're interested in. Other clients' communications will be published on that topic, and we will receive them this way. For that purpose, we use the subscribe method, which takes the name of the topic we want to subscribe to as an argument.
Arduino loop() Function
The next task will be to connect with the MQTT server which will happen in the main loop
Here, the device will keep trying to connect with the server unless it establishes a connection.
In order for the client to process incoming messages and maintain the connection to the MQTT server, the function should be invoked on a regular basis.
MQTT Testing
For testing purposes, we will use MQTT_lens which is a Google Chrome application to establish a connection with the broker.
Here are some screenshots of the MQTT lens broker:
Create a connection after adding the following details:
Connection, Hostname, Port etc.
Fig: MQTT_lens broker
This concludes today’s tutorial, hope you find it helpful.
Hello readers, I hope you all are having fun in your lives. Welcome to the 2nd Chapter of Section-2 in the ESP32 Programming Series. In today's lesson, we'll go over another built-in feature of the esp32 module that helps it stand out from the competition: BLE or Bluetooth Low Energy.
In the previous tutorial, we discussed the Classic Bluetooth in ESP32, which is considered the predecessor of Bluetooth Low Energy(which we are going to discuss today). We will first look at, what is BLE? and why is it used?, and then will design some examples to utilize the ESP32 BLE in Arduino IDE.
There have been numerous adjustments and upgrades to Bluetooth's characteristics since its inception, where Bluetooth 4.0(also called BLE or Bluetooth Smart) is the most influential.
BLE or Bluetooth Smart is also known as Wibree. The Wibree protocol was designed by Nokia in 2006 and was later included in Bluetooth 4.0 as Bluetooth Low Energy in December 2009.
Bluetooth Low Energy is a slightly different protocol from Classic Bluetooth, which is used in phones, headphones, TVs etc. Rather than continuously streaming data, BLE "servers" can "notify" clients to send the data chunks on a regular basis(which makes it preferable over traditional Bluetooth). As a result, BLE is better suited to low-power IoT applications that don't require significant volumes of data.
Both the server and clients now utilize a "service UUID", to determine which server and client needs to be connected. There are various "characteristics" that can be found inside these services.
Bluetooth Low Energy was developed and promoted by the Bluetooth Special Interest Group (SIG) for use in healthcare, beacons, fitness, home entertainment etc. It does not work with standard Bluetooth and does not have any compatibility, although it can coexist with BR/EDR and LE.
The Bluetooth Special Interest Group (SIG) recognizes several industries for low-energy technology, including smart homes, health, sport, and fitness.
Difference b/w traditional Bluetooth and BLE
Bluetooth Technology was created with the intention of allowing data to be streamed indefinitely. That implies you can send and receive a large amount of data over a short distance with Bluetooth.
It's crucial to discuss power usage while discussing the differences between Bluetooth and Bluetooth Low Energy. Bluetooth Low Energy is intended to transfer data only when the client is available to receive the data from the server; otherwise, the BLE device will go into low energy or sleep mode. Thus, use significantly less power as compared to traditional Bluetooth, while retaining a similar communication range.
Bluetooth Low Energy uses the same 2.4 GHz radio frequencies as traditional Bluetooth, but a different FHSS (Frequency Hopping Spread Spectrum) technique.
Classic Bluetooth uses Scatter-net topology whereas BLE uses Star topology.
Although Bluetooth Low Energy differs from the previous Bluetooth Basic Rate/Enhanced Data Rate protocol, both can be supported by the same device: the Bluetooth 4.0 specification allows devices to implement any or both of the LE and BR/EDR systems.
Because both, Bluetooth Low Energy and traditional Bluetooth use the same 2.4 GHz radio frequencies, allowing dual-mode devices to use a single radio antenna.
How does BLE work?
BLE Client & Server
Any BLE device can operate as both a server and a client.
Server ESP32 will announce its presence to nearby clients so that clients can establish a connection with the BLE server for communication.
Broadcast mode and mesh networks both are also supported by BLE.
In broadcast mode, only the BLE server transmits data to all the connected clients.
In mesh mode, all the devices are connected to each other. Therefore, all devices can communicate with all other available devices.
GATT
GATT is an acronym for Generic Attributes.
It defines a data structure that is visible to all BLE devices linked to it. GATT defines how BLE devices can communicate with each other. Understanding this structure is crucial to understand the working of BLE.
The GATT protocol includes a set of commands that allow the client to learn more about the server.
Read through all of the descriptors for a specific characteristic.
Find out everything there is to know about a specific service.
Find qualities that match a UUID.
Find UUIDs for all major services.
Find a service using a UUID.
For a particular principal service, locate subsidiary services.
BLE Service
A service is nothing more than a collection of data, such as data from a temperature sensor.
A profile, which is made up of multiple services, is at the top of the structure. Typically, a BLE-supported device will have multiple services.
The SIG has preset services for a variety of data kinds, such as battery level, weight, blood pressure, heart rate, and so on.
Every service has at least a single feature and can also refer to different services.
BLE Characteristics
The characteristic attribute is always held by a particular service, and it is where the hierarchy's real data is stored.
The characteristic has two attributes:
Characteristic value.
The characteristic declaration contains the metadata.
It essentially consists of the operations that can be used like Indicate, read, write, notify, broadcast etc.
UUID or Universally Unique Identifier
In a Generic Attribute (GATT) profile, the UUID is a universally unique 128-bit or 16-byte integer that is used to identify profiles, services, and data kinds.
Note:
In the code description, we will provide a link where you can generate a new UUID.
BLE network topology
BLE uses Star and mesh topology for communication.
A Broadcast Type or a Connection Type communication between two BLE devices is possible. The 'broadcaster' BLE Device sends data to any 'observer' BLE Device in broadcasting. It's a data transfer that only goes one way.
A 'Connection' between the BLE Devices is required for two-way communication. A Central (Master) BLE Device continuously checks for advertising data packets sent by a Peripheral (Slave) BLE Device.
BLE Applications
BLE is ideal for applications that need to exchange modest amounts of data on a regular basis.
BLE is used extensively in healthcare, fitness, tracking, beacons, security, and home automation etc.
Bluetooth Low Energy is natively supported by mobile operating systems such as iOS, Android, and Windows Phone, as well as macOS, Linux, Windows 8 & 10.
ESP32 BLE
You can use ESP32 BLE either as a BLE server or a client.
Examples are available in the ESP32 BLE library(Arduino IDE) which you can use to implement BLE services.
Note:
The Arduino IDE must have the ESP32 board manager file and libraries installed. If you haven't previously prepared your Arduino IDE to operate with the ESP32, then read our previous tutorial, i.e., Introduction to ESP32 Programming Series.
BLE Server Code Description
For coding, we are using Arduino IDE’s inbuilt example and will make the required changes in that code only.
I will also explain the code in detail for beginners to understand.
In this code, ESP32, BLE will be used as a server.
Import the necessary/required libraries for the BLE application.
Define a UUID for the Service and Characteristic.
To generate UUIDs, go to the following link:
https://www.uuidgenerator.net/
You can either use the default UUIDs if you wish to or go to the above link to generate random UUIDs as per your services and attributes.
Call back or acknowledge the server whether the client is connected or not
Arduino Setup() Function
Serial Communication at a baud rate of 115200.
Create a name for your BLE device for identification, we named it Wibree.
Set the BLE device as a server.
Create a service for the BLE server with the UUID defined earlier.
The characteristic for that service is then set. As you can see, you're still using the UUID you created previously, and you'll need to supply the properties of the characters as arguments. It's read and write in this scenario.
You can also add other services like battery, indicate, notify etc.
The setValue() method can be used to set the value of a characteristic.
The above value can be changed to whatever you like. This could be a sensor reading.
Finally, activate the service and advertising so that other BLE devices can scan and locate this BLE device.
Arduino Loop() Function
Here we can check if the device is connected to the client or not
If connected then do some tasks like transmitting data or receiving input from the client.
Data Size Per Packet
20 bytes per packet.
Unfortunately, BLE isn't built to handle large amounts of data. The maximum data size per packet in the BLE specification is 20 bytes, so if you wish to communicate more, you'll have to divide it up into many packets. Fortunately, this isn't a challenging task. Simply put, use a delimiter like "!" or "*" or something unique at the end of your whole message to signal the app that the message is done and to start listening for future communications. If you want to send + > 20 bytes cumulatively, for example, you can send and then proceed with the next message if needed.
Testing ESP32 BLE Server
After creating a BLE server using ESP32, we can use a BLE application available on the Play store for testing purposes.
Demonstration with BLE scanner app:
Go to the play store
Search for the BLE scanner and download the app
After installing the app turn on the Bluetooth.
Open the app and search for nearby devices.
Now connect to ESP32 BLE by clicking on the ESP32 device.
In our case, we named the device ‘Wibree’.
Now you can use the various services provided by BLE like writing and reading data packets, checking battery levels etc. and a lot more.
This concludes the tutorial. I hope you find it helpful.
Hello readers, I hope you all are doing great. Today, we are going to start the second section of the ESP32 tutorial series and today's our first tutorial, where we will have a look at How to Create a Web Server with ESP32. In our previous tutorial, we introduced you to the basics of the ESP32 microcontroller. where we discuss How to set up Arduino IDE to program ESP32. In this tutorial, we will discuss creating a web server using the ESP32 module.
One of the most interesting features of the ESP microcontroller series is its wireless connectivity via WiFi & Bluetooth. Wireless connectivity protocols supported by ESP32 are:
A web server is software or hardware that stores, processes, and delivers web pages to users on request. In other words, it serves users all over the World Wide Web (www). The web server uses the hypertext transfer protocol (HTTP or HTTPS) for communication with the clients(normally, web browsers). We know that HTTP is a set of rules to format and exchange messages.
The following are some important features of a web server:
Features of a Web Server
A web server, either physical or virtual, is a computer that hosts one or more websites.
The HTTP protocol is the foundation of any data exchange within the network when using the server. So a web server uses it to communicate with the client.
The web server uses static content and the files do not change dynamically. Some such files used in a web service are:
HTML files
Images
Stylesheets
JavaScript files
The web server has multiple settings to avoid unnecessary attacks. This helps to maintain the health and integrity of a website. There are multiple types of web security attacks, such as:
DDoS attacks
SQL injection
Cross-site scripting (XSS)
Hence, a web server has multiple features to serve the users on the web.
Web Server & Client Communication
A client is an entity that initiates communication with the web
server and then the server provides the information required. In simple
words, the client is a program, device, or user that requests services
or resources from the devices, such as the web server. The communication
and relationship between these two is called the server-client model.
The following are the general server-client model steps that will help
to understand the whole scenario:
The client sends an HTTP request to the server. The request includes the URL of the web page that the client wants to retrieve.
The
client (when the user requires data) sends an HTTP request to the
server. This request may include the URL of the web page from which the
client wants to retrieve the information.
The server receives
the request instantly and processes it. It does it when it looks up the
URL saved in its database to find the corresponding web page file a
client requires.
If the web page file is found, the server sends
it back to the client in the form of an HTTP response. This response
also includes other important types of information, such as the page's
content type and expiration date, etc.
The client then receives
the response and renders the web page on the user's screen. The client
uses the content type information to determine how to display the web
page.
If the page is not found in the URL database, the server shows the error.
Web browsers like Chrome, Firefox, and Safari are examples of clients.
ESP32 as a Web Server
The ESP32 is a microcontroller famous for its wireless capabilities, which makes it ideal for a large number of fields, especially IoT. We are talking about WiFi connectivity as a web server and here are the key features of this module related to it:
The ESP32 is made under the IEEE 802.11b/g/n standards; therefore it has a 2.4 GHz frequency band. Therefore, it can be used as:
Common WiFi routers
Access point
The built-in WiFi capabilities of the ESP32 allow it to be used as a server and carry out the easiest and most effective communication at a distance without any physical connection.
It has three operating modes:
In station mode, the ESP32 is operated as a WiFi client. It means it can be connected to the existing Wi-Fi network. (We are covering today)
In access point mode, it is operated as a WiFi access point; therefore it allows other devices to create a connection with it. (will be covered in the next lecture)
In dual mode, it can act as a server and as a client and allow the features of both at the same time. (will be covered in the 3rd lecture of section 2)
It has a dual processor that helps in handling multiple tasks at the same time. Therefore, ESP32 is more capable of managing a large network of devices and making it responsive for concurrent connections.
It has asynchronous web server libraries, such as “ESPAsyncWebServe” to handle the HTTP requests asynchronously. These are useful because they allow it to effectively manage the connections without blocking the execution of other tasks.
ESP32 has multiple security protocols that are used when creating the web server. As a result, it provides secure and protective communication between the devices.
It has over-the-air updates, which means it can update the device's firmware without physically accessing it. It helps with remote updates and maintenance.
The ESP32 is suitable for use as a server because of its multiple features, including:
It can serve static files
It can handle different HTTP methods (GET, POST, etc.)
It supports features like server-side scripting
The WebSockets feature of ESP32 allows it to carry out bi-directional communication between servers and clients. You will learn about both of these in just a bit.
The ESP32 supports WiFi Direct, which is also referred to as the Peer to Peer (P2P); therefore, it can form a direct connection with other devices with no need for an external WiFi network.
ESP32 WebServer Working Principle
We know that the ESP32 has a built-in WiFi feature. This makes it suitable to use as a server. The example of the server-client relationship we have just discussed shows the internet connection of the whole world. The ESP32 can be used for the intranet connection, which is defined as:
"An intranet is a private network that has limited functionalities and is only accessible to users within a specific organization/location."
Usually, this network may consist of different devices, such as mobile phones, computers, laptops and tablets. The Arduino IDE is for the programming of the ESP32, just like we have done in the previous session. If your Arduino IDE is ready with the boards and ports, then let us try the built-in example of the ESP32 to use as a server.
What is an SSID?
An SSID is a service set identifier that is the unique name of a wireless local area network (WLAN).
It can be 32 characters long.
It may include numbers, letters, and signs.
The SSID can be set by the user as well.
In simple words, the SSID is the name of the WiFi connection people use for their connection.
In the experiment we are just performing, the user has to replace the SSID with their own SSID to connect with the ESP32.
Using the ESP32 Server Built-in Example
Using the ESP32 as a server is easy with the web server example. It has the basics, and here are the steps to follow:
Open the Arduino IDE.
Connect the esp32 to your system through the cable. Make sure the ESP32 is connected accurately.
Click on tools>boards>ESP32>Node32s. This is my board and you can choose according to the model of ESP32.
Go to the files> examples>examples of Nose32s>WiFi and from the side menu, choose “SimpleWifiServer".
It will create a new project with the code in it to run the ESP32 (connected to your system) as a server.
Press the encoder (EN) button of the ESP32.
Change the SSID and password according to your choice. In my case, it is PTCL-BB.
Go to lines 38, 103, and 106 by one and replace the pin “5” digit with pin “2” because the built-in light is at pin 2.
Replace lines 70 and 71 with the following:
client.print("Click <a href=\"/H\">here</a> to turn the LED on pin 2 on.<br>");
client.print("Click <a href=\"/L\">here</a> to turn turn the LED on pin 2 off.<br>");
All the instructions are given in the code. Go to line 30 and place your SSID there.
Go to line 31 and enter the password of your choice.
Read the code carefully and hit the “verify” button.
Once the code is compiled, press "Boot" on the ESP32 when the uploading process is carried out.
Wait for the loading to complete.
Click on the “Serial Monitor” button at the upper right corner of the screen to open the monitor. You can go to Tool>Serial Monitor for the same task.
Choose the baud rate of 115200 from the drop-down menu at the right corner of the monitor.
Right now, the monitor is blank:
Click the EN button on the EPS32 to see the information.
Now that the monitor has data and is loading, it starts to connect with the WiFi connection of the system.
Once the loading is complete, it will provide the IP address. Copy this address.
Go to the new tab in the browser and paste the address there.
You will see that merely placing the “H” or “L” just after the IP address (as given in the code comment) will turn on and off the LED on ESP32 according to the URL.
Note: Make sure you have installed the port and board before you try this code and have selected all the right options; otherwise, you can face errors.
ESP32 Server as Messenger
The ESP32 can be used to send the message through the browser.
The microcontroller connects to the internet connection of the system.
The serial monitor shows the IP address.
The ESP32 acts as a server and through the URL of the browser, the user will send the message to the Arduino IDE.
This message will be shown on the serial monitor.
The user can change the message through the URL pasted in the web browser.
Material Required
Internet connection
System (e,g, laptop)
ESP32 microcontroller
Connecting cable
Code for ESP32 as Server
#include <WiFi.h>
const char *ssid = "My-SSID";
const char *password = "My-Password";
WiFiServer server(80);
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
void loop() {
WiFiClient client = server.available();
if (client) {
Serial.println("New Client.");
while (client.connected()) {
if (client.available()) {
String request = client.readStringUntil('\r');
client.flush();
// Check if the request contains a specific message
Make sure you have the respective port and board installed successfully.
Connect the right port and board.
Paste the code given above into the new project.
"Verify" the code by using the button.
Once verified, compile and upload the code.
Once the code is compiled, press the Boot button.
Once the installation is completed, go to the serial monitor.
Press the EN button.
The serial monitor will show the information. Copy the IP address shown on the end of loading.
The general ULR for sending the message through the server is given as: http://esp32-ip-address/message?message=Hello
To send the “Hello” message to the ESP32 through the browser, use your IP address and the message. In my case, I am pasting the following URL in the browser: http://192.168.43.251/message?message=Hello
Once reloaded, go to the serial monitor and check for the message:
For the demonstration purpose, we will create a webpage and will launch it through our ESP32 module, so ESP32 will be acting as a web server, serving the page.
This webpage will have 3 Buttons on it, which will be controlling three LEDs, we will turn ON or OFF respective LEDs using these buttons.
WebServer Page is shown in the below figure:
Now the question arises, how will ESP32 understand which Button has been pressed?
For that, we have created multiple links i.e. the HomePage Url will look like:
http://192.168.43.188/
When a user will click on LED 26 ON Button, we will redirect the user to:
http://192.168.43.188/26/on
Now, when the client wants to turn OFF the LED, we will redirect to:
http://192.168.43.188/26/off
So, actually, we are checking the request from the client and based on that request we are turning ON or OFF the respective LED.
Moreover, we are providing the same webpage to all the links but with the change in the state of each button i.e. if it's ON then Blue, otherwise Green.
If it looks too complicated, don't worry. These things will get more clear when we will cover the Arduino coding.
ESP32 Wi-Fi module includes a number of useful characteristics, including the ability to use a soft access point mode, a station mode, or both modes at the same time. Only station mode will be discussed in this session. I'll also cover how to use this board in soft access mode in future tutorials.
Station Mode: The ESP32 board connects to your Wi-Fi network via a router in Station mode. The router serves as the communication channel between the web client and the ESP32. The IP address is obtained from the Wi-Fi router. Web clients can connect to the Web server using this IP address across a local network.
Access Point Mode: In this mode, the ESP32 creates its own wireless Wi-Fi network, similar to the one provided by your existing router. We don't need to connect the ESP2 to a Wi-Fi network in this mode. This Wi-Fi board can link up to 5 devices to the Wifi network it creates.
Controlling peripherals Using ESP32 Web Server
Connect the peripherals to the ESP32 board which you want to control through the ESP32 Web Server.
Here, we are going to control two external LEDs connected to LED1 (GPIO 26), LED2 (GPIO 27), and an inbuilt LED.
The following are the requirements for creating an ESP32 webserver to control peripherals:
ESP32 module
Internet connection
LEDs
Resistors
Connecting Wires
Arduino IDE Code
Using the Arduino IDE, upload the following code to the ESP32 module:
#include
// Replace with your network credentials
char* ssid = "ESP32"; //enter SSID
char* passphrase = "asdfgf@123"; // enter the password
// Set web server port number to 80
WiFiServer server(80);
// Variable to store the HTTP request
String header;
// Auxiliar variables to store the current output state
String output26State = "off";
String output27State = "off";
String builtin_led_state = "off";
// Assign output variables to GPIO pins
const int output26 = 26;
const int output27 = 27;
// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;
void setup() {
Serial.begin(115200);
// Initialize the output variables as outputs
pinMode(output26, OUTPUT);
pinMode(output27, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
// Set outputs to LOW
digitalWrite(output26, LOW);
digitalWrite(output27, LOW);
digitalWrite(LED_BUILTIN, LOW);
// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, passphrase);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
void loop(){
WiFiClient client = server.available(); // Listen for incoming clients
if (client) {
// If a new client connects,
currentTime = millis();
previousTime = currentTime;
Serial.println("New Client."); // print a message out in the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
currentTime = millis();
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
header += c;
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
// turns the GPIOs on and off
if (header.indexOf("GET /26/on") >= 0)
{
Serial.println("GPIO 26 on");
output26State = "on";
digitalWrite(output26, HIGH);
}
else if (header.indexOf("GET /26/off") >= 0)
{
Serial.println("GPIO 26 off");
output26State = "off";
digitalWrite(output26, LOW);
}
else if (header.indexOf("GET /27/on") >= 0)
{
Serial.println("GPIO 27 on");
output27State = "on";
digitalWrite(output27, HIGH);
}
else if (header.indexOf("GET /27/off") >= 0)
{
Serial.println("GPIO 27 off");
output27State = "off";
digitalWrite(output27, LOW);
}
else if (header.indexOf("GET /LED_BUILTIN/on") >= 0)
{
Serial.println("BUILTIN LED on");
builtin_led_state = "on";
digitalWrite(LED_BUILTIN, HIGH);
}
else if (header.indexOf("GET /LED_BUILTIN/off") >= 0)
{
Serial.println("BUILTIN_LED off");
builtin_led_state = "off";
digitalWrite(LED_BUILTIN, LOW);
}
// Display the HTML web page
client.println("");
client.println("");
client.println("");
// CSS to style the on/off buttons
// Feel free to change the background-color and font-size attributes to fit your preferences
client.println("");
// Web Page Heading
client.println("
ESP32 Web Server
");
// Display current state, and ON/OFF buttons for builtin led
client.println("
LED_BUILTIN - State " + builtin_led_state + "
");
// If the LED is off, it displays the ON button
if (builtin_led_state=="off")
{
client.println("
");
}
else
{
client.println("
");
}
// Display current state, and ON/OFF buttons for GPIO 26
client.println("
LED_1 - State " + output26State + "
");
// If the output26State is off, it displays the ON button
if (output26State=="off")
{
client.println("
");
}
else
{
client.println("
");
}
// Display current state, and ON/OFF buttons for GPIO 27
client.println("
LED_2 - State " + output27State + "
");
// If the output27State is off, it displays the ON button
if (output27State=="off")
{
client.println("
");
}
else
{
client.println("
");
}
client.println("");
// The HTTP response ends with another blank line
client.println();
// Break out of the while loop
break;
} else { // if you got a newline, then clear currentLine
currentLine = "";
}
} else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// Clear the header variable
header = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}
Note:
You need to modify the SSID and password with your network credentials.
Code Description:
Here, we'll take a closer look at the code to see how it works.
The first task is to add a Wi-Fi library.
As mentioned previously, you must type your SSID and password inside the double quotes in the following lines.
As we are creating a web server, so we need to assign a port to it and normally we use port 80 for a local webserver.
So, in the below code, Port 80 is assigned to the webserver and then initialized a few variables:
String header: variable to store the header of the HTTP request.
Below the header variable, we have variables to store the current state of connected peripheral LEDs and built-in LED. If you wish to add more peripherals and save their states, you need to create more variables. By default, all LEDs are in the OFF state.
Next, assigned GPIOs to each peripheral device or component. Here we are using GPIO 26(LED1) and GPIO 27(LED2). You can use any other suitable GPIOs.
Lastly, we have initialized a few variables to check the connection timeout, we will check their working soon.
Arduino Setup() Function
Now let's first have a look at the Arduino setup loop.
First, we have initialized our Serial Port at a baud rate of 115200, so that we could monitor the results at the serial terminal.
Define the GPIOs as OUTPUTs and set them to LOW, as by default LEDs will be off.
To set up a wifi connection, we called the WiFI.begin() and here we have provided our SSID and passphrase as variables.
Now our ESP32 will try to connect to the provided WiFi connection.
As you can see, we have a while loop, where we are checking the WiFi Status.
If ESP32 gets connected with WiFi, the while loop will break and a message will get printed on the Serial Monitor "WiFi Connected".
Now our ESP32 is connected to the WiFi, so the router must have assigned an IP address to ESP32 and we are printing it on Serial using WiFi local IP Function.
Finally, we begin our server, to which we have assigned Port 80 at the start.
Arduino Loop() Function
Now, we are done with all the basic settings in the setup function. Let's have a look at the code in the Loop function:
At the last line of the Setup function, we have started our webserver, so now ESP32 is acting as a webserver and is waiting for incoming clients.
But what will happen, when someone will hit the IP Address of this webserver?
So, in the loop function, first of all, we are listening to the incoming client using the server.available() function.
If any client is available i.e. someone has entered our IP Address in the browser then we will print the HTML page.
So, we are going to write the rest of our code in this IF loop.
AS you can see in the below code, if the client is available, we have printed "New Client" on Serial Monitor.
After that, we have a while loop checking for client connection, so as long as we have a connection with the client, we will remain in this loop.
Inside this while loop, we have an If loop, checking if the client is available.
Now, if we are connected to the client, we need to read for the incoming request.
So, If there are any bytes to read from the client, read those bytes:
The client request ends at New Line Character \n, so we are checking for that.
Once we received the New Line Character, we are sending the response back to the Client.
In response, we have first sent the HTTP header, which is the default for webpages so that browsers should understand the response type.
Checking Request Type
As we discussed earlier, on each button press, we are redirecting our client to its respective link.
Depending on which button is pushed, we make requests to different URLs to turn the LEDs on and off using if else statements, as shown below:
As you can see in the above code, we are repeating the same code three times for 3 LEDs.
In the first block, we are simply checking the header response and if it's a GET request and from "/26/on", we have turned that Pin HIGH, changed the LED state variable to "on" and sent a message on the serial monitor.
So, if a client clicks on the LED 26 ON button, ESP32 will understand the GET request and glow the LED.
The other buttons work in the same way. If you wish to add more outputs, you'll need to change this section of the code.
HTML to display a web page
We have designed the output part i.e. what we are going to do when a user clicks any button.
And now we are going to design those buttons themselves i.e. we are designing the webpage.
As you can see in the below figure, we have standard HTML tags at the start.
After that, we have some CSS text to design the buttons and the appearance of the web page. We use the Helvetica font and set the information to be shown as a block with the center aligned.
Next, displaying Web page heading i.e. "ESP32 Web Server".
Next, comes the If Loop for the first Button, we are checking the LED state variable and based on LED state, we are displaying our Button.
So, if the LED state is OFF, we are redirecting the user to /LED_BUILTIN/on and vice versa.
That's how we are changing the Buttons on the webpage, as you can see buttons are using different CSS classes for on and off states.
Similar loops are used to display the states on other connected LEDs.
Finally, we are closing the web connection and clearing the header that was used to store the HTTP request header using client.stop() function.
Printing information about the closed web connection on the serial monitor.
Uploading Web Server Code to ESP32
Please reread the previous instruction, "Introduction to ESP32 programming series," if you are unfamiliar with the procedure of uploading code in the Arduino IDE.
After uploading the code, open the Serial Monitor with a baud rate of 115200.
Enable the ESP32 by pressing the EN (enable) button. The ESP32 establishes a Wi-Fi connection and the Serial Monitor displays the ESP32 IP address. To connect to the ESP32 web server, you'll need that IP address.
Note:
Make sure you have selected the right board and COM port.
Getting IP address and Access ESP32 web Server
After successfully uploading the code in esp32 module.
Open Serial Monitor from the top right corner of Arduino IDE screen as shown in figure below:
The IP address required to connect to the ESP32 point will be displayed on the Serial Monitor. It's 192.168.43.223 in this scenario.
To access the webserver, type the IP Address of the ESP32 into a Web Browser on a laptop or a mobile phone. It's 192.168.43.223 in our case.
You should be able to see a simple web page served by the ESP32's Web Server if everything goes well.
A screenshot of a Web Browser on a laptop accessing the ESP32 Web Server is shown below.
The image below is displaying the ONstate of the inbuilt LED.
The inbuilt LED is Blue in color.
The below image is displaying the OFF State of the inbuilt LED
Hence, We have done a lot of work on the ESP32 by using it as a server. In the beginning, we saw what is a web server and studied its features in detail. After that, we saw that ESP32 can be used as a server and we saw the feature that makes it ideal for this task. Then we experimented to learn the concept, in which we saw the built-in example of ESP32 as a server in Arduino IDE. We saw the step-by-step procedure to experiment and once it was completed, we moved on to a more complex example. I hope you find this tutorial useful and have performed it by yourself but if you are stuck at any point, you can ask in the comment section.
Using the ESP32 web server and the preceding process, you can control the peripherals linked to the ESP32 module from any mobile, tablet, or computer. The only need is that all of the devices to be linked to the same network.
This concludes the lesson. I hope it becomes useful to you. In the next tutorial, we will have a look at How to work the ESP32 BLE, so stay tuned. Have a good day. :)
Syed Zain Nasir
I am Syed Zain Nasir, the founder of <a href=https://www.TheEngineeringProjects.com/>The Engineering Projects</a> (TEP). I am a programmer since 2009 before that I just search things, make small projects and now I am sharing my knowledge through this platform.I also work as a freelancer and did many projects related to programming and electrical circuitry. <a href=https://plus.google.com/+SyedZainNasir/>My Google Profile+</a>